mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-12 04:01:20 +00:00
feat(subagent): carry model routing through DSH SDK
This commit is contained in:
+30
-10
@@ -1,17 +1,37 @@
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { LlmAdapter } from '@deepseek-ai/dsh-llm'
|
||||
import type { GenerateOptions, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { LlmAdapter, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
||||
|
||||
/**
|
||||
* Scripted model for the CHILD runtime: answers every request with its own
|
||||
* process cwd, so the driving e2e can prove the parent session's workspace
|
||||
* reached the child process across the SDK wire. `options` carries the
|
||||
* request; the reply depends only on process state.
|
||||
* Scripted model for the CHILD runtime: rejects any route drift, then reports
|
||||
* its effective route and process cwd so the driving evidence observes both
|
||||
* SDK initialization inputs and the inherited workspace.
|
||||
*/
|
||||
class CwdEchoAdapter extends LlmAdapter {
|
||||
class RouteEchoAdapter extends LlmAdapter {
|
||||
override resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo> {
|
||||
return Promise.resolve({
|
||||
provider,
|
||||
id: model,
|
||||
name: model,
|
||||
reasoning: {
|
||||
efforts: [{ id: ReasoningEffortId('max'), name: 'Maximum' }],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
|
||||
void options
|
||||
const reply = `child cwd: ${process.cwd()}`
|
||||
if (options.provider !== 'mock'
|
||||
|| options.model !== 'mock-routed'
|
||||
|| options.reasoningEffort !== 'max'
|
||||
|| options.maxTokens !== 777) {
|
||||
throw new Error(`unexpected child route: ${JSON.stringify({
|
||||
provider: options.provider,
|
||||
model: options.model,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
maxTokens: options.maxTokens,
|
||||
})}`)
|
||||
}
|
||||
const reply = `child route: mock/mock-routed/max/777; cwd: ${process.cwd()}`
|
||||
yield { type: 'block-start', index: 0, blockType: 'text' }
|
||||
yield { type: 'text-delta', index: 0, text: reply }
|
||||
yield { type: 'block-end', index: 0, block: { type: 'text', text: reply } }
|
||||
@@ -28,5 +48,5 @@ export const inject = ['llm']
|
||||
* @param ctx - the plugin context supplying `ctx.llm`.
|
||||
*/
|
||||
export function apply(ctx: Context): void {
|
||||
ctx.llm.registerAdapter(['mock'], new CwdEchoAdapter())
|
||||
ctx.llm.registerAdapter(['mock'], new RouteEchoAdapter())
|
||||
}
|
||||
|
||||
+9
-5
@@ -1,7 +1,7 @@
|
||||
# Test-only composition: the SDK subagent backend on the real Loader/app path.
|
||||
# The scripted model delegates once; the child — a COMPLETE second harness
|
||||
# runtime speaking stdio JSON-RPC — echoes its process cwd, so parent-session
|
||||
# cwd inheritance is asserted keylessly end to end across the SDK wire.
|
||||
# The scripted model selects a child route; the child — a COMPLETE second
|
||||
# harness runtime speaking stdio JSON-RPC — echoes the effective route and cwd,
|
||||
# so dynamic routing and parent-session cwd inheritance are asserted keylessly.
|
||||
# `cwd` is deliberately omitted — the inheritance branch under test. The child
|
||||
# profile patch and isolated Harness home are machine-absolute, supplied by
|
||||
# the driving e2e.
|
||||
@@ -19,8 +19,10 @@
|
||||
profile: sdk
|
||||
patches: !!js JSON.parse(process.env.DSH_TEST_CHILD_PATCHES ?? '[]')
|
||||
dshHome: !!js process.env.DSH_TEST_CHILD_HOME
|
||||
provider: mock
|
||||
model: mock-echo
|
||||
# These defaults are intentionally unavailable in the child composition;
|
||||
# the model-selected route must replace them before initialize.
|
||||
provider: unavailable-default
|
||||
model: unavailable-default
|
||||
env:
|
||||
DSH_TELEMETRY_DISABLED: '1'
|
||||
|
||||
@@ -29,6 +31,8 @@
|
||||
config:
|
||||
provider: dsh-sdk
|
||||
toolName: subagent
|
||||
agentOptions:
|
||||
maxTokens: 777
|
||||
# The SDK backend advertises no depthLimit: the child harness owns its own
|
||||
# recursion budget, so the local numeric default cannot apply here.
|
||||
maxDepth: 'provider-managed'
|
||||
|
||||
+20
-3
@@ -1,6 +1,6 @@
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm'
|
||||
import type { GenerateOptions, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { CallId, LlmAdapter, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
||||
|
||||
/**
|
||||
* Test adapter for the `mock-delegate` model: the first request calls the
|
||||
@@ -9,6 +9,17 @@ import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm'
|
||||
* cwd echo) reaches the parent session log for the driving e2e to assert.
|
||||
*/
|
||||
class MockDelegatingAdapter extends LlmAdapter {
|
||||
override resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo> {
|
||||
return Promise.resolve({
|
||||
provider,
|
||||
id: model,
|
||||
name: model,
|
||||
reasoning: {
|
||||
efforts: [{ id: ReasoningEffortId('max'), name: 'Maximum' }],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
|
||||
const toolResultText = options.messages.at(-1)?.content
|
||||
.filter(block => block.type === 'tool-result')
|
||||
@@ -18,7 +29,13 @@ class MockDelegatingAdapter extends LlmAdapter {
|
||||
.join('') ?? ''
|
||||
|
||||
if (toolResultText.length === 0) {
|
||||
const args = JSON.stringify({ description: 'cwd probe', prompt: 'report your workspace' })
|
||||
const args = JSON.stringify({
|
||||
description: 'route probe',
|
||||
prompt: 'report your route and workspace',
|
||||
provider: 'mock',
|
||||
model: 'mock-routed',
|
||||
reasoning_effort: 'max',
|
||||
})
|
||||
yield { type: 'block-start', index: 0, blockType: 'tool-call' }
|
||||
yield { type: 'tool-call-delta', index: 0, id: CallId('call-delegate'), name: 'subagent', argumentsDelta: args }
|
||||
yield { type: 'block-end', index: 0, block: { type: 'tool-call', id: CallId('call-delegate'), name: 'subagent', arguments: args } }
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
# JSON-RPC snapshot root: a deterministic parent model selects a route for a
|
||||
# separate SDK child runtime. Both runtimes persist their own request headers.
|
||||
- id: sdk-jsonrpc-server
|
||||
name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
|
||||
|
||||
- id: mock-llm
|
||||
name: './mock-delegating-llm.ts'
|
||||
|
||||
- id: subagent
|
||||
name: '@deepseek-ai/dsh-subagent'
|
||||
|
||||
- id: subagent-dsh-sdk
|
||||
name: '@deepseek-ai/dsh-subagent-dsh-sdk'
|
||||
config:
|
||||
profile: sdk
|
||||
patches: !!js JSON.parse(process.env.DSH_TEST_CHILD_PATCHES ?? '[]')
|
||||
dshHome: !!js process.env.DSH_TEST_CHILD_HOME
|
||||
provider: unavailable-default
|
||||
model: unavailable-default
|
||||
env:
|
||||
DSH_TELEMETRY_DISABLED: '1'
|
||||
|
||||
- id: tool-subagent
|
||||
name: '@deepseek-ai/dsh-tool-subagent'
|
||||
config:
|
||||
provider: dsh-sdk
|
||||
toolName: subagent
|
||||
enableRunInBackground: false
|
||||
agentOptions:
|
||||
maxTokens: 777
|
||||
maxDepth: 'provider-managed'
|
||||
|
||||
- id: agent-spine
|
||||
name: '@deepseek-ai/dsh-agent-spine-demo'
|
||||
config:
|
||||
persona: 'Test SDK subagent dynamic routing.'
|
||||
workspaceContext: false
|
||||
skills:
|
||||
enabled: false
|
||||
toolBash:
|
||||
enableRunInBackground: false
|
||||
toolJobs: false
|
||||
|
||||
- id: sessions
|
||||
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
||||
config:
|
||||
root: !!js process.env.DSH_SESSION_ROOT
|
||||
compression: none
|
||||
|
||||
- id: session-checkpoints
|
||||
name: '@deepseek-ai/dsh-session-checkpoint-policy'
|
||||
@@ -106,7 +106,13 @@ describe('Python SDK dsh profile keyless smoke', () => {
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: { cwd: root, provider: 'deepseek-official', model: 'deepseek-v4-pro', maxTokens: 1234 },
|
||||
params: {
|
||||
cwd: root,
|
||||
provider: 'deepseek-official',
|
||||
model: 'deepseek-v4-pro',
|
||||
reasoningEffort: 'max',
|
||||
maxTokens: 1234,
|
||||
},
|
||||
})}\n`)
|
||||
const initialized = await waitForLine(lines, value => value.id === 1, () => stderr)
|
||||
expect(initialized).toMatchObject({
|
||||
@@ -145,6 +151,7 @@ describe('Python SDK dsh profile keyless smoke', () => {
|
||||
},
|
||||
})
|
||||
const tools = modelRequests[0]?.tools as { function?: { name?: string } }[]
|
||||
expect(modelRequests[0]?.reasoning_effort).toBe('max')
|
||||
expect(modelRequests[0]?.max_tokens).toBe(1234)
|
||||
expect(tools.map(tool => tool.function?.name)).toContain('list_subagent_models')
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ const replayPlugin = fileURLToPath(new URL(
|
||||
: '../../../packages/test-support/llm-replay/src/index.ts',
|
||||
import.meta.url,
|
||||
))
|
||||
const dshSdkFixtureDir = join(testsDir, 'fixtures', 'subagent', 'subagent-dsh-sdk')
|
||||
const dshSdkSnapshotConfig = join(dshSdkFixtureDir, 'snapshot.cordis.yml')
|
||||
const dshSdkChildConfig = join(dshSdkFixtureDir, 'child.cordis.yml')
|
||||
const dshSdkChildMockPath = join(dshSdkFixtureDir, 'child-mock-llm.ts')
|
||||
|
||||
const MINIMAL_SYSTEM_PROMPT = 'You are the environment-selected minimal software engineer.'
|
||||
const MINIMAL_BASH_DESCRIPTION = `Run commands in a bash shell
|
||||
@@ -71,7 +75,7 @@ interface SdkScenario {
|
||||
prompt: string
|
||||
/** Fixed SDK session id, so fixtures and replay binding stay stable. */
|
||||
sessionId: string
|
||||
/** How many child sessions the turn persists (subagent scenarios). */
|
||||
/** How many additional session logs the scenario persists. */
|
||||
children: number
|
||||
/** Optional scenario-specific live and replay compositions. */
|
||||
configs?: { live: string; replay: string }
|
||||
@@ -79,6 +83,14 @@ interface SdkScenario {
|
||||
additionalPatches?: { live: readonly string[]; replay: readonly string[] }
|
||||
/** Environment overrides passed to the runtime subprocess. */
|
||||
environment?: Readonly<Record<string, string>>
|
||||
/** SDK initialization route for the root runtime. */
|
||||
sdkRoute?: { provider: string; model: string }
|
||||
/** Separate DSH SDK child process and the route its persisted request must prove. */
|
||||
dshSdkChild?: {
|
||||
config: string
|
||||
sessionRoot: string
|
||||
expectedRoute: Readonly<Record<string, unknown>>
|
||||
}
|
||||
/** Cwd-relative files whose final contents are part of the scenario contract. */
|
||||
expectedFiles?: Readonly<Record<string, string>>
|
||||
/** Assembled model-facing tool names and required argument keys. */
|
||||
@@ -111,6 +123,24 @@ const SCENARIOS: SdkScenario[] = [
|
||||
sessionId: 'sdk-snapshot-subagent',
|
||||
children: 1,
|
||||
},
|
||||
{
|
||||
name: 'subagent-dsh-sdk-dynamic-route',
|
||||
prompt: 'Delegate once using the requested child route.',
|
||||
sessionId: 'sdk-snapshot-dsh-sdk',
|
||||
children: 1,
|
||||
configs: { live: dshSdkSnapshotConfig, replay: dshSdkSnapshotConfig },
|
||||
sdkRoute: { provider: 'mock', model: 'mock-delegate' },
|
||||
dshSdkChild: {
|
||||
config: dshSdkChildConfig,
|
||||
sessionRoot: '.child-dsh/sessions',
|
||||
expectedRoute: {
|
||||
provider: 'mock',
|
||||
model: 'mock-routed',
|
||||
reasoningEffort: 'max',
|
||||
maxTokens: 777,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'persistent-tools',
|
||||
prompt: 'Prove that bash state persists. Then create {{cwd}}/note.txt with a tab-indented line, view it, replace that literal tab-indented line, and make the persistent shell exit with code 9.',
|
||||
@@ -193,6 +223,17 @@ function assembledSystem(log: PersistedLog): string {
|
||||
return system
|
||||
}
|
||||
|
||||
function assembledRequestConfig(log: PersistedLog): Record<string, unknown> {
|
||||
const event = log.content.trimEnd().split('\n')
|
||||
.map(line => JSON.parse(line) as { type?: string; data?: { header?: { config?: unknown } } })
|
||||
.find(candidate => candidate.type === 'request/header')
|
||||
const config = event?.data?.header?.config
|
||||
if (typeof config !== 'object' || config === null || Array.isArray(config)) {
|
||||
throw new Error('session log has no request/header config')
|
||||
}
|
||||
return config as Record<string, unknown>
|
||||
}
|
||||
|
||||
function assembledRuntimeContexts(log: PersistedLog): string[] {
|
||||
return log.content.trimEnd().split('\n').flatMap((line) => {
|
||||
const event = JSON.parse(line) as {
|
||||
@@ -300,6 +341,18 @@ async function runScenario(scenario: SdkScenario): Promise<{
|
||||
? scenario.additionalPatches?.live ?? []
|
||||
: scenario.additionalPatches?.replay ?? []
|
||||
const [parentFixture, ...childFixtures] = replayFixtures
|
||||
let childEnvironment: Record<string, string> = {}
|
||||
if (scenario.dshSdkChild !== undefined) {
|
||||
const childHome = join(cwd, '.child-dsh')
|
||||
const childPatch = join(childHome, 'child.cordis.yml')
|
||||
await mkdir(childHome, { recursive: true })
|
||||
await writeFile(childPatch, (await readFile(scenario.dshSdkChild.config, 'utf8'))
|
||||
.replace("'./child-mock-llm.ts'", JSON.stringify(pathToFileURL(dshSdkChildMockPath).href)))
|
||||
childEnvironment = {
|
||||
DSH_TEST_CHILD_PATCHES: JSON.stringify([childPatch]),
|
||||
DSH_TEST_CHILD_HOME: childHome,
|
||||
}
|
||||
}
|
||||
const env: Record<string, string> = {
|
||||
...Object.fromEntries(Object.entries(process.env).filter(([, value]) => value !== undefined)) as Record<string, string>,
|
||||
DSH_SNAPSHOT: mode,
|
||||
@@ -310,6 +363,7 @@ async function runScenario(scenario: SdkScenario): Promise<{
|
||||
...childFixtures.length > 0 ? { DSH_SNAPSHOT_CHILD_FILES: childFixtures.join(delimiter) } : {},
|
||||
},
|
||||
...scenario.environment,
|
||||
...childEnvironment,
|
||||
}
|
||||
|
||||
const harness = new DeepSeekHarness({
|
||||
@@ -324,8 +378,8 @@ async function runScenario(scenario: SdkScenario): Promise<{
|
||||
env,
|
||||
requestTimeoutMs: 110_000,
|
||||
cwd,
|
||||
provider: 'deepseek-official',
|
||||
model: 'deepseek-v4-flash',
|
||||
provider: scenario.sdkRoute?.provider ?? 'deepseek-official',
|
||||
model: scenario.sdkRoute?.model ?? 'deepseek-v4-flash',
|
||||
})
|
||||
try {
|
||||
const notifications: HarnessNotification[] = []
|
||||
@@ -334,7 +388,12 @@ async function runScenario(scenario: SdkScenario): Promise<{
|
||||
onNotification: (notification) => { notifications.push(notification) },
|
||||
})
|
||||
await harness.close()
|
||||
const logs = await persistedLogs(sessionsRoot)
|
||||
const logs = (await Promise.all([
|
||||
persistedLogs(sessionsRoot),
|
||||
...(scenario.dshSdkChild === undefined
|
||||
? []
|
||||
: [persistedLogs(join(cwd, scenario.dshSdkChild.sessionRoot))]),
|
||||
])).flat()
|
||||
const observedFiles = Object.fromEntries(await Promise.all(
|
||||
Object.keys(scenario.expectedFiles ?? {}).map(async (path): Promise<[string, string | MissingFile]> => [
|
||||
path,
|
||||
@@ -350,6 +409,10 @@ async function runScenario(scenario: SdkScenario): Promise<{
|
||||
|
||||
/** Order logs parent-first, children by creation time (fixture layout order). */
|
||||
function orderLogs(logs: PersistedLog[], scenario: SdkScenario): PersistedLog[] {
|
||||
if (scenario.dshSdkChild !== undefined) {
|
||||
expect(logs).toHaveLength(scenario.children + 1)
|
||||
return logs
|
||||
}
|
||||
const parents = logs.filter(log => typeof log.header.parentSession !== 'string')
|
||||
const children = logs.filter(log => typeof log.header.parentSession === 'string')
|
||||
.sort((left, right) => Number(left.header.createdAt) - Number(right.header.createdAt))
|
||||
@@ -480,7 +543,12 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
|
||||
for (const clause of scenario.runtimeContext.includes) expect(system).not.toContain(clause)
|
||||
}
|
||||
}
|
||||
if (scenario.children > 0) {
|
||||
if (scenario.dshSdkChild !== undefined) {
|
||||
const child = ordered[1]
|
||||
if (child === undefined) throw new Error(`${scenario.name} has no child session log`)
|
||||
expect(assembledRequestConfig(child)).toEqual(scenario.dshSdkChild.expectedRoute)
|
||||
}
|
||||
if (scenario.children > 0 && scenario.dshSdkChild === undefined) {
|
||||
expect(notifications.some(n => n.method === 'subagent.started')).toBe(true)
|
||||
expect(notifications.some(n => n.method === 'subagent.finished')).toBe(true)
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":0,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Delegate once using the requested child route."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}}}
|
||||
{"method":"session.status","params":{"sessionId":"{{sessionId}}","status":"running"}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/start","seq":1,"time":0,"data":{"turn":1}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":2,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":3,"time":0,"data":{"turn":1,"step":1}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":4,"time":0,"data":{"content":[{"type":"text","text":"Delegate once using the requested child route."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"session/title","seq":5,"time":0,"data":{"title":"Delegate once using the requested","messageSeqs":[4],"source":{"kind":"fallback"}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/header","seq":6,"time":0,"data":{"header":{"config":{"provider":"mock","model":"mock-delegate"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/context","seq":7,"time":0,"data":{"provider":"mock","model":"mock-delegate"}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":9,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"call-delegate","name":"subagent","argumentsDelta":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":10,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":11,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":12,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":13,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}],"source":{"kind":"model","provider":"mock","model":"mock-delegate"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":14,"time":0,"data":{"turn":1,"step":1,"callId":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":15,"time":0,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"call-delegate"},"content":[{"type":"tool-result","toolCallId":"call-delegate","content":[{"type":"text","text":"child route: mock/mock-routed/max/777; cwd: {{cwd}}"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[14],"surfaceOp":"append"}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":16,"time":0,"data":{"turn":1,"step":1}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":17,"time":0,"data":{"turn":1,"step":2}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":18,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":0,"text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":20,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":21,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":167}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":22,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":23,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}],"source":{"kind":"model","provider":"mock","model":"mock-delegate"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":167}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":24,"time":0,"data":{"turn":1,"step":2}}}}
|
||||
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":25,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}}
|
||||
{"method":"session.status","params":{"sessionId":"{{sessionId}}","status":"idle"}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"sessionId":"{{sessionId}}","finalResponse":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{"type":"session","version":0,"id":"session-d9caef61eced4f94a2d4f6265020896e","createdAt":1787254273406,"cwd":"{{cwd}}","delegationDepth":0}
|
||||
{"type":"agent/inbox/spliced","seq":0,"time":1787254273407,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"report your route and workspace"}],"source":{"kind":"user"},"role":"user","id":"18ece5d3-8dc4-4841-bc67-3287b1eb8ab2"}]}}
|
||||
{"type":"turn/start","seq":1,"time":1787254273408,"data":{"turn":1}}
|
||||
{"type":"agent/inbox/spliced","seq":2,"time":1787254273408,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","seq":3,"time":1787254273432,"data":{"turn":1,"step":1}}
|
||||
{"type":"user/message","seq":4,"time":1787254273432,"data":{"content":[{"type":"text","text":"report your route and workspace"}],"source":{"kind":"user"},"role":"user","id":"18ece5d3-8dc4-4841-bc67-3287b1eb8ab2"},"surfaceOp":"append"}
|
||||
{"type":"session/title","seq":5,"time":1787254273433,"data":{"title":"report your route and workspace","messageSeqs":[4],"source":{"kind":"fallback"}}}
|
||||
{"type":"request/header","seq":6,"time":1787254273433,"data":{"header":{"config":{"provider":"mock","model":"mock-routed","reasoningEffort":"max","maxTokens":777},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
|
||||
{"type":"request/context","seq":7,"time":1787254273433,"data":{"provider":"mock","model":"mock-routed"}}
|
||||
{"type":"assistant/chunk","seq":8,"time":1787254273438,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
|
||||
{"type":"assistant/chunk","seq":9,"time":1787254273438,"data":{"turn":1,"step":1,"chunk":{"type":"text-delta","index":0,"text":"child route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}
|
||||
{"type":"assistant/chunk","seq":10,"time":1787254273438,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"child route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}}
|
||||
{"type":"assistant/chunk","seq":11,"time":1787254273438,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":151}}}}
|
||||
{"type":"assistant/chunk","seq":12,"time":1787254273438,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
|
||||
{"type":"assistant/message","seq":13,"time":1787254273438,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"child route: mock/mock-routed/max/777; cwd: {{cwd}}"}],"source":{"kind":"model","provider":"mock","model":"mock-routed"},"id":"0f6dd3aa-2d48-4c64-9130-4812a99e1e31"},"usage":{"inputTokens":3,"outputTokens":151}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":14,"time":1787254273438,"data":{"turn":1,"step":1}}
|
||||
{"type":"turn/end","seq":15,"time":1787254273438,"data":{"turn":1,"reason":{"kind":"completed"}}}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{"type":"session","version":0,"id":"sdk-snapshot-dsh-sdk","createdAt":1787254272178,"cwd":"{{cwd}}","delegationDepth":0}
|
||||
{"type":"agent/inbox/spliced","seq":0,"time":1787254272180,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Delegate once using the requested child route."}],"source":{"kind":"user"},"role":"user","id":"7f17592a-8a93-4bb4-851c-f5e942372b06"}]}}
|
||||
{"type":"turn/start","seq":1,"time":1787254272180,"data":{"turn":1}}
|
||||
{"type":"agent/inbox/spliced","seq":2,"time":1787254272180,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","seq":3,"time":1787254272210,"data":{"turn":1,"step":1}}
|
||||
{"type":"user/message","seq":4,"time":1787254272210,"data":{"content":[{"type":"text","text":"Delegate once using the requested child route."}],"source":{"kind":"user"},"role":"user","id":"7f17592a-8a93-4bb4-851c-f5e942372b06"},"surfaceOp":"append"}
|
||||
{"type":"session/title","seq":5,"time":1787254272211,"data":{"title":"Delegate once using the requested","messageSeqs":[4],"source":{"kind":"fallback"}}}
|
||||
{"type":"request/header","seq":6,"time":1787254272211,"data":{"header":{"config":{"provider":"mock","model":"mock-delegate"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
|
||||
{"type":"request/context","seq":7,"time":1787254272211,"data":{"provider":"mock","model":"mock-delegate"}}
|
||||
{"type":"assistant/chunk","seq":8,"time":1787254272214,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
|
||||
{"type":"assistant/chunk","seq":9,"time":1787254272215,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"call-delegate","name":"subagent","argumentsDelta":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}}
|
||||
{"type":"assistant/chunk","seq":10,"time":1787254272215,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}}}
|
||||
{"type":"assistant/chunk","seq":11,"time":1787254272215,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}}}
|
||||
{"type":"assistant/chunk","seq":12,"time":1787254272215,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
|
||||
{"type":"assistant/message","seq":13,"time":1787254272215,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}],"source":{"kind":"model","provider":"mock","model":"mock-delegate"},"id":"09f8526a-e0ff-493f-8f43-b7f6b5558541"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}
|
||||
{"type":"tool/call","seq":14,"time":1787254272215,"data":{"turn":1,"step":1,"callId":"call-delegate","name":"subagent","arguments":"{\"description\":\"route probe\",\"prompt\":\"report your route and workspace\",\"provider\":\"mock\",\"model\":\"mock-routed\",\"reasoning_effort\":\"max\"}"}}
|
||||
{"type":"tool/result","seq":15,"time":1787254273451,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"call-delegate"},"content":[{"type":"tool-result","toolCallId":"call-delegate","content":[{"type":"text","text":"child route: mock/mock-routed/max/777; cwd: {{cwd}}"}],"isError":false}],"role":"user","id":"321d12a1-7801-4614-b800-c8c7ff267f52"}},"sourceEventSeqs":[14],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":16,"time":1787254273451,"data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","seq":17,"time":1787254273455,"data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/chunk","seq":18,"time":1787254273459,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
|
||||
{"type":"assistant/chunk","seq":19,"time":1787254273460,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":0,"text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}
|
||||
{"type":"assistant/chunk","seq":20,"time":1787254273460,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}}}}
|
||||
{"type":"assistant/chunk","seq":21,"time":1787254273460,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":167}}}}
|
||||
{"type":"assistant/chunk","seq":22,"time":1787254273460,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
|
||||
{"type":"assistant/message","seq":23,"time":1787254273460,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"child reported:\nchild route: mock/mock-routed/max/777; cwd: {{cwd}}"}],"source":{"kind":"model","provider":"mock","model":"mock-delegate"},"id":"373cadb7-313d-44e7-a31a-ec0a675e0255"},"usage":{"inputTokens":10,"outputTokens":167}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":24,"time":1787254273460,"data":{"turn":1,"step":2}}
|
||||
{"type":"turn/end","seq":25,"time":1787254273460,"data":{"turn":1,"reason":{"kind":"completed"}}}
|
||||
Reference in New Issue
Block a user