Add a reusable Go agent package (server/pkg/agent/) that provides a unified Backend interface for executing prompts via either Claude Code or Codex. The daemon now auto-detects which CLIs are available at startup, registers a runtime for each, and routes tasks to the correct backend based on task.Context.Runtime.Provider. Key changes: - server/pkg/agent/agent.go: Backend interface, Message/Result types, factory - server/pkg/agent/claude.go: Spawns claude CLI with stream-json, parses output - server/pkg/agent/codex.go: Spawns codex app-server, JSON-RPC 2.0 protocol - server/cmd/daemon/daemon.go: Multi-runtime registration, round-robin polling, provider-based backend selection. Removes old runCodexExec/codexResultSchema. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
3 KiB
Go
99 lines
3 KiB
Go
// Package agent provides a unified interface for executing prompts via
|
|
// coding agents (Claude Code, Codex). It mirrors the happy-cli AgentBackend
|
|
// pattern, translated to idiomatic Go.
|
|
package agent
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
// Backend is the unified interface for executing prompts via coding agents.
|
|
type Backend interface {
|
|
// Execute runs a prompt and returns a Session for streaming results.
|
|
// The caller should read from Session.Messages (optional) and wait on
|
|
// Session.Result for the final outcome.
|
|
Execute(ctx context.Context, prompt string, opts ExecOptions) (*Session, error)
|
|
}
|
|
|
|
// ExecOptions configures a single execution.
|
|
type ExecOptions struct {
|
|
Cwd string
|
|
Model string
|
|
SystemPrompt string
|
|
MaxTurns int
|
|
Timeout time.Duration
|
|
}
|
|
|
|
// Session represents a running agent execution.
|
|
type Session struct {
|
|
// Messages streams events as the agent works. The channel is closed
|
|
// when the agent finishes (before Result is sent).
|
|
Messages <-chan Message
|
|
// Result receives exactly one value — the final outcome — then closes.
|
|
Result <-chan Result
|
|
}
|
|
|
|
// MessageType identifies the kind of Message.
|
|
type MessageType string
|
|
|
|
const (
|
|
MessageText MessageType = "text"
|
|
MessageToolUse MessageType = "tool-use"
|
|
MessageToolResult MessageType = "tool-result"
|
|
MessageStatus MessageType = "status"
|
|
MessageError MessageType = "error"
|
|
MessageLog MessageType = "log"
|
|
)
|
|
|
|
// Message is a unified event emitted by an agent during execution.
|
|
type Message struct {
|
|
Type MessageType
|
|
Content string // text content (Text, Error, Log)
|
|
Tool string // tool name (ToolUse, ToolResult)
|
|
CallID string // tool call ID (ToolUse, ToolResult)
|
|
Input map[string]any // tool input (ToolUse)
|
|
Output string // tool output (ToolResult)
|
|
Status string // agent status string (Status)
|
|
Level string // log level (Log)
|
|
}
|
|
|
|
// Result is the final outcome after an agent session completes.
|
|
type Result struct {
|
|
Status string // "completed", "failed", "aborted", "timeout"
|
|
Output string // accumulated text output
|
|
Error string // error message if failed
|
|
DurationMs int64
|
|
SessionID string
|
|
}
|
|
|
|
// Config configures a Backend instance.
|
|
type Config struct {
|
|
ExecutablePath string // path to CLI binary (claude or codex)
|
|
Env map[string]string // extra environment variables
|
|
Logger *log.Logger
|
|
}
|
|
|
|
// New creates a Backend for the given agent type.
|
|
// Supported types: "claude", "codex".
|
|
func New(agentType string, cfg Config) (Backend, error) {
|
|
if cfg.Logger == nil {
|
|
cfg.Logger = log.Default()
|
|
}
|
|
|
|
switch agentType {
|
|
case "claude":
|
|
return &claudeBackend{cfg: cfg}, nil
|
|
case "codex":
|
|
return &codexBackend{cfg: cfg}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown agent type: %q (supported: claude, codex)", agentType)
|
|
}
|
|
}
|
|
|
|
// DetectVersion runs the agent CLI with --version and returns the output.
|
|
func DetectVersion(ctx context.Context, executablePath string) (string, error) {
|
|
return detectCLIVersion(ctx, executablePath)
|
|
}
|