From 622dd32e1acf9b01b519a227b120bb5e2dde61b8 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 25 Oct 2026 12:11:05 +0400 Subject: [PATCH] =?UTF-8?q?fix(dsh):=20isSubagent=20=E2=80=94=20origin=3D?= =?UTF-8?q?=3D=3Dsubagent=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20parentS?= =?UTF-8?q?ession=20(=D1=84=D0=BE=D1=80=D0=BA=D0=B8=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D1=81=D0=B0=D0=B1=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D1=8B)=20(T2.3?= =?UTF-8?q?,=20#43)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dsh/bundle/index.js | 2 +- dsh/tests/prestep.test.mjs | 28 ++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/dsh/bundle/index.js b/dsh/bundle/index.js index eefaa10..a29085a 100644 --- a/dsh/bundle/index.js +++ b/dsh/bundle/index.js @@ -75,7 +75,7 @@ export function resolveRolesDir(bundleDir, configured, home = homedir()) { function isSubagent(agent) { return Boolean( agent?.session?.header?.delegationDepth > 0 || - agent?.session?.header?.parentSession != null || + agent?.session?.header?.origin === 'subagent' || agent?.options?.subagentDepth > 0, ) } diff --git a/dsh/tests/prestep.test.mjs b/dsh/tests/prestep.test.mjs index 0ddff3f..81ac083 100644 --- a/dsh/tests/prestep.test.mjs +++ b/dsh/tests/prestep.test.mjs @@ -383,13 +383,13 @@ test('apply: bootstrap:false leaves harness-check wired (the gate is ctx.on, not // --------------------------------------------------------------------------- /** - * Agent shapes that the runtime uses for a delegated step. The old - * parent/parentAgent/parentSessionId/depth checks were dead; these three are - * the live ones. + * Agent shapes that the runtime uses for a delegated step: the session header + * carries `origin: 'subagent'` (or a positive delegationDepth / subagentDepth + * as a robust fallback). */ const SUBAGENT_AGENTS = [ { session: { header: { delegationDepth: 1 } } }, - { session: { header: { parentSession: 's0' } } }, + { session: { header: { origin: 'subagent', parentSession: 's0' } } }, { options: { subagentDepth: 1 } }, ] @@ -430,3 +430,23 @@ test('apply: a plain pre-step still injects bootstrap, harness-check, and role-h cleanup(skill) } }) + +test('apply: a forked session (parentSession without origin) still injects all three', async () => { + const repo = nonAdoptedRepo() + const skill = tempDir('dsh-harness-skill-') + try { + write(join(skill, 'SKILL.md'), '---\nname: using-superpowers\n---\nbody\n') + const harness = prestepHarness({ bootstrapSkillPath: join(skill, 'SKILL.md') }, repo) + const forkAgent = { session: { header: { parentSession: 's0', isSeeded: true } } } + const decision = await harness.run({ agent: forkAgent, messages: [userMessage('Напиши тест')] }) + + assert.equal(decision.messages.length, 4, 'forks are not subagents: all three injections expected') + const texts = decision.messages.map(messageText) + assert.ok(texts.some((text) => text.includes('DSH-HARNESS-BOOTSTRAP')), 'bootstrap injected') + assert.ok(texts.some((text) => text.includes('не подключён к обвязке')), 'harness-check injected') + assert.ok(texts.some((text) => text.includes('Роль сессии: dev')), 'role-hint injected') + } finally { + cleanup(repo) + cleanup(skill) + } +})