agent-orchestrator/docs/provider-adapter/task_plan.md

6 KiB

Agent Provider Adapter — Task Plan

Goal

Multi-provider agent support (Claude Code, Codex CLI, Ollama) via adapter pattern. Claude Code remains primary and fully functional. Zero regression.

Architecture Decisions

# Date Decision Rationale
PA-1 2026-03-11 Per-provider sidecar binaries (not single multi-SDK bundle) Independent testing, no bloat, clean separation. SidecarCommand already abstracts binary path.
PA-2 2026-03-11 Generic provider_config blob in AgentQueryOptions (not discriminated union) Rust passes through without parsing. TypeScript uses discriminated unions for compile-time safety. Minimal Rust changes.
PA-3 2026-03-11 Per-provider message adapter files → common AgentMessage type sdk-messages.ts becomes claude-messages.ts. Registry selects parser by provider. Store/UI unchanged.
PA-4 2026-03-11 Provider selection per-project with global default ProjectConfig.provider field (default: 'claude'). Matches real workflow.
PA-5 2026-03-11 Capability flags drive UI rendering (not provider ID checks) ProviderCapabilities interface. AgentPane checks hasProfiles/hasSkills/etc. No hardcoded if(provider==='claude').
PA-6 2026-03-11 Providers section in SettingsTab scroll (not inner tabs) Current sections aren't long enough for tabs. Collapsible per-provider config panels.

Phases

Phase 1: Core Abstraction Layer (no functional change)

Goal: Insert abstraction boundary. Claude remains the only registered provider. Zero user-visible change.

# Task Files Status
1.1 Create provider types NEW: src/lib/providers/types.ts done
1.2 Create provider registry NEW: src/lib/providers/registry.svelte.ts done
1.3 Create Claude provider meta NEW: src/lib/providers/claude.ts done
1.4 Rename sdk-messages.ts → claude-messages.ts RENAME + update imports done
1.5 Create message adapter registry NEW: src/lib/adapters/message-adapters.ts done
1.6 Update Rust AgentQueryOptions MOD: agor-core/src/sidecar.rs done
1.7 Update agent-bridge.ts options shape MOD: src/lib/adapters/agent-bridge.ts done
1.8 Rename agent-runner.ts → claude-runner.ts RENAME + update build script done
1.9 Add provider field to ProjectConfig MOD: src/lib/types/groups.ts done
1.10 Rename ClaudeSession.svelte → AgentSession.svelte RENAME + update imports done
1.11 Update agent-dispatcher provider routing MOD: src/lib/agent-dispatcher.ts done
1.12 Update AgentPane for capability-driven rendering MOD: src/lib/components/Agent/AgentPane.svelte done
1.13 Rename claude-bridge.ts → provider-bridge.ts RENAME + genericize done
1.14 Update Rust lib.rs commands MOD: src-tauri/src/lib.rs done
1.15 Update all tests MOD: test files done
1.16 Verify: 202 vitest + 42 cargo tests pass done

Phase 2: Settings UI

# Task Files Status
2.1 Add Providers section to SettingsTab MOD: SettingsTab.svelte done
2.2 Per-provider collapsible config panels MOD: SettingsTab.svelte done
2.3 Per-project provider dropdown MOD: SettingsTab.svelte done
2.4 Persist provider settings MOD: settings-bridge.ts done
2.5 Provider-aware AgentPane MOD: AgentPane.svelte done

Phase 3: Sidecar Routing

# Task Files Status
3.1 SidecarManager provider-based runner selection MOD: agor-core/src/sidecar.rs done
3.2 Per-provider runner discovery MOD: agor-core/src/sidecar.rs done
3.3 Provider-specific env var stripping MOD: agor-core/src/sidecar.rs done

Type System

ProviderQueryOptions (TypeScript → Rust → Sidecar)

Frontend (typed):
  AgentQueryOptions {
    provider: ProviderId        // 'claude' | 'codex' | 'ollama'
    session_id: string
    prompt: string
    model?: string
    max_turns?: number
    provider_config: Record<string, unknown>  // provider-specific
  }
         ↓ (Tauri invoke)
Rust (generic):
  AgentQueryOptions {
    provider: String
    session_id: String
    prompt: String
    model: Option<String>
    max_turns: Option<u32>
    provider_config: serde_json::Value
  }
         ↓ (stdin NDJSON)
Sidecar (provider-specific):
  claude-runner.ts parses provider_config as ClaudeProviderConfig
  codex-runner.ts parses provider_config as CodexProviderConfig
  ollama-runner.ts parses provider_config as OllamaProviderConfig

Message Flow (Sidecar → Frontend)

Sidecar stdout (NDJSON, provider-specific format)
         ↓
Rust SidecarManager (pass-through, adds sessionId)
         ↓
agent-dispatcher.ts
  → message-adapters.ts registry
    → claude-messages.ts (if provider=claude)
    → codex-messages.ts (if provider=codex, future)
    → ollama-messages.ts (if provider=ollama, future)
  → AgentMessage (common type)
         ↓
agents.svelte.ts store (unchanged)
         ↓
AgentPane.svelte (renders AgentMessage, capability-driven)

File Inventory

New Files (Phase 1)

  • src/lib/providers/types.ts
  • src/lib/providers/registry.svelte.ts
  • src/lib/providers/claude.ts
  • src/lib/adapters/message-adapters.ts

Renamed Files (Phase 1)

  • sdk-messages.tsclaude-messages.ts
  • agent-runner.tsclaude-runner.ts
  • ClaudeSession.svelteAgentSession.svelte
  • claude-bridge.tsprovider-bridge.ts (genericized)

Modified Files (Phase 1)

  • agor-core/src/sidecar.rs — AgentQueryOptions struct
  • src-tauri/src/lib.rs — command handlers
  • src/lib/adapters/agent-bridge.ts — options interface
  • src/lib/agent-dispatcher.ts — provider routing
  • src/lib/components/Agent/AgentPane.svelte — capability checks
  • src/lib/components/Workspace/ProjectBox.svelte — import rename
  • src/lib/types/groups.ts — ProjectConfig.provider field
  • package.json — build:sidecar script path
  • Test files — import path updates