# Agent (`pkg/agent`) LLM agent orchestration framework. ## Agent construction ```go agent := agent.NewAgent( "agent-name", "System instructions here", agent.WithTools(tool1, tool2), agent.WithHandoffs(otherAgent), agent.WithModel(model), ) ``` Functional options: `WithTools`, `WithHandoffs`, `WithInstructions`, `WithModel`, `WithModelSettings`, `WithMCPServers`, `WithInputGuardrails`, `WithOutputGuardrails`, `WithApproval`, `WithSession`. ## Execution ```go result, err := agent.Run(ctx, messages) result.FinalMessage().Text() // final output result.LastAgent // agent that produced the result ``` Prefer `RunTyped[T]` over `Run` + manual unmarshalling when the agent declares a structured output type via `WithOutputType`. `RunTyped` validates the response against the JSON Schema and returns the typed value directly: ```go result, err := agent.RunTyped[TrackerIdentification](ctx, ag, messages) identification := result.Output // already typed, no json.Unmarshal needed ``` Only fall back to `agent.Run` when the agent produces free-form text with no output schema. ## Tool interface ```go type Tool interface { Name() string Description() string Parameters() jsonschema.Schema Execute(ctx context.Context, input json.RawMessage) (string, error) } ``` ## Agent-as-tool `agent.AsTool(name, description)` wraps an agent as a tool for composition. ## Cancellation semantics `ctx.Done()` is a **graceful-suspend signal**, not a hard abort. When the caller cancels `ctx`, `Run`/`RunStreamed`/`Resume`/`Restore` let the in-flight LLM call and tool finish, persist a checkpoint via the configured `Checkpointer`, and return `*SuspendedError`. The framework shields downstream calls (LLM, tools, hooks, guardrails, save) from the cancellation so they complete naturally; the cancel is only observed at the next safe boundary. Use `agent.ErrSuspendForCheckpoint` as the cancel cause when the intent is graceful suspend — workers that distinguish a graceful-stop request from infrastructure-level causes (lease loss, heartbeat failure) inspect `context.Cause(ctx)` to dispatch. Implications: - A `context.WithTimeout` becomes a "max wall-clock budget then suspend" — strictly better than the alternative where the deadline kills work outright. - There is no in-process hard-abort path. Callers that genuinely need to kill a run terminate the process; stale recovery handles the row. - Tools receive a non-cancellable ctx; if a tool needs a hard deadline it must derive its own with `context.WithTimeout(ctx, ...)` inside the tool body. The agent run worker (`pkg/agentrun/handler.go`) maps a SIGTERM-driven shutdown broadcast onto a per-run `cancelRun(agent.ErrSuspendForCheckpoint)`, so the same contract drives both the public Go API and the worker infrastructure path. ## Prompt templates Prompt files with placeholders use `.txt.tmpl` (see general template naming convention in `.cursor/rules/template-files.mdc`). Use `agent.WithInstructionsFunc` to build prompts dynamically at runtime: ```go //go:embed prompts/tracker_identification.txt.tmpl var trackerIdentificationPrompt string func trackerMappingInstructions(_ context.Context, _ *agent.Agent) string { categories := coredata.ThirdPartyCategories() parts := make([]string, len(categories)) for i, c := range categories { parts[i] = string(c) } return strings.Replace(trackerIdentificationPrompt, "{{.Categories}}", strings.Join(parts, ", "), 1) } ``` ## Limits - Max turns: 10 (default) - Max tool depth: 16 (default) - Depth tracking prevents infinite recursion in handoffs