fix(subagent): identify lifecycle runs explicitly
This commit is contained in:
@@ -19,7 +19,7 @@ import type { Agent, AgentHandle } from '@deepseek-ai/dsh-agent'
|
||||
import { carrierKeyOf, type Scoped } from '@deepseek-ai/dsh-scope'
|
||||
import { SessionId, type TurnEndReason } from '@deepseek-ai/dsh-session'
|
||||
import type SubagentService from '@deepseek-ai/dsh-subagent'
|
||||
import type { SubagentRunEndInfo, SubagentRunInfo } from '@deepseek-ai/dsh-subagent'
|
||||
import type { SubagentRunEndInfo } from '@deepseek-ai/dsh-subagent'
|
||||
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek'
|
||||
import type { JsonRpcTransportPeer } from './transport.ts'
|
||||
|
||||
@@ -68,15 +68,6 @@ function subagentParentOf(carrier: Scoped<SubagentService>): Agent {
|
||||
return carrierKeyOf(carrier) as Agent
|
||||
}
|
||||
|
||||
/** Whether the live id names a local child related to this exact delegating parent. */
|
||||
function isLocalChild(ctx: Context, id: SessionId, parent: Agent): boolean {
|
||||
const child = ctx.agents.get(id)
|
||||
return child !== undefined && (
|
||||
ctx.agents.isOwnedBy(id, parent)
|
||||
|| child.session.header.parentSession === parent.session.id
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The SDK server over a booted harness context. Constructing it subscribes to
|
||||
* session and subagent lifecycle events, forwarding durable session
|
||||
@@ -92,7 +83,6 @@ export class HarnessSdkServer {
|
||||
private llmFiber: { dispose(): Promise<void> } | undefined
|
||||
private readonly sessions = new Map<string, SessionRecord>()
|
||||
private readonly sessionCreations = new Map<string, Promise<SessionRecord>>()
|
||||
private readonly localRuns = new Map<string, Map<SessionId, Map<Agent, number>>>()
|
||||
private readonly disposers: (() => void)[] = []
|
||||
private shutdownTask: Promise<Record<string, never>> | undefined
|
||||
private shuttingDown = false
|
||||
@@ -116,36 +106,12 @@ export class HarnessSdkServer {
|
||||
childSessionId: String(session.id),
|
||||
})
|
||||
}))
|
||||
// In-process providers publish the child before start. Count starts related
|
||||
// by exact runtime ownership or durable parent lineage so provider-owned
|
||||
// roots remain local, completions survive child disposal, and reused ids
|
||||
// need no settlement-order assumption.
|
||||
const localRuns = this.localRuns
|
||||
this.disposers.push(ctx.on('subagent/start', function (this: Scoped<SubagentService>, info: SubagentRunInfo) {
|
||||
const parent = subagentParentOf(this)
|
||||
if (!isLocalChild(ctx, info.id, parent)) return
|
||||
const providerRuns = localRuns.get(info.provider) ?? new Map<SessionId, Map<Agent, number>>()
|
||||
const parentRuns = providerRuns.get(info.id) ?? new Map<Agent, number>()
|
||||
parentRuns.set(parent, (parentRuns.get(parent) ?? 0) + 1)
|
||||
providerRuns.set(info.id, parentRuns)
|
||||
localRuns.set(info.provider, providerRuns)
|
||||
}))
|
||||
this.disposers.push(ctx.on('subagent/end', function (this: Scoped<SubagentService>, info: SubagentRunEndInfo) {
|
||||
const parent = subagentParentOf(this)
|
||||
const providerRuns = localRuns.get(info.provider)
|
||||
const parentRuns = providerRuns?.get(info.id)
|
||||
const pendingCount = parentRuns?.get(parent)
|
||||
if (pendingCount !== undefined) {
|
||||
if (pendingCount === 1) parentRuns?.delete(parent)
|
||||
else parentRuns?.set(parent, pendingCount - 1)
|
||||
if (parentRuns?.size === 0) providerRuns?.delete(info.id)
|
||||
if (providerRuns?.size === 0) localRuns.delete(info.provider)
|
||||
}
|
||||
// This protocol reports LOCAL child sessions. A lineage-bearing child
|
||||
// has the session/created-driven start notification above. A remote run
|
||||
// has neither a cached local start nor a live child related to this
|
||||
// parent; an unrelated local agent with the same id never makes it local.
|
||||
if (pendingCount === undefined && !isLocalChild(ctx, info.id, parent)) return
|
||||
// This protocol reports only in-process child sessions. The service
|
||||
// snapshots the provider's exact run provenance through child disposal;
|
||||
// matching ids or parent lineage alone never establishes locality.
|
||||
if (!info.local) return
|
||||
transport.notify('subagent.finished', {
|
||||
provider: info.provider,
|
||||
agentId: String(info.id),
|
||||
@@ -223,7 +189,6 @@ export class HarnessSdkServer {
|
||||
this.sessionCreations.clear()
|
||||
const records = [...this.sessions.values()]
|
||||
this.sessions.clear()
|
||||
this.localRuns.clear()
|
||||
const failures: unknown[] = []
|
||||
while (this.disposers.length > 0) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user