agentkit

package module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 6 Imported by: 0

README

AgentKit

基于 pluginkit 的 Go Agent Harness 运行时。通过 YAML 配置装配 Runner、Platform、Loop、Agent、工具与策略,支持交互式 REPL、自主长跑、子 Agent 委派、MCP 与 headless 守护等多种运行形态。

特性

  • 插件化装配 — 63+ 已注册 Plugin Kind,L0 默认配置 + L1 overlay 按需覆盖
  • Coding Agent 闭环 — 文件读写、Shell、策略审批、Session 持久化(jsonl)
  • 自主运行 — turn 续跑、预算分层、todo/finish 收尾、token 阈值压缩、崩溃恢复
  • 子 Agent 委派agents/*.md 定义子 agent,主 agent 只读回结论
  • 网络能力 — HTTP 抓取、Exa 搜索、向用户提问(HIL)
  • Headless 模式 — worker(一次性)、timer(固定间隔)、cron(日历 + 自主排期)
  • Web 管理台 — 装配树编辑、结构诊断、试装配与 build 校验

架构概览

flowchart TB
  subgraph entry["进程入口"]
    CLI["cmd/agent"]
    MGR["-manager Web UI"]
  end

  subgraph spine["Spine"]
    R["Runner"]
    P["Platform<br/>(cli / worker / timer / multiplex)"]
    L["Loop"]
    A["Agent<br/>(coding / …)"]
  end

  subgraph deps["依赖组件"]
    LLM["LLM Provider"]
    TOOLS["Tools Runtime"]
    SESS["Session Store"]
    HOOK["Hooks"]
    POL["Policy / Approval"]
  end

  CLI --> R
  MGR -.->|配置编辑| R
  R --> P
  P --> L
  L --> A
  A --> LLM
  A --> TOOLS
  A --> SESS
  A --> HOOK
  TOOLS --> POL

配置模型:config.base.yaml(L0 随仓库发布)+ config.yamlpresets/*.yaml(L1 overlay,后者覆盖前者)。实例图由 pluginkit/build 构造,root 通常为 runner

快速开始

环境要求
  • Go 1.26+
  • OpenAI 兼容 API Key(冒烟 preset 可跳过)
安装与运行
git clone https://github.com/lengzhao/agentkit.git
cd agentkit

export OPENAI_API_KEY=sk-...

# 交互式 REPL
go run ./cmd/agent

# 带首条消息进入 REPL
go run ./cmd/agent "帮我看看这个项目结构"

# 项目目录 coding preset
go run ./cmd/agent -config presets/coding.yaml "你的任务"

# 无 API Key 本地冒烟(scripted LLM)
go run ./cmd/agent -config presets/coding-smoke.yaml "列出当前目录并读取 README"
本地配置

复制示例配置为 L1 override(已在 .gitignore 中):

cp config.example.yaml config.yaml

-config 支持逗号分隔的多个 overlay,按顺序合并,后面的覆盖前面的:

go run ./cmd/agent -config presets/autonomous.yaml,presets/worker.yaml "一次性任务"

常用场景

场景 命令示例
交互式 coding go run ./cmd/agent -config presets/coding.yaml
自主长跑 go run ./cmd/agent -config presets/autonomous.yaml "多轮任务"
子 Agent 委派 go run ./cmd/agent -config presets/subagent.yaml "让 researcher 调研 …"
网络搜索 + 抓取 export EXA_API_KEY=...-config presets/web.yaml
Headless 批处理 -config presets/autonomous.yaml,presets/worker.yaml
定时守护 -config presets/autonomous.yaml,presets/cron.yaml
配置管理 Web UI go run ./cmd/agent -manager -addr :8080

完整 preset 索引见 presets/README.md

项目结构

agentkit/
├── cmd/agent/          # 主入口(REPL / headless / -manager)
├── config.base.yaml    # L0 默认装配
├── presets/            # 场景 L1 overlay
├── runtime/            # Runner、Loop、Agent、Session、Platform、LLM
├── plugins/            # 工具、Hook、Policy、Prompt 等插件实现
├── cap/                # 能力接口(filesystem、workspace、compaction …)
├── examples/agents/    # 子 Agent 定义示例
└── docs/               # 架构与设计文档(中文)

文档

详细设计文档见 docs/README.zh.md。建议阅读顺序:

flowchart LR
  A["reference-analysis<br/>业界共性"] --> B["plugin-catalog<br/>插件边界"]
  B --> C["go-agent-harness-architecture<br/>实现细节"]
  C --> D["roadmap<br/>现状与规划"]
文档 说明
go-agent-harness-architecture.zh.md 完整架构:Runner、Spine、装配模型、生命周期
plugin-catalog.zh.md Plugin Kind 目录与分阶段落地
autonomous-run.zh.md 自主运行:预算、todo/finish、崩溃恢复
subagent.zh.md 子 Agent 委派
mcp.zh.md MCP 动态工具接入
multi-tenant.zh.md 多租户与会话隔离
roadmap.zh.md 现状基线与路线图

开发

# 运行测试
go test ./...

# 新增插件后更新 blank import
go generate ./...

# 查看日志(默认写入 ~/.agentkit/agent.log)
tail -f ~/.agentkit/agent.log

插件通过 pluginkit.Register(kind, New) 注册;构造函数支持 (Config, Deps) 形态,依赖由配置中的 deps 字段注入。

外部参考

项目 说明
pluginkit 插件注册与实例图构建
DeepSeek Harness Agent Harness 参考实现
Pi Coding Agent 扩展模型参考

License

MIT

Documentation

Index

Constants

View Source
const (
	// KeySessionID is the context key for the current opaque SessionID.
	KeySessionID contextKey = "agentkit.session_id"
	// KeyAgentID is the context key for the current AgentID.
	KeyAgentID contextKey = "agentkit.agent_id"
	// KeyPlatformID is the context key for the current inbound/outbound platform.
	KeyPlatformID contextKey = "agentkit.platform_id"
	// KeyUserID is the context key for the current end-user identity, when known.
	KeyUserID contextKey = "agentkit.user_id"
	// KeyTurnID is the context key for the current turn, when one is active.
	KeyTurnID contextKey = "agentkit.turn_id"
	// KeyToolCallID is the context key for the current tool call, when one is active.
	KeyToolCallID contextKey = "agentkit.tool_call_id"
	// KeySessionControl is the context key for per-session steer/follow-up state.
	// Loop sets it before Agent.RunTurn; the value is a runtime/loop.Control that
	// also implements permission.Broker.
	KeySessionControl contextKey = "agentkit.session_control"
	// KeyOutboundEmit is the per-turn outbound hook. Loop sets it before
	// Agent.RunTurn so tools and permission waits can emit outbound events
	// through the same channel as assistant streaming.
	KeyOutboundEmit contextKey = "agentkit.outbound_emit"
	// KeyDeliverySessionID is the inbound delivery SessionID for the current turn
	// (finest grain). Outbound routing should prefer this over KeySessionID when
	// both are present.
	KeyDeliverySessionID contextKey = "agentkit.delivery_session_id"
)

Variables

This section is empty.

Functions

func FormatToolResult added in v0.1.2

func FormatToolResult(out any) (string, error)

FormatToolResult converts a typed tool handler result into model-visible text.

func MarshalOutboundData

func MarshalOutboundData(v any) json.RawMessage

Types

type AfterToolHook

type AfterToolHook interface {
	Hook
	AfterTool(context.Context, *ToolResult) error
}

func OnAfterTool

func OnAfterTool(fn func(context.Context, *ToolResult) error) AfterToolHook

OnAfterTool wraps a function as an AfterToolHook.

type Agent

type Agent interface {
	ID() AgentID
	RunTurn(context.Context, TurnInput) error
}

Agent is the execution unit below Loop. It owns prompt, model, tools, policies and hooks for a single agent identity. Conversation state lives in Session; the agent implementation resolves Session via SessionStore using ctx.Value(KeySessionID). Loop does not inject Session objects or duplicate routing fields in TurnInput.

Steer/follow-up/cancel are owned by Loop per SessionID. Loop seeds ctx.Value(KeySessionControl) before RunTurn; Agent reads it for step-level steer interrupts.

Agent plugins declare SessionStore in their Deps struct (pluginkit injection).

type AgentID

type AgentID string

type Approval

type Approval interface {
	Ask(context.Context, ApprovalRequest) (ApprovalDecision, error)
}

type ApprovalDecision

type ApprovalDecision struct {
	Allowed bool
	Reason  string
}

type ApprovalRequest

type ApprovalRequest struct {
	Reason   string
	ToolCall *ToolCall
}

type AssistantMessageEvent

type AssistantMessageEvent struct {
	Type         AssistantMessageEventType `json:"type"`
	ContentIndex int                       `json:"contentIndex,omitempty"`
	Delta        string                    `json:"delta,omitempty"`
	Content      string                    `json:"content,omitempty"`
	ID           string                    `json:"id,omitempty"`
	ToolName     string                    `json:"toolName,omitempty"`
	ToolCall     *ToolCall                 `json:"toolCall,omitempty"`
	Reason       string                    `json:"reason,omitempty"`
	ErrorMessage string                    `json:"errorMessage,omitempty"`
}

AssistantMessageEvent is the wire-safe Pi RPC delta payload (no cumulative partial).

type AssistantMessageEventType

type AssistantMessageEventType string

AssistantMessageEventType mirrors Pi RPC assistantMessageEvent.type values.

const (
	AssistantEventStart         AssistantMessageEventType = "start"
	AssistantEventTextStart     AssistantMessageEventType = "text_start"
	AssistantEventTextDelta     AssistantMessageEventType = "text_delta"
	AssistantEventTextEnd       AssistantMessageEventType = "text_end"
	AssistantEventThinkingStart AssistantMessageEventType = "thinking_start"
	AssistantEventThinkingDelta AssistantMessageEventType = "thinking_delta"
	AssistantEventThinkingEnd   AssistantMessageEventType = "thinking_end"
	AssistantEventToolCallStart AssistantMessageEventType = "toolcall_start"
	AssistantEventToolCallDelta AssistantMessageEventType = "toolcall_delta"
	AssistantEventToolCallEnd   AssistantMessageEventType = "toolcall_end"
	AssistantEventDone          AssistantMessageEventType = "done"
	AssistantEventError         AssistantMessageEventType = "error"
)
const LLMEventMessage AssistantMessageEventType = "message"

LLMEventMessage carries a finalized (or snapshot) ModelMessage rather than a delta. It is internal to the provider/agent boundary and is never forwarded to platforms, so it has no counterpart in the Pi RPC event set.

type BeforeStep

type BeforeStep struct {
	Messages []ModelMessage
}

BeforeStep is invoked before a model step. Hooks read routing context from ctx.Value(KeySessionID) / ctx.Value(KeyAgentID); hooks that need durable state should depend on SessionStore via pluginkit Deps.

type BeforeStepHook

type BeforeStepHook interface {
	Hook
	BeforeStep(context.Context, *BeforeStep) error
}

func OnBeforeStep

func OnBeforeStep(fn func(context.Context, *BeforeStep) error) BeforeStepHook

OnBeforeStep wraps a function as a BeforeStepHook.

type BeforeToolHook

type BeforeToolHook interface {
	Hook
	BeforeTool(context.Context, *ToolCall) error
}

func OnBeforeTool

func OnBeforeTool(fn func(context.Context, *ToolCall) error) BeforeToolHook

OnBeforeTool wraps a function as a BeforeToolHook.

type BudgetState

type BudgetState struct {
	RemainingSteps         int
	RemainingContinuations int
	RemainingSeconds       int
	RemainingTokens        int
	// SoftExhausted is true once any limited dimension crosses softRatio.
	SoftExhausted bool
	// Exhausted is true when a hard limit is reached; Continue is then ignored.
	Exhausted bool
}

BudgetState reports what is left of the run budget. Unlimited dimensions report -1 so hooks can distinguish "no limit" from "nothing left".

type Command

type Command interface {
	Name() string
	Alias() string
	Description() string
	CommandExec(ctx context.Context, args ...string) (string, error)
}

Command is one slash command contribution.

type CommandCollector

type CommandCollector interface {
	SetCommands(providers []CommandProvider) error
}

CommandCollector receives CommandProvider contributions after pluginkit build. Runner wires them with build.WireContributions during Run.

type CommandProvider

type CommandProvider interface {
	Commands() []Command
}

CommandProvider contributes human-facing commands from a built plugin instance. It is designed to work with pluginkit/build.WireContributions so commands can live next to the capability that owns their behavior.

type CommandResult

type CommandResult struct {
	Output     string
	NewSession SessionID
}

CommandResult is the outcome of a handled slash command.

type Commands

type Commands interface {
	Dispatch(ctx context.Context, name string, args []string) (*CommandResult, error)
	List() []Command
}

Commands is a post-build slash command catalog for platforms.

type ContentPart

type ContentPart struct {
	Type   string `json:"type"`
	Text   string `json:"text,omitempty"`
	URL    string `json:"url,omitempty"`
	MIME   string `json:"mime,omitempty"`
	Detail string `json:"detail,omitempty"`
}

type Decision

type Decision struct {
	Kind   DecisionKind
	Reason string
	// Audit is merged into ToolResult.Audit when the tool runtime denies a call.
	Audit map[string]string
}

func Allow

func Allow() Decision

func Ask

func Ask(reason string) Decision

func Deny

func Deny(reason string) Decision

type DecisionKind

type DecisionKind string
const (
	DecisionAllow DecisionKind = "allow"
	DecisionDeny  DecisionKind = "deny"
	DecisionAsk   DecisionKind = "ask"
)

type EventID

type EventID string

type EventSeq

type EventSeq int64

type EventType

type EventType string
const (
	EventTurnStart               EventType = "turn/start"
	EventTurnEnd                 EventType = "turn/end"
	EventStepStart               EventType = "step/start"
	EventStepEnd                 EventType = "step/end"
	EventUserMessage             EventType = "user/message"
	EventMessageStart            EventType = "message/start"
	EventMessageUpdate           EventType = "message/update"
	EventMessageEnd              EventType = "message/end"
	EventAssistantMessage        EventType = "assistant/message"
	EventToolCall                EventType = "tool/call"
	EventToolResult              EventType = "tool/result"
	EventCompaction              EventType = "session/compaction"
	EventSkillLoad               EventType = "skill/load"
	EventAutoRetryStart          EventType = "retry/start"
	EventAutoRetryEnd            EventType = "retry/end"
	EventSummarizationRetryStart EventType = "summarization/retry/start"
	EventSummarizationRetryEnd   EventType = "summarization/retry/end"
	EventOverflowRecovery        EventType = "overflow/recovery"
	EventTurnContinue            EventType = "turn/continue"
	EventUsage                   EventType = "usage"
	EventTodoUpdate              EventType = "todo/update"
	EventRunFinish               EventType = "run/finish"
	EventSessionRecovery         EventType = "session/recovery"
	EventSubagentStart           EventType = "subagent/start"
	EventSubagentEnd             EventType = "subagent/end"
	EventPermissionRequest       EventType = "permission/request"
	EventPermissionResolved      EventType = "permission/resolved"
)

type FollowUpMode

type FollowUpMode string

FollowUpMode controls how queued follow-up messages are drained after a turn.

const (
	FollowUpOneAtATime FollowUpMode = "one-at-a-time"
	FollowUpAll        FollowUpMode = "all"
)

type Hook

type Hook interface {
	// contains filtered or unexported methods
}

Hook marks a value that may implement one or more hook point interfaces. Execution order follows deps.providers list order; within a provider, Hooks() slice order is preserved.

type HookProvider

type HookProvider interface {
	Hooks() []Hook
}

type HookRuntime

type HookRuntime interface {
	BeforeStep(context.Context, *BeforeStep) error
	BeforeTool(context.Context, *ToolCall) error
	AfterTool(context.Context, *ToolResult) error
	TurnStopping(context.Context, *TurnStopping) error
}

type JSONSchema

type JSONSchema struct {
	Type        string                `json:"type,omitempty"`
	Description string                `json:"description,omitempty"`
	Properties  map[string]JSONSchema `json:"properties,omitempty"`
	Required    []string              `json:"required,omitempty"`
	Items       *JSONSchema           `json:"items,omitempty"`
	Raw         map[string]any        `json:"-"`
}

func (JSONSchema) MarshalJSON

func (s JSONSchema) MarshalJSON() ([]byte, error)

MarshalJSON emits Raw when set so MCP and other external schemas round-trip intact.

func (*JSONSchema) UnmarshalJSON

func (s *JSONSchema) UnmarshalJSON(data []byte) error

UnmarshalJSON stores the full object in Raw and also fills known fields when present.

type LLMEvent

type LLMEvent struct {
	Type         AssistantMessageEventType
	Message      *ModelMessage
	ContentIndex int
	Delta        string
	ToolCall     *ToolCall
	Usage        *Usage
}

LLMEvent reuses AssistantMessageEventType so provider output and the platform-facing stream share one vocabulary. Providers emit the text_*, thinking_* and toolcall_* values plus LLMEventMessage; AssistantEventDone and AssistantEventError are wire-only and never produced here.

type LLMProvider

type LLMProvider interface {
	Name() string
	Stream(context.Context, LLMRequest) (LLMStream, error)
}

LLMProvider streams model responses for an already assembled request. LLMRequest carries model-visible messages only; session routing is handled by the agent runtime before and after the provider boundary.

type LLMRequest

type LLMRequest struct {
	Model    string
	Messages []ModelMessage
	Tools    []ToolSpec
}

type LLMStream

type LLMStream interface {
	Recv() (LLMEvent, error)
	Close() error
}

type Loop

type Loop interface {
	Dispatch(context.Context, LoopRequest) error
	Steer(context.Context, ModelMessage) error
	FollowUp(context.Context, ModelMessage) error
	// TryDeliverPermission consumes a typed permission reply. It returns true
	// when the message was handled and must not start a new turn.
	TryDeliverPermission(MessageEvent) bool
	// SupersedePendingForInbound cancels an active permission wait when a new
	// user message arrives without a permission reply.
	SupersedePendingForInbound(MessageEvent)
}

Loop is the turn scheduler. It routes inbound MessageEvents to agents, serializes work per SessionID, and owns per-session steer/follow-up control. Loop seeds ctx with KeySessionID/KeyDeliverySessionID/KeyAgentID/KeyPlatformID/KeyUserID/ KeySessionControl/KeyOutboundEmit before calling the agent. It does not resolve Session objects; that is the agent's responsibility.

type LoopRequest

type LoopRequest struct {
	Event             MessageEvent
	DeliverySessionID SessionID // platform delivery target; empty means Event.SessionID
	Emit              OutboundEmit
	Capability        any // permission.Capability, resolved by runner from the inbound platform
}

LoopRequest wraps one inbound message. Runner rewrites Event.SessionID to the effective id (after sessionScope) before Dispatch; DeliverySessionID keeps the platform routing target for outbound Send.

type MessageEndPayload

type MessageEndPayload struct {
	Message ModelMessage `json:"message"`
}

MessageEndPayload is emitted when an assistant message is finalized.

type MessageEvent

type MessageEvent struct {
	SessionID  SessionID // required: platform delivery id
	AgentID    AgentID
	PlatformID string
	UserID     string
	Message    ModelMessage
	// Reply carries a permission answer as JSON. Decode with permission.DecodeReply.
	Reply json.RawMessage `json:"reply,omitempty"`
}

MessageEvent is the inbound envelope from Platform to Loop. SessionID is the delivery target (finest grain); runner collapses it per sessionScope before Loop dispatch.

type MessageStartPayload

type MessageStartPayload struct {
	Message ModelMessage `json:"message"`
}

MessageStartPayload is emitted when assistant streaming begins.

type MessageUpdatePayload

type MessageUpdatePayload struct {
	Usage                 *Usage                `json:"usage,omitempty"`
	AssistantMessageEvent AssistantMessageEvent `json:"assistantMessageEvent"`
}

MessageUpdatePayload matches Pi RPC message_update events.

type ModelMessage

type ModelMessage struct {
	Role        string
	Content     []ContentPart
	ToolCalls   []ToolCall
	ToolResults []ToolResult
}

ModelMessage is model-visible content only. Session routing lives on event envelopes and context keys, not on ModelMessage.

type OutboundEmit

type OutboundEmit func(context.Context, OutboundEvent) error

OutboundEmit sends platform events during a turn. When nil, streaming is suppressed.

type OutboundEvent

type OutboundEvent struct {
	SessionID  SessionID // required
	AgentID    AgentID
	PlatformID string
	UserID     string
	Type       EventType
	Data       json.RawMessage
}

OutboundEvent is the outbound envelope from Agent/Loop to Platform. SessionID must match the conversation that produced the turn so the platform can route the reply to the correct IM target.

type Platform

type Platform interface {
	Receive(context.Context) (MessageEvent, error)
	Send(context.Context, OutboundEvent) error
}

Platform adapts external transports into AgentKit message events. Every inbound MessageEvent must carry a delivery SessionID (finest grain); runner applies sessionScope for scheduling and history. OutboundEvent.SessionID must be the delivery id so replies reach the correct IM target.

Concurrency contract:

  • Receive is called from a single goroutine and may block.
  • Send must be safe for concurrent use. Runner runs turns from different effective sessions in parallel (runner.config.maxConcurrentTurns, default 64); each turn emits from its own goroutine.

type PlatformIdentifier added in v0.1.1

type PlatformIdentifier interface {
	PlatformID() string
}

PlatformIdentifier exposes the stable routing ID for a leaf platform. Multiplex and other aggregators use it to key sub-platforms without extra config; conflicts are disambiguated with an index suffix.

type Policy

type Policy interface {
	Evaluate(context.Context, PolicyInput) (Decision, error)
}

func PolicyFunc

func PolicyFunc(fn func(context.Context, PolicyInput) Decision) Policy

PolicyFunc wraps a function as a Policy implementation.

type PolicyInput

type PolicyInput struct {
	ToolCall *ToolCall
}

PolicyInput carries the policy payload. Per-conversation policy should read ctx.Value(KeySessionID) / ctx.Value(KeyAgentID) / ctx.Value(KeyUserID).

type PromptAssembler

type PromptAssembler interface {
	Assemble(context.Context, PromptRequest) ([]ModelMessage, error)
}

PromptAssembler builds the model request prompt from registered sections.

type PromptRequest

type PromptRequest struct {
	Messages []ModelMessage
}

PromptRequest carries model-visible prompt inputs. Routing context is read from ctx.Value(KeySessionID) / ctx.Value(KeyAgentID) / ctx.Value(KeyUserID), not duplicated here.

type PromptSection

type PromptSection struct {
	Name    string
	Content string
}

PromptSection is one section provider contribution before it is folded into the leading system message.

type Runner

type Runner interface {
	// Run starts the process. result is the build graph produced alongside this
	// runner; implementations may wire CommandProvider contributions to
	// commands/registry before serving traffic.
	Run(context.Context, *build.Result) error
	Stop(context.Context) error
}

Runner is the root plugin type. It owns process lifecycle and connects a Platform to a Loop.

type Section

type Section struct {
	Name  string
	Build func(context.Context, PromptRequest) (PromptSection, error)
}

type SectionProvider

type SectionProvider interface {
	Sections() []Section
}

type Session

type Session interface {
	ID() SessionID
	Append(context.Context, SessionEvent) (EventSeq, error)
	Read(context.Context, EventSeq) ([]SessionEvent, error)
	DeriveMessages(context.Context) ([]ModelMessage, error)
}

Session is the durable source of truth for model-visible state.

type SessionEvent

type SessionEvent struct {
	ID        EventID
	Seq       EventSeq
	SessionID SessionID
	AgentID   AgentID
	Type      EventType
	Data      json.RawMessage
	CreatedAt time.Time
	// UserID attributes the event to an end user. It is set on user messages
	// when the platform knows who spoke, and is what makes a session shared by a
	// whole Slack channel legible: without it the model reads one undifferentiated
	// stream of user turns. Empty for single-user transports such as the CLI, and
	// for everything the agent itself produces.
	UserID string
}

type SessionID

type SessionID string

SessionID identifies a conversation unit. Platforms emit a delivery SessionID (finest grain: channel + optional :t:thread + optional :u:user). Runner applies sessionScope to derive the effective SessionID used for Loop locking and session history; outbound replies still use the delivery id.

Delivery examples:

slack:C123ABC
slack:C123ABC:t:1712345678.123456:u:U456
feishu:oc_xxx:om_yyy
cli:default

Loop and Agent treat the effective SessionID as opaque. Only platform plugins decode delivery SessionIDs into IM routing targets.

type SessionStore

type SessionStore interface {
	Get(context.Context, SessionID) (Session, error)
}

SessionStore resolves durable sessions by opaque SessionID. Platform plugins generate SessionID values (cc-connect style: platform:segment:...); agent plugins depend on SessionStore and call Get with ctx.Value(KeySessionID) during RunTurn. Loop only uses SessionID for routing and per-session locking, never SessionStore.Get.

type Tool

type Tool interface {
	Name() string
	Description() string
	InputSchema() JSONSchema
	Call(context.Context, json.RawMessage) (string, error)
}

Tool is the model-visible consumer plugin type.

Call receives only the raw arguments and returns model-visible text. The tool runtime stamps call identity onto a ToolResult before writing to session or sending back to the model.

func First

func First(pack ToolPack) Tool

First returns the only tool in a single-tool pack.

type ToolBuilder

type ToolBuilder[In, Out any] struct {
	// contains filtered or unexported fields
}

func NewTool

func NewTool[In, Out any](name string, handler func(context.Context, In) (Out, error)) *ToolBuilder[In, Out]

NewTool starts building a typed tool plugin. The input schema is inferred from In; any inference error surfaces from Build. Handler output is adapted to model-visible text: string is returned as-is, other values are JSON.

func (*ToolBuilder[In, Out]) Build

func (b *ToolBuilder[In, Out]) Build() (Tool, error)

func (*ToolBuilder[In, Out]) Description

func (b *ToolBuilder[In, Out]) Description(desc string) *ToolBuilder[In, Out]

func (*ToolBuilder[In, Out]) Schema

func (b *ToolBuilder[In, Out]) Schema(schema JSONSchema) *ToolBuilder[In, Out]

Schema replaces the inferred input schema, discarding any inference error.

type ToolCall

type ToolCall struct {
	ID    ToolCallID
	Name  string
	Input json.RawMessage
}

type ToolCallID

type ToolCallID string

type ToolPack

type ToolPack []Tool

ToolPack is one plugin instance that exposes one or more model-visible tools.

func Pack

func Pack(tools ...Tool) ToolPack

Pack returns a ToolPack from individual tools.

type ToolProvider

type ToolProvider interface {
	ListTools(context.Context) ([]Tool, error)
}

ToolProvider supplies tools whose definitions may change between turns. Implementations re-read configuration or rediscover remote tools on each call.

type ToolResult

type ToolResult struct {
	ID      ToolCallID
	Name    string
	Content string
	Audit   map[string]string
}

ToolResult is a tool output bound to a specific call, used by session history, hooks, and LLM wire-up. Audit is populated by the tool runtime (policy deny, timeout, etc.), not by Tool.Call.

func ResultFromCall added in v0.1.2

func ResultFromCall(call ToolCall, output string) ToolResult

ResultFromCall attaches call identity to a tool output.

type ToolRuntime

type ToolRuntime interface {
	Visible(context.Context) ([]ToolSpec, error)
	Execute(context.Context, ToolCall) (ToolResult, error)
}

type ToolSpec

type ToolSpec struct {
	Name        string
	Description string
	InputSchema JSONSchema
}

type TurnInput

type TurnInput struct {
	Message ModelMessage
	Emit    OutboundEmit
}

TurnInput carries one turn's payload. Routing context is available through ctx.Value(KeySessionID), ctx.Value(KeyAgentID), ctx.Value(KeyUserID), and related agentkit keys.

type TurnStopReason

type TurnStopReason string

TurnStopReason explains why the agent reached the end of a turn segment.

const (
	// StopNoToolCalls means the assistant answered without requesting tools.
	StopNoToolCalls TurnStopReason = "no-tool-calls"
	// StopStepLimit means the per-segment step allowance ran out.
	StopStepLimit TurnStopReason = "step-limit"
	// StopBudget means a hard run budget is exhausted; Continue is ignored.
	StopBudget TurnStopReason = "budget"
)

type TurnStopping

type TurnStopping struct {
	Reason   TurnStopReason
	Steps    int
	Segments int
	Budget   BudgetState
	// Messages is the derived history at the stopping point. Read-only for hooks.
	Messages []ModelMessage
	// Continue holds messages that extend the turn. Hooks append to it.
	Continue   []ModelMessage
	Stop       bool
	StopReason string
}

TurnStopping is invoked when the agent is about to end a turn. Hooks may append Continue messages to extend the turn with another segment, or set Stop to force the turn to end. Stop wins over Continue, and the agent ignores Continue when Budget.Exhausted is true: no hook can outrun a hard budget.

type TurnStoppingHook

type TurnStoppingHook interface {
	Hook
	TurnStopping(context.Context, *TurnStopping) error
}

func OnTurnStopping

func OnTurnStopping(fn func(context.Context, *TurnStopping) error) TurnStoppingHook

OnTurnStopping wraps a function as a TurnStoppingHook.

type Usage

type Usage struct {
	InputTokens  int
	OutputTokens int
	TotalTokens  int
}

Directories

Path Synopsis
cap
filesystem
Package filesystem holds shared request/result types and gitignore helpers used by file tools.
Package filesystem holds shared request/result types and gitignore helpers used by file tools.
permission
Package permission is the capability boundary for human-in-the-loop decisions routed through the inbound platform (tool approval, ask_user, etc.).
Package permission is the capability boundary for human-in-the-loop decisions routed through the inbound platform (tool approval, ask_user, etc.).
schedule
Package schedule defines the calendar-scheduling capability: a durable set of cron jobs that schedule/cron fires and a tool can edit.
Package schedule defines the calendar-scheduling capability: a durable set of cron jobs that schedule/cron fires and a tool can edit.
subagent
Package subagent defines the delegation capability: running a scoped child agent and bringing back only its conclusion.
Package subagent defines the delegation capability: running a scoped child agent and bringing back only its conclusion.
telemetry
Package telemetry defines the observability exporter boundary for AgentKit.
Package telemetry defines the observability exporter boundary for AgentKit.
tenant
Package tenant derives the isolation unit a conversation belongs to.
Package tenant derives the isolation unit a conversation belongs to.
cmd
agent command
runtime
helpdoc
Package helpdoc resolves pluginkit kind documentation for slash commands.
Package helpdoc resolves pluginkit kind documentation for slash commands.
llm
platform/headless
Package headless holds the platforms that run without an interactive terminal: platform/worker for one-shot batches and platform/timer for in-process schedules.
Package headless holds the platforms that run without an interactive terminal: platform/worker for one-shot batches and platform/timer for in-process schedules.
subagent
Package subagent runs child agents in-process.
Package subagent runs child agents in-process.
scripts
gen-imports command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL