Implements weeks 1-4 of the multi-provider architecture: Week 1 - Foundation: - Add domain models (AgentProvider, AgentRequest, AgentEvent, AgentResult) - Define CodeAgent port interface with Execute, Cancel, Capabilities - Create thread-safe provider registry with first-registered default Week 2 - Claude Code Adapter: - Extract kubectl exec logic into CodeAgent implementation - Parse stream-json output format (init, message, tool_use, result) - Support session continuation via --resume flag Week 3 - OpenCode Adapter: - HTTP/SSE client for opencode serve API - Session management (create, send message, abort) - Event streaming with documented buffer rationale Week 4 - Quality & Polish: - Fix race condition in OpenCode Cancel method - Add AgentRequest.Validate() with ErrPromptRequired, ErrInvalidTimeout - Document DefaultAvailabilityTimeout constants - Add HTTP error context for debugging Also includes: - Work queue system with PostgreSQL adapter - Credential store for infrastructure secrets - Project templates with Woodpecker CI integration - Comprehensive test coverage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
198 lines
5.6 KiB
Go
198 lines
5.6 KiB
Go
// Package domain contains pure domain models with no external dependencies.
|
|
package domain
|
|
|
|
import "time"
|
|
|
|
// AgentProvider identifies which code agent implementation to use.
|
|
type AgentProvider string
|
|
|
|
const (
|
|
// AgentProviderClaudeCode uses Anthropic's Claude Code CLI.
|
|
AgentProviderClaudeCode AgentProvider = "claudecode"
|
|
|
|
// AgentProviderOpenCode uses the open-source OpenCode agent.
|
|
AgentProviderOpenCode AgentProvider = "opencode"
|
|
)
|
|
|
|
// ValidAgentProviders returns all valid agent provider values.
|
|
func ValidAgentProviders() []AgentProvider {
|
|
return []AgentProvider{AgentProviderClaudeCode, AgentProviderOpenCode}
|
|
}
|
|
|
|
// IsValid returns true if the provider is a known valid value.
|
|
func (p AgentProvider) IsValid() bool {
|
|
switch p {
|
|
case AgentProviderClaudeCode, AgentProviderOpenCode:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// String returns the string representation of the provider.
|
|
func (p AgentProvider) String() string {
|
|
return string(p)
|
|
}
|
|
|
|
// ParseAgentProvider converts a string to AgentProvider with validation.
|
|
// Returns empty provider and error if the string is not a valid provider.
|
|
func ParseAgentProvider(s string) (AgentProvider, error) {
|
|
p := AgentProvider(s)
|
|
if !p.IsValid() {
|
|
return "", ErrInvalidAgentProvider
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// AgentRequest contains parameters for executing a code agent command.
|
|
type AgentRequest struct {
|
|
// Prompt is the user's instruction to the agent.
|
|
Prompt string
|
|
|
|
// ProjectID identifies the project context.
|
|
ProjectID ProjectID
|
|
|
|
// SessionID enables conversation continuation. Empty for new sessions.
|
|
SessionID string
|
|
|
|
// AllowedTools specifies which tools the agent may use without prompting.
|
|
// Uses permission rule syntax (e.g., "Bash", "Read", "Bash(git:*)").
|
|
AllowedTools []string
|
|
|
|
// Model specifies which LLM to use. Provider-specific.
|
|
// For Claude Code: ignored (uses Claude).
|
|
// For OpenCode: e.g., "claude-sonnet-4-20250514", "gpt-4o".
|
|
Model string
|
|
|
|
// WorkingDir is the directory context for the agent. Defaults to /workspace.
|
|
WorkingDir string
|
|
|
|
// Timeout is the maximum execution time. Zero means use default.
|
|
Timeout time.Duration
|
|
|
|
// Metadata contains additional provider-specific options.
|
|
Metadata map[string]string
|
|
}
|
|
|
|
// Validate checks the AgentRequest for required fields and valid values.
|
|
// Returns an error describing the validation failure, or nil if valid.
|
|
func (r *AgentRequest) Validate() error {
|
|
if r.Prompt == "" {
|
|
return ErrPromptRequired
|
|
}
|
|
if r.Timeout < 0 {
|
|
return ErrInvalidTimeout
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AgentEventType categorizes events emitted during agent execution.
|
|
type AgentEventType string
|
|
|
|
const (
|
|
// AgentEventOutput is text output from the agent (stdout equivalent).
|
|
AgentEventOutput AgentEventType = "output"
|
|
|
|
// AgentEventToolUse indicates the agent is invoking a tool.
|
|
AgentEventToolUse AgentEventType = "tool_use"
|
|
|
|
// AgentEventToolResult contains the result of a tool invocation.
|
|
AgentEventToolResult AgentEventType = "tool_result"
|
|
|
|
// AgentEventThinking indicates the agent is processing/reasoning.
|
|
AgentEventThinking AgentEventType = "thinking"
|
|
|
|
// AgentEventError indicates an error occurred.
|
|
AgentEventError AgentEventType = "error"
|
|
|
|
// AgentEventComplete indicates execution finished.
|
|
AgentEventComplete AgentEventType = "complete"
|
|
)
|
|
|
|
// AgentEvent represents a single event during agent execution.
|
|
type AgentEvent struct {
|
|
// Type categorizes this event.
|
|
Type AgentEventType
|
|
|
|
// Timestamp when the event occurred.
|
|
Timestamp time.Time
|
|
|
|
// Content is the main payload (text output, tool name, error message).
|
|
Content string
|
|
|
|
// Stream identifies the output stream ("stdout", "stderr", or empty).
|
|
Stream string
|
|
|
|
// ToolName is set for tool_use and tool_result events.
|
|
ToolName string
|
|
|
|
// ToolInput contains the tool invocation arguments (for tool_use).
|
|
ToolInput map[string]any
|
|
|
|
// Metadata contains additional event-specific data.
|
|
Metadata map[string]any
|
|
}
|
|
|
|
// AgentEventHandler is a callback for receiving agent events during execution.
|
|
type AgentEventHandler func(event AgentEvent)
|
|
|
|
// AgentResult contains the outcome of agent execution.
|
|
type AgentResult struct {
|
|
// SessionID identifies this conversation for potential continuation.
|
|
SessionID string
|
|
|
|
// ExitCode is 0 for success, non-zero for failure.
|
|
ExitCode int
|
|
|
|
// DurationMs is the total execution time in milliseconds.
|
|
DurationMs int64
|
|
|
|
// Error contains any execution error (nil on success).
|
|
Error error
|
|
|
|
// TokensUsed tracks token consumption (if available from provider).
|
|
TokensUsed *AgentTokenUsage
|
|
|
|
// FinalOutput contains the agent's final text response (if any).
|
|
FinalOutput string
|
|
}
|
|
|
|
// Success returns true if the agent completed successfully.
|
|
func (r *AgentResult) Success() bool {
|
|
return r.Error == nil && r.ExitCode == 0
|
|
}
|
|
|
|
// AgentTokenUsage tracks token consumption during execution.
|
|
type AgentTokenUsage struct {
|
|
InputTokens int64
|
|
OutputTokens int64
|
|
TotalTokens int64
|
|
}
|
|
|
|
// AgentCapabilities describes what a code agent implementation supports.
|
|
type AgentCapabilities struct {
|
|
// Provider identifies this agent implementation.
|
|
Provider AgentProvider
|
|
|
|
// SupportsSessionContinuation indicates --resume/session support.
|
|
SupportsSessionContinuation bool
|
|
|
|
// SupportsModelSelection indicates the model can be changed.
|
|
SupportsModelSelection bool
|
|
|
|
// SupportsToolControl indicates --allowedTools support.
|
|
SupportsToolControl bool
|
|
|
|
// SupportedModels lists available models (empty if not applicable).
|
|
SupportedModels []string
|
|
|
|
// DefaultModel is used when none is specified.
|
|
DefaultModel string
|
|
|
|
// MaxPromptLength is the maximum prompt size (0 = unlimited).
|
|
MaxPromptLength int
|
|
|
|
// SupportsStreaming indicates real-time output streaming.
|
|
SupportsStreaming bool
|
|
}
|