Documentation
¶
Overview ¶
Package agent runs an agent step's LLM tool-calling conversation: it resolves the agent's model/connection, compiles the step's granted tools, drives the request/tool-execute/append loop (see runAgentConversation), and enforces required: true tools via the provider's tool_choice. It also runs a task's fix: agent (RunFix) on the same conversation machinery.
Index ¶
- Constants
- Variables
- func AnswerFlags(ctx context.Context, pipeline string) string
- func CheckExportedCommands(export config.MCPExport) error
- func Preflight(ctx context.Context, cfg *config.Config, agentNames []string, ...) []config.Problem
- func RecordOutcome(ctx context.Context, name string, up Upstream)
- func RenderUpstream(name string, level config.FromLevel, up Upstream) string
- func ResetProbeCache()
- func RunFix(ctx context.Context, cfg *config.Config, jobName string, stepIndex int, ...) error
- func RunHook(ctx context.Context, cfg *config.Config, jobName string, step config.Step, ...) error
- func UnquotedToolRefs(run string) []string
- func WithAnswerDB(ctx context.Context, db string) context.Context
- func WithAnswerSeeds(ctx context.Context, seeds []AnswerSeed) context.Context
- func WithExportWho(ctx context.Context, who ExportWho) context.Context
- func WithOutcomes(ctx context.Context) context.Context
- func WithRunBoundary(ctx context.Context) context.Context
- type AnswerSeed
- type ExportHooks
- type ExportServer
- type ExportWho
- type PreparedStep
- func (s *PreparedStep) Capture(ctx context.Context) error
- func (s *PreparedStep) Close()
- func (s *PreparedStep) MemoryDigest() string
- func (s *PreparedStep) Primary() config.ResolvedInvocation
- func (s *PreparedStep) Run(ctx context.Context, run StepRun) (StepResult, error)
- func (s *PreparedStep) Step() config.Step
- type RunnerFactory
- type StepResult
- type StepRun
- type StepStore
- type TranscriptStore
- type Upstream
Constants ¶
const RuleKey = "rule"
RuleKey is the key of a refusal result naming the rule that made it.
Variables ¶
var ErrRateLimited = errors.New("rate limit reached for this export; try again shortly")
ErrRateLimited is a call past an export's rate:.
Functions ¶
func AnswerFlags ¶
AnswerFlags finish a printed answer command; with no WithAnswerDB, as under a daemon, the read commands' default database is the run's.
func CheckExportedCommands ¶
CheckExportedCommands refuses an export whose command would put a caller's value into the shell as syntax. The caller is not the pipeline's author, so a value that reaches sh -c bare is a command the caller chose.
func Preflight ¶
func Preflight(ctx context.Context, cfg *config.Config, agentNames []string, settings *config.Preflight) []config.Problem
Preflight checks every model and MCP server the named agents need, and returns a problem per target that failed. An empty result means the job's dependencies are all live.
Only what this job needs: a pipeline with ten agents whose job uses two checks two. Distinct (endpoint, model) pairs are checked once even when several agents share one.
func RecordOutcome ¶
RecordOutcome notes what the step named name decided. A later visit of the same step replaces the earlier one: a revise loop's reader wants the verdict that just sent it back, not the one from two passes ago.
func RenderUpstream ¶
RenderUpstream formats one step's outcome at the demanded level, or "" when there is nothing to say.
Absence is deliberately not an error. A reader that runs BEFORE its sender — the writer at the top of a revise loop, whose critic has not judged anything yet — gets nothing on the first pass and the critic's verdict on every pass after. That is the same "routed entry only" behaviour, arrived at by asking whether the sender has run rather than by inspecting the route.
func ResetProbeCache ¶
func ResetProbeCache()
ResetProbeCache clears everything preflight has verified AND every source pin it (or a mid-run cascade) selected. Tests use it to stay independent of each other; a test about the pin's own lifetime wants only the first half, since wiping the pin is what such a test is trying to observe.
Every caller must be a serial test: this is process-wide state for all agents, so a `t.Parallel()` test that reached it would clear another's.
func RunFix ¶
func RunFix( ctx context.Context, cfg *config.Config, jobName string, stepIndex int, rt config.ResolvedTask, st StepStore, failureOutput, workspaceDir string, ) error
RunFix invokes a failed task's fix: agent. It reuses the normal agent-invocation resolution (tool grant, dials, attempts, max_turns) by projecting the FixSpec onto an agent Step, then injects the parent task as a zero-arg rerun tool — the task's own run: command (never its fix:, so a rerun can't recurse), exposed under the task's name — and seeds the conversation with the captured failure output. It does no merkle/store recording: the enclosing task step records the overall outcome, and the task's re-run (not the model's word) is the verdict.
The fix conversation's run_shell/custom tools and the injected rerun tool all execute under rt.Image — the failing task's own image, never the fix agent's own Agent.Image (config.validateFixAgentImages rejects a fix agent that sets one, at LoadConfig time, precisely because it can never take effect here). The premise of the fix loop is reproducing and resolving the exact failure the task hit; running under a different image than the one that produced (and re-verifies) the failure would make the loop incoherent.
func RunHook ¶
func RunHook(ctx context.Context, cfg *config.Config, jobName string, step config.Step, bw workspace.BuildWorkspace, st StepStore, newRunner RunnerFactory) error
RunHook runs an agent step as a hook: it resolves, materializes, runs the conversation, evaluates its assert, and captures declared outputs exactly like a plan step, but records no merkle node or job_run — the enclosing step/job records the aggregate outcome (the same no-record contract as RunFix). A returned error is already outcome-marked where appropriate (see runAgentConversation), so the caller's hook classification works unchanged.
The assert runs here for the same reason a task hook's does (see internal/pipeline's executeTask -> runAssertedTask): config.validateAsserts deliberately walks hook steps, so an assert on an on_failure: agent is checked and rejected at load like any other. Evaluating it at load and then never running it made that promise a lie — the hook reported success on a mismatch its own assert existed to catch.
func UnquotedToolRefs ¶
UnquotedToolRefs reports each action in a custom tool's run: that prints a .args value without shellquote — the model-authored half of a tool reaching sh -c as syntax.
func WithAnswerDB ¶
WithAnswerDB carries a local run's own state file to the printed commands, since the read commands default to a daemon's.
func WithAnswerSeeds ¶
func WithAnswerSeeds(ctx context.Context, seeds []AnswerSeed) context.Context
WithAnswerSeeds attaches pre-seeded answers to a run's context.
func WithExportWho ¶
WithExportWho carries who is calling to the rules checking the call.
func WithOutcomes ¶
WithOutcomes installs a fresh outcome register on ctx. Called once per job run; a run without one simply delivers nothing, which is what every pipeline that declares no from: should see.
func WithRunBoundary ¶
WithRunBoundary stamps a context with the moment its run started, which is the instant every pin read inside that run is judged against.
The lifetime still rides on the pin and is still applied wherever one is read — hanging it off a writer would leave it exactly as skippable as reconsiderPin. What this fixes is WHICH clock the read consults. Reading at wall-clock meant a job of six agent steps could cross the lifetime between steps 4 and 5: the pin vanished mid-job and the remaining steps resolved to a primary that was still down, each paying a full attempts: cycle before cascading and re-pinning. Nothing renews mid-job, because renewPinIf is reachable only from Preflight — once per job, and switched off entirely by --no-preflight, which is the configuration the lifetime exists to serve.
Judging against the run's own start makes the release land at a boundary where nothing is half-done, which is what docs/agents.md has always promised: a run decides before it starts, and one job sees a settled source throughout. internal/pipeline stamps this once per job run, beside the OpenRouter session, so concurrent jobs each carry their own.
Types ¶
type AnswerSeed ¶
AnswerSeed is one --answer: a substring of a question, and the answer to give when a question contains it.
Matched on the question's TEXT rather than on a position or an id, because neither exists when the flag is written: an id is minted by the run that is about to start, and which question a model asks first is the model's choice. The text is the only part of a question the pipeline author can predict.
func ParseAnswerSeed ¶
func ParseAnswerSeed(raw string) (AnswerSeed, error)
ParseAnswerSeed parses one --answer value, written `substring=answer`.
Split on the FIRST `=`, so an answer may contain one; a match may not, which is the right way round — the match is a fragment of a question somebody wrote, and an answer is arbitrary text.
type ExportHooks ¶
type ExportHooks struct {
// Before may refuse a call — a rate limit — and the refusal reaches the caller as the tool's error result.
Before func(ctx context.Context, tool string) error
// After is told every call that ran: the tool, the NAMES of the arguments it was sent (never their values, which can hold anything a caller pasted), whether it succeeded, and, when a rule refused it, that rule's name.
After func(ctx context.Context, tool string, argNames []string, ok bool, rule string)
}
ExportHooks are what the server that mounts an export decides about each call.
type ExportServer ¶
type ExportServer struct {
// Handler serves the MCP streamable HTTP protocol, statelessly: every request is answered from the tools alone.
Handler http.Handler
// Tools are the names a caller sees, in the order they are offered.
Tools []string
// contains filtered or unexported fields
}
ExportServer is one export, built and connected to its upstreams.
func NewExportServer ¶
func NewExportServer(ctx context.Context, cfg *config.Config, export config.MCPExport, hooks ExportHooks) (*ExportServer, error)
NewExportServer builds an export's tools under cfg and serves them. ctx bounds the upstream connections, which live until Close.
func (*ExportServer) Close ¶
func (e *ExportServer) Close() error
Close ends the upstream connections.
type ExportWho ¶
ExportWho is the person an export's call is made as. Zero for a call that is not a person's, an agent step's own tool among them.
type PreparedStep ¶
type PreparedStep struct {
// contains filtered or unexported fields
}
PreparedStep is an agent step resolved and materialized, with its memory: loaded — everything internal/pipeline needs to key it — but whose conversation has not started. Pipeline hashes it, asks the step cache, and records its node; Run is the conversation and nothing around it.
func PrepareStep ¶
func PrepareStep(ctx context.Context, cfg *config.Config, step config.Step, bw workspace.BuildWorkspace, st StepStore, newRunner RunnerFactory) (*PreparedStep, error)
PrepareStep resolves, materializes and loads the memory of an agent step. The caller must Close what it returns.
func (*PreparedStep) Capture ¶
func (s *PreparedStep) Capture(ctx context.Context) error
Capture files the step's declared outputs. After a successful Run only: the spill directory is removed first when it would otherwise ride into an artifact (see removeSpillDirIfCaptured).
func (*PreparedStep) Close ¶
func (s *PreparedStep) Close()
Close releases everything PrepareStep opened, the step's directory last.
func (*PreparedStep) MemoryDigest ¶
func (s *PreparedStep) MemoryDigest() string
MemoryDigest covers what the step's memory: scope holds as it starts, or "" when it declares no memory:. Part of the key: the same message with different memory is a different step (see applyStepMemory).
func (*PreparedStep) Primary ¶
func (s *PreparedStep) Primary() config.ResolvedInvocation
Primary is the invocation as CONFIGURED, before any preflight failover — the one to key on, so which source serves a run is availability rather than content and a fallback firing cannot invalidate a cache entry.
func (*PreparedStep) Run ¶
func (s *PreparedStep) Run(ctx context.Context, run StepRun) (StepResult, error)
Run runs the conversation and checks its assert:. Its usage and transcript are saved on every outcome, before the error is returned, so a step that FAILED still records what it spent and said — a failed agent step is often the expensive one, and its transcript is the one that gets read. Both writes are best-effort and detached (see saveAgentUsage, saveAgentTranscript), and both reference run.NodeHash, which is why the caller records that node before calling this.
func (*PreparedStep) Step ¶
func (s *PreparedStep) Step() config.Step
Step is the resolved step — the copy to key on. When message_files: named a run-time artifact, its loaded text is in Messages here (see prepareStepPrompt) while the step the caller holds still has none; keying on the caller's copy would collide every such pipeline onto one node regardless of what the file said.
type RunnerFactory ¶
RunnerFactory builds the runner a step's run_shell, custom tools and containerized file tools all execute through.
It is a parameter rather than a call to shell.NewRunner because placing a step is internal/pipeline's knowledge and not this package's: pipeline is what turns a step's tags: into a machine, and the dependency graph deliberately keeps internal/venue out of here. A nil factory runs on this machine, which is what every caller with no placement to apply passes.
type StepResult ¶
StepResult is what a conversation produced. Record is what its node records whatever the outcome, and Response is set whenever the conversation ran at all. Verdict and Note are set only on success: a failed run emitted no clean verdict, and internal/pipeline routes it via to["failure"] instead.
type StepRun ¶
StepRun is where a conversation belongs: the job and plan position it runs at, the name it is known by, and the node internal/pipeline recorded for it — which its usage and transcript rows reference.
type StepStore ¶
StepStore is the part of the state database an agent step's conversation touches: its spend in the usage ledger, the questions it parks for a person, what its memory: scope keeps, and its transcript. Not the node it is recorded under, nor the skip index — internal/pipeline owns both for every step kind, and this type having no way to write either is what keeps it so.
type TranscriptStore ¶
type TranscriptStore interface {
SaveNodeTranscript(ctx context.Context, hash, transcript string) error
}
TranscriptStore files a conversation's transcript under the node internal/pipeline recorded for it. The one store.Cache method an agent step needs, declared alone because the rest of that facet is pipeline's.
Source Files
¶
- answerseed.go
- askterminal.go
- askuser.go
- cli.go
- cliattest.go
- clibridge.go
- cliexec.go
- clifork.go
- cliprice.go
- cliprobe.go
- clistream.go
- compaction.go
- contextblocks.go
- conversation.go
- editfile.go
- export.go
- failover.go
- filetools.go
- fix.go
- genai.go
- loopdetect.go
- mcptool.go
- memory.go
- params.go
- pins.go
- preflight.go
- prepare.go
- probe_mcp.go
- probecache.go
- provider.go
- readfile.go
- readimage.go
- rules.go
- runnerfactory.go
- search.go
- step.go
- stepassert.go
- subagent.go
- tooldecls.go
- tooldispatch.go
- tooloutput.go
- tools.go
- transcript.go
- upstream.go
- usage.go
- verdict.go
- webfetch.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package llmclient builds the model.LLM an agent step talks to and the HTTP transports under it: retries, tool-call argument repair, OpenRouter's caching levers, and the choice of which fallback source to try next.
|
Package llmclient builds the model.LLM an agent step talks to and the HTTP transports under it: retries, tool-call argument repair, OpenRouter's caching levers, and the choice of which fallback source to try next. |
|
Package tree is how a file tool reaches the step's directory: directly, or through the image's own userland in the step's container.
|
Package tree is how a file tool reaches the step's directory: directly, or through the image's own userland in the step's container. |