mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
A continuable child that stopped without reporting — an error, a token ceiling, cancellation, teardown — left its parent nothing to act on. The continuation manager now delivers an unconditional settlement notice to the durable direct parent before releasing ownership, folding consumed work (foldConsumedWork supersedes findLastMessageTurnEnd) so a claimed-but-unrun prompt reads as aborted rather than completed, waking an idle parent, steering a busy one, and never waking a closing tree.
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
/**
|
|
* Loader fixture that holds the parent's second step until settlement delivery.
|
|
* @module subagent-settlement-fence
|
|
*/
|
|
|
|
import type { Context } from '@deepseek-ai/cordis'
|
|
import type {} from '@deepseek-ai/dsh-agent-loop'
|
|
import type {} from '@deepseek-ai/dsh-subagent'
|
|
|
|
/** Fixture plugin name. */
|
|
export const name = 'subagent-settlement-fence'
|
|
|
|
/**
|
|
* Fence the parent's post-spawn request behind admission of the manager notice.
|
|
*
|
|
* This pins content order, not step placement: the held pre-step runs after its
|
|
* own `Inbox.claim()`, so the notice lands after step 2's claim and is claimed at
|
|
* step 3 because the child's settlement pipeline is strictly longer than the
|
|
* parent's claim path, not because a barrier forces it.
|
|
* @param ctx - assembled headless-agent context.
|
|
*/
|
|
export function apply(ctx: Context): void {
|
|
const delivered = Promise.withResolvers<undefined>()
|
|
let hasDelivered = false
|
|
|
|
ctx.effect(() => {
|
|
const disposeInbox = ctx.root.on('agent/inbox/inserted', ({ agent, message }) => {
|
|
if (agent.session.header.parentSession !== undefined || message.source.kind !== 'subagent-settled') return
|
|
hasDelivered = true
|
|
delivered.resolve(undefined)
|
|
})
|
|
const disposeStep = ctx.root.on('agent/pre-step', async ({ agent, turn, step }, next) => {
|
|
if (agent.session.header.parentSession === undefined && turn === 1 && step === 2 && !hasDelivered) {
|
|
await delivered.promise
|
|
}
|
|
return next()
|
|
})
|
|
return () => {
|
|
disposeStep()
|
|
disposeInbox()
|
|
}
|
|
}, 'subagent-settlement-fence.listeners')
|
|
}
|