Documentation
¶
Overview ¶
Package export turns session trees into linear trajectories and ATIF documents. The session file stays the record; an ATIF document is one root-to-leaf path with compaction applied, carrying the raw Open Responses items in its extras so nothing is lost on the way.
Index ¶
- Constants
- Variables
- func DocumentName(doc *atif.Trajectory) string
- func Items(doc *atif.Trajectory) (openresponses.Items, error)
- func ItemsFrom(doc *atif.Trajectory) (openresponses.Items, error)
- func MainDocumentName(sessionID string) string
- func PreferCurrentLeaf(s *agentsession.Session, fork string, children []string) string
- func PreferLatest(s *agentsession.Session, fork string, children []string) string
- func PreferScore(s *agentsession.Session, fork string, children []string) string
- func Redact(doc *atif.Trajectory, redactors ...Redactor) error
- func ToATIF(t Trajectory, opts Options) (*atif.Trajectory, error)
- func Trajectories(s *agentsession.Session, prefs ...Preference) iter.Seq2[Trajectory, error]
- func WriteATIF(dir string, docs iter.Seq[*atif.Trajectory]) error
- type Options
- type Preference
- type Redactor
- type RedactorFunc
- type Trajectory
Constants ¶
const ( ExtraOpenResponses = "openresponses" ExtraAgentSession = "agentsession" ExtraEnvironment = "environment" ExtraOutcome = "outcome" ExtraPreferredOver = "preferred_over" ExtraAbandonedAt = "abandoned_at" ExtraBranchFrom = "branch_from" ExtraContextMgmt = "context_management" // ExtraRun carries, as a list, the runs whose records belong to a // step: a run's source, trigger, end reason, cause and pending // calls go in the extra of the first step its segment produces, or // in the root extra when it produces none. It is a list because a // run that produces no step, which is what a refusal on resume is, // would otherwise be overwritten by the next run's record, and // because a reader needs an order where several land in one place. ExtraRun = "run" // ExtraCalls carries, keyed by call ID in the extra of the agent // step that produced the call, the call's decisions and dispatch. ExtraCalls = "calls" // ExtraQueued carries, as a list, the inputs a harness accepted // before it could append them: the item, the mode and the trigger // of each. A queued input that was appended is a step of its own // carrying the same trigger under "source". ExtraQueued = "queued" )
Root extra members the exporter writes.
const Replacement = "[REDACTED]"
Replacement is what redacted text becomes.
Variables ¶
var ErrNoRawItems = errors.New("export: document carries no raw items")
ErrNoRawItems is returned by Items for a document that was not written by this package.
Functions ¶
func DocumentName ¶
func DocumentName(doc *atif.Trajectory) string
DocumentName returns the file name WriteATIF uses for a document.
func Items ¶
func Items(doc *atif.Trajectory) (openresponses.Items, error)
Items rebuilds the item list of the path a document was exported from, reading the raw items every step carries under extra.openresponses. Steps without them are skipped; a document with none at all yields ErrNoRawItems.
func ItemsFrom ¶ added in v0.0.5
func ItemsFrom(doc *atif.Trajectory) (openresponses.Items, error)
ItemsFrom rebuilds a conversation from an ATIF document's declared fields alone, so a document from any producer loads, not only one this package wrote. It is lossy where the declared fields are: use Items on a document that carries the raw items. Per step, a user step becomes a user message; a system step a system message, with any observation result that names a call becoming that call's output; an agent step a reasoning item from reasoning_content, an assistant message from message when it has text, one function call per tool call, and one function call output per observation result that names a call. Image parts keep their path as the image URL.
Lost: item IDs and statuses, message phases, encrypted reasoning and the summary-versus-content distinction, the original bytes of tool call arguments (re-encoded from the document's object, so key order may change and a call whose arguments were not an object comes back from its "_arguments" member), non-text tool outputs (flattened to text), visibility flags, extension items (only their text survives), and audio parts (a text placeholder). A copied context step is a system message like any other; the document's is_copied_context flag does not survive.
func MainDocumentName ¶
MainDocumentName returns the file name WriteATIF uses for a session's main trajectory, and the path an unresolved subsession reference carries.
func PreferCurrentLeaf ¶ added in v0.0.3
func PreferCurrentLeaf(s *agentsession.Session, fork string, children []string) string
PreferCurrentLeaf chooses the child whose subtree holds the session's current leaf, so the branch a user has switched back to counts as continued. It has no opinion at forks the leaf is not under.
func PreferLatest ¶ added in v0.0.3
func PreferLatest(s *agentsession.Session, fork string, children []string) string
PreferLatest is the default rule: the child whose subtree holds the most recently appended entry was continued. It is right when a user abandons a branch and moves on, and wrong when they hop between branches.
func PreferScore ¶ added in v0.0.3
func PreferScore(s *agentsession.Session, fork string, children []string) string
PreferScore chooses the child whose subtree holds the outcome with the highest score. An outcome counts for the entry it targets, or for its own position when it has no target. It has no opinion when no child has a scored outcome, or when the best scores tie.
func Redact ¶
func Redact(doc *atif.Trajectory, redactors ...Redactor) error
Redact applies redactors to the document in order.
func ToATIF ¶
func ToATIF(t Trajectory, opts Options) (*atif.Trajectory, error)
ToATIF converts one trajectory into an ATIF document. Every step carries the raw items it was built from under extra.openresponses, so Items can rebuild the item list; the mapping is documented in docs/plans/session-layer.md.
func Trajectories ¶
func Trajectories(s *agentsession.Session, prefs ...Preference) iter.Seq2[Trajectory, error]
Trajectories yields one trajectory per leaf of the session, in file order of the leaves. At every entry with more than one child, one child is the continued branch and the others are abandoned: the preferences are asked in order and the first that names a child decides; with none, or when none has an opinion, PreferLatest applies. A leaf reached through an abandoned child has AbandonedAt set to the first such fork; a leaf on the continued side of a fork lists the abandoned subtrees' leaves in PreferredOver. The trajectory ending at the last appended entry is marked Main whatever the preferences decide.
It is At over each leaf, so a caller that has to rebuild the document of a path that is no longer a leaf asks for it by entry.
func WriteATIF ¶
WriteATIF writes one JSON file per document under dir. A session's main trajectory (see Trajectory.Main) is named "<session_id>.json", which is what an unresolved subsession reference points at; every other document is "<session_id>_<trajectory_id>.json", or "<trajectory_id>.json" without a session ID. Media carried inline as data URLs is written beside the documents under images/ and audio/, named by content hash, and the parts are rewritten to point at those files. Documents are validated before they are written.
Types ¶
type Options ¶
type Options struct {
// AgentName and AgentVersion fill the ATIF agent object. They
// default to the session header's harness, then to "agentsession".
AgentName string
AgentVersion string
// ModelName overrides the model name the document reports, in
// agent.model_name and on every agent step, without touching the
// model the request was sent with. It exists because a consumer
// may want a name the provider would refuse: Harbor derives a
// provider by splitting model_name on the first slash, and a
// self-hosted model called "qwen3.5:9b" has none, while sending
// "ollama/qwen3.5:9b" is a 404. The session still records what was
// sent; this is what is reported.
ModelName string
// Cost returns the price of one model call when a price source is
// configured. When nil, cost_usd is left absent.
Cost func(model string, usage openresponses.Usage) (usd float64, ok bool)
// Subsessions resolves a link entry's session ID to the session so
// its main trajectory can be embedded as a subagent trajectory. A
// nil resolver, or one returning nil, leaves a file reference to
// [MainDocumentName] of the child, which is where [WriteATIF] puts
// the child's main trajectory.
Subsessions func(sessionID string) (*agentsession.Session, error)
// Preferences decide the continued branch at a fork of an embedded
// subsession; see [Trajectories]. The caller's own session is
// walked with the preferences it passed to Trajectories.
Preferences []Preference
// Redactors run over the finished document in order.
Redactors []Redactor
// Notes is copied to the document's notes member.
Notes string
}
Options configure ToATIF.
type Preference ¶ added in v0.0.3
type Preference func(s *agentsession.Session, fork string, children []string) string
A Preference chooses the continued child at a fork: fork is the entry with more than one child and children are its children in file order. It returns one of the children, or "" to express no opinion. Trajectories asks each preference in turn and falls back to PreferLatest.
func PreferLabel ¶ added in v0.0.3
func PreferLabel(label string) Preference
PreferLabel chooses the child whose subtree holds an entry carrying the label, for a harness that marks the branch it kept. It has no opinion when no child, or more than one, is labelled.
type Redactor ¶
type Redactor interface {
Redact(*atif.Trajectory) error
}
Redactor rewrites an ATIF document in place. Redaction runs at export, never at write, and covers the extras as well as the steps.
func Environment ¶
func Environment() Redactor
Environment removes environment snapshots from the document: the root and step extra.environment members and the working directory, which name machines, paths and file hashes that are rarely meant to travel.
func HomePaths ¶
HomePaths replaces absolute paths under home with "~"-relative ones in every string of the document, and the home directory itself with "~". With an empty home it does nothing.
func NoPassthrough ¶ added in v0.0.5
func NoPassthrough() Redactor
NoPassthrough removes the raw Open Responses items and response bodies the exporter carries under every step's and observation result's extra.openresponses, which roughly halve a document and say nothing the declared fields do not. Use it for a judge's input or a published document; keep the full document in the archive, because the passthrough is what makes Items lossless, and without it Items returns ErrNoRawItems. The root extra's payload profile name stays.
func Secrets ¶
Secrets replaces every occurrence of the given values, in every string of the document, with Replacement. Empty values are ignored. Longer values are replaced first so a value that contains another is not left half redacted.
type RedactorFunc ¶
type RedactorFunc func(*atif.Trajectory) error
RedactorFunc adapts a function to Redactor.
func (RedactorFunc) Redact ¶
func (f RedactorFunc) Redact(t *atif.Trajectory) error
Redact implements Redactor.
type Trajectory ¶
type Trajectory struct {
// Header is the session header.
Header agentsession.Header
// LeafID identifies the path; it becomes the ATIF trajectory_id.
LeafID string
// Context is the path after compaction: settings, items and the
// selected entries in order.
Context agentsession.Context
// Path is the root-first path the trajectory covers, before
// compaction, of which Context is what the model would be sent.
// The document's steps are built from Context; its totals are
// taken from Path, so a run that folded reports what it spent and
// not what survived the last fold. It is nil in a Trajectory built
// by hand, and then Context stands for the path.
Path []agentsession.Entry
// Name is the session's display name from its info entries.
Name string
// Labels are the current labels of the session, by target entry.
Labels map[string]string
// PreferredOver lists the leaf IDs of sibling branches this path
// was continued in preference to, at every fork it passes through
// on the preferred side.
PreferredOver []string
// AbandonedAt names the fork entry at which this path left the
// preferred route, or "" when it is a preferred path throughout.
AbandonedAt string
// Main is true for exactly one trajectory of a non-empty session:
// the path ending at the most recently appended entry, which is the
// session's current path. WriteATIF names its document after the
// session alone, and a subsession reference that cannot be embedded
// points at that file.
Main bool
}
Trajectory is one root-to-leaf path of a session with the context algorithm applied, plus what the tree says about it.
func At ¶ added in v0.0.6
func At(s *agentsession.Session, entryID string, prefs ...Preference) (Trajectory, error)
At returns the trajectory whose path ends at entryID, with the same PreferredOver, AbandonedAt and Main treatment Trajectories applies and LeafID set to entryID. The entry need not be a leaf: anything appended to a session after it was exported moves the leaf, and this is how the document that was exported, the one a judge read and a score names, is built again.