fabric/run

What a run is and what it can become. These are plain data: a suspended run is exactly its stored Snapshot, with no process behind it.

Types

Identifies an action within one run. A provider call id alone is not unique: providers reuse ids on later turns.

pub type ActionId {
  ActionId(turn: Int, call_id: String)
}

Constructors

  • ActionId(turn: Int, call_id: String)

One action of a run. Read it by label: Fabric may add fields. approvals lists the answered approval requests of the action, oldest first. child names the sub-agent run a delegation started, from the moment it is started, and stays after the action settles. replays counts how often a replayable tool’s body was started again after a crash, a timeout or a lost runner (tool.with_replay).

pub type ActionRecord {
  ActionRecord(
    id: ActionId,
    call: model.ToolCall,
    state: ActionState,
    approvals: List(Approval),
    child: option.Option(RunId),
    replays: Int,
  )
}

Constructors

Names one action of one run: the delegation that started a sub-agent run, or an uncertain effect to reconcile.

pub type ActionRef {
  ActionRef(run: RunId, id: ActionId)
}

Constructors

Where one action stands. This union may grow: keep a catch-all, or branch on action_state_kind.

pub type ActionState {
  Queued
  Running
  AwaitingApproval(
    requirement: Requirement,
    revision: Int,
    expires: option.Option(timestamp.Timestamp),
  )
  Succeeded(content: String)
  ToolFailed(content: String)
  Denied(reason: String)
  Rejected(reason: String)
  InvalidArguments(detail: String)
  UnknownTool
  Uncertain(evidence: String)
  Reconciled(content: String)
  ChildSettled(outcome: Outcome(String))
  NotStarted
  Delegated
  LimitReached(DelegationLimit)
  Faulted(detail: String)
}

Constructors

  • Queued

    Allowed and waiting for a concurrency slot.

  • Running

    The start was committed before the tool body ran.

  • AwaitingApproval(
      requirement: Requirement,
      revision: Int,
      expires: option.Option(timestamp.Timestamp),
    )

    Waiting for an answer to its approval request. expires is the request’s deadline (agent.with_approval_expiry): after it the request expires, and the action is rejected. None never expires.

  • Succeeded(content: String)
  • ToolFailed(content: String)

    A typed failure; content is what the model sees.

  • Denied(reason: String)
  • Rejected(reason: String)

    A reviewer rejected the action; the model sees reason.

  • InvalidArguments(detail: String)
  • UnknownTool
  • Uncertain(evidence: String)

    The effect may or may not have happened; the next model turn waits for reconciliation.

  • Reconciled(content: String)
  • ChildSettled(outcome: Outcome(String))

    A finished parent’s uncertain delegation was settled from the child’s saved outcome. This is evidence only, never a model-visible tool result. Its answer is the child’s stored text.

  • NotStarted

    Withdrawn before it started (cancellation, a budget, or a host failure).

  • Delegated

    A sub-agent run (ActionRecord.child) is working on it; its outcome becomes this action’s result.

  • LimitReached(DelegationLimit)

    A delegation refused before the policy because it would exceed a sub-agent limit; the model sees why.

  • Faulted(detail: String)

    The host could not complete the action: its output could not be encoded, or its tool changed after admission. The run stopped.

A stable classification of ActionState, by what the caller does next. It never gains variants.

pub type ActionStateKind {
  Active
  NeedsApproval
  NeedsReconciliation
  Ended
}

Constructors

  • Active

    The action settles without the caller (Queued, Running, Delegated). A delegation’s sub-agent run may itself wait for input.

  • NeedsApproval

    The action waits for an answer to its approval request (AwaitingApproval): fabric.approve or fabric.reject it.

  • NeedsReconciliation

    The action’s effect is of unknown status (Uncertain): fabric.reconcile it.

  • Ended

    The action has its final state: a result the model sees or saw, a refusal, a settlement, a withdrawal or a host fault.

The answer to an approval request.

pub type Answer {
  Approve
  Reject(reason: String)
  Expired
}

Constructors

  • Approve
  • Reject(reason: String)

    The action does not run; the model sees reason.

  • Expired

    No one answered before the request’s deadline: the action does not run, and the model sees that its approval expired.

An answered approval request, kept on its action. Read it by label: Fabric may add fields.

reviewer is the identity the approvers’ verify returned for the proof the answer was given with (fabric/approvers), and verifier those approvers’ name. Both are None for an Expired answer. An answer stored before reviewers were required has neither, and one stored before proofs were required has a reviewer the application named, with no verifier.

pub type Approval {
  Approval(
    requirement: Requirement,
    revision: Int,
    answer: Answer,
    reviewer: option.Option(reviewer.Reviewer),
    verifier: option.Option(String),
  )
}

Constructors

Identifies one approval request. revision is unique within the run and survives restarts, so a reference stays answerable until it is answered, superseded by a new requirement, or voided by the run ending. References are plain data: an application may serialize one (into a link or a form) and rebuild it later; fabric.approve and fabric.reject check it against the stored record.

pub type ApprovalRef {
  ApprovalRef(
    run: RunId,
    id: ActionId,
    requirement: Requirement,
    revision: Int,
  )
}

Constructors

The run-wide budget that ended a run.

pub type Budget {
  TurnLimit(limit: Int)
  TokenLimit(limit: Int, used: Int)
  FamilyLimit(budget.Denial)
}

Constructors

  • TurnLimit(limit: Int)
  • TokenLimit(limit: Int, used: Int)
  • FamilyLimit(budget.Denial)

    Shared by the root and all managed descendants.

The agent definition a run was started with. A stored run continues only under the same name and version.

pub type DefinitionId {
  DefinitionId(name: String, version: Int)
}

Constructors

  • DefinitionId(name: String, version: Int)

The sub-agent limit that refused one delegation; the run continues.

pub type DelegationLimit {
  ChildLimit(limit: Int)
  DepthLimit(limit: Int)
}

Constructors

  • ChildLimit(limit: Int)

    A run starts at most limit sub-agent runs.

  • DepthLimit(limit: Int)

    Sub-agents nest at most limit levels below the root run.

Failures of the host rather than of the model or a tool’s business logic. This union may grow: keep a catch-all, or branch on host_failure_kind.

pub type HostFailure {
  PolicyFailed(id: ActionId, reason: String)
  OutputEncodingFailed(id: ActionId, detail: String)
  ToolChanged(id: ActionId, detail: String)
  ModelFailed(model.ModelError)
  ModelProtocolViolation(reason: String)
}

Constructors

  • PolicyFailed(id: ActionId, reason: String)
  • OutputEncodingFailed(id: ActionId, detail: String)
  • ToolChanged(id: ActionId, detail: String)

    The call’s arguments were admitted, but when its tool started they no longer decode, or no tool of that name is registered: the tool changed between admission and start. The handler did not run. It is not shown to the model, whose arguments were valid.

  • ModelFailed(model.ModelError)
  • ModelProtocolViolation(reason: String)

A stable classification of HostFailure, by the part of the host to look at. It never gains variants.

pub type HostFailureKind {
  PolicyFault
  ToolFault
  ModelFault
}

Constructors

  • PolicyFault

    The policy failed on an action (PolicyFailed).

  • ToolFault

    A tool’s result could not be recorded, or the tool changed between admission and start (OutputEncodingFailed, ToolChanged).

  • ModelFault

    The model call failed after its retries, or the model broke the protocol (ModelFailed, ModelProtocolViolation). A ModelFailed carries its own model.error_kind.

Why a stored run cannot continue under a given agent.

pub type Incompatibility {
  OtherAgent(stored: DefinitionId)
  ToolNotRegistered(id: ActionId, tool: String)
  ArgumentsNotAccepted(
    id: ActionId,
    tool: String,
    detail: String,
  )
}

Constructors

  • OtherAgent(stored: DefinitionId)

    The run was started by another agent definition.

  • ToolNotRegistered(id: ActionId, tool: String)

    An action that may still run names a tool the agent does not have.

  • ArgumentsNotAccepted(id: ActionId, tool: String, detail: String)

    An action that has not started yet names a tool whose input codec no longer accepts its arguments.

How a run ended. This union may grow: keep a catch-all.

pub type Outcome(answer) {
  Completed(answer: answer)
  AnswerInvalid(raw: String, reason: String)
  Refused(reason: String)
  OutputLimited(partial_text: String)
  BudgetExhausted(Budget)
  BudgetUnverifiable(turn: Int)
  Cancelled
  Failed(HostFailure)
}

Constructors

  • Completed(answer: answer)

    The model’s final answer, read with the agent’s answer codec (agent.with_answer), or its text for a plain agent. Completion does not mean that every action succeeded: denied or failed tools can be observations the model answered. Read fabric.snapshot(handle) and inspect the returned snapshot’s actions and the application’s effect record.

  • AnswerInvalid(raw: String, reason: String)

    The model’s final answer is not one the agent’s codec reads: raw is the text it sent last, reason the codec’s complaint. A run ends this way when the model answers so on its last answer attempt (agent.with_answer_attempts) or with no turn or token left for a correction; a stored run reads this way when the agent that reads it has another codec than the one it completed under (a run stored before with_answer, say). Its effects have happened.

  • Refused(reason: String)
  • OutputLimited(partial_text: String)
  • BudgetExhausted(Budget)

    A limit was reached. Outstanding tool calls are kept as NotStarted.

  • BudgetUnverifiable(turn: Int)

    A token budget is set but the provider did not report usage for the reply of this turn, so the budget cannot be enforced.

  • Cancelled
  • Failed(HostFailure)

The durable attachment that owns a run. Graph visits and chat actions have different identities; neither is encoded as the other.

pub type Parent {
  AgentParent(run: RunId, id: ActionId)
  GraphParent(run: RunId, activation: Int)
  GraphBranch(run: RunId, activation: Int, member: Int)
}

Constructors

  • AgentParent(run: RunId, id: ActionId)
  • GraphParent(run: RunId, activation: Int)
  • GraphBranch(run: RunId, activation: Int, member: Int)

An approval request waiting for an answer. Read it by label: Fabric may add fields. expires is when it expires unanswered (None: never); an expired request rejects its action (see agent.with_approval_expiry).

pub type PendingApproval {
  PendingApproval(
    reference: ApprovalRef,
    tool: String,
    arguments_json: String,
    expires: option.Option(timestamp.Timestamp),
  )
}

Constructors

Which approval an action needs. version lets an application change the requirement for an action and have stale approvals refused.

pub type Requirement {
  Requirement(name: String, version: Int)
}

Constructors

  • Requirement(name: String, version: Int)

The id of a run. The caller chooses it when it starts a run (fabric.start, graph.start): new_id() for a fresh one, or parse_id of an application key (a job id, an order id) so that a retried start finds the run it already started. A string from outside (a link, a form, a job payload) becomes one only through parse_id.

pub type RunId =
  @internal RunId

A run as stored. Read it by label: Fabric may add fields.

pub type Snapshot(answer) {
  Snapshot(
    run: RunId,
    agent: DefinitionId,
    incarnation: Int,
    parent: option.Option(Parent),
    status: Status(answer),
    turns_used: Int,
    max_turns: Int,
    usage: TokenUsage,
    transcript: List(model.Message),
    actions: List(ActionRecord),
  )
}

Constructors

  • Snapshot(
      run: RunId,
      agent: DefinitionId,
      incarnation: Int,
      parent: option.Option(Parent),
      status: Status(answer),
      turns_used: Int,
      max_turns: Int,
      usage: TokenUsage,
      transcript: List(model.Message),
      actions: List(ActionRecord),
    )

    Arguments

    incarnation

    Increases by one each time recovery takes over work that no live runner owned.

    parent

    The action or graph activation that owns this run; None for a root.

A run’s status. answer is the agent’s answer type (agent.with_answer): String for a plain agent, and for commands that read the store without an agent (fabric.cancel_stored).

pub type Status(answer) {
  Working
  Unattended
  Suspended(
    approvals: List(PendingApproval),
    uncertain: List(UncertainAction),
  )
  Finished(Outcome(answer))
}

Constructors

  • Working

    A model call or a tool is in flight, driven by a runner.

  • Unattended

    Work is in flight but no runner known to this store drives it: its runner was lost, or the run is driven through another Store. fabric.recover takes it over. On an unleased store the previous owner must be known to be gone; a leased store checks ownership. A configured sweeper recovers it after the lease expires.

  • Suspended(
      approvals: List(PendingApproval),
      uncertain: List(UncertainAction),
    )

    Nothing is in flight and the run cannot continue without outside input: approvals to answer or uncertain effects to reconcile.

  • Finished(Outcome(answer))

A bound on a wait. Infinity is never a default: a caller that wants a wait unbounded says so.

pub type Timeout {
  After(duration.Duration)
  Infinity
}

Constructors

Token totals over every reply. unreported_replies counts replies that arrived without usage; they are not counted as zero.

pub type TokenUsage {
  TokenUsage(
    input_tokens: Int,
    output_tokens: Int,
    unreported_replies: Int,
  )
}

Constructors

  • TokenUsage(
      input_tokens: Int,
      output_tokens: Int,
      unreported_replies: Int,
    )

An effect of unknown status. reference names its run (this run, or one of its sub-agent runs) and action; fabric.reconcile takes it.

pub type UncertainAction {
  UncertainAction(
    reference: ActionRef,
    tool: String,
    evidence: String,
  )
}

Constructors

  • UncertainAction(
      reference: ActionRef,
      tool: String,
      evidence: String,
    )

Values

pub fn action_state_kind(state: ActionState) -> ActionStateKind
pub fn describe_action_state(state: ActionState) -> String

One line for logs. It names a tool’s result (Succeeded, ToolFailed, Reconciled) and a sub-agent’s answer only by their presence: they may carry application data.

pub fn describe_host_failure(failure: HostFailure) -> String

One line for logs; describe_outcome uses it for Failed.

pub fn describe_outcome(outcome: Outcome(answer)) -> String

One line for logs and for a caller that reports why a run did not complete, such as an MCP tool that served the run.

pub fn host_failure_kind(failure: HostFailure) -> HostFailureKind
pub fn id_from_parts(
  prefix: String,
  parts: List(String),
) -> RunId

A run id derived from an application key, for a start that must be idempotent: the same parts always give the same id, so a start retried with them finds its run (AlreadyStarted). Unlike parse_id it is total.

prefix names the kind of work, is written in source code, and must be 1 to 32 ASCII letters and digits; any other prefix is a bug and panics. The parts are joined to it with -: id_from_parts("job", ["42", "1"]) is job-42-1. When that text is not a valid id (a part has other characters, or it is longer than 128 characters), the id is the prefix, _ and the SHA-256 of the parts in hexadecimal instead, which stays unique and stable. Give each part a fixed shape (digits, a uuid), since ["4-2"] and ["4", "2"] join to the same text.

When a retry must start a fresh run rather than find the old one, include the attempt among the parts.

pub fn id_to_string(id: RunId) -> String
pub fn new_id() -> RunId

A fresh run id: run- and 32 random lowercase hexadecimal characters (128 random bits), so fresh ids do not collide.

pub fn parse_id(text: String) -> Result(RunId, Nil)

A run id in the shape Fabric issues: 1 to 128 letters, digits, - and _. Anything else names no run. A well-formed id may still name no stored run; commands then report RunNotFound.

✨ Search Document