Documentation
¶
Overview ¶
Package agent is the runtime: one entry point for running the agent. Everything after Fire — tool composition, system-prompt rendering, the model call, listener fan-out, cancellation — happens in here. A surface builds a Request and hands it over; it never touches the tools provider, the model, or the memory store directly.
Index ¶
- type Agent
- func (a *Agent) Accepting() bool
- func (a *Agent) AddDefaultListener(l ResponseListener)
- func (a *Agent) Cancel(requestID string) bool
- func (a *Agent) Fire(req Request) error
- func (a *Agent) FireOrQueue(req Request, text func() string, display string) bool
- func (a *Agent) Shutdown(ctx context.Context) error
- type AgentOption
- func WithBackend(backend store.Backend) AgentOption
- func WithDefaultListener(listener ResponseListener) AgentOption
- func WithKnowledgeBase(base knowledge.KnowledgeBase, cfg knowledge.RetrievalConfig) AgentOption
- func WithLogger(log *slog.Logger) AgentOption
- func WithMemoryWindow(window int) AgentOption
- func WithModelName(name string) AgentOption
- type Image
- type ListenerFuncs
- func (l ListenerFuncs) OnContent(c string)
- func (l ListenerFuncs) OnError(err error)
- func (l ListenerFuncs) OnFinished(o Outcome)
- func (l ListenerFuncs) OnMessageQueued(requestID, display string)
- func (l ListenerFuncs) OnModel(m string)
- func (l ListenerFuncs) OnQueuedMessageRead(requestIDs []string)
- func (l ListenerFuncs) OnReasoning(r string)
- func (l ListenerFuncs) OnStart(run *RunContext)
- func (l ListenerFuncs) OnSubagent(e SubagentEvent)
- func (l ListenerFuncs) OnSubscribe()
- func (l ListenerFuncs) OnUsage(m string, u *schema.TokenUsage)
- func (l ListenerFuncs) ShouldContinue() bool
- type Outcome
- type Request
- type RequestOption
- func WithBackground(background bool) RequestOption
- func WithConversation(conversationID, rootMessageID, replyMessageID string) RequestOption
- func WithDescription(description string) RequestOption
- func WithIdentity(userID, chatID, chatType string) RequestOption
- func WithImages(images ...Image) RequestOption
- func WithKnowledgeRetrieval(retrieval knowledge.KnowledgeRetrieval) RequestOption
- func WithListener(l ResponseListener) RequestOption
- func WithParent(parentRequestID string) RequestOption
- func WithPromptVariables(vars map[string]string) RequestOption
- func WithRequestID(id string) RequestOption
- func WithScheduledTaskID(id string) RequestOption
- func WithScope(groupID, tenantID string) RequestOption
- func WithSituationID(id string) RequestOption
- func WithTodoHandler(h tools.TodoEventHandler) RequestOption
- type ResponseListener
- type RunContext
- func (r *RunContext) Abort(reason string)
- func (r *RunContext) AbortReason() string
- func (r *RunContext) AddContext(mutate func(context.Context) context.Context)
- func (r *RunContext) AddListener(l ResponseListener)
- func (r *RunContext) AddQuestionHandler(h tools.QuestionHandler)
- func (r *RunContext) AddTodoHandler(h tools.TodoEventHandler)
- func (r *RunContext) Request() Request
- type Scenario
- type ScenarioBase
- type SubagentEvent
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent is the runtime entry point. Fire starts a run and Cancel stops one; models, memory, tools, and observers are supplied by the embedding application.
The loop is explicit instead of using a higher-level agent runner so this package owns the runtime semantics: accumulated content callbacks, cancellation, tool interception, turn-ending tools, and message store.
func New ¶
func New(m model.ToolCallingChatModel, mem chatmemory.Repository, provider *tools.Provider, cfg config.Config, options ...AgentOption) *Agent
New constructs an Agent and starts accepting runs.
func (*Agent) AddDefaultListener ¶ added in v1.0.0
func (a *Agent) AddDefaultListener(l ResponseListener)
AddDefaultListener adds a listener that observes every run, for observers that only come into existence after the agent was constructed — the subagent tools, which learn at Fire time which run's registry to forget. Call before the first Fire: a race against a starting run means that run may or may not carry the listener, never a corruption.
func (*Agent) Cancel ¶
Cancel stops a run by request id. False when no such run is live — already finished, or never started. The cancellation goes down the tree as well: a subagent nobody is waiting for any more is still work with a shell or an MCP call in it, and cancelling the parent alone would leave it running.
func (*Agent) Fire ¶
Fire starts a run and returns immediately; results reach listeners, never the caller. A caller that has to wait for the answer waits on a listener.
func (*Agent) FireOrQueue ¶ added in v1.0.0
FireOrQueue offers a message to the run already in flight over the same conversation, by the same user — a correction, an addition, an answer to "should I go on?" arriving while the agent works. True means the run took it: it is read into the turn at the next tool boundary, and this message needs no run of its own. False means nobody matching is live (or the run had already stopped reading), and the caller should Fire the request — which is why this does not fire on the caller's behalf: the caller built the request and owns what a refusal of it means.
A run matches when it is of the same conversation and the same user, not a background run and not a subagent: a group card being public does not make someone else's aside a correction of this run, and a subagent has no conversation to correct.
type AgentOption ¶
type AgentOption func(*Agent)
AgentOption configures an Agent during construction.
func WithBackend ¶
func WithBackend(backend store.Backend) AgentOption
WithBackend supplies the persistence backend used by the pending-question guard. The agent does not own the backend or any of its connections.
func WithDefaultListener ¶
func WithDefaultListener(listener ResponseListener) AgentOption
WithDefaultListener adds a listener that observes every run.
func WithKnowledgeBase ¶ added in v1.0.0
func WithKnowledgeBase(base knowledge.KnowledgeBase, cfg knowledge.RetrievalConfig) AgentOption
WithKnowledgeBase attaches an optional scoped knowledge base. Retrieval is best-effort: a vector-store outage is logged and the conversation still has a chance to answer from its normal context.
func WithLogger ¶
func WithLogger(log *slog.Logger) AgentOption
WithLogger supplies the logger used for runtime and callback failures.
func WithMemoryWindow ¶
func WithMemoryWindow(window int) AgentOption
WithMemoryWindow limits the number of conversation messages loaded per run. A non-positive value keeps the full conversation.
func WithModelName ¶
func WithModelName(name string) AgentOption
WithModelName supplies a fallback name for model callbacks when the stream does not include one.
type ListenerFuncs ¶
type ListenerFuncs struct {
OnStartFunc func(run *RunContext)
OnSubscribeFunc func()
OnModelFunc func(model string)
OnContentFunc func(contentSoFar string)
OnReasoningFunc func(reasoningSoFar string)
OnUsageFunc func(model string, usage *schema.TokenUsage)
OnSubagentFunc func(event SubagentEvent)
// OnMessageQueuedFunc and OnQueuedMessageReadFunc observe FireOrQueue
// joining messages to a run in flight.
OnMessageQueuedFunc func(requestID, display string)
OnQueuedMessageReadFunc func(requestIDs []string)
OnErrorFunc func(err error)
OnFinishedFunc func(outcome Outcome)
// ShouldContinueFunc nil means always continue.
ShouldContinueFunc func() bool
}
ListenerFuncs adapts functions to ResponseListener. The zero value is a listener that observes nothing and always continues — embed it and fill the hooks a surface needs.
func (ListenerFuncs) OnContent ¶
func (l ListenerFuncs) OnContent(c string)
func (ListenerFuncs) OnError ¶
func (l ListenerFuncs) OnError(err error)
func (ListenerFuncs) OnFinished ¶
func (l ListenerFuncs) OnFinished(o Outcome)
func (ListenerFuncs) OnMessageQueued ¶ added in v1.0.0
func (l ListenerFuncs) OnMessageQueued(requestID, display string)
func (ListenerFuncs) OnModel ¶
func (l ListenerFuncs) OnModel(m string)
func (ListenerFuncs) OnQueuedMessageRead ¶ added in v1.0.0
func (l ListenerFuncs) OnQueuedMessageRead(requestIDs []string)
func (ListenerFuncs) OnReasoning ¶ added in v1.0.0
func (l ListenerFuncs) OnReasoning(r string)
func (ListenerFuncs) OnStart ¶
func (l ListenerFuncs) OnStart(run *RunContext)
func (ListenerFuncs) OnSubagent ¶ added in v1.0.0
func (l ListenerFuncs) OnSubagent(e SubagentEvent)
func (ListenerFuncs) OnSubscribe ¶
func (l ListenerFuncs) OnSubscribe()
func (ListenerFuncs) OnUsage ¶
func (l ListenerFuncs) OnUsage(m string, u *schema.TokenUsage)
func (ListenerFuncs) ShouldContinue ¶
func (l ListenerFuncs) ShouldContinue() bool
type Request ¶
type Request struct {
// RequestID is what Cancel stops; empty means not cancellable.
RequestID string
// ParentRequestID names the run that started this one, when it is a
// subagent: cancelling the parent cancels this run, its tokens count on
// the parent's turn, and the parent is held open until it finishes. A
// parent that already ended is forgotten — there is nobody to tell.
ParentRequestID string
// Description is one line saying what the run is for, shown to listeners
// of the parent run while a subagent works.
Description string
// Scenario is required (NewRequest's argument).
Scenario Scenario
UserID string
ChatID string
// ChatType defaults to "p2p".
ChatType string
// GroupID and TenantID scope the run's reads beyond the user's own
// home: a group's or tenant's shared files and skills are read through
// (never written to), and the knowledge base and sandbox carry the same
// scope. Empty means no scope.
GroupID string
TenantID string
// SituationID is set by optional external-event triage runs. It is carried
// to situation management tools and otherwise has no runtime meaning.
SituationID string
// ScheduledTaskID identifies the task whose firing is executing.
ScheduledTaskID string
// ConversationID groups the runs that share chat memory.
ConversationID string
RootMessageID string
ReplyMessageID string
// Background runs post no answer of their own (see ScheduledTask).
Background bool
// PromptVariables extend the system prompt's variable set.
PromptVariables map[string]string
// Images may accompany Text.
Images []Image
// Listeners observe this run, alongside any application-level observers.
Listeners []ResponseListener
// TodoHandlers receive this run's todo updates.
TodoHandlers []tools.TodoEventHandler
// Text is the user message passed to the model.
Text string
// KnowledgeRetrieval is an explicit, fixed-scope lookup for unattended
// runs. When nil, an attached knowledge base derives scope from identity and
// retrieves using Text.
KnowledgeRetrieval *knowledge.KnowledgeRetrieval
}
Request describes one run. Built with NewRequest plus options; the zero Request is not runnable. Scenario and Text are required, and a caller that has no conversation id gets a memoryless run rather than an error: the identity fields default, ConversationID does not.
func NewRequest ¶
func NewRequest(scenario Scenario, text string, opts ...RequestOption) Request
NewRequest starts a Request for a scenario. Required: scenario and text.
func (Request) UserMessage ¶
UserMessage assembles the user message for the model call.
type RequestOption ¶
type RequestOption func(*Request)
RequestOption mutates a Request during NewRequest.
func WithBackground ¶
func WithBackground(background bool) RequestOption
WithBackground marks the run unattended (no answer of its own).
func WithConversation ¶
func WithConversation(conversationID, rootMessageID, replyMessageID string) RequestOption
WithConversation places the run in a conversation (chat memory) and identifies the root and reply messages for surfaces.
func WithDescription ¶ added in v1.0.0
func WithDescription(description string) RequestOption
WithDescription says what the run is for, in one line, where a surface shows work in progress.
func WithIdentity ¶
func WithIdentity(userID, chatID, chatType string) RequestOption
WithIdentity sets who is talking and where.
func WithImages ¶
func WithImages(images ...Image) RequestOption
WithImages attaches images to the user message, as URLs or data-URI Base64 payloads.
func WithKnowledgeRetrieval ¶ added in v1.0.0
func WithKnowledgeRetrieval(retrieval knowledge.KnowledgeRetrieval) RequestOption
WithKnowledgeRetrieval sets a fixed-scope retrieval request. The scope is not derived from the incoming message, which is important for event bodies and other untrusted briefings.
func WithListener ¶
func WithListener(l ResponseListener) RequestOption
WithListener attaches a run listener.
func WithParent ¶ added in v1.0.0
func WithParent(parentRequestID string) RequestOption
WithParent ties the run to the run that started it, making it a subagent: cancelled with the parent, its usage counted on the parent's turn, and the parent held open until it finishes.
func WithPromptVariables ¶
func WithPromptVariables(vars map[string]string) RequestOption
WithPromptVariables supplies extra system-prompt variables.
func WithRequestID ¶
func WithRequestID(id string) RequestOption
WithRequestID names the run for Cancel.
func WithScheduledTaskID ¶ added in v1.0.0
func WithScheduledTaskID(id string) RequestOption
WithScheduledTaskID binds optional task self-control tools to a firing.
func WithScope ¶ added in v1.0.0
func WithScope(groupID, tenantID string) RequestOption
WithScope gives the run a group and tenant: their homes' files and skills are read through the user's own, and the knowledge base and sandbox carry the same scope. Blank ids mean no scope.
func WithSituationID ¶ added in v1.0.0
func WithSituationID(id string) RequestOption
WithSituationID binds optional event-management tools to one situation.
func WithTodoHandler ¶
func WithTodoHandler(h tools.TodoEventHandler) RequestOption
WithTodoHandler attaches a todo handler.
type ResponseListener ¶
type ResponseListener interface {
OnStart(run *RunContext)
OnSubscribe()
OnModel(model string)
OnContent(contentSoFar string)
// OnReasoning receives the reasoning so far, accumulated like OnContent
// but reset per model call: a run's thinking is one block per model call,
// joined by a blank line, because a second call after a tool result is a
// new line of thought, not a continuation of the first.
OnReasoning(reasoningSoFar string)
OnUsage(model string, usage *schema.TokenUsage)
// OnSubagent reports what a run this one started is doing. Only the
// parent's listeners receive it, and only the fields the event kind
// carries — see SubagentEvent.
OnSubagent(event SubagentEvent)
// OnMessageQueued reports that a message joined this run in flight via
// FireOrQueue and is waiting to be read at the next tool boundary.
// Display names the message (a preview, a sender); it is identifying
// prose, not the body.
OnMessageQueued(requestID, display string)
// OnQueuedMessageRead reports the request ids the run just read into
// itself at a tool boundary — messages this run answers, so their
// senders are not waiting on a run of their own.
OnQueuedMessageRead(requestIDs []string)
OnError(err error)
// OnFinished is called exactly once, whatever the run ended by.
OnFinished(outcome Outcome)
// ShouldContinue is polled between model iterations; false ends the run as
// cancelled. It is how a surface that stopped listening (a closed card,
// say) stops the work that was feeding it.
ShouldContinue() bool
}
ResponseListener observes a run. Every method has a safe default (a no-op or true), and every method is called with the run's failures contained: a callback that panics is recovered and logged, because one listener must not be able to fail another's run.
OnContent receives the content so far, accumulated — not the deltas: a surface replaces what it shows, it does not append, so deltas would make every surface do its own accumulation and get it subtly wrong.
type RunContext ¶
type RunContext struct {
// contains filtered or unexported fields
}
RunContext is the per-run contribution point, handed to OnStart and valid for the duration of that call only: after OnStart returns, the agent reads it once and later mutations are dropped. A listener uses it to attach a late listener of its own, a todo handler, a question handler (the ask tool needs somewhere to put the questions before the run can offer it), or a context value tools will read.
func (*RunContext) Abort ¶
func (r *RunContext) Abort(reason string)
Abort stops the run before it starts, with a reason the error carries.
func (*RunContext) AbortReason ¶
func (r *RunContext) AbortReason() string
AbortReason is the reason passed to Abort, empty when none was.
func (*RunContext) AddContext ¶
func (r *RunContext) AddContext(mutate func(context.Context) context.Context)
AddContext adds a context decorator the run's tool context passes through.
func (*RunContext) AddListener ¶
func (r *RunContext) AddListener(l ResponseListener)
AddListener attaches a listener to this run.
func (*RunContext) AddQuestionHandler ¶
func (r *RunContext) AddQuestionHandler(h tools.QuestionHandler)
AddQuestionHandler attaches a question handler to this run. Dropped for background runs, where there is no surface to put a question on and no card to answer it — an ask that cannot be presented fails the ask, which the model experiences as "no channel could ask".
func (*RunContext) AddTodoHandler ¶
func (r *RunContext) AddTodoHandler(h tools.TodoEventHandler)
AddTodoHandler attaches a todo handler to this run.
func (*RunContext) Request ¶
func (r *RunContext) Request() Request
Request returns the request this run context belongs to.
type Scenario ¶
type Scenario interface {
// Name identifies the scenario in logs and surfaces.
Name() string
// ConversationMemory reports whether the run joins the conversation it
// names — reads its history and appends to it. A run with no memory
// still has an identity, but each one starts from nothing.
ConversationMemory() bool
// Offers decides whether a run of this scenario gets the named tool.
// The default is everything; see ScheduledTaskScenario for the one
// exception the runtime ships.
Offers(toolName string) bool
}
Scenario names the kind of run, and what follows from that: whether the run reads and writes conversation memory, and which tools it is offered.
var ChatScenario Scenario = &chatScenario{namedScenario{ScenarioBase{}, "CHAT"}}
ChatScenario is the ordinary run: a user said something, the agent answers in the conversation. Task-self-control tools are omitted because an ordinary run is not the firing of a task.
var ScheduledTaskScenario Scenario = &scheduledTaskScenario{namedScenario{ScenarioBase{}, "SCHEDULED_TASK"}}
ScheduledTaskScenario is a firing of a scheduled task. It does not get the tools that create or manage another task, but it does get the two task-self-control tools: a firing may stop or re-arm the task it is already executing without creating a second task.
var SubagentScenario Scenario = &subagentScenario{namedScenario{ScenarioBase{}, "SUBAGENT"}}
SubagentScenario is a run another run started. It joins no conversation — its whole task is the brief it was given, and a conversation of its own keeps it out of every store whatever the backend does. It gets neither the subagent tools (that is the depth cap: one level, enforced by name with no counter to get wrong) nor the schedule tools — unattended work must not leave work behind.
type ScenarioBase ¶
type ScenarioBase struct{}
ScenarioBase is embeddable default behaviour: memory on, every tool.
func (ScenarioBase) ConversationMemory ¶
func (ScenarioBase) ConversationMemory() bool
func (ScenarioBase) Offers ¶
func (ScenarioBase) Offers(string) bool
type SubagentEvent ¶ added in v1.0.0
type SubagentEvent struct {
SubagentID string
Description string
ContentSoFar string
Model string
Usage *schema.TokenUsage
Outcome Outcome
}
SubagentEvent is one report about one subagent of the run. Which fields are set says what happened; the predicates name them. ContentSoFar is the subagent's accumulated answer (set while it is talking and once at the end); Usage is one model call's spend, attributed; Outcome is set when the subagent has ended.
func (SubagentEvent) Ended ¶ added in v1.0.0
func (e SubagentEvent) Ended() bool
Ended reports the subagent finished, and how; with the final ContentSoFar.
func (SubagentEvent) Said ¶ added in v1.0.0
func (e SubagentEvent) Said() bool
Said reports ContentSoFar is set: the subagent's answer so far. A surface renders this where it shows work being waited on — never as the reply, which is what OnContent means.
func (SubagentEvent) Spent ¶ added in v1.0.0
func (e SubagentEvent) Spent() bool
Spent reports Usage is set: tokens this subagent just used, counted on the parent's turn as well.
func (SubagentEvent) Started ¶ added in v1.0.0
func (e SubagentEvent) Started() bool
Started reports the subagent was started.