Documentation
¶
Index ¶
- func ApproxTextTokens(value string) int
- func BuildSystemPromptPreview(options Options) string
- func Compact(messages []zeroruntime.Message, opts CompactionOptions) ([]zeroruntime.Message, error)
- func IsNoProgressStop(content string) bool
- func NewLSPDiagnosticsChecker(manager *lsp.Manager) diagnosticsChecker
- func NewProjectVerifier(workspaceRoot string) projectVerifier
- func ToolAdvertised(tool tools.Tool, permissionMode PermissionMode) bool
- func ToolAllowedByFilters(name string, enabledTools []string, disabledTools []string) bool
- func ToolVisible(tool tools.Tool, permissionMode PermissionMode, enabledTools []string, ...) bool
- type AskUserQuestion
- type AskUserRequest
- type AskUserResponse
- type CompactionOptions
- type CompactionResult
- type ContextBreakdown
- type CorrectionReport
- type DenialCategory
- type Message
- type Options
- type Outcome
- type PermissionAction
- type PermissionDecision
- type PermissionDecisionAction
- type PermissionEvent
- type PermissionMode
- type PermissionRequest
- type Provider
- type Result
- type SelfCorrectConfig
- type SelfCorrector
- type SpecialistInfo
- type StopReason
- type ToolCall
- type ToolResult
- type Usage
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApproxTextTokens ¶
ApproxTextTokens estimates the token count of text WITHOUT a real tokenizer. The BPE tokenizers zero targets fold a run's leading space into the following token rather than emitting whitespace as its own token, so naive len/4 overcounts real text by ~15-20% (measured: a 24.8k-char prompt counted 5.2k real tokens where len/4 said 6.2k). Counting NON-whitespace bytes / 4 tracks the provider's actual count closely (validated against live usage) while staying allocation- and dependency-free. zero still receives the exact count back as usage on every request; this estimate is only for the pre-request context budget preview and the compaction threshold.
func BuildSystemPromptPreview ¶
BuildSystemPromptPreview returns the same system prompt a run would seed for the supplied options. It is intended for non-runtime reporting surfaces that need to estimate prompt footprint without starting a provider call.
func Compact ¶
func Compact(messages []zeroruntime.Message, opts CompactionOptions) ([]zeroruntime.Message, error)
Compact summarizes the oldest middle of a conversation, keeping the leading system message(s) and the most recent turns verbatim. The result is:
[system..., summaryAsUser, preservedSuffix...]
Rules:
- Leading system messages stay at the head untouched.
- The preserved suffix is widened backward so it never begins with a tool/tool_result message (provider APIs reject a dangling tool result with no preceding assistant tool call).
- The summary is injected as a single user-role message labeled with summaryLabel.
- If there is nothing to summarize (too few messages once system and the preserved suffix are removed), the input is returned unchanged.
Compact is pure: it performs no provider I/O. A Summarize error is returned to the caller, which decides how to recover.
func IsNoProgressStop ¶
IsNoProgressStop reports whether content IS the no-output guardrail stop answer (a run that produced no visible text and no tool calls). It matches the EXACT structure noOutputStopAnswer emits — prefix + "<int> turns " + marker + " " + suffix, where only the integer turn count varies — rather than just looking for the three parts in order. A loose check (prefix && contains-marker && suffix) would misclassify a genuine assistant/tool message that merely quotes the marker amid other prose, which would wrongly hide a real session from /resume and skip its title generation.
func NewLSPDiagnosticsChecker ¶
NewLSPDiagnosticsChecker wraps an *lsp.Manager for use as a SelfCorrector checker. Returns nil when manager is nil so self-correct cleanly skips LSP.
func NewProjectVerifier ¶
func NewProjectVerifier(workspaceRoot string) projectVerifier
NewProjectVerifier builds the default verifier rooted at workspaceRoot.
func ToolAdvertised ¶
func ToolAdvertised(tool tools.Tool, permissionMode PermissionMode) bool
func ToolAllowedByFilters ¶
func ToolVisible ¶
Types ¶
type AskUserQuestion ¶
type AskUserQuestion struct {
Question string `json:"question"`
Header string `json:"header,omitempty"`
Options []string `json:"options,omitempty"`
OptionDescriptions []string `json:"optionDescriptions,omitempty"`
Recommended string `json:"recommended,omitempty"`
MultiSelect bool `json:"multiSelect,omitempty"`
}
AskUserQuestion is one clarifying question the agent wants answered. Options are optional suggested answers an interactive front-end can render as a picker; Recommended (when set) is the suggested default — it should match one of Options. Header is an optional short tab title for a multi-question prompt (falls back to the question text). OptionDescriptions, when present, holds a one-line description per option aligned by index to Options (empty string = no description).
type AskUserRequest ¶
type AskUserRequest struct {
ToolCallID string `json:"toolCallId"`
Header string `json:"header,omitempty"`
Questions []AskUserQuestion `json:"questions"`
}
AskUserRequest is handed to OnAskUser when the model invokes the ask_user tool.
type AskUserResponse ¶
type AskUserResponse struct {
Answers []string `json:"answers"`
}
AskUserResponse carries the user's answers back to the loop, one per question.
type CompactionOptions ¶
type CompactionOptions struct {
// PreserveLast is the number of trailing messages to keep verbatim. The
// preserved suffix is widened (never shrunk) so it begins at a safe
// user/assistant boundary. <= 0 falls back to defaultCompactionPreserveLast.
PreserveLast int
// Summarize turns the to-be-elided middle into a single dense summary. It is
// injected so Compact stays pure and testable; the agent loop wires it to a
// real provider call.
Summarize func(toSummarize []zeroruntime.Message) (string, error)
}
CompactionOptions configure a single Compact call.
type CompactionResult ¶
type CompactionResult struct {
// Messages is the original conversation or the compacted replacement.
Messages []zeroruntime.Message
// RemovedCount is the number of original messages summarized away.
RemovedCount int
// PreservedCount is the number of original messages kept verbatim, including
// leading system messages and the preserved suffix.
PreservedCount int
// SummaryText is the trimmed text returned by the summarizer. The injected
// summary message also includes summaryLabel and any preserved structured
// state needed by later compactions.
SummaryText string
// Compacted reports whether Messages contains an injected summary.
Compacted bool
}
CompactionResult is the metadata-bearing result returned by CompactMessages.
func CompactMessages ¶
func CompactMessages(messages []zeroruntime.Message, opts CompactionOptions) (CompactionResult, error)
CompactMessages summarizes the oldest middle of a conversation and returns both the replacement messages and UI/session-friendly metadata about what changed. It uses the same compaction rules as Compact.
type ContextBreakdown ¶
type ContextBreakdown struct {
SystemTokens int // leading system messages (prompt + injected context)
ToolTokens int // advertised tool definitions
MessageTokens int // non-system conversation messages
TotalTokens int // SystemTokens + ToolTokens + MessageTokens
ContextWindow int // model context window; 0 when unknown
UsedFraction float64 // TotalTokens / ContextWindow; 0 when window unknown
}
ContextBreakdown is a per-category estimate of a request's token footprint.
func MeasureContext ¶
func MeasureContext(messages []zeroruntime.Message, tools []zeroruntime.ToolDefinition, contextWindow int) ContextBreakdown
MeasureContext estimates the per-category token footprint of a request: the leading system messages, the advertised tool definitions, and the remaining conversation messages.
type CorrectionReport ¶
type CorrectionReport struct {
LSPDiagnostics map[string][]lsp.Diagnostic // path -> error diagnostics
VerifyReport verify.Report
// InspectErrors holds non-degradable verification failures (an LSP
// startup/sync error, an unreadable changed file, or plan detection failing).
// These are distinct from diagnostics and must fail the pass rather than be
// silently swallowed into a false "passed".
InspectErrors []string
Failed bool
}
CorrectionReport is the unified result of a post-edit verification pass.
type DenialCategory ¶
type DenialCategory string
DenialCategory classifies why a tool call was blocked before it executed.
const ( DenialNone DenialCategory = "" DenialFiltered DenialCategory = "filtered" // tool not enabled for this run DenialPermissionDenied DenialCategory = "permission_denied" // approval declined DenialApprovalCanceled DenialCategory = "approval_canceled" // approval canceled and run aborted DenialSandboxBlock DenialCategory = "sandbox_block" // blocked by the sandbox DenialHookBlocked DenialCategory = "hook_blocked" // vetoed by a beforeTool hook )
type Message ¶
type Message = zeroruntime.Message
type Options ¶
type Options struct {
MaxTurns int
// DeferThreshold activates deferred MCP-tool loading: when the number of
// deferred-eligible visible tools is >= this value (and it is > 0), their
// full schemas are withheld and advertised as compact lines via tool_search.
// 0 (or below the eligible count) keeps every tool eager — byte-identical to
// the pre-deferral behavior.
DeferThreshold int
// Specialists lists the sub-agents the orchestrator may delegate to via the
// Task tool; when non-empty the system prompt gains a delegation section that
// names them and nudges the model to offload read-heavy work (search,
// exploration) so verbose tool output stays out of the main context. It is
// populated only where the Task tool is actually registered, so an empty slice
// (the default) reproduces the previous prompt byte-for-byte.
Specialists []SpecialistInfo
// Specialist/sub-agent metadata is carried through exec now and consumed by
// the specialist runtime in later slices.
SessionID string
CallingSessionID string
CallingToolUseID string
Tag string
Depth int
SessionTitle string
ProviderName string
Model string
ReasoningEffort string
Cwd string
SystemPrompt string
// ResponseStyle is the operator-selected reply style from the TUI /style
// command (e.g. "concise", "explanatory", "review"). It is rendered into the
// system prompt as a short directive. Empty or "balanced" adds nothing — the
// prompt is then byte-identical to the pre-style behavior.
ResponseStyle string
// Images are optional image attachments to seed onto the initial user turn.
// nil for text-only runs (the seeded message then carries no images, exactly
// as before).
Images []zeroruntime.ImageBlock
// ContextWindow is the model's maximum input token budget. When > 0 the agent
// loop compacts long conversations once the estimated size crosses a fraction
// of this window. 0 DISABLES compaction entirely (every existing caller/test
// behaves identically).
ContextWindow int
// CompactionPreserveLast is how many trailing messages compaction keeps
// verbatim. <= 0 falls back to defaultCompactionPreserveLast.
CompactionPreserveLast int
Registry *tools.Registry
PermissionMode PermissionMode
Autonomy string
Sandbox *sandbox.Engine
// FileTracker records per-session file read/write versions so the write tools
// can detect a file changed on disk outside Zero since it was last read. nil
// disables the check. Created once per session and threaded into every tool run.
FileTracker *tools.FileTracker
// Hooks, when set, runs configured beforeTool (blocking) and afterTool
// (advisory) commands around each tool call. nil disables hooks entirely; a
// dispatcher built from an empty config is also a safe no-op.
Hooks *hooks.Dispatcher
EnabledTools []string
DisabledTools []string
OnText func(string)
OnReasoning func(string)
OnToolCall func(ToolCall)
// OnToolCallStart / OnToolCallDelta stream a tool call's arguments LIVE as the
// model generates them — OnToolCallStart on open (id, tool name), then
// OnToolCallDelta for each argument fragment. A surface can render the
// in-progress call (e.g. a file being written) instead of waiting for
// OnToolCall, which only fires once the whole call has accumulated. nil no-ops.
OnToolCallStart func(id, name string)
OnToolCallDelta func(id, fragment string)
OnPermissionRequest func(context.Context, PermissionRequest) (PermissionDecision, error)
OnPermission func(PermissionEvent)
OnAskUser func(context.Context, AskUserRequest) (AskUserResponse, error)
OnToolResult func(ToolResult)
OnUsage func(Usage)
// OnToolProgress, when set, is called with each stream-json event a
// specialist child process emits while running. The toolCallID identifies
// which Task tool call the progress belongs to. nil is a no-op.
OnToolProgress func(toolCallID string, event streamjson.Event)
// OnContext, when set, is called once per turn with the per-category context
// budget of the request about to be sent, so a surface (TUI/CLI) can show
// context utilization. Opt-in like the other callbacks; nil is a no-op.
OnContext func(ContextBreakdown)
// ModelSwitcher, when set, lets a tool escalate the run to a stronger model
// mid-run: the loop calls it with the requested model id and, on success,
// swaps the active provider and updates Options.Model for the rest of the
// run. nil DISABLES escalation entirely (the loop ignores any switch
// request), so every existing caller is unaffected. A returned error is
// non-fatal: the run continues on the current model.
ModelSwitcher func(ctx context.Context, modelID string) (Provider, error)
// SelfCorrect, when set, runs a post-edit verify-and-correct cycle after a
// mutating tool call: it verifies the changed files (LSP diagnostics + project
// tests) and feeds failures back to the model to fix, bounded by an attempt
// ceiling and the autonomy gate. nil disables it entirely (the loop is
// byte-identical to before). One instance per run — it holds attempt state.
SelfCorrect *SelfCorrector
// RequireCompletionSignal gates run completion for HEADLESS exec. Without it,
// any assistant turn that produces text but no tool call is accepted as the
// final answer. With it, a no-tool-call turn is NOT treated as "done" while
// work clearly remains — pending update_plan items, or a message that ends on a
// continuation cue ("…Let me check the config:"). The loop then nudges the
// model to continue instead, bounded by maxContinueNudges (and still by
// MaxTurns and the run deadline); if the model keeps stalling, the run
// finalizes as INCOMPLETE (Result.Incomplete) rather than success. Default
// false leaves the loop byte-identical, so the interactive TUI is unaffected.
RequireCompletionSignal bool
// contains filtered or unexported fields
}
type Outcome ¶
type Outcome string
Outcome reports what a self-correct round decided, for observability/tests.
const ( OutcomeDisabled Outcome = "disabled" // self-correct off, or nothing to check OutcomePassed Outcome = "passed" // verification passed; nothing to do OutcomeCorrecting Outcome = "correcting" // failed; feedback issued for the model to fix OutcomeReported Outcome = "reported" // failed; low autonomy, reported but no auto-fix OutcomeAborted Outcome = "aborted" // failed but the correction budget is exhausted )
type PermissionAction ¶
type PermissionAction string
const ( PermissionActionAllow PermissionAction = "allow" PermissionActionPrompt PermissionAction = "prompt" PermissionActionDeny PermissionAction = "deny" PermissionActionCancel PermissionAction = "cancel" )
type PermissionDecision ¶
type PermissionDecision struct {
Action PermissionDecisionAction `json:"action"`
Reason string `json:"reason,omitempty"`
}
type PermissionDecisionAction ¶
type PermissionDecisionAction string
const ( PermissionDecisionAllow PermissionDecisionAction = "allow" PermissionDecisionAllowStrict PermissionDecisionAction = "allow_with_strict_auto_review" PermissionDecisionAllowForSession PermissionDecisionAction = "allow_for_session" PermissionDecisionAllowPrefix PermissionDecisionAction = "allow_prefix_for_session" PermissionDecisionAlwaysAllowPrefix PermissionDecisionAction = "always_allow_prefix" PermissionDecisionDeny PermissionDecisionAction = "deny" PermissionDecisionAlwaysAllow PermissionDecisionAction = "always_allow" PermissionDecisionCancel PermissionDecisionAction = "cancel" )
type PermissionEvent ¶
type PermissionEvent struct {
ToolCallID string `json:"toolCallId"`
ToolName string `json:"name"`
Action PermissionAction `json:"action"`
DecisionAction PermissionDecisionAction `json:"decisionAction,omitempty"`
Permission string `json:"permission"`
PermissionGranted bool `json:"permissionGranted,omitempty"`
PermissionMode PermissionMode `json:"permissionMode"`
Autonomy string `json:"autonomy,omitempty"`
SideEffect string `json:"sideEffect"`
Reason string `json:"reason,omitempty"`
Scope string `json:"scope,omitempty"`
DecisionReason string `json:"decisionReason,omitempty"`
Risk sandbox.Risk `json:"risk"`
Block *sandbox.Block `json:"block,omitempty"`
GrantMatched bool `json:"grantMatched,omitempty"`
Grant *sandbox.Grant `json:"grant,omitempty"`
CommandPrefix []string `json:"commandPrefix,omitempty"`
}
type PermissionMode ¶
type PermissionMode string
const ( PermissionModeAuto PermissionMode = "auto" PermissionModeAsk PermissionMode = "ask" PermissionModeUnsafe PermissionMode = "unsafe" PermissionModeSpecDraft PermissionMode = "spec-draft" // PermissionModeMemberAuto is a headless mode for swarm/specialist MEMBERS: it // advertises the in-workspace mutators a member needs to build (write/edit + // shell) on top of the Auto set, while the sandbox engine still gates them at // call time — in-workspace writes and sandbox-backed shell auto-allow, but // out-of-workspace writes, network, and destructive commands still prompt (and // a headless member has no approver, so they are denied). It normalizes to Auto // everywhere except ToolAdvertised, so authority is never widened beyond what an // interactive auto agent already has inside the sandbox. PermissionModeMemberAuto PermissionMode = "member-auto" )
type PermissionRequest ¶
type PermissionRequest struct {
ToolCallID string `json:"toolCallId"`
ToolName string `json:"name"`
Action PermissionAction `json:"action"`
Permission string `json:"permission"`
PermissionMode PermissionMode `json:"permissionMode"`
Autonomy string `json:"autonomy,omitempty"`
SideEffect string `json:"sideEffect"`
Reason string `json:"reason,omitempty"`
Scope string `json:"scope,omitempty"`
Risk sandbox.Risk `json:"risk"`
Args map[string]any `json:"args,omitempty"`
Block *sandbox.Block `json:"block,omitempty"`
GrantMatched bool `json:"grantMatched,omitempty"`
Grant *sandbox.Grant `json:"grant,omitempty"`
CommandPrefix []string `json:"commandPrefix,omitempty"`
AvailableDecisions []PermissionDecisionAction `json:"availableDecisions,omitempty"`
}
type Provider ¶
type Provider = zeroruntime.Provider
type Result ¶
type Result struct {
FinalAnswer string
Turns int
Messages []Message
StopReason StopReason
// FinishReason is the provider's normalized terminal stop reason for the turn
// that produced FinalAnswer: zeroruntime.FinishReasonLength when the output
// hit the token cap, FinishReasonContentFilter when it was filtered. Empty for
// a normal completion.
FinishReason string
// Incomplete reports that a headless run (RequireCompletionSignal) stopped with
// work clearly unfinished: the model ended a turn with no tool call while plan
// items were pending or the message ended mid-step, the model admitted it
// guessed / could not meet the objective, and/or it failed a task-grounded
// acceptance check. Callers map it to a non-success terminal status / exit
// code. False for every normal completion.
Incomplete bool
// IncompleteReason is a short, model-derived explanation of why the run was
// marked Incomplete (e.g. "pending plan items remain"). Empty when Incomplete
// is false. Surfaced in logs / run_end so an abandoned run is debuggable.
IncompleteReason string
}
func (Result) Truncated ¶
Truncated reports whether the final response ended abnormally (cut off at the output token cap or withheld by a content filter) rather than completing naturally. Callers can use it to warn the user that FinalAnswer is incomplete.
func (Result) TruncationNotice ¶
TruncationNotice returns a user-facing warning when the final response was truncated, or "" for a normal completion. Shared by the CLI and TUI so the wording stays consistent.
type SelfCorrectConfig ¶
type SelfCorrectConfig struct {
Enabled bool
MaxAttempts int
IncludeTests bool
IncludeLSP bool
Autonomy string // low | medium | high
}
SelfCorrectConfig controls the post-edit verify-and-correct cycle.
type SelfCorrector ¶
type SelfCorrector struct {
// contains filtered or unexported fields
}
SelfCorrector runs verification after a mutating edit and, when it fails, synthesizes corrective feedback for the model — bounded by a per-run attempt budget and gated by the autonomy ceiling. One instance per run (it holds the attempt counter). A nil *SelfCorrector is a no-op.
func NewSelfCorrector ¶
func NewSelfCorrector(workspaceRoot string, checker diagnosticsChecker, verifier projectVerifier, cfg SelfCorrectConfig) *SelfCorrector
NewSelfCorrector builds a self-corrector. checker/verifier may be nil to disable that half of verification (e.g. no LSP server, or tests off).
func (*SelfCorrector) AfterEdit ¶
AfterEdit runs a verification pass over the files a mutating tool changed and returns corrective feedback (empty when nothing actionable) plus the outcome. The loop appends any non-empty feedback to the conversation so the model can fix the problem on its next turn.
type SpecialistInfo ¶
SpecialistInfo is a one-line summary of a delegatable sub-agent (its name and when-to-use description) surfaced to the orchestrator's system prompt so it can route work to the right specialist. It is plain data so the agent package needs no dependency on internal/specialist.
type StopReason ¶
type StopReason string
const (
StopReasonSpecReviewRequired StopReason = "spec_review_required"
)
type ToolCall ¶
type ToolCall = zeroruntime.ToolCall
type ToolResult ¶
type ToolResult struct {
ToolCallID string
Name string
Status tools.Status
Output string
Meta map[string]string
Redacted bool
ChangedFiles []string
Display tools.Display
// DenialReason categorizes why a tool call was blocked (empty when it ran).
// It lets a surface distinguish the cause precisely instead of parsing Output.
DenialReason DenialCategory
// LoadedTools carries the deferred-tool names a tool_search call asked the
// loop to expose next turn (lifted from Meta["load_tools"]). nil for every
// ordinary tool result; only tool_search populates it.
LoadedTools []string
// RequestedModel is the model id a tool asked the loop to switch to for the
// rest of the run (lifted from the tool's Meta["escalate_to_model"]). Empty
// for every normal tool result; the Run loop performs the switch when it is
// set and Options.ModelSwitcher is wired.
RequestedModel string
}
type Usage ¶
type Usage = zeroruntime.Usage