feat(agents): multi-provider POC — DeepSeek + Ollama (server-side) #547
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!547
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/multi-provider"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Per-agent LLM provider selection on
agents.json::types.<name>.provider. All providers expose the Anthropic Messages API so the in-container Claude CLI is unchanged — onlyANTHROPIC_BASE_URLandANTHROPIC_AUTH_TOKENflip per provider at container start.Server-side wiring only. Web UI +
/agents/modelsHTTP route registration deferred to follow-up PRs (route registration is entangled with an in-flight auth refactor inmain.ts; UI is entangled with aroutes/config.tsx→features/agents/sections.tsxfile move).Changes
agents-config-schema.ts,webhook-config.ts):providerenumanthropic | deepseek | ollama, defaultanthropic. Loader rejectsprovider != "anthropic"on host-mode types (foreman) since host bypasses container env injection.container-reconcile.ts): hardcoded provider conventions — DeepSeekhttps://api.deepseek.com/anthropic+DEEPSEEK_API_KEY, OllamaOLLAMA_BASE_URL+ dummy token. Newline-rejects every injected env value (--env-fileline termination cannot be hijacked). AllocatesenvTmppath beforetryso cleanup is reliable on partial-write throws.sdk-adapter.ts):listModels(provider)per-provider catalogues — Anthropic/v1/models, DeepSeek/v1/modelsBearer, Ollama/api/tags. 24 h cache, hardcoded fallback so UI combobox never goes blank.clearListModelsCache()invoked onreloadWebhookConfig().db.ts,http/handlers/config.ts): onPUT /config/agentsprovider change, scrub per-instancemodel_overriderows so dispatchers don't push a Claude model name through DeepSeek (silent gibberish at the alt endpoint).claude-port.ts,resolved-agent.ts):ModelInfo,AgentProvider,agentProvider()defaulter on the shared port.agent-runner.test.ts):FakeClaudeAgent.setModels()/listModels()stubs.docs/providers.md): operator setup (systemd drop-ins forDEEPSEEK_API_KEY/OLLAMA_BASE_URL), known caveats (no prompt cache for non-Anthropic, foreman host-mode limitation, Ollama tool-call model dependence).Test plan
just typecheckclean across all 4 packages.mainand are unrelated.provider: "deepseek"on a type, supplyDEEPSEEK_API_KEY, dispatch a task, confirm it routes to DeepSeek endpoint.PUT /config/agents, confirm[config] type X provider A→B: cleared N per-instance model override(s)log line.provider: "deepseek"→ loader rejects with clear error.\n→ reconciler rejects with clear error.🤖 Generated with Claude Code
usage_threshold_tokensenforcement #551