Files
deepseek-harness/packages/core/agent-default-model/tests/agent-default-model.spec.ts
imccyu ec601ca13d build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.

Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.

The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.

Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:13 +08:00

99 lines
3.8 KiB
TypeScript

/** Default Agent model settings layered over a real settings provider. */
import { describe, expect, it } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import AgentDefaultModelService, { AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE } from '../src/index.ts'
import { Settings } from '@deepseek-ai/dsh-settings'
import type { SettingsNamespace } from '@deepseek-ai/dsh-settings'
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
/** The smallest real provider: one in-memory document, always writable. */
class MemorySettings extends Settings {
doc: Record<string, unknown> = {}
get writable(): boolean {
return true
}
protected load(): Promise<Record<string, unknown>> {
return Promise.resolve(structuredClone(this.doc))
}
protected persist(ns: SettingsNamespace, section: Record<string, unknown>): Promise<void> {
this.doc = { ...this.doc, [ns]: structuredClone(section) }
return Promise.resolve()
}
}
async function boot(): Promise<{
ctx: Context
settingsFiber: Context['fiber']
defaultModel: AgentDefaultModelService
}> {
const ctx = new Context()
const settingsFiber = ctx.plugin(MemorySettings)
await settingsFiber.await()
await ctx.plugin(AgentDefaultModelService, {
provider: 'deepseek-official',
model: 'deepseek-v4-flash',
})
return { ctx, settingsFiber, defaultModel: ctx.agentDefaultModel }
}
describe('AgentDefaultModelService', () => {
it('resolves the user layer over the composition entry', async () => {
const bench = await boot()
expect(bench.defaultModel.currentSelection()).toEqual({
provider: 'deepseek-official', model: 'deepseek-v4-flash',
})
await bench.defaultModel.saveSelection({
provider: 'acme-gateway', model: 'acme-large', reasoningEffort: ReasoningEffortId('high'),
})
expect(bench.defaultModel.currentSelection()).toEqual({
provider: 'acme-gateway', model: 'acme-large', reasoningEffort: 'high',
})
await bench.ctx.fiber.dispose()
})
it('clears a stored effort when the saved selection has none', async () => {
const bench = await boot()
await bench.defaultModel.saveSelection({
provider: 'acme-gateway', model: 'acme-large', reasoningEffort: ReasoningEffortId('high'),
})
await bench.defaultModel.saveSelection({ provider: 'acme-gateway', model: 'acme-plain' })
expect(bench.defaultModel.currentSelection()).toEqual({ provider: 'acme-gateway', model: 'acme-plain' })
await bench.ctx.fiber.dispose()
})
it('layers a hand-written partial section over the entry', async () => {
const bench = await boot()
await bench.settingsFiber.ctx.settings.replace(AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, {
model: 'deepseek-reasoner',
})
expect(bench.defaultModel.currentSelection()).toEqual({
provider: 'deepseek-official', model: 'deepseek-reasoner',
})
await bench.ctx.fiber.dispose()
})
it('falls back to the composition entry when the settings provider detaches', async () => {
const bench = await boot()
await bench.defaultModel.saveSelection({ provider: 'acme-gateway', model: 'acme-large' })
expect(bench.defaultModel.currentSelection().provider).toBe('acme-gateway')
await bench.settingsFiber.dispose()
expect(bench.defaultModel.currentSelection()).toEqual({
provider: 'deepseek-official', model: 'deepseek-v4-flash',
})
await bench.ctx.fiber.dispose()
})
it('keeps the composition entry when no settings provider is mounted', async () => {
const ctx = new Context()
await ctx.plugin(AgentDefaultModelService, { provider: 'p', model: 'm' })
await ctx.agentDefaultModel.saveSelection({ provider: 'other', model: 'other' })
expect(ctx.agentDefaultModel.currentSelection()).toEqual({ provider: 'p', model: 'm' })
await ctx.fiber.dispose()
})
})