Documentation
¶
Overview ¶
Package model provides the ModelRegistry and claw-based NodeExecutor for resolving "provider/model-id" specs and executing LLM nodes.
Index ¶
- Constants
- Variables
- func AsyncAnswerText(in *store.Interaction) string
- func AsyncQuestionText(in *store.Interaction) string
- func BuildSecretGuard(ctx context.Context, wf *ir.Workflow, vars map[string]string) *secretguard.Guard
- func ClassifyStreamError(body []byte) error
- func CollectAsyncAnswersText(ctx context.Context, rs store.RunStore, runID, nodeID string) (string, error)
- func DefaultDangerousCommandPatterns() []string
- func FormatAsyncAnswerMessage(interactionID, question, answer string) string
- func KnownModelSpecs() []string
- func LoopIterationFromContext(ctx context.Context) int
- func NewDefaultLifecycleHooks(_ EventHooks) *hooks.Runner
- func NewSubagentRunner(modelReg *Registry, toolReg *tool.Registry, eventHooks EventHooks, ...) func(ctx context.Context, input map[string]any) (string, error)
- func NodeIDFromContext(ctx context.Context) string
- func ParseModelSpec(spec string) (providerName, modelID string, err error)
- func ProviderlessModelID(spec string) string
- func RecordAsyncAnswer(ctx context.Context, rs store.RunStore, publish func(store.Event), ...) (*store.Interaction, string, error)
- func RefreshModelSpecs(ctx context.Context) error
- func RunIDFromContext(ctx context.Context) string
- func SafetyHook(patterns []string) (hooks.Handler, error)
- func SchemaToJSON(schema *ir.Schema) (json.RawMessage, error)
- func SetCredentialsLookup(fn func(ctx context.Context) (func(provider string) string, bool))
- func SetOAuthDirLookup(fn func(ctx context.Context) (func(kind string) string, bool))
- func ValidateOutput(output map[string]any, schema *ir.Schema) error
- func WithLoopIteration(ctx context.Context, iter int) context.Context
- func WithNodeID(ctx context.Context, nodeID string) context.Context
- func WithRunID(ctx context.Context, runID string) context.Context
- func WithSandboxRunnerSession(ctx context.Context, runID string, store *NodeSessionStore, ...) context.Context
- func WithTemplateData(ctx context.Context, td *TemplateData) context.Context
- type APIError
- type AssistantTextInfo
- type AsyncAskBinder
- type AsyncAskHook
- type AttachmentInfo
- type AttachmentWriter
- type CapabilitySource
- type ClawBackend
- type ClawBackendOption
- type ClawExecutor
- func (e *ClawExecutor) Close() error
- func (e *ClawExecutor) Compact(ctx context.Context, nodeID string) error
- func (e *ClawExecutor) EffectiveBackendName(node ir.Node) string
- func (e *ClawExecutor) EvictRun(runID string)
- func (e *ClawExecutor) Execute(ctx context.Context, node ir.Node, input map[string]any) (map[string]any, error)
- func (e *ClawExecutor) ExecuteHumanLLMForInteraction(ctx context.Context, nodeID string, ni *ErrNeedsInteraction, ...) (answers map[string]any, needsHuman bool, err error)
- func (e *ClawExecutor) ExecuteReviewCompanion(ctx context.Context, node *ir.HumanNode, systemText, userMessage string) (map[string]any, error)
- func (e *ClawExecutor) ExfiltratesTo(s, host string) bool
- func (e *ClawExecutor) LifecycleHooks() *hooks.Runner
- func (e *ClawExecutor) MCPHealthCheck(ctx context.Context, servers []string) error
- func (e *ClawExecutor) MaterializeForHost(s, host string) string
- func (e *ClawExecutor) ScrubOutput(output map[string]any) map[string]any
- func (e *ClawExecutor) SecretsInspectActive() bool
- func (e *ClawExecutor) SetAskUserEndpoint(endpoint, token string)
- func (e *ClawExecutor) SetBoardEndpoint(endpoint string)
- func (e *ClawExecutor) SetPresetFocus(prompt string, skills []string)
- func (e *ClawExecutor) SetRepoRoot(dir string)
- func (e *ClawExecutor) SetRunExtraEnv(env []string)
- func (e *ClawExecutor) SetSandbox(run sandbox.Run)
- func (e *ClawExecutor) SetSkillHints(hints map[string]string)
- func (e *ClawExecutor) SetVars(vars map[string]any)
- func (e *ClawExecutor) SetWorkDir(dir string)
- type ClawExecutorOption
- func WithArtifactFilesDir(dir string) ClawExecutorOption
- func WithBackendRegistry(dr *delegate.Registry) ClawExecutorOption
- func WithBoardRegister(fn func(caps []string, sourceIssueID string) string) ClawExecutorOption
- func WithBotID(botID string) ClawExecutorOption
- func WithCompressOverride(mode string) ClawExecutorOption
- func WithDefaultBackend(name string) ClawExecutorOption
- func WithEventHooks(h EventHooks) ClawExecutorOption
- func WithExecutorAsyncAsk(b AsyncAskBinder) ClawExecutorOption
- func WithExecutorInbox(b InboxBinder) ClawExecutorOption
- func WithExtraClosers(closers ...io.Closer) ClawExecutorOption
- func WithLifecycleHooks(r *hooks.Runner) ClawExecutorOption
- func WithLogger(l *iterlog.Logger) ClawExecutorOption
- func WithMCPManager(m *mcp.Manager) ClawExecutorOption
- func WithModelOverrides(o ModelOverrides) ClawExecutorOption
- func WithPermissionOverride(mode string) ClawExecutorOption
- func WithPermissionRules(allow, ask, deny []string) ClawExecutorOption
- func WithRetryPolicy(rp RetryPolicy) ClawExecutorOption
- func WithRewriteChain(chain *rewrite.Chain) ClawExecutorOption
- func WithSecretGuard(g *secretguard.Guard) ClawExecutorOption
- func WithSourceIssueID(issueID string) ClawExecutorOption
- func WithStoreDir(dir string) ClawExecutorOption
- func WithToolPolicy(p tool.ToolChecker) ClawExecutorOption
- func WithToolRegistry(tr *tool.Registry) ClawExecutorOption
- func WithWorkDir(dir string) ClawExecutorOption
- type CompactInfo
- type ContextOverflowError
- type DelegateInfo
- type ErrNeedsInteraction
- type EventEmitter
- type EventHooks
- type FinishReason
- type GenerationOptions
- type GenerationTool
- type InboxBinder
- type InboxHook
- type KeyedProviderFactory
- type LLMCompactInfo
- type LLMRequestInfo
- type LLMResponseInfo
- type LLMStepInfo
- type LLMToolCallInfo
- type LLMToolStartedInfo
- type LLMTurnCaptureInfo
- type ModelCapabilities
- type ModelOverrides
- type NodeModelOverride
- type NodeSessionStore
- type ObjectResult
- type PlanWriter
- type ProviderFactory
- type ProviderFallbackInfo
- type Registry
- func (r *Registry) Capabilities(spec string) (ModelCapabilities, error)
- func (r *Registry) Register(providerName string, factory ProviderFactory)
- func (r *Registry) Resolve(spec string) (api.APIClient, error)
- func (r *Registry) ResolveWithContext(ctx context.Context, spec string) (api.APIClient, error)
- type RequestInfo
- type ResolvedCapabilities
- type ResponseInfo
- type RetryInfo
- type RetryPolicy
- type ScreenshotDirective
- type SessionCaptureSink
- type StepResult
- type StoreAsyncAskBinder
- type StoreInboxBinder
- type TemplateData
- type TextResult
- type ToolBlobWriter
- type ToolCall
- type ToolCallEntry
- type ToolCallInfo
- type TurnCaptureInfo
- type TurnWriter
- type Usage
Constants ¶
const ( MemoryReadToolName = "memory_read" MemoryWriteToolName = "memory_write" MemoryListToolName = "memory_list" )
Tool names surfaced to the LLM. Tracked as constants so prompts, skills, and validators can refer to them without drifting. They are stable across the FS/cloud MemoryStore backends.
const DefaultBackoffBase = time.Second
DefaultBackoffBase is the base duration for exponential backoff.
const DefaultMaxAttempts = 3
DefaultMaxAttempts is the default number of LLM call attempts (initial + retries).
const DefaultMaxAttemptsTransient = 6
DefaultMaxAttemptsTransient is the attempt budget for connectivity/transient failures. Larger than DefaultMaxAttempts so a brief internet/API outage is ridden out rather than aborting a long run: with a 1s base and the capped exponential backoff below, 6 attempts span roughly a minute of retrying.
Variables ¶
var ErrCompactionUnsupported = errors.New("model: compaction not supported by executor")
ErrCompactionUnsupported is the sentinel ClawExecutor.Compact returns when the backend has no in-process conversation handle to drop. The runtime re-exports it (runtime.ErrCompactionUnsupported is an alias) so the engine's `errors.Is` check works without importing model directly. Lives here because runtime imports model, not the reverse.
var ErrTextBlockTooLarge = errors.New("aggregateStream: text/thinking block exceeded max size")
ErrTextBlockTooLarge signals that a streamed text/thinking block's accumulated content exceeded maxTextBlockSize.
var ErrToolInputTooLarge = errors.New("aggregateStream: tool_use input exceeded max size")
ErrToolInputTooLarge signals that a streamed tool_use block's accumulated input JSON exceeded maxToolInputJSONSize.
Functions ¶
func AsyncAnswerText ¶ added in v1.1.0
func AsyncAnswerText(in *store.Interaction) string
AsyncAnswerText flattens the recorded answers of an answered async interaction. The canonical shape is a single AskUserQuestionKey string; other keys are rendered k=v so nothing is silently dropped.
func AsyncQuestionText ¶ added in v1.1.0
func AsyncQuestionText(in *store.Interaction) string
AsyncQuestionText extracts the question text of an async interaction.
func BuildSecretGuard ¶ added in v0.39.0
func BuildSecretGuard(ctx context.Context, wf *ir.Workflow, vars map[string]string) *secretguard.Guard
BuildSecretGuard assembles the per-run secret guard (Layer 0/1/2) from every value iterion can already see as sensitive:
- the resolved per-run credentials carried in ctx (cloud BYOK keys),
- host env vars whose name looks secret (the local-run path — same definition store.CaptureLaunchEnv uses), and
- the workflow's declared `secrets:` values (Layer 1; the agent only ever sees their placeholder).
Returns nil when redaction is disabled via ITERION_SECRETS_REDACT=off, in which case every guard method is a no-op. Otherwise returns a non-nil guard even with zero known values, so the heuristic detector pass still scrubs unknown token shapes from the run's sinks.
func ClassifyStreamError ¶
ClassifyStreamError parses a stream error event and returns the appropriate typed error (*ContextOverflowError or *APIError), or nil if the data is not a recognized error event.
func CollectAsyncAnswersText ¶ added in v1.1.0
func CollectAsyncAnswersText(ctx context.Context, rs store.RunStore, runID, nodeID string) (string, error)
CollectAsyncAnswersText formats every ANSWERED async question of a node (nodeID empty = whole run) into one human-readable block. Shared by the await_answers tool result (both backends) and the runtime's await-node output / resume re-injection so the agent always sees one shape.
func DefaultDangerousCommandPatterns ¶
func DefaultDangerousCommandPatterns() []string
DefaultDangerousCommandPatterns returns conservative regexes that match obviously destructive shell invocations. The list is small on purpose: each entry should have very low false-positive rate against typical engineering workflows.
func FormatAsyncAnswerMessage ¶ added in v1.1.0
FormatAsyncAnswerMessage renders the operator-message text delivered to the asking node's inbox when its async question is answered. One canonical formatter so claw mid-turn injection, claude_code hook drains, and the resume fold-in all show the same shape.
func KnownModelSpecs ¶ added in v0.39.0
func KnownModelSpecs() []string
KnownModelSpecs returns a representative set of model specs to list when the `iterion models` command is invoked without an explicit model. It spans the providers the resolver knows curated heuristics for (Anthropic Claude, the GLM family served via the Anthropic-compatible endpoint, and OpenAI) so the listing exercises every curated branch. It is a display convenience, not an exhaustive catalogue — any "provider/model-id" can be passed explicitly.
func LoopIterationFromContext ¶ added in v0.39.0
LoopIterationFromContext returns the loop iteration stamped by WithLoopIteration, or 0 when none was set (the natural default for nodes outside any loop).
func NewDefaultLifecycleHooks ¶
func NewDefaultLifecycleHooks(_ EventHooks) *hooks.Runner
NewDefaultLifecycleHooks returns a Runner pre-configured with the hooks every iterion run should have on by default:
- SafetyHook on PreToolUse: blocks dangerous bash commands (rm -rf /, fork bombs) before they run.
Tool-call observability (PostToolUse, PostToolUseFailure) is NOT wired here: the executor already emits OnToolCall via applyHooks with the correct node ID at every tool outcome (success, error, or hook-blocked). Adding a PostToolUse audit hook here would duplicate the same event under a placeholder node ID — see AuditHook docs.
Hosts that need to add or override hooks should construct their own runner via hooks.NewRunner and pass it via WithLifecycleHooks; this helper is a sane default for the common case.
The default patterns are hardcoded and known to compile, so this function never returns an error — but it preserves the error signature for symmetry with NewLifecycleHooks variants that take user-supplied patterns.
func NewSubagentRunner ¶
func NewSubagentRunner( modelReg *Registry, toolReg *tool.Registry, eventHooks EventHooks, lifecycle *clawhooks.Runner, defaultModel string, ) func(ctx context.Context, input map[string]any) (string, error)
NewSubagentRunner returns a closure suitable as the executor for the claw `agent` tool. When the LLM dispatches the agent tool, the closure spins up a child conversation against the same model registry, filters the tool registry by AllowedToolsForSubagent, and returns the child's final text alongside its agent_id.
Hooks are propagated to the parent's event stream with a "subagent:<agent_id>" nodeID so a live test can observe the full sub-tree.
The returned executor never recurses into itself: the `agent` tool is filtered out of the child's tool set, regardless of the subagent type's allowlist. defaultModel is used when the input omits the model field; pass an empty string to force an explicit model on every call.
func NodeIDFromContext ¶ added in v0.39.0
NodeIDFromContext returns the active node id set by WithNodeID, or "" when none is wired. "" means "run-scoped drain" — every queued message is delivered regardless of its NodeID tag (legacy behaviour).
func ParseModelSpec ¶
ParseModelSpec splits "provider/model-id" into its components.
func ProviderlessModelID ¶ added in v0.39.0
ProviderlessModelID strips the leading "<provider>/" off a claw model spec. claw's GenerationOptions.Model wants the bare model id while Registry.Resolve wants the full "<provider>/<model>" spec — direct structured callers (supervisors, the session-board curator) resolve the client from the full spec but pass the bare id on the request. Returns the input unchanged when it carries no provider prefix.
func RecordAsyncAnswer ¶ added in v1.1.0
func RecordAsyncAnswer(ctx context.Context, rs store.RunStore, publish func(store.Event), runID, interactionID, answer string) (*store.Interaction, string, error)
RecordAsyncAnswer is the shared trunk of every "operator answers an async question" surface (runview service, CLI): it records the answer on the pending interaction, appends + publishes interaction_answered, and returns the answered record with the canonical delivery text for the asking node's inbox. Callers own the delivery-specific tail (QueueMessage vs direct AppendQueuedMessage).
func RefreshModelSpecs ¶ added in v0.39.0
RefreshModelSpecs force-refetches the model-spec cache synchronously via the existing resolver, blocking until the fetch completes or fails. On success the on-disk cache (~/.iterion) and the in-process table are both updated; on failure the prior cache is left untouched and the error is returned. This is the `iterion models --refresh` path.
func RunIDFromContext ¶
RunIDFromContext returns the run ID set by WithRunID, or "" when none is wired (e.g. unit tests that exercise the executor without the runtime engine).
func SafetyHook ¶
SafetyHook blocks PreToolUse events whose top-level "command" input matches one of `patterns`. Returns an error listing every pattern that fails to compile so operators are not silently running without the safety net they configured.
func SchemaToJSON ¶
func SchemaToJSON(schema *ir.Schema) (json.RawMessage, error)
SchemaToJSON converts an IR Schema to a JSON Schema (json.RawMessage) suitable for use with sdk.WithExplicitSchema.
func SetCredentialsLookup ¶ added in v0.39.0
SetCredentialsLookup wires a per-ctx credentials lookup. The runner calls this at boot once with a closure that reads from secrets.CredentialsFromContext and returns the per-provider key. Idempotent; the latest call wins.
func SetOAuthDirLookup ¶ added in v0.50.0
SetOAuthDirLookup wires a per-ctx OAuth-dir reader. The runner calls this at boot with a closure over secrets.CredentialsFromContext(ctx).OAuthDir. Idempotent; latest call wins.
func ValidateOutput ¶
ValidateOutput checks that output contains all required fields from the schema with compatible types. It does NOT attempt to repair or coerce invalid values — the node must fail explicitly on schema mismatch.
func WithLoopIteration ¶ added in v0.39.0
WithLoopIteration returns a derived context carrying the 0-based loop iteration counter for the node about to execute. The runtime calls this immediately before Executor.Execute so backends can tag their log output as [NodeID#iter/...] for per-(node, iteration) filtering in the studio.
func WithNodeID ¶ added in v0.39.0
WithNodeID returns a derived ctx carrying the active node id. The runtime engine calls this once per node execution, alongside WithRunID. Empty nodeID is a no-op (drain falls back to run-scope).
func WithRunID ¶
WithRunID returns a derived ctx carrying the run ID. The runtime engine calls this once per node execution, before `executor.Execute`. ClawExecutor reads it via RunIDFromContext.
func WithSandboxRunnerSession ¶ added in v0.5.0
func WithSandboxRunnerSession(ctx context.Context, runID string, store *NodeSessionStore, sink SessionCaptureSink) context.Context
WithSandboxRunnerSession is the runner-side entry point (V2-4) that hooks a freshly-built session store + capture sink into ctx so the in-runner ClawBackend mirrors every saved snapshot back across the IPC. The runner constructs the store via NewNodeSessionStore and the sink as a thin wrapper over the delegate.EnvelopeWriter.
Exported (where [withRuntimeContext] stays unexported) because the runner lives in `cmd/iterion` which can't reach package-private helpers — and we don't want every executor caller to discover a "sink" parameter they'd have to thread nil through.
func WithTemplateData ¶
func WithTemplateData(ctx context.Context, td *TemplateData) context.Context
WithTemplateData returns a derived ctx carrying the template data snapshot. The runtime engine calls this once per node execution before invoking executor.Execute. Passing nil clears the snapshot.
Types ¶
type AssistantTextInfo ¶ added in v0.39.0
type AssistantTextInfo struct {
Text string
// Iteration is the 0-based loop iteration (see LLMRequestInfo.Iteration).
Iteration int
}
AssistantTextInfo carries one chunk of assistant narration (mid-turn prose), passed to the OnAssistantText hook. Fired per assistant text block for claude_code and per tool-bearing step for claw.
type AsyncAskBinder ¶ added in v1.1.0
type AsyncAskBinder interface {
BindAsyncAsk(ctx context.Context, runID, nodeID string) AsyncAskHook
}
AsyncAskBinder constructs a per-(run,node) AsyncAskHook. Returning nil disables async asks for that run (the tools then error explicitly).
type AsyncAskHook ¶ added in v1.1.0
type AsyncAskHook interface {
// Post persists a pending Kind=async Interaction and emits
// human_input_requested{async:true}. Returns the interaction ID.
Post(ctx context.Context, q delegate.AsyncQuestion) (string, error)
// Pending lists the node's still-unanswered async questions
// (oldest first).
Pending(ctx context.Context) ([]delegate.PendingAsync, error)
// CollectAnswers formats every answered async question of the node
// into one human-readable block (the await_answers success result).
CollectAnswers(ctx context.Context) (string, error)
}
AsyncAskHook is one node's async-question surface.
type AttachmentInfo ¶ added in v0.7.0
type AttachmentInfo struct {
Name string
Path string // absolute host path; empty in cloud unless prefetched
OriginalFilename string
MIME string
Size int64
SHA256 string
// PresignURL, when set, is invoked lazily the first time a
// `.url` reference is resolved. Returns "" when no presigner
// is wired (e.g. unit-test stubs).
PresignURL func() (string, error)
}
AttachmentInfo is the resolved per-attachment view consumed by template references. Built once per node execution from the store's AttachmentRecord plus a lazy presign hook so prompts that never touch `.url` don't pay the URL signing cost.
func (AttachmentInfo) URL ¶ added in v0.7.0
func (a AttachmentInfo) URL() (string, error)
URL evaluates the presign hook. Each call re-runs the hook because AttachmentInfo is stored by value in TemplateData.Attachments and cache mutation wouldn't be visible across map lookups.
type AttachmentWriter ¶ added in v0.39.0
type AttachmentWriter interface {
WriteAttachment(ctx context.Context, runID string, rec store.AttachmentRecord, body io.Reader) error
}
AttachmentWriter is the optional capability the Browser pane uses to persist binary captures (PNG/JPEG screenshots) as run attachments reachable through `GET /api/runs/:id/attachments/:name`. The production EventEmitter is `*store.FilesystemRunStore` (or its Mongo equivalent), both of which already implement WriteAttachment. Mocks/tests that pass an emitter without this method silently skip screenshot capture.
type CapabilitySource ¶ added in v0.39.0
type CapabilitySource string
CapabilitySource records where a resolved capability value came from.
const ( // SourceAggregator means the online model-spec aggregator (models.dev, // cached under ~/.iterion) had an entry for the model and was merged over // the curated fallback. SourceAggregator CapabilitySource = "aggregator" // SourceCurated means the curated static table in capabilities.go was the // sole source — the aggregator lacked the model, was disabled, or offline. SourceCurated CapabilitySource = "curated" )
type ClawBackend ¶
type ClawBackend struct {
// contains filtered or unexported fields
}
ClawBackend implements delegate.Backend by calling GenerateTextDirect and GenerateObjectDirect against api.APIClient. It wraps the direct LLM path into the unified Backend interface.
func NewClawBackend ¶
func NewClawBackend(registry *Registry, hk EventHooks, retry RetryPolicy, opts ...ClawBackendOption) *ClawBackend
NewClawBackend creates a new ClawBackend.
func (*ClawBackend) Execute ¶
Execute implements delegate.Backend.
When the run is sandboxed (task.Sandbox != nil), the call is forwarded to the iterion-claw-runner sub-process inside the container — see [executeViaSandboxRunner]. This keeps the LLM's in-process tool execution (Bash, file edits) inside the sandbox rather than escaping to the host. The unsandboxed path below is the historical in-process implementation.
V1 limitations of the sandbox-routed path are documented on delegate.IOTask and in docs/sandbox.md: no MCP servers, no mid-tool-loop ask_user resume.
type ClawBackendOption ¶
type ClawBackendOption func(*ClawBackend)
ClawBackendOption configures a ClawBackend at construction time.
func WithBackendLifecycleHooks ¶
func WithBackendLifecycleHooks(r *hooks.Runner) ClawBackendOption
WithBackendLifecycleHooks installs an in-process hook runner fired around tool execution and at session end. A nil runner is a no-op.
func WithInbox ¶ added in v0.39.0
func WithInbox(b InboxBinder) ClawBackendOption
WithInbox wires an InboxBinder into the backend so the generation engine drains the operator chatbox between tool iterations.
func WithMemoryStore ¶ added in v0.39.0
func WithMemoryStore(ms knowledge.MemoryStore) ClawBackendOption
WithMemoryStore injects a non-default workspace-memory backend (e.g. the cloud Mongo store). nil leaves the filesystem default.
type ClawExecutor ¶
type ClawExecutor struct {
// contains filtered or unexported fields
}
ClawExecutor implements runtime.NodeExecutor by routing LLM calls through pluggable Backend implementations (claw, claude_code, codex, etc.).
func NewClawExecutor ¶
func NewClawExecutor(registry *Registry, wf *ir.Workflow, opts ...ClawExecutorOption) *ClawExecutor
NewClawExecutor creates a ClawExecutor for a given workflow.
func (*ClawExecutor) Close ¶
func (e *ClawExecutor) Close() error
Close releases resources held by the executor, including MCP server connections and the per-run host secret-file tempdir (host runs only — sandbox runs never populate it).
func (*ClawExecutor) Compact ¶
func (e *ClawExecutor) Compact(ctx context.Context, nodeID string) error
Compact satisfies the runtime.Compactor structural interface.
ClawExecutor maintains a session-per-node store of messages accumulated during the previous attempt. On Compact, the pure CompactSessionPure helper from claw-code-go is applied to that list — the next retry's claw backend prepends the (now smaller) list to its opts.Messages so the LLM sees a summarised history instead of the full pre-overflow conversation.
When no session is wired (non-claw backends, or a node that has never been executed) Compact returns ErrCompactionUnsupported, the recovery dispatcher logs the gap, and the retry runs without special treatment — the same behaviour as before session tracking existed.
func (*ClawExecutor) EffectiveBackendName ¶ added in v0.50.0
func (e *ClawExecutor) EffectiveBackendName(node ir.Node) string
EffectiveBackendName exposes the exact runtime resolution to safety checks. In particular, callers must not reimplement this chain and accidentally miss launch overrides, environment defaults, or credential-based auto-detection.
func (*ClawExecutor) EvictRun ¶
func (e *ClawExecutor) EvictRun(runID string)
EvictRun drops every per-node session belonging to the given run. The runtime engine calls this when a run terminates (success, terminal failure, or cancellation) so a long-lived executor shared across runs does not leak session state from failed nodes.
func (*ClawExecutor) Execute ¶
func (e *ClawExecutor) Execute(ctx context.Context, node ir.Node, input map[string]any) (map[string]any, error)
Execute implements runtime.NodeExecutor.
func (*ClawExecutor) ExecuteHumanLLMForInteraction ¶
func (e *ClawExecutor) ExecuteHumanLLMForInteraction( ctx context.Context, nodeID string, ni *ErrNeedsInteraction, fields ir.InteractionFields, ) (answers map[string]any, needsHuman bool, err error)
ExecuteHumanLLMForInteraction handles delegate interaction requests by creating a synthetic HumanNode from the original node's InteractionFields and calling executeHumanLLM. The questions from the ErrNeedsInteraction become the input, and the interaction schema is synthesized from the question keys.
Returns:
- answers: LLM-generated answers for each question
- needsHuman: true if the LLM decided to escalate (llm_or_human mode only)
- err: any error from model execution
func (*ClawExecutor) ExecuteReviewCompanion ¶ added in v0.39.0
func (e *ClawExecutor) ExecuteReviewCompanion(ctx context.Context, node *ir.HumanNode, systemText, userMessage string) (map[string]any, error)
ExecuteReviewCompanion drives a review gate's companion LLM (interaction: review). Given a pre-resolved system prompt (the companion's authored contract) and a user message (the diff context + dialogue transcript + the human's latest reply, assembled by the runtime), it returns a structured result carrying:
- "message" — the next test-walkthrough message to show the human
- "needs_human_input" — false when the companion is satisfied it can conclude
- plus every field of the review node's output schema (the verdict: decision / confidence / blockers / …)
The companion never has tools — it reasons over the change and the conversation. systemText is resolved by the caller (the runtime, which holds rs.vars/outputs), so this layer only performs the LLM call.
func (*ClawExecutor) ExfiltratesTo ¶ added in v0.39.0
func (e *ClawExecutor) ExfiltratesTo(s, host string) bool
func (*ClawExecutor) LifecycleHooks ¶
func (e *ClawExecutor) LifecycleHooks() *hooks.Runner
LifecycleHooks returns the runner installed via WithLifecycleHooks (nil if none). It is intended for backends that need to forward the runner into their own generation paths.
func (*ClawExecutor) MCPHealthCheck ¶
func (e *ClawExecutor) MCPHealthCheck(ctx context.Context, servers []string) error
MCPHealthCheck verifies that the listed MCP servers are reachable by connecting and sending an MCP ping. Should be called before execution starts to fail fast on misconfigured servers.
func (*ClawExecutor) MaterializeForHost ¶ added in v0.39.0
func (e *ClawExecutor) MaterializeForHost(s, host string) string
MaterializeForHost / ExfiltratesTo / SecretsInspectActive let the engine use the executor's guard as the egress rewriter for the sandbox proxy's TLS-inspection mode (Layer 2), via a structural interface — so the runtime needn't import pkg/backend/secretguard.
func (*ClawExecutor) ScrubOutput ¶ added in v0.39.0
func (e *ClawExecutor) ScrubOutput(output map[string]any) map[string]any
ScrubOutput satisfies runtime.SecretScrubber: it returns a redacted deep copy of a node's output for the (observational) node_finished event stream, never mutating the live output (which feeds downstream nodes and the resume checkpoint). Nil-safe via the guard.
func (*ClawExecutor) SecretsInspectActive ¶ added in v0.39.0
func (e *ClawExecutor) SecretsInspectActive() bool
SecretsInspectActive reports whether the run has known secrets worth inspecting egress for. Egress TLS inspection only pays its cost (CA minting + trust injection) when there is something to substitute or protect.
func (*ClawExecutor) SetAskUserEndpoint ¶ added in v1.9.0
func (e *ClawExecutor) SetAskUserEndpoint(endpoint, token string)
SetAskUserEndpoint installs the per-run gateway-reachable ask-user MCP URL + token (started with the sandbox) so the executor can wire Task.AskUserHTTPEndpoint/AskUserRunToken for sandboxed interactive nodes (ADR-082 Phase 3). Called by the engine after the sandbox starts; empty values leave the sandboxed ask-user transport unwired.
func (*ClawExecutor) SetBoardEndpoint ¶ added in v0.39.0
func (e *ClawExecutor) SetBoardEndpoint(endpoint string)
SetBoardEndpoint installs the per-run gateway-reachable board MCP URL (started with the sandbox) so the executor can wire Task.BoardHTTPEndpoint/BoardRunToken for sandboxed board-cap nodes (C082). Called by the engine after the sandbox starts; no-op endpoint "" leaves sandboxed board-emit disabled.
func (*ClawExecutor) SetPresetFocus ¶ added in v0.39.0
func (e *ClawExecutor) SetPresetFocus(prompt string, skills []string)
SetPresetFocus records the selected launch-time preset's prompt bias and relevant-skill hints. The engine calls this at run start (and on resume) for the `--preset <name>` selection; every LLM node then renders a "## Focus" section in its system prompt (see executeBackend). The prompt is stored raw and {{vars.X}}-resolved per node. Empty args clear the focus. Must be called before Execute; not safe to call concurrently.
func (*ClawExecutor) SetRepoRoot ¶ added in v0.39.0
func (e *ClawExecutor) SetRepoRoot(dir string)
SetRepoRoot updates the source-of-truth repository root. The engine calls this once per run, alongside SetWorkDir, so memory specs that opt into `project_root: true` resolve their scope under the operator's main repo even when the run executes from a worktree or dispatcher workspace. Empty string means "no project root captured" — memory specs that require it will fall back to WorkDir's encoded key.
func (*ClawExecutor) SetRunExtraEnv ¶ added in v1.1.0
func (e *ClawExecutor) SetRunExtraEnv(env []string)
SetRunExtraEnv installs run-level process-environment additions (KEY=value entries) applied to every host-spawned command of the run. The engine calls this once per run, before the first node executes, from host devbox provisioning (pkg/runtime/devbox_host.go); the same happens-before as SetSandbox makes a mutex unnecessary.
func (*ClawExecutor) SetSandbox ¶ added in v0.4.0
func (e *ClawExecutor) SetSandbox(run sandbox.Run)
SetSandbox installs the live sandbox handle on the executor. The engine calls this once per run, after [resolveAndStartSandbox] returns. Subsequent tool node and backend invocations consult the handle to route through the sandbox transparently.
Passing nil clears the previous handle (used between runs).
func (*ClawExecutor) SetSkillHints ¶ added in v0.39.0
func (e *ClawExecutor) SetSkillHints(hints map[string]string)
SetSkillHints records the name→description map of skill-library skills that resolved in the library at run start (from the runtime mirror). Every LLM node then renders a "## Skills" section for the subset it references (node `skills:` ∪ workflow default). Nil/empty clears the hints. Must be called before Execute; not safe to call concurrently.
func (*ClawExecutor) SetVars ¶
func (e *ClawExecutor) SetVars(vars map[string]any)
SetVars merges run-level workflow variables into the executor's vars map. Keys present in vars override the matching default seeded from wf.Vars at construction time; keys absent from vars retain their default. Must be called before Execute.
func (*ClawExecutor) SetWorkDir ¶
func (e *ClawExecutor) SetWorkDir(dir string)
SetWorkDir updates the working directory for backend subprocesses (claude_code, codex) and tool node shell exec. The engine calls this at run start when `worktree: auto` produces a per-run worktree path that wasn't known at executor construction time. Safe to call before Execute; not safe to call concurrently with an in-flight Execute.
type ClawExecutorOption ¶
type ClawExecutorOption func(*ClawExecutor)
ClawExecutorOption configures a ClawExecutor.
func WithArtifactFilesDir ¶ added in v0.50.0
func WithArtifactFilesDir(dir string) ClawExecutorOption
WithStoreDir sets the dispatcher store root forwarded to capability-gated backend tools (currently the board MCP server). Backends translate this to the ITERION_STORE_DIR env var on spawned MCP children. WithArtifactFilesDir sets the run's artifact_files scratch dir, exported to host tool-node subprocesses as ITERION_ARTIFACT_FILES_DIR (sandboxed runs receive it from the container env instead).
func WithBackendRegistry ¶
func WithBackendRegistry(dr *delegate.Registry) ClawExecutorOption
WithBackendRegistry sets the backend registry on the executor. When set, nodes with a `backend` property are executed via the named backend instead of the default claw backend.
func WithBoardRegister ¶ added in v0.39.0
func WithBoardRegister(fn func(caps []string, sourceIssueID string) string) ClawExecutorOption
WithBoardRegister installs the per-node board MCP token minter (server path). The closure registers a token for the node's board capabilities with the server's BoardMCPTokenRegistry and returns it; the executor pairs it with the board endpoint on each sandboxed board-cap node. sourceIssueID is the ticket owning the run, so the HTTP transport can auto-stamp parent_id on board.create like the other two transports.
func WithBotID ¶ added in v0.39.0
func WithBotID(botID string) ClawExecutorOption
WithBotID sets the stable bot identity used to qualify structured visibility=bot memory spaces. When unset, NewClawExecutor falls back to Workflow.Name.
func WithCompressOverride ¶ added in v0.39.0
func WithCompressOverride(mode string) ClawExecutorOption
WithCompressOverride sets the run-level compression override (CLI --compress / studio Launch toggle): on|ultra|off, or "" for "unset, defer to DSL/env". It is the highest-priority input to rewrite.Resolve.
func WithDefaultBackend ¶
func WithDefaultBackend(name string) ClawExecutorOption
WithDefaultBackend sets the workflow-level default backend.
func WithEventHooks ¶
func WithEventHooks(h EventHooks) ClawExecutorOption
WithEventHooks sets observability callbacks on the executor.
func WithExecutorAsyncAsk ¶ added in v1.1.0
func WithExecutorAsyncAsk(b AsyncAskBinder) ClawExecutorOption
WithExecutorAsyncAsk installs the async-ask binder on the executor. Tasks built for interaction: async nodes then carry the PostAsyncQuestion / PendingAsyncQuestions / CollectAsyncAnswers closures consumed by both backends.
func WithExecutorInbox ¶ added in v0.39.0
func WithExecutorInbox(b InboxBinder) ClawExecutorOption
WithExecutorInbox installs the operator-chatbox binder on the executor. Every Task built by executeBackend / executeLLMRouterUnified then carries an InboxDrain closure so CLI-based backends (claude_code) can drain queued messages from inside their PostToolUse / Stop hooks. The claw backend's own copy is wired separately via WithInbox on the backend (set together in runview/executor.go); both share the same StoreInboxBinder so the run's queue is the single source of truth.
func WithExtraClosers ¶ added in v0.50.0
func WithExtraClosers(closers ...io.Closer) ClawExecutorOption
WithExtraClosers registers auxiliary resources (nil entries ignored) to be released when the executor is closed — e.g. the native board store opened for board.* MCP tools, whose fsnotify watcher would otherwise leak a goroutine + inotify fd per BuildExecutor call. Close() aggregates their errors.
func WithLifecycleHooks ¶
func WithLifecycleHooks(r *hooks.Runner) ClawExecutorOption
WithLifecycleHooks installs an in-process lifecycle hook runner. When set, the runner is consulted around every tool execution (PreToolUse, PostToolUse, PostToolUseFailure) and at session end (Stop). Build the runner once via hooks.NewRunner, register callbacks with runner.Register(event, handler), then pass it here.
A nil runner disables the integration (default).
func WithLogger ¶
func WithLogger(l *iterlog.Logger) ClawExecutorOption
WithLogger sets a leveled logger for the executor.
func WithMCPManager ¶
func WithMCPManager(m *mcp.Manager) ClawExecutorOption
WithMCPManager sets the generic MCP manager used to lazily discover MCP tools.
func WithModelOverrides ¶ added in v0.39.0
func WithModelOverrides(o ModelOverrides) ClawExecutorOption
WithModelOverrides sets the launch-time per-node/-group backend+model+ provider overrides (studio Launch dropdowns / CLI --model/--backend). They take precedence over the node's DSL backend:/model:. Empty is a no-op.
func WithPermissionOverride ¶ added in v0.39.0
func WithPermissionOverride(mode string) ClawExecutorOption
WithPermissionOverride sets the run-level permission-gate override (CLI --permission / studio Launch): off|ask|deny, or "" to defer to DSL/env. Highest-priority input to the mode precedence (override > node > workflow > env > off).
func WithPermissionRules ¶ added in v0.39.0
func WithPermissionRules(allow, ask, deny []string) ClawExecutorOption
WithPermissionRules adds run-level permission rules (CLI --permission-allow / --permission-ask / --permission-deny). They are additive on top of the workflow-level rule lists.
func WithRetryPolicy ¶
func WithRetryPolicy(rp RetryPolicy) ClawExecutorOption
WithRetryPolicy sets the retry policy for transient LLM errors.
func WithRewriteChain ¶ added in v0.39.0
func WithRewriteChain(chain *rewrite.Chain) ClawExecutorOption
WithRewriteChain sets the active rewriter chain (the enabled rewriter plugins, rtk by default), wired from the plugin registry at startup. Nil disables compression regardless of mode.
func WithSecretGuard ¶ added in v0.39.0
func WithSecretGuard(g *secretguard.Guard) ClawExecutorOption
WithSecretGuard installs the per-run secrets scrubber. Shared with the event hooks; the executor uses it to redact node_finished output (runtime.SecretScrubber) and to materialise ${secret.X} placeholders at tool/shell exec. A nil guard disables secrets protection.
func WithSourceIssueID ¶ added in v1.0.0
func WithSourceIssueID(issueID string) ClawExecutorOption
WithSourceIssueID stamps the ticket that owns this run so board.create can auto-link spawned children (parent_id / spawned_from).
func WithStoreDir ¶ added in v0.39.0
func WithStoreDir(dir string) ClawExecutorOption
func WithToolPolicy ¶
func WithToolPolicy(p tool.ToolChecker) ClawExecutorOption
WithToolPolicy sets the tool execution policy on the executor. When set, every tool call is checked against the allowlist before execution. A denied tool produces an explicit error.
func WithToolRegistry ¶
func WithToolRegistry(tr *tool.Registry) ClawExecutorOption
WithToolRegistry sets the unified tool registry on the executor.
func WithWorkDir ¶
func WithWorkDir(dir string) ClawExecutorOption
WithWorkDir sets the working directory for backend subprocesses. When set, backend nodes will run their CLI in this directory.
type CompactInfo ¶
type CompactInfo struct {
// BeforeMessages is the message count before compaction.
BeforeMessages int
// AfterMessages is the message count after compaction.
AfterMessages int
// RemovedMessageCount is reported by claw's CompactionResult.
RemovedMessageCount int
}
CompactInfo is passed to the OnCompact hook when the running tool-loop message history is shrunk by claw's pure-function compactor between iterations. Emitted only when compaction actually fired (no event when the transcript was short enough to skip).
type ContextOverflowError ¶
type ContextOverflowError struct {
Message string
}
ContextOverflowError indicates the prompt exceeded the model's context window.
func (*ContextOverflowError) Error ¶
func (e *ContextOverflowError) Error() string
type DelegateInfo ¶
type DelegateInfo struct {
BackendName string // e.g. "claude_code", "codex"
Duration time.Duration // subprocess wall-clock time
Tokens int // estimated total tokens consumed
ExitCode int // process exit code
Stderr string // captured stderr output
RawOutputLen int // byte length of raw stdout
ParseFallback bool // true if structured output fell back to text wrapper
FormattingPassUsed bool // true if two-pass execution was used (tools + schema)
Error error // non-nil for OnDelegateError
Attempt int // 1-based retry number (for OnDelegateRetry)
Delay time.Duration // backoff delay (for OnDelegateRetry)
}
DelegateInfo describes a backend execution attempt, passed to backend hooks.
type ErrNeedsInteraction ¶
type ErrNeedsInteraction struct {
NodeID string
Questions map[string]any // question_key → question text
SessionID string // delegate session ID for re-invocation
Backend string // delegate backend name (empty for claw direct)
// Conversation is the persisted backend-specific conversation history
// captured at the pause point (claw: marshalled []api.Message). The
// runtime relays this opaque blob into the checkpoint so that resume
// can rehydrate the LLM's mid-tool-loop state instead of restarting
// from system+user prompts. Backends that cannot persist conversation
// state (CLI: claude_code, codex) leave this nil.
Conversation json.RawMessage
// PendingToolUseID is the ID of the tool_use block in Conversation
// that is awaiting an answer. Required when Conversation is non-nil.
PendingToolUseID string
}
ErrNeedsInteraction is returned by the executor when a delegate or LLM signals that it needs user input to continue. The runtime engine should handle this by pausing (interaction: human), auto-responding (interaction: llm), or deciding (interaction: llm_or_human) based on the node's InteractionMode.
func (*ErrNeedsInteraction) Error ¶
func (e *ErrNeedsInteraction) Error() string
type EventEmitter ¶
type EventEmitter interface {
AppendEvent(ctx context.Context, runID string, evt store.Event) (*store.Event, error)
}
EventEmitter is the subset of store.RunStore used by the event bridge.
type EventHooks ¶
type EventHooks struct {
OnLLMRequest func(nodeID string, info LLMRequestInfo)
OnLLMPrompt func(nodeID string, systemPrompt string, userMessage string)
OnLLMResponse func(nodeID string, info LLMResponseInfo)
OnLLMRetry func(nodeID string, info RetryInfo)
OnLLMStepFinish func(nodeID string, step LLMStepInfo)
// OnAssistantText fires with each chunk of assistant narration —
// mid-turn prose the conversation views render as the agent
// "talking" while it works. claude_code fires it per streamed
// assistant text block; claw derives it from tool-bearing steps in
// the store hooks layer.
OnAssistantText func(nodeID string, info AssistantTextInfo)
// OnLLMTurnCapture fires once per claw tool-loop iteration after
// the conversation has been augmented with this step's
// assistant + tool_results blocks. The runtime persists the
// snapshot as a store.TurnCheckpoint anchored at (run, node,
// loop_iter, turn) — the load-bearing primitive for the
// fork-from-here UX and the per-node timeline. Conversation is
// an opaque []byte (JSON-encoded []api.Message) so EventHooks
// stays neutral to the wire format.
OnLLMTurnCapture func(nodeID string, info LLMTurnCaptureInfo)
OnLLMCompacted func(nodeID string, info LLMCompactInfo)
OnToolStarted func(nodeID string, info LLMToolStartedInfo)
OnToolCall func(nodeID string, info LLMToolCallInfo)
// OnToolNodeResult is called for direct tool nodes (not LLM tool loops)
// with full input/output content for detailed logging.
OnToolNodeResult func(nodeID string, toolName string, input []byte, output string, elapsed time.Duration, err error)
// Delegation lifecycle hooks.
OnDelegateStarted func(nodeID string, backendName string)
OnDelegateFinished func(nodeID string, info DelegateInfo)
OnDelegateError func(nodeID string, info DelegateInfo)
OnDelegateRetry func(nodeID string, info DelegateInfo)
// OnProviderFallback fires once each time a node's provider
// fallback chain falls through from a failed provider to the next
// one (see the DSL `provider: "a,b,c"` chain). It is purely
// observational — the run continues transparently against the next
// provider — and lets the studio / Prometheus exporter surface that
// a credential route was exhausted without the run itself failing.
OnProviderFallback func(nodeID string, info ProviderFallbackInfo)
// OnNodeFinished fires after a node's executor returns successfully.
// The output map carries iterion's conventional usage keys (`_tokens`,
// `_cost_usd`, `_model`) so observers (e.g. the Prometheus exporter)
// can attribute cost and tokens per-node without re-parsing the event
// log.
OnNodeFinished func(nodeID string, output map[string]any)
}
EventHooks allows the executor to emit observability events back to the caller.
func ChainHooks ¶
func ChainHooks(a, b EventHooks) EventHooks
ChainHooks composes two EventHooks so callbacks registered on either side run in order (a then b) for every event. Either side may leave any callback nil; the result keeps the non-nil one without an extra closure.
func NewStoreEventHooks ¶
func NewStoreEventHooks(ctx context.Context, emitter EventEmitter, runID string, logger *iterlog.Logger, guard *secretguard.Guard, observers ...func(store.Event)) EventHooks
NewStoreEventHooks returns EventHooks that emit store events for a given run and log emoji-rich console output via the provided logger. The logger controls which content fields are included in events:
- debug+: prompts, response text
- trace: tool call inputs/outputs, tool call details
ctx is captured by the returned hook closures: filesystem stores ignore it but cloud (Mongo) stores honor cancellation/timeout. The hook lifetime is bounded by the engine.Run call that constructed it. observers (ADR-046) fire on every persisted event emitted through the backend-hook layer — the dispatcher's stall-heartbeat seam for the high-frequency tool events that bypass the engine's WithEventObserver.
type FinishReason ¶
type FinishReason string
FinishReason indicates why generation stopped.
const ( FinishStop FinishReason = "stop" FinishToolCalls FinishReason = "tool-calls" FinishLength FinishReason = "length" FinishContentFilter FinishReason = "content-filter" FinishError FinishReason = "error" FinishOther FinishReason = "other" )
Canonical FinishReason constants.
type GenerationOptions ¶
type GenerationOptions struct {
// Model is the model ID (e.g., "claude-sonnet-4-6").
Model string
// System is the system prompt (plain string form).
System string
// SystemBlocks, when non-empty, takes precedence over System and is sent
// as the Anthropic array-form `system` field. This is the only way to
// attach `cache_control` markers to system content for prompt caching.
SystemBlocks []api.ContentBlock
// Messages is the initial conversation history.
Messages []api.Message
// Tools available for the model to call.
Tools []GenerationTool
// MaxSteps is the maximum number of tool-loop iterations (default 10).
MaxSteps int
// ForceInitialToolUse compels the model to call a tool before it may
// emit a final answer: while no tool has been called yet, the tool loop
// pins tool_choice to "any" (mapped to the provider's required/any
// form), reverting to auto once the first tool call lands. This is the
// agentic-parity lever for backends/models that, under the default
// "auto" tool_choice, skip provided tools and answer from priors — the
// exact failure that let a claw+gpt-5.5 reviewer produce an ungrounded
// verdict (0 tool calls) while claude_code read the files. No-op when
// Tools is empty. Set by the claw backend for tool-equipped agent/judge
// nodes; harmless for models that already use their tools.
ForceInitialToolUse bool
// MaxTokens is the maximum tokens per response (default 8192).
MaxTokens int
// Temperature controls randomness (nil = provider default).
Temperature *float64
// ExplicitSchema is the JSON schema for structured output (GenerateObjectDirect).
ExplicitSchema json.RawMessage
// SchemaName is the name for the synthetic structured-output tool (default "structured_output").
SchemaName string
// ProviderOptions are provider-specific options (e.g., reasoning_effort).
ProviderOptions map[string]any
// MaterializeSecrets, when non-nil, swaps secret placeholders for
// their real values in agent-emitted tool input immediately before
// execution (Layer 1). The placeholder form is what hooks/events
// persist, so the real secret never reaches the store.
MaterializeSecrets func(string) string
// CompactThresholdRatio overrides the default compaction trigger as a
// fraction of the model's context window. 0 falls back to the built-in
// default (0.85). Values outside (0, 1] fall back to the default.
CompactThresholdRatio float64
// CompactPreserveRecent overrides the default count of recent messages
// kept verbatim during compaction. 0 falls back to the built-in default
// (4). Values < 0 fall back to the default.
CompactPreserveRecent int
// OnRequest is called before each StreamResponse call.
OnRequest func(RequestInfo)
// OnResponse is called after each StreamResponse aggregation completes.
OnResponse func(ResponseInfo)
// OnStepFinish is called after each tool-loop step completes.
OnStepFinish func(StepResult)
// OnTurnCapture is called once per loop iteration after the
// conversation has been augmented with the step's assistant message
// (and tool_results, when the step contained tool calls). The
// snapshot is a defensive copy the callback may persist or hand off
// to a goroutine. Used by the runtime to write per-turn
// TurnCheckpoint artifacts that anchor the fork-from-here UX
// without disturbing the live message slice. Nil disables turn
// capture.
OnTurnCapture func(turn TurnCaptureInfo)
// OnToolStarted is called immediately before each tool executes,
// once the PreToolUse lifecycle hook (if any) has allowed the call.
// Mirrors OnToolCall but carries no duration/error.
OnToolStarted func(ToolCallInfo)
// OnToolCall is called after each tool execution.
OnToolCall func(ToolCallInfo)
// OnBeforeCompact fires only when in-loop compaction is about to
// shrink the history. The callback may return a modified slice
// (e.g. with an injected session-memory user turn) that feeds the
// summariser; the live history keeps the originals. Returning nil
// is a no-op.
OnBeforeCompact func(messages []api.Message) []api.Message
// OnCompact is called once after each in-loop compaction round
// that actually shrunk the message history. No-op compactions
// (transcript too short) do not fire the callback.
OnCompact func(CompactInfo)
// OnContextCompactRetry fires when a model call was REJECTED for
// exceeding the backend's real context window and the loop reacted by
// force-compacting the history and retrying. afterMessages is the
// post-compaction message count; targetTokens the budget it shrank to.
// Lets the backend surface the recovery as an llm_retry event.
OnContextCompactRetry func(attempt int, err error, afterMessages, targetTokens int)
// Hooks, when non-nil, is consulted around tool execution and at
// session end. PreToolUse fires before each Execute and may Block
// (the tool returns a synthetic refusal). PostToolUse fires after
// successful Execute, PostToolUseFailure fires on error. Stop
// fires once when the generation loop exits (success or failure).
Hooks *hooks.Runner
// Inbox, when non-nil, plumbs the run's operator-message inbox
// into the tool loop. After each tool-results turn the engine
// calls Inbox.Consume (transitioning the previous round's
// delivered messages to "consumed") and then Inbox.Drain
// (returning new operator texts to append as a synthetic user
// turn). Delivery is cooperative — between iterations, never
// mid-stream — mirroring Claude Code CLI's queued-message
// semantics. Nil disables the inbox plumbing.
Inbox InboxHook
// Permission, when enabled, is the tool-permission gate evaluated
// before each tool executes (the anti-prompt-injection boundary).
// Allow → execute; Deny → a synthetic refusal tool_result; Ask →
// the loop aborts with a *delegate.ErrAskUser so the run pauses and
// the human approves (claw's half of cross-backend parity with
// claude_code's PreToolUse permission hook). Nil/disabled = no gate.
Permission *permission.Policy
}
GenerationOptions configures a direct generation call.
type GenerationTool ¶
type GenerationTool struct {
// Name is the tool identifier.
Name string
// Description describes what the tool does.
Description string
// InputSchema is the JSON schema for the tool's input parameters.
InputSchema json.RawMessage
// Execute runs the tool with the given JSON input and returns the result text.
Execute func(ctx context.Context, input json.RawMessage) (string, error)
}
GenerationTool describes a tool available during direct generation. It replaces sdk.Tool for the native generation engine.
type InboxBinder ¶ added in v0.39.0
InboxBinder constructs a per-run InboxHook. The runtime supplies a store-backed implementation; tests can plug in a stub. Returning nil disables the inbox plumbing for that specific run.
type InboxHook ¶ added in v0.39.0
InboxHook is invoked by the generation tool-loop between iterations: Consume marks the previous round's delivered messages as consumed, Drain returns any new operator-typed texts to inject before the next LLM call. Both run cooperatively at safe boundaries — never mid-stream.
type KeyedProviderFactory ¶ added in v0.39.0
KeyedProviderFactory builds an APIClient given an explicit API key. Used by ResolveWithContext when a per-run BYOK plaintext is available — the result is NOT cached (multi-tenant safety).
type LLMCompactInfo ¶
type LLMCompactInfo struct {
BeforeMessages int
AfterMessages int
RemovedMessageCount int
// Iteration is the 0-based loop iteration (see LLMRequestInfo.Iteration).
Iteration int
}
LLMCompactInfo describes a mid-tool-loop compaction round, passed to the OnLLMCompacted hook. Emitted when claw's pure-function compactor shrinks the running message history before the next StreamResponse call so long agentic loops on small-context models do not silently hit context_length_exceeded.
type LLMRequestInfo ¶
type LLMRequestInfo struct {
Model string
MessageCount int
ToolCount int
ReasoningEffort string
Timestamp time.Time
// Iteration is the 0-based loop iteration the node is executing in,
// threaded through by applyHooks. Drives the [node#iter/claw] console
// tag so the studio's per-(node,iteration) Logs tab can associate the
// line; without it every claw line stuck at #0 (the hook closures
// captured a base context, not the live per-iteration one).
Iteration int
}
LLMRequestInfo describes an LLM request, passed to the OnLLMRequest hook.
type LLMResponseInfo ¶
type LLMResponseInfo struct {
Latency time.Duration
InputTokens int
OutputTokens int
CacheReadTokens int
CacheWriteTokens int
FinishReason string
Error error
StatusCode int
}
LLMResponseInfo describes an LLM response, passed to the OnLLMResponse hook.
type LLMStepInfo ¶
type LLMStepInfo struct {
Number int
Text string
ToolCalls []ToolCallEntry
FinishReason string
InputTokens int
OutputTokens int
CacheReadTokens int
CacheWriteTokens int
// ReasoningTokens is an approximate count of extended-thinking tokens
// (re-encoded from the thinking text); ThinkingMs is the wall-clock spent
// in thinking blocks. Both are 0 when the step produced no thinking.
ReasoningTokens int
ThinkingMs int
// Thinking is the extended-thinking text for this step (empty when the
// step produced no thinking).
Thinking string
// Iteration is the 0-based loop iteration (see LLMRequestInfo.Iteration).
Iteration int
}
LLMStepInfo describes a single step in a multi-step LLM generation, passed to the OnLLMStepFinish hook.
type LLMToolCallInfo ¶
type LLMToolCallInfo struct {
ToolName string
InputSize int
// ToolUseID correlates this completion event with the matching
// tool_started event. The studio merges the two by this id so the
// post-execution event (duration + error) lines up with the
// pre-execution event (structured input payload for whitelisted
// tools). Empty when the path can't provide one — the merge then
// falls through and the card renders with whatever data the
// tool_called event alone carries.
ToolUseID string
// Output is the string the tool returned to the LLM. The hooks layer
// truncates and persists it on the tool_called event so the studio's
// per-node Tools tab can render in+out the way Claude Code does.
// Empty when the backend can't surface a result (e.g. tool blocked
// pre-execution by a lifecycle hook, unknown tool dispatch).
Output string
Duration time.Duration
Error error
}
LLMToolCallInfo describes a tool call execution, passed to the OnToolCall hook.
type LLMToolStartedInfo ¶ added in v0.39.0
type LLMToolStartedInfo struct {
ToolName string
InputSize int
// ToolUseID correlates start↔completion when the same node fires
// multiple parallel tool calls (e.g. claude_code's assistant message
// with several tool_use blocks). Empty when the path can't provide
// one (direct tool nodes, claw single tool loop).
ToolUseID string
// Input is the raw JSON arguments the LLM produced for this call.
// May be empty when the backend cannot surface it. The hooks layer
// persists it (truncated) on the tool_started event so the studio's
// per-node Tools tab can render parameters (command, file_path,
// todos, …) for every tool — symmetric with the post-execution
// `output` field on LLMToolCallInfo.
Input json.RawMessage
// Iteration is the 0-based loop iteration of the node firing this
// tool call (see LLMRequestInfo.Iteration). Populated so the plan-
// capture hook can tag each TodoWrite snapshot with the pass it came
// from; 0 for direct tool nodes / paths that don't carry one.
Iteration int
}
LLMToolStartedInfo describes a tool call about to execute, passed to the OnToolStarted hook. Emitted immediately before the tool runs so observers can render an in-flight indicator (e.g. the studio's "Running <tool>" footer) while waiting for completion.
type LLMTurnCaptureInfo ¶ added in v0.39.0
type LLMTurnCaptureInfo struct {
Step int
Text string
ToolCalls []ToolCallEntry
FinishReason string
InputTokens int
OutputTokens int
CacheReadTokens int
CacheWriteTokens int
// Iteration is the 0-based loop iteration (see LLMRequestInfo.Iteration).
// Threaded so TurnCheckpoint.LoopIter is correct — it previously came
// from a stale captured context and was always 0.
Iteration int
// Backend names the executor that produced this turn ("claw" or
// "claude_code"). Used by the store-backed hook to set the
// matching TurnCheckpoint.Backend field. Empty defaults to "claw"
// for back-compat with paths that don't fill it explicitly.
Backend string
// SessionID is the claude_code CLI session id captured at the end
// of a delegate call. Empty for claw (no session-id concept) and
// for claude_code paths that didn't surface one. The Fork API
// passes it to `claude --resume <id> --fork-session` for the
// claude_code rehydration path.
SessionID string
// contains filtered or unexported fields
}
LLMTurnCaptureInfo describes one captured tool-loop turn, passed to the OnLLMTurnCapture hook. Carries the per-step metadata (finish_reason, tool calls, usage) plus the JSON-encoded conversation snapshot the runtime persists as a store.TurnCheckpoint.MessagesRef for the Fork API rehydration path.
Conversation is the JSON-encoded []api.Message slice taken at the natural end-of-iteration boundary — the very state the next LLM call would observe if the loop continued. Treat as immutable.
func (LLMTurnCaptureInfo) MarshalConversation ¶ added in v0.39.0
func (i LLMTurnCaptureInfo) MarshalConversation() json.RawMessage
MarshalConversation encodes the captured message slice as JSON, on demand. Returns nil when the turn carried no conversation (the claude_code path, or an SDK that didn't surface one). Errors are folded into a nil return so the store-backed hook treats them as "snapshot unavailable" rather than aborting the run.
type ModelCapabilities ¶
type ModelCapabilities = llmtypes.ModelCapabilities
ModelCapabilities describes what features a model supports. Re-exported from llmtypes to keep the model package API stable.
type ModelOverrides ¶ added in v0.39.0
type ModelOverrides struct {
// contains filtered or unexported fields
}
ModelOverrides is an ordered set of launch-time per-node/per-group backend+model+provider overrides, populated from the studio Launch dropdowns or the CLI --model / --backend flags. The zero value applies nothing, so a run with no overrides behaves exactly as before.
A selector matches a node by (most specific first):
- exact node id ("reviewer_claude")
- id glob ("reviewer_*", "fix_*") — path.Match syntax
- node-kind keyword ("agent", "judge", "router")
- "*" every LLM node (run-level default)
For each field (backend/model/provider) the most specific matching rule that sets a non-empty value wins; ties resolve to the later rule. Because resolution is per-field, `--model 'reviewer_*=X'` and `--backend '*=claw'` compose (the reviewer gets model X on backend claw). Overrides sit at the TOP of the resolution chain — above the node's DSL backend:/model: — because the operator is explicitly re-targeting the bot at launch without editing the .bot.
func ParseModelOverrides ¶ added in v0.39.0
func ParseModelOverrides(modelFlags, backendFlags []string) (ModelOverrides, error)
ParseModelOverrides builds a ModelOverrides from repeatable CLI flag values. Each element of modelFlags/backendFlags is a "selector=value" (or a bare "value" targeting every node). Returns a descriptive error on a malformed element so the run fails fast instead of silently ignoring a typo.
func (ModelOverrides) Empty ¶ added in v0.39.0
func (o ModelOverrides) Empty() bool
Empty reports whether no rules are configured.
func (ModelOverrides) ForNode ¶ added in v0.39.0
func (o ModelOverrides) ForNode(id string, kind ir.NodeKind) NodeModelOverride
ForNode resolves the effective override for a node id + kind. Returns an empty override when nothing matches (the caller then keeps the node's DSL values). Resolution is per-field: the most specific matching rule setting a non-empty value for that field wins.
func (*ModelOverrides) SetBackend ¶ added in v0.39.0
func (o *ModelOverrides) SetBackend(selector, backend string)
SetBackend adds a backend directive for the selector.
func (*ModelOverrides) SetModel ¶ added in v0.39.0
func (o *ModelOverrides) SetModel(selector, model string)
SetModel adds a model directive for the selector.
func (*ModelOverrides) SetProvider ¶ added in v0.39.0
func (o *ModelOverrides) SetProvider(selector, provider string)
SetProvider adds a provider directive for the selector.
type NodeModelOverride ¶ added in v0.39.0
NodeModelOverride is the resolved launch-time override for a single node: which backend / model / provider to use instead of the node's DSL values. Empty fields mean "leave the node's resolved value unchanged".
func (NodeModelOverride) Empty ¶ added in v0.39.0
func (o NodeModelOverride) Empty() bool
Empty reports whether the override carries no directive (all fields blank).
type NodeSessionStore ¶ added in v0.5.0
type NodeSessionStore = nodeSessionStore
NodeSessionStore is the public alias the runner uses to construct a store (the unexported alias preserves the in-package call-sites).
func NewNodeSessionStore ¶ added in v0.5.0
func NewNodeSessionStore() *NodeSessionStore
NewNodeSessionStore exposes the internal store constructor for the claw runner sub-binary (V2-4).
type ObjectResult ¶
type ObjectResult[T any] struct { // Object is the deserialized result. Object T // Text is the raw text that was parsed. Text string // Steps contains results from each generation step. Steps []StepResult // TotalUsage is the aggregated token usage across all steps. TotalUsage Usage // FinishReason indicates why generation stopped. FinishReason FinishReason }
ObjectResult is a typed wrapper around a text generation result that includes a deserialized object of type T (for structured output / GenerateObject).
func GenerateObjectDirect ¶
func GenerateObjectDirect[T any](ctx context.Context, client api.APIClient, opts GenerationOptions) (*ObjectResult[T], error)
GenerateObjectDirect generates structured output by injecting a synthetic tool with the given schema and forcing the model to call it. The tool_use input is parsed as the result object of type T.
type PlanWriter ¶ added in v0.39.0
type PlanWriter interface {
AppendPlanSnapshot(ctx context.Context, runID string, snap store.PlanSnapshot) (store.PlanSnapshot, bool, error)
}
PlanWriter is the optional capability stores satisfy for persisting the chronological plan snapshots agents produce via their TodoWrite (claude_code) / todo_write (claw) tool. When present, the tool-started hook captures each snapshot (filesystem → runs/<id>/plans/, Mongo → run_plans collection). The hook skips the capture when the capability is missing rather than failing the LLM call. In cloud mode the runner's metricsEmitter wrapper forwards this interface to the inner Mongo store (see pkg/runner metricsEmitter.AppendPlanSnapshot), otherwise the plain `emitter.(PlanWriter)` assertion below would hide it. See store.PlanStore for the format + dedup semantics.
type ProviderFactory ¶
ProviderFactory creates an APIClient for a given model ID. The factory is called once per unique model ID; results are cached.
type ProviderFallbackInfo ¶ added in v0.39.0
type ProviderFallbackInfo struct {
BackendName string // backend that ran the chain (e.g. "claude_code")
From string // provider hint that just failed ("" = auto)
To string // provider hint about to be tried next
FromModel string // effective model the failed provider ran (per-element override or node baseline)
ToModel string // effective model the next provider will run
Attempts int // retry attempts spent on the failed provider
Err error // the hard failure that triggered the fall-through
}
ProviderFallbackInfo describes a single fall-through within a node's provider fallback chain, passed to the OnProviderFallback hook.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func NewRegistry ¶
func NewRegistry() *Registry
NewRegistry creates a model registry pre-loaded with built-in providers.
func (*Registry) Capabilities ¶
func (r *Registry) Capabilities(spec string) (ModelCapabilities, error)
Capabilities returns the capabilities of the model identified by spec. Capabilities are derived from a static table keyed by provider and model family.
func (*Registry) Register ¶
func (r *Registry) Register(providerName string, factory ProviderFactory)
Register adds a provider factory under the given name. Calling Register with an already-registered name replaces the factory and invalidates any previously cached entries for that provider, so subsequent Resolve calls go through the new factory.
func (*Registry) Resolve ¶
Resolve parses a model spec ("provider/model-id") and returns the corresponding APIClient, creating it via the provider factory if not already cached.
Concurrency: the registry mutex is only held while looking up or creating the per-key cache entry — never during the factory call. Concurrent Resolve calls for the same spec rendezvous on the entry's sync.Once so the factory runs exactly once; concurrent calls for different specs run their factories in parallel.
func (*Registry) ResolveWithContext ¶ added in v0.39.0
ResolveWithContext is the BYOK-aware variant of Resolve.
When ctx carries per-run secrets.Credentials with a non-empty key for the requested provider, this method bypasses the cache and constructs a fresh APIClient using the override key. This is crucial in cloud mode: a single runner pod serially handles runs for many tenants, so caching one tenant's API key against a modelID would leak it across tenants.
When ctx has no credentials (local mode, or no BYOK configured), this falls through to Resolve(spec) which uses the env-var fallback + per-process cache.
type RequestInfo ¶
type RequestInfo struct {
// Model is the model ID.
Model string
// MessageCount is the number of messages in the request.
MessageCount int
// ToolCount is the number of tools available.
ToolCount int
// ReasoningEffort is the resolved reasoning_effort spec sent on the
// request, when set ("low", "medium", "high", "xhigh", "max"). Empty
// when the node did not request a reasoning level.
ReasoningEffort string
// Timestamp is when the request was initiated.
Timestamp time.Time
}
RequestInfo is passed to the OnRequest hook before a generation call.
type ResolvedCapabilities ¶ added in v0.39.0
type ResolvedCapabilities struct {
Provider string `json:"provider"`
Model string `json:"model"`
Spec string `json:"spec"`
Source CapabilitySource `json:"source"`
Reasoning bool `json:"reasoning"`
ToolCall bool `json:"tool_call"`
Temperature bool `json:"temperature"`
ContextWindow int `json:"context_window"`
}
ResolvedCapabilities is the CLI-facing resolution result: the same ModelCapabilities the runtime would compute, plus the resolution source.
func ResolveCapabilities ¶ added in v0.39.0
func ResolveCapabilities(provider, modelID string) ResolvedCapabilities
ResolveCapabilities resolves capabilities for an explicit provider + model ID, exactly as the runtime does via capabilitiesForModel(), and additionally reports whether the dynamic aggregator contributed (Source). It performs no blocking network fetch — call RefreshModelSpecs first to force one.
func ResolveSpec ¶ added in v0.39.0
func ResolveSpec(spec string) (ResolvedCapabilities, error)
ResolveSpec resolves a "provider/model-id" spec string. It returns an error (suitable for surfacing as a user-input error) when the spec is malformed.
type ResponseInfo ¶
type ResponseInfo struct {
// Latency is the time from request to response.
Latency time.Duration
// Usage is the token consumption for this call.
Usage Usage
// FinishReason indicates why generation stopped.
FinishReason FinishReason
// Error is non-nil if the call failed.
Error error
// StatusCode is the HTTP status code (0 if not applicable).
StatusCode int
}
ResponseInfo is passed to the OnResponse hook after a generation call completes.
type RetryInfo ¶
type RetryInfo struct {
Attempt int // 1-based retry number (attempt 1 = first retry)
Error error // the error that triggered this retry
StatusCode int // HTTP status code if available
Delay time.Duration // backoff delay before this retry
}
RetryInfo describes a retry attempt, passed to the OnLLMRetry hook.
type RetryPolicy ¶
type RetryPolicy struct {
// MaxAttempts is the total number of attempts (1 = no retry). Default: 3.
MaxAttempts int
// MaxAttemptsTransient is the attempt budget for connectivity/transient
// failures (network blips, upstream 5xx). Default: 6. Falls back to
// max(MaxAttempts, DefaultMaxAttemptsTransient) so it is never smaller
// than the standard budget.
MaxAttemptsTransient int
// BackoffBase is the base delay for exponential backoff. Default: 1s.
BackoffBase time.Duration
}
RetryPolicy controls automatic retry on transient LLM errors.
func RetryPolicyFromEnv ¶ added in v0.39.0
func RetryPolicyFromEnv() RetryPolicy
RetryPolicyFromEnv builds the in-executor per-node retry budget from the environment, falling back to the built-in defaults (DefaultMaxAttempts / DefaultMaxAttemptsTransient) for any dimension left unset. This is the LAYER-1 knob: it bounds how many times a transient backend failure (rate-limit, session-limit, idle-watchdog, network/5xx) is retried IN-EXECUTOR with exponential backoff before the failure bubbles up to a run-level failed_resumable (which the LAYER-2 auto-resume then handles).
The env values are RETRY counts (they exclude the initial attempt), so ITERION_NODE_MAX_TRANSIENT_RETRIES=8 yields 9 attempts. A value of 0 means "no retry" (fail-fast); a negative or non-numeric value is ignored (keeps the default) rather than silently disabling retries.
- ITERION_NODE_MAX_TRANSIENT_RETRIES → the connectivity/transient budget (network blips, upstream 5xx, rate-limit, idle hang). Default: 5 retries (6 attempts).
- ITERION_NODE_MAX_RETRIES → the standard budget for deterministic-but- retryable errors (signal kill). Default: 2 retries (3 attempts).
type ScreenshotDirective ¶ added in v0.39.0
ScreenshotDirective is one parsed `[iterion] preview_screenshot=...` line. Path is host-absolute; URL and ToolCallID are optional.
type SessionCaptureSink ¶ added in v0.5.0
type SessionCaptureSink interface {
// Capture is called after the local store has saved the snapshot.
// Implementations should not block — the caller is on the LLM
// loop's hot path.
Capture(runID, nodeID string, snapshot []byte)
}
SessionCaptureSink mirrors per-(runID, nodeID) message snapshots out of the local store into a side channel as they are saved. V2-4 uses it on the runner side: the sink emits delegate.EnvelopeSessionCapture envelopes so the launcher's host nodeSessionStore stays in sync with the runner's, enabling CompactAndRetry to compact the LATEST history rather than the last-known-good one. The host side leaves this nil — it owns the canonical store directly.
type StepResult ¶
type StepResult struct {
// Number is the 1-based step index.
Number int
// Text generated in this step.
Text string
// ToolCalls requested in this step.
ToolCalls []ToolCall
// FinishReason for this step.
FinishReason FinishReason
// Usage for this step.
Usage Usage
// Thinking is the extended-thinking (reasoning) text produced during
// this step; empty when the step produced no thinking.
Thinking string
}
StepResult describes a single generation step in a tool loop.
type StoreAsyncAskBinder ¶ added in v1.1.0
type StoreAsyncAskBinder struct {
Store store.RunStore
Publish func(store.Event)
// OnPosted, when set, is invoked after each successfully posted
// question (e.g. to ring a notification surface). Optional.
OnPosted func(runID, interactionID string)
}
StoreAsyncAskBinder is the production AsyncAskBinder, backed by a store.RunStore + an event-broker publish callback (same pair as StoreInboxBinder — local mode passes EventBroker.Publish, cloud mode nil and the change stream surfaces transitions).
func (*StoreAsyncAskBinder) BindAsyncAsk ¶ added in v1.1.0
func (b *StoreAsyncAskBinder) BindAsyncAsk(_ context.Context, runID, nodeID string) AsyncAskHook
BindAsyncAsk returns the hook scoped to (runID, nodeID), or nil when the binder is not configured for this run.
type StoreInboxBinder ¶ added in v0.39.0
type StoreInboxBinder struct {
Store store.RunStore
// Publish receives each user_message_* event after store-side
// persistence. Local mode passes EventBroker.Publish; cloud mode
// passes nil (the Mongo change-stream surfaces transitions).
Publish func(store.Event)
}
StoreInboxBinder is the production InboxBinder, backed by a store.RunStore + an event-broker publish callback. The hooks it returns reuse the shared store.DrainPending / store.MarkConsumed helpers so the runtime's pauseAtHuman drainer and the agent-loop drainer emit identical event payloads.
type TemplateData ¶
type TemplateData struct {
// Outputs is the per-node output map. Keys are node IDs.
Outputs map[string]map[string]any
// LoopCounters is the current iteration count per loop name
// (1-indexed once incremented by the engine).
LoopCounters map[string]int
// LoopMaxIterations is the declared `as <name>(N)` upper bound
// per loop name, sourced from ir.Workflow.Loops.
LoopMaxIterations map[string]int
// LoopPreviousOutput is the snapshot of the source node's output
// at the previous traversal of each loop's edge — i.e. one
// iteration behind the current one. Nil on the first iteration.
LoopPreviousOutput map[string]map[string]any
// Artifacts is the publish-name → output map for artifacts that
// have been produced so far in this run.
Artifacts map[string]map[string]any
// RunID is the current run identifier, exposed to prompts as
// `{{run.id}}`.
RunID string
// Attachments maps the workflow's attachment names to their
// resolved per-run metadata. Populated from Run.Attachments at
// the start of every node execution. Resolvers expose:
//
// {{attachments.<name>}} → host filesystem path
// {{attachments.<name>.path}} → host filesystem path (explicit)
// {{attachments.<name>.url}} → presigned URL (lazy: filled on demand)
// {{attachments.<name>.mime}} → sniffed MIME
// {{attachments.<name>.size}} → byte length as decimal string
// {{attachments.<name>.sha256}} → hex SHA-256
Attachments map[string]AttachmentInfo
}
TemplateData carries runtime state needed to resolve prompt template references in the `outputs.*`, `loop.*`, `artifacts.*`, and `run.*` namespaces. The runtime engine populates a snapshot of its current state before each node execution and attaches it via WithTemplateData so the executor can render prompt bodies that reference upstream outputs, loop counters, and previous-iteration snapshots.
All fields are read-only views — callers must not mutate them.
func TemplateDataFromContext ¶
func TemplateDataFromContext(ctx context.Context) *TemplateData
TemplateDataFromContext returns the TemplateData attached by WithTemplateData, or nil when none is set. Resolvers tolerate nil by leaving cross-namespace refs (`outputs.*`, `loop.*`, etc.) unresolved — callers that don't wire the runtime context still get `input.*` and `vars.*` resolution.
type TextResult ¶
type TextResult struct {
// Text is the accumulated generated text.
Text string
// ToolCalls requested by the model in the final step.
ToolCalls []ToolCall
// Steps contains results from each generation step.
Steps []StepResult
// TotalUsage is the aggregated token usage across all steps.
TotalUsage Usage
// FinishReason indicates why generation stopped.
FinishReason FinishReason
// Messages is the final accumulated conversation list, including
// the initial input plus every assistant turn (with tool_use
// blocks) and tool_result message produced during the loop. Hosts
// that maintain a per-node session — e.g. for compaction-aware
// retries — capture this slice and feed it back as opts.Messages
// on the next attempt.
Messages []api.Message
}
TextResult is the final result of a text generation call.
func GenerateTextDirect ¶
func GenerateTextDirect(ctx context.Context, client api.APIClient, opts GenerationOptions) (*TextResult, error)
type ToolBlobWriter ¶ added in v0.39.0
type ToolBlobWriter interface {
WriteToolBlob(ctx context.Context, runID, toolUseID, kind string, body []byte) (int64, error)
}
ToolBlobWriter is the optional capability filesystem stores satisfy for the per-tool-call sidecar I/O persistence path. When present, tool inputs/outputs exceeding `toolInlineThreshold` are written through it and the event carries a small head preview + a ref instead of the full body. Mongo (cloud) stores don't satisfy it today; the hook layer falls back to inline truncation in that case.
type ToolCall ¶
type ToolCall struct {
// ID is a unique identifier for this tool call.
ID string
// Name of the tool to invoke.
Name string
// Input is the JSON-encoded arguments.
Input json.RawMessage
}
ToolCall represents the model's request to invoke a tool.
type ToolCallEntry ¶
type ToolCallEntry struct {
Name string
Input json.RawMessage
}
ToolCallEntry describes a single tool call within a step.
type ToolCallInfo ¶
type ToolCallInfo struct {
// ToolName is the name of the tool that was called.
ToolName string
// InputSize is the byte length of the tool input JSON.
InputSize int
// ToolUseID correlates start↔completion when multiple parallel tool
// calls share a node. Populated for OnToolStarted; the post-execution
// OnToolCall path leaves it empty (existing callers don't need it).
ToolUseID string
// Input is the raw JSON arguments passed to the tool. Populated for
// OnToolStarted so observers can render the tool's target (URL, file
// path, query, …) and persist structured input for whitelisted tools.
// Empty on the post-execution OnToolCall path to avoid duplicating
// payloads in events.jsonl.
Input json.RawMessage
// Output is the string the tool returned to the LLM. Populated only on
// the post-execution OnToolCall path; empty on OnToolStarted. The
// hooks layer persists it (truncated) on the tool_called event so the
// studio's per-node Tools tab can render the in/out pair the way
// Claude Code does.
Output string
// Duration is how long the tool execution took.
Duration time.Duration
// Error is non-nil if the tool execution failed.
Error error
}
ToolCallInfo is passed to the OnToolCall / OnToolStarted hooks before (started) and after (completed) a tool executes.
type TurnCaptureInfo ¶ added in v0.39.0
type TurnCaptureInfo struct {
// Step is the 1-based step index, matching StepResult.Number.
Step int
// Result mirrors the StepResult passed to OnStepFinish.
Result StepResult
// Conversation is the snapshot the runtime persists. Treat as
// immutable — the generation loop reuses the underlying slice
// after the callback returns. Callbacks that hand the snapshot
// off to a goroutine MUST take their own copy first (the
// generation loop already does so before invoking the hook).
Conversation []api.Message
}
TurnCaptureInfo is the payload of the OnTurnCapture hook fired by the generation loop after every step completes (and after its tool results have been appended, when applicable). It carries everything the runtime needs to write a per-turn store.TurnCheckpoint plus, optionally, a sibling messages.json blob used as the rehydration source for the Fork API.
Conversation is a defensive copy of the messages slice at the natural end-of-iteration boundary — the very state the next LLM call would be made from if the loop continued. For the final step (no follow-up tool calls), the slice is augmented in-snapshot with a synthetic assistant text message so the snapshot is forkable too.
type TurnWriter ¶ added in v0.39.0
type TurnWriter interface {
WriteTurn(ctx context.Context, t *store.TurnCheckpoint) error
}
TurnWriter is the optional capability filesystem stores satisfy for the per-LLM-turn snapshot persistence path. Each tool-loop iteration completing inside the claw backend (or a delegate-call boundary for claude_code) is persisted as a store.TurnCheckpoint so the studio's timeline + the Fork API have a stable anchor. Mongo (cloud) stores don't satisfy it today; the hook layer skips the write when the capability is missing rather than failing the LLM call.
type Usage ¶
type Usage struct {
InputTokens int
OutputTokens int
TotalTokens int
ReasoningTokens int // approximate count of extended-thinking tokens (re-encoded text)
CacheReadTokens int
CacheWriteTokens int
ThinkingMs int // wall-clock spent in thinking blocks, milliseconds
}
Usage tracks token consumption for a request.
Source Files
¶
- api_errors.go
- async_ask.go
- capabilities.go
- capabilities_public.go
- claw_backend.go
- cursors.go
- effort.go
- events.go
- executor.go
- executor_build_task.go
- executor_hooks.go
- executor_human.go
- executor_resolve.go
- executor_retry.go
- executor_retry_policy.go
- executor_router.go
- executor_template.go
- executor_tool.go
- executor_toolresolve.go
- executor_verified_action.go
- generation.go
- generation_request.go
- generation_stream.go
- generation_tool.go
- generation_toolexec.go
- generation_types.go
- hooks.go
- iteration_ctx.go
- lifecycle_hooks.go
- llm_tool.go
- memory_tools.go
- model_override.go
- modelspec.go
- modelspecs.go
- preview_url.go
- registry.go
- review_companion.go
- schema.go
- secretguard.go
- session.go
- settings_hooks.go
- streaming_types.go
- subagent.go
- system_reminder.go
- template_ctx.go
- validate.go