mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 22:32:04 +00:00
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
801 lines
19 KiB
Markdown
801 lines
19 KiB
Markdown
# Provider Architecture Reference
|
|
|
|
This document describes the modular provider architecture in `apps/server/src/providers/` that enables support for multiple AI model providers (Claude SDK, OpenAI Codex CLI, and future providers like Cursor, OpenCode, etc.).
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Architecture Overview](#architecture-overview)
|
|
2. [Provider Interface](#provider-interface)
|
|
3. [Available Providers](#available-providers)
|
|
4. [Provider Factory](#provider-factory)
|
|
5. [Adding New Providers](#adding-new-providers)
|
|
6. [Provider Types](#provider-types)
|
|
7. [Best Practices](#best-practices)
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
The provider architecture separates AI model execution logic from business logic, enabling clean abstraction and easy extensibility.
|
|
|
|
### Architecture Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ AgentService / AutoModeService │
|
|
│ (No provider logic) │
|
|
└──────────────────┬──────────────────────┘
|
|
│
|
|
┌─────────▼──────────┐
|
|
│ ProviderFactory │ Model-based routing
|
|
│ (Routes by model) │ "gpt-*" → Codex
|
|
└─────────┬──────────┘ "claude-*" → Claude
|
|
│
|
|
┌────────────┴────────────┐
|
|
│ │
|
|
┌─────▼──────┐ ┌──────▼──────┐
|
|
│ Claude │ │ Codex │
|
|
│ Provider │ │ Provider │
|
|
│ (Agent SDK)│ │ (CLI Spawn) │
|
|
└────────────┘ └─────────────┘
|
|
```
|
|
|
|
### Key Benefits
|
|
|
|
- ✅ **Adding new providers**: Only 1 new file + 1 line in factory
|
|
- ✅ **Services remain clean**: No provider-specific logic
|
|
- ✅ **All providers implement same interface**: Consistent behavior
|
|
- ✅ **Model prefix determines provider**: Automatic routing
|
|
- ✅ **Easy to test**: Each provider can be tested independently
|
|
|
|
---
|
|
|
|
## Provider Interface
|
|
|
|
**Location**: `apps/server/src/providers/base-provider.ts`
|
|
|
|
All providers must extend `BaseProvider` and implement the required methods.
|
|
|
|
### BaseProvider Abstract Class
|
|
|
|
```typescript
|
|
export abstract class BaseProvider {
|
|
protected config: ProviderConfig;
|
|
|
|
constructor(config: ProviderConfig = {}) {
|
|
this.config = config;
|
|
}
|
|
|
|
/**
|
|
* Get provider name (e.g., "claude", "codex")
|
|
*/
|
|
abstract getName(): string;
|
|
|
|
/**
|
|
* Execute a query and stream responses
|
|
*/
|
|
abstract executeQuery(options: ExecuteOptions): AsyncGenerator<ProviderMessage>;
|
|
|
|
/**
|
|
* Detect provider installation status
|
|
*/
|
|
abstract detectInstallation(): Promise<InstallationStatus>;
|
|
|
|
/**
|
|
* Get available models for this provider
|
|
*/
|
|
abstract getAvailableModels(): ModelDefinition[];
|
|
|
|
/**
|
|
* Check if provider supports a specific feature (optional)
|
|
*/
|
|
supportsFeature(feature: string): boolean {
|
|
return false;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Shared Types
|
|
|
|
**Location**: `apps/server/src/providers/types.ts`
|
|
|
|
#### ExecuteOptions
|
|
|
|
Input configuration for executing queries:
|
|
|
|
```typescript
|
|
export interface ExecuteOptions {
|
|
prompt: string | Array<{ type: string; text?: string; source?: object }>;
|
|
model: string;
|
|
cwd: string;
|
|
systemPrompt?: string;
|
|
maxTurns?: number;
|
|
allowedTools?: string[];
|
|
mcpServers?: Record<string, unknown>;
|
|
abortController?: AbortController;
|
|
conversationHistory?: ConversationMessage[];
|
|
}
|
|
```
|
|
|
|
#### ProviderMessage
|
|
|
|
Output messages streamed from providers:
|
|
|
|
```typescript
|
|
export interface ProviderMessage {
|
|
type: 'assistant' | 'user' | 'error' | 'result';
|
|
subtype?: 'success' | 'error';
|
|
message?: {
|
|
role: 'user' | 'assistant';
|
|
content: ContentBlock[];
|
|
};
|
|
result?: string;
|
|
error?: string;
|
|
}
|
|
```
|
|
|
|
#### ContentBlock
|
|
|
|
Individual content blocks in messages:
|
|
|
|
```typescript
|
|
export interface ContentBlock {
|
|
type: 'text' | 'tool_use' | 'thinking' | 'tool_result';
|
|
text?: string;
|
|
thinking?: string;
|
|
name?: string;
|
|
input?: unknown;
|
|
tool_use_id?: string;
|
|
content?: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Available Providers
|
|
|
|
### 1. Claude Provider (SDK-based)
|
|
|
|
**Location**: `apps/server/src/providers/claude-provider.ts`
|
|
|
|
Uses `@anthropic-ai/claude-agent-sdk` for direct SDK integration.
|
|
|
|
#### Features
|
|
|
|
- ✅ Native multi-turn conversation support
|
|
- ✅ Vision support (images)
|
|
- ✅ Tool use (Read, Write, Edit, Glob, Grep, Bash, WebSearch, WebFetch)
|
|
- ✅ Thinking blocks (extended thinking)
|
|
- ✅ Streaming responses
|
|
- ✅ No CLI installation required (npm dependency)
|
|
|
|
#### Model Detection
|
|
|
|
Routes models that:
|
|
|
|
- Start with `"claude-"` (e.g., `"claude-opus-4-5-20251101"`)
|
|
- Are Claude aliases: `"opus"`, `"sonnet"`, `"haiku"`
|
|
|
|
#### Authentication
|
|
|
|
Requires:
|
|
|
|
- `ANTHROPIC_API_KEY` environment variable
|
|
|
|
#### Example Usage
|
|
|
|
```typescript
|
|
const provider = new ClaudeProvider();
|
|
|
|
const stream = provider.executeQuery({
|
|
prompt: 'What is 2+2?',
|
|
model: 'claude-opus-4-5-20251101',
|
|
cwd: '/project/path',
|
|
systemPrompt: 'You are a helpful assistant.',
|
|
maxTurns: 20,
|
|
allowedTools: ['Read', 'Write', 'Bash'],
|
|
abortController: new AbortController(),
|
|
conversationHistory: [
|
|
{ role: 'user', content: 'Hello' },
|
|
{ role: 'assistant', content: 'Hi! How can I help?' },
|
|
],
|
|
});
|
|
|
|
for await (const msg of stream) {
|
|
if (msg.type === 'assistant') {
|
|
console.log(msg.message?.content);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Conversation History Handling
|
|
|
|
Uses `convertHistoryToMessages()` utility to convert history to SDK format:
|
|
|
|
```typescript
|
|
const historyMessages = convertHistoryToMessages(conversationHistory);
|
|
for (const msg of historyMessages) {
|
|
yield msg; // Yield to SDK
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. Codex Provider (CLI-based)
|
|
|
|
**Location**: `apps/server/src/providers/codex-provider.ts`
|
|
|
|
Spawns OpenAI Codex CLI as a subprocess and converts JSONL output to provider format.
|
|
|
|
#### Features
|
|
|
|
- ✅ Subprocess execution (`codex exec --model <model> --json --full-auto`)
|
|
- ✅ JSONL stream parsing
|
|
- ✅ Supports GPT-5.1/5.2 Codex models
|
|
- ✅ Vision support (GPT-5.1, GPT-5.2)
|
|
- ✅ Tool use via MCP servers
|
|
- ✅ Timeout detection (30s no output)
|
|
- ✅ Abort signal handling
|
|
|
|
#### Model Detection
|
|
|
|
Routes models that:
|
|
|
|
- Start with `"gpt-"` (e.g., `"gpt-5.2"`, `"gpt-5.1-codex-max"`)
|
|
- Start with `"o"` (e.g., `"o1"`, `"o1-mini"`)
|
|
|
|
#### Available Models
|
|
|
|
| Model | Description | Context | Max Output | Vision |
|
|
| -------------------- | ------------------ | ------- | ---------- | ------ |
|
|
| `gpt-5.2` | Latest Codex model | 256K | 32K | Yes |
|
|
| `gpt-5.1-codex-max` | Maximum capability | 256K | 32K | Yes |
|
|
| `gpt-5.1-codex` | Standard Codex | 256K | 32K | Yes |
|
|
| `gpt-5.1-codex-mini` | Lightweight | 256K | 16K | No |
|
|
| `gpt-5.1` | General-purpose | 256K | 32K | Yes |
|
|
|
|
#### Authentication
|
|
|
|
Supports two methods:
|
|
|
|
1. **CLI login**: `codex login` (OAuth tokens stored in `~/.codex/auth.json`)
|
|
2. **API key**: `OPENAI_API_KEY` environment variable
|
|
|
|
#### Installation Detection
|
|
|
|
Uses `CodexCliDetector` to check:
|
|
|
|
- PATH for `codex` command
|
|
- npm global: `npm list -g @openai/codex`
|
|
- Homebrew (macOS): `/opt/homebrew/bin/codex`
|
|
- Common paths: `~/.local/bin/codex`, `/usr/local/bin/codex`
|
|
|
|
#### Example Usage
|
|
|
|
```typescript
|
|
const provider = new CodexProvider();
|
|
|
|
const stream = provider.executeQuery({
|
|
prompt: 'Fix the bug in main.ts',
|
|
model: 'gpt-5.2',
|
|
cwd: '/project/path',
|
|
systemPrompt: 'You are an expert TypeScript developer.',
|
|
abortController: new AbortController(),
|
|
});
|
|
|
|
for await (const msg of stream) {
|
|
if (msg.type === 'assistant') {
|
|
console.log(msg.message?.content);
|
|
} else if (msg.type === 'error') {
|
|
console.error(msg.error);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### JSONL Event Conversion
|
|
|
|
Codex CLI outputs JSONL events that get converted to `ProviderMessage` format:
|
|
|
|
| Codex Event | Provider Message |
|
|
| ------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
| `item.completed` (reasoning) | `{ type: "assistant", content: [{ type: "thinking" }] }` |
|
|
| `item.completed` (agent_message) | `{ type: "assistant", content: [{ type: "text" }] }` |
|
|
| `item.completed` (command_execution) | `{ type: "assistant", content: [{ type: "text", text: "```bash\n...\n```" }] }` |
|
|
| `item.started` (command_execution) | `{ type: "assistant", content: [{ type: "tool_use" }] }` |
|
|
| `item.updated` (todo_list) | `{ type: "assistant", content: [{ type: "text", text: "**Updated Todo List:**..." }] }` |
|
|
| `thread.completed` | `{ type: "result", subtype: "success" }` |
|
|
| `error` | `{ type: "error", error: "..." }` |
|
|
|
|
#### Conversation History Handling
|
|
|
|
Uses `formatHistoryAsText()` utility to prepend history as text context (CLI doesn't support native multi-turn):
|
|
|
|
```typescript
|
|
const historyText = formatHistoryAsText(conversationHistory);
|
|
combinedPrompt = `${historyText}Current request:\n${combinedPrompt}`;
|
|
```
|
|
|
|
#### MCP Server Configuration
|
|
|
|
**Location**: `apps/server/src/providers/codex-config-manager.ts`
|
|
|
|
Manages TOML configuration for MCP servers:
|
|
|
|
```typescript
|
|
await codexConfigManager.configureMcpServer(cwd, mcpServerScriptPath);
|
|
```
|
|
|
|
Generates `.codex/config.toml`:
|
|
|
|
```toml
|
|
[mcp_servers.automaker-tools]
|
|
command = "node"
|
|
args = ["/path/to/mcp-server.js"]
|
|
enabled_tools = ["UpdateFeatureStatus"]
|
|
```
|
|
|
|
---
|
|
|
|
## Provider Factory
|
|
|
|
**Location**: `apps/server/src/providers/provider-factory.ts`
|
|
|
|
Routes requests to the appropriate provider based on model string.
|
|
|
|
### Model-Based Routing
|
|
|
|
```typescript
|
|
export class ProviderFactory {
|
|
/**
|
|
* Get provider for a specific model
|
|
*/
|
|
static getProviderForModel(modelId: string): BaseProvider {
|
|
const lowerModel = modelId.toLowerCase();
|
|
|
|
// OpenAI/Codex models
|
|
if (lowerModel.startsWith('gpt-') || lowerModel.startsWith('o')) {
|
|
return new CodexProvider();
|
|
}
|
|
|
|
// Claude models
|
|
if (lowerModel.startsWith('claude-') || ['haiku', 'sonnet', 'opus'].includes(lowerModel)) {
|
|
return new ClaudeProvider();
|
|
}
|
|
|
|
// Default to Claude
|
|
return new ClaudeProvider();
|
|
}
|
|
|
|
/**
|
|
* Check installation status of all providers
|
|
*/
|
|
static async checkAllProviders(): Promise<Record<string, InstallationStatus>> {
|
|
const claude = new ClaudeProvider();
|
|
const codex = new CodexProvider();
|
|
|
|
return {
|
|
claude: await claude.detectInstallation(),
|
|
codex: await codex.detectInstallation(),
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### Usage in Services
|
|
|
|
```typescript
|
|
import { ProviderFactory } from '../providers/provider-factory.js';
|
|
|
|
// In AgentService or AutoModeService
|
|
const provider = ProviderFactory.getProviderForModel(model);
|
|
const stream = provider.executeQuery(options);
|
|
|
|
for await (const msg of stream) {
|
|
// Handle messages (format is consistent across all providers)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Adding New Providers
|
|
|
|
### Step 1: Create Provider File
|
|
|
|
Create `apps/server/src/providers/[name]-provider.ts`:
|
|
|
|
```typescript
|
|
import { BaseProvider } from './base-provider.js';
|
|
import type {
|
|
ExecuteOptions,
|
|
ProviderMessage,
|
|
InstallationStatus,
|
|
ModelDefinition,
|
|
} from './types.js';
|
|
|
|
export class CursorProvider extends BaseProvider {
|
|
getName(): string {
|
|
return 'cursor';
|
|
}
|
|
|
|
async *executeQuery(options: ExecuteOptions): AsyncGenerator<ProviderMessage> {
|
|
// Implementation here
|
|
// 1. Spawn cursor CLI or use SDK
|
|
// 2. Convert output to ProviderMessage format
|
|
// 3. Yield messages
|
|
}
|
|
|
|
async detectInstallation(): Promise<InstallationStatus> {
|
|
// Check if cursor is installed
|
|
// Return { installed: boolean, path?: string, version?: string }
|
|
}
|
|
|
|
getAvailableModels(): ModelDefinition[] {
|
|
return [
|
|
{
|
|
id: 'cursor-premium',
|
|
name: 'Cursor Premium',
|
|
modelString: 'cursor-premium',
|
|
provider: 'cursor',
|
|
description: "Cursor's premium model",
|
|
contextWindow: 200000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: true,
|
|
supportsTools: true,
|
|
tier: 'premium',
|
|
default: true,
|
|
},
|
|
];
|
|
}
|
|
|
|
supportsFeature(feature: string): boolean {
|
|
const supportedFeatures = ['tools', 'text', 'vision'];
|
|
return supportedFeatures.includes(feature);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 2: Add Routing in Factory
|
|
|
|
Update `apps/server/src/providers/provider-factory.ts`:
|
|
|
|
```typescript
|
|
import { CursorProvider } from "./cursor-provider.js";
|
|
|
|
static getProviderForModel(modelId: string): BaseProvider {
|
|
const lowerModel = modelId.toLowerCase();
|
|
|
|
// Cursor models
|
|
if (lowerModel.startsWith("cursor-")) {
|
|
return new CursorProvider();
|
|
}
|
|
|
|
// ... existing routing
|
|
}
|
|
|
|
static async checkAllProviders() {
|
|
const cursor = new CursorProvider();
|
|
|
|
return {
|
|
claude: await claude.detectInstallation(),
|
|
codex: await codex.detectInstallation(),
|
|
cursor: await cursor.detectInstallation(), // NEW
|
|
};
|
|
}
|
|
```
|
|
|
|
### Step 3: Update Models List
|
|
|
|
Update `apps/server/src/routes/models.ts`:
|
|
|
|
```typescript
|
|
{
|
|
id: "cursor-premium",
|
|
name: "Cursor Premium",
|
|
provider: "cursor",
|
|
contextWindow: 200000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: true,
|
|
supportsTools: true,
|
|
}
|
|
```
|
|
|
|
### Step 4: Done!
|
|
|
|
No changes needed in:
|
|
|
|
- ✅ AgentService
|
|
- ✅ AutoModeService
|
|
- ✅ Any business logic
|
|
|
|
The provider architecture handles everything automatically.
|
|
|
|
---
|
|
|
|
## Provider Types
|
|
|
|
### SDK-Based Providers (like Claude)
|
|
|
|
**Characteristics**:
|
|
|
|
- Direct SDK/library integration
|
|
- No subprocess spawning
|
|
- Native multi-turn support
|
|
- Streaming via async generators
|
|
|
|
**Example**: ClaudeProvider using `@anthropic-ai/claude-agent-sdk`
|
|
|
|
**Advantages**:
|
|
|
|
- Lower latency
|
|
- More control over options
|
|
- Easier error handling
|
|
- No CLI installation required
|
|
|
|
---
|
|
|
|
### CLI-Based Providers (like Codex)
|
|
|
|
**Characteristics**:
|
|
|
|
- Subprocess spawning
|
|
- JSONL stream parsing
|
|
- Text-based conversation history
|
|
- Requires CLI installation
|
|
|
|
**Example**: CodexProvider using `codex exec --json`
|
|
|
|
**Advantages**:
|
|
|
|
- Access to CLI-only features
|
|
- No SDK dependency
|
|
- Can use any CLI tool
|
|
|
|
**Implementation Pattern**:
|
|
|
|
1. Use `spawnJSONLProcess()` from `subprocess-manager.ts`
|
|
2. Convert JSONL events to `ProviderMessage` format
|
|
3. Handle authentication (CLI login or API key)
|
|
4. Implement timeout detection
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### 1. Message Format Consistency
|
|
|
|
All providers MUST output the same `ProviderMessage` format so services can handle them uniformly:
|
|
|
|
```typescript
|
|
// ✅ Correct - Consistent format
|
|
yield {
|
|
type: "assistant",
|
|
message: {
|
|
role: "assistant",
|
|
content: [{ type: "text", text: "Response" }]
|
|
}
|
|
};
|
|
|
|
// ❌ Incorrect - Provider-specific format
|
|
yield {
|
|
customType: "response",
|
|
data: "Response"
|
|
};
|
|
```
|
|
|
|
### 2. Error Handling
|
|
|
|
Always yield error messages, never throw:
|
|
|
|
```typescript
|
|
// ✅ Correct
|
|
try {
|
|
// ...
|
|
} catch (error) {
|
|
yield {
|
|
type: "error",
|
|
error: (error as Error).message
|
|
};
|
|
return;
|
|
}
|
|
|
|
// ❌ Incorrect
|
|
throw new Error("Provider failed");
|
|
```
|
|
|
|
### 3. Abort Signal Support
|
|
|
|
Respect the abort controller:
|
|
|
|
```typescript
|
|
if (abortController?.signal.aborted) {
|
|
yield { type: "error", error: "Operation cancelled" };
|
|
return;
|
|
}
|
|
```
|
|
|
|
### 4. Conversation History
|
|
|
|
- **SDK providers**: Use `convertHistoryToMessages()` and yield messages
|
|
- **CLI providers**: Use `formatHistoryAsText()` and prepend to prompt
|
|
|
|
### 5. Image Handling
|
|
|
|
- **Vision models**: Pass images as content blocks
|
|
- **Non-vision models**: Extract text only using utilities
|
|
|
|
### 6. Logging
|
|
|
|
Use consistent logging prefixes:
|
|
|
|
```typescript
|
|
console.log(`[${this.getName()}Provider] Operation started`);
|
|
console.error(`[${this.getName()}Provider] Error:`, error);
|
|
```
|
|
|
|
### 7. Installation Detection
|
|
|
|
Implement thorough detection:
|
|
|
|
- Check multiple installation methods
|
|
- Verify authentication
|
|
- Return detailed status
|
|
|
|
### 8. Model Definitions
|
|
|
|
Provide accurate model metadata:
|
|
|
|
```typescript
|
|
{
|
|
id: "model-id",
|
|
name: "Human-readable name",
|
|
modelString: "exact-model-string",
|
|
provider: "provider-name",
|
|
description: "What this model is good for",
|
|
contextWindow: 200000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: true,
|
|
supportsTools: true,
|
|
tier: "premium" | "standard" | "basic",
|
|
default: false
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Providers
|
|
|
|
### Unit Tests
|
|
|
|
Test each provider method independently:
|
|
|
|
```typescript
|
|
describe('ClaudeProvider', () => {
|
|
it('should detect installation', async () => {
|
|
const provider = new ClaudeProvider();
|
|
const status = await provider.detectInstallation();
|
|
|
|
expect(status.installed).toBe(true);
|
|
expect(status.method).toBe('sdk');
|
|
});
|
|
|
|
it('should stream messages correctly', async () => {
|
|
const provider = new ClaudeProvider();
|
|
const messages = [];
|
|
|
|
for await (const msg of provider.executeQuery(options)) {
|
|
messages.push(msg);
|
|
}
|
|
|
|
expect(messages.length).toBeGreaterThan(0);
|
|
expect(messages[0].type).toBe('assistant');
|
|
});
|
|
});
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
Test provider interaction with services:
|
|
|
|
```typescript
|
|
describe('Provider Integration', () => {
|
|
it('should work with AgentService', async () => {
|
|
const provider = ProviderFactory.getProviderForModel('claude-opus-4-5-20251101');
|
|
|
|
// Test full workflow
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
### Claude Provider
|
|
|
|
```bash
|
|
# Required:
|
|
ANTHROPIC_API_KEY=sk-ant-...
|
|
```
|
|
|
|
### Codex Provider
|
|
|
|
```bash
|
|
# Required (one of):
|
|
OPENAI_API_KEY=sk-...
|
|
# OR run: codex login
|
|
|
|
# Optional:
|
|
CODEX_CLI_PATH=/custom/path/to/codex
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Provider Not Found
|
|
|
|
**Problem**: `ProviderFactory.getProviderForModel()` returns wrong provider
|
|
|
|
**Solution**: Check model string prefix in factory routing
|
|
|
|
### Authentication Errors
|
|
|
|
**Problem**: Provider fails with auth error
|
|
|
|
**Solution**:
|
|
|
|
1. Check environment variables
|
|
2. For CLI providers, verify CLI login status
|
|
3. Check `detectInstallation()` output
|
|
|
|
### JSONL Parsing Errors (CLI providers)
|
|
|
|
**Problem**: Failed to parse JSONL line
|
|
|
|
**Solution**:
|
|
|
|
1. Check CLI output format
|
|
2. Verify JSON is valid
|
|
3. Add error handling for malformed lines
|
|
|
|
### Timeout Issues (CLI providers)
|
|
|
|
**Problem**: Subprocess hangs
|
|
|
|
**Solution**:
|
|
|
|
1. Increase timeout in `spawnJSONLProcess` options
|
|
2. Check CLI process for hangs
|
|
3. Verify abort signal handling
|
|
|
|
---
|
|
|
|
## Future Provider Ideas
|
|
|
|
Potential providers to add:
|
|
|
|
1. **Cursor Provider** (`cursor-*`)
|
|
- CLI-based
|
|
- Code completion specialist
|
|
|
|
2. **OpenCode Provider** (`opencode-*`)
|
|
- SDK or CLI-based
|
|
- Open-source alternative
|
|
|
|
3. **Gemini Provider** (`gemini-*`)
|
|
- Google's AI models
|
|
- SDK-based via `@google/generative-ai`
|
|
|
|
4. **Ollama Provider** (`ollama-*`)
|
|
- Local model hosting
|
|
- CLI or HTTP API
|
|
|
|
Each would follow the same pattern:
|
|
|
|
1. Create `[name]-provider.ts` implementing `BaseProvider`
|
|
2. Add routing in `provider-factory.ts`
|
|
3. Update models list
|
|
4. Done! ✅
|