Documentation
¶
Index ¶
- Constants
- func BoolValue(pb *bool, defaultVal bool) bool
- func InitGlobalProviderFactory()
- func IsPluginRegistered(t ProviderType) bool
- func PtrBool(b bool) *bool
- func RegisterPlugin(p ProviderPlugin)
- func ResolveBinaryPath(cfg ProviderConfig, meta ProviderMeta) (string, error)
- func ValidateProviderConfig(cfg ProviderConfig) error
- func WritePermissionResponse(w io.Writer, behavior PermissionBehavior, message string) error
- type AssistantMessage
- type ClaudeCodeProvider
- func (p *ClaudeCodeProvider) BuildCLIArgs(providerSessionID string, opts *ProviderSessionOptions) []string
- func (p *ClaudeCodeProvider) BuildInputMessage(prompt string, taskInstructions string, _ string) (map[string]any, error)
- func (p *ClaudeCodeProvider) CheckSessionMarker(providerSessionID string) bool
- func (p *ClaudeCodeProvider) CleanupSession(providerSessionID string, workDir string) error
- func (p *ClaudeCodeProvider) DetectTurnEnd(event *ProviderEvent) bool
- func (p *ClaudeCodeProvider) GetMarkerDir() string
- func (p *ClaudeCodeProvider) ParseEvent(line string) ([]*ProviderEvent, error)
- func (p *ClaudeCodeProvider) ValidateBinary() (string, error)
- func (p *ClaudeCodeProvider) VerifySession(providerSessionID string, workDir string) bool
- type ContentBlock
- type DecisionDetail
- type EventMeta
- type EventWithMeta
- type FinishReason
- type HTTPTransport
- func (t *HTTPTransport) Close() error
- func (t *HTTPTransport) Connect(ctx context.Context, cfg TransportConfig) error
- func (t *HTTPTransport) CreateSession(ctx context.Context, title string) (string, error)
- func (t *HTTPTransport) DeleteSession(ctx context.Context, sessionID string) error
- func (t *HTTPTransport) Events() <-chan string
- func (t *HTTPTransport) Health(ctx context.Context) error
- func (t *HTTPTransport) RespondPermission(ctx context.Context, sessionID, permissionID, response string) error
- func (t *HTTPTransport) Send(ctx context.Context, sessionID string, message map[string]any) error
- func (t *HTTPTransport) Stats() TransportStats
- func (t *HTTPTransport) Subscribe() <-chan string
- func (t *HTTPTransport) Unsubscribe(ch <-chan string)
- type HTTPTransportConfig
- type ModelUsageStats
- type OCAssistantMessage
- type OCCacheUsage
- type OCError
- type OCMessage
- type OCPart
- type OCPartState
- type OCPartUpdateProps
- type OCPermissionProps
- type OCSSEEvent
- type OCSession
- type OCSessionErrorProps
- type OCSessionState
- type OCSessionStatusProps
- type OCTimeStamp
- type OCUsage
- type OpenCodeConfig
- type OpenCodeServerProvider
- func (p *OpenCodeServerProvider) BuildCLIArgs(_ string, _ *ProviderSessionOptions) []string
- func (p *OpenCodeServerProvider) BuildInputMessage(prompt, taskInstructions, baseSystemPrompt string) (map[string]any, error)
- func (p *OpenCodeServerProvider) CleanupSession(_ string, _ string) error
- func (p *OpenCodeServerProvider) Close() error
- func (p *OpenCodeServerProvider) Connect(ctx context.Context, cfg TransportConfig) error
- func (p *OpenCodeServerProvider) DetectTurnEnd(e *ProviderEvent) bool
- func (p *OpenCodeServerProvider) Events() <-chan string
- func (p *OpenCodeServerProvider) GetHTTPTransport() Transport
- func (p *OpenCodeServerProvider) ParseEvent(line string) ([]*ProviderEvent, error)
- func (p *OpenCodeServerProvider) ValidateBinary() (string, error)
- type PendingPermissionRequest
- type PermissionBehavior
- type PermissionDeniedDetail
- type PermissionDetail
- type PermissionRequest
- type PermissionResponse
- type PermissionStatus
- type PermissionTool
- type PiAgentEvent
- type PiAgentMessage
- type PiAssistantMessageEvent
- type PiConfig
- type PiContentBlock
- type PiMessageUpdateEvent
- type PiProvider
- func (p *PiProvider) BuildCLIArgs(providerSessionID string, opts *ProviderSessionOptions) []string
- func (p *PiProvider) BuildInputMessage(prompt string, taskInstructions string, _ string) (map[string]any, error)
- func (p *PiProvider) CleanupSession(providerSessionID string, workDir string) error
- func (p *PiProvider) DetectTurnEnd(event *ProviderEvent) bool
- func (p *PiProvider) ParseEvent(line string) ([]*ProviderEvent, error)
- func (p *PiProvider) ValidateBinary() (string, error)
- type PiSessionEvent
- type PiToolExecutionEvent
- type PiUsage
- type PluginMetadataError
- type PromptBuilder
- type Provider
- type ProviderBase
- func (p *ProviderBase) CleanupSession(providerSessionID string, workDir string) error
- func (p *ProviderBase) Metadata() ProviderMeta
- func (p *ProviderBase) Name() string
- func (p *ProviderBase) ValidateBinary() (string, error)
- func (p *ProviderBase) VerifySession(providerSessionID string, workDir string) bool
- type ProviderConfig
- type ProviderContentBlock
- type ProviderCreator
- type ProviderEvent
- type ProviderEventMeta
- type ProviderEventParser
- type ProviderEventType
- type ProviderFactory
- func (f *ProviderFactory) Create(cfg ProviderConfig) (Provider, error)
- func (f *ProviderFactory) CreateDefault(t ProviderType) (Provider, error)
- func (f *ProviderFactory) GetPlugin(t ProviderType) ProviderPlugin
- func (f *ProviderFactory) IsRegistered(t ProviderType) bool
- func (f *ProviderFactory) ListRegistered() []ProviderType
- func (f *ProviderFactory) Register(t ProviderType, creator ProviderCreator)
- type ProviderFeatures
- type ProviderMeta
- type ProviderPlugin
- type ProviderRegistry
- type ProviderSessionOptions
- type ProviderType
- type StreamMessage
- type Transport
- type TransportConfig
- type TransportStats
- type UsageStats
Constants ¶
const ( OCPartText = "text" OCPartReasoning = "reasoning" OCPartTool = "tool" OCPartStepStart = "step-start" OCPartStepFinish = "step-finish" )
OpenCode Part types (from research results).
const ( OCEventMessagePartUpdated = "message.part.updated" OCEventMessageUpdated = "message.updated" OCEventSessionStatus = "session.status" OCEventSessionIdle = "session.idle" OCEventSessionError = "session.error" OCEventPermissionUpdated = "permission.updated" )
SSE Event types from opencode serve.
const ( ToolStatusPending = "pending" ToolStatusRunning = "running" ToolStatusCompleted = "completed" ToolStatusError = "error" )
Tool status constants for type safety
const ( PiEventTypeAgentStart = "agent_start" PiEventTypeAgentEnd = "agent_end" PiEventTypeTurnStart = "turn_start" PiEventTypeTurnEnd = "turn_end" PiEventTypeMessageStart = "message_start" PiEventTypeMessageUpdate = "message_update" PiEventTypeMessageEnd = "message_end" PiEventTypeToolExecutionStart = "tool_execution_start" PiEventTypeToolExecutionUpdate = "tool_execution_update" PiEventTypeToolExecutionEnd = "tool_execution_end" PiEventTypeSession = "session" PiEventTypeAutoCompactionStart = "auto_compaction_start" PiEventTypeAutoCompactionEnd = "auto_compaction_end" PiEventTypeAutoRetryStart = "auto_retry_start" PiEventTypeAutoRetryEnd = "auto_retry_end" )
Pi event types from the JSON output stream. Reference: https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/json.md
const ( PiContentTypeText = "text" PiContentTypeThinking = "thinking" PiContentTypeToolCall = "toolCall" PiContentTypeImage = "image" )
Pi content block types.
Variables ¶
This section is empty.
Functions ¶
func BoolValue ¶ added in v0.23.4
BoolValue returns the value of a bool pointer if not nil, otherwise returns defaultVal.
func InitGlobalProviderFactory ¶
func InitGlobalProviderFactory()
InitGlobalProviderFactory initializes the global provider factory. This is called automatically on first use.
func IsPluginRegistered ¶ added in v0.22.0
func IsPluginRegistered(t ProviderType) bool
IsPluginRegistered checks if a plugin type is registered.
func RegisterPlugin ¶ added in v0.22.0
func RegisterPlugin(p ProviderPlugin)
RegisterPlugin registers a provider plugin with the global registry. This is typically called from an init() function in the plugin package.
Example:
func init() {
provider.RegisterPlugin(&myCustomPlugin{})
}
Plugins registered here are automatically available through the GlobalProviderFactory after initialization.
func ResolveBinaryPath ¶ added in v0.22.0
func ResolveBinaryPath(cfg ProviderConfig, meta ProviderMeta) (string, error)
ResolveBinaryPath resolves the binary path from config or PATH lookup. This is a shared helper for all provider implementations.
func ValidateProviderConfig ¶
func ValidateProviderConfig(cfg ProviderConfig) error
ValidateProviderConfig validates a provider configuration.
func WritePermissionResponse ¶ added in v0.12.0
func WritePermissionResponse(w io.Writer, behavior PermissionBehavior, message string) error
WritePermissionResponse writes a permission response to stdout/stdin. Format: single-line JSON with newline terminator.
Types ¶
type AssistantMessage ¶
type AssistantMessage struct {
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Role string `json:"role,omitempty"`
Content []ContentBlock `json:"content,omitempty"`
}
AssistantMessage represents the structured message emitted by the model.
type ClaudeCodeProvider ¶
type ClaudeCodeProvider struct {
ProviderBase
// contains filtered or unexported fields
}
func NewClaudeCodeProvider ¶
func NewClaudeCodeProvider(cfg ProviderConfig, logger *slog.Logger) (*ClaudeCodeProvider, error)
NewClaudeCodeProvider creates a new Claude Code provider instance.
func (*ClaudeCodeProvider) BuildCLIArgs ¶
func (p *ClaudeCodeProvider) BuildCLIArgs(providerSessionID string, opts *ProviderSessionOptions) []string
BuildCLIArgs constructs Claude Code CLI arguments.
func (*ClaudeCodeProvider) BuildInputMessage ¶
func (p *ClaudeCodeProvider) BuildInputMessage(prompt string, taskInstructions string, _ string) (map[string]any, error)
BuildInputMessage constructs the stream-json input message. baseSystemPrompt is ignored — Claude Code handles it via --append-system-prompt in BuildCLIArgs.
func (*ClaudeCodeProvider) CheckSessionMarker ¶
func (p *ClaudeCodeProvider) CheckSessionMarker(providerSessionID string) bool
CheckSessionMarker checks if a session marker exists for the given ID.
func (*ClaudeCodeProvider) CleanupSession ¶ added in v0.17.0
func (p *ClaudeCodeProvider) CleanupSession(providerSessionID string, workDir string) error
CleanupSession overrides ProviderBase to delete Claude Code's project session file. This is necessary when starting a fresh session to prevent "Session ID is already in use" errors or when executing a /reset command to completely scrub the context.
func (*ClaudeCodeProvider) DetectTurnEnd ¶
func (p *ClaudeCodeProvider) DetectTurnEnd(event *ProviderEvent) bool
DetectTurnEnd checks if the event signals turn completion.
func (*ClaudeCodeProvider) GetMarkerDir ¶
func (p *ClaudeCodeProvider) GetMarkerDir() string
GetMarkerDir returns the session marker directory path.
func (*ClaudeCodeProvider) ParseEvent ¶
func (p *ClaudeCodeProvider) ParseEvent(line string) ([]*ProviderEvent, error)
ParseEvent parses a Claude Code stream-json line into one or more ProviderEvents.
func (*ClaudeCodeProvider) ValidateBinary ¶
func (p *ClaudeCodeProvider) ValidateBinary() (string, error)
ValidateBinary checks if the Claude CLI is available.
func (*ClaudeCodeProvider) VerifySession ¶ added in v0.29.0
func (p *ClaudeCodeProvider) VerifySession(providerSessionID string, workDir string) bool
VerifySession checks if a CLI session data file exists and can be resumed. This prevents "No conversation found with session ID" errors when the marker exists but the CLI session data has been deleted or expired.
type ContentBlock ¶
type ContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Input map[string]any `json:"input,omitempty"`
Content string `json:"content,omitempty"`
IsError bool `json:"is_error,omitempty"`
}
ContentBlock represents an atomic unit of model output.
func (*ContentBlock) GetUnifiedToolID ¶
func (b *ContentBlock) GetUnifiedToolID() string
GetUnifiedToolID returns a tool identifier suitable for matching calls with results.
type DecisionDetail ¶ added in v0.12.0
type DecisionDetail struct {
Type string `json:"type"` // "ask", "allow", "deny"
Reason string `json:"reason,omitempty"`
Options []struct {
Name string `json:"name"`
} `json:"options,omitempty"`
}
DecisionDetail contains the permission decision details.
type EventMeta ¶
type EventMeta struct {
DurationMs int64 `json:"duration_ms,omitempty"`
TotalDurationMs int64 `json:"total_duration_ms,omitempty"`
ToolName string `json:"tool_name,omitempty"`
ToolID string `json:"tool_id,omitempty"`
Status string `json:"status,omitempty"`
ErrorMsg string `json:"error_msg,omitempty"`
InputTokens int32 `json:"input_tokens,omitempty"`
OutputTokens int32 `json:"output_tokens,omitempty"`
CacheWriteTokens int32 `json:"cache_write_tokens,omitempty"`
CacheReadTokens int32 `json:"cache_read_tokens,omitempty"`
InputSummary string `json:"input_summary,omitempty"`
OutputSummary string `json:"output_summary,omitempty"`
FilePath string `json:"file_path,omitempty"`
LineCount int32 `json:"line_count,omitempty"`
Progress int32 `json:"progress,omitempty"`
TotalSteps int32 `json:"total_steps,omitempty"`
CurrentStep int32 `json:"current_step,omitempty"`
}
EventMeta contains detailed metadata for streaming events.
type EventWithMeta ¶
type EventWithMeta struct {
EventType string `json:"event_type"`
EventData string `json:"event_data"`
Meta *EventMeta `json:"meta,omitempty"`
}
EventWithMeta extends the basic event with metadata for observability.
func NewEventWithMeta ¶
func NewEventWithMeta(eventType, eventData string, meta *EventMeta) *EventWithMeta
NewEventWithMeta creates a new EventWithMeta with guaranteed non-nil Meta.
type FinishReason ¶ added in v0.36.0
type FinishReason string
FinishReason represents the reason why a step finished
const ( ReasonMaxTokens FinishReason = "max_tokens" ReasonToolUse FinishReason = "tool_use" ReasonEndTurn FinishReason = "end_turn" )
var ReasonToolCalls FinishReason = "tool_calls"
ReasonToolCalls matches MiniMax API's stop_reason value for tool-use termination. OpenAI-compatible API uses "tool_use"; MiniMax uses "tool_calls".
type HTTPTransport ¶ added in v0.36.0
type HTTPTransport struct {
// contains filtered or unexported fields
}
func NewHTTPTransport ¶ added in v0.36.0
func NewHTTPTransport(cfg HTTPTransportConfig) *HTTPTransport
NewHTTPTransport creates a new HTTPTransport.
func (*HTTPTransport) Close ¶ added in v0.36.0
func (t *HTTPTransport) Close() error
Close stops the SSE goroutine and closes all subscriber channels. It is idempotent and goroutine-safe. On close, stats are logged to aid debugging upstream memory leak issues (opencode #15645).
func (*HTTPTransport) Connect ¶ added in v0.36.0
func (t *HTTPTransport) Connect(ctx context.Context, cfg TransportConfig) error
Connect establishes the SSE connection to the server. It starts a background goroutine that reads SSE events and reconnects on failure.
func (*HTTPTransport) CreateSession ¶ added in v0.36.0
CreateSession creates a new session on the server via POST /session.
func (*HTTPTransport) DeleteSession ¶ added in v0.36.0
func (t *HTTPTransport) DeleteSession(ctx context.Context, sessionID string) error
DeleteSession terminates a session via DELETE /session/:id.
func (*HTTPTransport) Events ¶ added in v0.36.0
func (t *HTTPTransport) Events() <-chan string
Events returns the SSE event channel (deprecated: use Subscribe for fan-out). Kept for backwards compatibility with single-session use cases.
func (*HTTPTransport) Health ¶ added in v0.36.0
func (t *HTTPTransport) Health(ctx context.Context) error
Health checks if the server is reachable via GET /global/health.
func (*HTTPTransport) RespondPermission ¶ added in v0.36.0
func (t *HTTPTransport) RespondPermission(ctx context.Context, sessionID, permissionID, response string) error
RespondPermission sends a permission response via POST /session/:id/permissions/:permID.
func (*HTTPTransport) Send ¶ added in v0.36.0
Send delivers a message to an existing session via POST /session/:id/prompt_async. This is an async endpoint that returns 204 immediately. Responses are delivered via SSE /event stream (see HTTPTransport.Events).
func (*HTTPTransport) Stats ¶ added in v0.36.1
func (t *HTTPTransport) Stats() TransportStats
Stats returns a snapshot of transport health metrics.
func (*HTTPTransport) Subscribe ¶ added in v0.36.0
func (t *HTTPTransport) Subscribe() <-chan string
Subscribe returns a new channel for receiving SSE events. Each subscriber gets its own channel, enabling fan-out to multiple sessions. The caller must call Unsubscribe when done to prevent memory leaks.
func (*HTTPTransport) Unsubscribe ¶ added in v0.36.0
func (t *HTTPTransport) Unsubscribe(ch <-chan string)
Unsubscribe removes a subscriber and closes its channel. Must be called when done with a subscription to prevent memory leaks. Holds mutex through the close to prevent race with streamSSE broadcasting: streamSSE copies the subscriber list while holding the lock, then sends without the lock. By holding the lock through close, we guarantee that streamSSE cannot send on a closed channel (it would have to hold the lock to send, which we hold during close).
type HTTPTransportConfig ¶ added in v0.36.0
type HTTPTransportConfig struct {
Endpoint string
Password string
Logger *slog.Logger
Timeout time.Duration
WorkDir string // Working directory for OpenCode Server context
}
TransportConfig for HTTPTransport.
type ModelUsageStats ¶ added in v0.17.0
type ModelUsageStats struct {
InputTokens int32 `json:"inputTokens"`
OutputTokens int32 `json:"outputTokens"`
CacheReadInputTokens int32 `json:"cacheReadInputTokens"`
CacheCreationInputTokens int32 `json:"cacheCreationInputTokens"`
WebSearchRequests int32 `json:"webSearchRequests"` // WebSearchRequests is the count of tool-level web search operations.
CostUSD float64 `json:"costUSD"`
ContextWindow int32 `json:"contextWindow"` // ContextWindow is the model's total context capacity (tokens). Used for utilization calculation.
MaxOutputTokens int32 `json:"maxOutputTokens"` // MaxOutputTokens is the model's maximum output limit.
}
ModelUsageStats represents the token consumption per model.
type OCAssistantMessage ¶ added in v0.36.0
type OCAssistantMessage struct {
ID string `json:"id,omitempty"`
SessionID string `json:"sessionID,omitempty"`
Role string `json:"role,omitempty"`
ModelID string `json:"modelID,omitempty"`
Cost float64 `json:"cost,omitempty"`
Tokens OCUsage `json:"tokens"`
Finish string `json:"finish,omitempty"`
Error *OCError `json:"error,omitempty"`
}
OCAssistantMessage is the info payload for message.updated events.
type OCCacheUsage ¶ added in v0.36.0
type OCCacheUsage struct {
Read int32 `json:"read,omitempty"`
Write int32 `json:"write,omitempty"`
}
OCCacheUsage represents cache token usage.
type OCError ¶ added in v0.36.0
type OCError struct {
Name string `json:"name"`
Message string `json:"message,omitempty"`
Data map[string]any `json:"data,omitempty"`
}
OCError represents an error from the OpenCode server.
type OCMessage ¶ added in v0.36.0
type OCMessage struct {
ID string `json:"id,omitempty"`
Role string `json:"role,omitempty"`
Parts []OCPart `json:"parts,omitempty"`
Content string `json:"content,omitempty"`
Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
}
OCMessage represents the output message structure from OpenCode.
type OCPart ¶ added in v0.36.0
type OCPart struct {
ID string `json:"id,omitempty"`
Type string `json:"type"`
// text / reasoning
Text string `json:"text,omitempty"`
// tool (v1.3.2+ uses nested state and tool field)
Tool string `json:"tool,omitempty"`
Input map[string]any `json:"input,omitempty"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
State *OCPartState `json:"state,omitempty"`
// step
StepNumber int `json:"step_number,omitempty"`
TotalSteps int `json:"total_steps,omitempty"`
Reason string `json:"reason,omitempty"`
// token usage (SDK field name is "tokens")
Tokens *OCUsage `json:"tokens,omitempty"`
// Legacy compatibility (fallback for older versions)
Status string `json:"status,omitempty"`
Name string `json:"name,omitempty"`
}
OCPart represents a single part in an OpenCode message.
func (*OCPart) GetStatus ¶ added in v0.36.0
GetStatus returns the effective status from nested state (v1.3.2+) or legacy field. Supports backward compatibility with older OpenCode versions.
func (*OCPart) GetToolName ¶ added in v0.36.0
GetToolName returns the effective tool name from Tool field (v1.3.2+) or legacy Name field. Supports backward compatibility with older OpenCode versions.
type OCPartState ¶ added in v0.36.0
type OCPartState struct {
Status string `json:"status,omitempty"` // pending, running, completed, error
}
OCPartState represents the nested state structure in v1.3.2+ tool parts.
type OCPartUpdateProps ¶ added in v0.36.0
OCPartUpdateProps is the properties payload for message.part.updated events.
type OCPermissionProps ¶ added in v0.36.0
type OCPermissionProps struct {
ID string `json:"id"`
Type string `json:"type"`
SessionID string `json:"sessionID,omitempty"`
Title string `json:"title,omitempty"`
}
OCPermissionProps is the properties payload for permission.updated events.
type OCSSEEvent ¶ added in v0.36.0
type OCSSEEvent struct {
Type string `json:"type"`
Properties json.RawMessage `json:"properties,omitempty"`
}
OCSSEEvent is the SSE "data:" payload from opencode serve. Wraps a JSON object with a "type" field and "properties" field.
type OCSession ¶ added in v0.36.0
type OCSession struct {
ID string `json:"id"`
ProjectID string `json:"projectID,omitempty"`
Directory string `json:"directory,omitempty"`
Title string `json:"title"`
Version string `json:"version,omitempty"`
}
OCSession represents an OpenCode server-side session.
type OCSessionErrorProps ¶ added in v0.36.0
type OCSessionErrorProps struct {
Error OCError `json:"error"`
}
OCSessionErrorProps is the properties payload for session.error events.
type OCSessionState ¶ added in v0.36.0
OCSessionState describes the current state of an OpenCode session.
type OCSessionStatusProps ¶ added in v0.36.0
type OCSessionStatusProps struct {
Status OCSessionState `json:"status"`
}
OCSessionStatusProps is the properties payload for session.status events.
type OCTimeStamp ¶ added in v0.36.0
type OCTimeStamp struct {
Created int64 `json:"created,omitempty"`
Updated int64 `json:"updated,omitempty"`
}
OCTimeStamp represents a timestamp from OpenCode.
type OCUsage ¶ added in v0.36.0
type OCUsage struct {
Input int32 `json:"input,omitempty"`
Output int32 `json:"output,omitempty"`
Reasoning int32 `json:"reasoning,omitempty"`
Cache *OCCacheUsage `json:"cache,omitempty"`
}
OCUsage represents token usage information. JSON tags match OpenCode SDK: input, output, reasoning, cache.
type OpenCodeConfig ¶
type OpenCodeConfig struct {
// UseHTTPAPI enables HTTP API mode instead of CLI mode
UseHTTPAPI bool `json:"use_http_api,omitempty" koanf:"use_http_api"`
// Port for HTTP API server
Port int `json:"port,omitempty" koanf:"port"`
// PlanMode enables planning mode
PlanMode bool `json:"plan_mode,omitempty" koanf:"plan_mode"`
// Provider is the LLM provider to use
Provider string `json:"provider,omitempty" koanf:"provider"`
// Model is the model ID
Model string `json:"model,omitempty" koanf:"model"`
// ServerURL is the HTTP endpoint for opencode serve (e.g., "http://127.0.0.1:4096").
// Used by OpenCodeServerProvider (opencode-server type).
ServerURL string `json:"server_url,omitempty" koanf:"server_url"`
// Agent is the opencode serve --agent flag (e.g., "build", "plan").
Agent string `json:"agent,omitempty" koanf:"agent"`
// Password is the Basic Auth password for opencode serve.
Password string `json:"password,omitempty" koanf:"password"`
// WorkDir is the working directory for OpenCode Server context.
// This is passed via x-opencode-directory HTTP header to specify project directory.
WorkDir string `json:"work_dir,omitempty" koanf:"work_dir"`
}
OpenCodeConfig contains OpenCode-specific configuration.
type OpenCodeServerProvider ¶ added in v0.36.0
type OpenCodeServerProvider struct {
ProviderBase
// contains filtered or unexported fields
}
OpenCodeServerProvider implements the Provider interface for OpenCode HTTP API mode. Unlike the CLI-based OpenCodeProvider, this uses HTTP transport to communicate with a running opencode serve instance.
func NewOpenCodeServerProvider ¶ added in v0.36.0
func NewOpenCodeServerProvider(cfg ProviderConfig, logger *slog.Logger) (*OpenCodeServerProvider, error)
NewOpenCodeServerProvider creates a new HTTP-based OpenCode provider.
func (*OpenCodeServerProvider) BuildCLIArgs ¶ added in v0.36.0
func (p *OpenCodeServerProvider) BuildCLIArgs(_ string, _ *ProviderSessionOptions) []string
BuildCLIArgs returns nil for server mode (no CLI subprocess).
func (*OpenCodeServerProvider) BuildInputMessage ¶ added in v0.36.0
func (p *OpenCodeServerProvider) BuildInputMessage(prompt, taskInstructions, baseSystemPrompt string) (map[string]any, error)
BuildInputMessage creates an input message for the OpenCode API. The baseSystemPrompt is injected as the "system" field (per-message system instructions). Pass empty string to skip injection (e.g., resume/hot-multiplexing turns).
func (*OpenCodeServerProvider) CleanupSession ¶ added in v0.36.0
func (p *OpenCodeServerProvider) CleanupSession(_ string, _ string) error
CleanupSession removes session resources.
func (*OpenCodeServerProvider) Close ¶ added in v0.36.0
func (p *OpenCodeServerProvider) Close() error
Close closes the provider and releases resources.
func (*OpenCodeServerProvider) Connect ¶ added in v0.36.0
func (p *OpenCodeServerProvider) Connect(ctx context.Context, cfg TransportConfig) error
Connect establishes connection to the OpenCode server.
func (*OpenCodeServerProvider) DetectTurnEnd ¶ added in v0.36.0
func (p *OpenCodeServerProvider) DetectTurnEnd(e *ProviderEvent) bool
DetectTurnEnd detects if an event indicates the end of a turn. OpenCode Server emits result events in two contexts:
- message.updated with finish: per-step intermediate result (NOT turn end)
- session.idle / session.status(idle): session is truly idle (turn end)
Only session-level idle events indicate the turn is complete. Treating per-step results as turn-end would prematurely finalize the session, leaving the Slack status bar stuck at "✅ 当前任务阶段构建完成".
func (*OpenCodeServerProvider) Events ¶ added in v0.36.0
func (p *OpenCodeServerProvider) Events() <-chan string
Events returns the SSE event channel (deprecated: use Subscribe for fan-out).
func (*OpenCodeServerProvider) GetHTTPTransport ¶ added in v0.36.0
func (p *OpenCodeServerProvider) GetHTTPTransport() Transport
GetHTTPTransport returns the underlying HTTP transport for HTTPSessionStarter. This method is used by the engine to create HTTP-based sessions.
func (*OpenCodeServerProvider) ParseEvent ¶ added in v0.36.0
func (p *OpenCodeServerProvider) ParseEvent(line string) ([]*ProviderEvent, error)
ParseEvent parses an SSE event line into provider events.
func (*OpenCodeServerProvider) ValidateBinary ¶ added in v0.36.0
func (p *OpenCodeServerProvider) ValidateBinary() (string, error)
ValidateBinary checks if the OpenCode server is reachable.
type PendingPermissionRequest ¶ added in v0.12.0
type PendingPermissionRequest struct {
ID string // Unique ID (messageID or generated)
SessionID string // Claude Code session ID
Request *PermissionRequest
ChannelID string // Slack channel ID
MessageTS string // Slack message timestamp for update
UserID string // Slack user who triggered the request
CreatedAt time.Time // When the request was created
ExpiresAt time.Time // When the request expires (timeout)
SlackMessageTS string // TS of the Slack message with buttons
Status PermissionStatus // Current status
}
PendingPermissionRequest tracks a pending permission request waiting for user response.
func (*PendingPermissionRequest) IsExpired ¶ added in v0.12.0
func (p *PendingPermissionRequest) IsExpired() bool
IsExpired returns true if the pending request has expired.
func (*PendingPermissionRequest) TimeUntilExpiry ¶ added in v0.12.0
func (p *PendingPermissionRequest) TimeUntilExpiry() time.Duration
TimeUntilExpiry returns the duration until the request expires.
type PermissionBehavior ¶ added in v0.12.0
type PermissionBehavior string
PermissionBehavior is the user's decision for a permission request.
const ( PermissionBehaviorAllow PermissionBehavior = "allow" PermissionBehaviorDeny PermissionBehavior = "deny" PermissionBehaviorAllowAlways PermissionBehavior = "allow_always" PermissionBehaviorDenyAlways PermissionBehavior = "deny_always" )
type PermissionDeniedDetail ¶ added in v0.31.7
type PermissionDeniedDetail struct {
ToolName string `json:"tool_name"` // Name of the denied tool (e.g., "Edit", "Bash")
ToolUseID string `json:"tool_use_id"` // Unique ID for correlating with tool_use event
ToolInput map[string]any `json:"tool_input,omitempty"` // The tool input that was denied
}
PermissionDeniedDetail represents a tool permission denial in Claude Code's result event. This is embedded in the "result" type event's permission_denials array when the user denies a tool execution request (stop_reason="tool_disallowed").
type PermissionDetail ¶ added in v0.12.0
type PermissionDetail struct {
Name string `json:"name"` // Tool name (e.g., "bash", "Read", "Edit")
Input string `json:"input,omitempty"` // Tool input (e.g., command to execute)
}
PermissionDetail contains the permission details (legacy format). Used when Claude Code requests permission for a specific tool/action.
type PermissionRequest ¶ added in v0.12.0
type PermissionRequest struct {
Type string `json:"type"`
SessionID string `json:"session_id,omitempty"`
MessageID string `json:"message_id,omitempty"`
Decision *DecisionDetail `json:"decision,omitempty"`
Permission *PermissionDetail `json:"permission,omitempty"` // Legacy format
}
PermissionRequest represents a permission request from Claude Code. Format as described in GitHub Issue #39. Note: Claude Code has two permission request formats: 1. Legacy format with "permission" object: {"type":"permission_request","permission":{"name":"bash","input":"cmd"}} 2. Current format with "decision" object: {"type":"permission_request","decision":{"type":"ask","options":[...]}}
func ParsePermissionRequest ¶ added in v0.12.0
func ParsePermissionRequest(data []byte) (*PermissionRequest, error)
ParsePermissionRequest parses a permission request from JSON. It handles both legacy (permission) and current (decision) formats.
func (*PermissionRequest) GetDescription ¶ added in v0.12.0
func (p *PermissionRequest) GetDescription() string
GetDescription returns a human-readable description of the permission request.
func (*PermissionRequest) GetToolAndInput ¶ added in v0.12.0
func (p *PermissionRequest) GetToolAndInput() (tool string, input string)
GetToolAndInput extracts the tool name and input from a permission request. Handles both legacy and current formats.
func (*PermissionRequest) IsLegacy ¶ added in v0.12.0
func (p *PermissionRequest) IsLegacy() bool
IsLegacy returns true if this is a legacy format permission request.
type PermissionResponse ¶ added in v0.12.0
type PermissionResponse struct {
Behavior string `json:"behavior"`
Message string `json:"message,omitempty"`
}
PermissionResponse represents the response sent to Claude Code stdin. Format: {"behavior": "allow"} or {"behavior": "deny", "message": "User rejected"}
type PermissionStatus ¶ added in v0.12.0
type PermissionStatus string
PermissionStatus is the status of a pending permission request.
const ( PermissionStatusPending PermissionStatus = "pending" PermissionStatusAllowed PermissionStatus = "allowed" PermissionStatusDenied PermissionStatus = "denied" PermissionStatusExpired PermissionStatus = "expired" PermissionStatusTimedOut PermissionStatus = "timed_out" )
type PermissionTool ¶ added in v0.12.0
type PermissionTool string
PermissionTool is the type of tool requesting permission.
const ( PermissionToolBash PermissionTool = "Bash" PermissionToolRead PermissionTool = "Read" PermissionToolEdit PermissionTool = "Edit" PermissionToolWrite PermissionTool = "Write" PermissionToolMultiEdit PermissionTool = "MultiEdit" )
type PiAgentEvent ¶ added in v0.21.0
type PiAgentEvent struct {
Type string `json:"type"`
Messages []PiAgentMessage `json:"messages,omitempty"`
Message *PiAgentMessage `json:"message,omitempty"`
}
PiAgentEvent represents agent lifecycle events.
type PiAgentMessage ¶ added in v0.21.0
type PiAgentMessage struct {
Role string `json:"role"`
Content []PiContentBlock `json:"content,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
Provider string `json:"provider,omitempty"`
Model string `json:"model,omitempty"`
API string `json:"api,omitempty"`
Usage *PiUsage `json:"usage,omitempty"`
StopReason string `json:"stopReason,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
}
PiAgentMessage represents a message in the pi event stream.
type PiAssistantMessageEvent ¶ added in v0.21.0
type PiAssistantMessageEvent struct {
Type string `json:"type"`
Delta string `json:"delta,omitempty"`
}
PiAssistantMessageEvent represents message update events.
type PiConfig ¶ added in v0.21.0
type PiConfig struct {
// Provider is the LLM provider to use (anthropic, openai, google, etc.)
Provider string `json:"provider,omitempty" koanf:"provider"`
// Model is the model ID or pattern (supports provider/id format)
Model string `json:"model,omitempty" koanf:"model"`
// Thinking level: off, minimal, low, medium, high, xhigh
Thinking string `json:"thinking,omitempty" koanf:"thinking"`
// UseRPC enables RPC mode for process integration (stdin/stdout)
UseRPC bool `json:"use_rpc,omitempty" koanf:"use_rpc"`
// SessionDir custom session storage directory
SessionDir string `json:"session_dir,omitempty" koanf:"session_dir"`
// NoSession enables ephemeral mode (don't save session)
NoSession bool `json:"no_session,omitempty" koanf:"no_session"`
}
PiConfig contains pi-mono (pi-coding-agent) specific configuration. Pi supports multiple LLM providers through a unified API.
type PiContentBlock ¶ added in v0.21.0
type PiContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Thinking string `json:"thinking,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Arguments map[string]any `json:"arguments,omitempty"`
Data string `json:"data,omitempty"`
MimeType string `json:"mimeType,omitempty"`
}
PiContentBlock represents a content block in a pi message.
type PiMessageUpdateEvent ¶ added in v0.21.0
type PiMessageUpdateEvent struct {
Type string `json:"type"`
Message *PiAgentMessage `json:"message"`
AssistantMessageEvent *PiAssistantMessageEvent `json:"assistantMessageEvent,omitempty"`
}
PiMessageUpdateEvent represents a message_update event.
type PiProvider ¶ added in v0.21.0
type PiProvider struct {
ProviderBase
// contains filtered or unexported fields
}
PiProvider implements the Provider interface for pi-coding-agent CLI. Pi is a minimal terminal coding harness that supports 15+ LLM providers through a unified API. It outputs events in JSON Lines format.
Key features:
- Multi-provider support (Anthropic, OpenAI, Google, etc.)
- JSON mode for structured output
- RPC mode for process integration
- Session management with JSONL storage
func NewPiProvider ¶ added in v0.21.0
func NewPiProvider(cfg ProviderConfig, logger *slog.Logger) (*PiProvider, error)
NewPiProvider creates a new pi provider instance.
func (*PiProvider) BuildCLIArgs ¶ added in v0.21.0
func (p *PiProvider) BuildCLIArgs(providerSessionID string, opts *ProviderSessionOptions) []string
BuildCLIArgs constructs pi CLI arguments.
func (*PiProvider) BuildInputMessage ¶ added in v0.21.0
func (p *PiProvider) BuildInputMessage(prompt string, taskInstructions string, _ string) (map[string]any, error)
BuildInputMessage constructs the input for pi. Note: Pi typically takes the prompt as a CLI argument, not stdin. baseSystemPrompt is ignored — pi does not support per-message system injection.
func (*PiProvider) CleanupSession ¶ added in v0.21.0
func (p *PiProvider) CleanupSession(providerSessionID string, workDir string) error
CleanupSession cleans up pi session files. Pi stores sessions in ~/.pi/agent/sessions/ as JSONL files.
func (*PiProvider) DetectTurnEnd ¶ added in v0.21.0
func (p *PiProvider) DetectTurnEnd(event *ProviderEvent) bool
DetectTurnEnd checks if the event signals turn completion.
func (*PiProvider) ParseEvent ¶ added in v0.21.0
func (p *PiProvider) ParseEvent(line string) ([]*ProviderEvent, error)
ParseEvent parses a pi JSON output line into one or more ProviderEvents.
func (*PiProvider) ValidateBinary ¶ added in v0.21.0
func (p *PiProvider) ValidateBinary() (string, error)
ValidateBinary checks if the pi CLI is available.
type PiSessionEvent ¶ added in v0.21.0
type PiSessionEvent struct {
Type string `json:"type"`
Version int `json:"version"`
ID string `json:"id"`
Timestamp string `json:"timestamp"`
Cwd string `json:"cwd"`
}
PiSessionEvent represents the session header event.
type PiToolExecutionEvent ¶ added in v0.21.0
type PiToolExecutionEvent struct {
Type string `json:"type"`
ToolCallID string `json:"toolCallId"`
ToolName string `json:"toolName"`
Args map[string]any `json:"args,omitempty"`
Result any `json:"result,omitempty"`
PartialResult any `json:"partialResult,omitempty"`
IsError bool `json:"isError,omitempty"`
}
PiToolExecutionEvent represents tool execution events.
type PiUsage ¶ added in v0.21.0
type PiUsage struct {
InputTokens int32 `json:"input_tokens"`
OutputTokens int32 `json:"output_tokens"`
}
PiUsage represents token usage information.
type PluginMetadataError ¶ added in v0.22.0
type PluginMetadataError struct {
Type ProviderType
Message string
}
PluginMetadataError is returned when plugin metadata validation fails.
func (*PluginMetadataError) Error ¶ added in v0.22.0
func (e *PluginMetadataError) Error() string
type PromptBuilder ¶ added in v0.22.0
type PromptBuilder struct {
// contains filtered or unexported fields
}
PromptBuilder helps construct prompts with task instructions. It provides a consistent format across all providers.
func NewPromptBuilder ¶ added in v0.22.0
func NewPromptBuilder(useCDATA bool) *PromptBuilder
NewPromptBuilder creates a new PromptBuilder.
func (*PromptBuilder) Build ¶ added in v0.22.0
func (b *PromptBuilder) Build(prompt, taskInstructions string) string
Build constructs the final prompt with task instructions. If taskInstructions is empty, returns the prompt unchanged.
type Provider ¶
type Provider interface {
// Metadata returns the provider's identity and capabilities.
Metadata() ProviderMeta
// BuildCLIArgs constructs the command-line arguments for starting the CLI process.
// The sessionID is the internal SDK identifier, providerSessionID is the
// provider-specific persistent session identifier (e.g., Claude's --session-id).
BuildCLIArgs(providerSessionID string, opts *ProviderSessionOptions) []string
// BuildInputMessage constructs the stdin message payload for sending user input.
// This handles provider-specific input formatting (e.g., stream-json for Claude).
// The baseSystemPrompt is injected as a system message for providers that support it
// (e.g., OpenCode Server's "system" field). Pass empty string to skip injection.
BuildInputMessage(prompt string, taskInstructions string, baseSystemPrompt string) (map[string]any, error)
// ParseEvent parses a raw output line into one or more normalized ProviderEvents.
// Returns empty slice if the line should be ignored (e.g., system messages).
// Returns an error if parsing fails critically.
ParseEvent(line string) ([]*ProviderEvent, error)
// DetectTurnEnd checks if the event indicates the end of a turn.
// Different providers signal turn completion differently:
// - Claude Code: type="result"
// - OpenCode: step-finish or specific completion marker
DetectTurnEnd(event *ProviderEvent) bool
// ValidateBinary checks if the CLI binary is available and returns its path.
ValidateBinary() (string, error)
// CleanupSession cleans up provider-specific session files from disk (e.g. for /reset).
CleanupSession(providerSessionID string, workDir string) error
// VerifySession checks if a session can be resumed (i.e., session data exists on disk).
// This is called before attempting to resume a session to avoid "No conversation found" errors.
// Returns true if the session exists and can be resumed, false otherwise.
VerifySession(providerSessionID string, workDir string) bool
// Name returns the provider name for logging and identification.
Name() string
}
Provider defines the interface for AI CLI agent providers. Each provider (Claude Code, OpenCode) implements this interface to handle its specific CLI protocol, argument construction, and event parsing.
The interface follows the Strategy Pattern, allowing HotPlex Engine to switch between different AI CLI tools without modifying core logic.
func CreateDefaultProvider ¶
func CreateDefaultProvider(t ProviderType) (Provider, error)
CreateDefaultProvider is a convenience function for creating providers with defaults.
func CreateProvider ¶
func CreateProvider(cfg ProviderConfig) (Provider, error)
CreateProvider is a convenience function that uses the global factory.
type ProviderBase ¶
type ProviderBase struct {
// contains filtered or unexported fields
}
ProviderBase provides common functionality for provider implementations. Embed this struct to reduce boilerplate in concrete providers.
func (*ProviderBase) CleanupSession ¶ added in v0.17.0
func (p *ProviderBase) CleanupSession(providerSessionID string, workDir string) error
CleanupSession provides a default no-op implementation for cleaning up session files. Providers that store session files on disk (like Claude Code) should override this.
func (*ProviderBase) Metadata ¶
func (p *ProviderBase) Metadata() ProviderMeta
Metadata returns the provider metadata.
func (*ProviderBase) ValidateBinary ¶
func (p *ProviderBase) ValidateBinary() (string, error)
ValidateBinary checks if the CLI binary exists and returns its path. It uses BinaryPath from config if set, otherwise looks up the binary in PATH. Returns a helpful error message with install hint if the binary is not found.
func (*ProviderBase) VerifySession ¶ added in v0.29.0
func (p *ProviderBase) VerifySession(providerSessionID string, workDir string) bool
VerifySession provides a default implementation that always returns true. Providers that support session resumption should override this to check if session data exists.
type ProviderConfig ¶
type ProviderConfig struct {
// Type identifies the provider (required)
Type ProviderType `json:"type" yaml:"type" koanf:"type"`
// Enabled controls whether this provider is available
Enabled *bool `json:"enabled" yaml:"enabled" koanf:"enabled"`
// ExplicitDisable explicitly disables the provider, overriding base config's Enabled=true.
// This is needed because bool zero value (false) cannot be distinguished from "not set"
// in config merging. Use this when you want to disable a provider in overlay config.
ExplicitDisable bool `json:"explicit_disable,omitempty" yaml:"explicit_disable,omitempty" koanf:"explicit_disable"`
// BinaryPath overrides the default binary lookup path
BinaryPath string `json:"binary_path,omitempty" yaml:"binary_path,omitempty" koanf:"binary_path"`
// DefaultModel is the default model to use
DefaultModel string `json:"default_model,omitempty" yaml:"default_model,omitempty" koanf:"default_model"`
// DefaultPermissionMode is the default permission mode
DefaultPermissionMode string `json:"default_permission_mode,omitempty" yaml:"default_permission_mode,omitempty" koanf:"default_permission_mode"`
// DangerouslySkipPermissions bypasses all permission checks.
// Equivalent to --permission-mode bypassPermissions but skips permission prompts entirely.
// Recommended only for sandboxes with no internet access.
DangerouslySkipPermissions *bool `` /* 128-byte string literal not displayed */
// AllowedTools restricts available tools (provider-level override)
AllowedTools []string `json:"allowed_tools,omitempty" yaml:"allowed_tools,omitempty" koanf:"allowed_tools"`
// DisallowedTools blocks specific tools (provider-level override)
DisallowedTools []string `json:"disallowed_tools,omitempty" yaml:"disallowed_tools,omitempty" koanf:"disallowed_tools"`
// ExtraArgs are additional CLI arguments
ExtraArgs []string `json:"extra_args,omitempty" yaml:"extra_args,omitempty" koanf:"extra_args"`
// ExtraEnv are additional environment variables
ExtraEnv map[string]string `json:"extra_env,omitempty" yaml:"extra_env,omitempty" koanf:"extra_env"`
// Timeout overrides the default execution timeout
Timeout time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty" koanf:"timeout"`
// OpenCode-specific options
OpenCode *OpenCodeConfig `json:"opencode,omitempty" yaml:"opencode,omitempty" koanf:"opencode"`
// Pi-specific options
Pi *PiConfig `json:"pi,omitempty" yaml:"pi,omitempty" koanf:"pi"`
}
ProviderConfig defines the configuration for a specific provider instance. This is used in the layered configuration system.
func MergeProviderConfigs ¶
func MergeProviderConfigs(base, overlay ProviderConfig) ProviderConfig
MergeProviderConfigs merges multiple provider configurations with precedence. Later configurations override earlier ones for non-zero values.
Note: For boolean fields like Enabled, false cannot override true because false is the zero value. Use ExplicitDisable field in ProviderConfig if you need to explicitly disable a provider in an overlay config.
func (*ProviderConfig) Validate ¶
func (c *ProviderConfig) Validate() error
Validate validates the provider configuration. Returns an error if required fields are missing or invalid.
type ProviderContentBlock ¶
type ProviderContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Input map[string]any `json:"input,omitempty"`
Content string `json:"content,omitempty"`
IsError bool `json:"is_error,omitempty"`
}
ProviderContentBlock represents a structured content block within an event.
type ProviderCreator ¶
type ProviderCreator func(cfg ProviderConfig, logger *slog.Logger) (Provider, error)
ProviderCreator is a function that creates a new Provider instance.
type ProviderEvent ¶
type ProviderEvent struct {
// Type is the normalized event type
Type ProviderEventType `json:"type"`
// RawType is the original type string from the provider (for debugging)
RawType string `json:"raw_type,omitempty"`
// Timestamp of the event
Timestamp time.Time `json:"timestamp,omitempty"`
// SessionID is the provider-specific session identifier
SessionID string `json:"session_id,omitempty"`
// Content contains the main event payload
Content string `json:"content,omitempty"`
// Blocks contains structured content blocks (if applicable)
Blocks []ProviderContentBlock `json:"blocks,omitempty"`
// Tool information (for tool_use and tool_result events)
ToolName string `json:"tool_name,omitempty"`
ToolID string `json:"tool_id,omitempty"`
ToolInput map[string]any `json:"tool_input,omitempty"`
// Status indicates operation status ("running", "success", "error")
Status string `json:"status,omitempty"`
// Error contains error message if applicable
Error string `json:"error,omitempty"`
IsError bool `json:"is_error,omitempty"`
// Metadata contains additional provider-specific information
Metadata *ProviderEventMeta `json:"metadata,omitempty"`
// RawLine preserves the original JSON line for debugging
RawLine string `json:"-"`
}
ProviderEvent represents a normalized event from any AI CLI provider. This unified model allows the HotPlex Engine to handle events consistently regardless of the underlying provider.
func ParseProviderEvent ¶
func ParseProviderEvent(line string) (*ProviderEvent, error)
ParseProviderEvent parses a JSON line into a ProviderEvent. This is a generic parser; providers should implement custom parsing for their specific event formats.
func (*ProviderEvent) GetFirstTextBlock ¶
func (e *ProviderEvent) GetFirstTextBlock() string
GetFirstTextBlock extracts the first text block content from the event.
func (*ProviderEvent) HasToolInfo ¶
func (e *ProviderEvent) HasToolInfo() bool
HasToolInfo returns true if this event contains tool information.
func (*ProviderEvent) IsTerminalEvent ¶
func (e *ProviderEvent) IsTerminalEvent() bool
IsTerminalEvent returns true if this event indicates the turn is complete.
func (*ProviderEvent) ToEventWithMeta ¶
func (e *ProviderEvent) ToEventWithMeta() *EventWithMeta
ToEventWithMeta converts ProviderEvent to the existing EventWithMeta type. This provides backward compatibility with the existing event system.
func (*ProviderEvent) ToJSON ¶
func (e *ProviderEvent) ToJSON() (string, error)
ToJSON returns the JSON representation of the event.
type ProviderEventMeta ¶
type ProviderEventMeta struct {
// Timing information
DurationMs int64 `json:"duration_ms,omitempty"`
TotalDurationMs int64 `json:"total_duration_ms,omitempty"`
// Token usage
InputTokens int32 `json:"input_tokens,omitempty"`
OutputTokens int32 `json:"output_tokens,omitempty"`
CacheWriteTokens int32 `json:"cache_write_tokens,omitempty"`
CacheReadTokens int32 `json:"cache_read_tokens,omitempty"`
// Cost information
TotalCostUSD float64 `json:"total_cost_usd,omitempty"`
// Model information
Model string `json:"model,omitempty"`
ModelName string `json:"model_name,omitempty"` // ModelName is the primary model name from modelUsage (the most active model).
ContextWindow int32 `json:"context_window,omitempty"` // ContextWindow is the model's total context capacity (tokens).
MaxOutputTokens int32 `json:"max_output_tokens,omitempty"` // MaxOutputTokens is the model's maximum output limit.
// Context usage percentage (priority over manual calculation)
ContextUsedPercent *float64 `json:"context_used_percent,omitempty"` // ContextUsedPercent is the direct percentage from provider (e.g., Claude Code provides this).
// Progress tracking
Progress int32 `json:"progress,omitempty"`
TotalSteps int32 `json:"total_steps,omitempty"`
CurrentStep int32 `json:"current_step,omitempty"`
}
ProviderEventMeta contains additional metadata for observability.
type ProviderEventParser ¶
type ProviderEventParser interface {
// Parse converts a raw output line to a normalized ProviderEvent.
Parse(line string) (*ProviderEvent, error)
// IsTurnEnd returns true if the event signals turn completion.
IsTurnEnd(event *ProviderEvent) bool
// ExtractSessionID extracts the provider session ID from an event.
ExtractSessionID(event *ProviderEvent) string
}
ProviderEventParser defines the interface for parsing provider-specific events. Each provider implements this to convert their raw output to normalized events.
type ProviderEventType ¶
type ProviderEventType string
ProviderEventType defines the normalized event types across all providers. These types abstract away provider-specific event names to provide a unified event model for the HotPlex Engine and downstream consumers.
const ( // EventTypeThinking indicates the AI is reasoning or thinking. // Claude Code: type="thinking" or type="status" // OpenCode: Part.Type="reasoning" EventTypeThinking ProviderEventType = "thinking" // EventTypeAnswer indicates text output from the AI. // Claude Code: type="assistant" with text blocks // OpenCode: Part.Type="text" EventTypeAnswer ProviderEventType = "answer" // EventTypeToolUse indicates a tool invocation is starting. // Claude Code: type="tool_use" // OpenCode: Part.Type="tool" EventTypeToolUse ProviderEventType = "tool_use" // EventTypeToolResult indicates a tool execution result. // Claude Code: type="tool_result" // OpenCode: Part.Type="tool" with result content EventTypeToolResult ProviderEventType = "tool_result" // EventTypeError indicates an error occurred. EventTypeError ProviderEventType = "error" // EventTypeResult indicates the turn has completed with final result. // Claude Code: type="result" // OpenCode: step-finish or completion marker EventTypeResult ProviderEventType = "result" // EventTypeSystem indicates a system-level message (often filtered). EventTypeSystem ProviderEventType = "system" // EventTypeUser indicates a user message reflection (often filtered). EventTypeUser ProviderEventType = "user" // EventTypeStepStart indicates a new step/milestone (OpenCode specific). EventTypeStepStart ProviderEventType = "step_start" // EventTypeStepFinish indicates a step/milestone completed (OpenCode specific). EventTypeStepFinish ProviderEventType = "step_finish" // EventTypeRaw indicates unparsed raw output (fallback). EventTypeRaw ProviderEventType = "raw" // EventTypePermissionRequest indicates a permission request from Claude Code. // This event type is used when Claude Code requests user approval for tool execution. // Format: {"type":"permission_request","session_id":"...","permission":{"name":"Bash","input":"..."}} EventTypePermissionRequest ProviderEventType = "permission_request" // EventTypePlanMode indicates Claude is in Plan Mode and generating a plan. // Claude Code: type="thinking" with subtype="plan_generation" // In this mode, Claude analyzes and plans but does not execute any tools. EventTypePlanMode ProviderEventType = "plan_mode" // EventTypeExitPlanMode indicates Claude has completed planning and requests user approval. // Claude Code: type="tool_use" with name="ExitPlanMode" // The plan content is in input.plan field. EventTypeExitPlanMode ProviderEventType = "exit_plan_mode" // EventTypeAskUserQuestion indicates Claude is asking a clarifying question. // Claude Code: type="tool_use" with name="AskUserQuestion" // Note: This feature is primarily for interactive mode; headless mode may not support stdin responses. // HotPlex handles this as a degraded text prompt (user replies via message). EventTypeAskUserQuestion ProviderEventType = "ask_user_question" // EventTypeCommandProgress indicates a slash command is executing with progress updates. // Used by /reset, /dc, and future slash commands to show step-by-step execution status. EventTypeCommandProgress ProviderEventType = "command_progress" // EventTypeCommandComplete indicates a slash command has completed successfully. EventTypeCommandComplete ProviderEventType = "command_complete" // EventTypeSessionStart indicates a new session is starting (cold start). // Sent when user sends first message or CLI needs cold start. EventTypeSessionStart ProviderEventType = "session_start" // EventTypeEngineStarting indicates the engine is starting up. // Sent during CLI cold start when engine is being initialized. EventTypeEngineStarting ProviderEventType = "engine_starting" // EventTypeUserMessageReceived indicates user message has been received. // Sent immediately after user message is received to acknowledge receipt. EventTypeUserMessageReceived ProviderEventType = "user_message_received" // EventTypePermissionDenied indicates a tool permission was denied by user. // Claude Code: type="result" with permission_denials array (stop_reason="tool_disallowed") // This event is emitted when Claude Code tries to execute a tool but the user denies permission. EventTypePermissionDenied ProviderEventType = "permission_denied" )
type ProviderFactory ¶
type ProviderFactory struct {
// contains filtered or unexported fields
}
ProviderFactory creates Provider instances based on configuration. It implements the Factory Pattern to decouple provider creation from usage.
var GlobalProviderFactory *ProviderFactory
GlobalProviderFactory is the default factory instance. It comes pre-registered with built-in providers.
func NewProviderFactory ¶
func NewProviderFactory(logger *slog.Logger) *ProviderFactory
NewProviderFactory creates a new provider factory with default providers registered.
func (*ProviderFactory) Create ¶
func (f *ProviderFactory) Create(cfg ProviderConfig) (Provider, error)
Create creates a new Provider instance based on the configuration.
func (*ProviderFactory) CreateDefault ¶
func (f *ProviderFactory) CreateDefault(t ProviderType) (Provider, error)
CreateDefault creates a Provider with default configuration.
func (*ProviderFactory) GetPlugin ¶ added in v0.22.0
func (f *ProviderFactory) GetPlugin(t ProviderType) ProviderPlugin
GetPlugin retrieves a registered plugin by type. Returns nil if the plugin is not registered.
func (*ProviderFactory) IsRegistered ¶
func (f *ProviderFactory) IsRegistered(t ProviderType) bool
IsRegistered checks if a provider type is registered.
func (*ProviderFactory) ListRegistered ¶
func (f *ProviderFactory) ListRegistered() []ProviderType
ListRegistered returns a list of registered provider types.
func (*ProviderFactory) Register ¶
func (f *ProviderFactory) Register(t ProviderType, creator ProviderCreator)
Register adds a new provider creator to the factory. If a creator for the given type already exists, it will be replaced.
type ProviderFeatures ¶
type ProviderFeatures struct {
SupportsResume bool // Can resume existing sessions (e.g., --resume)
SupportsStreamJSON bool // Supports stream-json input/output format
SupportsSSE bool // Supports Server-Sent Events output
SupportsHTTPAPI bool // Has HTTP API mode
SupportsSessionID bool // Supports explicit session ID assignment
SupportsPermissions bool // Supports permission modes
MultiTurnReady bool // Can handle multiple turns in one session
RequiresInitialPromptAsArg bool // Requires first prompt to be passed via CLI args instead of stdin
}
ProviderFeatures describes the capabilities of a provider.
type ProviderMeta ¶
type ProviderMeta struct {
Type ProviderType // Provider type identifier
DisplayName string // Human-readable name (e.g., "Claude Code")
BinaryName string // CLI binary name (e.g., "claude", "opencode")
InstallHint string // Installation hint (e.g., "npm install -g @anthropic-ai/claude-code")
Version string // CLI version (if available)
Features ProviderFeatures
}
ProviderMeta contains metadata about a provider.
type ProviderPlugin ¶ added in v0.22.0
type ProviderPlugin interface {
// Type returns the unique provider type identifier.
Type() ProviderType
// New creates a new Provider instance with the given configuration.
// The logger may be nil, in which case the default logger should be used.
New(cfg ProviderConfig, logger *slog.Logger) (Provider, error)
// Meta returns the provider's metadata including capabilities.
Meta() ProviderMeta
}
ProviderPlugin defines the interface for provider plugins. Third-party extensions implement this interface to register custom providers without modifying HotPlex core code.
Usage:
// external/aider/provider.go
type aiderPlugin struct{}
func (p *aiderPlugin) Type() ProviderType { return "aider" }
func (p *aiderPlugin) New(cfg ProviderConfig, logger *slog.Logger) (Provider, error) { ... }
func (p *aiderPlugin) Meta() ProviderMeta { ... }
func init() {
provider.RegisterPlugin(&aiderPlugin{})
}
func GetPlugin ¶ added in v0.22.0
func GetPlugin(t ProviderType) ProviderPlugin
GetPlugin retrieves a registered plugin by type. Returns nil if the plugin is not registered.
type ProviderRegistry ¶
type ProviderRegistry struct {
// contains filtered or unexported fields
}
ProviderRegistry maintains a cache of initialized providers. This is useful for reusing provider instances across sessions.
func NewProviderRegistry ¶
func NewProviderRegistry(factory *ProviderFactory, logger *slog.Logger) *ProviderRegistry
NewProviderRegistry creates a new provider registry.
func (*ProviderRegistry) Clear ¶
func (r *ProviderRegistry) Clear()
Clear removes all providers from the cache.
func (*ProviderRegistry) Get ¶
func (r *ProviderRegistry) Get(t ProviderType, cfg ProviderConfig) (Provider, error)
Get retrieves a cached provider or creates a new one.
func (*ProviderRegistry) GetOrCreate ¶
func (r *ProviderRegistry) GetOrCreate(t ProviderType) (Provider, error)
GetOrCreate retrieves a cached provider or creates one with default config.
func (*ProviderRegistry) List ¶
func (r *ProviderRegistry) List() []ProviderType
List returns all cached provider types.
func (*ProviderRegistry) Remove ¶
func (r *ProviderRegistry) Remove(t ProviderType)
Remove removes a provider from the cache.
type ProviderSessionOptions ¶
type ProviderSessionOptions struct {
// Working directory for the CLI process
WorkDir string
// Permission mode (e.g., "bypassPermissions", "acceptEdits", "default")
PermissionMode string
// DangerouslySkipPermissions bypasses all permission checks
DangerouslySkipPermissions bool
// Tool restrictions
AllowedTools []string
DisallowedTools []string
// System prompts
BaseSystemPrompt string // Engine-level foundational prompt
TaskInstructions string // Per-task instructions (persisted per session)
InitialPrompt string // First prompt for cold start (sent as CLI arg if needed)
// Session management
SessionID string // Internal SDK session ID
ProviderSessionID string // Provider-specific persistent session ID
ResumeSession bool // Whether to resume an existing session
// Provider-specific flags
// Claude Code specific
Model string // Model override (e.g., "claude-3-5-sonnet")
// OpenCode specific
PlanMode bool // Use planning mode instead of build mode
Port int // Port for HTTP API mode (if applicable)
}
ProviderSessionOptions configures a provider session. This is the provider-specific subset of session configuration, extracted from the global EngineOptions and per-request Config.
type ProviderType ¶
type ProviderType string
ProviderType defines the type of AI CLI provider.
const ( ProviderTypeClaudeCode ProviderType = "claude-code" ProviderTypeOpenCode ProviderType = "opencode" ProviderTypePi ProviderType = "pi" ProviderTypeOpenCodeServer ProviderType = "opencode-server" )
func ListPlugins ¶ added in v0.22.0
func ListPlugins() []ProviderType
ListPlugins returns all registered plugin types.
func (ProviderType) IsRegistered ¶ added in v0.22.0
func (t ProviderType) IsRegistered() bool
IsRegistered checks if the provider type is registered in the global factory. This is the preferred method for checking provider availability. It checks both built-in providers and registered plugins.
func (ProviderType) Valid ¶
func (t ProviderType) Valid() bool
Valid checks if the provider type is registered in the global factory. This method delegates to IsRegistered for consistency with the plugin system. Deprecated: Use IsRegistered() instead for clearer semantics.
type StreamMessage ¶
type StreamMessage struct {
Message *AssistantMessage `json:"message,omitempty"`
Input map[string]any `json:"input,omitempty"`
Type string `json:"type"`
Timestamp string `json:"timestamp,omitempty"`
SessionID string `json:"session_id,omitempty"`
MessageID string `json:"message_id,omitempty"`
Role string `json:"role,omitempty"`
Name string `json:"name,omitempty"`
Output string `json:"output,omitempty"`
Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
Content []ContentBlock `json:"content,omitempty"`
Duration int `json:"duration,omitempty"` // Claude Code often uses "duration"
DurationMs int `json:"duration_ms,omitempty"` // Some versions/providers use "duration_ms"
Subtype string `json:"subtype,omitempty"`
IsError bool `json:"is_error,omitempty"`
TotalCostUSD float64 `json:"total_cost_usd,omitempty"`
Usage *UsageStats `json:"usage,omitempty"`
Result string `json:"result,omitempty"`
// Permission request fields (Issue #39)
Permission *PermissionDetail `json:"permission,omitempty"`
Decision *DecisionDetail `json:"decision,omitempty"`
ModelUsage map[string]ModelUsageStats `json:"modelUsage,omitempty"`
// PermissionDenials contains tools that were denied by user (Claude Code stop_reason="tool_disallowed")
PermissionDenials []PermissionDeniedDetail `json:"permission_denials,omitempty"`
}
StreamMessage represents a single event in the stream-json format emitted by CLI tools. This is a minimal copy for the provider package to avoid circular dependencies.
func (*StreamMessage) GetContentBlocks ¶
func (m *StreamMessage) GetContentBlocks() []ContentBlock
GetContentBlocks returns the primary content blocks of the message.
type Transport ¶ added in v0.36.0
type Transport interface {
// Connect establishes the connection to the agent server.
// It is called once during transport initialization.
Connect(ctx context.Context, cfg TransportConfig) error
// Send delivers a message to an existing session.
Send(ctx context.Context, sessionID string, message map[string]any) error
// Events returns a channel that emits raw SSE event payloads (JSON strings).
// The channel is closed when the transport is closed.
// Multiple goroutines may read from the channel concurrently.
Events() <-chan string
// CreateSession creates a new session on the server and returns its ID.
CreateSession(ctx context.Context, title string) (string, error)
// DeleteSession terminates a session on the server.
DeleteSession(ctx context.Context, sessionID string) error
// RespondPermission sends a permission response to the server.
RespondPermission(ctx context.Context, sessionID, permissionID, response string) error
// Health checks if the server is reachable.
Health(ctx context.Context) error
// Close releases all resources held by the transport.
// Close is idempotent and goroutine-safe.
Close() error
}
Transport defines the low-level communication interface with an agent backend. It is responsible for HTTP or other network protocol details, exposing a simple request/response interface and an SSE event stream to its callers.
Implementations must be safe for concurrent use by multiple goroutines.
type TransportConfig ¶ added in v0.36.0
type TransportConfig struct {
// Endpoint is the base URL of the agent server (e.g., "http://127.0.0.1:4096").
Endpoint string
// Env contains environment variables to pass to the server.
Env map[string]string
// WorkDir is the working directory for the session.
WorkDir string
// Password is the Basic Auth password for the server.
Password string
}
TransportConfig contains configuration for establishing a transport connection.
type TransportStats ¶ added in v0.36.1
type TransportStats struct {
EventsReceived int64
EventsDropped int64
DroppedBySubscriber int64
ReconnectAttempts int64
ReconnectsSuccess int64
ReconnectsFailed int64
LastHeartbeatTs int64 // Unix timestamp of last heartbeat (0 if none)
HeartbeatTimeout time.Duration
ActiveSubscribers int
Running bool
}
TransportStats holds SSE transport health metrics for monitoring and debugging.
type UsageStats ¶
type UsageStats struct {
InputTokens int32 `json:"input_tokens"`
OutputTokens int32 `json:"output_tokens"`
CacheWriteInputTokens int32 `json:"cache_creation_input_tokens,omitempty"`
CacheReadInputTokens int32 `json:"cache_read_input_tokens,omitempty"`
}
UsageStats represents the token consumption breakdown.