Skip to content

Commit be0a2d6

Browse files
jimgqyuclaude
andcommitted
fix: DeepSeek /anthropic endpoint support + model config overhaul
- Route DeepSeek /anthropic endpoint through AnthropicProvider (Anthropic SDK format) since it does not accept OpenAI Chat Completions format. The engine-factory now auto-detects anthropic in the base URL and uses the correct provider. - Fix --model CLI flag by making KODE_MODEL the highest priority in resolveModelConfig() and the KodeGatewayClient constructor. - Make /model command persistent by updating settings.json on disk via config.set RPC handler (writes env.ANTHROPIC_MODEL/BASE_URL/AUTH_TOKEN and default_model). - Add protected buildStreamUrl() in OpenAICompatProvider for subclasses to override URL path construction. DeepSeekProvider overrides to append /v1/chat/completions to the base URL. - Change DeepSeek default base URL to https://api.deepseek.com/anthropic. - Remove dead code: shared/src/config/loader.ts (201 lines, never imported by CLI — settings.json is the sole config source). - Update configuration priority comment to reflect actual flow: CLI args > Env vars > ~/.kode/settings.json > Defaults. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent dfcf8f3 commit be0a2d6

9 files changed

Lines changed: 183 additions & 309 deletions

File tree

README.md

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
<p align="center">
44
<b>An open-source, enterprise-grade CLI agent coding tool</b><br/>
5-
<em>Multi-provider LLM support, Agent Teams, and a powerful hook system</em>
5+
<em>A Claude Code alternative with multi-provider support, Agent Teams, and a powerful hook system</em>
66
</p>
77

88
<p align="center">
9-
<img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License: Apache 2.0" />
9+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" />
1010
<img src="https://img.shields.io/badge/TypeScript-5.7-blue" alt="TypeScript" />
1111
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen" alt="Node.js >= 18.0.0" />
1212
<img src="https://img.shields.io/badge/tests-~500%20passed-success" alt="Tests" />
@@ -38,9 +38,9 @@ cat > ~/.kode/settings.json << 'EOF'
3838
"theme": "dark",
3939
"model_list": [
4040
{
41-
"name": "deepseek-v4-pro",
42-
"model": "deepseek-v4-pro",
43-
"base_url": "https://api.deepseek.com/v1",
41+
"name": "deepseek/deepseek-v4-pro",
42+
"model": "deepseek-chat",
43+
"base_url": "https://api.deepseek.com/anthropic",
4444
"auth_token_env": "DEEPSEEK_API_KEY",
4545
"provider": "deepseek"
4646
},
@@ -52,7 +52,7 @@ cat > ~/.kode/settings.json << 'EOF'
5252
"provider": "anthropic"
5353
}
5454
],
55-
"default_model": "deepseek-v4-pro"
55+
"default_model": "deepseek/deepseek-v4-pro"
5656
}
5757
EOF
5858

@@ -67,7 +67,7 @@ kode
6767
For a guided setup, run the installer:
6868

6969
```bash
70-
curl -fsSL https://raw.githubusercontent.com/AgenticMatrix/Kode-Agent/main/install.sh | bash
70+
curl -fsSL https://raw.githubusercontent.com/kode-agent/kode-agent/main/install.sh | bash
7171
```
7272

7373
---
@@ -235,7 +235,7 @@ skills:
235235

236236
| Feature | Kode Agent | Claude Code | Hermes-Agent |
237237
|---------|-----------|-------------|--------------|
238-
| **License** | Apache 2.0 | Proprietary | MIT |
238+
| **License** | MIT | Proprietary | MIT |
239239
| **Multi-Provider** | ✅ Anthropic + OpenAI + DeepSeek + Auto | ❌ Anthropic only | ✅ Multi-provider |
240240
| **Agent Teams** | ✅ Coordinator/Worker + SubagentBus | ❌ Single agent | ❌ Single agent |
241241
| **Hook System** | ✅ 27 events, Shell + JS | ⚠️ Limited hooks | ❌ No hooks |
@@ -283,18 +283,19 @@ export KODE_PROVIDER=openai
283283
export OPENAI_API_KEY="sk-..."
284284

285285
# Use DeepSeek with Anthropic-compatible endpoint
286-
export KODE_PROVIDER=deepseek
287-
export DEEPSEEK_API_KEY="sk-..."
288-
export DEEPSEEK_BASE_URL="https://api.deepseek.com/v1"
286+
export KODE_PROVIDER=anthropic
287+
export ANTHROPIC_API_KEY="sk-..."
288+
export ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
289+
export ANTHROPIC_MODEL="deepseek-chat"
289290
```
290291

291292
### Configuration File (~/.kode/config.yaml)
292293

293294
For persistent configuration, use `~/.kode/config.yaml`:
294295

295296
```yaml
296-
provider: deepseek
297-
model: deepseek-v4-pro
297+
provider: anthropic
298+
model: claude-sonnet-4-20250514
298299

299300
providers:
300301
anthropic:
@@ -306,7 +307,7 @@ providers:
306307
maxRetries: 3
307308
timeoutMs: 120000
308309
deepseek:
309-
baseUrl: https://api.deepseek.com/v1
310+
baseUrl: https://api.deepseek.com/anthropic
310311
maxRetries: 3
311312
timeoutMs: 120000
312313

@@ -326,21 +327,21 @@ You can also use `~/.kode/settings.json` (JSON format) for environment variables
326327
"theme": "dark",
327328
"model_list": [
328329
{
329-
"name": "deepseek-v4-pro",
330-
"model": "deepseek-v4-pro",
331-
"base_url": "https://api.deepseek.com/v1",
332-
"auth_token_env": "DEEPSEEK_API_KEY",
333-
"provider": "deepseek"
334-
},
335-
{
336-
"name": "anthropic/claude-sonnet-4-6",
330+
"name": "claude-sonnet-4-6",
337331
"model": "claude-sonnet-4-6",
338332
"base_url": "https://api.anthropic.com/v1",
339333
"auth_token_env": "ANTHROPIC_API_KEY",
340334
"provider": "anthropic"
335+
},
336+
{
337+
"name": "deepseek/deepseek-v4-pro",
338+
"model": "deepseek-chat",
339+
"base_url": "https://api.deepseek.com/anthropic",
340+
"auth_token_env": "DEEPSEEK_API_KEY",
341+
"provider": "deepseek"
341342
}
342343
],
343-
"default_model": "deepseek-v4-pro"
344+
"default_model": "claude-sonnet-4-6"
344345
}
345346
```
346347

@@ -363,9 +364,9 @@ Place hook definitions in `~/.kode/hooks/*.json`:
363364

364365
Supported events: `SessionStart`, `UserPromptSubmit`, `PreMessage`, `PostMessage`, `PreToolUse`, `PostToolUse`, `PostToolBatch`, `Stop`, `StopFailure`, `PreCompact`, `PostCompact`, `PermissionRequest`, `PermissionDenied`, `Notification`, `SubagentStart`, `SubagentStop`, and more.
365366

366-
### Project Configuration (KODE.md)
367+
### Project Configuration (CLAUDE.md)
367368

368-
Place a `KODE.md` file in your project root for project-specific instructions. Kode Agent automatically loads this as context at the start of every session (also supports `CLAUDE.md` and `CODEBUDDY.md` for compatibility):
369+
Place a `CLAUDE.md` file in your project root for project-specific instructions. Kode Agent automatically loads this as context at the start of every session:
369370

370371
```markdown
371372
# Project Overview
@@ -384,7 +385,7 @@ This is a Next.js e-commerce application with Prisma ORM and PostgreSQL.
384385
- API routes follow RESTful conventions
385386
```
386387
387-
Use `/init` in an interactive session to have Kode Agent auto-generate a `KODE.md` for your project.
388+
Use `/init` in an interactive session to have Kode Agent auto-generate a `CLAUDE.md` for your project.
388389

389390
---
390391

@@ -442,7 +443,7 @@ pnpm ci
442443

443444
## License
444445

445-
[Apache 2.0](LICENSE) © Kode Agent Contributors
446+
MIT © Kode Agent Contributors
446447

447448
---
448449

docs/configuration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ automatically on first run if it doesn't exist.
1212

1313
```yaml
1414
# ── Provider ──────────────────────────────────────────────────────────────
15-
provider: deepseek # deepseek | anthropic | openai
16-
model: deepseek-v4-pro
15+
provider: anthropic # anthropic | deepseek | openai
16+
model: claude-sonnet-4-20250514
1717

1818
# ── Provider-specific settings ────────────────────────────────────────────
1919
providers:
@@ -22,7 +22,7 @@ providers:
2222
maxRetries: 3
2323
timeoutMs: 120000
2424
deepseek:
25-
baseUrl: https://api.deepseek.com/v1
25+
baseUrl: https://api.deepseek.com/anthropic
2626
maxRetries: 3
2727
timeoutMs: 120000
2828
openai:
@@ -304,5 +304,5 @@ compactThreshold: 0.7 # Start compacting at 126K tokens
304304
### Multiple Projects
305305

306306
Configuration is global (`~/.kode/config.yaml`), but project-specific
307-
instructions go in `KODE.md` at the project root. The agent reads this
307+
instructions go in `CLAUDE.md` at the project root. The agent reads this
308308
file at the start of every session.

packages/cli/src/gateway/engine-factory.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export interface EngineFactoryOptions {
8383
apiKey?: string;
8484
/** Base URL override for the provider */
8585
baseUrl?: string;
86-
/** Model identifier (default: from env or 'deepseek-v4-pro') */
86+
/** Model identifier (default: from env or 'claude-sonnet-4-6') */
8787
model?: string;
8888
/** Provider name: "anthropic" | "openai" | "deepseek" | "auto" (default: "anthropic") */
8989
providerName?: string;
@@ -240,8 +240,8 @@ export function createQueryEngine(
240240
const cwd = opts.cwd ?? process.cwd();
241241
const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY ?? '';
242242
const baseUrl = opts.baseUrl ?? process.env.ANTHROPIC_BASE_URL;
243-
const model = opts.model ?? process.env.KODE_MODEL ?? process.env.ANTHROPIC_MODEL ?? 'deepseek-v4-pro';
244-
const providerName = opts.providerName ?? process.env.KODE_PROVIDER ?? 'anthropic';
243+
const model = (opts.model && opts.model !== 'claude-sonnet-4-6') ? opts.model : process.env.KODE_MODEL ?? process.env.ANTHROPIC_MODEL ?? opts.model ?? 'claude-sonnet-4-6';
244+
const providerName = opts.providerName ?? (model.toLowerCase().includes('deepseek') ? 'deepseek' : process.env.KODE_PROVIDER ?? 'anthropic');
245245

246246
// ── Determine agent role ─────────────────────────────────────────
247247
const coordinatorMode = opts.coordinatorMode ?? false;
@@ -371,11 +371,21 @@ export function createQueryEngine(
371371
* @returns A Provider instance
372372
*/
373373
function createProvider(name: string, config: ProviderConfig): Provider {
374+
const isAnthropicEndpoint = config.baseUrl?.includes('/anthropic');
375+
374376
switch (name) {
375377
case 'openai':
376378
return new OpenAICompatProvider(config, 'openai');
377-
case 'deepseek':
379+
case 'deepseek': {
380+
// DeepSeek's /anthropic endpoint uses Anthropic Messages API format, not
381+
// OpenAI Chat Completions. When the base URL targets the /anthropic
382+
// endpoint we must use AnthropicProvider so the SDK sends the correct
383+
// request shape.
384+
if (isAnthropicEndpoint) {
385+
return new AnthropicProvider(config);
386+
}
378387
return new DeepSeekProvider(config);
388+
}
379389
case 'auto': {
380390
// Auto mode: create a router with all providers that have API keys configured
381391
const router = new ProviderRouter();
@@ -386,10 +396,14 @@ function createProvider(name: string, config: ProviderConfig): Provider {
386396
if (openaiKey) {
387397
router.register('openai', new OpenAICompatProvider({ ...config, apiKey: openaiKey }, 'openai'), ['gpt-4o', 'gpt-4o-mini']);
388398
}
389-
// Register DeepSeek if key available
399+
// Register DeepSeek if key available — use the right provider per endpoint
390400
const deepseekKey = process.env.DEEPSEEK_API_KEY;
391401
if (deepseekKey) {
392-
router.register('deepseek', new DeepSeekProvider({ ...config, apiKey: deepseekKey }), ['deepseek-chat', 'deepseek-reasoner']);
402+
const deepseekCfg = { ...config, apiKey: deepseekKey };
403+
const deepseekProvider = isAnthropicEndpoint
404+
? new AnthropicProvider(deepseekCfg)
405+
: new DeepSeekProvider(deepseekCfg);
406+
router.register('deepseek', deepseekProvider, ['deepseek-chat', 'deepseek-reasoner']);
393407
}
394408
// Return a proxy provider that delegates to the router
395409
return createRouterProxy(router, config.apiKey ? 'anthropic' : undefined);
@@ -407,7 +421,7 @@ function createProvider(name: string, config: ProviderConfig): Provider {
407421
function createRouterProxy(router: ProviderRouter, _defaultProvider?: string): Provider {
408422
const routerRef = { current: router };
409423
const providerRef: { current: Provider | null } = { current: null };
410-
const modelRef: { current: string } = { current: 'deepseek-v4-pro' };
424+
const modelRef: { current: string } = { current: 'claude-sonnet-4-6' };
411425

412426
return {
413427
async stream(modelConfig, system, messages, tools, onEvent) {
@@ -455,5 +469,5 @@ export function hasApiKey(): boolean {
455469
* Get the configured model name.
456470
*/
457471
export function getConfiguredModel(): string {
458-
return process.env.KODE_MODEL ?? process.env.ANTHROPIC_MODEL ?? 'deepseek-v4-pro';
472+
return process.env.KODE_MODEL ?? process.env.ANTHROPIC_MODEL ?? 'claude-sonnet-4-6';
459473
}

0 commit comments

Comments
 (0)