mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-13 19:20:06 +00:00
153 lines
4.6 KiB
Go
153 lines
4.6 KiB
Go
// Package extensions provides subagent spawning capabilities for Kit extensions.
|
|
package extensions
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Subagent types
|
|
// ---------------------------------------------------------------------------
|
|
// SubagentConfig configures a subagent spawn.
|
|
type SubagentConfig struct {
|
|
// Prompt is the task/instruction for the subagent (required).
|
|
Prompt string
|
|
|
|
// Model overrides the parent's model (e.g. "anthropic/claude-haiku-3-5-20241022").
|
|
// Empty string uses the parent's current model.
|
|
Model string
|
|
|
|
// SystemPrompt provides domain-specific instructions.
|
|
// Empty string uses the default system prompt.
|
|
SystemPrompt string
|
|
|
|
// Timeout limits execution time. Zero means 5 minute default.
|
|
Timeout time.Duration
|
|
|
|
// OnOutput streams stderr output chunks as the subagent runs.
|
|
// Called from a goroutine; must be safe for concurrent use.
|
|
OnOutput func(chunk string)
|
|
|
|
// OnEvent receives real-time events from the subagent's execution:
|
|
// text chunks, tool calls, tool results, reasoning deltas, etc.
|
|
// Called synchronously from the subagent's event loop.
|
|
OnEvent func(SubagentEvent)
|
|
|
|
// OnComplete is called when the subagent finishes (success or error).
|
|
// Called from a goroutine; must be safe for concurrent use.
|
|
OnComplete func(result SubagentResult)
|
|
|
|
// Blocking, when true, makes SpawnSubagent wait for completion and
|
|
// return the result directly. When false (default), spawns in background
|
|
// and returns immediately with a handle.
|
|
Blocking bool
|
|
|
|
// NoSession, when true, runs the subagent without persisting a session
|
|
// file. By default (false), subagent sessions are persisted so they can
|
|
// be loaded for replay/inspection. Set to true for ephemeral tasks
|
|
// where session history is not needed.
|
|
NoSession bool
|
|
|
|
// ParentSessionID links the subagent's session to the parent (optional).
|
|
// When set, the subagent's session header includes a parent reference
|
|
// so viewers can navigate the session tree.
|
|
ParentSessionID string
|
|
}
|
|
|
|
// SubagentEvent carries a real-time event from a running subagent. Extensions
|
|
// use the Type field to determine what happened and read the relevant fields.
|
|
// This is a concrete struct (not an interface) for Yaegi compatibility.
|
|
type SubagentEvent struct {
|
|
// Type identifies the event: "text", "reasoning", "tool_call",
|
|
// "tool_result", "tool_execution_start", "tool_execution_end",
|
|
// "turn_start", "turn_end".
|
|
Type string
|
|
|
|
// Content carries text for "text" and "reasoning" events.
|
|
Content string
|
|
|
|
// ToolCallID is set on tool_call, tool_result, tool_execution_start,
|
|
// and tool_execution_end events.
|
|
ToolCallID string
|
|
// ToolName is set on tool-related events.
|
|
ToolName string
|
|
// ToolKind is set on tool-related events.
|
|
ToolKind string
|
|
// ToolArgs is set on tool_call events (JSON-encoded).
|
|
ToolArgs string
|
|
// ToolResult is set on tool_result events.
|
|
ToolResult string
|
|
// IsError is set on tool_result events.
|
|
IsError bool
|
|
}
|
|
|
|
// SubagentResult contains the outcome of a subagent execution.
|
|
type SubagentResult struct {
|
|
// Response is the subagent's final text response.
|
|
Response string
|
|
|
|
// Error is set if the subagent failed (nil on success).
|
|
Error error
|
|
|
|
// ExitCode is the subprocess exit code (0 = success).
|
|
ExitCode int
|
|
|
|
// Elapsed is the total execution time.
|
|
Elapsed time.Duration
|
|
|
|
// Usage contains token usage if available.
|
|
Usage *SubagentUsage
|
|
|
|
// SessionID is the subagent's session identifier, if available.
|
|
// Populated when the subagent persists its session (requires running
|
|
// without --no-session). Empty for ephemeral sessions.
|
|
SessionID string
|
|
}
|
|
|
|
// SubagentUsage contains token usage from the subagent's run.
|
|
type SubagentUsage struct {
|
|
InputTokens int64
|
|
OutputTokens int64
|
|
}
|
|
|
|
// SubagentHandle provides control over a running subagent.
|
|
type SubagentHandle struct {
|
|
// ID is a unique identifier for this subagent instance.
|
|
ID string
|
|
|
|
proc *os.Process
|
|
done chan struct{}
|
|
result *SubagentResult
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// Kill terminates the subagent process.
|
|
func (h *SubagentHandle) Kill() error {
|
|
h.mu.Lock()
|
|
proc := h.proc
|
|
h.mu.Unlock()
|
|
if proc != nil {
|
|
return proc.Kill()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Wait blocks until the subagent completes and returns the result.
|
|
func (h *SubagentHandle) Wait() SubagentResult {
|
|
<-h.done
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
if h.result != nil {
|
|
return *h.result
|
|
}
|
|
return SubagentResult{Error: fmt.Errorf("subagent completed without result")}
|
|
}
|
|
|
|
// Done returns a channel that closes when the subagent completes.
|
|
func (h *SubagentHandle) Done() <-chan struct{} {
|
|
return h.done
|
|
}
|