Documentation
¶
Overview ¶
Package aichannel provides an interface for communicating with AI coding agents.
Package aichannel provides an interface for communicating with AI coding agents.
Package aichannel provides an interface for communicating with AI coding agents via CLI.
Package aichannel provides an interface for communicating with AI coding agents.
Package aichannel provides an interface for communicating with AI coding agents.
Package aichannel provides an interface for communicating with AI coding agents via CLI.
JSON Extraction Scenarios ¶
There are two distinct scenarios for extracting JSON from AI responses:
## 1. Claude Code CLI Output Format (extractClaudeCodeJSON)
When using Claude Code CLI with --output-format json, the response is wrapped in a structured JSON envelope:
{"type":"result","result":"<AI's text response>","session_id":"..."}
The AI's actual response is in the "result" field. Use OutputFormatJSON with parseJSONResponse, which internally uses extractClaudeCodeJSON to find the type:"result" object.
Prompt pattern: No special JSON instructions needed - the AI returns plain text, Claude Code wraps it in JSON.
## 2. AI-Embedded JSON in Prose (extractEmbeddedJSON)
When you want the AI to return structured data AS JSON in its text response. Use OutputFormatText and call extractEmbeddedJSON on the result.
Prompt pattern: Explicitly instruct the AI to output JSON:
"Return your response as a JSON object with the following structure:
{\"status\": \"ok|error\", \"items\": [...], \"summary\": \"...\"}"
Or use BuildEmbeddedJSONPrompt helper.
Index ¶
- Constants
- Variables
- func BuildEmbeddedJSONPrompt(instruction string, jsonSchema string) string
- func BuildEmbeddedJSONSystemPrompt(basePrompt string, jsonSchema string) string
- func ExtractLastResponse(output string, format OutputFormat) (string, error)
- func GetAPIKeyForProvider(provider LLMProvider) string
- func IsProviderConfigured(provider LLMProvider) bool
- func RunWithAdapter(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (string, error)
- type AgentAdapter
- type AgentType
- type AiderAdapter
- func (a *AiderAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
- func (a *AiderAdapter) Name() string
- func (a *AiderAdapter) ParseOutput(output string) string
- func (a *AiderAdapter) RequiresPTY() bool
- func (a *AiderAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string
- type AnthropicProvider
- func (p *AnthropicProvider) Complete(ctx context.Context, systemPrompt, userPrompt string) (*Response, error)
- func (p *AnthropicProvider) CompleteWithContext(ctx context.Context, systemPrompt, userPrompt, inputContext string) (*Response, error)
- func (p *AnthropicProvider) IsConfigured() bool
- func (p *AnthropicProvider) Model() string
- func (p *AnthropicProvider) Name() string
- func (p *AnthropicProvider) SetModel(model string)
- type Channel
- func (c *Channel) Config() Config
- func (c *Channel) Configure(config Config)
- func (c *Channel) IsAPIMode() bool
- func (c *Channel) IsAvailable() bool
- func (c *Channel) Send(ctx context.Context, prompt string, inputContext string) (string, error)
- func (c *Channel) SendAndParse(ctx context.Context, prompt string, inputContext string) (*Response, error)
- func (c *Channel) SupportsJSONOutput() bool
- type ClaudeAdapter
- func (a *ClaudeAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
- func (a *ClaudeAdapter) Name() string
- func (a *ClaudeAdapter) ParseOutput(output string) string
- func (a *ClaudeAdapter) RequiresPTY() bool
- func (a *ClaudeAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string
- type Config
- type ContentBlock
- type CopilotAdapter
- func (a *CopilotAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
- func (a *CopilotAdapter) Name() string
- func (a *CopilotAdapter) ParseOutput(output string) string
- func (a *CopilotAdapter) RequiresPTY() bool
- func (a *CopilotAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string
- type GeminiAdapter
- func (a *GeminiAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
- func (a *GeminiAdapter) Name() string
- func (a *GeminiAdapter) ParseOutput(output string) string
- func (a *GeminiAdapter) RequiresPTY() bool
- func (a *GeminiAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string
- type GenericAdapter
- func (a *GenericAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
- func (a *GenericAdapter) Name() string
- func (a *GenericAdapter) ParseOutput(output string) string
- func (a *GenericAdapter) RequiresPTY() bool
- func (a *GenericAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string
- type JSONResponse
- type LLMProvider
- type LangChainConfig
- type LangChainProvider
- func (p *LangChainProvider) Complete(ctx context.Context, systemPrompt, userPrompt string) (*Response, error)
- func (p *LangChainProvider) CompleteWithContext(ctx context.Context, systemPrompt, userPrompt, inputContext string) (*Response, error)
- func (p *LangChainProvider) IsConfigured() bool
- func (p *LangChainProvider) Model() string
- func (p *LangChainProvider) Name() string
- type OutputFormat
- type Provider
- type ProviderConfig
- type ProviderInfo
- type Response
- type StreamJSONMessage
- type StreamMessage
Constants ¶
const ( AnthropicModelSonnet = "claude-sonnet-4-5-20250929" AnthropicModelHaiku = "claude-haiku-3-5-20241022" AnthropicModelOpus = "claude-opus-4-5-20251101" )
Default Anthropic models
Variables ¶
var ( ErrNotConfigured = errors.New("channel not configured") ErrNotAvailable = errors.New("AI agent not available") ErrTimeout = errors.New("request timed out") )
Common errors
var ( ErrNoAPIKey = errors.New("API key not configured") ErrProviderError = errors.New("provider error") )
Common errors for providers
var ErrAgentError = errors.New("agent error")
ErrAgentError is returned when the AI agent reports an error in its response.
Functions ¶
func BuildEmbeddedJSONPrompt ¶ added in v0.7.8
BuildEmbeddedJSONPrompt creates a prompt that instructs the AI to return structured JSON in its text response. Use with OutputFormatText and extractEmbeddedJSON.
Example:
prompt := BuildEmbeddedJSONPrompt(
"Analyze the system status",
`{"status": "ok|error", "issues": ["..."], "summary": "..."}`,
)
func BuildEmbeddedJSONSystemPrompt ¶ added in v0.7.8
BuildEmbeddedJSONSystemPrompt creates a system prompt for API mode that instructs the AI to always return JSON responses.
func ExtractLastResponse ¶
func ExtractLastResponse(output string, format OutputFormat) (string, error)
ExtractLastResponse extracts just the final response text from any format. This is a convenience method for when you only care about the result.
func GetAPIKeyForProvider ¶
func GetAPIKeyForProvider(provider LLMProvider) string
GetAPIKeyForProvider returns the API key for a provider from environment variables.
func IsProviderConfigured ¶
func IsProviderConfigured(provider LLMProvider) bool
IsProviderConfigured checks if a provider has an API key available.
Types ¶
type AgentAdapter ¶ added in v0.7.12
type AgentAdapter interface {
// Name returns the adapter name for logging
Name() string
// BuildCommand constructs the exec.Cmd for invoking the agent.
// It receives the full config, prompt, context, and system prompt.
BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)
// RequiresPTY returns true if this agent needs a pseudo-terminal
RequiresPTY() bool
// StdinData returns any data that should be written to stdin after command starts.
// Returns empty string if all data is passed via command args.
StdinData(config Config, prompt, inputContext, systemPrompt string) string
// ParseOutput processes the raw output from the agent and returns clean text.
ParseOutput(output string) string
}
AgentAdapter defines how to invoke a specific AI agent CLI. Each agent may have different CLI patterns for: - Passing prompts (flags, arguments, stdin) - Passing context (embedded in prompt, stdin, or files) - Passing system prompts (flags or not supported) - Output formats
func GetAdapter ¶ added in v0.7.12
func GetAdapter(agent AgentType) AgentAdapter
GetAdapter returns the appropriate adapter for the given agent type.
type AgentType ¶
type AgentType string
AgentType represents a known AI coding agent.
const ( AgentClaude AgentType = "claude" AgentCopilot AgentType = "copilot" AgentGemini AgentType = "gemini" AgentOpenCode AgentType = "opencode" AgentKimi AgentType = "kimi-cli" AgentAuggie AgentType = "auggie" AgentAider AgentType = "aider" AgentCursor AgentType = "cursor-agent" AgentCustom AgentType = "custom" )
func DetectAvailableAgents ¶
func DetectAvailableAgents() []AgentType
DetectAvailableAgents returns a list of AI agents that are available in PATH.
func GetKnownAgents ¶
func GetKnownAgents() []AgentType
GetKnownAgents returns a list of known AI agent types.
type AiderAdapter ¶ added in v0.7.12
type AiderAdapter struct{}
AiderAdapter handles Aider CLI invocation.
func (*AiderAdapter) BuildCommand ¶ added in v0.7.12
func (*AiderAdapter) Name ¶ added in v0.7.12
func (a *AiderAdapter) Name() string
func (*AiderAdapter) ParseOutput ¶ added in v0.7.12
func (a *AiderAdapter) ParseOutput(output string) string
func (*AiderAdapter) RequiresPTY ¶ added in v0.7.12
func (a *AiderAdapter) RequiresPTY() bool
type AnthropicProvider ¶
type AnthropicProvider struct {
// contains filtered or unexported fields
}
AnthropicProvider implements the Provider interface using the Anthropic API.
func NewAnthropicProvider ¶
func NewAnthropicProvider(config ProviderConfig) *AnthropicProvider
NewAnthropicProvider creates a new Anthropic API provider. If apiKey is empty, it will try environment variables in order: ANTHROPIC_API_KEY, CLAUDE_KEY
func (*AnthropicProvider) Complete ¶
func (p *AnthropicProvider) Complete(ctx context.Context, systemPrompt, userPrompt string) (*Response, error)
Complete sends a prompt and returns the completion.
func (*AnthropicProvider) CompleteWithContext ¶
func (p *AnthropicProvider) CompleteWithContext(ctx context.Context, systemPrompt, userPrompt, inputContext string) (*Response, error)
CompleteWithContext sends a prompt with additional context and returns the completion.
func (*AnthropicProvider) IsConfigured ¶
func (p *AnthropicProvider) IsConfigured() bool
IsConfigured returns true if the provider has an API key.
func (*AnthropicProvider) Model ¶
func (p *AnthropicProvider) Model() string
Model returns the configured model name.
func (*AnthropicProvider) Name ¶
func (p *AnthropicProvider) Name() string
Name returns the provider name.
func (*AnthropicProvider) SetModel ¶
func (p *AnthropicProvider) SetModel(model string)
SetModel updates the model to use.
type Channel ¶
type Channel struct {
// contains filtered or unexported fields
}
Channel represents a communication channel to an AI coding agent.
func NewWithConfig ¶
NewWithConfig creates a new AI channel with the given configuration.
func (*Channel) IsAvailable ¶
IsAvailable checks if the configured AI agent is available.
func (*Channel) Send ¶
Send sends a prompt to the AI agent and returns the response. If context is non-empty, it's passed appropriately based on the agent type.
func (*Channel) SendAndParse ¶
func (c *Channel) SendAndParse(ctx context.Context, prompt string, inputContext string) (*Response, error)
SendAndParse sends a prompt and parses the response based on the configured OutputFormat. This provides a structured response with metadata for JSON/stream-json formats. For agents that don't support JSON output, it falls back to text parsing. For API mode, always returns a structured Response directly from the provider.
If the agent returns an error (is_error: true), this method returns ErrAgentError with the error message. This ensures errors are reported to users rather than being passed to downstream LLM calls.
func (*Channel) SupportsJSONOutput ¶
SupportsJSONOutput returns true if the configured agent supports JSON output format.
type ClaudeAdapter ¶ added in v0.7.12
type ClaudeAdapter struct{}
ClaudeAdapter handles Claude Code CLI invocation. Claude CLI uses: - `-p <prompt>` for non-interactive mode (prompt includes context) - `--system-prompt <prompt>` for custom system prompt - `--model <model>` for model selection - `--output-format <format>` for structured output - Does NOT read from stdin in -p mode
func (*ClaudeAdapter) BuildCommand ¶ added in v0.7.12
func (*ClaudeAdapter) Name ¶ added in v0.7.12
func (a *ClaudeAdapter) Name() string
func (*ClaudeAdapter) ParseOutput ¶ added in v0.7.12
func (a *ClaudeAdapter) ParseOutput(output string) string
func (*ClaudeAdapter) RequiresPTY ¶ added in v0.7.12
func (a *ClaudeAdapter) RequiresPTY() bool
type Config ¶
type Config struct {
// Agent is the type of AI agent to use
Agent AgentType `json:"agent"`
// Command is the executable command (defaults based on agent type)
Command string `json:"command,omitempty"`
// Args are additional arguments to pass to the command
Args []string `json:"args,omitempty"`
// NonInteractiveFlag is the flag to use for non-interactive mode (e.g., "-p")
NonInteractiveFlag string `json:"non_interactive_flag,omitempty"`
// QuietFlag suppresses progress output (e.g., "-s" for copilot, "-q" for gemini)
QuietFlag string `json:"quiet_flag,omitempty"`
// OutputFormat specifies desired output format ("text", "json", "stream-json")
// Note: Not all agents support all formats. Use SupportsJSONOutput() to check.
OutputFormat string `json:"output_format,omitempty"`
// OutputFormatFlag is the CLI flag for output format (e.g., "--output-format")
// Set automatically based on agent type.
OutputFormatFlag string `json:"output_format_flag,omitempty"`
// SupportsJSON indicates if this agent supports structured JSON output
SupportsJSON bool `json:"supports_json,omitempty"`
// UseStdin determines if context should be piped via stdin
UseStdin bool `json:"use_stdin"`
// UsePTY runs the command in a pseudo-terminal (required for some CLI tools)
UsePTY bool `json:"use_pty"`
// Timeout for the request (default 2 minutes)
Timeout time.Duration `json:"timeout,omitempty"`
// Environment variables to set
Env map[string]string `json:"env,omitempty"`
// UseAPI enables API mode instead of CLI mode.
// When true, uses the Provider interface instead of executing CLI commands.
UseAPI bool `json:"use_api,omitempty"`
// LLMProvider specifies which LLM provider to use in API mode.
// If empty, auto-detects based on available API keys.
LLMProvider LLMProvider `json:"llm_provider,omitempty"`
// APIKey is the authentication key for API-based providers.
// If empty, uses environment variables based on provider.
APIKey string `json:"api_key,omitempty"`
// Model specifies the model to use.
// For CLI mode (e.g., Claude Code): passed via --model flag. Defaults to "haiku".
// For API mode: uses the provider's default model if empty.
Model string `json:"model,omitempty"`
// MaxTokens limits API response length (default 1024).
MaxTokens int `json:"max_tokens,omitempty"`
// SystemPrompt provides context/instructions for API-based completions.
SystemPrompt string `json:"system_prompt,omitempty"`
}
Config holds the configuration for an AI channel.
type ContentBlock ¶
ContentBlock represents a content block in a message.
type CopilotAdapter ¶ added in v0.7.12
type CopilotAdapter struct{}
CopilotAdapter handles GitHub Copilot CLI invocation.
func (*CopilotAdapter) BuildCommand ¶ added in v0.7.12
func (*CopilotAdapter) Name ¶ added in v0.7.12
func (a *CopilotAdapter) Name() string
func (*CopilotAdapter) ParseOutput ¶ added in v0.7.12
func (a *CopilotAdapter) ParseOutput(output string) string
func (*CopilotAdapter) RequiresPTY ¶ added in v0.7.12
func (a *CopilotAdapter) RequiresPTY() bool
type GeminiAdapter ¶ added in v0.7.12
type GeminiAdapter struct{}
GeminiAdapter handles Google Gemini CLI invocation.
func (*GeminiAdapter) BuildCommand ¶ added in v0.7.12
func (*GeminiAdapter) Name ¶ added in v0.7.12
func (a *GeminiAdapter) Name() string
func (*GeminiAdapter) ParseOutput ¶ added in v0.7.12
func (a *GeminiAdapter) ParseOutput(output string) string
func (*GeminiAdapter) RequiresPTY ¶ added in v0.7.12
func (a *GeminiAdapter) RequiresPTY() bool
type GenericAdapter ¶ added in v0.7.12
type GenericAdapter struct {
// contains filtered or unexported fields
}
GenericAdapter provides a fallback for unknown agents. It uses stdin for context if UseStdin is configured.
func (*GenericAdapter) BuildCommand ¶ added in v0.7.12
func (*GenericAdapter) Name ¶ added in v0.7.12
func (a *GenericAdapter) Name() string
func (*GenericAdapter) ParseOutput ¶ added in v0.7.12
func (a *GenericAdapter) ParseOutput(output string) string
func (*GenericAdapter) RequiresPTY ¶ added in v0.7.12
func (a *GenericAdapter) RequiresPTY() bool
type JSONResponse ¶
type JSONResponse struct {
Type string `json:"type"`
Subtype string `json:"subtype"`
TotalCostUSD float64 `json:"total_cost_usd"`
IsError bool `json:"is_error"`
DurationMS int64 `json:"duration_ms"`
DurationAPIMS int64 `json:"duration_api_ms"`
NumTurns int `json:"num_turns"`
Result string `json:"result"`
SessionID string `json:"session_id"`
}
JSONResponse is the structure returned by --output-format json.
type LLMProvider ¶
type LLMProvider string
LLMProvider represents a supported LLM provider type.
const ( ProviderOpenAI LLMProvider = "openai" ProviderAnthropic LLMProvider = "anthropic" ProviderGoogle LLMProvider = "google" ProviderMistral LLMProvider = "mistral" ProviderDeepSeek LLMProvider = "deepseek" ProviderOpenRouter LLMProvider = "openrouter" ProviderTogether LLMProvider = "together" ProviderHyperbolic LLMProvider = "hyperbolic" ProviderReplicate LLMProvider = "replicate" ProviderSambaNova LLMProvider = "sambanova" ProviderGLM LLMProvider = "glm" )
func GetAvailableProviders ¶
func GetAvailableProviders() []LLMProvider
GetAvailableProviders returns a list of providers that have API keys configured.
func GetDefaultProvider ¶
func GetDefaultProvider() LLMProvider
GetDefaultProvider returns the first available provider (preference order).
type LangChainConfig ¶
type LangChainConfig struct {
// Provider is the LLM provider to use
Provider LLMProvider
// APIKey overrides environment variable lookup
APIKey string
// Model overrides the default model
Model string
// MaxTokens limits response length
MaxTokens int
}
LangChainConfig configures a LangChain provider.
type LangChainProvider ¶
type LangChainProvider struct {
// contains filtered or unexported fields
}
LangChainProvider implements the Provider interface using langchaingo.
func NewLangChainProvider ¶
func NewLangChainProvider(config LangChainConfig) (*LangChainProvider, error)
NewLangChainProvider creates a new LangChain-based provider.
func (*LangChainProvider) Complete ¶
func (p *LangChainProvider) Complete(ctx context.Context, systemPrompt, userPrompt string) (*Response, error)
Complete sends a prompt and returns the completion.
func (*LangChainProvider) CompleteWithContext ¶
func (p *LangChainProvider) CompleteWithContext(ctx context.Context, systemPrompt, userPrompt, inputContext string) (*Response, error)
CompleteWithContext sends a prompt with additional context and returns the completion.
func (*LangChainProvider) IsConfigured ¶
func (p *LangChainProvider) IsConfigured() bool
IsConfigured returns true if the provider has an API key.
func (*LangChainProvider) Model ¶
func (p *LangChainProvider) Model() string
Model returns the configured model name.
func (*LangChainProvider) Name ¶
func (p *LangChainProvider) Name() string
Name returns the provider name.
type OutputFormat ¶
type OutputFormat string
OutputFormat represents the format of CLI output.
const ( OutputFormatText OutputFormat = "text" OutputFormatJSON OutputFormat = "json" OutputFormatStreamJSON OutputFormat = "stream-json" )
type Provider ¶
type Provider interface {
// Name returns the provider name (e.g., "anthropic", "openai")
Name() string
// Complete sends a prompt and returns the completion.
// The systemPrompt provides context/instructions, userPrompt is the actual query.
Complete(ctx context.Context, systemPrompt, userPrompt string) (*Response, error)
// CompleteWithContext is like Complete but allows passing additional context via stdin-like input.
CompleteWithContext(ctx context.Context, systemPrompt, userPrompt, inputContext string) (*Response, error)
// IsConfigured returns true if the provider has necessary credentials.
IsConfigured() bool
}
Provider represents an LLM provider that can generate completions.
type ProviderConfig ¶
type ProviderConfig struct {
// APIKey is the authentication key for the provider
APIKey string `json:"api_key,omitempty"`
// Model is the model to use (e.g., "claude-sonnet-4-5-20250929")
Model string `json:"model,omitempty"`
// MaxTokens limits the response length
MaxTokens int `json:"max_tokens,omitempty"`
// Temperature controls randomness (0.0-1.0)
Temperature float64 `json:"temperature,omitempty"`
// BaseURL overrides the default API endpoint (for proxies/self-hosted)
BaseURL string `json:"base_url,omitempty"`
}
ProviderConfig holds common configuration for API-based providers.
func DefaultProviderConfig ¶
func DefaultProviderConfig() ProviderConfig
DefaultProviderConfig returns sensible defaults for provider configuration.
type ProviderInfo ¶
type ProviderInfo struct {
// EnvKeys are environment variable names to check for API key (in order)
EnvKeys []string
// BaseURL for OpenAI-compatible providers
BaseURL string
// DefaultModel is the default model to use
DefaultModel string
// IsOpenAICompatible indicates if this uses the OpenAI API format
IsOpenAICompatible bool
}
ProviderInfo contains configuration for a provider.
type Response ¶
type Response struct {
// Result is the final text response from the agent
Result string `json:"result"`
// SessionID uniquely identifies the conversation session
SessionID string `json:"session_id,omitempty"`
// TotalCostUSD is the API cost for Claude-based agents
TotalCostUSD float64 `json:"total_cost_usd,omitempty"`
// DurationMS is the total elapsed time in milliseconds
DurationMS int64 `json:"duration_ms,omitempty"`
// DurationAPIMS is the time spent calling the API
DurationAPIMS int64 `json:"duration_api_ms,omitempty"`
// NumTurns is the number of conversation turns
NumTurns int `json:"num_turns,omitempty"`
// IsError indicates if the response represents an error
IsError bool `json:"is_error,omitempty"`
// Subtype is the result type (success/error) for JSON formats
Subtype string `json:"subtype,omitempty"`
}
Response represents the parsed response from an AI agent.
func ParseResponse ¶
func ParseResponse(output string, format OutputFormat) (*Response, error)
ParseResponse parses the raw output from an AI agent based on the output format.
type StreamJSONMessage ¶
type StreamJSONMessage struct {
Type string `json:"type"`
Subtype string `json:"subtype,omitempty"`
SessionID string `json:"session_id,omitempty"`
Message *StreamMessage `json:"message,omitempty"`
// Result fields for type=="result"
TotalCostUSD float64 `json:"total_cost_usd,omitempty"`
DurationMS int64 `json:"duration_ms,omitempty"`
DurationAPIMS int64 `json:"duration_api_ms,omitempty"`
NumTurns int `json:"num_turns,omitempty"`
Result string `json:"result,omitempty"`
IsError bool `json:"is_error,omitempty"`
}
StreamJSONMessage is a single message in stream-json format.
type StreamMessage ¶
type StreamMessage struct {
Role string `json:"role"`
Content []ContentBlock `json:"content"`
}
StreamMessage represents a message in stream-json output.