Documentation
¶
Overview ¶
Package view is the reconciler: a pure model that takes the record's changes and the agent's live events, in whatever order they arrive, and produces what a client renders.
The rule is the plan's: the record is the truth for everything committed, and live events cover only what is not. So a rendering is the path's items from the record, then an overlay of what is in flight on top: items still streaming, calls opened and not answered, the state of the turn, the permissions that are out. An overlay item is dropped when the entry carrying it lands, matched on the item's ID within its response, or on the call ID for a function call and its output.
Order independence ¶
The record and the live stream reach a client through two paths, and an entry is written before the live event that follows it is queued, so a follower can deliver the entry first. The view therefore remembers what has landed and ignores a live event for an item that has: an entry never leaves a ghost behind it. A landed item is shown once, from the record; an overlay item is shown once, until its entry lands.
The recorder's lags ¶
The overlay waits for the entry, never for the event.
- A live item_end is not a commit. A model item that completes before the stream names its response is written at response_end, so its overlay copy stays through agentturn.ItemEnd and agentturn.ResponseEnd until the entry lands.
- A config entry is written by the next entry-writing event, so the record's model lags the model of the turn running. Both are reported: Model.Config is the record's, Turn.Model the turn's.
- A run's end flushes what is left of its overlay, but only once the record holds the run's end entry as well, which is written after everything the run wrote. Flushing at the live event alone would drop an item whose entry the follower has not delivered yet.
Limits ¶
An item with no ID, which only the loop appends (a prompt, a steered message), has no key to reconcile on and is never overlaid: the recorder writes it in the barrier of its item_end, so it is on the record before the model is called. A function call output is not overlaid either; the call row carries the result until the output lands. A model that streams items with no ID would not show them live.
A View is not safe for concurrent use; a client drives it from one goroutine.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Usage ¶
func Usage(path []agentsession.Entry) (openresponses.Usage, map[string]openresponses.Usage)
Usage sums the token usage of every model call on a path, split by the model each call was made under. It counts responses and the folds, failed or not.
Types ¶
type Branch ¶
type Branch struct {
// Leaf is the item the branch rests on (Model.Leaves holds the same
// IDs).
Leaf string
// Label names the branch by its newest message: who wrote it ("agent"
// for the assistant role) and its first words. A branch with no
// message on it is labelled "(no message)".
Label string
// Role is the role of that message.
Role string
// RunID is the run of the nearest run entry at or behind the tip.
RunID string
// Time is when the tip entry was written.
Time time.Time
// Current is set for the branch the view is on.
Current bool
}
Branch is one branch tip of the session, for a tree view.
type Call ¶
type Call struct {
CallID string
Name string
Args string
// Schema is the parameters schema of the tool the call names, as the
// config in force where the call sits on the line holds it: the tool
// the call was made against, which a later config may have changed
// or dropped. A live call takes the config in force at the end of
// the line. It is nil when the config names no such function tool,
// and for a child call, which another agent's tools made.
Schema json.RawMessage
State CallState
// Partial is the latest progress of a running tool.
Partial string
// Output is what the model sees, once the call has ended.
Output string
// Committed is set when the output is on the record, so the call is
// answered for good; before that Output is live.
Committed bool
// Verdict and Reason are the last policy decision the record holds
// for the call, and Reason the question of a deferred one.
Verdict string
Reason string
// Children are the calls this call's tool made, live only.
Children []Call
}
Call is how a function call stands.
type CallState ¶
type CallState int
CallState says how far a call got.
const ( // CallOpen: the call is on the record or the stream and has not // reached its tool. CallOpen CallState = iota // CallRunning: the call was handed to its tool. CallRunning // CallEnded: the call ended and Output holds what the model sees. CallEnded // CallBlocked: a policy refused the call; Output says why. CallBlocked // CallDeferred: the call waits for an answer. CallDeferred // CallCutOff: an abort or a failure ended the run with the call // unanswered. It is not a question; the next prompt answers it. CallCutOff )
Call states.
type Fold ¶
type Fold struct {
// FirstKept is the entry the context keeps from: everything before it
// on the path is replaced by the summary in the model's request, and
// stays on the record.
FirstKept string
// SummaryLen is the summary's text length in runes.
SummaryLen int
// Pinned is how many items the compaction carries over whole.
Pinned int
// TokensBefore is the estimate that triggered the fold, 0 if not
// recorded.
TokensBefore int
}
Fold is what a compaction entry says it folded.
type Link ¶
type Link struct {
// Rel is the link's relation: agentsession.RelSubsession, RelPeer,
// RelContinuedIn, RelForkOf or RelJudgedBy.
Rel string
// Session is the other session. It is empty for a callee in another
// system that published no session ID.
Session string
// CallID is the call that spawned a subsession or reached a peer,
// when the link says.
CallID string
// Entry is the link entry's own ID.
Entry string
// URL, Task and Context name a callee in another system, reached
// over a protocol such as A2A, on a subsession or peer link: the
// endpoint the call was sent to, the callee's task (empty when it
// answered without one) and its conversation. URL is empty for a
// subsession of this store.
URL string
Task string
Context string
// CancelSent is set when a cancel notice names this link: the caller
// told the callee it no longer wanted the work and did not wait. It
// does not say the work stopped.
CancelSent bool
}
Link is a link entry of the session: a subsession it spawned, a callee in another system, a successor it was continued in, a fork or a judge. A cancel notice is not a link of its own: it marks the callee link it names (CancelSent).
type Model ¶
type Model struct {
// Session is the followed session's ID.
Session string
// Leaf is the entry the rendered path ends at, and Leaves every
// branch tip the session has.
Leaf string
Leaves []string
// Tail is the last entry of the viewed line: the leaf and the
// bookkeeping behind it. The line is Session.Path(Tail).
Tail string
// Entries is how many entries the session held at this step.
Entries int
// Branches describes the tips a tree shows, newest first. They are
// Leaves less a leaf label that only marks a head (see branchTips),
// plus the viewed line.
Branches []Branch
// Links are the session's link entries, on any branch: its
// subsessions, its peers, its successor. A cancel notice is folded
// into the link it names.
Links []Link
// Origin is where the session came from, by its header.
Origin Origin
// Config is the model in force at the leaf, by the record.
Config string
// Usage is the token usage of the viewed line's model calls, and
// UsageByModel the same split by the model each call was made under.
Usage openresponses.Usage
UsageByModel map[string]openresponses.Usage
// Run is the last run on the viewed line, by the record, and Worked
// how long the line's runs that ended took, summed: the session's
// time working.
Run Run
Worked time.Duration
// Rows is the path's visible items, then the live rows.
Rows []Row
Turn Turn
Permissions []Permission
// CutOff lists the calls the last run left unanswered without asking
// anyone: it was aborted or failed. They are shown as cut off.
CutOff []Permission
// Questions are the questions running calls wait on the user for,
// in the order they were asked: a sub-agent's call its policy asks
// about, a tool's own question.
Questions []agentturn.Question
// Queued are the inputs waiting to join the conversation, in the
// order they were accepted, from the record's path to its head
// (agentsession.Queued). An input a run did not take before it
// ended is written again after the run's end by the recorder, so it
// stays listed until the next run appends it.
Queued []Queued
}
Model is what a client renders.
func At ¶
func At(s *agentsession.Session, leaf string) Model
At renders the line of s that ends at leaf, as a view attached to the session with its head there would, and nothing live: no overlay, and no turn. It reads s and keeps nothing, so a caller can pass a session it read for the purpose, the session a fork came from or one a link names, and show it without following it. Its Permissions and CutOff are the record's reading of the line, which a read-only display does not offer to answer.
type Origin ¶
type Origin struct {
// ParentSession is the header's parent_session: the origin of a
// fork, the predecessor of a continuation, or the parent of a
// subsession.
ParentSession string
// Base is the entry of ParentSession the session was forked at, "" for
// a session that is not a fork.
Base string
// SpawnedBy is the header's spawned_by: the call that spawned the
// session, for a subsession.
SpawnedBy string
}
Origin is where a session came from, from its header: the session it was forked, continued or spawned from, and the entry it was forked at.
type Permission ¶
type Permission struct {
CallID string
Name string
Args string
// Question is the reason the call was deferred, as a front puts it
// to the user.
Question string
// Subject is the part of the call the question is about, when the
// policy decided on a part (one command of a compound line), from
// the decision that deferred it; "" for the whole call. The record
// does not hold it, so a permission read from the record alone has
// none.
Subject string
// MayHaveRun is set for a call that was handed to its tool before
// it was left unanswered: a call held after its dispatch, or one an
// abort cut off while it ran. Its effects may have happened.
MayHaveRun bool
Reason string
}
Permission is a call that waits for the caller.
type PriceSummary ¶
type PriceSummary struct {
// Total is the line's cost in US dollars, valid when Priced is true.
Total float64
// Priced says every model with usage on the line was priced.
Priced bool
// Unpriced lists the models the cost source has no price for, sorted.
Unpriced []string
}
func Price ¶
func Price(byModel map[string]openresponses.Usage, cost client.Cost) PriceSummary
Price prices one model call under cost. Cost hooks are linear over the usage they are given (the price table's are), so each model's aggregate usage is priced once. A nil cost leaves the line unpriced and unnamed.
type Queued ¶ added in v0.0.8
type Queued struct {
// EntryID is the queued entry.
EntryID string
// Mode is agentsession.ModeSteer or agentsession.ModeFollowUp.
Mode string
Item openresponses.Item
}
Queued is an input the agent accepted into its queue, a steer or a follow-up, that the conversation does not hold yet: a queued entry on the record that no item entry names as its source. It leaves the list in the same step its item becomes a row, so it is never shown twice.
type Row ¶
type Row struct {
// EntryID is the entry that holds the item, and "" while the item is
// live only.
EntryID string
// Live is set for an overlay row: not on the record yet.
Live bool
// Open is set for a live row still streaming.
Open bool
// KeptFromModel marks a row the record holds as a custom entry: an
// item the filter kept out of the model's context. It is on the
// record, so it is shown, and a renderer may say it was not sent.
KeptFromModel bool
ResponseID string
Item openresponses.Item
// Call is set on the row of a function call.
Call *Call
// Fold is set on the row of a compaction entry: the point where the
// record folds what came before into a summary, which Item carries.
Fold *Fold
}
Row is one line of the conversation.
type Run ¶
type Run struct {
ID string
Started time.Time
// Ended is zero while the line holds no end entry for the run.
Ended time.Time
Usage openresponses.Usage
}
Run is a run on a line, by the record: when its start entry and its end entry were written, and the token use of its model calls so far. A client shows it as the current turn's figures.
type Turn ¶
type Turn struct {
State TurnState
RunID string
// Number is the turn within the run, from 1, and 0 between runs.
Number int
// Model is the model the turn is calling, which can be ahead of
// [Model.Config]: the config entry is written by the next
// entry-writing event.
Model string
// Withheld is set when the last run ended because a guard withheld
// a message: the text that streamed was never committed.
Withheld bool
// Cause is what stopped the last run, when it ended with
// [agentturn.ReasonStopped] (a turn limit, a hook, a guard, a tool
// that ended it, a refusal), and "" otherwise. It is the live end's:
// the record does not hold it.
Cause agentturn.StopCause
// Err is what failed the last run, when it ended with
// [agentturn.ReasonError], and nil otherwise: the live end's.
Err error
// Attempt is the number of the model call that failed and is being
// retried, 0 when none is.
Attempt int
}
Turn is the state of the run, from live events alone.
type TurnState ¶
type TurnState int
TurnState says what the agent is doing.
type View ¶
type View struct {
// contains filtered or unexported fields
}
View reconciles the record with the live stream.
func (*View) Live ¶
Live applies a live event: one of agentturn's, as a client.Source delivers it and client.Copy copies it. The view keeps what it is given, so an event must share nothing the agent goes on changing. An event the view does not read is ignored.
func (*View) Record ¶
func (v *View) Record(ch agentsession.Change)
Record applies a change from the record's follow.