fabric/model
The model port Fabric owns.
A Model is a function from a full Request to one Reply. Fabric keeps
the transcript itself and sends it whole on every turn, so a model never
needs hidden continuation state: a pure function of the request is a
complete, deterministic model, and fabric/llm adapts an llm_wire
provider to the same port.
Types
One assistant response and the provider data that belongs to that response.
Plain application models use None; adapters retain everything needed to
send the turn back after a restart.
pub type AssistantTurn {
AssistantTurn(
text: String,
calls: List(ToolCall),
data: option.Option(ProviderData),
)
}
Constructors
-
AssistantTurn( text: String, calls: List(ToolCall), data: option.Option(ProviderData), )
What went wrong, as a stable classification. The first four kinds are retryable: another attempt may succeed. This union may grow; match the kinds you handle and keep a catch-all.
pub type ErrorKind {
Unreachable
TimedOut
RateLimited
Overloaded
Rejected
InvalidRequest
InvalidReply
Crashed
Other
}
Constructors
-
UnreachableThe provider could not be reached: the connection failed or was refused before a reply. Retryable.
-
TimedOutThe call did not finish in time: the agent’s model timeout, a provider’s deadline or HTTP 408. Retryable.
-
RateLimitedThe provider asked to slow down (HTTP 429, or its rate-limit error). Retryable, usually after
retry_after. -
OverloadedThe provider failed or was overloaded for now (HTTP 5xx, Anthropic’s 529). Retryable.
-
RejectedThe provider refused the request as it was sent: a bad credential, a missing permission, an unknown model, a request it will not serve. Trying the same request again does not help.
-
InvalidRequestThe request could not be built from the run’s transcript and tools, so nothing was sent.
-
InvalidReplyThe reply could not be read: a broken stream, a protocol violation, or output beyond a limit.
-
CrashedThe model function crashed, or the process that ran it exited.
-
OtherAnything else; not retried.
pub type Message {
UserMessage(text: String)
AssistantMessage(turn: AssistantTurn)
ToolResultMessage(call_id: String, content: String)
}
Constructors
-
UserMessage(text: String) -
AssistantMessage(turn: AssistantTurn)turn.callsis empty for a plain answer. -
ToolResultMessage(call_id: String, content: String)
A model: build one with new, or with fabric/llm.model for an
llm_wire provider.
pub type Model =
@internal Port(Request, Reply, ModelError)
A failed model call. Build one with error(kind, detail); Fabric reads
its kind to decide whether to try again (is_retryable), and waits at
least its retry_after before that attempt. Every attempt counts against
the run’s turn limit.
pub opaque type ModelError
Adapter-owned response metadata. format identifies its encoding and
version; only the adapter interprets value. Fabric stores it unchanged.
It must contain data only, never credentials or live process state.
pub type ProviderData {
ProviderData(format: String, value: String)
}
Constructors
-
ProviderData(format: String, value: String)
usage is None when the provider did not report it; Fabric never treats
a missing report as zero.
pub type Reply {
FinalAnswer(text: String, usage: option.Option(Usage))
ToolRequest(turn: AssistantTurn, usage: option.Option(Usage))
Refusal(reason: String, usage: option.Option(Usage))
Truncated(partial_text: String, usage: option.Option(Usage))
}
Constructors
-
FinalAnswer(text: String, usage: option.Option(Usage))The final answer. For an agent with an answer codec,
textis the answer as JSON. -
ToolRequest(turn: AssistantTurn, usage: option.Option(Usage)) -
Refusal(reason: String, usage: option.Option(Usage)) -
Truncated(partial_text: String, usage: option.Option(Usage))The provider stopped at its output limit. Partial tool calls are dropped.
One model call. Read it by label: Fabric may add fields.
run and turn name the call: turn is the run’s model attempt,
counting every retry, the same number fabric/telemetry reports.
correlation is the run’s (see fabric.start): a model that makes
requests of its own tags them with it, as fabric/llm does, so one agent
serves every run and each call joins its run’s events.
answer is the schema of the agent’s final answer (agent.with_answer),
None for a plain text answer. A model that can constrain its output
asks the provider for it, as fabric/llm does; Fabric checks a
FinalAnswer against the agent’s codec either way. A text it refuses
gets a corrective turn (agent.with_answer_attempts): the next request
holds the refused answer and a user message that says why and repeats
the schema. The run ends as run.AnswerInvalid when no attempt is left.
pub type Request {
Request(
run: @internal RunId,
turn: Int,
correlation: correlation.Correlation,
system: option.Option(String),
messages: List(Message),
tools: List(ToolSpec),
answer: option.Option(codec.Schema),
)
}
Constructors
-
Request( run: @internal RunId, turn: Int, correlation: correlation.Correlation, system: option.Option(String), messages: List(Message), tools: List(ToolSpec), answer: option.Option(codec.Schema), )
A tool call as the provider issued it. id is unique only within one
model turn. Build one with tool_call, and read it by label (call.name,
call.arguments_json): Fabric may add fields. provider_id and
provider_state carry provider replay metadata (for example a Google
thought signature) that must be sent back unchanged when the transcript is
replayed; with_provider_replay sets them.
pub type ToolCall =
@internal ToolCall
A tool declaration derived from the tool’s input codec.
pub type ToolSpec {
ToolSpec(
name: String,
description: String,
schema: codec.Schema,
)
}
Constructors
-
ToolSpec(name: String, description: String, schema: codec.Schema)
Values
pub fn describe_error(error: ModelError) -> String
One line for logs: the kind, the detail and any provider delay.
pub fn error(kind: ErrorKind, detail: String) -> ModelError
A model failure of kind. detail says what happened, for logs and
stored records; it must not carry secrets.
pub fn error_detail(error: ModelError) -> String
The detail the error was built with.
pub fn error_kind(error: ModelError) -> ErrorKind
pub fn is_retryable(error: ModelError) -> Bool
Whether another attempt may succeed: Unreachable, TimedOut,
RateLimited and Overloaded.
pub fn new(
call: fn(Request) -> Result(Reply, ModelError),
) -> @internal Port(Request, Reply, ModelError)
Wraps a model function. The function runs in a task owned by the run; a
crash is contained and reported as a Crashed error, which is not
retried.
pub fn retry_after(
error: ModelError,
) -> option.Option(duration.Duration)
The delay set with with_retry_after.
pub fn tool_call(
id id: String,
name name: String,
arguments_json arguments_json: String,
) -> ToolCall
A call to the tool name with the arguments the model sent, as JSON text.
pub fn with_provider_replay(
call: ToolCall,
id provider_id: option.Option(String),
state provider_state: option.Option(String),
) -> ToolCall
Sets the provider’s own call id and opaque replay state, kept with the call and sent back unchanged when the transcript is replayed.
pub fn with_retry_after(
error: ModelError,
delay: duration.Duration,
) -> ModelError
The provider’s own delay before another attempt (its Retry-After).
Fabric waits at least this long before it retries a retryable failure,
and at most 10 minutes; a negative delay is no delay.