refactor: unify agent and session identity

This commit is contained in:
Tianyi Cui
2026-07-14 01:59:21 +08:00
parent 7a33ee94be
commit 709cc7200e
105 changed files with 899 additions and 948 deletions

View File

@@ -38,8 +38,8 @@
*/
import * as vm from 'node:vm'
import { AgentId } from '@deepseek-ai/dsh-agent'
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
import { assertSupportedOutputSchema, OutputSchemaError } from '@deepseek-ai/dsh-tools'
import type { StructuredOutputSchema } from '@deepseek-ai/dsh-tools'
import { isFatalWorkflowError, WorkflowError } from '@deepseek-ai/dsh-workflow'
@@ -319,7 +319,7 @@ export class WorkflowExecution {
await run.dispose()
throw this.cancelledError()
}
const info: WorkflowAgentInfo = { seq, label, ...phase !== undefined ? { phase } : {}, childId: AgentId(run.id) }
const info: WorkflowAgentInfo = { seq, label, ...phase !== undefined ? { phase } : {}, childId: SessionId(run.id) }
this.observer.agentStart(info)
try {
let result

View File

@@ -1,10 +1,11 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import LlmService from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import AgentRegistry, { AgentId } from '@deepseek-ai/dsh-agent'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import * as Invariants from '@deepseek-ai/dsh-invariants'
import SubagentService from '@deepseek-ai/dsh-subagent'
@@ -37,7 +38,7 @@ async function setup(script: Script) {
await ctx.plugin(spawn, { providerName: 'spawn' })
await ctx.plugin(WorkerWorkflowEngine, {})
ctx.llm.registerAdapter(['mock'], adapter)
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(SessionId('parent'), { model: 'mock' })
return { ctx, parent, adapter }
}
@@ -73,7 +74,7 @@ return { prose, verdict: judged.verdict, confidence: judged.confidence }`,
// Both children were disposed to quiescence — no live child agents remain.
expect(childIds.length).toBe(2)
for (const childId of childIds) {
expect(ctx.agents.get(AgentId(childId))).toBeUndefined()
expect(ctx.agents.get(SessionId(childId))).toBeUndefined()
}
})

View File

@@ -6,10 +6,10 @@
import { expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import { AgentId } from '@deepseek-ai/dsh-agent'
import type { Agent } from '@deepseek-ai/dsh-agent'
import SubagentService from '@deepseek-ai/dsh-subagent'
import WorkerWorkflowEngine from '../src/index.ts'
import { SessionId } from '@deepseek-ai/dsh-session'
// A fresh thread compiles the source runtime. Leave contention headroom on
// shared CI runners without weakening any engine-level timeout assertion.
@@ -19,7 +19,7 @@ it('runs the default config through the source worker', async () => {
const ctx = new Context()
const subagents = await ctx.plugin(SubagentService)
const engine = await ctx.plugin(WorkerWorkflowEngine, {})
const parent = { id: AgentId('workflow-compat-parent'), options: {} } as unknown as Agent
const parent = { id: SessionId('workflow-compat-parent'), options: {} } as unknown as Agent
try {
const run = ctx.workflows.start({
script: 'return 6 * 7',

View File

@@ -1,10 +1,11 @@
import { afterEach, describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import LlmService from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
import AgentRegistry, { AgentId } from '@deepseek-ai/dsh-agent'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek'
import SubagentService from '@deepseek-ai/dsh-subagent'
@@ -62,7 +63,6 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('worker workflow engine with-key
it('runs a two-phase script in a worker thread over real children, one through the structured runtime', async () => {
ctx = await harness()
const parentHandle = await ctx.agents.create({
agentId: AgentId('wf-worker-e2e-parent'),
sessionId: 'wf-worker-e2e-session' as never,
agentOptions: { model: 'deepseek-v4-flash' },
})
@@ -95,7 +95,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('worker workflow engine with-key
expect(childIds.length).toBe(2)
// The children were disposed to quiescence after collection.
for (const childId of childIds) {
expect(ctx.agents.get(AgentId(childId))).toBeUndefined()
expect(ctx.agents.get(SessionId(childId))).toBeUndefined()
}
await parentHandle.dispose()
}, 240_000)

View File

@@ -3,17 +3,17 @@ import { fileURLToPath } from 'node:url'
import type { Worker } from 'node:worker_threads'
import { Context } from 'cordis'
import Loader from '@cordisjs/plugin-loader'
import { AgentId } from '@deepseek-ai/dsh-agent'
import type { Agent } from '@deepseek-ai/dsh-agent'
import SubagentService from '@deepseek-ai/dsh-subagent'
import type { SubagentCapabilities, SubagentProvider, SubagentResult, SubagentRun, SubagentStartRequest } from '@deepseek-ai/dsh-subagent'
import type { WorkflowMeta, WorkflowResult, WorkflowResultInfo, WorkflowRunInfo } from '@deepseek-ai/dsh-workflow'
import * as workerEngineModule from '../src/index.ts'
import WorkerWorkflowEngine, { HostToWorkerType, WorkerToHostType, type Config } from '../src/index.ts'
import { SessionId } from '@deepseek-ai/dsh-session'
/** A minimal parent stand-in: the engine only threads it through to the provider. */
function fakeParent(): Agent {
return { id: AgentId('workflow-parent'), options: {} } as unknown as Agent
return { id: SessionId('workflow-parent'), options: {} } as unknown as Agent
}
// Worker-thread startup is CPU-bound (a fresh thread compiles the runtime on
@@ -117,7 +117,7 @@ class StubProvider implements SubagentProvider {
}
if (request.signal.aborted) throw new Error('child start aborted before publication')
return {
id: AgentId(`stub-child-${index}`),
id: SessionId(`stub-child-${index}`),
result: terminal.promise,
dispose: () => {
controlled.disposeCalls += 1
@@ -366,7 +366,7 @@ describe('dsh-workflow-workerthread', () => {
capabilities: { outputSchema: true, depthLimit: true, toolFilter: true, persona: false },
inheritsParentContext: false,
start: async () => ({
id: AgentId('reject-child'),
id: SessionId('reject-child'),
result: Promise.reject(new Error('backend exploded')),
dispose: () => Promise.resolve(),
}),
@@ -400,7 +400,7 @@ describe('dsh-workflow-workerthread', () => {
stopReason: 'completed',
} as unknown as SubagentResult
const start = vi.spyOn(ctx.subagents, 'start').mockResolvedValue({
id: AgentId('raw-invalid-child'),
id: SessionId('raw-invalid-child'),
result: Promise.resolve(invalid),
dispose: () => Promise.resolve(),
})
@@ -423,7 +423,7 @@ describe('dsh-workflow-workerthread', () => {
capabilities: { outputSchema: true, depthLimit: true, toolFilter: true, persona: false },
inheritsParentContext: false,
start: async () => ({
id: AgentId('bad-dispose-child'),
id: SessionId('bad-dispose-child'),
result: Promise.resolve({ output: [{ type: 'text', text: 'fine' }], stopReason: 'completed' }),
cancel: () => { /* settled already */ },
dispose: () => { throw new Error('dispose exploded') },
@@ -444,7 +444,7 @@ describe('dsh-workflow-workerthread', () => {
capabilities: { outputSchema: true, depthLimit: true, toolFilter: true, persona: false },
inheritsParentContext: false,
start: async () => ({
id: AgentId('trap-child'),
id: SessionId('trap-child'),
result: Promise.resolve({ output: [{ type: 'text', text: 'fine' }], stopReason: 'completed' }),
cancel: () => { /* settled already */ },
// The rejection VALUE's own coercion throws: a warn built with bare
@@ -771,7 +771,7 @@ describe('dsh-workflow-workerthread', () => {
settle({ output: [], stopReason: 'aborted' })
}, { once: true })
return {
id: AgentId('signal-only-child'),
id: SessionId('signal-only-child'),
result,
dispose: () => Promise.resolve(),
}
@@ -1092,7 +1092,7 @@ describe('dsh-workflow-workerthread', () => {
expect(request.signal.reason).toBe('workflow worker gone')
ready.resolve({
id: AgentId('late-ready-child'),
id: SessionId('late-ready-child'),
result: Promise.resolve({ output: [], stopReason: 'aborted' }),
dispose: () => {
disposeCalls += 1
@@ -1128,7 +1128,7 @@ describe('dsh-workflow-workerthread', () => {
handle.cancel('reentered from worker-death signal cleanup')
}, { once: true })
return {
id: AgentId('doomed-child'),
id: SessionId('doomed-child'),
result: new Promise(() => { /* never settles; the reap is the teardown */ }),
dispose: () => Promise.reject(new Error('dispose exploded during reap')),
}