soev for developers
soev-agentsReference

soev_agents.domain

Record what happens in a thread as events, and read the events back from the thread's trace.

An is one immutable fact: an input, a model's output, a 's result, a failure. A keeps nothing else, so a stored reads the same in each process and after each deploy. are what the model is shown and can refer to again by id. record the numbers that the model cited.

Traces

A is a 's whole record, in . A reads the part of the that the gives it.

Trace

classTrace(events=())

A 's whole record: every of every , in .

A is a value: it holds and has no identity of its own. A , a and a each get a of the as a Trace, never the itself. The query methods select and apply no rule.

Example

from soev_agents.domain import ModelOutput, ToolCall, Trace


def tool_calls(view: Trace) -> tuple[ToolCall, ...]:
    output = view.latest(ModelOutput)
    if output is not None and output.calls_tools:
        return output.tool_calls
    return ()

Make a of events.

parameventsIterable[Event]
= ()

The , in . The keeps them in the order given and does not sort them.

methodlast() -> Event | None

Return the last of the , or None for an empty .

methodlatest[T: Event](event_type) -> T | None

Return the last of a type.

paramevent_typetype[T]

The class. An of a subclass also matches.

Returns

T | None

The last that is an instance of event_type, or None if the has none.

methodby_type[T: Event](event_type) -> tuple[T, ...]

Return every of a type, in the order of the .

paramevent_typetype[T]

The class. An of a subclass also matches. Event selects all .

Returns

tuple[T, ...]

Each that is an instance of event_type. Empty if the has none.

methodstream(name) -> tuple[Event, ...]

Return the of one , in the order of the .

paramnameStream

The name of the . The below it are not included.

Returns

tuple[Event, ...]

Each whose stream is name. Empty if the has none.

methodscope_of(name) -> Stream

Return the that heads the of the name.

A is the part of the that one run produced: the 's, or one 's. The root stream heads the 's , and each whose first is an Input heads a 's .

paramnameStream

The name of a .

Returns

Stream

The nearest of name and its ancestors that is the root stream or starts with an Input in this .

methodview(name) -> Trace

Return the that a in the name can read.

These are its own , everything forked below it, and its ancestors up to the point it forked from. The excludes a sibling stream, because its can arrive at any time, and nothing computed from a can depend on timing.

The also stays inside the of name. A 's holds nothing of its parent before the , and a parent's holds nothing of a 's .

paramnameStream

The name of the that reads.

Returns

Trace

A new with the of the , in the order of this . An ancestor's stop after the that name forked after.

Stream

type aliasStream = str

The name of a , which gives the place of the in the tree of streams of the .

Each starts with one , root. A that a starts at the search, after 3 of the root, is root/search@3. A 's carries its index after #, as in root/research#0@7.

Events

An is one fact in a . Subclass Event for an type of your own.

Event

modelEvent

One recorded fact. Subclasses add their fields.

An never changes. A creates it with its fields only. The stamps stream, origin and version, and the store stamps seq and ts when it appends the . Validation fails for an with only one of seq and ts.

For an type of your own, subclass Event with a type field whose default is the . Then add the class to the event_types of the whose record it.

Example

from typing import Literal

from soev_agents.domain import Actor, Event


class Escalated(Event):
    type: Literal["escalated"] = "escalated"
    actor: Actor = "system"
    reason: str
attributestreamStream
= …

The name of the that the belongs to.

attributeseqint | None
= None

The place of the in its , from 0, or None before the store appends it.

attributeactorActor

Which kind of party produced the .

attributeoriginNodeName | None
= None

The name of the that produced the , or None for an that no produced, such as an Input from outside.

attributetsdatetime | None
= None

When the store appended the , or None before then.

attributeversionstr | None
= None

The code that wrote the , as the names it. Nothing reads it to decide anything.

attributesealedbool

Whether the store appended the : true once seq and ts are stamped.

Actor

type aliasActor = Literal['user', 'model', 'tool', 'system']

Which kind of party produced an : user, model, tool or system.

user is the party outside the system, whoever it is. The framework sets user on each Input and Cancelled that a caller produces. The runtime records actor but does not read it to decide anything.

NodeName

type aliasNodeName = str

The name of a , unique in its . An carries the name of the that produced it.

tag

functiontag(model_type) -> str

Return the type of an class or an class.

The is the default of the class's type field. A store keeps an or an under its . To read it back, the framework looks the class up by the .

parammodel_typetype[BaseModel]

The class or class.

Returns

str

The , such as model_output for ModelOutput.

Raises:

  • TypeError: The class has no type field with a string default.

Opened

modelOpened

The 's first : which registered runs it.

attributetypeLiteral['opened']
= 'opened'

The , opened.

attributeactorActor
= 'system'

system by default.

attributeagentstr

The name of the that this runs. It is set once, when the opens.

Input

modelInput

Something that arrives from outside: a user message, a spec, an approval decision.

It starts or continues a . Its are recorded when it is accepted, so reads the alone.

A fresh input opens a . An input that responds to a Request continues the that the request was made in. Subclass it for a typed input of your own, with a type of its own.

attributetypestr
= 'input'

The , input, or the of a subclass.

attributeactorActor
= 'user'

user by default: the party outside the system.

attributepayloadJsonValue

The message or value as it arrived: any JSON.

attributemodelstr | None
= None

The model that this input asks for, or None for the deployment's default.

Request

modelRequest

The halted because it needs input from outside.

A whose last is a Request is waiting.

The Input that responds to a request is its response. The response continues the at the of the that asked. A request has no default actor: the model for a clarification, system for a .

attributetypeLiteral['request']
= 'request'

The , request.

attributekindstr

What kind of request this is, in the 's own words, such as a clarification or an approval.

attributeaboutstr | None
= None

What the asks, written for a person to read, or None.

attributeexpectsdict[str, JsonValue] | None
= None

The JSON Schema that the payload of the response must satisfy, or None to accept any JSON.

Finished

modelFinished

The stopped because the 's had no work left in the .

Recorded because only the that ran the knows where its work ends, and that is not kept.

attributetypeLiteral['finished']
= 'finished'

The , finished.

attributeactorActor
= 'system'

system by default.

Cancelled

modelCancelled

The was ended from outside the .

attributetypeLiteral['cancelled']
= 'cancelled'

The , cancelled.

attributeactorActor
= 'user'

user by default: the caller that cancelled.

Failure

modelFailure

A raised instead of returning: no result exists for the named in .

The halted there. An error the can react to (a 404, an empty retrieval) is not a Failure: it is recorded as data on its own type.

attributetypeLiteral['failure']
= 'failure'

The , failure.

attributeactorActor
= 'system'

system by default.

attributeerrorstr

What went wrong, as the runtime saw it.

attributetransientbool
= False

True if the same can succeed when it runs again, such as after a timeout or an outage. False if it fails again until something changes.

BudgetExceeded

modelBudgetExceeded

The made more model calls that call than its allows.

The of the last model output did not run, and the runtime told the model to give its final answer. The records no setting of the .

attributetypeLiteral['budget_exceeded']
= 'budget_exceeded'

The , budget_exceeded.

attributeactorActor
= 'system'

system by default.

Model calls and tool calls

A ModelOutput records what a model call gave, and a ToolOutput records the result of a .

ModelOutput

modelModelOutput

One model output: the text, the it asks for, its reasoning, why it stopped and what it cost.

Whether it is a message or a is read off tool_calls. A model records it with the out of content and real ids in its . markers and each call's translated give back what the model wrote.

attributetypeLiteral['model_output']
= 'model_output'

The , model_output.

attributeactorActor
= 'model'

model by default.

attributecontentstr

The model's text, without its . Empty if the model only called .

attributemarkerstuple[Marker, ...]
= ()

The taken out of content, in text order. Empty if the does not cite.

attributemodelstr | None
= None

The model that produced the output: the model of the call, unless the model names another, as a fallback does. None if no model call produced the .

attributetool_callstuple[ToolCall, ...]
= ()

The that the model asked for. The ToolOutput with the result of each call carries the same call_id.

attributereasoningstr | None
= None

The model's reasoning text, or None if it produced none.

attributefinish_reasonFinishReason | None
= None

Why the model stopped, or None if the did not say.

attributeusageTokenUsage | None
= None

The token counts of the call, or None.

attributeprompt_charactersint | None
= None

The characters of the ChatRequest of the call: its messages, the in them and the offered. With usage.prompt_tokens, the next call estimates only what was added. None if not counted.

attributerequest_hashstr | None
= None

The SHA-256 of the ChatRequest that the framework built for the call, as canonical JSON. A rebuild of the ChatRequest from the before the call gives the same hash, unless the code changed. None if not recorded.

attributecalls_toolsbool

Whether the model asked for at least one .

FinishReason

type aliasFinishReason = Literal['stop', 'length', 'tool_calls', 'content_filter']

Why a model stopped, as the model reports it.

stop is the end of the output, length a token limit, tool_calls a stop to call , and content_filter a stop by the provider's filter.

TokenUsage

modelTokenUsage

Token counts for one model call.

attributeprompt_tokensint

The tokens in what the model was given.

attributecompletion_tokensint

The tokens that the model produced.

attributetotal_tokensint

The total, as the provider reported it.

ToolCall

modelToolCall

One that the model asked for, with real ids for its numbers and .

Put each translated value back to get the call as the model wrote it.

attributeidstr

The call's id. The ToolOutput with the result of the call carries it as call_id.

attributenamestr

The 's name, as the model saw it.

attributeargumentsdict[str, JsonValue]

The arguments that the receives. An argument that names an holds its real id. An argument that names a result holds the call id of that result's call. A value that named nothing that the argument accepts is None.

attributetranslatedtuple[Translation, ...]
= ()

Each value of arguments that replaced a number or a handle that the model wrote.

Translation

modelTranslation

One argument value that the model wrote as an number or a .

The call's arguments hold the real id or the call id that the value named instead.

attributepathstr

Where the value sits in the arguments: document_id, or documents.1 for an item of a list.

attributewrittenJsonValue

What the model wrote there.

ToolOutputBase

modelToolOutputBase

The result of one , linked to the call by call_id.

Each result has a . The base is never recorded itself: ToolOutput carries what a returned, and Reopened names what is shown again.

attributeactorActor
= 'tool'

tool by default.

attributecall_idstr | None
= None

The id of the that this is the result of.

ToolOutput

modelToolOutput

The result of one , linked by call_id. error is data the model reacts to.

Its are shown before text.

A error is never a Failure: the model reads error and continues. Subclass it for a that records typed fields, with a type of its own.

attributetypestr
= 'tool_output'

The , tool_output, or the of a subclass.

attributedataJsonValue
= None

The 's result, as JSON.

attributetextstr | None
= None

The 's result as text that the model reads as written, before data. It never holds an id.

attributecitationstuple[Citation, ...]
= ()

The sources that text cites, each at its offset in text, which holds no . A 's result that is handed back carries them. The model reads a there, in its own .

attributeerrorstr | None
= None

Why the could not give a result, or None if it could. The model reacts to it as data.

attributeimagestuple[Image, ...]
= ()

Pictures that the model is shown with the result, such as rendered pages. The HTTP of a leave them out.

Image

modelImage

A picture that a shows the model with its result, such as a rendered page.

attributedatabytes

The image's bytes. JSON holds them as base64 text, and validation accepts both encodings.

attributemimestr
= 'image/png'

The image's media type, image/png by default.

Reopened

modelReopened

Content shown again that was shortened or removed earlier, named by its ids only.

What the model sees is drawn from the earlier results when the context is rendered, so nothing is stored twice.

attributetypestr
= 'reopened'

The , reopened.

attributereopened_elementstuple[str, ...]
= ()

The real ids of the shown again.

attributereopened_resultstuple[str, ...]
= ()

The call ids of the whose whole results are shown again.

Compaction

modelCompaction

A summary that replaces the before a kept in every later request to the model.

The kept is the one at kept_from_seq in kept_from_stream. The keeps the that the summary replaces.

attributetypeLiteral['compaction']
= 'compaction'

The , compaction.

attributeactorActor
= 'model'

model by default.

attributesummarystr

The summary that the model wrote of the it replaces, without its .

attributemarkerstuple[Marker, ...]
= ()

The taken out of summary, in text order.

attributekept_from_seqint

The seq of the first still sent in full, in kept_from_stream. Every before it is sent only as the summary.

attributekept_from_streamStream
= …

The of the first still sent in full. A summary written in a can keep from an of a above it.

attributemodelstr | None
= None

The model that wrote the summary.

attributeusageTokenUsage | None
= None

The token counts of the call that wrote the summary.

attributerequest_hashstr | None
= None

The SHA-256 of the ChatRequest that the framework built for the call that wrote the summary, as canonical JSON. None if not recorded.

methodfirst_kept(events) -> int

Return the index in events of the first that this summary keeps.

parameventsSequence[Event]

The that the summary applies to, such as the of a .

Returns

int

The index of the at kept_from_seq in kept_from_stream. len(events) if events do not hold it, so the summary replaces them all.

Effects

An EffectIntent records an action outside the , and an EffectResult records its result.

EffectIntent

modelEffectIntent

The declaration, before anything happens, that the will now act outside the .

kind is the declared verb, args the argument.

For an without an EffectResult in the log, it is unknown whether the world changed.

attributetypeLiteral['effect_intent']
= 'effect_intent'

The , effect_intent.

attributeactorActor
= 'system'

system by default.

attributekindstr

The declared verb, such as refund or send_mail.

attributeargsdict[str, JsonValue]

The argument that the runs with, before it runs.

EffectResult

modelEffectResult

The result of one , linked by intent_seq. error is data the routes on.

The stamps intent_seq. An result has no default actor: system if the runtime saw the result, user if a party outside the system reported the result.

attributetypeLiteral['effect_result']
= 'effect_result'

The , effect_result.

attributeintent_seqint | None
= None

The seq of the EffectIntent that this is the result of.

attributedataJsonValue
= None

What the world gave back, as JSON.

attributeerrorstr | None
= None

A definitive refusal from the world, or None if there was none.

Elements

An is something the model is shown and can refer to again by id: in a argument or in a .

Element

modelElement

Something the model is shown and can refer to again. Subclass Reference or Source, never this.

The class of an tells what the is. A class is stored under its name in kebab case (KnowledgeBase as knowledge-base) unless it declares type itself. So when you rename a class, its stored name changes too, and stored no longer read back. Declare the old name as type to rename safely.

An is immutable. Add each subclass to the element_types of the whose record it.

attributetypestr
= 'element'

The of the class, which reads a stored back as the right class.

attributeidstr

The real id. The model never sees it, only the number that the is shown under.

attributerefstr | None
= None

The real id of the that this one is part of, such as a passage's document. None if it is part of nothing.

attributepropertiesMapping[str, JsonValue]
= {}

What the that recorded the passed through, such as a title or a page. Read the keys that you know. JSON values only, so the reads back exactly as it was recorded.

Reference

modelReference

An the model can name, for example as a argument, but not cite: it saw no content of it.

Subclass it once for each kind of thing, such as a document in a listing or a knowledge base.

Source

modelSource

An whose content the model saw, and so the only kind it can cite.

Subclass it once for each kind of thing, such as a passage or a web page. A source must name the that it is part of in ref: validation fails without it.

attributetextstr

The material that the retrieved, a verbatim quote of the that ref names. The model sees it as the 's renders it, which can be shortened.

ElementEvent

modelElementEvent

An that shows to the model.

The can be an input's attachments, a 's documents and passages, or the retrieved sources of an 's own type. Every shown is numbered by first appearance in the , so the model can cite it and name it to . Subclass it for an type of your own that shows .

attributeelementstuple[SerializeAsAny[Element], ...]
= ()

What the shows that the model can refer to again, such as attached documents, listed documents or retrieved passages. Each keeps its own class when the is read back.

ElementTypes

classElementTypes(*types)

The classes stored are read back into, by their type .

A set never changes: including returns a new one.

Make the set of classes.

paramtypestype[Element]

The classes to read.

Raises:

  • ValueError: Two classes share a type .
methodincluding(*types) -> ElementTypes

Return a new set with types added. This set does not change.

paramtypestype[Element]

The classes to add. A class that the set holds already is kept once.

Raises:

  • ValueError: Two classes share a type .
methoddecode(data) -> Element

Read a stored back into its class.

paramdataMapping[str, Any]

The as JSON data, with its type .

Returns

Element

The , as an instance of the class that its names.

Raises:

  • UnknownElementTypeError: The 's type is not in this set.
  • pydantic.ValidationError: The data does not fit the class.

UnknownElementTypeError

errorUnknownElementTypeError

A stored has a type that is not among the types that it is read with.

ElementTypes.decode raises it, and so does EventTypes.decode for an that holds such an . Add the class to the 's element_types. The error's argument is the unknown .

Citations

A is one number that the model cited, and the source that the number named.

Citation

modelCitation

One number that a model output cited, at an offset in its cleaned text, and what it resolved to.

A that cites several numbers gives one for each number.

attributeatint

Where the stood in the text without , in characters (Unicode code points).

attributestatusLiteral['resolved', 'invalid']

resolved if the number named a source, invalid if it named none.

attributesourcestr | None
= None

The real id of the cited source, or None if the is invalid.

attributedocumentstr | None
= None

The real id of the that the source is part of, or None if the is invalid.

attributereasonstr | None
= None

Why an invalid did not resolve, or None if it resolved.

Marker

modelMarker

A that the model wrote, taken out of its text.

A records where it stood, the exact characters cut out there, and the numbers that it cited. Put each text back at its at to get the text as the model wrote it (see inserted).

attributeatint

Where the stood in the text without , in characters (code points).

attributetextstr

The characters cut out there: the and the spaces before it.

attributecitedtuple[CitedNumber, ...]

The numbers that the cited, in the order written.

CitedNumber

modelCitedNumber

One number inside a : what the model wrote, and the real id of the Source it named then.

attributewrittenint

The number as the model wrote it.

attributesourcestr | None
= None

The real id of the source that the number named when the model wrote it, or None if it named none.

inserted

functioninserted(text, pieces) -> str

Return text with each piece put in at its offset.

inserted(text, [(m.at, m.text) for m in markers]) gives back the text as the model wrote it.

paramtextstr

The text without the pieces.

parampiecesSequence[tuple[int, str]]

Pairs of an offset in text, in characters, and the string to put in there. The pairs can come in any order. Pieces at one offset keep their order.

Returns

str

The text with every piece put in.

On this page