mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
183 lines
6.4 KiB
HTML
183 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Subagents | Kit</title>
|
|
<meta name="description" content="Multi-agent orchestration with Kit subagents.">
|
|
<link rel="canonical" href="/advanced/subagents">
|
|
<link rel="stylesheet" href="/assets/index-Di_r5hA0.css">
|
|
<script type="module" src="/assets/index-BbQ_p9l4.js"></script>
|
|
<script type="application/ld+json">{"@context":"https://schema.org","@type":"TechArticle","headline":"Subagents","description":"Multi-agent orchestration with Kit subagents.","url":"https://go-kit.dev/advanced/subagents","isPartOf":{"@type":"WebSite","name":"Kit","url":"https://go-kit.dev"}}</script>
|
|
</head>
|
|
<body>
|
|
<div id="tome-root"></div>
|
|
<div data-pagefind-body style="display:none"><h1>Subagents</h1>
|
|
# Subagents
|
|
|
|
Kit supports multi-agent orchestration through both subprocess spawning and in-process subagents.
|
|
|
|
## Subprocess pattern
|
|
|
|
Spawn Kit as a subprocess for isolated agent execution:
|
|
|
|
```bash
|
|
kit "Analyze codebase" \
|
|
--json \
|
|
--no-session \
|
|
--no-extensions \
|
|
--quiet \
|
|
--model anthropic/claude-haiku-latest
|
|
```
|
|
|
|
Key flags for subprocess usage:
|
|
|
|
| Flag | Purpose |
|
|
|------|---------|
|
|
| `--quiet` | Stdout only, no TUI |
|
|
| `--no-session` | Ephemeral, no persistence |
|
|
| `--no-extensions` | Prevent recursive extension loading |
|
|
| `--json` | Machine-readable output |
|
|
| `--system-prompt` | Custom system prompt (string or file path) |
|
|
|
|
Positional arguments are the prompt. `@file` arguments attach file content as context.
|
|
|
|
## Built-in subagent tool
|
|
|
|
Kit includes a built-in `subagent` tool that the LLM can use to delegate tasks to independent child agents:
|
|
|
|
```
|
|
subagent(
|
|
task: "Analyze the test files and summarize coverage",
|
|
model: "anthropic/claude-haiku-latest", // optional
|
|
system_prompt: "You are a test analysis expert.", // optional
|
|
timeout_seconds: 300 // optional, max 1800
|
|
)
|
|
```
|
|
|
|
Subagents run as separate in-process Kit instances with full tool access (except spawning further subagents, to prevent infinite recursion). They can run in parallel.
|
|
|
|
## Extension subagents
|
|
|
|
Extensions can spawn subagents programmatically:
|
|
|
|
```go
|
|
result := ctx.SpawnSubagent(ext.SubagentConfig{
|
|
Task: "Review this code for security issues",
|
|
Model: "anthropic/claude-sonnet-latest",
|
|
SystemPrompt: "You are a security auditor.",
|
|
})
|
|
```
|
|
|
|
### Monitoring subagents from extensions
|
|
|
|
When the LLM (not the extension itself) spawns a subagent using the `subagent` tool, extensions can monitor its activity in real-time using three lifecycle event handlers:
|
|
|
|
```go
|
|
// Track active subagents and display their output
|
|
var subagentWidgets map[string]*SubagentWidget
|
|
|
|
func Init(api ext.API) {
|
|
// Subagent started by the main agent
|
|
api.OnSubagentStart(func(e ext.SubagentStartEvent, ctx ext.Context) {
|
|
// e.ToolCallID — unique ID for this subagent invocation
|
|
// e.Task — the task/prompt sent to the subagent
|
|
widget := NewWidget(e.ToolCallID, e.Task)
|
|
subagentWidgets[e.ToolCallID] = widget
|
|
ctx.SetWidget(widget.Config())
|
|
})
|
|
|
|
// Real-time streaming from subagent
|
|
api.OnSubagentChunk(func(e ext.SubagentChunkEvent, ctx ext.Context) {
|
|
// e.ToolCallID — matches the start event
|
|
// e.ChunkType — "text", "tool_call", "tool_execution_start", "tool_result"
|
|
// e.Content — text content
|
|
// e.ToolName — tool name (for tool chunks)
|
|
// e.IsError — true if tool result failed
|
|
widget := subagentWidgets[e.ToolCallID]
|
|
if widget != nil {
|
|
widget.AddOutput(e)
|
|
ctx.SetWidget(widget.Config())
|
|
}
|
|
})
|
|
|
|
// Subagent completed
|
|
api.OnSubagentEnd(func(e ext.SubagentEndEvent, ctx ext.Context) {
|
|
// e.Response — final response from subagent
|
|
// e.ErrorMsg — error message if subagent failed
|
|
widget := subagentWidgets[e.ToolCallID]
|
|
if widget != nil {
|
|
widget.MarkComplete(e.Response, e.ErrorMsg)
|
|
ctx.SetWidget(widget.Config())
|
|
delete(subagentWidgets, e.ToolCallID)
|
|
}
|
|
})
|
|
}
|
|
```
|
|
|
|
**Event structs:**
|
|
|
|
```go
|
|
type SubagentStartEvent struct {
|
|
ToolCallID string // Unique ID for this subagent invocation
|
|
Task string // The task/prompt sent to subagent
|
|
}
|
|
|
|
type SubagentChunkEvent struct {
|
|
ToolCallID string // Matches SubagentStartEvent.ToolCallID
|
|
Task string // Task description
|
|
ChunkType string // "text", "tool_call", "tool_execution_start", "tool_result"
|
|
Content string // For text chunks
|
|
ToolName string // For tool-related chunks
|
|
IsError bool // For tool_result chunks
|
|
}
|
|
|
|
type SubagentEndEvent struct {
|
|
ToolCallID string // Matches start event
|
|
Task string // Task description
|
|
Response string // Final response from subagent
|
|
ErrorMsg string // Error message if failed
|
|
}
|
|
```
|
|
|
|
This enables building monitoring widgets that display real-time activity from all subagents spawned by the main agent.
|
|
|
|
## Go SDK subagents
|
|
|
|
The SDK provides in-process subagent spawning:
|
|
|
|
```go
|
|
result, err := host.Subagent(ctx, kit.SubagentConfig{
|
|
Task: "Summarize the changes in this PR",
|
|
Model: "anthropic/claude-haiku-latest",
|
|
SystemPrompt: "You are a code reviewer.",
|
|
Timeout: 5 * time.Minute,
|
|
})
|
|
```
|
|
|
|
### Real-time subagent events
|
|
|
|
Use `SubscribeSubagent` to receive real-time events from LLM-initiated subagents (i.e., when the model uses the `subagent` tool). Register inside an `OnToolCall` handler using the tool call ID:
|
|
|
|
```go
|
|
host.OnToolCall(func(e kit.ToolCallEvent) {
|
|
if e.ToolName == "subagent" {
|
|
host.SubscribeSubagent(e.ToolCallID, func(event kit.Event) {
|
|
switch ev := event.(type) {
|
|
case kit.MessageUpdateEvent:
|
|
fmt.Print(ev.Chunk) // streaming text from child
|
|
case kit.ToolCallEvent:
|
|
fmt.Printf("Child calling: %s\n", ev.ToolName)
|
|
case kit.ToolResultEvent:
|
|
fmt.Printf("Child result: %s\n", ev.ToolName)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
```
|
|
|
|
The listener receives the same event types as `Subscribe()` (`ToolCallEvent`, `MessageUpdateEvent`, `ReasoningDeltaEvent`, etc.) but scoped to the child agent's activity. Listeners are cleaned up automatically when the subagent completes.
|
|
|
|
If no listeners are registered for a tool call, no event dispatching overhead is incurred.</div>
|
|
</body>
|
|
</html> |