aichannel

package
v0.13.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

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

View Source
const (
	AnthropicModelSonnet = "claude-sonnet-4-5-20250929"
	AnthropicModelHaiku  = "claude-haiku-3-5-20241022"
	AnthropicModelOpus   = "claude-opus-4-5-20251101"
)

Default Anthropic models

Variables

View Source
var (
	ErrNotConfigured = errors.New("channel not configured")
	ErrNotAvailable  = errors.New("AI agent not available")
	ErrTimeout       = errors.New("request timed out")
)

Common errors

View Source
var (
	ErrNoAPIKey      = errors.New("API key not configured")
	ErrProviderError = errors.New("provider error")
)

Common errors for providers

View Source
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

func BuildEmbeddedJSONPrompt(instruction string, jsonSchema string) string

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

func BuildEmbeddedJSONSystemPrompt(basePrompt string, jsonSchema string) string

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.

func RunWithAdapter added in v0.7.12

func RunWithAdapter(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (string, error)

RunWithAdapter executes an AI agent using the appropriate adapter.

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 (a *AiderAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)

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

func (*AiderAdapter) StdinData added in v0.7.12

func (a *AiderAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string

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 New

func New() *Channel

New creates a new AI channel.

func NewWithConfig

func NewWithConfig(config Config) *Channel

NewWithConfig creates a new AI channel with the given configuration.

func (*Channel) Config

func (c *Channel) Config() Config

Config returns a copy of the current configuration.

func (*Channel) Configure

func (c *Channel) Configure(config Config)

Configure sets up the channel with the given configuration.

func (*Channel) IsAPIMode

func (c *Channel) IsAPIMode() bool

IsAPIMode returns true if the channel is configured to use API mode.

func (*Channel) IsAvailable

func (c *Channel) IsAvailable() bool

IsAvailable checks if the configured AI agent is available.

func (*Channel) Send

func (c *Channel) Send(ctx context.Context, prompt string, inputContext string) (string, error)

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

func (c *Channel) SupportsJSONOutput() bool

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 (a *ClaudeAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)

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

func (*ClaudeAdapter) StdinData added in v0.7.12

func (a *ClaudeAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string

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

type ContentBlock struct {
	Type string `json:"type"`
	Text string `json:"text,omitempty"`
}

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 (a *CopilotAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)

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

func (*CopilotAdapter) StdinData added in v0.7.12

func (a *CopilotAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string

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 (a *GeminiAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)

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

func (*GeminiAdapter) StdinData added in v0.7.12

func (a *GeminiAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string

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 (a *GenericAdapter) BuildCommand(ctx context.Context, config Config, prompt, inputContext, systemPrompt string) (*exec.Cmd, error)

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

func (*GenericAdapter) StdinData added in v0.7.12

func (a *GenericAdapter) StdinData(config Config, prompt, inputContext, systemPrompt string) string

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.

func ParseStreamJSONReader

func ParseStreamJSONReader(reader io.Reader) (*Response, error)

ParseStreamJSONReader parses stream-json from a reader (for real-time processing).

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL