Documentation
¶
Index ¶
- Constants
- Variables
- func ApplySafeError(event *ToolEvent, err error)
- func ArgumentsHash(args []byte) string
- func DurationMillis(elapsed time.Duration) int64
- func MessageIDFrom(ctx context.Context) (string, bool)
- func MessageWorkingDirectory(message protocol.ChatMessage) (string, bool)
- func RegisterArtifact(reg *Registry, cfg ArtifactConfig) error
- func RegisterInjectImage(reg *Registry, cfg InjectImageConfig) error
- func RegisterLocal(reg *Registry, cfg LocalConfig) error
- func RegisterMCPListResourceTemplatesTool(reg *Registry, cfg MCPResourceConfig) error
- func RegisterMCPListResourcesTool(reg *Registry, cfg MCPResourceConfig) error
- func RegisterMCPReadResourceTool(reg *Registry, cfg MCPResourceConfig) error
- func RegisterMCPTool(reg *Registry, cfg MCPToolConfig) error
- func RegisterMemory(reg *Registry, recaller MemoryRecaller) error
- func RegisterRemote(reg *Registry, names []string, cfg RemoteConfig) error
- func RegisterSubagent(reg *Registry, runner subagent.Runner, maxDepth int) error
- func RegisterSubagentWithConfig(reg *Registry, cfg SubagentConfig) error
- func ResolveWorkingPath(ctx context.Context, path string) string
- func SafeToolError(err error) (string, string)
- func StampWorkingDirectory(message *protocol.ChatMessage, cwd string)
- func ViewMutatingTool(name string) bool
- func WithCommandDelegate(ctx context.Context, d CommandDelegate) context.Context
- func WithFileDelegate(ctx context.Context, d FileDelegate) context.Context
- func WithMemoryAuthority(ctx context.Context, auth MemoryAuthority) context.Context
- func WithMessageID(ctx context.Context, id string) context.Context
- func WithModelPreference(ctx context.Context, fn ModelPreferenceFunc) context.Context
- func WithPartEmitter(ctx context.Context, e PartEmitter) context.Context
- func WithSkillRealizer(ctx context.Context, fn SkillRealizerFunc) context.Context
- func WithToolDelegate(ctx context.Context, d ToolDelegate) context.Context
- func WithViewWriteAccess(ctx context.Context, access workspacepkg.ViewWriteAccess) context.Context
- func WithWorkingDirectory(ctx context.Context, cwd string) context.Context
- func WithWorldStateSink(ctx context.Context, s WorldStateSink) context.Context
- func WithoutToolDelegate(ctx context.Context) context.Context
- func WorkingDirectoryFrom(ctx context.Context) (string, bool)
- type ArtifactConfig
- type ArtifactUploader
- type AuditRecord
- type AuditSink
- type CommandDecider
- type CommandDecision
- type CommandDelegate
- type CommandPattern
- type CommandPolicy
- type CommandPolicyConfig
- type CommandRequest
- type CommandRule
- type CommandRuleMatch
- type CommandToken
- type ConcurrencyClass
- type Decision
- type DecisionCode
- type Descriptor
- type DynamicPolicy
- type EffectLookup
- type FileAuditSink
- type FileChange
- type FileDelegate
- type GrantStore
- type Handler
- type HandlerFunc
- type HostExecutable
- type InjectImageConfig
- type LocalConfig
- type MCPCaller
- type MCPProvider
- type MCPProviderConfig
- type MCPResourceConfig
- type MCPToolConfig
- type MemoryAuthority
- type MemoryHit
- type MemoryRecaller
- type ModelPreferenceFunc
- type PartEmitter
- type PatchFileDelegate
- type Policy
- type PreparedInvocation
- type ReadOnlyAutoApprove
- type Registry
- func (r *Registry) Describe(d Descriptor)
- func (r *Registry) Descriptors() []Descriptor
- func (r *Registry) EffectOf(name string) (spec.ToolEffect, bool)
- func (r *Registry) Invoke(ctx context.Context, req Request) (Result, error)
- func (r *Registry) Names() []string
- func (r *Registry) Override(name string, handler Handler) error
- func (r *Registry) Prepare(ctx context.Context, req Request) (PreparedInvocation, error)
- func (r *Registry) Register(name string, handler Handler) error
- func (r *Registry) SetEventSink(events ToolEventSink)
- func (r *Registry) SetExcluded(names []string)
- func (r *Registry) SetPolicy(policy Policy, audit AuditSink)
- type RemoteConfig
- type RemoteInvoker
- type Request
- type Result
- type ResultMetadata
- type ResultReference
- type SkillRealizerFunc
- type StaticPolicy
- type SubagentConfig
- type ToolDelegate
- type ToolEvent
- type ToolEventSink
- type ToolEventStatus
- type TrustLevel
- type WorldStateSink
Constants ¶
const ( // DefaultOutputArchiveLimit is the per-call archive budget. It is deliberately // larger than a typical MaxOutput so the archive is worth reading, and small // enough that a runaway command cannot fill the workspace from one call. DefaultOutputArchiveLimit = 1 << 20 // 1 MiB // DefaultOutputArchiveDir sits beside the compaction eviction sink's dir so // everything the model is expected to read back lives under one root. DefaultOutputArchiveDir = ".agent/tool-output" )
const SubagentToolName = "spawn_subagent"
SubagentToolName is the registry name of the spawn_subagent tool. Exported so a distribution can scope it out per turn (e.g. WithExcludedTools on an ephemeral one-shot, which must not spawn durable child threads).
const WorkingDirectoryMetaKey = "working_directory"
WorkingDirectoryMetaKey carries a client-selected per-turn working directory. The local workspace still enforces its read/write roots; this value only changes how otherwise-relative tool paths are resolved.
Variables ¶
var ( ErrInvalidCommandPolicy = errors.New("tools: invalid command policy") ErrCommandPolicyFixture = errors.New("tools: command policy fixture failed") )
var ( ErrInvalidTool = errors.New("tools: invalid tool") ErrToolExists = errors.New("tools: already registered") ErrUnknownTool = errors.New("tools: unknown tool") ErrInvalidArgument = errors.New("tools: invalid argument") )
var ErrToolRequiresApproval = fmt.Errorf("tools: approval required")
Functions ¶
func ApplySafeError ¶
func ArgumentsHash ¶
func DurationMillis ¶
func MessageIDFrom ¶
MessageIDFrom returns the assistant message id carried by WithMessageID.
func MessageWorkingDirectory ¶
func MessageWorkingDirectory(message protocol.ChatMessage) (string, bool)
MessageWorkingDirectory returns an absolute client-selected cwd when present.
func RegisterArtifact ¶
func RegisterArtifact(reg *Registry, cfg ArtifactConfig) error
RegisterArtifact registers present_artifact: the agent names workspace files it produced (e.g. a chart it saved) and the harness surfaces them to the user as native image/file content parts on the assistant message — bypassing markdown image rendering entirely. Small images inline as a data_uri; larger images and non-image files upload via the ArtifactUploader and ride as a vfs_ref the frontend presigns and fetches.
func RegisterInjectImage ¶
func RegisterInjectImage(reg *Registry, cfg InjectImageConfig) error
RegisterInjectImage registers inject_image: the agent names a local image it produced (a chart it saved, a rendered slide/PDF page) and the harness injects it as a user-role image message into the agent's OWN context so it can visually inspect its own work before finishing. The image snapshot rides as a base64 data_uri (reusing the provider passthrough — no provider change); when the image enters context the harness escalates the rest of the turn to a vision-capable model.
func RegisterLocal ¶
func RegisterLocal(reg *Registry, cfg LocalConfig) error
func RegisterMCPListResourceTemplatesTool ¶
func RegisterMCPListResourceTemplatesTool(reg *Registry, cfg MCPResourceConfig) error
func RegisterMCPListResourcesTool ¶
func RegisterMCPListResourcesTool(reg *Registry, cfg MCPResourceConfig) error
func RegisterMCPReadResourceTool ¶
func RegisterMCPReadResourceTool(reg *Registry, cfg MCPResourceConfig) error
func RegisterMCPTool ¶
func RegisterMCPTool(reg *Registry, cfg MCPToolConfig) error
func RegisterMemory ¶
func RegisterMemory(reg *Registry, recaller MemoryRecaller) error
RegisterMemory registers the memory_search and memory_get tools backed by the recaller, with descriptors so they are exposed via the provider tool-API.
func RegisterRemote ¶
func RegisterRemote(reg *Registry, names []string, cfg RemoteConfig) error
func RegisterSubagent ¶
RegisterSubagent registers the spawn_subagent tool, which delegates a self-contained sub-task to a fresh, bounded sub-agent. maxDepth caps nesting (a call at or beyond the limit returns an error result rather than recursing). The runner may be a late-bound *subagent.Ref so the tool can be surfaced to the model before the concrete runner is constructed.
func RegisterSubagentWithConfig ¶
func RegisterSubagentWithConfig(reg *Registry, cfg SubagentConfig) error
func ResolveWorkingPath ¶
ResolveWorkingPath resolves a tool path from the active per-turn cwd. With no active cwd it preserves the original argument byte-for-byte.
func SafeToolError ¶
func StampWorkingDirectory ¶
func StampWorkingDirectory(message *protocol.ChatMessage, cwd string)
StampWorkingDirectory records cwd on an inbound message. Empty and relative values are ignored so an untrusted message cannot silently reinterpret paths.
func ViewMutatingTool ¶ added in v0.0.2
ViewMutatingTool reports tools that can modify the selected execution view. Shell and Python are conservatively mutating because their payloads are general programs and cannot be proven read-only from the tool name alone.
func WithCommandDelegate ¶
func WithCommandDelegate(ctx context.Context, d CommandDelegate) context.Context
WithCommandDelegate carries a CommandDelegate on ctx. nil is a no-op.
func WithFileDelegate ¶
func WithFileDelegate(ctx context.Context, d FileDelegate) context.Context
WithFileDelegate carries a FileDelegate on ctx. nil is a no-op.
func WithMemoryAuthority ¶
func WithMemoryAuthority(ctx context.Context, auth MemoryAuthority) context.Context
WithMemoryAuthority returns a context carrying the per-turn MemoryAuthority. The runner sets this before a history load so an authority-aware store can apply the user's OBO grant; stores that don't need it simply ignore it.
func WithMessageID ¶
WithMessageID carries the enclosing assistant message id on ctx so the Request builders (session + dynamic invocation) can stamp Request.MessageID. Mirrors how MemoryAuthority flows on ctx. Empty id is a no-op.
func WithModelPreference ¶
func WithModelPreference(ctx context.Context, fn ModelPreferenceFunc) context.Context
WithModelPreference returns a context carrying the per-turn model-preference fn.
func WithPartEmitter ¶
func WithPartEmitter(ctx context.Context, e PartEmitter) context.Context
WithPartEmitter returns a context carrying the per-turn PartEmitter.
func WithSkillRealizer ¶
func WithSkillRealizer(ctx context.Context, fn SkillRealizerFunc) context.Context
WithSkillRealizer returns a context carrying the per-turn skill realizer.
func WithToolDelegate ¶ added in v0.0.2
func WithToolDelegate(ctx context.Context, d ToolDelegate) context.Context
WithToolDelegate carries a full-invocation delegate on ctx. nil is a no-op.
func WithViewWriteAccess ¶ added in v0.0.2
func WithViewWriteAccess(ctx context.Context, access workspacepkg.ViewWriteAccess) context.Context
WithViewWriteAccess applies a local execution ceiling even when standalone mode has no explicit distributed view binding.
func WithWorkingDirectory ¶
WithWorkingDirectory carries the active cwd across the whole tool loop, including synchronous subagents spawned from that turn.
func WithWorldStateSink ¶
func WithWorldStateSink(ctx context.Context, s WorldStateSink) context.Context
WithWorldStateSink returns a context carrying the per-turn WorldStateSink.
func WithoutToolDelegate ¶ added in v0.0.2
WithoutToolDelegate marks a host-local execution boundary. A remote/worker delegate calls a local registry to execute the selected tool; that nested registry must not rediscover the outer delegate and recurse into itself.
Types ¶
type ArtifactConfig ¶
type ArtifactConfig struct {
// Workspace reads the artifact bytes the agent names. Required.
Workspace *localtools.Workspace
// Uploader stores large images + non-image files and returns a vfs_ref. nil →
// inline images only; non-image files error.
Uploader ArtifactUploader
// InlineMaxBytes is the image inline-vs-upload threshold (<=0 → 128 KiB).
InlineMaxBytes int
// MaxBytes hard-caps a single artifact read (<=0 → 32 MiB).
MaxBytes int
// SessionDir, when set, returns the per-(thread,context) working directory a
// code session writes relative files into (e.g. sahara's
// /sahara/sessions/<key>). A RELATIVE artifact path is resolved against it
// first — so a file a kernel saved with a bare name (plt.savefig('p.png')) is
// found — falling back to the workspace root. nil (or "" result) → paths
// resolve against the workspace root only (the prior behavior). The harness
// stays scheme-agnostic; the distribution owns the path derivation.
SessionDir func(threadID, context string) string
}
ArtifactConfig configures the present_artifact tool.
type ArtifactUploader ¶
type ArtifactUploader interface {
Upload(ctx context.Context, addr protocol.MessageAddress, name, mimeType string, data []byte) (vfsRef string, err error)
}
ArtifactUploader uploads agent-produced artifact bytes to a durable, frontend-fetchable store and returns an opaque reference (a data-connectors vfs_ref) the frontend resolves to a presigned download URL. The harness core ships no uploader; the distribution wires one (sahara: data-connectors). A nil uploader limits present_artifact to inlining images (non-image files error).
type AuditRecord ¶
type AuditRecord struct {
CallID string `json:"call_id"`
ToolName string `json:"tool_name"`
Decision DecisionCode `json:"decision"`
Reason string `json:"reason"`
AuditCode string `json:"audit_code"`
ArgumentsHash string `json:"arguments_hash"`
}
func NewAuditRecord ¶
func NewAuditRecord(req Request, decision Decision) AuditRecord
type CommandDecider ¶
type CommandDecider interface {
DecideCommand(req CommandRequest) CommandDecision
}
type CommandDecision ¶
type CommandDelegate ¶
type CommandDelegate interface {
RunCommand(ctx context.Context, spec localtools.CommandSpec) (localtools.CommandResult, error)
}
CommandDelegate overrides RunCommand for a turn: when one is on ctx (WithCommandDelegate), the shell/python handlers run the command through it (e.g. the ACP terminal/* client capability) instead of cfg.Workspace. The command policy is still enforced first, on the handler side.
func CommandDelegateFrom ¶
func CommandDelegateFrom(ctx context.Context) CommandDelegate
CommandDelegateFrom returns the CommandDelegate carried by WithCommandDelegate, or nil.
type CommandPattern ¶
type CommandPattern struct {
Tokens []CommandToken
}
type CommandPolicy ¶
type CommandPolicy struct {
// contains filtered or unexported fields
}
func NewCommandPolicy ¶
func NewCommandPolicy(cfg CommandPolicyConfig) (*CommandPolicy, error)
func (*CommandPolicy) DecideCommand ¶
func (p *CommandPolicy) DecideCommand(req CommandRequest) CommandDecision
type CommandPolicyConfig ¶
type CommandPolicyConfig struct {
Rules []CommandRule
HostExecutables []HostExecutable
ResolveHostExecutables bool
DefaultDecision DecisionCode
}
type CommandRequest ¶
type CommandRule ¶
type CommandRule struct {
ID string
Decision DecisionCode
Reason string
AuditCode string
Pattern CommandPattern
HostExecutable string
ReadOnly bool
Match [][]string
NotMatch [][]string
EnvAllowlist []string
}
type CommandRuleMatch ¶
type CommandRuleMatch struct {
RuleID string `json:"rule_id"`
MatchedPrefix []string `json:"matched_prefix"`
Decision DecisionCode `json:"decision"`
Reason string `json:"reason"`
AuditCode string `json:"audit_code"`
ReadOnly bool `json:"read_only"`
HostExecutable string `json:"host_executable,omitempty"`
ResolvedProgram string `json:"resolved_program,omitempty"`
}
type CommandToken ¶
func AnyToken ¶
func AnyToken(values ...string) CommandToken
func LiteralToken ¶
func LiteralToken(value string) CommandToken
type ConcurrencyClass ¶ added in v0.0.2
type ConcurrencyClass int
ConcurrencyClass declares whether invocations of a tool may overlap other calls from the same assistant message. This is execution metadata only: it is intentionally not sent to the model or inferred from a tool name.
The zero value is conservative. A call is eligible for concurrent execution only when every call in the assistant's batch is explicitly ParallelSafe.
const ( // ConcurrencyUnspecified keeps the tool sequential. This is the descriptor // zero value so existing and dynamically discovered tools fail closed. ConcurrencyUnspecified ConcurrencyClass = iota // ConcurrencySequential explicitly requires source-ordered execution. ConcurrencySequential // ConcurrencyParallelSafe promises that overlapping invocations do not // mutate shared state, do not use turn-mutating emitters, and are safe under // the turn's shared cancellation. Effects must be returned in Result. ConcurrencyParallelSafe )
type Decision ¶
type Decision struct {
Code DecisionCode `json:"code"`
Reason string `json:"reason"`
AuditCode string `json:"audit_code"`
}
type DecisionCode ¶
type DecisionCode string
const ( DecisionAllow DecisionCode = "allow" DecisionRequiresApproval DecisionCode = "requires_approval" DecisionDeny DecisionCode = "deny" )
type Descriptor ¶
type Descriptor struct {
Name string
Description string
Parameters json.RawMessage // JSON-schema object; empty => {"type":"object"}
// CatalogKind is the portable descriptor kind for dynamically published
// tools. Empty defaults to "remote" in the ToolProvider compatibility
// adapter.
CatalogKind string
// CatalogMeta is provider-owned metadata that is admitted as part of the
// immutable catalog entry and returned to that same provider at invocation.
// It is never exposed as model arguments. Transport adapters use it to carry
// an upstream exact reference through a wrapper catalog without trusting
// caller-supplied routing fields.
CatalogMeta map[string]json.RawMessage
// Effect is the highest admitted portable side-effect class. Empty defaults
// conservatively to execute; providers should set it when they can classify
// the tool more precisely.
Effect spec.ToolEffect
// Trust is the authorization hint for the tool. Zero value (TrustDefault)
// leaves authorization to the runtime policy; a provider may stamp a stronger
// hint (a later stage — no local descriptor sets it today).
Trust TrustLevel
// Concurrency is the tool's neutral runtime concurrency contract. It is not
// part of the model-facing function schema. Unspecified is sequential.
Concurrency ConcurrencyClass
}
Descriptor is the model-facing metadata for a tool: its name, a one-line description, and a JSON-schema object for its arguments. It is what the provider tool-API needs to expose the tool to the model.
type DynamicPolicy ¶
type DynamicPolicy struct {
// contains filtered or unexported fields
}
DynamicPolicy augments a base policy with runtime grants from the approval flow: in-memory grants (session and hydrated "always") plus an optional GrantStore for durable persistence. Grants are keyed by (workspace, tool). Safe for concurrent use.
func NewDynamicPolicy ¶
func NewDynamicPolicy(base Policy, store GrantStore) *DynamicPolicy
func (*DynamicPolicy) Decide ¶
func (p *DynamicPolicy) Decide(req Request) Decision
func (*DynamicPolicy) GrantAlways ¶
func (p *DynamicPolicy) GrantAlways(ctx context.Context, workspaceID, tool string) error
GrantAlways persists a durable per-workspace grant (and covers the session). Degrades to a session grant when no store is configured.
func (*DynamicPolicy) GrantSession ¶
func (p *DynamicPolicy) GrantSession(workspaceID, tool string)
GrantSession records an in-memory grant for the rest of this session/process.
type EffectLookup ¶ added in v0.0.2
type EffectLookup func(tool string) (spec.ToolEffect, bool)
EffectLookup resolves a tool name to its declared portable effect. The bool is false for a tool that declared none — an unclassified tool must never be treated as read-only by omission.
type FileAuditSink ¶
type FileAuditSink struct {
// contains filtered or unexported fields
}
func NewFileAuditSink ¶
func NewFileAuditSink(path string) (*FileAuditSink, error)
func (*FileAuditSink) Record ¶
func (s *FileAuditSink) Record(ctx context.Context, record AuditRecord) (err error)
type FileChange ¶
type FileDelegate ¶
type FileDelegate interface {
ReadFile(ctx context.Context, path string, maxBytes int64) (string, error)
WriteFile(ctx context.Context, path, content string) error
EditFile(ctx context.Context, path, oldText, newText string) error
}
FileDelegate overrides the workspace file ops for a turn: when one is on ctx (WithFileDelegate), the read_file/write_file/edit_file handlers route through it instead of cfg.Workspace. The ACP channel wires one that proxies to the editor's fs/* client capability so edits land in the user's open buffers. No ACP import here — the seam is ctx-carried, so tools stays transport-agnostic. ReadFile may be called concurrently when an assistant emits a batch composed entirely of explicitly parallel-safe read tools; implementations must correlate concurrent requests or serialize internally.
func FileDelegateFrom ¶
func FileDelegateFrom(ctx context.Context) FileDelegate
FileDelegateFrom returns the FileDelegate carried by WithFileDelegate, or nil.
type GrantStore ¶
type GrantStore interface {
// ListGranted returns the tools durably authorized for a workspace.
ListGranted(ctx context.Context, workspaceID string) ([]string, error)
// Grant durably authorizes tool for workspaceID.
Grant(ctx context.Context, workspaceID, tool string) error
// IsGranted reports whether tool is durably authorized for workspaceID.
// Used by the approval slow-path to short-circuit a prompt when a prior
// "always" grant already exists in durable storage.
IsGranted(ctx context.Context, workspaceID, tool string) (bool, error)
}
GrantStore persists "always"-scoped tool authorizations per workspace. The approval flow writes to it on an "always" grant; DynamicPolicy hydrates from it. Implemented by the distribution (e.g. a MemoryLayer-backed store). Phase-3 surface; DynamicPolicy works without one (session-only).
type HandlerFunc ¶
type HostExecutable ¶
type InjectImageConfig ¶
type InjectImageConfig struct {
// Workspace reads the image bytes the agent names. Required.
Workspace *localtools.Workspace
// SessionDir, when set, returns the per-(thread,context) working directory a
// code session writes relative files into (sahara's /sahara/sessions/<key>).
// A RELATIVE image path resolves against it first, falling back to the
// workspace root. nil → workspace-root only. Shares the artifact tool's
// derivation; the distribution owns it.
SessionDir func(threadID, context string) string
// MaxBytes hard-caps a single injected image read (<=0 → 5 MiB).
MaxBytes int
// MaxImageEdge, when > 0, downscales an injected image so its longest edge is
// <= MaxImageEdge before it's inlined as a data_uri — bounding the vision-token
// cost of a high-resolution screenshot / PDF-page render. Only the model-bound
// copy is scaled; the on-disk artifact is untouched. <=0 → no downscale.
MaxImageEdge int
}
InjectImageConfig configures the inject_image tool. It mirrors the artifact tool's path-resolution seam (Workspace + SessionDir) so a bare relative path resolves to the code session's working dir (where the python tool saves).
type LocalConfig ¶
type LocalConfig struct {
Workspace *localtools.Workspace
Python string
Exa *localtools.ExaClient
Timeout time.Duration
MaxOutput int
CommandPolicy CommandDecider
// OutputArchiveLimit bounds the bytes one truncated command retains in the
// recovery archive. 0 uses DefaultOutputArchiveLimit; negative disables
// archiving (the truncation marker is still emitted — a silent cut is the
// bug, the archive is the remedy).
OutputArchiveLimit int
// OutputArchiveDir is the workspace-relative directory archives are written
// to. Empty uses DefaultOutputArchiveDir.
OutputArchiveDir string
}
type MCPCaller ¶
type MCPCaller interface {
CallTool(ctx context.Context, server string, tool string, args json.RawMessage) (mcp.CallToolResult, error)
}
type MCPProvider ¶
type MCPProvider struct {
// contains filtered or unexported fields
}
MCPProvider exposes configured MCP servers' tools as a dynamic, per-turn tool provider (structurally a turn ToolProvider: ID/Tools/Invoke). It replaces the static per-tool RegisterMCPTool model while keeping identical tool names, schemas, and result shapes so the swap is behavior-identical. Trust is left at the descriptor zero value (TrustDefault): gating is the pipeline's job.
func NewMCPProvider ¶
func NewMCPProvider(cfg MCPProviderConfig) *MCPProvider
NewMCPProvider builds an MCPProvider from cfg.
func (*MCPProvider) Invoke ¶
Invoke resolves the registry name back to (server, tool) — via the route map built by Tools(), falling back to mcpParseRegistryName — calls CallTool, and converts the result identically to RegisterMCPTool's handler.
func (*MCPProvider) Tools ¶
func (p *MCPProvider) Tools(ctx context.Context, _ protocol.MessageAddress, _ protocol.ChatMessage) ([]Descriptor, error)
Tools lists every configured server's tools and converts each mcp.Tool to a Descriptor using the mcpRegistryName scheme. A per-server ListTools error is logged and that server skipped (best-effort, mirroring the manager's own tolerance); other servers still contribute. It also refreshes the internal registry-name -> (server, tool) route map used by Invoke.
type MCPProviderConfig ¶
MCPProviderConfig configures an MCPProvider. Caller is the same MCPCaller used by RegisterMCPTool (a *mcp.Manager also satisfies the internal lister used for discovery). Servers is the explicit set of MCP server names to expose.
type MCPResourceConfig ¶
type MCPResourceConfig struct {
RegistryName string
ServerName string
Client mcp.ResourceClient
}
type MCPToolConfig ¶
type MemoryAuthority ¶
MemoryAuthority is the per-turn OBO grant for MemoryLayer calls. A zero value means "use the client's default authority" (the configured fallback grant).
func MemoryAuthorityFrom ¶
func MemoryAuthorityFrom(ctx context.Context) (MemoryAuthority, bool)
MemoryAuthorityFrom returns the MemoryAuthority carried on ctx, and whether one was present. Absence yields the zero value (no OBO → client/default behavior).
type MemoryHit ¶
type MemoryHit struct {
ID string `json:"id"`
Content string `json:"content"`
Score float64 `json:"score"`
// Detail fields — populated by memory_get (fetch-by-id) to give the model
// full context + provenance; memory_search leaves them empty so scan results
// stay lean (omitempty drops them). Document provenance (source filename,
// document id, page) lives in Metadata/Tags for ingested memories.
Type string `json:"type,omitempty"`
Subtype string `json:"subtype,omitempty"`
Tags []string `json:"tags,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
Abstract string `json:"abstract,omitempty"`
SourceMemoryID string `json:"source_memory_id,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
}
MemoryHit is a single recalled memory.
type MemoryRecaller ¶
type MemoryRecaller interface {
Recall(ctx context.Context, auth MemoryAuthority, workspace, query string, limit int) ([]MemoryHit, error)
GetMemory(ctx context.Context, auth MemoryAuthority, id string) (MemoryHit, error)
}
MemoryRecaller is the read surface of MemoryLayer the harness exposes to the model as on-demand tools (semantic recall + fetch-by-id). Implemented by the MemoryLayer SDK adapter in internal/memory. Workspace + OBO authority are passed per call (the turn's chat workspace and grant) rather than baked into the client.
type ModelPreferenceFunc ¶
ModelPreferenceFunc requests that the thread switch to model `name` for subsequent turns. Best-effort: the runner applies it only if `name` is a registered/available model and returns whether it did. It pins the thread's model exactly like the /model command — effective from the NEXT turn, since the current turn's model is fixed at turn start. An empty name, no model registry, or an unknown model is a silent no-op.
Like WorldStateSink and PartEmitter, this is a request-scoped capability the runner installs on ctx rather than threading a model-switch dependency through every tool signature. load_skill uses it to honor a skill's metadata.scitrera.preferred_model.
func ModelPreferenceFrom ¶
func ModelPreferenceFrom(ctx context.Context) (ModelPreferenceFunc, bool)
ModelPreferenceFrom returns the model-preference fn carried on ctx, and whether one was present. Absence is a no-op (e.g. a transport with no model registry).
type PartEmitter ¶
type PartEmitter interface {
// UpsertPart streams part: appended the first time its id is seen, or merged
// in place (part_updated) on subsequent calls with the same id. A part with
// no id is appended each call. The latest version of each id-bearing part is
// folded into the finalized assistant message.
UpsertPart(ctx context.Context, part protocol.ContentPart) error
}
PartEmitter lets a tool surface a content part on the current assistant message's stream (e.g. a todo checklist the model writes via todo_write). The runner provides one per turn via the context; it streams the part and folds it into the finalized message so it persists. Like MemoryAuthority, it is a request-scoped capability carried on ctx rather than threaded through every tool signature.
func PartEmitterFrom ¶
func PartEmitterFrom(ctx context.Context) (PartEmitter, bool)
PartEmitterFrom returns the PartEmitter carried on ctx, and whether one was present. Tools that want to surface a part check this; absence means the part is simply not streamed (e.g. a non-streaming CLI path).
type PatchFileDelegate ¶ added in v0.0.2
type PatchFileDelegate interface {
ApplyPatch(ctx context.Context, operations []localtools.PatchOperation) ([]localtools.PatchChange, error)
}
PatchFileDelegate is an optional extension for transports that can preserve apply_patch's multi-file validation and commit semantics. When a FileDelegate is present without this extension, apply_patch fails closed instead of bypassing the editor/remote filesystem and mutating the local workspace.
type PreparedInvocation ¶ added in v0.0.2
type PreparedInvocation struct {
// contains filtered or unexported fields
}
PreparedInvocation is a registry call whose policy, audit, and execution-view checks have already succeeded. Preparing a batch in assistant source order lets the turn runner settle every approval before any explicitly safe call is started. A prepared invocation is immutable and may be invoked once.
type ReadOnlyAutoApprove ¶ added in v0.0.2
type ReadOnlyAutoApprove struct {
Base Policy
Effect EffectLookup
}
ReadOnlyAutoApprove is the read-only approval tier: it allows any tool whose declared effect is `read` and defers everything else to the base policy.
It exists because an always-ask configuration that prompts for `read_file` teaches users to approve without reading the prompt, which costs more safety than the prompt ever bought. Only an EXPLICIT read effect qualifies: a tool with no declared effect, or one whose effect the provider could not classify, falls through to the base policy unchanged.
func NewReadOnlyAutoApprove ¶ added in v0.0.2
func NewReadOnlyAutoApprove(base Policy, lookup EffectLookup) ReadOnlyAutoApprove
NewReadOnlyAutoApprove wraps base so read-effect tools resolved through lookup are auto-approved. A nil lookup disables the tier (every call defers to base), so a misconfiguration fails closed rather than approving everything.
func (ReadOnlyAutoApprove) Decide ¶ added in v0.0.2
func (p ReadOnlyAutoApprove) Decide(req Request) Decision
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func NewAuditedRegistry ¶
func NewRegistry ¶
func NewRegistry() *Registry
func (*Registry) Describe ¶
func (r *Registry) Describe(d Descriptor)
Describe attaches model-facing metadata for an already-registered tool. Unknown names are ignored so callers can describe best-effort.
func (*Registry) Descriptors ¶
func (r *Registry) Descriptors() []Descriptor
Descriptors returns descriptors for all registered tools, sorted by name. Tools registered without an explicit descriptor get a name-only entry so the model still learns they exist.
func (*Registry) EffectOf ¶ added in v0.0.2
func (r *Registry) EffectOf(name string) (spec.ToolEffect, bool)
EffectOf returns a registered tool's declared portable effect. The bool is false for an unknown tool or one registered without a descriptor/effect, so a caller can distinguish "declared read" from "never said" — a policy that conflated the two would auto-approve every unclassified tool.
func (*Registry) Override ¶
Override registers handler under name, replacing any existing handler for that name (unlike Register, which errors on a duplicate). Used to swap an already-registered tool implementation — e.g. redirecting the local "python" tool to a sandboxed execd backend. Descriptors are left untouched; re-describe separately if the schema changes.
func (*Registry) Prepare ¶ added in v0.0.2
Prepare resolves a tool and performs every admission check without executing its body. Authorization is deliberately separated from Invoke so a caller can preflight an entire explicitly parallel-safe batch deterministically.
func (*Registry) SetEventSink ¶
func (r *Registry) SetEventSink(events ToolEventSink)
func (*Registry) SetExcluded ¶
SetExcluded marks tool names that must NOT enter the registry: subsequent Register/Override/Describe calls for an excluded name become silent no-ops, so the tool is invisible to the model (absent from Descriptors) and uninvocable (Invoke returns ErrUnknownTool). Call before registering tools; additive across calls. This is the general "drop a built-in tool" seam (e.g. a distribution that provides web_search as a skill instead of the built-in Exa tool).
type RemoteConfig ¶
type RemoteConfig struct {
Invoker RemoteInvoker
Policy Policy
Audit AuditSink
}
type RemoteInvoker ¶
type Request ¶
type Request struct {
CallID string
// MessageID is the id of the assistant message that carries this tool call.
// Tools that create cross-thread back-refs (spawn_subagent) record it as the
// parent MESSAGE id; the tool CallID alone doesn't identify the enclosing
// message. Empty when the caller doesn't supply it.
MessageID string
Name string
Arguments json.RawMessage
Addr protocol.MessageAddress
// Authority is the turn's OBO grant, injected by the session so tools (e.g.
// memory_search) act on behalf of the turn's user with a fresh grant.
Authority MemoryAuthority
// Approved marks a call the user just authorized via the approval flow, so
// the registry bypasses the policy gate for this single invocation. (Durable
// session/always grants are recorded separately in the policy.)
Approved bool
// ToolRef is the exact provider-qualified catalog entry selected for a
// dynamically surfaced tool. It is nil for the standalone static-registry
// path and older bare-name callers.
ToolRef *protocol.ToolReference
// CatalogMeta is copied from the exact catalog entry after the independent
// invocation-time resolution succeeds. It is trusted admitted metadata, not
// model input. Providers may use it to validate an upstream exact reference.
CatalogMeta map[string]json.RawMessage
}
func RequestFromEnvelope ¶
func RequestFromEnvelope(env protocol.ToolInvokeEnvelope) Request
type Result ¶
type Result struct {
CallID string `json:"call_id"`
Name string `json:"name"`
Payload json.RawMessage `json:"payload"`
IsError bool `json:"is_error"`
Metadata ResultMetadata `json:"metadata,omitempty"`
// Parts holds optional extra content parts the tool loop records alongside
// the tool_result part (e.g. a subagent reference part). Runtime-only (not a
// wire field); nil = today's single tool_result behavior.
Parts []protocol.ContentPart `json:"-"`
// InjectUserParts holds content parts the tool loop records as a NEW
// user-role message (distinct from Parts, which co-locate on the tool-result
// message). Used by inject_image to put a locally-produced image into the
// model's OWN context: an image must ride on a user-role message (a tool-role
// message is text-only), so it cannot go on the tool_result. Runtime-only;
// nil = no-op. An image part here also triggers mid-loop vision escalation.
InjectUserParts []protocol.ContentPart `json:"-"`
}
func NewJSONResult ¶
func (Result) ContentPart ¶
func (r Result) ContentPart() (protocol.ContentPart, error)
type ResultMetadata ¶
type ResultMetadata struct {
PayloadBytes int `json:"payload_bytes,omitempty"`
ExitCode int `json:"exit_code,omitempty"`
OutputBytes int `json:"output_bytes,omitempty"`
OutputTruncated bool `json:"output_truncated,omitempty"`
PID int `json:"pid,omitempty"`
FileChanges []FileChange `json:"file_changes,omitempty"`
// References are stable pointers returned by a tool to an authoritative
// record. They let execution observers retain provenance without copying the
// record payload into an operational ledger.
References []ResultReference `json:"references,omitempty"`
}
type ResultReference ¶ added in v0.0.2
type SkillRealizerFunc ¶
SkillRealizerFunc materializes the named skills' bundle files — utils.py, references/, assets/, and the shared bundle — into the distribution's skills root (e.g. the sandbox's shared /skills directory), so code running in the code-sidecar (e.g. import_path('/skills/<name>/utils.py'), and skill bodies citing that root) resolves them. load_skill calls it with the target skill plus its prerequisites. It is best-effort and idempotent: it returns the number of files realized; absence on ctx (no materialize dir / non-relay transport) is a silent no-op.
Like ModelPreference and WorldStateSink, this is a request-scoped capability the runner installs on ctx rather than threading a materialization dependency through every tool signature. The realization SOURCE (MemoryLayer bundle files, a workspace skill folder, an image-baked root) is the distribution's concern; the tool just names the skills it loaded.
func SkillRealizerFrom ¶
func SkillRealizerFrom(ctx context.Context) (SkillRealizerFunc, bool)
SkillRealizerFrom returns the skill realizer carried on ctx, and whether one was present. Absence is a no-op (e.g. a transport with no skills materialization).
type StaticPolicy ¶
func (StaticPolicy) Decide ¶
func (p StaticPolicy) Decide(req Request) Decision
type SubagentConfig ¶
type SubagentConfig struct {
Runner subagent.Runner
MaxDepth int
Catalog subagent.Catalog
// AllowBackground advertises + enables the `background` spawn argument. Set it
// only when the Runner supports detached execution (implements
// subagent.BackgroundRunner with a Notifier wired); off → the tool is
// synchronous-only and the schema omits `background`.
AllowBackground bool
}
type ToolDelegate ¶ added in v0.0.2
type ToolDelegate interface {
HandlesTool(name string) bool
InvokeTool(ctx context.Context, req Request) (Result, error)
}
ToolDelegate redirects complete tool invocations for a turn. It is used when the tool authority is on another host (for example, an Aether-connected TUI that owns the selected checkout). Registry policy and audit run before this seam, so the remote host receives only admitted calls. InvokeTool may be called concurrently only for descriptors explicitly marked ParallelSafe; implementations must support that overlap or serialize internally.
func ToolDelegateFrom ¶ added in v0.0.2
func ToolDelegateFrom(ctx context.Context) ToolDelegate
ToolDelegateFrom returns the full-invocation delegate on ctx, or nil.
type ToolEvent ¶
type ToolEvent struct {
Status ToolEventStatus `json:"status"`
CallID string `json:"call_id"`
ToolName string `json:"tool_name"`
Addr protocol.MessageAddress `json:"addr"`
ArgumentsHash string `json:"arguments_hash"`
ArgumentsBytes int `json:"arguments_bytes"`
DurationMS int64 `json:"duration_ms,omitempty"`
ApprovalDecision string `json:"approval_decision,omitempty"`
PolicyDecision string `json:"policy_decision,omitempty"`
Reason string `json:"reason,omitempty"`
IsError bool `json:"is_error,omitempty"`
ErrorCode string `json:"error_code,omitempty"`
ErrorMessage string `json:"error,omitempty"`
Result ResultMetadata `json:"result,omitempty"`
}
func NewToolEvent ¶
func NewToolEvent(status ToolEventStatus, req Request) ToolEvent
type ToolEventSink ¶
type ToolEventStatus ¶
type ToolEventStatus string
const ( ToolEventQueued ToolEventStatus = "queued" ToolEventStarted ToolEventStatus = "started" ToolEventFinished ToolEventStatus = "finished" ToolEventAborted ToolEventStatus = "aborted" )
type TrustLevel ¶
type TrustLevel int
TrustLevel is a tool's authorization hint carried on its Descriptor: how the authorization pipeline should treat it before the runtime policy weighs in. The zero value (TrustDefault) preserves today's behavior — the local requires-approval trigger stays the runtime policy, not this hint.
const ( // TrustDefault leaves authorization to the runtime policy (local tools) or // the provider's own gating (provider tools). Zero value; today's behavior. TrustDefault TrustLevel = iota // TrustRequiresApproval marks a tool that must be approved before it runs. TrustRequiresApproval // TrustPreAuthorized marks a tool authorized ahead of time (no prompt); it // still passes through the safety authorizer like every other tool. TrustPreAuthorized // TrustRequiresFreshApproval requires a new once-only human decision for // every invocation. Session and durable grants cannot bypass it. Use it for // mutations whose exact arguments, not merely the tool name, need review. TrustRequiresFreshApproval )
type WorldStateSink ¶
type WorldStateSink interface {
// RecordInvokedSkill notes that the model loaded a skill this turn (its name
// and origin). The sink stamps the current turn as the skill's LastTurn.
RecordInvokedSkill(name, source string)
// RecordFile notes a file the agent wrote or edited this turn (kind is
// "write" or "edit"). Aged in WorldState.RecentFiles.
RecordFile(path, kind string)
// RecordTodos records the current todo board (the model rewrites the whole
// list via todo_write). Items are merged by id, keeping the latest touch, so
// the board survives compaction.
RecordTodos(items []spec.TodoItem)
// RecordSubagent notes a sub-agent the model spawned/resumed this turn: its
// thread_id handle (id, the re-addressable key), display name, status, and
// short summary. Aged in WorldState.ActiveSubagents so the orchestrator sees
// its live specialists and can route follow-ups back to them. Primitives only
// (no compaction import from this package).
RecordSubagent(id, name, status, summary string)
}
WorldStateSink lets a tool record durable, compaction-surviving world-state contributions — e.g. load_skill recording which skill the model loaded this turn. The runner provides one per turn via ctx and folds the collected state into the turn's message meta, so it rides ExtractWorldState across compaction (unlike the tool_result body, which is a droppable message). Like PartEmitter and MemoryAuthority, it is a request-scoped capability carried on ctx rather than threaded through every tool signature.
func WorldStateSinkFrom ¶
func WorldStateSinkFrom(ctx context.Context) (WorldStateSink, bool)
WorldStateSinkFrom returns the WorldStateSink carried on ctx, and whether one was present. Absence is a no-op (e.g. a transport with no world-state plumbing).
Source Files
¶
- artifact.go
- audit_file.go
- delegate.go
- descriptor.go
- events.go
- exec_policy.go
- exec_policy_match.go
- exec_policy_types.go
- execution_scope.go
- inject_image.go
- json.go
- local.go
- local_exec.go
- mcp.go
- mcp_provider.go
- memory.go
- model_preference.go
- part_emitter.go
- policy.go
- registry.go
- remote.go
- skill_realizer.go
- subagent.go
- todo.go
- types.go
- working_directory.go
- worldstate_sink.go