# llmsurgery


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Install

``` sh
pip install llmsurgery
```

## What’s here

Dialogs are LLM conversations kept as Jupyter notebooks: notes, runnable
code with outputs, and prompt/reply pairs in one editable, diffable
document. This library is the data model and surgery toolkit for them,
consisting of:

- `llmsurgery.dialog`:
  [`Message`](https://AnswerDotAI.github.io/llmsurgery/dialog.html#message),
  [`Dialog`](https://AnswerDotAI.github.io/llmsurgery/dialog.html#dialog),
  and
  [`Attachment`](https://AnswerDotAI.github.io/llmsurgery/dialog.html#attachment)
  — a message carries exactly what the ipynb spec provides (content,
  output, type, id, attachments) plus a verbatim metadata dict, so host
  annotations round-trip untouched; hosts declare their own fields via
  `meta_attrs` and inject their subclasses through `msg_cls` and
  `read_ipynb(cls=)`.
- `llmsurgery.ipynb`: reading and writing dialogs as `.ipynb` files.
- `llmsurgery.hist`: converting dialogs to LLM chat history, including
  recovering tool calls from replies as structured messages. Rendering
  defaults are deliberately unopinionated (bare prompts, pass-through
  media, verbatim latex); hosts install their policies as class members
  (`prompt_txt`, `prep_img`, `media_extra`, `ai_renderers`,
  `UNSUPPORTED_MSG`).
- `llmsurgery.ant`: Claude Code session transcripts: read, write,
  search, curate, and build them from dialogs, so `claude --resume`
  opens an authored conversation.
- `llmsurgery.oai`: Codex threads: drive `codex app-server` to inject
  authored histories, ready for `codex resume`.

## The theory

A dialog is a conversation between a human, an AI, and an interpreter.
Each message type addresses one of them and expects a certain kind of
answer:

- A **prompt** asks the AI a question and holds its reply.
- A **code** message gives the interpreter source and holds its outputs.
- A **note** is read by everyone and answered by nobody.
- A **raw** message addresses no one. It is inert matter the
  conversation carries along.

A reply may itself contain runnable code with results, so a whole dialog
can live inside one message.
[`reply2dlg`](https://AnswerDotAI.github.io/llmsurgery/hist.html#reply2dlg)
opens a reply up as a dialog and
[`dlg2reply`](https://AnswerDotAI.github.io/llmsurgery/hist.html#dlg2reply)
puts it back.

Dialogs and Jupyter notebooks both serialize to the ipynb format, but
they are not the same thing. A notebook has cells. A dialog has
messages. Messages can be *prompts*, which notebooks cannot express, and
they make structure explicit that notebooks leave implicit. E.g a
heading opens a section that runs to the next heading of the same level;
an export directive marks the code that belongs to a module. The shared
file format means the same tools read both. The word tells you which
layer you are on. File-level tools such as `fastcore.nbio` and `exhash`
speak of cells and notebooks. Everything in this library speaks of
messages and dialogs.

The
[`Dialog`](https://AnswerDotAI.github.io/llmsurgery/dialog.html#dialog)
is the center of the library. Everything else is a projection of it. A
storage projection must preserve everything that means something. What
it does not understand it carries verbatim in metadata, and what is
broken it heals rather than rejects. A transmission projection
normalizes on purpose, and what it drops is written into its contract. A
display projection only goes one way. The rule is to convert in, edit at
the center, and project out. The function names say the same thing.
Every converter has `dlg` on exactly one side.

<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr>
<th>projection</th>
<th>contract</th>
<th>in</th>
<th>out</th>
</tr>
</thead>
<tbody>
<tr>
<td>ipynb file</td>
<td>storage, pragmatically lossless</td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/ipynb.html#read_ipynb"><code>read_ipynb</code></a></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/ipynb.html#write_ipynb"><code>write_ipynb</code></a></td>
</tr>
<tr>
<td>Claude Code session</td>
<td>storage</td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/ant.html#sess2dlg"><code>sess2dlg</code></a></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/ant.html#dlg2sess"><code>dlg2sess</code></a></td>
</tr>
<tr>
<td>Codex thread</td>
<td>storage (write-only so far)</td>
<td></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/oai.html#dlg2thread"><code>dlg2thread</code></a></td>
</tr>
<tr>
<td>fastllm chat (<code>Msg</code>/<code>Part</code>)</td>
<td>transmission, normalizing</td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/ant.html#chat2dlg"><code>chat2dlg</code></a></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/hist.html#dlg2chat"><code>dlg2chat</code></a></td>
</tr>
<tr>
<td>fastllm hist (live call input)</td>
<td>transmission, one-way</td>
<td></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/hist.html#dlg2hist"><code>dlg2hist</code></a></td>
</tr>
<tr>
<td>a prompt’s reply</td>
<td>self-similar</td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/hist.html#reply2dlg"><code>reply2dlg</code></a></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/hist.html#dlg2reply"><code>dlg2reply</code></a></td>
</tr>
<tr>
<td>XML views</td>
<td>display, one-way</td>
<td></td>
<td><a
href="https://AnswerDotAI.github.io/llmsurgery/dlgskill.html#view_dlg"><code>view_dlg</code></a>,
<a
href="https://AnswerDotAI.github.io/llmsurgery/dlgskill.html#msg2xml"><code>msg2xml</code></a></td>
</tr>
</tbody>
</table>

The session codecs route through chat on their way to the wire: ant’s
[`dlg2msgs`](https://AnswerDotAI.github.io/llmsurgery/ant.html#dlg2msgs)
and oai’s
[`dlg2items`](https://AnswerDotAI.github.io/llmsurgery/oai.html#dlg2items)
are each `denorm_msgs(dlg2chat(...))`.
