Merge commit 'refs/codex/pr1006/master' into worktree/pr1006-merge-20260731

# Conflicts:
#	docs/architecture.i18n.yaml
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/headless-agent/cordis.yml
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/llm/llm-deepseek/README.i18n.yaml
#	packages/llm/llm-deepseek/README.md
#	packages/llm/llm-deepseek/README.zh.md
#	packages/llm/llm-deepseek/src/adapter.ts
#	packages/llm/llm-deepseek/src/index.ts
#	packages/llm/llm-deepseek/tests/adapter.spec.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/llm/llm/README.md
#	packages/llm/llm/README.zh.md
#	packages/subagent/subagent-dsh-sdk/README.i18n.yaml
#	packages/ui/jsonrpc/README.i18n.yaml
This commit is contained in:
Tianyi Cui
2026-07-31 01:55:19 +08:00
664 changed files with 19076 additions and 2562 deletions

View File

@@ -11,7 +11,7 @@ import type { PackageManagerName, RunInterface } from '@deepseek-ai/dsh-helper'
export interface CreateArgs {
directory?: string
description?: string
provider?: 'deepseek' | 'custom'
provider?: 'deepseek-official' | 'custom'
baseURL?: string
apiKey?: string
model?: string
@@ -27,7 +27,7 @@ export interface CreateArgs {
interface CommanderCreateOptions {
description?: string
provider?: 'deepseek' | 'custom'
provider?: 'deepseek-official' | 'custom'
baseUrl?: string
apiKey?: string
model?: string
@@ -57,7 +57,7 @@ function createProgram(): Command {
.argument('[directory]')
.option('-h, --help')
.option('--description <text>')
.addOption(new Option('--provider <name>').choices(['deepseek', 'custom']))
.addOption(new Option('--provider <name>').choices(['deepseek-official', 'custom']))
.option('--base-url <url>')
.option('--api-key <key>')
.option('--model <name>')

View File

@@ -24,7 +24,7 @@ export interface ProjectAnswers {
directory: string
name: string
description: string
provider: 'deepseek' | 'custom'
provider: 'deepseek-official' | 'custom'
baseURL: string
apiKey: string
model: string
@@ -142,14 +142,14 @@ const PROJECT_QUESTION_STEPS: readonly WizardStep<ProjectAnswerState>[] = [
apply: (state, value) => { state.description = value },
}),
questionStep({
question: () => new SelectQuestion<'deepseek' | 'custom'>({
question: () => new SelectQuestion<'deepseek-official' | 'custom'>({
id: 'provider',
message: 'Model provider',
options: [
{ value: 'deepseek', label: 'DeepSeek' },
{ value: 'deepseek-official', label: 'DeepSeek' },
{ value: 'custom', label: 'Custom endpoint (pi-ai)' },
],
initialValue: 'deepseek',
initialValue: 'deepseek-official',
}),
prefilled: state => state.args.provider,
apply: (state, value) => { state.provider = value },

View File

@@ -18,7 +18,7 @@ import type { CreateArgs } from './args.ts'
interface HeadlessCreateSpec {
directory?: string
description?: string
provider?: 'deepseek' | 'custom'
provider?: 'deepseek-official' | 'custom'
baseURL?: string
apiKey?: string
model?: string

View File

@@ -2,7 +2,7 @@ Usage: create-sdk [directory] [options]
Options:
--description <text>
--provider <deepseek|custom>
--provider <deepseek-official|custom>
--base-url <url>
--api-key <key>
--model <name>

View File

@@ -87,7 +87,7 @@ describe.skipIf(process.platform === 'win32')('create-sdk terminal contract', ()
'my-agent',
'my-agent',
'Snapshot agent',
'deepseek',
'deepseek-official',
'secret-key',
'acp',
[
@@ -166,7 +166,7 @@ describe.skipIf(process.platform === 'win32')('create-sdk terminal contract', ()
"message": "Project description",
},
{
"initialValue": "deepseek",
"initialValue": "deepseek-official",
"kind": "select",
"message": "Model provider",
"options": [
@@ -330,7 +330,7 @@ describe.skipIf(process.platform === 'win32')('create-sdk terminal contract', ()
{
"id": "provider",
"options": [
"deepseek",
"deepseek-official",
],
},
{

View File

@@ -131,13 +131,13 @@ afterEach(async () => {
describe('create arguments', () => {
it('parses public options and the private repository link mode', () => {
expect(parseCreateArgs([
'agent', '--description=demo', '--provider', 'deepseek', '--base-url=https://api.example',
'agent', '--description=demo', '--provider', 'deepseek-official', '--base-url=https://api.example',
'--api-key', 'key', '--model=m', '--interface', 'acp', '--pm=pnpm', '--no-install',
'--link-workspace',
])).toEqual({
directory: 'agent',
description: 'demo',
provider: 'deepseek',
provider: 'deepseek-official',
baseURL: 'https://api.example',
apiKey: 'key',
model: 'm',
@@ -205,7 +205,7 @@ describe('CreateWizard and scaffolder', () => {
const args = parseCreateArgs([
'my-agent',
'--description=demo',
'--provider=deepseek',
'--provider=deepseek-official',
'--api-key=deepseek-key',
'--model=deepseek-v4-flash',
'--interface=tui',
@@ -246,7 +246,7 @@ describe('CreateWizard and scaffolder', () => {
]
const resolved = await new CreateWizard({
args: parseCreateArgs([
'my-agent', '--description=demo', '--provider=deepseek', '--api-key=deepseek-key',
'my-agent', '--description=demo', '--provider=deepseek-official', '--api-key=deepseek-key',
'--model=deepseek-v4-flash', '--interface=tui', '--pm=npm', '--no-install',
]),
port: new HeadlessPromptPort(),
@@ -274,7 +274,7 @@ describe('CreateWizard and scaffolder', () => {
] as unknown as FeatureSelection[]
await expect(new CreateWizard({
args: parseCreateArgs([
'my-agent', '--description=demo', '--provider=deepseek', '--api-key=k',
'my-agent', '--description=demo', '--provider=deepseek-official', '--api-key=k',
'--model=m', '--interface=tui', '--pm=npm', '--no-install',
]),
port: new HeadlessPromptPort(),
@@ -295,7 +295,7 @@ describe('CreateWizard and scaffolder', () => {
packageManager: new NpmPackageManager('10.0.0'),
releaseVersion: '0.0.1',
features: [
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'key' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'key' } },
{ id: featureId('bash'), options: ['local'] },
{ id: featureId('app'), options: ['embed'] },
{ id: featureId('persistence'), options: ['jsonl'] },
@@ -346,7 +346,7 @@ describe('CreateWizard and scaffolder', () => {
])
const resolved = await new CreateWizard({
args: parseCreateArgs([
'workflow-agent', '--description=test', '--provider=deepseek', '--api-key=key',
'workflow-agent', '--description=test', '--provider=deepseek-official', '--api-key=key',
'--interface=embed', '--pm=npm', '--no-install',
]),
port,
@@ -371,7 +371,7 @@ describe('CreateWizard and scaffolder', () => {
])
const resolved = await new CreateWizard({
args: parseCreateArgs([
'empty-key-agent', '--description=test', '--provider=deepseek',
'empty-key-agent', '--description=test', '--provider=deepseek-official',
'--interface=embed', '--pm=npm', '--no-install',
]),
port,
@@ -398,7 +398,7 @@ describe('CreateWizard and scaffolder', () => {
'embed',
[
{ value: featureId('persistence'), choices: ['jsonl'] },
{ value: featureId('web'), choices: ['deepseek'] },
{ value: featureId('web'), choices: ['deepseek-official'] },
],
true,
'none',
@@ -426,14 +426,14 @@ describe('CreateWizard and scaffolder', () => {
'agent',
[
{ value: featureId('persistence'), choices: ['jsonl'] },
{ value: featureId('web'), choices: ['deepseek'] },
{ value: featureId('web'), choices: ['deepseek-official'] },
{ value: featureId('timeout-policy'), choices: ['default'] },
],
'none',
])
const resolved = await new CreateWizard({
args: parseCreateArgs([
'agent', '--description=test', '--provider=deepseek', '--api-key=key',
'agent', '--description=test', '--provider=deepseek-official', '--api-key=key',
'--interface=embed', '--pm=npm', '--no-install',
]),
port,
@@ -451,7 +451,7 @@ describe('CreateWizard and scaffolder', () => {
])
const resolved = await new CreateWizard({
args: parseCreateArgs([
name, '--description=test', '--provider=deepseek', '--api-key=key',
name, '--description=test', '--provider=deepseek-official', '--api-key=key',
'--interface=embed', '--pm=npm', '--no-install',
]),
port,
@@ -467,7 +467,7 @@ describe('CreateWizard and scaffolder', () => {
describe('create command composition', () => {
const argv = (directory: string, install: boolean): string[] => [
directory, '--description=test', '--provider=deepseek', '--api-key=key',
directory, '--description=test', '--provider=deepseek-official', '--api-key=key',
'--interface=embed', '--pm=npm', install ? '--install' : '--no-install',
]
@@ -490,7 +490,7 @@ describe('create command composition', () => {
const root = await mkdtemp(join(tmpdir(), 'create-headless-cmd-'))
temporary.push(root)
const spec = JSON.stringify({
directory: 'agent', description: 'test', provider: 'deepseek', apiKey: 'key',
directory: 'agent', description: 'test', provider: 'deepseek-official', apiKey: 'key',
model: 'deepseek-v4-flash', interface: 'embed', pm: 'npm', install: false,
features: [{ id: 'persistence', options: ['jsonl'] }],
})
@@ -510,7 +510,7 @@ describe('create command composition', () => {
const ok = commandContext(root)
ok.stdin.isTTY = false
ok.stdout.isTTY = false
const okSpec = JSON.stringify({ ...base, directory: 'done-agent', provider: 'deepseek', apiKey: 'key', features: [] })
const okSpec = JSON.stringify({ ...base, directory: 'done-agent', provider: 'deepseek-official', apiKey: 'key', features: [] })
await expect(runCreateCommand(['--config-json', okSpec, '--json'], ok)).resolves.toBe(0)
expect(ok.readStdout()).toContain('{"type":"done"}')
// stdout stays pure NDJSON: every line parses, human progress goes to stderr
@@ -573,7 +573,7 @@ describe('create command composition', () => {
expect(install).toHaveBeenCalledOnce()
expect(build).toHaveBeenCalledOnce()
const spec = JSON.stringify({
directory: 'json-agent', description: 'test', provider: 'deepseek', apiKey: 'key',
directory: 'json-agent', description: 'test', provider: 'deepseek-official', apiKey: 'key',
model: 'deepseek-v4-flash', interface: 'embed', pm: 'npm', install: true, features: [],
})
const json = commandContext(root)

View File

@@ -64,7 +64,7 @@ describe.skipIf(!existsSync(builtScripts))('live-linked generated projects', ()
releaseVersion: '0.0.1',
linkWorkspaceRoot: repoRoot,
features: [
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'test-key' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'test-key' } },
{ id: featureId('bash'), options: ['local'] },
{ id: featureId('app'), options: ['embed'] },
{ id: featureId('persistence'), options: ['jsonl'] },

View File

@@ -154,7 +154,7 @@ config:
],
options: [
{
id: 'deepseek',
id: 'deepseek-official',
label: 'DeepSeek search',
default: true,
markers: [{ id: 'web-search-deepseek', name: '@deepseek-ai/dsh-web-search-deepseek' }],

View File

@@ -20,7 +20,7 @@ const DEFAULT_MODEL = 'deepseek-v4-flash'
const API_KEY_COMMENT = 'Required before start; an empty value makes provider startup fail.'
class DeepSeekOption extends FeatureOption {
override readonly id = 'deepseek'
override readonly id = 'deepseek-official'
override readonly label = 'DeepSeek'
override readonly secrets = [{
id: 'apiKey',
@@ -76,7 +76,7 @@ export class ProviderFeature extends ExclusiveOptionFeature {
/** Prefer the direct-fetch adapter and its public endpoint defaults. */
override defaultOptions(): readonly string[] {
return ['deepseek']
return ['deepseek-official']
}
/** Recover literal endpoint overrides from either provider entry. */

View File

@@ -61,7 +61,7 @@ function request(
packageManager: new NpmPackageManager('10.0.0'),
releaseVersion: '0.0.1',
features: [
selection('provider', ['deepseek'], { apiKey: 'test-key' }),
selection('provider', ['deepseek-official'], { apiKey: 'test-key' }),
selection('bash', [bash]),
selection('app', [app]),
selection('persistence', ['jsonl']),
@@ -344,7 +344,7 @@ describe('SdkProject and ProjectEditSession', () => {
const edit = project.edit(registry)
expect(edit.inspections()).not.toHaveLength(0)
const todo = registry.get(featureId('todo'))
edit.configureFeature(registry.get(featureId('web')), selection('web', ['deepseek']))
edit.configureFeature(registry.get(featureId('web')), selection('web', ['deepseek-official']))
edit.disableFeature(todo)
edit.configureFeature(todo, selection('todo', ['default']))
edit.enableFeature(todo)
@@ -598,7 +598,7 @@ describe('SdkProject and ProjectEditSession', () => {
expect(installation.diagnostics).toContain('missing package.json dependencies entry @deepseek-ai/dsh-llm-deepseek')
const partialEdit = partial.edit(createBuiltinRegistry(partial.profile))
const provider = createBuiltinRegistry(partial.profile).get(featureId('provider'))
expect(() => { partialEdit.configureFeature(provider, selection('provider', ['deepseek'])) }).toThrow('inconsistent')
expect(() => { partialEdit.configureFeature(provider, selection('provider', ['deepseek-official'])) }).toThrow('inconsistent')
expect(() => { partialEdit.enableFeature(provider) }).toThrow('inconsistent')
expect(() => { partialEdit.disableFeature(provider) }).toThrow('required feature')
})
@@ -615,7 +615,7 @@ describe('SdkProject and ProjectEditSession', () => {
const edit = project.edit(builtin)
const web = builtin.get(featureId('web'))
expect(() => { edit.disableFeature(web) }).toThrow('inconsistent')
expect(() => { edit.installFeature(web, selection('web', ['deepseek'])) }).toThrow('inconsistent')
expect(() => { edit.installFeature(web, selection('web', ['deepseek-official'])) }).toThrow('inconsistent')
class RequiresWeb extends FixedFeature {
override readonly id = featureId('requires-web')
@@ -656,7 +656,7 @@ describe('SdkProject and ProjectEditSession', () => {
const project = await createCommitted([selection('web', ['exa'], { apiKey: 'exa' })])
const registry = createBuiltinRegistry(project.profile)
const edit = project.edit(registry)
edit.configureFeature(registry.get(featureId('web')), selection('web', ['deepseek']))
edit.configureFeature(registry.get(featureId('web')), selection('web', ['deepseek-official']))
expect(edit.readEnvironment('.env.example', 'EXA_API_KEY')).toBeUndefined()
})
@@ -676,7 +676,7 @@ describe('SdkProject and ProjectEditSession', () => {
const edit = reopened.edit(registry)
edit.configureFeature(
registry.get(featureId('provider')),
selection('provider', ['deepseek'], { apiKey: 'replacement' }),
selection('provider', ['deepseek-official'], { apiKey: 'replacement' }),
)
edit.installFeature(registry.get(featureId('web')), selection('web', ['exa'], { apiKey: 'exa-key' }))
const withExa = (await edit.commit()).project
@@ -686,7 +686,7 @@ describe('SdkProject and ProjectEditSession', () => {
}
const nextRegistry = createBuiltinRegistry(withExa.profile)
const remove = withExa.edit(nextRegistry)
remove.configureFeature(nextRegistry.get(featureId('web')), selection('web', ['deepseek']))
remove.configureFeature(nextRegistry.get(featureId('web')), selection('web', ['deepseek-official']))
await remove.commit()
expect(await readFile(join(withExa.root, '.env'), 'utf8')).toBe(`${original}EXA_API_KEY=exa-key\n`)
})
@@ -936,12 +936,12 @@ describe('extension points', () => {
expect(spineAgentLoop?.validateConfig?.({ agents: 'main' })).toEqual(['agents must be an array'])
expect(spineAgentLoop?.validateConfig?.({ agents: ['main'] })).toEqual(['agents must be empty'])
expect(spineAgentLoop?.validateConfig?.({ agents: [] })).toEqual([])
expect(builtins.get(featureId('provider')).defaultOptions(profile)).toEqual(['deepseek'])
expect(builtins.get(featureId('provider')).defaultOptions(profile)).toEqual(['deepseek-official'])
expect(() => builtins.get(featureId('provider')).contribution({
id: featureId('provider'), options: ['custom'], values: { baseURL: 1 },
}, profile)).toThrow('baseURL must be a string')
const alternateModel = builtins.get(featureId('provider')).contribution({
id: featureId('provider'), options: ['deepseek'],
id: featureId('provider'), options: ['deepseek-official'],
}, { ...profile, runtime: { model: 'other' } }).resources
.find(resource => resource.kind === 'cordis-config-entry')
expect(alternateModel?.entry.config?.models).toEqual(['other'])

View File

@@ -383,7 +383,7 @@ describe('feature configurator', () => {
it('shares exclusive, multiple, fixed, and secret behavior', async () => {
const registry = createBuiltinRegistry(profile)
const port = new QueuePromptPort(['sqlite', ['spawn', 'fork'], 'deepseek', 'new-key'])
const port = new QueuePromptPort(['sqlite', ['spawn', 'fork'], 'deepseek-official', 'new-key'])
const configurator = new FeatureConfigurator(port)
await expect(configurator.configure(registry.get(featureId('persistence')), profile)).resolves.toMatchObject({
options: ['sqlite'],
@@ -394,7 +394,7 @@ describe('feature configurator', () => {
await expect(configurator.configure(
registry.get(featureId('provider')),
profile,
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'old-key' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'old-key' } },
)).resolves.toMatchObject({ secrets: { apiKey: 'new-key' } })
expect(port.requests).toEqual([
'Choose durable session storage',
@@ -412,13 +412,13 @@ describe('feature configurator', () => {
})
const requiredSecret = new FeatureConfigurator(new QueuePromptPort([]))
await expect(requiredSecret.configure(
registry.get(featureId('provider')), profile, undefined, ['deepseek'], { apiKey: '' },
registry.get(featureId('provider')), profile, undefined, ['deepseek-official'], { apiKey: '' },
)).rejects.toThrow('required')
const keep = new FeatureConfigurator(new QueuePromptPort(['deepseek', '']))
const keep = new FeatureConfigurator(new QueuePromptPort(['deepseek-official', '']))
await expect(keep.configure(
registry.get(featureId('provider')),
profile,
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'old' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'old' } },
)).resolves.toMatchObject({ secrets: { apiKey: 'old' } })
const custom = registry.get(featureId('provider'))
await expect(new FeatureConfigurator(new QueuePromptPort(['custom'])).configure(

View File

@@ -34,7 +34,7 @@ Change file: package.json
{
"default": true,
"label": "DeepSeek",
"value": "deepseek",
"value": "deepseek-official",
},
{
"default": false,
@@ -173,7 +173,7 @@ Change file: package.json
{
"default": true,
"label": "DeepSeek search",
"value": "deepseek",
"value": "deepseek-official",
},
{
"default": false,

View File

@@ -92,7 +92,7 @@ async function baseProject(): Promise<SdkProject> {
packageManager: new NpmPackageManager('10.0.0'),
releaseVersion: '0.0.1',
features: [
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'key' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'key' } },
{ id: featureId('bash'), options: ['local'] },
{ id: featureId('app'), options: ['tui'] },
{ id: featureId('persistence'), options: ['jsonl'] },

View File

@@ -94,7 +94,7 @@ function creation(
packageManager: new NpmPackageManager('10.0.0'),
releaseVersion: '0.0.1',
features: [
{ id: featureId('provider'), options: ['deepseek'], secrets: { apiKey: 'key' } },
{ id: featureId('provider'), options: ['deepseek-official'], secrets: { apiKey: 'key' } },
{ id: featureId('bash'), options: ['local'] },
{ id: featureId('app'), options: [app] },
{ id: featureId('persistence'), options: ['jsonl'] },
@@ -550,7 +550,7 @@ describe('ConfigWorkflow', () => {
const output = outputBuffer()
const workflow = new ConfigWorkflow(new QueuePort([
[
{ value: 'feature:provider', choices: ['deepseek'] },
{ value: 'feature:provider', choices: ['deepseek-official'] },
{ value: 'feature:app', choices: ['acp'] },
{ value: 'feature:persistence', choices: ['jsonl'] },
{ value: 'feature:ask-user', choices: ['default'] },

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/sdk/sdk-client/README.md
README.md: 3ac4de540401f6f40dab3e84f7005f91d024aee8
README.zh.md: 95fb6b2887a7bc748a610f7fedae4be1aa2af623
README.md: eb0387292fb0093b3ed9360e8aec087201b611f0
README.zh.md: 3745d2bd3aba72942a0c69b8669ea707bd429188

View File

@@ -13,7 +13,7 @@ import { DeepSeekHarness } from '@deepseek-ai/dsh-sdk-client'
await using harness = new DeepSeekHarness({
launch: { command: 'node', args: ['lib/bin.js', 'cordis.yml'] },
provider: 'deepseek',
provider: 'deepseek-official',
model: 'deepseek-v4-flash',
maxTokens: 49_152,
})

View File

@@ -13,7 +13,7 @@ import { DeepSeekHarness } from '@deepseek-ai/dsh-sdk-client'
await using harness = new DeepSeekHarness({
launch: { command: 'node', args: ['lib/bin.js', 'cordis.yml'] },
provider: 'deepseek',
provider: 'deepseek-official',
model: 'deepseek-v4-flash',
maxTokens: 49_152,
})

View File

@@ -37,7 +37,7 @@ export class DeepSeekHarness implements AsyncDisposable {
// process's cwd, but the wire cwd is resolved again inside the child — a
// relative value would double-resolve (e.g. `worker` → `worker/worker`).
this.cwd = resolve(options.cwd ?? options.launch.cwd ?? process.cwd())
this.provider = options.provider ?? 'deepseek'
this.provider = options.provider ?? 'deepseek-official'
this.model = options.model ?? 'deepseek-v4-flash'
this.maxTokens = options.maxTokens
}

View File

@@ -51,7 +51,7 @@ export interface DeepSeekHarnessOptions {
launch: HarnessClientOptions
/** Workspace cwd recorded on every SDK-created session (default: the launch cwd, else `process.cwd()`). */
cwd?: string
/** Provider route for SDK-created agents (default `deepseek`). */
/** Provider route for SDK-created agents (default `deepseek-official`). */
provider?: string
/** Model for SDK-created agents (default `deepseek-v4-flash`). */
model?: string