Skip to content

Commit 91209ef

Browse files
milos85vasicclaude
andcommitted
feat: complete LLMOrchestrator module with all packages and tests
Full implementation of headless CLI agent management: - pkg/agent: Agent interface, AgentPool (mutex-safe), HealthMonitor, circuit breaker - pkg/adapter: BaseAdapter + 5 CLI adapters (OpenCode, ClaudeCode, Gemini, Junie, QwenCode) - pkg/protocol: PipeTransport (stdin/stdout JSON-lines), FileTransport (inbox/outbox/shared) - pkg/parser: ResponseParser with JSON extraction, action/issue parsing, fuzz-safe - pkg/config: .env loading, agent path resolution 247 tests passing with -race -count=1. Includes unit, integration, stress, security, E2E, and automation tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 parents  commit 91209ef

47 files changed

Lines changed: 8363 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# LLMOrchestrator Configuration
2+
# Copy this file to .env and fill in your values.
3+
4+
# CLI Agents
5+
HELIX_AGENTS_ENABLED=opencode,claude-code,gemini
6+
HELIX_AGENT_OPENCODE_PATH=/usr/local/bin/opencode
7+
HELIX_AGENT_CLAUDE_PATH=/usr/local/bin/claude
8+
HELIX_AGENT_GEMINI_PATH=/usr/local/bin/gemini
9+
HELIX_AGENT_JUNIE_PATH=/usr/local/bin/junie
10+
HELIX_AGENT_QWEN_PATH=/usr/local/bin/qwen-code
11+
HELIX_AGENT_TIMEOUT=60s
12+
HELIX_AGENT_MAX_RETRIES=3
13+
HELIX_AGENT_POOL_SIZE=3
14+
15+
# API Keys (required for the respective agents)
16+
OPENAI_API_KEY=sk-...
17+
ANTHROPIC_API_KEY=sk-ant-...
18+
GOOGLE_API_KEY=AI...
19+
GROQ_API_KEY=gsk_...
20+
MISTRAL_API_KEY=...
21+
DEEPSEEK_API_KEY=...
22+
XAI_API_KEY=...
23+
TOGETHER_API_KEY=...
24+
QWEN_API_KEY=...
25+
JUNIE_API_KEY=...

.gitignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Binaries
2+
*.exe
3+
*.dll
4+
*.so
5+
*.dylib
6+
/orchestrator
7+
8+
# Test
9+
*.test
10+
coverage.out
11+
coverage.html
12+
13+
# IDE
14+
.idea/
15+
.vscode/
16+
*.swp
17+
*.swo
18+
*~
19+
20+
# OS
21+
.DS_Store
22+
Thumbs.db
23+
24+
# Environment
25+
.env
26+
27+
# Build
28+
/bin/
29+
/dist/

AGENTS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Supported Agents
2+
3+
## Agent Overview
4+
5+
| Agent | CLI Binary | Headless Mode | Vision | Max Tokens |
6+
|-------|-----------|---------------|--------|------------|
7+
| OpenCode | `opencode` | `--headless --non-interactive` | Via configured LLM | 128K |
8+
| Claude Code | `claude` | `--print --output-format json` | Native (Claude) | 200K |
9+
| Gemini | `gemini` | `--non-interactive` | Native (Gemini) | 1M |
10+
| Junie | `junie` | `--headless` | Via configured LLM | 128K |
11+
| Qwen Code | `qwen-code` | `--headless --non-interactive` | Native (Qwen-VL) | 128K |
12+
13+
## OpenCode
14+
15+
OpenCode is a multi-provider CLI agent. It supports OpenAI, Anthropic, and Google providers. Vision capabilities depend on the configured LLM backend.
16+
17+
**Response format**: JSON with `content`, `tool_use`, `tokens_in`, `tokens_out` fields.
18+
19+
## Claude Code
20+
21+
Anthropic's official CLI for Claude. Uses `--print --output-format json` for headless operation. Native vision through Claude's multimodal capabilities.
22+
23+
**Response format**: JSON with `result`, `usage.input_tokens`, `usage.output_tokens`, `model` fields.
24+
25+
## Gemini
26+
27+
Google's Gemini CLI agent. Supports the largest context window (1M tokens). Native vision through Gemini's multimodal capabilities.
28+
29+
**Response format**: JSON with `text`, `token_count`, `finish_reason` fields.
30+
31+
## Junie
32+
33+
JetBrains' AI coding assistant. Uses `--headless` mode. Vision capabilities depend on the configured backend.
34+
35+
**Response format**: JSON with `response`, `status`, `tokens` fields.
36+
37+
## Qwen Code
38+
39+
Alibaba's Qwen-VL coding assistant. Native vision through Qwen-VL model. Uses `--headless --non-interactive` mode.
40+
41+
**Response format**: JSON with `output`, `token_usage.input`, `token_usage.output`, `model` fields.
42+
43+
## Adding a New Agent
44+
45+
1. Create `pkg/adapter/youragent.go`
46+
2. Embed `*BaseAdapter`
47+
3. Implement `parseYourAgentResponse(raw string) (agent.Response, error)`
48+
4. Set appropriate flags in the constructor
49+
5. Add tests in `pkg/adapter/adapter_test.go`
50+
6. Update this document

API_REFERENCE.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# API Reference
2+
3+
## Package `agent`
4+
5+
### Interfaces
6+
7+
#### `Agent`
8+
Core interface for all CLI agents.
9+
10+
| Method | Signature | Description |
11+
|--------|-----------|-------------|
12+
| `ID` | `() string` | Unique instance identifier |
13+
| `Name` | `() string` | Agent type name |
14+
| `Start` | `(ctx context.Context) error` | Launch agent process |
15+
| `Stop` | `(ctx context.Context) error` | Graceful shutdown |
16+
| `IsRunning` | `() bool` | Process active status |
17+
| `Health` | `(ctx context.Context) HealthStatus` | Health check |
18+
| `Send` | `(ctx context.Context, prompt string) (Response, error)` | Send prompt, get response |
19+
| `SendStream` | `(ctx context.Context, prompt string) (<-chan StreamChunk, error)` | Streaming response |
20+
| `SendWithAttachments` | `(ctx context.Context, prompt string, attachments []Attachment) (Response, error)` | Send with files |
21+
| `OutputDir` | `() string` | Artifact output directory |
22+
| `Capabilities` | `() AgentCapabilities` | Agent capabilities |
23+
| `SupportsVision` | `() bool` | Vision support |
24+
| `ModelInfo` | `() ModelInfo` | Model information |
25+
26+
#### `AgentPool`
27+
Thread-safe pool with capability matching.
28+
29+
| Method | Signature | Description |
30+
|--------|-----------|-------------|
31+
| `Register` | `(agent Agent) error` | Add agent to pool |
32+
| `Acquire` | `(ctx context.Context, requirements AgentRequirements) (Agent, error)` | Get matching agent (blocks) |
33+
| `Release` | `(agent Agent)` | Return agent to pool |
34+
| `Available` | `() []Agent` | List available agents |
35+
| `HealthCheck` | `(ctx context.Context) []HealthStatus` | Check all agents |
36+
| `Shutdown` | `(ctx context.Context) error` | Stop all agents |
37+
38+
### Types
39+
40+
- `Response` - Parsed result from Send()
41+
- `StreamChunk` - Individual streaming chunk
42+
- `Attachment` - File attachment
43+
- `AgentCapabilities` - Agent feature flags
44+
- `AgentRequirements` - Caller requirements
45+
- `HealthStatus` - Health check result
46+
- `Action` - Structured action (click, type, scroll, etc.)
47+
- `ParsedResponse` - Fully parsed response
48+
- `Issue` - Detected problem
49+
- `ModelInfo` - LLM model information
50+
51+
### Functions
52+
53+
- `NewPool() AgentPool` - Create thread-safe agent pool
54+
- `NewCircuitBreaker() *CircuitBreaker` - Create circuit breaker (default config)
55+
- `NewCircuitBreakerWithConfig(threshold int, timeout time.Duration) *CircuitBreaker` - Custom config
56+
- `NewHealthMonitor() *HealthMonitor` - Create health monitor
57+
58+
## Package `adapter`
59+
60+
### Constructors
61+
62+
| Function | Description |
63+
|----------|-------------|
64+
| `NewOpenCodeAgent(id string, config AdapterConfig) *OpenCodeAgent` | OpenCode adapter |
65+
| `NewClaudeCodeAgent(id string, config AdapterConfig) *ClaudeCodeAgent` | Claude Code adapter |
66+
| `NewGeminiAgent(id string, config AdapterConfig) *GeminiAgent` | Gemini adapter |
67+
| `NewJunieAgent(id string, config AdapterConfig) *JunieAgent` | Junie adapter |
68+
| `NewQwenCodeAgent(id string, config AdapterConfig) *QwenCodeAgent` | Qwen Code adapter |
69+
| `NewBaseAdapter(id, name string, config AdapterConfig, caps AgentCapabilities, modelInfo ModelInfo) *BaseAdapter` | Base adapter |
70+
71+
### `AdapterConfig`
72+
73+
```go
74+
type AdapterConfig struct {
75+
BinaryPath string
76+
Args []string
77+
Env []string
78+
WorkDir string
79+
OutputDir string
80+
Timeout time.Duration
81+
MaxRetries int
82+
}
83+
```
84+
85+
## Package `protocol`
86+
87+
### `PipeTransport`
88+
89+
| Method | Description |
90+
|--------|-------------|
91+
| `NewPipeTransport(reader io.Reader, writer io.Writer) *PipeTransport` | Create transport |
92+
| `Send(ctx, msg PipeMessage) error` | Write JSON-line |
93+
| `Receive(ctx) (PipeMessage, error)` | Read JSON-line |
94+
| `SendPrompt(ctx, requestID, content, imagePath string) error` | Convenience prompt |
95+
| `SendShutdown(ctx) error` | Send shutdown signal |
96+
| `Close() error` | Mark closed |
97+
98+
### `FileTransport`
99+
100+
| Method | Description |
101+
|--------|-------------|
102+
| `NewFileTransport(sessionDir string) (*FileTransport, error)` | Create with inbox/outbox/shared |
103+
| `WriteToInbox(msg FileMessage) error` | Write to inbox |
104+
| `WriteToOutbox(msg FileMessage) error` | Write to outbox |
105+
| `ReadFromInbox() ([]FileMessage, error)` | Read inbox messages |
106+
| `ReadFromOutbox() ([]FileMessage, error)` | Read outbox messages |
107+
| `WriteSharedFile(name string, data []byte) error` | Write shared artifact |
108+
| `ReadSharedFile(name string) ([]byte, error)` | Read shared artifact |
109+
| `Cleanup() error` | Remove session directory |
110+
111+
## Package `parser`
112+
113+
### `ResponseParser` Interface
114+
115+
| Method | Description |
116+
|--------|-------------|
117+
| `Parse(raw string) (ParsedResponse, error)` | Full parse |
118+
| `ExtractJSON(raw string) (map[string]any, error)` | Extract JSON |
119+
| `ExtractActions(raw string) ([]Action, error)` | Extract actions |
120+
| `ExtractIssues(raw string) ([]Issue, error)` | Extract issues |
121+
122+
### Functions
123+
124+
- `NewParser() ResponseParser` - Create default parser
125+
126+
## Package `config`
127+
128+
### Functions
129+
130+
| Function | Description |
131+
|----------|-------------|
132+
| `DefaultConfig() *Config` | Sane defaults |
133+
| `LoadFromEnv(path string) (*Config, error)` | Load from .env file |
134+
| `LoadFromEnvironment() *Config` | Load from OS env |
135+
| `MaskAPIKey(key string) string` | Mask key for logging |
136+
137+
### `Config` Methods
138+
139+
| Method | Description |
140+
|--------|-------------|
141+
| `AgentBinaryPath(name string) (string, error)` | Resolve binary path |
142+
| `IsAgentEnabled(name string) bool` | Check if enabled |
143+
| `SessionDir(sessionID string) string` | Get session directory |
144+
| `Validate() error` | Validate configuration |

0 commit comments

Comments
 (0)