Sigma request persistence uses the public sigma.Request JSON shape. Store a
request with sigma.MarshalRequest, load it with sigma.UnmarshalRequest, and
pass the decoded value to Client.Complete or Client.Stream.
data, err := sigma.MarshalRequest(req)
if err != nil {
return err
}
req, err = sigma.UnmarshalRequest(data)
if err != nil {
return err
}
final, err := client.Complete(ctx, model, req)No envelope or schema version is added today. The JSON field names on
Request, Message, ContentBlock, and Tool are part of sigma's public API
stability policy. If a future format change needs an envelope, it should be added
as an opt-in format rather than changing what MarshalRequest emits.
UnmarshalRequest rejects unknown struct fields and then validates replay
invariants:
- every message has a supported role
- content blocks have a supported type for their role
- image blocks use supported
base64orurlsources - tool results refer to an earlier assistant tool call
- assistant tool-call IDs are unique
- assistant provenance metadata is attached only to assistant messages
- assistant stop reasons are known
Open-ended JSON maps are intentionally preserved. ProviderMetadata,
ToolArguments, and tool schemas may contain provider-specific fields that
sigma does not interpret but that may be required to continue a conversation.
Opaque provider signatures on thinking, tool-call, and assistant text blocks are
also preserved. Empty assistant text is valid only when Signature or
ProviderSignature is non-empty, or it anchors Anthropic hosted-result metadata.
Other unsigned empty text remains invalid. Persistence does not interpret
signatures. Provider replay validates their format and exact
provider/API/model provenance before sending them. Responses serializers omit
signatures and encrypted content when any provenance component is missing or
mismatched, without erasing them from saved blocks. They send a thinking block as
a reasoning item only when it carries replayable encrypted content, or when the
request sets the store provider option and the block keeps its provider item
ID; OpenAI cannot resolve other reasoning items, so they are omitted from the
request but kept in saved blocks. Chat Completions applies the
same nonempty provenance requirement to both ordered openai_reasoning_details
and legacy tool-call reasoning_details. Eligible modern metadata takes
precedence; validated legacy metadata is a fallback only for the same source.
Chat Completions thinking records the field it streamed in
(ProviderMetadata["reasoning_field"]), and same-model replay without reasoning
details sends the thinking back in that field.
Existing histories remain readable without migration, but histories lacking
provenance no longer replay reasoning details. Ordinary text, calls, and results
remain available.
Responses request serialization reserves existing native item IDs before allocating distinct synthetic IDs for messages, reasoning, and tool calls. A deterministic request-local mapping preserves call/result associations when wire IDs require normalization, including grammar and deferred tools. Persist and match the original history IDs; normalized wire IDs are not a migration of the conversation.
Provider-authored numbers in tool arguments are json.Number, including values
retained from partial or canceled streams. Persistence preserves their exact JSON
numeric spelling. See numeric tool arguments for
migration and explicit conversion guidance.
Anthropic hosted-tool results use an anthropic_hosted_replay entry inside a
preceding block's ProviderMetadata. Preserve the entire content block and its
metadata, including ordered results_after entries and source provider/API/model.
Compatible replay validates these associations locally; incompatible or missing
provenance omits hosted calls and results. Old histories remain readable, but
results discarded before this metadata was captured cannot be reconstructed.
Persistence retains failed and aborted messages as saved. At provider dispatch, non-Responses adapters keep only their nonblank visible text and remove their reasoning, tool calls, associated results, and deferred-tool markers. Responses omits the whole failed turn. Neither path changes the stored request. Anthropic also omits blank text after cleaning, including foreign signature-only blocks; valid signed thinking and empty tool results remain serializable.
Synthetic tool-call IDs are opaque and distinct across generated turns. Persist the final assistant IDs and use those exact IDs for matching tool results. Conversation-wide duplicate validation remains in place. Existing histories containing duplicate tool-call IDs are not automatically migrated; applications must repair ambiguous calls and their matching results before persisting them.
AssistantMessage is output metadata. Persist conversation history by converting
the final assistant response back into a Message:
history = append(history, sigma.Message{
Role: sigma.RoleAssistant,
Content: final.Content,
Provider: final.Provider,
API: model.API,
Model: final.Model,
StopReason: final.StopReason,
ProviderThinkingLevel: final.ProviderThinkingLevel,
Usage: final.Usage,
})For tool loops, append the assistant message first, then append one
sigma.ToolResult or sigma.ToolError for each tool call you executed. See
Tools.
When a caller-owned tool execution has its own token usage, attach it to the tool-result message before persisting it:
result := sigma.ToolResult(call.ID, output)
result.Usage = &sigma.Usage{
InputTokens: toolInputTokens,
OutputTokens: toolOutputTokens,
Provider: toolProvider,
Model: toolModel,
}
history = append(history, result)Tool-result usage is execution-local metadata. Sigma preserves it through
persistence and model handoff but does not send it to providers or include it
in request-token estimates, model-turn cost accounting, or evaluation usage
totals. It is distinct from Usage.ToolUseInputTokens, which records
provider-reported tool or connector input tokens on an assistant turn.
For canceled streams, only persist the aborted assistant message if the partial content was visible to the user or needed for a later continue request. See Cancellation.
Persisting assistant usage is optional. When present on the latest successful
assistant message, sigma.EstimateRequestTokens uses it as an anchor and only
estimates messages that follow it. Tool-result usage is preserved but never
used as an anchor. Usage on user and developer messages is rejected by
ValidateRequest.
Persisted requests can become large. Base64 image blocks expand binary data and should usually be stored out-of-band with only a stable reference in your application data, unless the provider requires inline image bytes for replay.
Do not store credentials in persisted requests. API keys, OAuth access tokens,
session cookies, and Authorization headers belong in an AuthResolver, request
options, or your application's secret store. MarshalRequest only covers
conversation context and tool definitions; it does not include client options or
credential callbacks.
Apply your own redaction policy before storing user messages, tool results, and provider metadata. Tool outputs often contain secrets from external systems, and provider metadata may include opaque continuation handles or signatures. Those values can be necessary for provider continuity, but they should be treated as sensitive application data.
This package does not implement a database layer and does not encrypt persisted data. Choose storage, retention, redaction, access control, and encryption at the application boundary.