Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input
# Conflicts: # docs/architecture.i18n.yaml # docs/architecture.md # docs/architecture.zh.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/llm-streaming.i18n.yaml # docs/event-producer-consumer.md # docs/module-graph.md # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # packages/client/connection/README.i18n.yaml # packages/client/connection/README.md # packages/client/connection/README.zh.md # packages/client/connection/src/client/fixture.ts # packages/client/runtime/README.i18n.yaml # packages/client/runtime/README.md # packages/client/runtime/README.zh.md # packages/client/ui-conversation/README.i18n.yaml # packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx # packages/client/ui-conversation/src/client/chat/ChatView.tsx # packages/host/apiproxy/README.i18n.yaml # packages/host/apiproxy/src/api-proxy.ts # packages/llm/llm-deepseek/tests/adapter.spec.ts # packages/llm/llm-pi-ai/README.i18n.yaml # packages/llm/llm-pi-ai/src/index.ts # packages/llm/llm/README.i18n.yaml # packages/llm/llm/README.md # packages/llm/llm/README.zh.md # packages/llm/llm/src/index.ts # packages/llm/llm/src/types.ts
This commit is contained in:
@@ -234,7 +234,8 @@ export function assertEntriesActive(ctx: Context, binName: string): void {
|
||||
* @param patches - optional overlay patches applied over the included tree
|
||||
* (see {@link loadPersonalPatches}); an empty list mounts none.
|
||||
* @param prepare - optional host setup run after Loader installation and before any config-tree entry mounts.
|
||||
* @returns the root context once every entry has started.
|
||||
* @returns the root context once every entry has started, or as soon as a
|
||||
* surface disposed the tree while startup was still in flight.
|
||||
*/
|
||||
export async function boot(
|
||||
binName: string,
|
||||
@@ -255,6 +256,13 @@ export async function boot(
|
||||
},
|
||||
})
|
||||
await ctx.loader.await()
|
||||
// A surface can finish and dispose the whole tree while that await is still
|
||||
// pending: the TUI renders as soon as its own fiber starts, so an `/exit`
|
||||
// typed before the last entry settles tears the context down under us. The
|
||||
// Loader service goes with it, and both assertions below describe a live
|
||||
// tree — reading `ctx.loader` here would throw a TypeError over an app that
|
||||
// exited exactly as asked.
|
||||
if (ctx.get('loader') === undefined) return ctx
|
||||
assertEntriesLoaded(ctx, binName)
|
||||
assertEntriesActive(ctx, binName)
|
||||
return ctx
|
||||
|
||||
@@ -207,6 +207,25 @@ describe('boot', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('returns instead of asserting over a tree a surface disposed mid-startup', async () => {
|
||||
// What a TUI `/exit` does (ui-tui's disposeRootAndExit): dispose the root
|
||||
// fiber, which lands while boot() is still awaiting the Loader whenever the
|
||||
// surface renders before the last entry settles. The Loader service goes
|
||||
// with the tree, so reading it for the post-boot assertions would crash an
|
||||
// app that exited exactly as the user asked.
|
||||
const dir = tmp()
|
||||
writeFileSync(join(dir, 'exiting.mjs'), [
|
||||
'export const name = "exiting"',
|
||||
'export function apply(ctx) {',
|
||||
' void ctx.root.fiber.dispose()',
|
||||
'}',
|
||||
'',
|
||||
].join('\n'))
|
||||
writeFileSync(join(dir, 'cordis.yml'), '- id: exiting\n name: ./exiting.mjs\n')
|
||||
const ctx = await boot(NAME, join(dir, 'cordis.yml'))
|
||||
expect(ctx.get('loader')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('rejects (never exits 0 half-empty) when a config names a plugin that cannot be imported', async () => {
|
||||
const dir = tmp()
|
||||
writeFileSync(join(dir, 'cordis.yml'), '- id: ghost\n name: ./missing.mjs\n')
|
||||
|
||||
@@ -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/ui/jsonrpc/README.md
|
||||
README.md: b1219ba10269fc7d046da22c280ff1b91424a5ae
|
||||
README.zh.md: 1c27f5edf2f1f172aa6303697b17e2e77a65842a
|
||||
README.md: ac47af28e69e647ba44a7718478db163d406f5dc
|
||||
README.zh.md: 2ab600dce52f471d8eef63848e6283217008dcf6
|
||||
|
||||
@@ -6,7 +6,7 @@ The `jsonrpc` plugin serves newline-delimited JSON-RPC over stdio so out-of-proc
|
||||
|
||||
## Wiring
|
||||
|
||||
`inject: ['agents']`. The server gets or creates one agent per `sessionId`. It forwards subagent completions only when the service-snapshotted lifecycle `local` flag is true; provider names, child ids, and durable lineage never establish locality. A registered adapter wins, an unowned `deepseek` route mounts `dsh-llm-deepseek`, and any other unowned provider fails initialization. Other capabilities come from the surrounding `cordis.yml`.
|
||||
`inject: ['agents']`. The server gets or creates one agent per `sessionId`. It forwards subagent completions only when the service-snapshotted lifecycle `local` flag is true; provider names, child ids, and durable lineage never establish locality. A registered adapter wins, an unowned `deepseek-official` route mounts `dsh-llm-deepseek`, and any other unowned provider fails initialization. Other capabilities come from the surrounding `cordis.yml`.
|
||||
|
||||
## Config
|
||||
|
||||
@@ -22,7 +22,7 @@ The plugin answers `shutdown`, disposes SDK-owned agents and subscriptions to qu
|
||||
|
||||
## Wire notes
|
||||
|
||||
`initialize.serverInfo.name` is the wire-stable `deepseek-harness-sdk-runtime`. An optional positive `initialize.maxTokens` becomes the request output cap of each SDK-created agent and its in-process descendants; invalid values reject initialization, while omission sends no cap and preserves provider defaults. A session accepts one in-flight prompt; overlap fails immediately, other sessions remain independent, and the session is reusable after settlement. `session.finished` reports that prompt's message-triggered turn outcome; later between-turn records still stream as `session.event` notifications but cannot replace the prompt status. Persistence roots and persona come from `cordis.yml`.
|
||||
`initialize.serverInfo.name` is the wire-stable `deepseek-harness-sdk-runtime`. An optional positive `initialize.maxTokens` becomes the request output cap of each SDK-created agent and its in-process descendants; invalid values reject initialization, while omission sends no SDK cap and allows the selected adapter or provider route default to apply. A session accepts one in-flight prompt; overlap fails immediately, other sessions remain independent, and the session is reusable after settlement. `session.finished` reports that prompt's message-triggered turn outcome; later between-turn records still stream as `session.event` notifications but cannot replace the prompt status. Persistence roots and persona come from `cordis.yml`.
|
||||
|
||||
## Model Experience
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## 组装
|
||||
|
||||
`inject: ['agents']`。服务器按 `sessionId` 获取或创建一个 agent。只有服务对生命周期建立快照时记录的 `local` 标志为 true,服务器才会转发 subagent 完成事件;提供方名称、子级 id 和持久化谱系均不能证明本地性。已注册的适配器优先;尚无适配器负责的 `deepseek` 路由会挂载 `dsh-llm-deepseek`,任何其他尚无适配器负责的提供方都会导致初始化失败。其他功能由外围 `cordis.yml` 提供。
|
||||
`inject: ['agents']`。服务器按 `sessionId` 获取或创建一个 agent。只有服务对生命周期建立快照时记录的 `local` 标志为 true,服务器才会转发 subagent 完成事件;提供方名称、子级 id 和持久化谱系均不能证明本地性。已注册的适配器优先;尚无适配器负责的 `deepseek-official` 路由会挂载 `dsh-llm-deepseek`,任何其他尚无适配器负责的提供方都会导致初始化失败。其他功能由外围 `cordis.yml` 提供。
|
||||
|
||||
## 配置
|
||||
|
||||
@@ -22,7 +22,7 @@ Stdout 只承载 JSON-RPC 帧。部署不得组合 stdout logger;诊断应写
|
||||
|
||||
## 协议说明
|
||||
|
||||
`initialize.serverInfo.name` 的协议稳定值为 `deepseek-harness-sdk-runtime`。可选的正整数 `initialize.maxTokens` 会成为每个 SDK 创建的 agent 及其进程内后代的请求输出上限;非法值会使初始化失败,省略时则不发送上限并保留提供方默认值。一个会话只接受一个进行中的提示词;重叠请求会立即失败,其他会话保持独立,当前请求结算后该会话可再次使用。`session.finished` 报告由该提示词消息触发的轮次结果;后续轮次间记录仍会作为 `session.event` 通知流式发出,但不能替换该提示词的状态。持久化根目录和 persona 由 `cordis.yml` 提供。
|
||||
`initialize.serverInfo.name` 的协议稳定值为 `deepseek-harness-sdk-runtime`。可选的正整数 `initialize.maxTokens` 会成为每个 SDK 创建的 agent 及其进程内后代的请求输出上限;非法值会使初始化失败,省略时则不发送 SDK 上限,并应用所选适配器或提供方路由的默认值。一个会话只接受一个进行中的提示词;重叠请求会立即失败,其他会话保持独立,当前请求结算后该会话可再次使用。`session.finished` 报告由该提示词消息触发的轮次结果;后续轮次间记录仍会作为 `session.event` 通知流式发出,但不能替换该提示词的状态。持久化根目录和 persona 由 `cordis.yml` 提供。
|
||||
|
||||
## 模型体验
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ function successStatus(reason: string, options: HarnessSdkServerOptions): 'ok' |
|
||||
*/
|
||||
export class HarnessSdkServer {
|
||||
private cwd = process.cwd()
|
||||
private provider = 'deepseek'
|
||||
private model = 'deepseek'
|
||||
private provider = 'deepseek-official'
|
||||
private model = 'deepseek-official'
|
||||
private maxTokens: number | undefined
|
||||
private llmFiber: { dispose(): Promise<void> } | undefined
|
||||
private readonly sessions = new Map<string, SessionRecord>()
|
||||
@@ -124,7 +124,7 @@ export class HarnessSdkServer {
|
||||
this.model = params.model
|
||||
this.maxTokens = params.maxTokens
|
||||
if (!this.hasAdapterFor(this.provider)) {
|
||||
if (this.provider !== 'deepseek') throw new Error(`no adapter registered for provider "${this.provider}"`)
|
||||
if (this.provider !== 'deepseek-official') throw new Error(`no adapter registered for provider "${this.provider}"`)
|
||||
this.llmFiber = await this.ctx.plugin(LlmDeepSeek, {})
|
||||
}
|
||||
return { serverInfo: { name: 'deepseek-harness-sdk-runtime', version: '0.0.1' } }
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('dsh-jsonrpc plugin apply', () => {
|
||||
vi.stubEnv('DEEPSEEK_API_KEY', 'test-key')
|
||||
const harness = await mountPlugin(storageDir)
|
||||
try {
|
||||
harness.send({ jsonrpc: '2.0', id: 'init-1', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek', model: 'apply-model' } })
|
||||
harness.send({ jsonrpc: '2.0', id: 'init-1', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek-official', model: 'apply-model' } })
|
||||
|
||||
const response = await harness.waitForFrame(frame => frame.id === 'init-1', 'initialize response')
|
||||
expect(response).toEqual({
|
||||
@@ -175,7 +175,7 @@ describe('dsh-jsonrpc plugin apply', () => {
|
||||
vi.stubEnv('DEEPSEEK_BASE_URL', llmServer.url)
|
||||
const harness = await mountPlugin(storageDir)
|
||||
try {
|
||||
harness.send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { cwd: storageDir, provider: 'deepseek', model: 'dsagent-model' } })
|
||||
harness.send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { cwd: storageDir, provider: 'deepseek-official', model: 'dsagent-model' } })
|
||||
await harness.waitForFrame(frame => frame.id === 1, 'initialize response')
|
||||
|
||||
harness.send({
|
||||
@@ -236,7 +236,7 @@ describe('dsh-jsonrpc plugin apply', () => {
|
||||
expect(harness.exits()).toEqual([0])
|
||||
|
||||
const before = harness.frames().length
|
||||
harness.send({ jsonrpc: '2.0', id: 'after-exit', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek', model: 'x' } })
|
||||
harness.send({ jsonrpc: '2.0', id: 'after-exit', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek-official', model: 'x' } })
|
||||
await settle()
|
||||
expect(harness.frames().length).toBe(before)
|
||||
} finally {
|
||||
@@ -257,7 +257,7 @@ describe('dsh-jsonrpc plugin apply', () => {
|
||||
expect(harness.outputErrors.map(error => error.message)).toEqual(['flush callback failed'])
|
||||
|
||||
const before = harness.frames().length
|
||||
harness.send({ jsonrpc: '2.0', id: 'after-flush-failure', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek', model: 'x' } })
|
||||
harness.send({ jsonrpc: '2.0', id: 'after-flush-failure', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek-official', model: 'x' } })
|
||||
await settle()
|
||||
expect(harness.frames().length).toBe(before)
|
||||
} finally {
|
||||
@@ -281,7 +281,7 @@ describe('dsh-jsonrpc plugin apply', () => {
|
||||
await harness.fiber.dispose()
|
||||
|
||||
const before = harness.frames().length
|
||||
harness.send({ jsonrpc: '2.0', id: 'probe-2', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek', model: 'x' } })
|
||||
harness.send({ jsonrpc: '2.0', id: 'probe-2', method: 'initialize', params: { cwd: storageDir, provider: 'deepseek-official', model: 'x' } })
|
||||
await settle()
|
||||
expect(harness.frames().length).toBe(before)
|
||||
expect(harness.exits()).toEqual([])
|
||||
|
||||
@@ -121,7 +121,7 @@ describe('HarnessSdkServer', () => {
|
||||
|
||||
const init = await server.handleRequest('initialize', {
|
||||
cwd: storageDir,
|
||||
provider: 'deepseek',
|
||||
provider: 'deepseek-official',
|
||||
model: 'dsagent-model',
|
||||
maxTokens: 321,
|
||||
}) as { serverInfo: { name: string } }
|
||||
@@ -154,7 +154,7 @@ describe('HarnessSdkServer', () => {
|
||||
const orphanHandle = await ctx.agents.create({
|
||||
sessionId: SessionId('orphan-session'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { provider: 'deepseek', model: 'dsagent-model' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'dsagent-model' },
|
||||
})
|
||||
orphanHandle.agent.followup(createUserMessage({ content: [{ type: 'text', text: 'outside the sdk session map' }], source: { kind: 'user' } }))
|
||||
await orphanHandle.agent.whenIdle()
|
||||
@@ -352,7 +352,7 @@ describe('HarnessSdkServer', () => {
|
||||
try {
|
||||
const server = new HarnessSdkServer(ctx, new FakeTransport())
|
||||
|
||||
await server.initialize({ cwd: storageDir, provider: 'deepseek', model: 'plain-model' })
|
||||
await server.initialize({ cwd: storageDir, provider: 'deepseek-official', model: 'plain-model' })
|
||||
await server.prompt({
|
||||
sessionId: 'plain',
|
||||
contentBlocks: [{ type: 'text', text: 'hello' }],
|
||||
@@ -376,20 +376,20 @@ describe('HarnessSdkServer', () => {
|
||||
const parentHandle = await ctx.agents.create({
|
||||
sessionId: SessionId('main'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-official' },
|
||||
})
|
||||
// A custom in-process provider may own its child at the provider/root
|
||||
// scope while preserving durable parent lineage.
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId('child-session'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('main') },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-official' },
|
||||
})
|
||||
expect(ctx.agents.roots()).toContain(handle.agent)
|
||||
const parentlessHandle = await parentHandle.agent.ctx.agents.create({
|
||||
sessionId: SessionId('parentless-child-session'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
await settleSubagent(ctx, parentHandle.agent, {
|
||||
provider: 'spawn',
|
||||
@@ -446,12 +446,12 @@ describe('HarnessSdkServer', () => {
|
||||
const parentHandle = await ctx.agents.create({
|
||||
sessionId: SessionId('collision-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const collidingChild = await parentHandle.agent.ctx.agents.create({
|
||||
sessionId: SessionId('remote-run-id'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('collision-parent') },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
|
||||
await settleSubagent(ctx, parentHandle.agent, {
|
||||
@@ -485,12 +485,12 @@ describe('HarnessSdkServer', () => {
|
||||
const parentHandle = await ctx.agents.create({
|
||||
sessionId: SessionId('continuation-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const childHandle = await parentHandle.agent.ctx.agents.create({
|
||||
sessionId: SessionId('continuation-child'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('continuation-parent') },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
|
||||
await settleSubagent(ctx, parentHandle.agent, {
|
||||
@@ -530,12 +530,12 @@ describe('HarnessSdkServer', () => {
|
||||
const oldParent = await ctx.agents.create({
|
||||
sessionId: SessionId('old-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const oldChild = await oldParent.agent.ctx.agents.create({
|
||||
sessionId: SessionId('reused-child'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('old-parent') },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const first = Promise.withResolvers<SubagentResult>()
|
||||
const sameLifetime = Promise.withResolvers<SubagentResult>()
|
||||
@@ -571,12 +571,12 @@ describe('HarnessSdkServer', () => {
|
||||
const newParent = await ctx.agents.create({
|
||||
sessionId: SessionId('new-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const newChild = await newParent.agent.ctx.agents.create({
|
||||
sessionId: SessionId('reused-child'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('new-parent') },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
currentLocalAgent = newChild.agent
|
||||
const secondRun = await ctx.subagents.start('reused', {
|
||||
@@ -629,12 +629,12 @@ describe('HarnessSdkServer', () => {
|
||||
const parent = await ctx.agents.create({
|
||||
sessionId: SessionId('provider-reuse-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const child = await parent.agent.ctx.agents.create({
|
||||
sessionId: SessionId('provider-reuse-child'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('provider-reuse-parent') },
|
||||
agentOptions: { model: 'deepseek' },
|
||||
agentOptions: { model: 'deepseek-official' },
|
||||
})
|
||||
const localResult = Promise.withResolvers<SubagentResult>()
|
||||
const remoteResult = Promise.withResolvers<SubagentResult>()
|
||||
@@ -722,18 +722,18 @@ describe('HarnessSdkServer', () => {
|
||||
parentHandle = await ctx.agents.create({
|
||||
sessionId: SessionId('fallback-parent'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-official' },
|
||||
})
|
||||
handle = await parentHandle.agent.ctx.agents.create({
|
||||
sessionId: SessionId('fallback-child-session'),
|
||||
meta: { cwd: storageDir, parentSession: SessionId('fallback-parent') },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-official' },
|
||||
})
|
||||
const fallbackChild = handle.agent
|
||||
failedHandle = await parentHandle.agent.ctx.agents.create({
|
||||
sessionId: SessionId('failed-child-session'),
|
||||
meta: { cwd: storageDir },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-official' },
|
||||
})
|
||||
const missedStartResult = Promise.withResolvers<SubagentResult>()
|
||||
const disposeMissedStartProvider = ctx.subagents.registerProvider({
|
||||
@@ -831,11 +831,11 @@ describe('HarnessSdkServer', () => {
|
||||
const server = new HarnessSdkServer(ctx, new FakeTransport())
|
||||
const inspect = server as unknown as { hasAdapterFor(provider: string): boolean }
|
||||
|
||||
expect(inspect.hasAdapterFor('deepseek')).toBe(true)
|
||||
expect(inspect.hasAdapterFor('deepseek-official')).toBe(true)
|
||||
expect(inspect.hasAdapterFor('missing-provider')).toBe(false)
|
||||
await server.initialize({ cwd: storageDir, provider: 'deepseek', model: 'preinstalled-model' })
|
||||
await server.initialize({ cwd: storageDir, provider: 'deepseek-official', model: 'preinstalled-model' })
|
||||
|
||||
expect(ctx.get('llm')?.listProviders().filter(provider => provider.id === 'deepseek')).toEqual([{ id: 'deepseek', name: 'DeepSeek' }])
|
||||
expect(ctx.get('llm')?.listProviders().filter(provider => provider.id === 'deepseek-official')).toEqual([{ id: 'deepseek-official', name: 'DeepSeek' }])
|
||||
await server.shutdown()
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
@@ -854,7 +854,7 @@ describe('HarnessSdkServer', () => {
|
||||
await expect(server.initialize({ cwd: storageDir, provider: 'private', model: 'new-model' }))
|
||||
.rejects.toThrow('no adapter registered for provider "private"')
|
||||
|
||||
expect(ctx.get('llm')?.listProviders()).toEqual([{ id: 'deepseek', name: 'DeepSeek' }])
|
||||
expect(ctx.get('llm')?.listProviders()).toEqual([{ id: 'deepseek-official', name: 'DeepSeek' }])
|
||||
await server.shutdown()
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
@@ -871,7 +871,7 @@ describe('HarnessSdkServer', () => {
|
||||
const server = new HarnessSdkServer(ctx, new FakeTransport())
|
||||
await expect(server.initialize({
|
||||
cwd: storageDir,
|
||||
provider: 'deepseek',
|
||||
provider: 'deepseek-official',
|
||||
model: 'model',
|
||||
maxTokens,
|
||||
})).rejects.toThrow('initialize maxTokens must be a positive safe integer')
|
||||
|
||||
@@ -105,10 +105,10 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
await ctx.plugin(UserInteractionService)
|
||||
await ctx.plugin(TuiPromptService)
|
||||
const catalog = options.catalog ?? {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [
|
||||
{ provider: 'deepseek', id: 'deepseek-v4-flash', name: 'DeepSeek V4 Flash' },
|
||||
{ provider: 'deepseek', id: 'deepseek-v4-pro', name: 'DeepSeek V4 Pro' },
|
||||
{ provider: 'deepseek-official', id: 'deepseek-v4-flash', name: 'DeepSeek V4 Flash' },
|
||||
{ provider: 'deepseek-official', id: 'deepseek-v4-pro', name: 'DeepSeek V4 Pro' },
|
||||
],
|
||||
}
|
||||
ctx.provide('tokenMeter', {
|
||||
@@ -194,7 +194,7 @@ export async function createTuiTestHarness<TerminalType extends Terminal, Exit e
|
||||
const cancelled: AgentCancelCause[] = []
|
||||
const agent: FakeAgent = {
|
||||
id: sessionId,
|
||||
options: options.agentOptions ?? { provider: 'deepseek', model: 'deepseek-v4-flash' },
|
||||
options: options.agentOptions ?? { provider: 'deepseek-official', model: 'deepseek-v4-flash' },
|
||||
session,
|
||||
status: options.status ?? 'idle',
|
||||
get acceptsNextStep() {
|
||||
|
||||
@@ -152,8 +152,8 @@ describe('TUI prompt values', () => {
|
||||
describe('TUI prompt templates', () => {
|
||||
it('interpolates values and removes separators around unavailable values', () => {
|
||||
const tokens = parseTuiPromptTemplate('${cwd} ${git/worktree} :: ${missing} ${model}')
|
||||
const values = new Map([['cwd', '/work'], ['model', 'deepseek']])
|
||||
expect(renderTuiPromptTemplate(tokens, name => values.get(name))).toBe('/work :: deepseek')
|
||||
const values = new Map([['cwd', '/work'], ['model', 'deepseek-official']])
|
||||
expect(renderTuiPromptTemplate(tokens, name => values.get(name))).toBe('/work :: deepseek-official')
|
||||
})
|
||||
|
||||
it('keeps a trailing literal after the last value', () => {
|
||||
|
||||
@@ -36,9 +36,9 @@ buffer
|
||||
14| " │ │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
style 83-83 fg=bright-magenta
|
||||
15| " │ → deepseek/deepseek-v4-pro DeepSeek V4 Pro │ "
|
||||
15| " │ → deepseek-official/deepseek-v4- DeepSeek V4 Pro │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
style 10-58 fg=bright-magenta inverse
|
||||
style 10-41 fg=bright-magenta inverse
|
||||
style 83-83 fg=bright-magenta
|
||||
16| " │ │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
|
||||
@@ -36,13 +36,13 @@ buffer
|
||||
14| " │ │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
style 83-83 fg=bright-magenta
|
||||
15| " │ → deepseek/deepseek-v4-flash DeepSeek V4 Flash — current │ "
|
||||
15| " │ → deepseek-official/deepseek-v4- DeepSeek V4 Flash — current │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
style 10-70 fg=bright-magenta inverse
|
||||
style 10-41 fg=bright-magenta inverse
|
||||
style 83-83 fg=bright-magenta
|
||||
16| " │ deepseek/deepseek-v4-pro DeepSeek V4 Pro │ "
|
||||
16| " │ deepseek-official/deepseek-v4- DeepSeek V4 Pro │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
style 36-58 dim
|
||||
style 42-58 dim
|
||||
style 83-83 fg=bright-magenta
|
||||
17| " │ │ "
|
||||
style 8-8 fg=bright-magenta
|
||||
|
||||
@@ -16,8 +16,8 @@ buffer
|
||||
5| "Model wait 0.0s "
|
||||
style 0-14 dim
|
||||
6| <blank>
|
||||
7| "Model selected: deepseek/deepseek-v4-pro. New steps will use it. "
|
||||
style 0-63 dim
|
||||
7| "Model selected: deepseek-official/deepseek-v4-pro. New steps will use it. "
|
||||
style 0-72 dim
|
||||
8| <blank>
|
||||
9| "/workspace/project (tui-staging) deepseek-v4-pro ↑0 ↓0 0% context"
|
||||
style 0-17 fg=bright-magenta bold
|
||||
|
||||
@@ -31,15 +31,15 @@ buffer
|
||||
13| " unavailable: current session "
|
||||
style 2-31 fg=yellow
|
||||
14| " Other workspace work "
|
||||
15| " 2024-02-02T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
|
||||
style 2-74 dim
|
||||
15| " 2024-02-02T00:00:08.000Z · turn 1: completed · deepseek-official/deepseek-v4-pro "
|
||||
style 2-83 dim
|
||||
16| " persisted · elsewhere-session "
|
||||
style 2-32 dim
|
||||
17| " workspace /workspace/other "
|
||||
style 2-29 dim
|
||||
18| " Resume selector design "
|
||||
19| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
|
||||
style 2-74 dim
|
||||
19| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek-official/deepseek-v4-pro "
|
||||
style 2-83 dim
|
||||
20| " persisted · earlier-session "
|
||||
style 2-30 dim
|
||||
21| " workspace /workspace/project "
|
||||
|
||||
@@ -29,8 +29,8 @@ buffer
|
||||
12| " unavailable: current session "
|
||||
style 2-31 fg=yellow
|
||||
13| " Resume selector design "
|
||||
14| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek/deepseek-v4-pro "
|
||||
style 2-74 dim
|
||||
14| " 2024-01-01T00:00:08.000Z · turn 1: completed · deepseek-official/deepseek-v4-pro "
|
||||
style 2-83 dim
|
||||
15| " persisted · earlier-session "
|
||||
style 2-30 dim
|
||||
16| " "
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
terminal 56x36 buffer=normal length=44 base=8 viewport=8
|
||||
terminal 56x36 buffer=normal length=45 base=9 viewport=9
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Inspect session diagnostics — DSH snapshot"
|
||||
cursor hidden column=7 viewportRow=35 bufferRow=43
|
||||
cursor hidden column=7 viewportRow=35 bufferRow=44
|
||||
buffer
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-magenta bold
|
||||
@@ -37,84 +37,87 @@ buffer
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
15| "│ Model: deepseek/deepseek-v4-pro (effort │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 40-55 dim
|
||||
16| "│ default; reasoning blocks shown) │"
|
||||
style 0-0 dim
|
||||
style 15-46 dim
|
||||
style 55-55 dim
|
||||
17| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
18| "│ Agent: idle · 8 events · 1 turn · 1 step · 1 │"
|
||||
15| "│ Model: deepseek-official/deepseek-v4-pro │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
19| "│ tool call │"
|
||||
16| "│ (effort default; reasoning blocks │"
|
||||
style 0-0 dim
|
||||
style 15-55 dim
|
||||
17| "│ shown) │"
|
||||
style 0-0 dim
|
||||
style 15-20 dim
|
||||
style 55-55 dim
|
||||
18| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
20| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
21| "│ Tokens: 1,250 input + 340 output │"
|
||||
19| "│ Agent: idle · 8 events · 1 turn · 1 step · 1 │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
22| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read │"
|
||||
20| "│ tool call │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
21| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
22| "│ Tokens: 1,250 input + 340 output │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
23| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 15-15 dim
|
||||
style 16-26 fg=bright-magenta
|
||||
style 27-32 dim
|
||||
style 55-55 dim
|
||||
23| "│ + 250 write) │"
|
||||
24| "│ + 250 write) │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
24| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / │"
|
||||
25| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 15-15 dim
|
||||
style 16-20 fg=bright-magenta
|
||||
style 21-32 dim
|
||||
style 55-55 dim
|
||||
25| "│ 128,000) │"
|
||||
26| "│ 128,000) │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
26| "│ │"
|
||||
27| "│ │"
|
||||
style 0-0 dim
|
||||
style 55-55 dim
|
||||
27| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
28| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
28| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
29| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 55-55 dim
|
||||
29| "╰──────────────────────────────────────────────────────╯"
|
||||
30| "╰──────────────────────────────────────────────────────╯"
|
||||
style 0-55 dim
|
||||
30| <blank>
|
||||
31| "System prompt "
|
||||
31| <blank>
|
||||
32| "System prompt "
|
||||
style 0-12 fg=bright-magenta bold
|
||||
32| "You are an AI agent powered by the DeepSeek Harness SDK."
|
||||
33| " "
|
||||
34| "Paths prefixed with @ are files explicitly referenced by"
|
||||
35| "the user. Use the read tool when their contents are "
|
||||
36| "needed; do not claim to have inspected a file before "
|
||||
37| "reading it. "
|
||||
38| <blank>
|
||||
39| "Registered tools "
|
||||
33| "You are an AI agent powered by the DeepSeek Harness SDK."
|
||||
34| " "
|
||||
35| "Paths prefixed with @ are files explicitly referenced by"
|
||||
36| "the user. Use the read tool when their contents are "
|
||||
37| "needed; do not claim to have inspected a file before "
|
||||
38| "reading it. "
|
||||
39| <blank>
|
||||
40| "Registered tools "
|
||||
style 0-15 fg=bright-magenta bold
|
||||
40| "read, write "
|
||||
41| <blank>
|
||||
42| "/workspace/project (tui-staging) deepseek-v4-pro ↑1.3k"
|
||||
41| "read, write "
|
||||
42| <blank>
|
||||
43| "/workspace/project (tui-staging) deepseek-v4-pro ↑1.3k"
|
||||
style 0-17 fg=bright-magenta bold
|
||||
style 18-31 dim
|
||||
style 34-48 dim
|
||||
style 51-55 dim
|
||||
43| " dsh > "
|
||||
44| " dsh > "
|
||||
style 1-3 fg=bright-magenta bold
|
||||
style 5-6 dim
|
||||
style 7-7 inverse
|
||||
|
||||
@@ -21,68 +21,68 @@ buffer
|
||||
style 0-2 fg=bright-magenta bold underline
|
||||
9| "inspect this session "
|
||||
10| <blank>
|
||||
11| "╭─ Session status ───────────────────────────────────────────────────────────────╮"
|
||||
11| "╭─ Session status ────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-2 dim
|
||||
style 3-16 fg=bright-magenta bold
|
||||
style 17-81 dim
|
||||
12| "│ Session: main-session │"
|
||||
style 17-90 dim
|
||||
12| "│ Session: main-session │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
13| "│ Title: Inspect session diagnostics │"
|
||||
style 90-90 dim
|
||||
13| "│ Title: Inspect session diagnostics │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
14| "│ Directory: /workspace/project │"
|
||||
style 90-90 dim
|
||||
14| "│ Directory: /workspace/project │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
15| "│ Model: deepseek/deepseek-v4-pro (effort default; reasoning blocks shown) │"
|
||||
style 90-90 dim
|
||||
15| "│ Model: deepseek-official/deepseek-v4-pro (effort default; reasoning blocks shown) │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 40-79 dim
|
||||
style 81-81 dim
|
||||
16| "│ │"
|
||||
style 49-88 dim
|
||||
style 90-90 dim
|
||||
16| "│ │"
|
||||
style 0-0 dim
|
||||
style 81-81 dim
|
||||
17| "│ Agent: idle · 8 events · 1 turn · 1 step · 1 tool call │"
|
||||
style 90-90 dim
|
||||
17| "│ Agent: idle · 8 events · 1 turn · 1 step · 1 tool call │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
18| "│ │"
|
||||
style 90-90 dim
|
||||
18| "│ │"
|
||||
style 0-0 dim
|
||||
style 81-81 dim
|
||||
19| "│ Tokens: 1,250 input + 340 output │"
|
||||
style 90-90 dim
|
||||
19| "│ Tokens: 1,250 input + 340 output │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
20| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read + 250 write) │"
|
||||
style 90-90 dim
|
||||
20| "│ KV cache: [███████████░░░░░] 67% hit (3,000 read + 250 write) │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 15-15 dim
|
||||
style 16-26 fg=bright-magenta
|
||||
style 27-32 dim
|
||||
style 81-81 dim
|
||||
21| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / 128,000) │"
|
||||
style 90-90 dim
|
||||
21| "│ Context: [█████░░░░░░░░░░░] 33% used (42,000 / 128,000) │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 15-15 dim
|
||||
style 16-20 fg=bright-magenta
|
||||
style 21-32 dim
|
||||
style 81-81 dim
|
||||
22| "│ │"
|
||||
style 90-90 dim
|
||||
22| "│ │"
|
||||
style 0-0 dim
|
||||
style 81-81 dim
|
||||
23| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
style 90-90 dim
|
||||
23| "│ Created: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
24| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
style 90-90 dim
|
||||
24| "│ Active: 2026-07-22 09:10:11 UTC │"
|
||||
style 0-0 dim
|
||||
style 3-12 dim
|
||||
style 81-81 dim
|
||||
25| "╰────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-81 dim
|
||||
style 90-90 dim
|
||||
25| "╰─────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-90 dim
|
||||
26| <blank>
|
||||
27| "System prompt "
|
||||
style 0-12 fg=bright-magenta bold
|
||||
|
||||
@@ -554,7 +554,7 @@ describe('TUI terminal-state snapshots', () => {
|
||||
description: 'Audit terminal states from independent angles',
|
||||
phases: [
|
||||
{ title: 'Inspect', detail: 'Map renderer branches' },
|
||||
{ title: 'Verify', detail: 'Challenge missing states', provider: 'deepseek', model: 'deepseek-v4-flash' },
|
||||
{ title: 'Verify', detail: 'Challenge missing states', provider: 'deepseek-official', model: 'deepseek-v4-flash' },
|
||||
],
|
||||
},
|
||||
args: { packages: ['ui/tui', 'workflow/tool-workflow'] },
|
||||
@@ -866,13 +866,13 @@ describe('TUI terminal-state snapshots', () => {
|
||||
{ type: 'turn/start', seq: 0, time: Date.parse(`${day}T00:00:01Z`), data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } },
|
||||
{ type: 'user/message', seq: 1, time: Date.parse(`${day}T00:00:02Z`), data: createUserMessage({ content: [{ type: 'text', text: 'restore the selector' }], source: { kind: 'user' } }), surfaceOp: 'append' },
|
||||
{ type: 'step/start', seq: 2, time: Date.parse(`${day}T00:00:03Z`), data: { turn: 1, step: 1 } },
|
||||
{ type: 'request/header', seq: 3, time: Date.parse(`${day}T00:00:04Z`), data: { header: { config: { provider: 'deepseek', model: 'deepseek-v4-pro' } }, reason: 'initial' } },
|
||||
{ type: 'request/header', seq: 3, time: Date.parse(`${day}T00:00:04Z`), data: { header: { config: { provider: 'deepseek-official', model: 'deepseek-v4-pro' } }, reason: 'initial' } },
|
||||
{ type: 'assistant/message', seq: 4, time: Date.parse(`${day}T00:00:05Z`), data: {
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'ready' }],
|
||||
source: { kind: 'model', provider: 'deepseek', model: 'deepseek-v4-pro' },
|
||||
source: { kind: 'model', provider: 'deepseek-official', model: 'deepseek-v4-pro' },
|
||||
}),
|
||||
}, surfaceOp: 'append' },
|
||||
{ type: 'step/end', seq: 5, time: Date.parse(`${day}T00:00:06Z`), data: { turn: 1, step: 1 } },
|
||||
@@ -913,7 +913,7 @@ describe('TUI terminal-state snapshots', () => {
|
||||
const harness = await setupSnapshot({
|
||||
contextWindow: 128_000,
|
||||
contextTokens: 42_000,
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek-v4-pro' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-v4-pro' },
|
||||
tools: {
|
||||
read: {
|
||||
name: 'read',
|
||||
|
||||
@@ -247,7 +247,7 @@ describe('goodbye message and /resume', () => {
|
||||
({ version: 0, id: SessionId(id), createdAt, cwd })
|
||||
const resumeEvents = (
|
||||
title: string,
|
||||
provider = 'deepseek',
|
||||
provider = 'deepseek-official',
|
||||
time = 100,
|
||||
reason: TurnEndReason = { kind: 'completed' },
|
||||
): SessionEvent[] => [
|
||||
@@ -319,8 +319,8 @@ describe('goodbye message and /resume', () => {
|
||||
sessionPersistence: {
|
||||
list: async () => [older, newer, header('foreign-session', 3000, '/elsewhere')],
|
||||
load: async id => id === newer.id
|
||||
? { meta: newer, events: resumeEvents('Newer product work', 'deepseek', 300) }
|
||||
: { meta: older, events: resumeEvents('Older investigation', 'deepseek', 100) },
|
||||
? { meta: newer, events: resumeEvents('Newer product work', 'deepseek-official', 300) }
|
||||
: { meta: older, events: resumeEvents('Older investigation', 'deepseek-official', 100) },
|
||||
},
|
||||
})
|
||||
result.terminal.send('/resume')
|
||||
@@ -419,7 +419,7 @@ describe('goodbye message and /resume', () => {
|
||||
list: async () => targets,
|
||||
load: async id => ({
|
||||
meta: targets.find(target => target.id === id)!,
|
||||
events: resumeEvents(`Paged ${id.slice('paged-'.length)}`, 'deepseek', 1000 - Number(id.slice('paged-'.length)) * 10),
|
||||
events: resumeEvents(`Paged ${id.slice('paged-'.length)}`, 'deepseek-official', 1000 - Number(id.slice('paged-'.length)) * 10),
|
||||
}),
|
||||
},
|
||||
})
|
||||
@@ -475,7 +475,7 @@ describe('goodbye message and /resume', () => {
|
||||
cwd: '/workspace',
|
||||
sessionPersistence: {
|
||||
list: async () => [target],
|
||||
load: async () => ({ meta: target, events: resumeEvents(`Turn ${label}`, 'deepseek', 100, reason) }),
|
||||
load: async () => ({ meta: target, events: resumeEvents(`Turn ${label}`, 'deepseek-official', 100, reason) }),
|
||||
},
|
||||
})
|
||||
result.terminal.send('/resume')
|
||||
@@ -711,7 +711,7 @@ describe('goodbye message and /resume', () => {
|
||||
it('falls back to assistant provenance and header creation time for sparse logs', async () => {
|
||||
const assistantOnly = header('assistant-route', 20, '/workspace')
|
||||
const empty = header('empty-log', 10, '/workspace')
|
||||
const events = resumeEvents('Assistant route', 'deepseek')
|
||||
const events = resumeEvents('Assistant route', 'deepseek-official')
|
||||
.filter(event => event.type !== 'request/header')
|
||||
.map((event, seq) => ({ ...event, seq })) as SessionEvent[]
|
||||
const result = await setup({
|
||||
@@ -726,7 +726,7 @@ describe('goodbye message and /resume', () => {
|
||||
result.terminal.send('/resume')
|
||||
result.terminal.send('\r')
|
||||
await tick(); await tick()
|
||||
expect(result.terminal.output).toContain('deepseek/model-1')
|
||||
expect(result.terminal.output).toContain('deepseek-official/model-1')
|
||||
expect(result.terminal.output).toContain(new Date(empty.createdAt).toISOString())
|
||||
await dispose(result)
|
||||
})
|
||||
@@ -2443,7 +2443,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
contextWindow: 128_000,
|
||||
contextTokens: 42_000,
|
||||
config: { showReasoning: false },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek-v4-pro' },
|
||||
agentOptions: { provider: 'deepseek-official', model: 'deepseek-v4-pro' },
|
||||
tools: {
|
||||
read: {
|
||||
name: 'read', description: 'Read a file', parameters: {},
|
||||
@@ -2491,7 +2491,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
expect(result.terminal.output).toContain('main-session')
|
||||
expect(result.terminal.output).toContain('Inspect status \\x1b]2;unsafe\\x07')
|
||||
expect(result.terminal.output).toContain('/workspace/status')
|
||||
expect(result.terminal.output).toContain('deepseek/deepseek-v4-pro (effort default; reasoning blocks')
|
||||
expect(result.terminal.output).toContain('deepseek-official/deepseek-v4-pro (effort default; reasoning blocks')
|
||||
expect(result.terminal.output).toContain('hidden)')
|
||||
// 6 domain events + the /status invocation's own command/run (open turn: joined directly).
|
||||
expect(result.terminal.output).toContain('running · 7 events · 1 turn · 1 step · 2 tool calls')
|
||||
@@ -3647,7 +3647,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
|
||||
const failed = await setup({
|
||||
catalog: {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [],
|
||||
listModels: () => Promise.reject(new Error('catalog offline')),
|
||||
resolveModelInfo: () => Promise.reject(new Error('capacity offline')),
|
||||
@@ -3663,8 +3663,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
|
||||
const reasoningFailed = await setup({
|
||||
catalog: {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
models: [{ provider: 'deepseek', id: 'model-1', name: 'Model One' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [{ provider: 'deepseek-official', id: 'model-1', name: 'Model One' }],
|
||||
resolveModelInfo: () => Promise.reject(new Error('reasoning metadata offline')),
|
||||
},
|
||||
})
|
||||
@@ -3680,7 +3680,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
const deferred = Promise.withResolvers<never[]>()
|
||||
const result = await setup({
|
||||
catalog: {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [],
|
||||
listModels: () => deferred.promise,
|
||||
},
|
||||
@@ -3696,7 +3696,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
const rejected = Promise.withResolvers<never[]>()
|
||||
const rejectedResult = await setup({
|
||||
catalog: {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [],
|
||||
listModels: () => rejected.promise,
|
||||
},
|
||||
@@ -3713,7 +3713,7 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
const contextResult = await setup({
|
||||
contextTokens: 99,
|
||||
catalog: {
|
||||
providers: [{ id: 'deepseek', name: 'DeepSeek' }],
|
||||
providers: [{ id: 'deepseek-official', name: 'DeepSeek' }],
|
||||
models: [],
|
||||
resolveModelInfo: () => context.promise.then(value => ({ context: value })),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user