Loading the documentation…

Chat log format

DataMind Oda keeps each chat's lasting record as a session log file on your computer. This page covers the format of that log: its header, the events inside it, and the rules Oda follows when reading and writing it. It is written for people who inspect, support or process chat logs. Where the files live and how Oda keeps them is covered in Session logs.

What a chat log holds

A log holds everything the model saw in the chat, in the order it happened:

The first line is the header. It names the chat and how it started, and Oda can read it on its own to decide how to treat the file before reading anything else. The header carries:

The number of inherited events is kept with the log, not among the records a reader replays.

Before trusting a header, Oda checks its fields:

A log written by a different version of Oda is converted or refused when it opens; see Opening older chats.

Messages, roles and content

Every message carries a role:

RoleWhat it carries
usermessages from you and other human input
modelOda's answers, including the reasoning that came with them
toola tool result, as a message of its own
developernotes about which tools the model had

Message content comes in a few kinds: text, reasoning, image, file, tool-call and tool-result. Images are held as attachments in PNG, JPEG, WebP or GIF; each image record carries its media type, its size and its dimensions.

Two details matter when you process a log:

What a log refuses to store

Oda stores each value in a log exactly as it was, and refuses a value it cannot store that way instead of storing an approximation. This covers:

The same test runs on the chat's metadata, refused with session metadata must be losslessly JSON-serializable. When a value is refused, nothing from that batch is stored. For the messages a failed check can show, see Session log problems.

How the format is versioned

Note

These version numbers name the log format, not a release of DataMind Oda. They count one series: a lower number in an older record or release note is an earlier step of this same series.

Changes that stay in the same version

A change can stay in a released version only in three cases, each with exact conditions:

Changes that need a new version

Every other kind of change starts a new version, for example: adding or removing a kind of record a log can carry; removing a property or changing its type; adding a required property or changing an existing property's optionality; changing a union's variants, an index signature, or a tuple's length; and changing the source compatibility policy.

How two versions are compared

Every type the format can reach is fingerprinted with a SHA-256 digest that covers every referenced field, and a change is reviewed by comparing the fingerprints before and after.

A change that looks cosmetic, such as reordering tuple elements, can still count; renaming a type alias does not.

Reading part of a log

A log is read in pieces, not all at once. Saved events keep their order and their sequence numbers, and reading a log never changes it. A read asks for two things:

  1. a starting position: the sequence number of the first event to return;
  2. a length: how many events to return.

Both are whole numbers of zero or more; anything else is refused with read offset must be a non-negative safe integer, got <v> or read length must be a non-negative safe integer, got <v>, depending on which value is wrong. By default a read starts at the beginning and returns the rest of the log. A read that starts at or past the end returns nothing; it is not an error.

A later read never shows an older state than an earlier one.

Read models and checkpoints

Oda also keeps small current values built from a chat's log, so it can present the chat's state without replaying every event. These values are called read models.

Questions, answered

What does a chat log contain?

Everything the model saw in the chat: the messages, the tool calls and their results, the files and images, and the settings each request ran with, all in order. The header at the top names the chat and how it started.

What do the roles in a log mean?

Each message carries one of four roles: user, model, tool or developer. They say where the message came from; the table above lists what each role carries.

Which image types can a log hold?

PNG, JPEG, WebP and GIF. An image is stored with its media type, its size and its dimensions, and a reference to the attachment that holds it.

Why is a tool result a message of its own?

So a reader sees every result exactly where it belongs in the conversation. The result message keeps the id of the call it answers and is marked when the call failed. Logs from older formats are converted as they open, and their results also become messages of their own.

What values does a log refuse to store?

Values that JSON cannot keep exactly: negative zero, infinity and NaN, undefined members, empty array slots, hidden or symbol-named members, cycles, and instances of custom classes. Oda refuses them rather than storing a changed value.

How do I read only part of a log?

Ask for a starting position and a length. The position is the sequence number of the first event to return, and the length is how many events to return. By default a read returns the log from its start, and a position at or past the end returns nothing.

Which changes need a new format version?

Every change except three: an optional property added within an event's body, a new event payload version that keeps every earlier variant, and a source kind added only as an attribution. Adding or removing a kind of record, removing a property or changing its type or optionality, or giving a retired field data again all start a new version.

Why do older records name a different format number?

The numbers count one series, the log format's own versions, which have moved one step at a time from v0 to v4. Not every step was carried by a published release, so an older record can name a lower number of this same series.

What does the position in a read-model snapshot mean?

It is the sequence number of the last event that the snapshot's values account for, so you can tell how current they are. A chat with no events yet reports the position -1.

Do saved read-model values go stale?

They can lag behind the chat, but they are never wrong: when a saved checkpoint no longer fits the log, Oda rebuilds the state from the log instead of serving it.