Documentation
¶
Overview ¶
Package capuchin is the Capuchin agent SDK: define tools and agents in plain Go and run them as durable Temporal workflows. Conversations survive restarts and deploys, and any tool marked NeedsApproval pauses durably until a human approves or denies it.
A minimal agent:
var refund = capuchin.Tool{
Name: "issueRefund",
Input: capuchin.Schema{"orderId": "string", "cents": "int"},
NeedsApproval: true,
Run: func(a capuchin.Args, ctx capuchin.Ctx) (string, error) {
return doRefund(a.String("orderId"), a.Int("cents"))
},
}
var billing = capuchin.Agent{
Name: "billing",
System: "You handle billing disputes.",
Tools: capuchin.Tools{refund},
}
func main() { log.Fatal(capuchin.Serve(billing)) }
Run `capuchin dev` in the project directory to bring up the local stack (embedded Temporal + web UI) and build/run this worker with hot reload; `capuchin chat` talks to the agent.
Index ¶
- Constants
- func ActiveModelLabel() string
- func Serve(agents ...Agent) error
- func StartWorker(c client.Client, agents ...Agent) (worker.Worker, error)
- type Agent
- type AgentConfig
- type AgentState
- type ApprovalPolicy
- type ApproveToolInput
- type ApproveToolResult
- type Args
- type CallModelInput
- type CallModelResult
- type ContentBlock
- type Ctx
- type Event
- type Message
- type PendingApproval
- type Price
- type RunToolInput
- type Schema
- type StartInput
- type Tool
- type ToolDef
- type Tools
- type UserMessageResult
Constants ¶
const DefaultAddress = "127.0.0.1:7233"
DefaultAddress is where `capuchin dev` runs Temporal; Serve dials it unless TEMPORAL_ADDRESS overrides.
const TaskQueue = "capuchin"
TaskQueue is the Temporal task queue every capuchin worker serves.
Variables ¶
This section is empty.
Functions ¶
func ActiveModelLabel ¶
func ActiveModelLabel() string
ActiveModelLabel describes which model adapter the current environment selects — what the `capuchin dev` banner shows.
func Serve ¶
Serve is the agent-project entry point: dial Temporal (TEMPORAL_ADDRESS, or the `capuchin dev` default), serve the given agents, and block until interrupted.
func StartWorker ¶
StartWorker registers the harness workflow and activities for the given agents on a non-blocking worker attached to an existing client. Most programs want Serve; the capuchin CLI uses this to host its embedded demo.
Types ¶
type Agent ¶
type Agent struct {
Name string // how `capuchin chat <name>` addresses it; defaults to "agent" when serving a single agent
System string
Tools Tools
Model string // optional model override, passed through to the adapter (e.g. "claude-opus-4-8")
MaxTurns int // model calls per user message (default 8)
Price Price // marketplace metadata only
}
Agent is tools + a prompt. Everything else — durability, approval gating, metering, replayable history — is inherited from the harness.
type AgentConfig ¶
type AgentConfig struct {
System string `json:"system"`
Tools []ToolDef `json:"tools,omitempty"`
ApprovalPolicy ApprovalPolicy `json:"approvalPolicy"`
Injected map[string]any `json:"injected,omitempty"` // model-hidden per-call context
ConversationID string `json:"conversationId"`
// Model is an opaque pass-through: the workflow copies it into every
// CallModelInput; the adapter interprets it (and supplies a default when empty).
Model string `json:"model,omitempty"`
MaxTurns int `json:"maxTurns,omitempty"` // model calls per user message
ApprovalTimeoutMs int64 `json:"approvalTimeoutMs,omitempty"` // pending-approval abandon bound
}
AgentConfig is the uniform agent input contract: tools + a prompt.
type AgentState ¶
type AgentState struct {
ConversationID string `json:"conversationId"`
Status string `json:"status"` // idle|thinking|awaiting_approval|cancelled|abandoned|max_turns
Messages []Message `json:"messages"`
Events []Event `json:"events"`
TurnSeq int `json:"turnSeq"`
PendingApprovals []PendingApproval `json:"pendingApprovals"`
}
AgentState is the full serializable state — the getState query payload and the workflow return value.
type ApprovalPolicy ¶
ApprovalPolicy decides which tool calls pause for a human:
auto — nothing gates all — every tool call gates allowlist — listed tools run without approval; everything else gates denylist — listed tools gate; everything else runs
type ApproveToolInput ¶
type ApproveToolResult ¶
type ApproveToolResult struct {
Ok bool `json:"ok"`
}
type Args ¶
Args is a tool call's model-provided input, decoded from JSON.
type CallModelInput ¶
type CallModelInput struct {
System string `json:"system"`
Messages []Message `json:"messages"`
Tools []ToolDef `json:"tools,omitempty"`
TurnSeq int `json:"turnSeq"`
ConversationID string `json:"conversationId"`
Model string `json:"model,omitempty"` // pass-through from AgentConfig.Model
}
CallModelInput / CallModelResult — the model activity contract. The harness defines the shape; an adapter (mock, Anthropic, …) implements it.
type CallModelResult ¶
type ContentBlock ¶
type ContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ToolUseID string `json:"toolUseId,omitempty"`
Name string `json:"name,omitempty"` // tool_use: which tool
Input map[string]any `json:"input,omitempty"` // tool_use: model-visible args only
Content string `json:"content,omitempty"` // tool_result payload (or deny reason)
IsError bool `json:"isError,omitempty"` // tool_result: error / denied
}
ContentBlock is one span of a message. Go has no unions, so this is a flat struct; Type picks which fields are meaningful ("text" | "tool_use" | "tool_result").
type Ctx ¶
Ctx is the worker-side context a tool runs with. Injected carries model-hidden per-call values (tenant, credentials) — the model can neither see nor forge them; they arrive through the serving seam, never through Args.
type Event ¶
type Event struct {
Offset int `json:"offset"`
Type string `json:"type"` // turn_start|assistant_message|tool_start|tool_end|approval_required|max_turns_reached
TurnSeq int `json:"turnSeq,omitempty"`
Text string `json:"text,omitempty"`
StopReason string `json:"stopReason,omitempty"`
ToolUseID string `json:"toolUseId,omitempty"`
ToolName string `json:"toolName,omitempty"`
Input map[string]any `json:"input,omitempty"`
IsError bool `json:"isError,omitempty"`
}
Event is one entry in the offset-keyed, replay-identical event log — the resume cursor for clients (the chat REPL polls getEvents(sinceOffset)).
type Message ¶
type Message struct {
Role string `json:"role"`
Content []ContentBlock `json:"content"`
}
Message is one transcript entry. Roles: user | assistant | tool.
type PendingApproval ¶
type PendingApproval struct {
ToolUseID string `json:"toolUseId"`
ToolName string `json:"toolName"`
Input map[string]any `json:"input"`
}
PendingApproval surfaces a paused tool call so a client can prompt the human.
type Price ¶
Price is marketplace listing metadata. Nothing is billed locally; this is recorded when the agent is pushed to a marketplace.
type RunToolInput ¶
type RunToolInput struct {
Name string `json:"name"`
Input map[string]any `json:"input"`
Injected map[string]any `json:"injected,omitempty"`
}
RunToolInput — the tool-dispatch activity contract. Injected params ride here, never in the model-visible Input.
type Schema ¶
Schema declares a tool's input fields. Values are either a JSON type name ("string", "int", "number", "bool") or a full JSON-schema property map for anything richer. All declared fields are required.
type StartInput ¶
type StartInput struct {
Agent string `json:"agent,omitempty"`
ConversationID string `json:"conversationId"`
}
StartInput starts a conversation: which registered agent (empty = the worker's default), plus the conversation id. The workflow resolves the agent's full config through the getAgentConfig activity as its first step, which pins the config in durable history — replay stays deterministic even after the worker's code changes.
type Tool ¶
type Tool struct {
Name string
Description string
Input Schema
NeedsApproval bool
Run func(Args, Ctx) (string, error)
}
Tool is one capability an agent can call. Run executes worker-side as a Temporal activity, so I/O is fine. NeedsApproval gates the call behind a durable human approve/deny pause.
type ToolDef ¶
type ToolDef struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema map[string]any `json:"inputSchema"`
InherentlySafe bool `json:"inherentlySafe,omitempty"`
}
ToolDef is the model-visible tool description plus gating metadata. Handlers are NOT here (functions don't serialize) — they live in the worker's tool registry and are dispatched by name through the runTool activity.
type UserMessageResult ¶
type UserMessageResult struct {
Accepted bool `json:"accepted"`
}
Update payloads/acks.