msgmodel

package
v0.4.2-rc.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Cursor encoding: a pagination cursor is `{id, time}` encoded as unpadded RFC 4648 URL-safe base64.

Event names and payloads. The runtime's bus owns registration and delivery; this package owns the public names, versions, aggregate key, and wire payload shapes.

Error conversion. Stream-error parsing lives here because it is a pure JSON decision.

Package msgmodel is the persisted message and part model: the assistant, user and tool parts a session stores, the conversion pipeline from stored messages to the model-facing message list, the compaction filter, and the part-assembly helpers the step loop and the stream processor build on.

Opaque provider objects (metadata, tool input, structured output) are kept as raw JSON so their bytes round-trip unchanged; the doom-loop guard compares tool inputs byte for byte. Optional fields are pointers with omitempty. Every discriminated union re-asserts its own tag in MarshalJSON, and parts are stored and type-switched as VALUES, never pointers.

Storage functions. Query construction is behind Store; Page does the descending (time,id) pagination with a one-row lookahead, hydration, and per-page reversal. Stream returns newest-first order.

Index

Constants

View Source
const (
	EventMessageUpdated     = "message.updated"
	EventMessageRemoved     = "message.removed"
	EventMessagePartUpdated = "message.part.updated"
	EventMessagePartDelta   = "message.part.delta"
	EventMessagePartRemoved = "message.part.removed"

	SyncEventVersion = 1
	SyncAggregateKey = "sessionID"
)
View Source
const (
	PartTypeText       = "text"
	PartTypeReasoning  = "reasoning"
	PartTypeFile       = "file"
	PartTypeTool       = "tool"
	PartTypeStepStart  = "step-start"
	PartTypeStepFinish = "step-finish"
	PartTypeCompaction = "compaction"
)

Part `type` discriminants.

View Source
const (
	ToolStatusPending   = "pending"
	ToolStatusRunning   = "running"
	ToolStatusCompleted = "completed"
	ToolStatusError     = "error"
)

ToolState `status` discriminants.

View Source
const (
	ErrNameUnknown             = "UnknownError"
	ErrNameMessageOutputLength = "MessageOutputLengthError"
	ErrNameMessageAborted      = "MessageAbortedError"
	ErrNameStructuredOutput    = "StructuredOutputError"
	ErrNameContextOverflow     = "ContextOverflowError"
	ErrNameAPI                 = "APIError"
)

AssistantError `name` discriminants.

View Source
const (
	ToolAbortedError     = "Tool execution aborted"
	ToolInterruptedError = "[Tool execution was interrupted]"
	ToolCompactedOutput  = "[Old tool result content cleared]"
)

Fixed strings the settlement path writes. ToolAbortedError is replayed to the model as the tool's errorText; ToolInterruptedError is what a pending or running tool replays as.

View Source
const (
	UIToolInputStreaming  = "input-streaming"
	UIToolInputAvailable  = "input-available"
	UIToolOutputAvailable = "output-available"
	UIToolOutputError     = "output-error"
)

UI part `state` values.

View Source
const SyntheticAttachmentPrompt = "Attached media from tool result:"

SyntheticAttachmentPrompt opens the synthetic user message that carries media extracted from a tool result.

Variables

View Source
var ErrNotFound = errors.New("msgmodel: not found")

Functions

func DifferentModel

func DifferentModel(model Model, msg Assistant) bool

DifferentModel is a plain string comparison of "<providerID>/<modelID>" between the model about to be called and the model that produced the historical turn. When they differ, that turn's provider-specific metadata is stripped below.

func EncodeCursor

func EncodeCursor(input Cursor) (string, error)

func IsMedia

func IsMedia(mime string) bool

IsMedia reports whether a mime type is an image or a PDF.

func IsRecord

func IsRecord(v RawObject) bool

IsRecord reports a JSON object: neither null nor an array.

func SameInput

func SameInput(a, b RawObject) bool

SameInput is the doom-loop equality test: two tool inputs compared as stored bytes. Both sides are already verbatim, so this only has to normalise insignificant whitespace; key order is deliberately NOT normalised.

func SetMessageIDFactoryForTesting

func SetMessageIDFactoryForTesting(f func() string) func()

SetMessageIDFactoryForTesting swaps the synthetic-message id source and returns a restore func.

func SpreadAbortedToolState

func SpreadAbortedToolState(prev ToolState, now uint64) (json.RawMessage, error)

SpreadAbortedToolState is the cleanup drain's force-write: `status:"error"`, `error:"Tool execution aborted"`, `metadata:{...existing, interrupted:true}` and `time.start` taken from the previous state, or `now` when the state has none (`pending` does not). It is a spread over the previous state, `{...state, status, error, metadata, time}`, so a `pending` state's `raw` and a `running` state's `title` survive into an object ToolStateError does not declare. Returned as raw JSON because those fields have no typed home.

func SpreadObject

func SpreadObject(base RawObject, overrides ...RawField) json.RawMessage

SpreadObject is the object spread `{...base, k1: v1, k2: v2}`: an overridden key keeps the position it had in base and takes the new value; a new key is appended in the order given. Key order is load-bearing: the doom-loop guard compares the stored bytes verbatim.

func SpreadToolState

func SpreadToolState(prev ToolState, overrides ...RawField) (json.RawMessage, error)

SpreadToolState is `{...prev, ...overrides}` for any transition: the tool-call → running step as well as the cleanup drain.

func TruncateToolOutput

func TruncateToolOutput(text string, maxChars *float64) string

TruncateToolOutput keeps the first maxChars characters of a tool output and appends a marker naming how many were dropped. A nil or non-positive limit leaves the text alone.

Types

type APIError

type APIError struct {
	Message         string    `json:"message"`
	StatusCode      *uint64   `json:"statusCode,omitempty"`
	IsRetryable     bool      `json:"isRetryable"`
	ResponseHeaders RawObject `json:"responseHeaders,omitempty"`
	ResponseBody    *string   `json:"responseBody,omitempty"`
	Metadata        RawObject `json:"metadata,omitempty"`
}

APIError is the `data` payload of the APIError variant. `responseBody` is searched by substring by the error classifiers, so it is a string kept byte-for-byte, never re-encoded JSON.

type AbortFailure

type AbortFailure struct{ Message string }

Marker errors FromError classifies by type.

func (AbortFailure) Error

func (e AbortFailure) Error() string

type Assistant

type Assistant struct {
	MessageBase
	Role       string          `json:"role"`
	Time       AssistantTime   `json:"time"`
	Error      *AssistantError `json:"error,omitempty"`
	ParentID   string          `json:"parentID"`
	ModelID    string          `json:"modelID"`
	ProviderID string          `json:"providerID"`
	// Mode always carries the same value as Agent; both are persisted.
	Mode       string        `json:"mode"`
	Agent      string        `json:"agent"`
	Path       AssistantPath `json:"path"`
	Summary    *bool         `json:"summary,omitempty"`
	Cost       float64       `json:"cost"`
	Tokens     Tokens        `json:"tokens"`
	Structured RawValue      `json:"structured,omitempty"`
	Variant    *string       `json:"variant,omitempty"`
	// Finish is one of the unified finish reasons (orclient.Finish*).
	Finish *string `json:"finish,omitempty"`
	// Upstream is the endpoint that served the message's last step, copied
	// from the step-finish part so a message-level consumer (the agent
	// summary) can attribute cache misses without walking parts.
	Upstream string `json:"upstream,omitempty"`
}

func (Assistant) MarshalJSON

func (m Assistant) MarshalJSON() ([]byte, error)

func (Assistant) MessageID

func (m Assistant) MessageID() string

func (Assistant) MessageRole

func (m Assistant) MessageRole() string

type AssistantError

type AssistantError struct {
	Name string          `json:"name"`
	Data json.RawMessage `json:"data"`
}

AssistantError is `{name, data}`. `Data` stays raw so an error minted elsewhere round-trips verbatim; the typed constructors below cover the seven known variants.

func FromError

func FromError(value any) AssistantError

FromError classifies a failure value into the persisted AssistantError shape. `value` is the raw `error` payload of a model stream, a Go error, or one of the marker types above.

func NewAPIError

func NewAPIError(data APIError) AssistantError

func NewContextOverflowError

func NewContextOverflowError(data ContextOverflowErrorData) AssistantError

func NewMessageAbortedError

func NewMessageAbortedError(message string) AssistantError

func NewMessageOutputLengthError

func NewMessageOutputLengthError() AssistantError

func NewStructuredOutputError

func NewStructuredOutputError(message string, retries uint64) AssistantError

func NewUnknownError

func NewUnknownError(message string) AssistantError

func (*AssistantError) IsAborted

func (e *AssistantError) IsAborted() bool

IsAborted is a bare `name` comparison, nothing more.

type AssistantPath

type AssistantPath struct {
	Cwd  string `json:"cwd"`
	Root string `json:"root"`
}

AssistantPath is Assistant.path.

type AssistantTime

type AssistantTime struct {
	Created   uint64  `json:"created"`
	Completed *uint64 `json:"completed,omitempty"`
}

AssistantTime is Assistant.time.

type CompactionPart

type CompactionPart struct {
	PartBase
	Type        string  `json:"type"`
	Auto        bool    `json:"auto"`
	Overflow    *bool   `json:"overflow,omitempty"`
	TailStartID *string `json:"tail_start_id,omitempty"`
}

func (CompactionPart) Base

func (p CompactionPart) Base() PartBase

func (CompactionPart) MarshalJSON

func (p CompactionPart) MarshalJSON() ([]byte, error)

func (CompactionPart) PartType

func (p CompactionPart) PartType() string

type ContextOverflowErrorData

type ContextOverflowErrorData struct {
	Message      string  `json:"message"`
	ResponseBody *string `json:"responseBody,omitempty"`
}

ContextOverflowErrorData is the ContextOverflowError payload.

type ConvertOptions

type ConvertOptions struct {
	IgnoreIncompleteToolCalls bool
	Tools                     map[string]ToolModelOutputFn
}

ConvertOptions are the conversion options.

type Cursor

type Cursor struct {
	ID   string  `json:"id"`
	Time float64 `json:"time"`
}

func DecodeCursor

func DecodeCursor(input string) (Cursor, error)

type FileContent

type FileContent struct {
	Type            string   `json:"type"`
	MediaType       string   `json:"mediaType"`
	Filename        RawValue `json:"filename,omitempty"`
	Data            string   `json:"data"`
	ProviderOptions RawValue `json:"providerOptions,omitempty"`
}

FileContent is a file content part.

type FileDiff

type FileDiff struct {
	File      string  `json:"file"`
	Patch     string  `json:"patch"`
	Additions float64 `json:"additions"`
	Deletions float64 `json:"deletions"`
}

type FilePart

type FilePart struct {
	PartBase
	Type     string          `json:"type"`
	Mime     string          `json:"mime"`
	Filename *string         `json:"filename,omitempty"`
	URL      string          `json:"url"`
	Source   *FilePartSource `json:"source,omitempty"`
}

func (FilePart) Base

func (p FilePart) Base() PartBase

func (FilePart) MarshalJSON

func (p FilePart) MarshalJSON() ([]byte, error)

func (FilePart) PartType

func (p FilePart) PartType() string

type FilePartSource

type FilePartSource struct {
	Text       FilePartSourceText `json:"text"`
	Type       string             `json:"type"`
	Path       string             `json:"path,omitempty"`
	Range      *LSPRange          `json:"range,omitempty"`
	Name       string             `json:"name,omitempty"`
	Kind       *uint64            `json:"kind,omitempty"`
	ClientName string             `json:"clientName,omitempty"`
	URI        string             `json:"uri,omitempty"`
}

FilePartSource is the file / symbol / resource source union, discriminated on `type`. Nothing in this package reads it, so it is a single carrier struct rather than an interface, with the shared `text` first.

type FilePartSourceText

type FilePartSourceText struct {
	Value string `json:"value"`
	Start uint64 `json:"start"`
	End   uint64 `json:"end"`
}

FilePartSourceText is the text span a file part source covers.

type Info

type Info interface {
	MessageRole() string
	MessageID() string
	json.Marshaler
}

Info is the User | Assistant union.

func UnmarshalInfo

func UnmarshalInfo(raw []byte) (Info, error)

UnmarshalInfo dispatches on `role`.

type LSPPosition

type LSPPosition struct {
	Line      uint64 `json:"line"`
	Character uint64 `json:"character"`
}

LSPPosition / LSPRange locate a symbol source in its file.

type LSPRange

type LSPRange struct {
	Start LSPPosition `json:"start"`
	End   LSPPosition `json:"end"`
}

type MessageAbortedErrorData

type MessageAbortedErrorData struct {
	Message string `json:"message"`
}

MessageAbortedErrorData is the MessageAbortedError payload.

type MessageBase

type MessageBase struct {
	ID        string `json:"id"`
	SessionID string `json:"sessionID"`
}

MessageBase is the id pair every message carries.

type MessageConversionError

type MessageConversionError struct {
	Message string
}

MessageConversionError is the only error ConvertToModelMessages raises.

func (*MessageConversionError) Error

func (e *MessageConversionError) Error() string

type MessageOutputLengthErrorData

type MessageOutputLengthErrorData struct{}

MessageOutputLengthErrorData is the MessageOutputLengthError payload: no fields.

type MessageRecord

type MessageRecord struct {
	Info        Info
	TimeCreated float64
}

type Model

type Model struct {
	ProviderID string   `json:"providerID"`
	ID         string   `json:"id"`
	API        ModelAPI `json:"api"`
}

Model is the slice of a catalog model this package reads: `providerID` and `id` feed DifferentModel, `api` feeds supportsMediaInToolResult.

type ModelAPI

type ModelAPI struct {
	Npm string `json:"npm"`
	ID  string `json:"id"`
}

ModelAPI is the `api` sub-object of a catalog model: the provider SDK identifier and the provider-side model id. supportsMediaInToolResult reads both.

type ModelMessage

type ModelMessage struct {
	Role            string   `json:"role"`
	Content         any      `json:"content"`
	ProviderOptions RawValue `json:"providerOptions,omitempty"`
}

ModelMessage is one entry of the `ModelMessage[]` handed to the provider. `Content` is a string for `role:"system"` and a content-part slice otherwise.

func ConvertToModelMessages

func ConvertToModelMessages(messages []UIMessage, options *ConvertOptions) ([]ModelMessage, error)

ConvertToModelMessages is the conversion described above.

func ToModelMessages

func ToModelMessages(input []WithParts, model Model, options *ToModelOptions) ([]ModelMessage, error)

ToModelMessages converts stored messages into the model-facing message list.

func UserText

func UserText(text string) ModelMessage

UserText builds a plain-text user message in the one content shape the wire converter accepts: a []any list holding a single TextContent, which is what ConvertToModelMessages emits for the coder's own prompt.

The shape is easy to get wrong: a typed []TextContent slice fails the converter's `msg.Content.([]any)` assertion. Every hand-built user message must come from here, and the converter rejects any other shape instead of sending an empty turn.

type OutputFormat

type OutputFormat = json.RawMessage

OutputFormat is the `OutputFormatText | OutputFormatJsonSchema` union. It is only carried, never inspected, by anything in this package, so it keeps its bytes verbatim.

type OutputLengthFailure

type OutputLengthFailure struct{}

func (OutputLengthFailure) Error

func (OutputLengthFailure) Error() string

type PageInput

type PageInput struct {
	SessionID string
	Limit     int
	Before    *string
}

type PageResult

type PageResult struct {
	Items  []WithParts `json:"items"`
	More   bool        `json:"more"`
	Cursor *string     `json:"cursor,omitempty"`
}

func Page

func Page(ctx context.Context, store Store, input PageInput) (PageResult, error)

type ParsedStreamError

type ParsedStreamError struct {
	Type         string
	Message      string
	IsRetryable  bool
	ResponseBody *string
}

func ParseStreamError

func ParseStreamError(input any) *ParsedStreamError

type Part

type Part interface {
	// PartType is the `type` discriminant.
	PartType() string
	// PartBase returns the shared {id, sessionID, messageID}.
	Base() PartBase
	json.Marshaler
}

Part is the seven-variant part union, discriminated on `type`. PartBase is embedded first in every variant, so id/sessionID/messageID lead the JSON.

func UnmarshalPart

func UnmarshalPart(raw []byte) (Part, error)

UnmarshalPart dispatches on `type`.

type PartBase

type PartBase struct {
	ID        string `json:"id"`
	SessionID string `json:"sessionID"`
	MessageID string `json:"messageID"`
}

PartBase is embedded first in every part so id/sessionID/messageID lead the JSON.

type PartDeltaEvent

type PartDeltaEvent struct {
	SessionID string `json:"sessionID"`
	MessageID string `json:"messageID"`
	PartID    string `json:"partID"`
	Field     string `json:"field"`
	Delta     string `json:"delta"`
}

type PartRemovedEvent

type PartRemovedEvent struct {
	SessionID string `json:"sessionID"`
	MessageID string `json:"messageID"`
	PartID    string `json:"partID"`
}

type PartUpdatedEvent

type PartUpdatedEvent struct {
	SessionID string `json:"sessionID"`
	Part      Part   `json:"part"`
	Time      uint64 `json:"time"`
}

type Parts

type Parts []Part

Parts is `Part[]` with union-aware decoding.

func MessageParts

func MessageParts(ctx context.Context, store Store, messageID string) (Parts, error)

func (Parts) MarshalJSON

func (ps Parts) MarshalJSON() ([]byte, error)

MarshalJSON keeps a nil slice as `[]`; `parts` is a required array.

func (*Parts) UnmarshalJSON

func (ps *Parts) UnmarshalJSON(b []byte) error

type RawField

type RawField struct {
	Key   string
	Value json.RawMessage
}

RawField is one own property of a JSON object, in source order.

type RawObject

type RawObject json.RawMessage

RawObject is a JSON object kept as the verbatim bytes it arrived as. Never decode one into map[string]any: Go sorts map keys on re-marshal, and the doom-loop guard compares tool inputs byte for byte, key order included.

A zero-length RawObject is an absent value. On an OPTIONAL field (tagged `omitempty`) that means the key is omitted; on a REQUIRED field it marshals as `{}`, which is what the processor writes for an empty input/metadata.

func MergeInterrupted

func MergeInterrupted(metadata RawObject) RawObject

MergeInterrupted is `{...metadata, interrupted: true}`. A pre-existing `interrupted` key keeps its original position.

func (RawObject) Field

func (r RawObject) Field(key string) (json.RawMessage, bool)

Field returns the raw value at key, or ok=false when absent (or when the receiver is not an object).

func (RawObject) Fields

func (r RawObject) Fields() []RawField

Fields returns the object's own properties in insertion order, or nil when the value is absent or not an object.

func (RawObject) MarshalJSON

func (r RawObject) MarshalJSON() ([]byte, error)

func (RawObject) Raw

func (r RawObject) Raw() json.RawMessage

Raw returns the underlying bytes, or nil when the value was absent: the reading for an OPTIONAL field.

func (RawObject) StrictTrue

func (r RawObject) StrictTrue(key string) bool

StrictTrue reports whether the value at key is exactly `true`.

func (RawObject) StringField

func (r RawObject) StringField(key string) (string, bool)

StringField returns the value at key when it is a string.

func (RawObject) Truthy

func (r RawObject) Truthy(key string) bool

Truthy applies truthyJSON to the value at key; an absent key is false.

func (*RawObject) UnmarshalJSON

func (r *RawObject) UnmarshalJSON(b []byte) error

func (RawObject) Value

func (r RawObject) Value() json.RawMessage

Value returns `{}` for an absent value: the reading for a REQUIRED field (`input`, ToolStateCompleted.metadata), which is always at least an empty object.

type RawValue

type RawValue = json.RawMessage

RawValue is any JSON value carried verbatim. A zero-length RawValue is an absent value (the key is omitted), not JSON null.

type ReasoningContent

type ReasoningContent struct {
	Type            string   `json:"type"`
	Text            string   `json:"text"`
	ProviderOptions RawValue `json:"providerOptions,omitempty"`
}

ReasoningContent is a reasoning content part. `providerOptions` is copied unconditionally (contrast text/file); an absent value is dropped by `omitempty`.

type ReasoningPart

type ReasoningPart struct {
	PartBase
	Type     string       `json:"type"`
	Text     string       `json:"text"`
	Metadata RawObject    `json:"metadata,omitempty"`
	Time     TimeStartEnd `json:"time"`
}

func (ReasoningPart) Base

func (p ReasoningPart) Base() PartBase

func (ReasoningPart) MarshalJSON

func (p ReasoningPart) MarshalJSON() ([]byte, error)

func (ReasoningPart) PartType

func (p ReasoningPart) PartType() string

type RemovedEvent

type RemovedEvent struct {
	SessionID string `json:"sessionID"`
	MessageID string `json:"messageID"`
}

type StepFinishPart

type StepFinishPart struct {
	PartBase
	Type     string  `json:"type"`
	Reason   string  `json:"reason"`
	Snapshot *string `json:"snapshot,omitempty"`
	Cost     float64 `json:"cost"`
	Tokens   Tokens  `json:"tokens"`
	// Upstream is the endpoint OpenRouter reports as having served the call
	// (its response `provider` field). Cache-miss attribution needs to know
	// when successive calls changed endpoint, and the wire already says so.
	// Absent when the provider never reported one.
	Upstream string `json:"upstream,omitempty"`
}

func (StepFinishPart) Base

func (p StepFinishPart) Base() PartBase

func (StepFinishPart) MarshalJSON

func (p StepFinishPart) MarshalJSON() ([]byte, error)

func (StepFinishPart) PartType

func (p StepFinishPart) PartType() string

type StepStartPart

type StepStartPart struct {
	PartBase
	Type     string  `json:"type"`
	Snapshot *string `json:"snapshot,omitempty"`
}

func (StepStartPart) Base

func (p StepStartPart) Base() PartBase

func (StepStartPart) MarshalJSON

func (p StepStartPart) MarshalJSON() ([]byte, error)

func (StepStartPart) PartType

func (p StepStartPart) PartType() string

type Store

type Store interface {
	SelectMessages(ctx context.Context, sessionID string, limit int, before *Cursor) ([]MessageRecord, error)
	SessionExists(ctx context.Context, sessionID string) (bool, error)
	SelectParts(ctx context.Context, messageIDs []string) (Parts, error)
	SelectMessage(ctx context.Context, sessionID, messageID string) (MessageRecord, bool, error)
	SelectMessageParts(ctx context.Context, messageID string) (Parts, error)
}

Store methods must return messages in descending (time_created,id) order and parts in ascending (message_id,id) order.

type StructuredOutputErrorData

type StructuredOutputErrorData struct {
	Message string `json:"message"`
	Retries uint64 `json:"retries"`
}

StructuredOutputErrorData is the StructuredOutputError payload.

type TextContent

type TextContent struct {
	Type            string   `json:"type"`
	Text            string   `json:"text"`
	ProviderOptions RawValue `json:"providerOptions,omitempty"`
}

TextContent is a text content part.

type TextPart

type TextPart struct {
	PartBase
	Type      string        `json:"type"`
	Text      string        `json:"text"`
	Synthetic *bool         `json:"synthetic,omitempty"`
	Ignored   *bool         `json:"ignored,omitempty"`
	Time      *TimeStartEnd `json:"time,omitempty"`
	Metadata  RawObject     `json:"metadata,omitempty"`
}

func (TextPart) Base

func (p TextPart) Base() PartBase

func (TextPart) MarshalJSON

func (p TextPart) MarshalJSON() ([]byte, error)

func (TextPart) PartType

func (p TextPart) PartType() string

type TimeCreated

type TimeCreated struct {
	Created uint64 `json:"created"`
}

TimeCreated is `{created}`.

type TimeStartEnd

type TimeStartEnd struct {
	Start uint64  `json:"start"`
	End   *uint64 `json:"end,omitempty"`
}

TimeStartEnd is `{start, end?}`. TextPart.time and ReasoningPart.time share the shape; only the outer optionality differs.

type ToModelOptions

type ToModelOptions struct {
	StripMedia         *bool
	ToolOutputMaxChars *float64
}

ToModelOptions tune the conversion. Both are pointers: an absent StripMedia is false, and an absent or non-positive ToolOutputMaxChars leaves outputs untruncated.

type TokenCache

type TokenCache struct {
	Read  uint64 `json:"read"`
	Write uint64 `json:"write"`
}

TokenCache is `{read, write}`.

type Tokens

type Tokens struct {
	Total     *uint64    `json:"total,omitempty"`
	Input     uint64     `json:"input"`
	Output    uint64     `json:"output"`
	Reasoning uint64     `json:"reasoning"`
	Cache     TokenCache `json:"cache"`
}

Tokens is the token block shared by StepFinishPart and Assistant.

type ToolCallContent

type ToolCallContent struct {
	Type             string   `json:"type"`
	ToolCallID       string   `json:"toolCallId"`
	ToolName         string   `json:"toolName"`
	Input            RawValue `json:"input,omitempty"`
	ProviderExecuted RawValue `json:"providerExecuted,omitempty"`
	ProviderOptions  RawValue `json:"providerOptions,omitempty"`
}

ToolCallContent is a tool-call content part.

type ToolModelOutputFn

type ToolModelOutputFn func(toolCallID string, input RawValue, output RawValue) ToolOutput

ToolModelOutputFn converts a tool's stored output into the shape the model sees. `output` is the raw JSON value; a nil `output` is absent.

type ToolOutput

type ToolOutput struct {
	Type  string `json:"type"`
	Value any    `json:"value"`
}

ToolOutput is a tool result as the model sees it: one of text / json / error-text / error-json / content.

type ToolOutputContentMedia

type ToolOutputContentMedia struct {
	Type      string `json:"type"`
	MediaType string `json:"mediaType"`
	Data      string `json:"data"`
}

type ToolOutputContentText

type ToolOutputContentText struct {
	Type string `json:"type"`
	Text string `json:"text"`
}

ToolOutputContentText / ToolOutputContentMedia are the two element shapes toModelOutput emits inside `{type:"content"}`.

type ToolPart

type ToolPart struct {
	PartBase
	Type     string    `json:"type"`
	CallID   string    `json:"callID"`
	Tool     string    `json:"tool"`
	State    ToolState `json:"state"`
	Metadata RawObject `json:"metadata,omitempty"`
}

func (ToolPart) Base

func (p ToolPart) Base() PartBase

func (ToolPart) MarshalJSON

func (p ToolPart) MarshalJSON() ([]byte, error)

func (ToolPart) PartType

func (p ToolPart) PartType() string

func (ToolPart) ProviderExecuted

func (p ToolPart) ProviderExecuted() bool

ProviderExecuted reads the one key of ToolPart.metadata that has a read path. It is a truthiness test, not a strict `true` comparison.

func (*ToolPart) UnmarshalJSON

func (p *ToolPart) UnmarshalJSON(b []byte) error

UnmarshalJSON on ToolPart has to route `state` through the union decoder.

type ToolResultContent

type ToolResultContent struct {
	Type            string     `json:"type"`
	ToolCallID      string     `json:"toolCallId"`
	ToolName        string     `json:"toolName"`
	Output          ToolOutput `json:"output"`
	ProviderOptions RawValue   `json:"providerOptions,omitempty"`
}

ToolResultContent is a tool-result content part.

type ToolState

type ToolState interface {
	ToolStatus() string
	// Input is `Record<string, any>`, present on every variant.
	ToolInput() RawObject
	// ToolMetadata is the variant's `metadata`, or a zero RawObject when the
	// variant has none (pending).
	ToolMetadata() RawObject
	// StartTime is `state.time.start`; ok=false for `pending`.
	StartTime() (uint64, bool)
	json.Marshaler
}

ToolState is the four-variant tool state union, discriminated on `status`. The field sets differ: `pending` has no `time` at all, which is why the cleanup drain falls back to `now`.

func UnmarshalToolState

func UnmarshalToolState(raw []byte) (ToolState, error)

UnmarshalToolState dispatches on `status`.

type ToolStateCompleted

type ToolStateCompleted struct {
	Status      string            `json:"status"`
	Input       RawObject         `json:"input"`
	Output      string            `json:"output"`
	Title       string            `json:"title"`
	Metadata    RawObject         `json:"metadata"`
	Time        ToolTimeCompleted `json:"time"`
	Attachments *[]FilePart       `json:"attachments,omitempty"`
}

func CompletedToolState

func CompletedToolState(input RawObject, output, title string, metadata RawObject, start, end uint64, attachments *[]FilePart) ToolStateCompleted

CompletedToolState is the typed `completed` state. The processor writes its keys in the order status, input, output, metadata, title, time, attachments; this struct keeps the declared order (title before metadata).

func (ToolStateCompleted) MarshalJSON

func (s ToolStateCompleted) MarshalJSON() ([]byte, error)

func (ToolStateCompleted) StartTime

func (s ToolStateCompleted) StartTime() (uint64, bool)

func (ToolStateCompleted) ToolInput

func (s ToolStateCompleted) ToolInput() RawObject

func (ToolStateCompleted) ToolMetadata

func (s ToolStateCompleted) ToolMetadata() RawObject

func (ToolStateCompleted) ToolStatus

func (s ToolStateCompleted) ToolStatus() string

type ToolStateError

type ToolStateError struct {
	Status   string       `json:"status"`
	Input    RawObject    `json:"input"`
	Error    string       `json:"error"`
	Metadata RawObject    `json:"metadata,omitempty"`
	Time     ToolTimeSpan `json:"time"`
}

func (ToolStateError) MarshalJSON

func (s ToolStateError) MarshalJSON() ([]byte, error)

func (ToolStateError) StartTime

func (s ToolStateError) StartTime() (uint64, bool)

func (ToolStateError) ToolInput

func (s ToolStateError) ToolInput() RawObject

func (ToolStateError) ToolMetadata

func (s ToolStateError) ToolMetadata() RawObject

func (ToolStateError) ToolStatus

func (s ToolStateError) ToolStatus() string

type ToolStatePending

type ToolStatePending struct {
	Status string    `json:"status"`
	Input  RawObject `json:"input"`
	Raw    string    `json:"raw"`
}

func PendingToolState

func PendingToolState() ToolStatePending

PendingToolState is `{status:"pending", input:{}, raw:""}`.

func (ToolStatePending) MarshalJSON

func (s ToolStatePending) MarshalJSON() ([]byte, error)

func (ToolStatePending) StartTime

func (s ToolStatePending) StartTime() (uint64, bool)

func (ToolStatePending) ToolInput

func (s ToolStatePending) ToolInput() RawObject

func (ToolStatePending) ToolMetadata

func (s ToolStatePending) ToolMetadata() RawObject

func (ToolStatePending) ToolStatus

func (s ToolStatePending) ToolStatus() string

type ToolStateRunning

type ToolStateRunning struct {
	Status   string        `json:"status"`
	Input    RawObject     `json:"input"`
	Title    *string       `json:"title,omitempty"`
	Metadata RawObject     `json:"metadata,omitempty"`
	Time     ToolTimeStart `json:"time"`
}

func (ToolStateRunning) MarshalJSON

func (s ToolStateRunning) MarshalJSON() ([]byte, error)

func (ToolStateRunning) StartTime

func (s ToolStateRunning) StartTime() (uint64, bool)

func (ToolStateRunning) ToolInput

func (s ToolStateRunning) ToolInput() RawObject

func (ToolStateRunning) ToolMetadata

func (s ToolStateRunning) ToolMetadata() RawObject

func (ToolStateRunning) ToolStatus

func (s ToolStateRunning) ToolStatus() string

type ToolTimeCompleted

type ToolTimeCompleted struct {
	Start     uint64  `json:"start"`
	End       uint64  `json:"end"`
	Compacted *uint64 `json:"compacted,omitempty"`
}

ToolTimeCompleted is ToolStateCompleted.time.

type ToolTimeSpan

type ToolTimeSpan struct {
	Start uint64 `json:"start"`
	End   uint64 `json:"end"`
}

ToolTimeSpan is ToolStateError.time.

type ToolTimeStart

type ToolTimeStart struct {
	Start uint64 `json:"start"`
}

ToolTimeStart is ToolStateRunning.time.

type UIMessage

type UIMessage struct {
	ID    string   `json:"id"`
	Role  string   `json:"role"`
	Parts []UIPart `json:"parts"`
}

UIMessage / UIPart are the intermediate value ToModelMessages builds before handing it to ConvertToModelMessages.

A UIPart is ONE flat struct rather than a Go union: the parts are duck-typed on their `type` string, and the tool discriminant is a DYNAMIC string `"tool-" + toolName`, so an interface would buy nothing. UIMessages are never serialised as an output, so field order here is documentation rather than contract.

type UIPart

type UIPart struct {
	Type string `json:"type"`

	// text / reasoning
	Text string `json:"text,omitempty"`

	// text / file / reasoning
	ProviderMetadata RawValue `json:"providerMetadata,omitempty"`

	// file
	MediaType string   `json:"mediaType,omitempty"`
	Filename  RawValue `json:"filename,omitempty"`
	URL       string   `json:"url,omitempty"`

	// dynamic-tool
	ToolName string `json:"toolName,omitempty"`

	// tool-* / dynamic-tool
	ToolCallID             string   `json:"toolCallId,omitempty"`
	State                  string   `json:"state,omitempty"`
	Input                  RawValue `json:"input,omitempty"`
	RawInput               RawValue `json:"rawInput,omitempty"`
	Output                 RawValue `json:"output,omitempty"`
	ErrorText              string   `json:"errorText,omitempty"`
	ProviderExecuted       RawValue `json:"providerExecuted,omitempty"`
	CallProviderMetadata   RawValue `json:"callProviderMetadata,omitempty"`
	ResultProviderMetadata RawValue `json:"resultProviderMetadata,omitempty"`
}

func (UIPart) ResolveToolName

func (p UIPart) ResolveToolName() string

ResolveToolName returns the tool a part refers to: a dynamic part carries the name; a static part's name is everything after the first dash of its type, which preserves every internal dash. That is load-bearing because the type is built as `"tool-" + part.tool` and tool names contain dashes.

type UnknownErrorData

type UnknownErrorData struct {
	Message string `json:"message"`
}

UnknownErrorData is the UnknownError payload.

type UpdatedEvent

type UpdatedEvent struct {
	SessionID string `json:"sessionID"`
	Info      Info   `json:"info"`
}

type User

type User struct {
	MessageBase
	Role    string           `json:"role"`
	Time    TimeCreated      `json:"time"`
	Format  OutputFormat     `json:"format,omitempty"`
	Summary *UserSummary     `json:"summary,omitempty"`
	Agent   string           `json:"agent"`
	Model   UserModel        `json:"model"`
	System  *string          `json:"system,omitempty"`
	Tools   *map[string]bool `json:"tools,omitempty"`
}

func (User) MarshalJSON

func (m User) MarshalJSON() ([]byte, error)

func (User) MessageID

func (m User) MessageID() string

func (User) MessageRole

func (m User) MessageRole() string

type UserModel

type UserModel struct {
	ProviderID string  `json:"providerID"`
	ModelID    string  `json:"modelID"`
	Variant    *string `json:"variant,omitempty"`
}

UserModel is User.model.

type UserSummary

type UserSummary struct {
	Title *string    `json:"title,omitempty"`
	Body  *string    `json:"body,omitempty"`
	Diffs []FileDiff `json:"diffs"`
}

UserSummary is User.summary.

type WithParts

type WithParts struct {
	Info  Info  `json:"info"`
	Parts Parts `json:"parts"`
}

func FilterCompacted

func FilterCompacted(msgs []WithParts) []WithParts

FilterCompacted projects a session onto what the model should see: a newest-first walk over the messages that stops at the last completed compaction, then (when the compaction names a `tail_start_id` that sits BEFORE it) rotates the summary block in front of the retained tail.

`msgs` must arrive newest-first; the result is chronological.

The step loop mutates the returned parts in place (WrapLateUserText), so the caller needs parts it owns. This function does NOT deep-copy; the storage layer that feeds it must hand over fresh values.

func Get

func Get(ctx context.Context, store Store, sessionID, messageID string) (WithParts, error)

func Stream

func Stream(ctx context.Context, store Store, sessionID string) ([]WithParts, error)

func (*WithParts) UnmarshalJSON

func (w *WithParts) UnmarshalJSON(b []byte) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL