@minpeter/pss-runtime 0.1.0-next.2 → 0.1.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +166 -78
  2. package/dist/agent-host-session-store.js +2 -4
  3. package/dist/agent-host-session-store.js.map +1 -1
  4. package/dist/agent-loop.js +2 -3
  5. package/dist/agent-loop.js.map +1 -1
  6. package/dist/agent-namespace.js +3 -7
  7. package/dist/agent-namespace.js.map +1 -1
  8. package/dist/agent-options.d.ts +2 -8
  9. package/dist/agent-options.js +4 -4
  10. package/dist/agent-options.js.map +1 -1
  11. package/dist/agent-resume.js +2 -82
  12. package/dist/agent-resume.js.map +1 -1
  13. package/dist/agent-session-entry.d.ts +1 -1
  14. package/dist/agent.d.ts +4 -4
  15. package/dist/agent.js +16 -70
  16. package/dist/agent.js.map +1 -1
  17. package/dist/cloudflare/cloudflare-agent-context.d.ts +40 -0
  18. package/dist/cloudflare/cloudflare-agent-context.js +37 -0
  19. package/dist/cloudflare/cloudflare-agent-context.js.map +1 -0
  20. package/dist/cloudflare/cloudflare-alarm-budget.d.ts +18 -0
  21. package/dist/cloudflare/cloudflare-alarm-budget.js +77 -0
  22. package/dist/cloudflare/cloudflare-alarm-budget.js.map +1 -0
  23. package/dist/cloudflare/cloudflare-alarm-drainer.d.ts +45 -0
  24. package/dist/cloudflare/cloudflare-alarm-drainer.js +103 -0
  25. package/dist/cloudflare/cloudflare-alarm-drainer.js.map +1 -0
  26. package/dist/cloudflare/cloudflare-alarm-run-drain.d.ts +13 -0
  27. package/dist/cloudflare/cloudflare-alarm-run-drain.js +81 -0
  28. package/dist/cloudflare/cloudflare-alarm-run-drain.js.map +1 -0
  29. package/dist/cloudflare/cloudflare-alarm-work.js +110 -0
  30. package/dist/cloudflare/cloudflare-alarm-work.js.map +1 -0
  31. package/dist/cloudflare/cloudflare-checkpoint-store.js +39 -0
  32. package/dist/cloudflare/cloudflare-checkpoint-store.js.map +1 -0
  33. package/dist/cloudflare/cloudflare-durable-object-fetch.d.ts +21 -0
  34. package/dist/cloudflare/cloudflare-durable-object-fetch.js +11 -0
  35. package/dist/cloudflare/cloudflare-durable-object-fetch.js.map +1 -0
  36. package/dist/cloudflare/cloudflare-event-store.js +33 -0
  37. package/dist/cloudflare/cloudflare-event-store.js.map +1 -0
  38. package/dist/cloudflare/cloudflare-execution-session-store.js +40 -0
  39. package/dist/cloudflare/cloudflare-execution-session-store.js.map +1 -0
  40. package/dist/cloudflare/cloudflare-execution-store.js +35 -0
  41. package/dist/cloudflare/cloudflare-execution-store.js.map +1 -0
  42. package/dist/cloudflare/cloudflare-host.d.ts +61 -0
  43. package/dist/cloudflare/cloudflare-host.js +113 -0
  44. package/dist/cloudflare/cloudflare-host.js.map +1 -0
  45. package/dist/cloudflare/cloudflare-notification-store.js +59 -0
  46. package/dist/cloudflare/cloudflare-notification-store.js.map +1 -0
  47. package/dist/cloudflare/cloudflare-run-store.js +81 -0
  48. package/dist/cloudflare/cloudflare-run-store.js.map +1 -0
  49. package/dist/cloudflare/cloudflare-store-utils.js +43 -0
  50. package/dist/cloudflare/cloudflare-store-utils.js.map +1 -0
  51. package/dist/cloudflare/durable-object-storage.d.ts +20 -0
  52. package/dist/cloudflare/durable-object-storage.js +76 -0
  53. package/dist/cloudflare/durable-object-storage.js.map +1 -0
  54. package/dist/cloudflare/index.d.ts +7 -0
  55. package/dist/cloudflare/index.js +6 -0
  56. package/dist/execution/capabilities.d.ts +40 -0
  57. package/dist/execution/host.d.ts +9 -0
  58. package/dist/execution/host.js +49 -1
  59. package/dist/execution/host.js.map +1 -1
  60. package/dist/execution/index.d.ts +3 -1
  61. package/dist/execution/index.js +2 -1
  62. package/dist/execution/memory.js +1 -1
  63. package/dist/execution/memory.js.map +1 -1
  64. package/dist/execution/types.d.ts +5 -10
  65. package/dist/index.d.ts +8 -4
  66. package/dist/index.js +6 -1
  67. package/dist/plugins.d.ts +25 -3
  68. package/dist/plugins.js +35 -6
  69. package/dist/plugins.js.map +1 -1
  70. package/dist/session/delegate-input.d.ts +9 -0
  71. package/dist/session/delegate-input.js +16 -0
  72. package/dist/session/delegate-input.js.map +1 -0
  73. package/dist/session/events.d.ts +43 -25
  74. package/dist/session/events.js +41 -0
  75. package/dist/session/events.js.map +1 -0
  76. package/dist/session/input-meta-types.d.ts +10 -0
  77. package/dist/session/input-meta.d.ts +13 -0
  78. package/dist/session/input-meta.js +45 -0
  79. package/dist/session/input-meta.js.map +1 -0
  80. package/dist/session/input.d.ts +4 -0
  81. package/dist/session/mapping.js +4 -2
  82. package/dist/session/mapping.js.map +1 -1
  83. package/dist/session/runtime-input-emit.js +41 -0
  84. package/dist/session/runtime-input-emit.js.map +1 -0
  85. package/dist/session/runtime-input.js +5 -1
  86. package/dist/session/runtime-input.js.map +1 -1
  87. package/dist/session/session-events.js +20 -6
  88. package/dist/session/session-events.js.map +1 -1
  89. package/dist/session/session-notification.js +3 -2
  90. package/dist/session/session-notification.js.map +1 -1
  91. package/dist/session/session-runtime-drain.js +3 -9
  92. package/dist/session/session-runtime-drain.js.map +1 -1
  93. package/dist/session/session-turn-processor.js +7 -17
  94. package/dist/session/session-turn-processor.js.map +1 -1
  95. package/dist/session/session.js +11 -4
  96. package/dist/session/session.js.map +1 -1
  97. package/package.json +6 -1
  98. package/dist/agent-child-runs.js +0 -16
  99. package/dist/agent-child-runs.js.map +0 -1
  100. package/dist/agent-host-capabilities.js +0 -9
  101. package/dist/agent-host-capabilities.js.map +0 -1
  102. package/dist/agent-validation.js +0 -35
  103. package/dist/agent-validation.js.map +0 -1
  104. package/dist/child-session-cleanups.js +0 -61
  105. package/dist/child-session-cleanups.js.map +0 -1
  106. package/dist/execution/run.js +0 -55
  107. package/dist/execution/run.js.map +0 -1
  108. package/dist/subagent-background-child-run-state.js +0 -51
  109. package/dist/subagent-background-child-run-state.js.map +0 -1
  110. package/dist/subagent-background-child-run.js +0 -103
  111. package/dist/subagent-background-child-run.js.map +0 -1
  112. package/dist/subagent-background-in-process.js +0 -98
  113. package/dist/subagent-background-in-process.js.map +0 -1
  114. package/dist/subagent-background-notification-inbox.js +0 -106
  115. package/dist/subagent-background-notification-inbox.js.map +0 -1
  116. package/dist/subagent-background-notify.js +0 -136
  117. package/dist/subagent-background-notify.js.map +0 -1
  118. package/dist/subagent-background-resume-group.js +0 -99
  119. package/dist/subagent-background-resume-group.js.map +0 -1
  120. package/dist/subagent-background-runner.js +0 -115
  121. package/dist/subagent-background-runner.js.map +0 -1
  122. package/dist/subagent-background-schedule.js +0 -43
  123. package/dist/subagent-background-schedule.js.map +0 -1
  124. package/dist/subagent-child-run.js +0 -68
  125. package/dist/subagent-child-run.js.map +0 -1
  126. package/dist/subagent-job-cancel.js +0 -84
  127. package/dist/subagent-job-cancel.js.map +0 -1
  128. package/dist/subagent-job-observer.js +0 -19
  129. package/dist/subagent-job-observer.js.map +0 -1
  130. package/dist/subagent-job-output.js +0 -87
  131. package/dist/subagent-job-output.js.map +0 -1
  132. package/dist/subagent-job-state.js +0 -66
  133. package/dist/subagent-job-state.js.map +0 -1
  134. package/dist/subagent-jobs.js +0 -96
  135. package/dist/subagent-jobs.js.map +0 -1
  136. package/dist/subagent-prompt-schema.js +0 -114
  137. package/dist/subagent-prompt-schema.js.map +0 -1
  138. package/dist/subagent-run.js +0 -111
  139. package/dist/subagent-run.js.map +0 -1
  140. package/dist/subagents.js +0 -125
  141. package/dist/subagents.js.map +0 -1
@@ -1,103 +0,0 @@
1
- import { durableBackgroundChildRunState } from "./subagent-background-child-run-state.js";
2
- //#region src/subagent-background-child-run.ts
3
- function createBackgroundTaskId() {
4
- return `bg_${crypto.randomUUID().replaceAll("-", "")}`;
5
- }
6
- async function createDurableBackgroundTaskId({ delegateToolCallId, prompt, sessionKey }) {
7
- const digestInput = backgroundSubagentDedupeKey({
8
- delegateToolCallId,
9
- prompt,
10
- sessionKey
11
- });
12
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(digestInput));
13
- return `bg_${[...new Uint8Array(digest.slice(0, 16))].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
14
- }
15
- async function getBackgroundChildRun({ delegateToolCallId, executionHost, prompt, sessionKey }) {
16
- if (!executionHost) return;
17
- const dedupeKey = backgroundSubagentDedupeKey({
18
- delegateToolCallId,
19
- prompt,
20
- sessionKey
21
- });
22
- return await executionHost.store.runs.getByDedupeKey(dedupeKey) ?? void 0;
23
- }
24
- async function getOrCreateBackgroundChildRun(input) {
25
- if (!input.executionHost) return;
26
- const id = input.publicTaskId ?? createBackgroundTaskId();
27
- const dedupeKey = backgroundSubagentDedupeKey(input);
28
- return await input.executionHost.store.transaction(async (tx) => {
29
- const existing = await tx.runs.getByDedupeKey(dedupeKey);
30
- if (existing) return existing;
31
- const parentRunId = input.parentRunId ?? input.parentSessionKey ?? input.sessionKey;
32
- const runtimeState = durableBackgroundChildRunState(input);
33
- const run = {
34
- checkpointVersion: 0,
35
- dedupeKey,
36
- kind: "background-subagent",
37
- ...input.ownerNamespace ? { ownerNamespace: input.ownerNamespace } : {},
38
- parentRunId,
39
- publicTaskId: id,
40
- rootRunId: parentRunId,
41
- runId: `background:${id}`,
42
- sessionKey: `${input.sessionKey}:task:${id}`,
43
- status: "queued"
44
- };
45
- await tx.runs.create(run);
46
- await tx.checkpoints.append({
47
- checkpointId: crypto.randomUUID(),
48
- phase: "before-child-run",
49
- runId: run.runId,
50
- runtimeState,
51
- sessionSnapshot: {},
52
- version: 1
53
- }, { expectedVersion: 0 });
54
- await tx.checkpoints.append({
55
- checkpointId: crypto.randomUUID(),
56
- childRunId: run.runId,
57
- phase: "child-linked",
58
- runId: run.runId,
59
- runtimeState,
60
- sessionSnapshot: {},
61
- version: 2
62
- }, { expectedVersion: 1 });
63
- return await tx.runs.get(run.runId) ?? run;
64
- });
65
- }
66
- async function updateBackgroundRunStatus(job, status) {
67
- if (!(job.executionHost && job.childRunId)) return true;
68
- return await job.executionHost.store.transaction(async (tx) => {
69
- const run = await tx.runs.get(job.childRunId ?? "");
70
- if (!run || isTerminalBackgroundRunStatus(run.status)) return false;
71
- if (job.childRunLeaseId && run.lease?.leaseId !== job.childRunLeaseId) return false;
72
- await tx.runs.update({
73
- ...run,
74
- output: job.result ?? run.output,
75
- status
76
- });
77
- return true;
78
- });
79
- }
80
- async function cancelBackgroundChildRun({ executionHost, runId }) {
81
- return await executionHost.store.transaction(async (tx) => {
82
- const run = await tx.runs.get(runId);
83
- if (!run || isTerminalBackgroundRunStatus(run.status)) return run;
84
- return await tx.runs.update({
85
- ...run,
86
- status: "cancelled"
87
- });
88
- });
89
- }
90
- function childRunStatus(result) {
91
- if (result === "aborted") return "cancelled";
92
- return result;
93
- }
94
- function backgroundSubagentDedupeKey({ delegateToolCallId, prompt, sessionKey }) {
95
- return `background-subagent:${sessionKey}:${delegateToolCallId ?? "unknown"}:${JSON.stringify(prompt)}`;
96
- }
97
- function isTerminalBackgroundRunStatus(status) {
98
- return status === "cancelled" || status === "completed" || status === "error";
99
- }
100
- //#endregion
101
- export { cancelBackgroundChildRun, childRunStatus, createBackgroundTaskId, createDurableBackgroundTaskId, getBackgroundChildRun, getOrCreateBackgroundChildRun, updateBackgroundRunStatus };
102
-
103
- //# sourceMappingURL=subagent-background-child-run.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subagent-background-child-run.js","names":[],"sources":["../src/subagent-background-child-run.ts"],"sourcesContent":["import type { ExecutionHost, RunRecord, RunStatus } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\nimport { durableBackgroundChildRunState } from \"./subagent-background-child-run-state\";\nimport type { SubagentJob } from \"./subagent-types\";\n\ninterface BackgroundChildRunInput {\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly executionHost?: ExecutionHost;\n readonly groupId?: string;\n readonly ownerNamespace?: string;\n readonly parentRunId?: string;\n readonly parentSessionKey?: string;\n readonly prompt: AgentInput;\n readonly publicTaskId?: string;\n readonly sessionKey: string;\n readonly subagent?: string;\n}\n\nexport function createBackgroundTaskId(): string {\n return `bg_${crypto.randomUUID().replaceAll(\"-\", \"\")}`;\n}\n\nexport async function createDurableBackgroundTaskId({\n delegateToolCallId,\n prompt,\n sessionKey,\n}: Pick<\n BackgroundChildRunInput,\n \"delegateToolCallId\" | \"prompt\" | \"sessionKey\"\n>): Promise<string> {\n const digestInput = backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n });\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(digestInput)\n );\n const bytes = [...new Uint8Array(digest.slice(0, 16))];\n const hex = bytes.map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n return `bg_${hex}`;\n}\n\nexport async function getBackgroundChildRun({\n delegateToolCallId,\n executionHost,\n prompt,\n sessionKey,\n}: BackgroundChildRunInput): Promise<RunRecord | undefined> {\n if (!executionHost) {\n return;\n }\n\n const dedupeKey = backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n });\n return (\n (await executionHost.store.runs.getByDedupeKey(dedupeKey)) ?? undefined\n );\n}\n\nexport async function getOrCreateBackgroundChildRun(\n input: BackgroundChildRunInput\n): Promise<RunRecord | undefined> {\n if (!input.executionHost) {\n return;\n }\n\n const id = input.publicTaskId ?? createBackgroundTaskId();\n const dedupeKey = backgroundSubagentDedupeKey(input);\n return await input.executionHost.store.transaction(async (tx) => {\n const existing = await tx.runs.getByDedupeKey(dedupeKey);\n if (existing) {\n return existing;\n }\n\n const parentRunId =\n input.parentRunId ?? input.parentSessionKey ?? input.sessionKey;\n const runtimeState = durableBackgroundChildRunState(input);\n const run: RunRecord = {\n checkpointVersion: 0,\n dedupeKey,\n kind: \"background-subagent\",\n ...(input.ownerNamespace ? { ownerNamespace: input.ownerNamespace } : {}),\n parentRunId,\n publicTaskId: id,\n rootRunId: parentRunId,\n runId: `background:${id}`,\n sessionKey: `${input.sessionKey}:task:${id}`,\n status: \"queued\",\n };\n await tx.runs.create(run);\n await tx.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n phase: \"before-child-run\",\n runId: run.runId,\n runtimeState,\n sessionSnapshot: {},\n version: 1,\n },\n { expectedVersion: 0 }\n );\n await tx.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n childRunId: run.runId,\n phase: \"child-linked\",\n runId: run.runId,\n runtimeState,\n sessionSnapshot: {},\n version: 2,\n },\n { expectedVersion: 1 }\n );\n return (await tx.runs.get(run.runId)) ?? run;\n });\n}\n\nexport async function updateBackgroundRunStatus(\n job: SubagentJob,\n status: Extract<RunStatus, \"cancelled\" | \"completed\" | \"error\">\n): Promise<boolean> {\n if (!(job.executionHost && job.childRunId)) {\n return true;\n }\n\n return await job.executionHost.store.transaction(async (tx) => {\n const run = await tx.runs.get(job.childRunId ?? \"\");\n if (!run || isTerminalBackgroundRunStatus(run.status)) {\n return false;\n }\n if (job.childRunLeaseId && run.lease?.leaseId !== job.childRunLeaseId) {\n return false;\n }\n\n await tx.runs.update({\n ...run,\n output: job.result ?? run.output,\n status,\n });\n return true;\n });\n}\n\nexport async function cancelBackgroundChildRun({\n executionHost,\n runId,\n}: {\n readonly executionHost: ExecutionHost;\n readonly runId: string;\n}): Promise<RunRecord | null> {\n return await executionHost.store.transaction(async (tx) => {\n const run = await tx.runs.get(runId);\n if (!run || isTerminalBackgroundRunStatus(run.status)) {\n return run;\n }\n\n return await tx.runs.update({ ...run, status: \"cancelled\" });\n });\n}\n\nexport function childRunStatus(\n result: Exclude<SubagentJob[\"status\"], \"cancelled\" | \"pending\" | \"running\">\n): Extract<RunStatus, \"cancelled\" | \"completed\" | \"error\"> {\n if (result === \"aborted\") {\n return \"cancelled\";\n }\n\n return result;\n}\n\nfunction backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n}: {\n readonly delegateToolCallId?: string;\n readonly prompt: AgentInput;\n readonly sessionKey: string;\n}): string {\n return `background-subagent:${sessionKey}:${delegateToolCallId ?? \"unknown\"}:${JSON.stringify(prompt)}`;\n}\n\nfunction isTerminalBackgroundRunStatus(status: RunStatus): boolean {\n return status === \"cancelled\" || status === \"completed\" || status === \"error\";\n}\n"],"mappings":"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"}
@@ -1,98 +0,0 @@
1
- import { cancelBackgroundChildRun } from "./subagent-background-child-run.js";
2
- import { backgroundCancelledLaunchOutput, backgroundLaunchOutput, backgroundReplayOutput, backgroundRunJobStatus } from "./subagent-job-state.js";
3
- import { registerBackgroundJobGroup } from "./subagent-background-notify.js";
4
- import { runBackgroundJob } from "./subagent-background-runner.js";
5
- //#region src/subagent-background-in-process.ts
6
- async function startInProcessBackgroundJob({ abortSignal, childRun, delegateToolCallId, description, executionHost, groupId, groups, id, jobs, parentRunId, parentSession, parentSessionKey, ownerNamespace, prompt, registerCleanup, sessionKey, subagent }) {
7
- const subagentName = subagent.name ?? "subagent";
8
- const claimedChildRun = childRun ? await claimBackgroundChildRun({
9
- executionHost,
10
- run: childRun,
11
- subagent: subagentName
12
- }) : void 0;
13
- if (claimedChildRun?.replay) return claimedChildRun.replay;
14
- if (abortSignal.aborted) {
15
- if (executionHost && claimedChildRun?.run) await cancelBackgroundChildRun({
16
- executionHost,
17
- runId: claimedChildRun.run.runId
18
- });
19
- return backgroundCancelledLaunchOutput({
20
- id,
21
- subagent: subagent.name
22
- });
23
- }
24
- const childSessionKey = claimedChildRun?.run.sessionKey ?? `${sessionKey}:task:${id}`;
25
- const childSession = subagent.session(childSessionKey);
26
- const abort = () => childSession.interrupt();
27
- abortSignal.addEventListener("abort", abort, { once: true });
28
- const cleanup = () => childSession.delete();
29
- const unregisterCleanup = registerCleanup(cleanup);
30
- const job = {
31
- abort,
32
- childRunId: claimedChildRun?.run.runId,
33
- childRunLeaseId: claimedChildRun?.run.lease?.leaseId,
34
- cleanup,
35
- dedupeKey: claimedChildRun?.run.dedupeKey,
36
- description,
37
- id,
38
- delegateToolCallId,
39
- executionHost,
40
- ownerNamespace,
41
- parentSessionKey,
42
- parentRunId,
43
- promise: Promise.resolve(),
44
- groupId,
45
- sessionKey: childSessionKey,
46
- settled: false,
47
- status: "pending",
48
- subagent: subagentName,
49
- unregisterCleanup
50
- };
51
- jobs.set(id, job);
52
- registerBackgroundJobGroup({
53
- groupId,
54
- groups,
55
- job
56
- });
57
- await parentSession.emitObserverEvent({
58
- description,
59
- delegateToolCallId,
60
- run_in_background: true,
61
- subagent: subagentName,
62
- task_id: id,
63
- type: "subagent-job-start"
64
- });
65
- job.status = "running";
66
- job.promise = runBackgroundJob({
67
- childSession,
68
- groups,
69
- jobs,
70
- job,
71
- parentSession,
72
- prompt
73
- }).finally(() => {
74
- abortSignal.removeEventListener("abort", abort);
75
- job.settled = true;
76
- });
77
- return backgroundLaunchOutput(job);
78
- }
79
- async function claimBackgroundChildRun({ executionHost, run, subagent }) {
80
- if (!executionHost) return { run };
81
- const claim = await executionHost.store.runs.claim(run.runId, {
82
- attempt: (run.lease?.attempt ?? 0) + 1,
83
- leaseId: crypto.randomUUID(),
84
- leaseMs: 3e5,
85
- nowMs: Date.now()
86
- });
87
- if (claim.ok) return { run: claim.record };
88
- const status = backgroundRunJobStatus((await executionHost.store.runs.get(run.runId))?.status) ?? "pending";
89
- return { replay: backgroundReplayOutput({
90
- id: run.publicTaskId ?? run.runId,
91
- status,
92
- subagent
93
- }) };
94
- }
95
- //#endregion
96
- export { startInProcessBackgroundJob };
97
-
98
- //# sourceMappingURL=subagent-background-in-process.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subagent-background-in-process.js","names":[],"sources":["../src/subagent-background-in-process.ts"],"sourcesContent":["import type { ExecutionHost, RunRecord } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\nimport { cancelBackgroundChildRun } from \"./subagent-background-child-run\";\nimport { registerBackgroundJobGroup } from \"./subagent-background-notify\";\nimport { runBackgroundJob } from \"./subagent-background-runner\";\nimport {\n backgroundCancelledLaunchOutput,\n backgroundLaunchOutput,\n backgroundReplayOutput,\n backgroundRunJobStatus,\n} from \"./subagent-job-state\";\nimport type {\n RuntimeInputSink,\n Subagent,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nexport async function startInProcessBackgroundJob({\n abortSignal,\n childRun,\n delegateToolCallId,\n description,\n executionHost,\n groupId,\n groups,\n id,\n jobs,\n parentRunId,\n parentSession,\n parentSessionKey,\n ownerNamespace,\n prompt,\n registerCleanup,\n sessionKey,\n subagent,\n}: {\n readonly abortSignal: AbortSignal;\n readonly childRun?: RunRecord;\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly executionHost?: ExecutionHost;\n readonly groupId?: string;\n readonly groups: Map<string, SubagentJobGroup>;\n readonly id: string;\n readonly jobs: Map<string, SubagentJob>;\n readonly parentRunId?: string;\n readonly parentSession: RuntimeInputSink;\n readonly parentSessionKey?: string;\n readonly ownerNamespace?: string;\n readonly prompt: AgentInput;\n readonly registerCleanup: (cleanup: () => Promise<void>) => () => void;\n readonly sessionKey: string;\n readonly subagent: Subagent;\n}) {\n const subagentName = subagent.name ?? \"subagent\";\n const claimedChildRun = childRun\n ? await claimBackgroundChildRun({\n executionHost,\n run: childRun,\n subagent: subagentName,\n })\n : undefined;\n if (claimedChildRun?.replay) {\n return claimedChildRun.replay;\n }\n if (abortSignal.aborted) {\n if (executionHost && claimedChildRun?.run) {\n await cancelBackgroundChildRun({\n executionHost,\n runId: claimedChildRun.run.runId,\n });\n }\n return backgroundCancelledLaunchOutput({ id, subagent: subagent.name });\n }\n\n const childSessionKey =\n claimedChildRun?.run.sessionKey ?? `${sessionKey}:task:${id}`;\n const childSession = subagent.session(childSessionKey);\n const abort = () => childSession.interrupt();\n abortSignal.addEventListener(\"abort\", abort, { once: true });\n const cleanup = () => childSession.delete();\n const unregisterCleanup = registerCleanup(cleanup);\n const job: SubagentJob = {\n abort,\n childRunId: claimedChildRun?.run.runId,\n childRunLeaseId: claimedChildRun?.run.lease?.leaseId,\n cleanup,\n dedupeKey: claimedChildRun?.run.dedupeKey,\n description,\n id,\n delegateToolCallId,\n executionHost,\n ownerNamespace,\n parentSessionKey,\n parentRunId,\n promise: Promise.resolve(),\n groupId,\n sessionKey: childSessionKey,\n settled: false,\n status: \"pending\",\n subagent: subagentName,\n unregisterCleanup,\n };\n jobs.set(id, job);\n registerBackgroundJobGroup({ groupId, groups, job });\n await parentSession.emitObserverEvent({\n description,\n delegateToolCallId,\n run_in_background: true,\n subagent: subagentName,\n task_id: id,\n type: \"subagent-job-start\",\n });\n job.status = \"running\";\n job.promise = runBackgroundJob({\n childSession,\n groups,\n jobs,\n job,\n parentSession,\n prompt,\n }).finally(() => {\n abortSignal.removeEventListener(\"abort\", abort);\n job.settled = true;\n });\n\n return backgroundLaunchOutput(job);\n}\n\nasync function claimBackgroundChildRun({\n executionHost,\n run,\n subagent,\n}: {\n readonly executionHost: ExecutionHost | undefined;\n readonly run: RunRecord;\n readonly subagent: string;\n}): Promise<\n | { readonly replay?: never; readonly run: RunRecord }\n | {\n readonly replay: ReturnType<typeof backgroundReplayOutput>;\n readonly run?: never;\n }\n> {\n if (!executionHost) {\n return { run };\n }\n\n const claim = await executionHost.store.runs.claim(run.runId, {\n attempt: (run.lease?.attempt ?? 0) + 1,\n leaseId: crypto.randomUUID(),\n leaseMs: 300_000,\n nowMs: Date.now(),\n });\n if (claim.ok) {\n return { run: claim.record };\n }\n\n const latestRun = await executionHost.store.runs.get(run.runId);\n const status = backgroundRunJobStatus(latestRun?.status) ?? \"pending\";\n return {\n replay: backgroundReplayOutput({\n id: run.publicTaskId ?? run.runId,\n status,\n subagent,\n }),\n };\n}\n"],"mappings":";;;;;AAkBA,eAAsB,4BAA4B,EAChD,aACA,UACA,oBACA,aACA,eACA,SACA,QACA,IACA,MACA,aACA,eACA,kBACA,gBACA,QACA,iBACA,YACA,YAmBC;CACD,MAAM,eAAe,SAAS,QAAQ;CACtC,MAAM,kBAAkB,WACpB,MAAM,wBAAwB;EAC5B;EACA,KAAK;EACL,UAAU;CACZ,CAAC,IACD,KAAA;CACJ,IAAI,iBAAiB,QACnB,OAAO,gBAAgB;CAEzB,IAAI,YAAY,SAAS;EACvB,IAAI,iBAAiB,iBAAiB,KACpC,MAAM,yBAAyB;GAC7B;GACA,OAAO,gBAAgB,IAAI;EAC7B,CAAC;EAEH,OAAO,gCAAgC;GAAE;GAAI,UAAU,SAAS;EAAK,CAAC;CACxE;CAEA,MAAM,kBACJ,iBAAiB,IAAI,cAAc,GAAG,WAAW,QAAQ;CAC3D,MAAM,eAAe,SAAS,QAAQ,eAAe;CACrD,MAAM,cAAc,aAAa,UAAU;CAC3C,YAAY,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CAC3D,MAAM,gBAAgB,aAAa,OAAO;CAC1C,MAAM,oBAAoB,gBAAgB,OAAO;CACjD,MAAM,MAAmB;EACvB;EACA,YAAY,iBAAiB,IAAI;EACjC,iBAAiB,iBAAiB,IAAI,OAAO;EAC7C;EACA,WAAW,iBAAiB,IAAI;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,QAAQ,QAAQ;EACzB;EACA,YAAY;EACZ,SAAS;EACT,QAAQ;EACR,UAAU;EACV;CACF;CACA,KAAK,IAAI,IAAI,GAAG;CAChB,2BAA2B;EAAE;EAAS;EAAQ;CAAI,CAAC;CACnD,MAAM,cAAc,kBAAkB;EACpC;EACA;EACA,mBAAmB;EACnB,UAAU;EACV,SAAS;EACT,MAAM;CACR,CAAC;CACD,IAAI,SAAS;CACb,IAAI,UAAU,iBAAiB;EAC7B;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,EAAE,cAAc;EACf,YAAY,oBAAoB,SAAS,KAAK;EAC9C,IAAI,UAAU;CAChB,CAAC;CAED,OAAO,uBAAuB,GAAG;AACnC;AAEA,eAAe,wBAAwB,EACrC,eACA,KACA,YAWA;CACA,IAAI,CAAC,eACH,OAAO,EAAE,IAAI;CAGf,MAAM,QAAQ,MAAM,cAAc,MAAM,KAAK,MAAM,IAAI,OAAO;EAC5D,UAAU,IAAI,OAAO,WAAW,KAAK;EACrC,SAAS,OAAO,WAAW;EAC3B,SAAS;EACT,OAAO,KAAK,IAAI;CAClB,CAAC;CACD,IAAI,MAAM,IACR,OAAO,EAAE,KAAK,MAAM,OAAO;CAI7B,MAAM,SAAS,wBAAuB,MADd,cAAc,MAAM,KAAK,IAAI,IAAI,KAAK,IACb,MAAM,KAAK;CAC5D,OAAO,EACL,QAAQ,uBAAuB;EAC7B,IAAI,IAAI,gBAAgB,IAAI;EAC5B;EACA;CACF,CAAC,EACH;AACF"}
@@ -1,106 +0,0 @@
1
- //#region src/subagent-background-notification-inbox.ts
2
- async function enqueueDurableBackgroundNotification({ input, jobs, observerEvents }) {
3
- const host = findExecutionHost(jobs);
4
- const parentSessionKey = findParentSessionKey(jobs);
5
- const ownerNamespace = findOwnerNamespace(jobs);
6
- if (!host) return "inline";
7
- if (await allChildRunsCancelled({
8
- host,
9
- jobs
10
- })) return "queued-only";
11
- if (!(parentSessionKey && ownerNamespace)) return "inline";
12
- if (host.capabilities.backgroundSubagents !== "durable") return "inline";
13
- const idempotencyKey = backgroundNotificationIdempotencyKey({
14
- jobs,
15
- parentSessionKey
16
- });
17
- const existing = await host.store.notifications.getByIdempotencyKey(idempotencyKey);
18
- if (existing) {
19
- if (existing.status === "pending" && host.capabilities.backgroundSubagents === "durable") await host.scheduler.resumeSession(existing.sessionKey, resumePayloadFromNotification(existing));
20
- return "queued-only";
21
- }
22
- const created = await createNotificationRecord({
23
- host,
24
- idempotencyKey,
25
- input,
26
- jobs,
27
- observerEvents,
28
- ownerNamespace,
29
- parentSessionKey
30
- });
31
- if (created) await host.scheduler.resumeSession(parentSessionKey, created);
32
- return "queued-only";
33
- }
34
- async function allChildRunsCancelled({ host, jobs }) {
35
- let childRunCount = 0;
36
- for (const job of jobs) {
37
- if (!job.childRunId) continue;
38
- childRunCount += 1;
39
- if ((await host.store.runs.get(job.childRunId))?.status !== "cancelled") return false;
40
- }
41
- return childRunCount > 0;
42
- }
43
- function findExecutionHost(jobs) {
44
- return jobs.find((job) => job.executionHost)?.executionHost;
45
- }
46
- function findParentSessionKey(jobs) {
47
- return jobs.find((job) => job.parentSessionKey)?.parentSessionKey;
48
- }
49
- function findOwnerNamespace(jobs) {
50
- return jobs.find((job) => job.ownerNamespace)?.ownerNamespace;
51
- }
52
- function backgroundNotificationIdempotencyKey({ jobs, parentSessionKey }) {
53
- return `background-complete:${parentSessionKey}:${jobs.map((job) => job.id).sort().join(",")}`;
54
- }
55
- async function createNotificationRecord({ host, idempotencyKey, input, jobs, observerEvents, ownerNamespace, parentSessionKey }) {
56
- const notificationId = `ntf_${crypto.randomUUID().replaceAll("-", "")}`;
57
- const runId = `notification:${notificationId}`;
58
- return await host.store.transaction(async (tx) => {
59
- if (await tx.notifications.getByIdempotencyKey(idempotencyKey)) return;
60
- if (!(await tx.notifications.enqueue({
61
- idempotencyKey,
62
- input,
63
- notificationId,
64
- observerEvents,
65
- ownerNamespace,
66
- runId,
67
- sessionKey: parentSessionKey,
68
- status: "pending"
69
- })).ok) return;
70
- await tx.runs.create({
71
- checkpointVersion: 0,
72
- dedupeKey: idempotencyKey,
73
- kind: "notification",
74
- ownerNamespace,
75
- parentRunId: jobs.length === 1 ? jobs[0]?.childRunId : void 0,
76
- rootRunId: runId,
77
- runId,
78
- sessionKey: parentSessionKey,
79
- status: "queued"
80
- });
81
- if (!(await tx.checkpoints.append({
82
- checkpointId: crypto.randomUUID(),
83
- phase: "before-notification",
84
- runId,
85
- runtimeState: {},
86
- sessionSnapshot: {},
87
- version: 1
88
- }, { expectedVersion: 0 })).ok) throw new Error("Failed to write background notification checkpoint.");
89
- return {
90
- idempotencyKey,
91
- notificationId,
92
- runId
93
- };
94
- });
95
- }
96
- function resumePayloadFromNotification(notification) {
97
- return {
98
- idempotencyKey: notification.idempotencyKey,
99
- notificationId: notification.notificationId,
100
- runId: notification.runId
101
- };
102
- }
103
- //#endregion
104
- export { enqueueDurableBackgroundNotification };
105
-
106
- //# sourceMappingURL=subagent-background-notification-inbox.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subagent-background-notification-inbox.js","names":[],"sources":["../src/subagent-background-notification-inbox.ts"],"sourcesContent":["import type { ExecutionHost } from \"./execution/types\";\nimport type { AgentEvent } from \"./session/events\";\nimport type { UserInput } from \"./session/input\";\nimport type { SubagentJob } from \"./subagent-types\";\n\ntype InlineNotificationMode = \"inline\" | \"queued-only\";\n\ninterface NotificationResumePayload {\n readonly idempotencyKey: string;\n readonly notificationId: string;\n readonly runId: string;\n}\n\nexport async function enqueueDurableBackgroundNotification({\n input,\n jobs,\n observerEvents,\n}: {\n readonly input: UserInput;\n readonly jobs: readonly SubagentJob[];\n readonly observerEvents: readonly AgentEvent[];\n}): Promise<InlineNotificationMode> {\n const host = findExecutionHost(jobs);\n const parentSessionKey = findParentSessionKey(jobs);\n const ownerNamespace = findOwnerNamespace(jobs);\n if (!host) {\n return \"inline\";\n }\n\n if (await allChildRunsCancelled({ host, jobs })) {\n return \"queued-only\";\n }\n\n if (!(parentSessionKey && ownerNamespace)) {\n return \"inline\";\n }\n\n if (host.capabilities.backgroundSubagents !== \"durable\") {\n return \"inline\";\n }\n\n const idempotencyKey = backgroundNotificationIdempotencyKey({\n jobs,\n parentSessionKey,\n });\n const existing =\n await host.store.notifications.getByIdempotencyKey(idempotencyKey);\n if (existing) {\n if (\n existing.status === \"pending\" &&\n host.capabilities.backgroundSubagents === \"durable\"\n ) {\n await host.scheduler.resumeSession(\n existing.sessionKey,\n resumePayloadFromNotification(existing)\n );\n }\n return \"queued-only\";\n }\n\n const created = await createNotificationRecord({\n host,\n idempotencyKey,\n input,\n jobs,\n observerEvents,\n ownerNamespace,\n parentSessionKey,\n });\n if (created) {\n await host.scheduler.resumeSession(parentSessionKey, created);\n }\n\n return \"queued-only\";\n}\n\nasync function allChildRunsCancelled({\n host,\n jobs,\n}: {\n readonly host: ExecutionHost;\n readonly jobs: readonly SubagentJob[];\n}): Promise<boolean> {\n let childRunCount = 0;\n for (const job of jobs) {\n if (!job.childRunId) {\n continue;\n }\n\n childRunCount += 1;\n const run = await host.store.runs.get(job.childRunId);\n if (run?.status !== \"cancelled\") {\n return false;\n }\n }\n\n return childRunCount > 0;\n}\n\nfunction findExecutionHost(\n jobs: readonly SubagentJob[]\n): ExecutionHost | undefined {\n return jobs.find((job) => job.executionHost)?.executionHost;\n}\n\nfunction findParentSessionKey(\n jobs: readonly SubagentJob[]\n): string | undefined {\n return jobs.find((job) => job.parentSessionKey)?.parentSessionKey;\n}\n\nfunction findOwnerNamespace(jobs: readonly SubagentJob[]): string | undefined {\n return jobs.find((job) => job.ownerNamespace)?.ownerNamespace;\n}\n\nfunction backgroundNotificationIdempotencyKey({\n jobs,\n parentSessionKey,\n}: {\n readonly jobs: readonly SubagentJob[];\n readonly parentSessionKey: string;\n}): string {\n const taskIds = jobs\n .map((job) => job.id)\n .sort()\n .join(\",\");\n return `background-complete:${parentSessionKey}:${taskIds}`;\n}\n\nasync function createNotificationRecord({\n host,\n idempotencyKey,\n input,\n jobs,\n observerEvents,\n ownerNamespace,\n parentSessionKey,\n}: {\n readonly host: ExecutionHost;\n readonly idempotencyKey: string;\n readonly input: UserInput;\n readonly jobs: readonly SubagentJob[];\n readonly observerEvents: readonly AgentEvent[];\n readonly ownerNamespace: string;\n readonly parentSessionKey: string;\n}): Promise<NotificationResumePayload | undefined> {\n const notificationId = `ntf_${crypto.randomUUID().replaceAll(\"-\", \"\")}`;\n const runId = `notification:${notificationId}`;\n return await host.store.transaction(async (tx) => {\n const duplicate =\n await tx.notifications.getByIdempotencyKey(idempotencyKey);\n if (duplicate) {\n return;\n }\n\n const enqueued = await tx.notifications.enqueue({\n idempotencyKey,\n input,\n notificationId,\n observerEvents,\n ownerNamespace,\n runId,\n sessionKey: parentSessionKey,\n status: \"pending\",\n });\n if (!enqueued.ok) {\n return;\n }\n\n await tx.runs.create({\n checkpointVersion: 0,\n dedupeKey: idempotencyKey,\n kind: \"notification\",\n ownerNamespace,\n parentRunId: jobs.length === 1 ? jobs[0]?.childRunId : undefined,\n rootRunId: runId,\n runId,\n sessionKey: parentSessionKey,\n status: \"queued\",\n });\n const checkpoint = await tx.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n phase: \"before-notification\",\n runId,\n runtimeState: {},\n sessionSnapshot: {},\n version: 1,\n },\n { expectedVersion: 0 }\n );\n if (!checkpoint.ok) {\n throw new Error(\"Failed to write background notification checkpoint.\");\n }\n return { idempotencyKey, notificationId, runId };\n });\n}\n\nfunction resumePayloadFromNotification(\n notification: NotificationResumePayload\n): NotificationResumePayload {\n return {\n idempotencyKey: notification.idempotencyKey,\n notificationId: notification.notificationId,\n runId: notification.runId,\n };\n}\n"],"mappings":";AAaA,eAAsB,qCAAqC,EACzD,OACA,MACA,kBAKkC;CAClC,MAAM,OAAO,kBAAkB,IAAI;CACnC,MAAM,mBAAmB,qBAAqB,IAAI;CAClD,MAAM,iBAAiB,mBAAmB,IAAI;CAC9C,IAAI,CAAC,MACH,OAAO;CAGT,IAAI,MAAM,sBAAsB;EAAE;EAAM;CAAK,CAAC,GAC5C,OAAO;CAGT,IAAI,EAAE,oBAAoB,iBACxB,OAAO;CAGT,IAAI,KAAK,aAAa,wBAAwB,WAC5C,OAAO;CAGT,MAAM,iBAAiB,qCAAqC;EAC1D;EACA;CACF,CAAC;CACD,MAAM,WACJ,MAAM,KAAK,MAAM,cAAc,oBAAoB,cAAc;CACnE,IAAI,UAAU;EACZ,IACE,SAAS,WAAW,aACpB,KAAK,aAAa,wBAAwB,WAE1C,MAAM,KAAK,UAAU,cACnB,SAAS,YACT,8BAA8B,QAAQ,CACxC;EAEF,OAAO;CACT;CAEA,MAAM,UAAU,MAAM,yBAAyB;EAC7C;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,IAAI,SACF,MAAM,KAAK,UAAU,cAAc,kBAAkB,OAAO;CAG9D,OAAO;AACT;AAEA,eAAe,sBAAsB,EACnC,MACA,QAImB;CACnB,IAAI,gBAAgB;CACpB,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,CAAC,IAAI,YACP;EAGF,iBAAiB;EAEjB,KAAI,MADc,KAAK,MAAM,KAAK,IAAI,IAAI,UAAU,IAC3C,WAAW,aAClB,OAAO;CAEX;CAEA,OAAO,gBAAgB;AACzB;AAEA,SAAS,kBACP,MAC2B;CAC3B,OAAO,KAAK,MAAM,QAAQ,IAAI,aAAa,GAAG;AAChD;AAEA,SAAS,qBACP,MACoB;CACpB,OAAO,KAAK,MAAM,QAAQ,IAAI,gBAAgB,GAAG;AACnD;AAEA,SAAS,mBAAmB,MAAkD;CAC5E,OAAO,KAAK,MAAM,QAAQ,IAAI,cAAc,GAAG;AACjD;AAEA,SAAS,qCAAqC,EAC5C,MACA,oBAIS;CAKT,OAAO,uBAAuB,iBAAiB,GAJ/B,KACb,KAAK,QAAQ,IAAI,EAAE,EACnB,KAAK,EACL,KAAK,GACgD;AAC1D;AAEA,eAAe,yBAAyB,EACtC,MACA,gBACA,OACA,MACA,gBACA,gBACA,oBASiD;CACjD,MAAM,iBAAiB,OAAO,OAAO,WAAW,EAAE,WAAW,KAAK,EAAE;CACpE,MAAM,QAAQ,gBAAgB;CAC9B,OAAO,MAAM,KAAK,MAAM,YAAY,OAAO,OAAO;EAGhD,IAAI,MADI,GAAG,cAAc,oBAAoB,cAAc,GAEzD;EAaF,IAAI,EAAC,MAVkB,GAAG,cAAc,QAAQ;GAC9C;GACA;GACA;GACA;GACA;GACA;GACA,YAAY;GACZ,QAAQ;EACV,CAAC,GACa,IACZ;EAGF,MAAM,GAAG,KAAK,OAAO;GACnB,mBAAmB;GACnB,WAAW;GACX,MAAM;GACN;GACA,aAAa,KAAK,WAAW,IAAI,KAAK,IAAI,aAAa,KAAA;GACvD,WAAW;GACX;GACA,YAAY;GACZ,QAAQ;EACV,CAAC;EAYD,IAAI,EAAC,MAXoB,GAAG,YAAY,OACtC;GACE,cAAc,OAAO,WAAW;GAChC,OAAO;GACP;GACA,cAAc,CAAC;GACf,iBAAiB,CAAC;GAClB,SAAS;EACX,GACA,EAAE,iBAAiB,EAAE,CACvB,GACgB,IACd,MAAM,IAAI,MAAM,qDAAqD;EAEvE,OAAO;GAAE;GAAgB;GAAgB;EAAM;CACjD,CAAC;AACH;AAEA,SAAS,8BACP,cAC2B;CAC3B,OAAO;EACL,gBAAgB,aAAa;EAC7B,gBAAgB,aAAa;EAC7B,OAAO,aAAa;CACtB;AACF"}
@@ -1,136 +0,0 @@
1
- import { enqueueDurableBackgroundNotification } from "./subagent-background-notification-inbox.js";
2
- //#region src/subagent-background-notify.ts
3
- function registerBackgroundJobGroup({ groupId, groups, job }) {
4
- if (!groupId) return;
5
- let group = groups.get(groupId);
6
- if (!group) {
7
- group = {
8
- completedEvents: [],
9
- failedNotifiedJobIds: /* @__PURE__ */ new Set(),
10
- finalNotified: false,
11
- id: groupId,
12
- jobIds: /* @__PURE__ */ new Set()
13
- };
14
- groups.set(groupId, group);
15
- }
16
- group.jobIds.add(job.id);
17
- }
18
- async function notifyBackgroundCompletion({ endEvent, groups, job, jobs, parentSession }) {
19
- const group = job.groupId ? groups.get(job.groupId) : void 0;
20
- if (!group) {
21
- await notifyParentSession({
22
- input: buildBackgroundReminder([job]),
23
- jobs: [job],
24
- observerEvents: [endEvent],
25
- parentSession
26
- });
27
- return;
28
- }
29
- group.completedEvents.push(endEvent);
30
- if (isFailureStatus(endEvent.status)) {
31
- group.failedNotifiedJobIds.add(job.id);
32
- await notifyParentSession({
33
- input: buildBackgroundReminder([job]),
34
- jobs: [job],
35
- observerEvents: [endEvent],
36
- parentSession
37
- });
38
- }
39
- if (!isGroupSettled(group, jobs) || group.finalNotified) return;
40
- group.finalNotified = true;
41
- const notifyableGroupJobs = [...group.jobIds].map((id) => jobs.get(id)).filter(isDefinedJob).filter((groupJob) => !group.failedNotifiedJobIds.has(groupJob.id));
42
- if (notifyableGroupJobs.length === 0) {
43
- groups.delete(group.id);
44
- return;
45
- }
46
- const observerEvents = group.completedEvents.filter((event) => !group.failedNotifiedJobIds.has(event.task_id ?? ""));
47
- await notifyParentSession({
48
- input: buildBackgroundReminder(notifyableGroupJobs),
49
- jobs: notifyableGroupJobs,
50
- observerEvents: [...observerEvents],
51
- parentSession
52
- });
53
- groups.delete(group.id);
54
- }
55
- async function notifyParentSession({ input, jobs, observerEvents, parentSession }) {
56
- try {
57
- if (await enqueueDurableBackgroundNotification({
58
- input,
59
- jobs,
60
- observerEvents
61
- }) === "queued-only") return;
62
- await Promise.all(observerEvents.map((event) => parentSession.emitObserverEvent(event)));
63
- await parentSession.notify(input, {
64
- deferWhenUnobserved: true,
65
- observerEvents
66
- });
67
- } catch (error) {
68
- await parentSession.emitObserverEvent({
69
- message: errorMessage(error),
70
- type: "turn-error"
71
- });
72
- }
73
- }
74
- function buildBackgroundReminder(jobs) {
75
- return {
76
- text: jobs.length === 1 ? buildSingleJobReminder(jobs[0]) : buildGroupReminder(jobs),
77
- type: "user-text"
78
- };
79
- }
80
- function buildSingleJobReminder(job) {
81
- if (!job) return [
82
- "<system-reminder>",
83
- "[BACKGROUND TASK COMPLETED]",
84
- "[SUBAGENT JOB RESULT READY]",
85
- "A background task completed, but its task metadata is no longer available.",
86
- "</system-reminder>"
87
- ].join("\n");
88
- return [
89
- "<system-reminder>",
90
- "[BACKGROUND TASK COMPLETED]",
91
- "[SUBAGENT JOB RESULT READY]",
92
- `Task ID: ${job.id}`,
93
- `Subagent: ${job.subagent}`,
94
- `Status: ${job.status}`,
95
- `Description: ${sanitizeReminderField(job.description ?? "")}`,
96
- `Use background_output({ task_id: "${job.id}" }) to retrieve the result.`,
97
- "</system-reminder>"
98
- ].join("\n");
99
- }
100
- function buildGroupReminder(jobs) {
101
- return [
102
- "<system-reminder>",
103
- "[ALL BACKGROUND TASKS COMPLETE]",
104
- `Completed task count: ${jobs.length}`,
105
- "Tasks:",
106
- ...jobs.map((job) => `- ${job.id} (${job.subagent}): ${job.status}. Description: ${sanitizeReminderField(job.description ?? "")}. Use background_output({ task_id: "${job.id}" }) to retrieve the result.`),
107
- "</system-reminder>"
108
- ].join("\n");
109
- }
110
- function isGroupSettled(group, jobs) {
111
- for (const id of group.jobIds) {
112
- const job = jobs.get(id);
113
- if (!job || isActiveJobStatus(job.status) || !job.settled) return false;
114
- }
115
- return true;
116
- }
117
- function isActiveJobStatus(status) {
118
- return status === "pending" || status === "running";
119
- }
120
- function isFailureStatus(status) {
121
- return status === "aborted" || status === "cancelled" || status === "error";
122
- }
123
- function isDefinedJob(job) {
124
- return job !== void 0;
125
- }
126
- function sanitizeReminderField(value) {
127
- return value.replaceAll("\r", " ").replaceAll("\n", " ").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
128
- }
129
- function errorMessage(error) {
130
- if (error instanceof Error) return error.message;
131
- return String(error);
132
- }
133
- //#endregion
134
- export { notifyBackgroundCompletion, registerBackgroundJobGroup };
135
-
136
- //# sourceMappingURL=subagent-background-notify.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subagent-background-notify.js","names":[],"sources":["../src/subagent-background-notify.ts"],"sourcesContent":["import type { AgentEvent } from \"./session/events\";\nimport type { UserInput } from \"./session/input\";\nimport { enqueueDurableBackgroundNotification } from \"./subagent-background-notification-inbox\";\nimport type {\n RuntimeInputSink,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nexport function registerBackgroundJobGroup({\n groupId,\n groups,\n job,\n}: {\n readonly groupId: string | undefined;\n readonly groups: Map<string, SubagentJobGroup>;\n readonly job: SubagentJob;\n}): void {\n if (!groupId) {\n return;\n }\n\n let group = groups.get(groupId);\n if (!group) {\n group = {\n completedEvents: [],\n failedNotifiedJobIds: new Set(),\n finalNotified: false,\n id: groupId,\n jobIds: new Set(),\n };\n groups.set(groupId, group);\n }\n group.jobIds.add(job.id);\n}\n\nexport async function notifyBackgroundCompletion({\n endEvent,\n groups,\n job,\n jobs,\n parentSession,\n}: {\n readonly endEvent: Extract<AgentEvent, { type: \"subagent-job-end\" }>;\n readonly groups: Map<string, SubagentJobGroup>;\n readonly job: SubagentJob;\n readonly jobs: Map<string, SubagentJob>;\n readonly parentSession: RuntimeInputSink;\n}): Promise<void> {\n const group = job.groupId ? groups.get(job.groupId) : undefined;\n if (!group) {\n await notifyParentSession({\n input: buildBackgroundReminder([job]),\n jobs: [job],\n observerEvents: [endEvent],\n parentSession,\n });\n return;\n }\n\n group.completedEvents.push(endEvent);\n if (isFailureStatus(endEvent.status)) {\n group.failedNotifiedJobIds.add(job.id);\n await notifyParentSession({\n input: buildBackgroundReminder([job]),\n jobs: [job],\n observerEvents: [endEvent],\n parentSession,\n });\n }\n\n if (!isGroupSettled(group, jobs) || group.finalNotified) {\n return;\n }\n\n group.finalNotified = true;\n const groupJobs = [...group.jobIds]\n .map((id) => jobs.get(id))\n .filter(isDefinedJob);\n const notifyableGroupJobs = groupJobs.filter(\n (groupJob) => !group.failedNotifiedJobIds.has(groupJob.id)\n );\n if (notifyableGroupJobs.length === 0) {\n groups.delete(group.id);\n return;\n }\n const observerEvents = group.completedEvents.filter(\n (event) => !group.failedNotifiedJobIds.has(event.task_id ?? \"\")\n );\n await notifyParentSession({\n input: buildBackgroundReminder(notifyableGroupJobs),\n jobs: notifyableGroupJobs,\n observerEvents: [...observerEvents],\n parentSession,\n });\n groups.delete(group.id);\n}\n\nasync function notifyParentSession({\n input,\n jobs,\n observerEvents,\n parentSession,\n}: {\n readonly input: UserInput;\n readonly jobs: readonly SubagentJob[];\n readonly observerEvents: readonly AgentEvent[];\n readonly parentSession: RuntimeInputSink;\n}): Promise<void> {\n try {\n const mode = await enqueueDurableBackgroundNotification({\n input,\n jobs,\n observerEvents,\n });\n if (mode === \"queued-only\") {\n return;\n }\n\n await Promise.all(\n observerEvents.map((event) => parentSession.emitObserverEvent(event))\n );\n await parentSession.notify(input, {\n deferWhenUnobserved: true,\n observerEvents,\n });\n } catch (error) {\n await parentSession.emitObserverEvent({\n message: errorMessage(error),\n type: \"turn-error\",\n });\n }\n}\n\nfunction buildBackgroundReminder(jobs: readonly SubagentJob[]): UserInput {\n const text =\n jobs.length === 1\n ? buildSingleJobReminder(jobs[0])\n : buildGroupReminder(jobs);\n return { text, type: \"user-text\" };\n}\n\nfunction buildSingleJobReminder(job: SubagentJob | undefined): string {\n if (!job) {\n return [\n \"<system-reminder>\",\n \"[BACKGROUND TASK COMPLETED]\",\n \"[SUBAGENT JOB RESULT READY]\",\n \"A background task completed, but its task metadata is no longer available.\",\n \"</system-reminder>\",\n ].join(\"\\n\");\n }\n\n return [\n \"<system-reminder>\",\n \"[BACKGROUND TASK COMPLETED]\",\n \"[SUBAGENT JOB RESULT READY]\",\n `Task ID: ${job.id}`,\n `Subagent: ${job.subagent}`,\n `Status: ${job.status}`,\n `Description: ${sanitizeReminderField(job.description ?? \"\")}`,\n `Use background_output({ task_id: \"${job.id}\" }) to retrieve the result.`,\n \"</system-reminder>\",\n ].join(\"\\n\");\n}\n\nfunction buildGroupReminder(jobs: readonly SubagentJob[]): string {\n return [\n \"<system-reminder>\",\n \"[ALL BACKGROUND TASKS COMPLETE]\",\n `Completed task count: ${jobs.length}`,\n \"Tasks:\",\n ...jobs.map(\n (job) =>\n `- ${job.id} (${job.subagent}): ${job.status}. Description: ${sanitizeReminderField(\n job.description ?? \"\"\n )}. Use background_output({ task_id: \"${job.id}\" }) to retrieve the result.`\n ),\n \"</system-reminder>\",\n ].join(\"\\n\");\n}\n\nfunction isGroupSettled(\n group: SubagentJobGroup,\n jobs: Map<string, SubagentJob>\n): boolean {\n for (const id of group.jobIds) {\n const job = jobs.get(id);\n if (!job || isActiveJobStatus(job.status) || !job.settled) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isActiveJobStatus(status: SubagentJob[\"status\"]): boolean {\n return status === \"pending\" || status === \"running\";\n}\n\nfunction isFailureStatus(\n status: Extract<AgentEvent, { type: \"subagent-job-end\" }>[\"status\"]\n): boolean {\n return status === \"aborted\" || status === \"cancelled\" || status === \"error\";\n}\n\nfunction isDefinedJob(job: SubagentJob | undefined): job is SubagentJob {\n return job !== undefined;\n}\n\nfunction sanitizeReminderField(value: string): string {\n return value\n .replaceAll(\"\\r\", \" \")\n .replaceAll(\"\\n\", \" \")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\");\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n"],"mappings":"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"}
@@ -1,99 +0,0 @@
1
- import { readDurableBackgroundChildRunState } from "./subagent-background-child-run-state.js";
2
- import { backgroundRunJobStatus, isActiveJob } from "./subagent-job-state.js";
3
- //#region src/subagent-background-resume-group.ts
4
- async function buildDurableResumeGroups({ currentJob, host, jobs, run, state }) {
5
- const groups = /* @__PURE__ */ new Map();
6
- if (!(state.groupId && run.parentRunId)) return groups;
7
- const group = {
8
- completedEvents: [],
9
- failedNotifiedJobIds: /* @__PURE__ */ new Set(),
10
- finalNotified: false,
11
- id: state.groupId,
12
- jobIds: /* @__PURE__ */ new Set()
13
- };
14
- groups.set(group.id, group);
15
- for (const sibling of await host.store.runs.listByParentRunId(run.parentRunId)) await addSiblingToGroup({
16
- currentJob,
17
- group,
18
- host,
19
- jobs,
20
- run,
21
- sibling,
22
- state
23
- });
24
- return groups;
25
- }
26
- async function addSiblingToGroup({ currentJob, group, host, jobs, run, sibling, state }) {
27
- if (sibling.kind !== "background-subagent") return;
28
- const siblingState = readDurableBackgroundChildRunState(await host.store.checkpoints.latest(sibling.runId));
29
- if (!siblingState || siblingState.groupId !== state.groupId) return;
30
- const siblingJob = sibling.runId === run.runId ? currentJob : durableSiblingJob({
31
- host,
32
- run: sibling,
33
- state: siblingState
34
- });
35
- jobs.set(siblingJob.id, siblingJob);
36
- group.jobIds.add(siblingJob.id);
37
- const endEvent = durableTerminalEvent(siblingJob, sibling.output);
38
- if (!endEvent || sibling.runId === run.runId) return;
39
- group.completedEvents.push(endEvent);
40
- if (endEvent.status === "aborted" || endEvent.status === "cancelled" || endEvent.status === "error") group.failedNotifiedJobIds.add(siblingJob.id);
41
- }
42
- function durableSiblingJob({ host, run, state }) {
43
- const status = backgroundRunJobStatus(run.status) ?? "pending";
44
- const compactResult = compactSubagentResult(run.output);
45
- return {
46
- abort: () => void 0,
47
- childRunId: run.runId,
48
- cleanup: () => Promise.resolve(),
49
- dedupeKey: run.dedupeKey,
50
- delegateToolCallId: state.delegateToolCallId,
51
- description: state.description,
52
- executionHost: host,
53
- groupId: state.groupId,
54
- id: run.publicTaskId ?? run.runId,
55
- parentRunId: run.parentRunId,
56
- parentSessionKey: state.parentSessionKey,
57
- promise: Promise.resolve(),
58
- result: compactResult,
59
- sessionKey: run.sessionKey,
60
- settled: !isActiveJob(status),
61
- status,
62
- subagent: state.subagent
63
- };
64
- }
65
- function durableTerminalEvent(job, output) {
66
- if (job.status !== "completed" && job.status !== "cancelled") return null;
67
- const result = compactSubagentResult(output);
68
- return {
69
- error: result?.error,
70
- eventCount: result?.eventCount ?? 0,
71
- delegateToolCallId: job.delegateToolCallId,
72
- status: job.status,
73
- subagent: job.subagent,
74
- task_id: job.id,
75
- type: "subagent-job-end"
76
- };
77
- }
78
- function compactSubagentResult(output) {
79
- if (!isRecord(output)) return;
80
- if (typeof output.eventCount !== "number" || output.run_in_background !== false || typeof output.subagent !== "string" || typeof output.text !== "string" || !isCompactResultStatus(output.result)) return;
81
- return {
82
- ...typeof output.error === "string" ? { error: output.error } : {},
83
- eventCount: output.eventCount,
84
- result: output.result,
85
- run_in_background: false,
86
- subagent: output.subagent,
87
- text: output.text
88
- };
89
- }
90
- function isCompactResultStatus(value) {
91
- return value === "aborted" || value === "completed" || value === "error";
92
- }
93
- function isRecord(value) {
94
- return typeof value === "object" && value !== null;
95
- }
96
- //#endregion
97
- export { buildDurableResumeGroups };
98
-
99
- //# sourceMappingURL=subagent-background-resume-group.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subagent-background-resume-group.js","names":[],"sources":["../src/subagent-background-resume-group.ts"],"sourcesContent":["import type { ExecutionHost, RunRecord } from \"./execution/types\";\nimport type { AgentEvent } from \"./session/events\";\nimport type { DurableBackgroundChildRunState } from \"./subagent-background-child-run-state\";\nimport { readDurableBackgroundChildRunState } from \"./subagent-background-child-run-state\";\nimport { backgroundRunJobStatus, isActiveJob } from \"./subagent-job-state\";\nimport type {\n CompactSubagentResult,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nexport async function buildDurableResumeGroups({\n currentJob,\n host,\n jobs,\n run,\n state,\n}: {\n readonly currentJob: SubagentJob;\n readonly host: ExecutionHost;\n readonly jobs: Map<string, SubagentJob>;\n readonly run: RunRecord;\n readonly state: DurableBackgroundChildRunState;\n}): Promise<Map<string, SubagentJobGroup>> {\n const groups = new Map<string, SubagentJobGroup>();\n if (!(state.groupId && run.parentRunId)) {\n return groups;\n }\n\n const group: SubagentJobGroup = {\n completedEvents: [],\n failedNotifiedJobIds: new Set(),\n finalNotified: false,\n id: state.groupId,\n jobIds: new Set(),\n };\n groups.set(group.id, group);\n\n for (const sibling of await host.store.runs.listByParentRunId(\n run.parentRunId\n )) {\n await addSiblingToGroup({\n currentJob,\n group,\n host,\n jobs,\n run,\n sibling,\n state,\n });\n }\n\n return groups;\n}\n\nasync function addSiblingToGroup({\n currentJob,\n group,\n host,\n jobs,\n run,\n sibling,\n state,\n}: {\n readonly currentJob: SubagentJob;\n readonly group: SubagentJobGroup;\n readonly host: ExecutionHost;\n readonly jobs: Map<string, SubagentJob>;\n readonly run: RunRecord;\n readonly sibling: RunRecord;\n readonly state: DurableBackgroundChildRunState;\n}): Promise<void> {\n if (sibling.kind !== \"background-subagent\") {\n return;\n }\n\n const siblingState = readDurableBackgroundChildRunState(\n await host.store.checkpoints.latest(sibling.runId)\n );\n if (!siblingState || siblingState.groupId !== state.groupId) {\n return;\n }\n\n const siblingJob =\n sibling.runId === run.runId\n ? currentJob\n : durableSiblingJob({ host, run: sibling, state: siblingState });\n jobs.set(siblingJob.id, siblingJob);\n group.jobIds.add(siblingJob.id);\n\n const endEvent = durableTerminalEvent(siblingJob, sibling.output);\n if (!endEvent || sibling.runId === run.runId) {\n return;\n }\n group.completedEvents.push(endEvent);\n if (\n endEvent.status === \"aborted\" ||\n endEvent.status === \"cancelled\" ||\n endEvent.status === \"error\"\n ) {\n group.failedNotifiedJobIds.add(siblingJob.id);\n }\n}\n\nfunction durableSiblingJob({\n host,\n run,\n state,\n}: {\n readonly host: ExecutionHost;\n readonly run: RunRecord;\n readonly state: DurableBackgroundChildRunState;\n}): SubagentJob {\n const status = backgroundRunJobStatus(run.status) ?? \"pending\";\n const compactResult = compactSubagentResult(run.output);\n return {\n abort: () => undefined,\n childRunId: run.runId,\n cleanup: () => Promise.resolve(),\n dedupeKey: run.dedupeKey,\n delegateToolCallId: state.delegateToolCallId,\n description: state.description,\n executionHost: host,\n groupId: state.groupId,\n id: run.publicTaskId ?? run.runId,\n parentRunId: run.parentRunId,\n parentSessionKey: state.parentSessionKey,\n promise: Promise.resolve(),\n result: compactResult,\n sessionKey: run.sessionKey,\n settled: !isActiveJob(status),\n status,\n subagent: state.subagent,\n };\n}\n\nfunction durableTerminalEvent(\n job: SubagentJob,\n output: unknown\n): Extract<AgentEvent, { type: \"subagent-job-end\" }> | null {\n if (job.status !== \"completed\" && job.status !== \"cancelled\") {\n return null;\n }\n\n const result = compactSubagentResult(output);\n return {\n error: result?.error,\n eventCount: result?.eventCount ?? 0,\n delegateToolCallId: job.delegateToolCallId,\n status: job.status,\n subagent: job.subagent,\n task_id: job.id,\n type: \"subagent-job-end\",\n };\n}\n\nfunction compactSubagentResult(\n output: unknown\n): CompactSubagentResult | undefined {\n if (!isRecord(output)) {\n return;\n }\n\n if (\n typeof output.eventCount !== \"number\" ||\n output.run_in_background !== false ||\n typeof output.subagent !== \"string\" ||\n typeof output.text !== \"string\" ||\n !isCompactResultStatus(output.result)\n ) {\n return;\n }\n\n return {\n ...(typeof output.error === \"string\" ? { error: output.error } : {}),\n eventCount: output.eventCount,\n result: output.result,\n run_in_background: false,\n subagent: output.subagent,\n text: output.text,\n };\n}\n\nfunction isCompactResultStatus(\n value: unknown\n): value is CompactSubagentResult[\"result\"] {\n return value === \"aborted\" || value === \"completed\" || value === \"error\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n"],"mappings":"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"}