Documentation
¶
Overview ¶
Package extensions implements a Pi-style in-process extension system for KIT. Extensions are plain Go files loaded at runtime via Yaegi (a Go interpreter). They register event handlers using an API object, enabling tool interception, input transformation, and lifecycle observation — all without recompilation.
Index ¶
- func ExtensionToolsAsFantasy(defs []ToolDef) []fantasy.AgentTool
- func Symbols() interp.Exports
- func WrapToolsWithExtensions(tools []fantasy.AgentTool, runner *Runner) []fantasy.AgentTool
- type API
- func (a *API) OnAgentEnd(handler func(AgentEndEvent, Context))
- func (a *API) OnAgentStart(handler func(AgentStartEvent, Context))
- func (a *API) OnBeforeAgentStart(handler func(BeforeAgentStartEvent, Context) *BeforeAgentStartResult)
- func (a *API) OnInput(handler func(InputEvent, Context) *InputResult)
- func (a *API) OnMessageEnd(handler func(MessageEndEvent, Context))
- func (a *API) OnMessageStart(handler func(MessageStartEvent, Context))
- func (a *API) OnMessageUpdate(handler func(MessageUpdateEvent, Context))
- func (a *API) OnSessionShutdown(handler func(SessionShutdownEvent, Context))
- func (a *API) OnSessionStart(handler func(SessionStartEvent, Context))
- func (a *API) OnToolCall(handler func(ToolCallEvent, Context) *ToolCallResult)
- func (a *API) OnToolExecutionEnd(handler func(ToolExecutionEndEvent, Context))
- func (a *API) OnToolExecutionStart(handler func(ToolExecutionStartEvent, Context))
- func (a *API) OnToolResult(handler func(ToolResultEvent, Context) *ToolResultResult)
- func (a *API) RegisterCommand(cmd CommandDef)
- func (a *API) RegisterTool(tool ToolDef)
- type AgentEndEvent
- type AgentStartEvent
- type BeforeAgentStartEvent
- type BeforeAgentStartResult
- type CommandDef
- type Context
- type Event
- type EventType
- type HandlerFunc
- type InputEvent
- type InputResult
- type LoadedExtension
- type MessageEndEvent
- type MessageStartEvent
- type MessageUpdateEvent
- type PrintBlockOpts
- type Result
- type Runner
- func (r *Runner) Emit(event Event) (Result, error)
- func (r *Runner) Extensions() []LoadedExtension
- func (r *Runner) GetContext() Context
- func (r *Runner) HasHandlers(event EventType) bool
- func (r *Runner) RegisteredCommands() []CommandDef
- func (r *Runner) RegisteredTools() []ToolDef
- func (r *Runner) SetContext(ctx Context)
- type SessionShutdownEvent
- type SessionStartEvent
- type ToolCallEvent
- type ToolCallResult
- type ToolDef
- type ToolExecutionEndEvent
- type ToolExecutionStartEvent
- type ToolResultEvent
- type ToolResultResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtensionToolsAsFantasy ¶
ExtensionToolsAsFantasy converts ToolDef values registered by extensions into fantasy.AgentTool implementations so the LLM can invoke them.
func Symbols ¶
Symbols returns the Yaegi export table that makes KIT's extension API available to interpreted Go code. Extensions import these types as:
import "kit/ext"
IMPORTANT: Only concrete types (structs, constants) are exported. Interfaces (Event, Result) and the HandlerFunc type are NOT exported because Yaegi cannot generate interface wrappers for them. Instead, extensions use event-specific methods like api.OnToolCall() which accept concrete function signatures.
func WrapToolsWithExtensions ¶
WrapToolsWithExtensions wraps each tool so that ToolCall and ToolResult events are emitted through the extension runner before and after execution. This is the Go equivalent of Pi's wrapper.ts pattern.
If the runner has no relevant handlers the original tools are returned unchanged (zero overhead).
Types ¶
type API ¶
type API struct {
// contains filtered or unexported fields
}
API is passed to each extension's Init function. Extensions use it to register typed event handlers, custom tools, and slash commands.
func (*API) OnAgentEnd ¶
func (a *API) OnAgentEnd(handler func(AgentEndEvent, Context))
OnAgentEnd registers a handler for when the agent finishes responding.
func (*API) OnAgentStart ¶
func (a *API) OnAgentStart(handler func(AgentStartEvent, Context))
OnAgentStart registers a handler for when the agent loop begins.
func (*API) OnBeforeAgentStart ¶
func (a *API) OnBeforeAgentStart(handler func(BeforeAgentStartEvent, Context) *BeforeAgentStartResult)
OnBeforeAgentStart registers a handler that fires before the agent loop.
func (*API) OnInput ¶
func (a *API) OnInput(handler func(InputEvent, Context) *InputResult)
OnInput registers a handler that fires when user input is received. Return a non-nil InputResult to transform or handle the input.
func (*API) OnMessageEnd ¶
func (a *API) OnMessageEnd(handler func(MessageEndEvent, Context))
OnMessageEnd registers a handler for when the assistant message is complete.
func (*API) OnMessageStart ¶
func (a *API) OnMessageStart(handler func(MessageStartEvent, Context))
OnMessageStart registers a handler for when an assistant message begins.
func (*API) OnMessageUpdate ¶
func (a *API) OnMessageUpdate(handler func(MessageUpdateEvent, Context))
OnMessageUpdate registers a handler for streaming text chunks.
func (*API) OnSessionShutdown ¶
func (a *API) OnSessionShutdown(handler func(SessionShutdownEvent, Context))
OnSessionShutdown registers a handler for when the application is closing.
func (*API) OnSessionStart ¶
func (a *API) OnSessionStart(handler func(SessionStartEvent, Context))
OnSessionStart registers a handler for when a session is loaded or created.
func (*API) OnToolCall ¶
func (a *API) OnToolCall(handler func(ToolCallEvent, Context) *ToolCallResult)
OnToolCall registers a handler that fires before a tool executes. Return a non-nil ToolCallResult with Block=true to prevent execution.
func (*API) OnToolExecutionEnd ¶
func (a *API) OnToolExecutionEnd(handler func(ToolExecutionEndEvent, Context))
OnToolExecutionEnd registers a handler for tool execution end.
func (*API) OnToolExecutionStart ¶
func (a *API) OnToolExecutionStart(handler func(ToolExecutionStartEvent, Context))
OnToolExecutionStart registers a handler for tool execution start.
func (*API) OnToolResult ¶
func (a *API) OnToolResult(handler func(ToolResultEvent, Context) *ToolResultResult)
OnToolResult registers a handler that fires after tool execution. Return a non-nil ToolResultResult to modify the output.
func (*API) RegisterCommand ¶
func (a *API) RegisterCommand(cmd CommandDef)
RegisterCommand adds a slash command available in interactive mode.
func (*API) RegisterTool ¶
RegisterTool adds a custom tool that the LLM can invoke.
type AgentEndEvent ¶
type AgentEndEvent struct {
Response string
StopReason string // "completed", "cancelled", "error"
}
AgentEndEvent fires when the agent finishes responding.
func (AgentEndEvent) Type ¶
func (e AgentEndEvent) Type() EventType
type AgentStartEvent ¶
type AgentStartEvent struct {
Prompt string
}
AgentStartEvent fires when the agent loop begins.
func (AgentStartEvent) Type ¶
func (e AgentStartEvent) Type() EventType
type BeforeAgentStartEvent ¶
type BeforeAgentStartEvent struct {
Prompt string
}
BeforeAgentStartEvent fires before the agent loop begins.
func (BeforeAgentStartEvent) Type ¶
func (e BeforeAgentStartEvent) Type() EventType
type BeforeAgentStartResult ¶
BeforeAgentStartResult can inject context before the agent runs.
type CommandDef ¶
type CommandDef struct {
Name string
Description string
Execute func(args string, ctx Context) (string, error)
}
CommandDef describes a slash command registered by an extension.
type Context ¶
type Context struct {
SessionID string
CWD string
Model string
Interactive bool
// Print outputs plain text to the user. In interactive mode this
// routes through BubbleTea's scrollback (tea.Println); in
// non-interactive mode it writes to stdout. Extensions must use
// this instead of fmt.Println, which is swallowed by BubbleTea.
Print func(string)
// PrintInfo outputs text as a styled system message block (bordered,
// themed). Use this for informational notices the user should see.
PrintInfo func(string)
// PrintError outputs text as a styled error block (red border, bold).
// Use this for error messages or warnings.
PrintError func(string)
// PrintBlock outputs text as a custom styled block with caller-chosen
// border color and optional subtitle. Example:
//
// ctx.PrintBlock(ext.PrintBlockOpts{
// Text: "Deployment complete!",
// BorderColor: "#a6e3a1",
// Subtitle: "my-extension",
// })
PrintBlock func(PrintBlockOpts)
// SendMessage injects a message into the conversation and triggers a
// new agent turn. If the agent is currently busy the message is queued
// and processed after the current turn completes.
//
// This is safe to call from goroutines. Common pattern:
//
// go func() {
// out, _ := exec.Command("kit", "-p", task).Output()
// ctx.SendMessage("Subagent result:\n" + string(out))
// }()
SendMessage func(string)
}
Context provides runtime information to handlers about the current session.
type Event ¶
type Event interface {
Type() EventType
}
Event is the interface satisfied by all event types internally.
type EventType ¶
type EventType string
EventType identifies a point in KIT's lifecycle where extensions can hook in.
const ( // ToolCall fires before a tool executes. Handlers can block execution. ToolCall EventType = "tool_call" // ToolExecutionStart fires when a tool begins executing. ToolExecutionStart EventType = "tool_execution_start" // ToolExecutionEnd fires when a tool finishes executing. ToolExecutionEnd EventType = "tool_execution_end" // ToolResult fires after a tool executes. Handlers can modify the result. ToolResult EventType = "tool_result" // Input fires when user input is received. Handlers can transform or handle it. Input EventType = "input" // BeforeAgentStart fires before the agent loop begins for a prompt. BeforeAgentStart EventType = "before_agent_start" // AgentStart fires when the agent loop begins processing. AgentStart EventType = "agent_start" // AgentEnd fires when the agent finishes responding. AgentEnd EventType = "agent_end" // MessageStart fires when a new assistant message begins. MessageStart EventType = "message_start" // MessageUpdate fires for each streaming text chunk. MessageUpdate EventType = "message_update" // MessageEnd fires when the assistant message is complete. MessageEnd EventType = "message_end" // SessionStart fires when a session is loaded or created. SessionStart EventType = "session_start" // SessionShutdown fires when the application is closing. SessionShutdown EventType = "session_shutdown" )
func AllEventTypes ¶
func AllEventTypes() []EventType
AllEventTypes returns every supported event type.
type HandlerFunc ¶
HandlerFunc is the internal handler signature used by the runner.
type InputEvent ¶
InputEvent fires when user input is received.
func (InputEvent) Type ¶
func (e InputEvent) Type() EventType
type InputResult ¶
InputResult controls what happens with user input.
Action: "continue" (default), "transform", "handled"
type LoadedExtension ¶
type LoadedExtension struct {
Path string
Handlers map[EventType][]HandlerFunc
Tools []ToolDef
Commands []CommandDef
}
LoadedExtension represents a single extension that has been discovered, loaded, and initialised. It holds the registered handlers and any custom tools or commands the extension provided.
func LoadExtensions ¶
func LoadExtensions(extraPaths []string) ([]LoadedExtension, error)
LoadExtensions discovers and loads extensions from standard locations and any extra paths. Each extension is loaded into its own Yaegi interpreter for isolation. Extensions that fail to load are logged and skipped.
type MessageEndEvent ¶
type MessageEndEvent struct {
Content string
}
MessageEndEvent fires when the assistant message is complete.
func (MessageEndEvent) Type ¶
func (e MessageEndEvent) Type() EventType
type MessageStartEvent ¶
type MessageStartEvent struct{}
MessageStartEvent fires when a new assistant message begins.
func (MessageStartEvent) Type ¶
func (e MessageStartEvent) Type() EventType
type MessageUpdateEvent ¶
type MessageUpdateEvent struct {
Chunk string
}
MessageUpdateEvent fires for each streaming text chunk.
func (MessageUpdateEvent) Type ¶
func (e MessageUpdateEvent) Type() EventType
type PrintBlockOpts ¶
type PrintBlockOpts struct {
// Text is the main content to display.
Text string
// BorderColor is a hex color string (e.g. "#a6e3a1") for the left border.
// Defaults to the theme's system color if empty.
BorderColor string
// Subtitle is optional text shown below the content in muted style
// (e.g. extension name, timestamp). Empty means no subtitle line.
Subtitle string
}
PrintBlockOpts configures a custom styled block for PrintBlock.
type Result ¶
type Result interface {
// contains filtered or unexported methods
}
Result is the interface satisfied by all result types internally.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner manages loaded extensions and dispatches events to their handlers sequentially, mirroring Pi's ExtensionRunner. Handlers execute in extension load order; for cancellable events the first blocking result wins.
func NewRunner ¶
func NewRunner(exts []LoadedExtension) *Runner
NewRunner creates a Runner from a set of loaded extensions.
func (*Runner) Emit ¶
Emit dispatches an event to all matching handlers sequentially. It returns the accumulated result from all handlers, or nil if no handler responded.
For blocking events (ToolCall, Input), the first blocking result short-circuits:
- ToolCallResult{Block: true} stops iteration and returns immediately.
- InputResult{Action: "handled"} stops iteration and returns immediately.
For chainable events (ToolResult), each handler sees the accumulated result from previous handlers. The final merged result is returned.
Panics in handlers are recovered and logged; they do not crash the process.
func (*Runner) Extensions ¶
func (r *Runner) Extensions() []LoadedExtension
Extensions returns the loaded extensions for inspection (e.g. CLI list).
func (*Runner) GetContext ¶
GetContext returns the current runtime context. Thread-safe.
func (*Runner) HasHandlers ¶
HasHandlers returns true if any loaded extension has at least one handler registered for the given event type.
func (*Runner) RegisteredCommands ¶
func (r *Runner) RegisteredCommands() []CommandDef
RegisteredCommands returns all slash commands registered by loaded extensions.
func (*Runner) RegisteredTools ¶
RegisteredTools returns all custom tools registered by loaded extensions.
func (*Runner) SetContext ¶
SetContext updates the runtime context (session ID, model, etc.) that is passed to every handler invocation. Thread-safe.
type SessionShutdownEvent ¶
type SessionShutdownEvent struct{}
SessionShutdownEvent fires when the application is closing.
func (SessionShutdownEvent) Type ¶
func (e SessionShutdownEvent) Type() EventType
type SessionStartEvent ¶
type SessionStartEvent struct {
SessionID string
}
SessionStartEvent fires when a session is loaded or created.
func (SessionStartEvent) Type ¶
func (e SessionStartEvent) Type() EventType
type ToolCallEvent ¶
type ToolCallEvent struct {
ToolName string
ToolCallID string
Input string // JSON-encoded tool parameters
}
ToolCallEvent fires before a tool executes.
func (ToolCallEvent) Type ¶
func (e ToolCallEvent) Type() EventType
type ToolCallResult ¶
ToolCallResult controls whether the tool call proceeds.
type ToolDef ¶
type ToolDef struct {
Name string
Description string
Parameters string // JSON Schema string
Execute func(input string) (string, error)
}
ToolDef describes a custom tool registered by an extension.
type ToolExecutionEndEvent ¶
type ToolExecutionEndEvent struct {
ToolName string
}
ToolExecutionEndEvent fires when a tool finishes executing.
func (ToolExecutionEndEvent) Type ¶
func (e ToolExecutionEndEvent) Type() EventType
type ToolExecutionStartEvent ¶
type ToolExecutionStartEvent struct {
ToolName string
}
ToolExecutionStartEvent fires when a tool begins executing.
func (ToolExecutionStartEvent) Type ¶
func (e ToolExecutionStartEvent) Type() EventType
type ToolResultEvent ¶
ToolResultEvent fires after tool execution with the output.
func (ToolResultEvent) Type ¶
func (e ToolResultEvent) Type() EventType
type ToolResultResult ¶
type ToolResultResult struct {
Content *string // nil = unchanged
IsError *bool // nil = unchanged
}
ToolResultResult can modify the tool's output before it reaches the LLM.