File size: 2,637 Bytes
4c76b0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import type { SubagentLifecycleHookRunner } from "../../../plugins/hooks.js";
import type { DeliveryContext } from "../../../utils/delivery-context.types.js";
import type { SpawnSubagentMode } from "./subagent-spawn.types.js";

export function createSubagentSpawnLifecycleEmitter(params: {
  hookRunner: SubagentLifecycleHookRunner | null;
  childSessionKey: string;
  requesterInternalKey: string;
  progressOrigin: {
    channel?: string;
    accountId?: string;
    to?: string;
    threadId?: string | number;
    channelId?: string;
    messageId?: string | number;
  };
  targetAgentId: string;
  label?: string;
  requesterOrigin?: DeliveryContext;
  requestThreadBinding: boolean;
  spawnMode: SpawnSubagentMode;
  resolvedModelMetadata: {
    resolvedModel?: string;
    resolvedProvider?: string;
  };
}): (hookRunId: string) => Promise<void> {
  // "spawned"/"started" hooks mean an accepted Gateway run. Direct runs emit
  // after the shared pipeline; queued collectors emit from the scheduler start.
  return async (hookRunId: string) => {
    if (params.hookRunner?.hasHooks("subagent_progress")) {
      try {
        await params.hookRunner.runSubagentProgress(
          {
            phase: "started",
            runId: hookRunId,
            childSessionKey: params.childSessionKey,
            requester: params.progressOrigin,
          },
          {
            runId: hookRunId,
            childSessionKey: params.childSessionKey,
            requesterSessionKey: params.requesterInternalKey,
          },
        );
      } catch {
        // Presentation hooks are best-effort after durable registration.
      }
    }
    if (params.hookRunner?.hasHooks("subagent_spawned")) {
      try {
        await params.hookRunner.runSubagentSpawned(
          {
            runId: hookRunId,
            childSessionKey: params.childSessionKey,
            agentId: params.targetAgentId,
            label: params.label,
            requester: {
              channel: params.requesterOrigin?.channel,
              accountId: params.requesterOrigin?.accountId,
              to: params.requesterOrigin?.to,
              threadId: params.requesterOrigin?.threadId,
            },
            threadRequested: params.requestThreadBinding,
            mode: params.spawnMode,
            ...params.resolvedModelMetadata,
          },
          {
            runId: hookRunId,
            childSessionKey: params.childSessionKey,
            requesterSessionKey: params.requesterInternalKey,
          },
        );
      } catch {
        // Spawn stays accepted if lifecycle presentation fails.
      }
    }
  };
}