@minpeter/pss-runtime 0.1.0-next.2 → 0.1.0-next.4
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.
- package/README.md +172 -85
- package/dist/agent-host-session-store.js +2 -4
- package/dist/agent-host-session-store.js.map +1 -1
- package/dist/agent-loop.js +9 -8
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +3 -7
- package/dist/agent-namespace.js.map +1 -1
- package/dist/agent-options.d.ts +4 -19
- package/dist/agent-options.js +2 -8
- package/dist/agent-options.js.map +1 -1
- package/dist/agent-resume.js +2 -82
- package/dist/agent-resume.js.map +1 -1
- package/dist/agent-session-entry.d.ts +1 -1
- package/dist/agent.d.ts +4 -4
- package/dist/agent.js +19 -89
- package/dist/agent.js.map +1 -1
- package/dist/cloudflare/cloudflare-agent-context.d.ts +40 -0
- package/dist/cloudflare/cloudflare-agent-context.js +37 -0
- package/dist/cloudflare/cloudflare-agent-context.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-budget.d.ts +18 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js +77 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.d.ts +45 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js +103 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.d.ts +13 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js +81 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-work.js +110 -0
- package/dist/cloudflare/cloudflare-alarm-work.js.map +1 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js +39 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.d.ts +21 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js +11 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js.map +1 -0
- package/dist/cloudflare/cloudflare-event-store.js +33 -0
- package/dist/cloudflare/cloudflare-event-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js +40 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-store.js +35 -0
- package/dist/cloudflare/cloudflare-execution-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-host.d.ts +61 -0
- package/dist/cloudflare/cloudflare-host.js +113 -0
- package/dist/cloudflare/cloudflare-host.js.map +1 -0
- package/dist/cloudflare/cloudflare-notification-store.js +59 -0
- package/dist/cloudflare/cloudflare-notification-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-run-store.js +81 -0
- package/dist/cloudflare/cloudflare-run-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-store-utils.js +43 -0
- package/dist/cloudflare/cloudflare-store-utils.js.map +1 -0
- package/dist/cloudflare/durable-object-storage.d.ts +20 -0
- package/dist/cloudflare/durable-object-storage.js +76 -0
- package/dist/cloudflare/durable-object-storage.js.map +1 -0
- package/dist/cloudflare/index.d.ts +7 -0
- package/dist/cloudflare/index.js +6 -0
- package/dist/execution/capabilities.d.ts +40 -0
- package/dist/execution/host.d.ts +9 -0
- package/dist/execution/host.js +49 -1
- package/dist/execution/host.js.map +1 -1
- package/dist/execution/index.d.ts +3 -1
- package/dist/execution/index.js +2 -1
- package/dist/execution/memory.js +1 -1
- package/dist/execution/memory.js.map +1 -1
- package/dist/execution/types.d.ts +5 -10
- package/dist/index.d.ts +9 -5
- package/dist/index.js +6 -2
- package/dist/llm-tool-execution.js.map +1 -1
- package/dist/llm.d.ts +1 -21
- package/dist/llm.js +12 -14
- package/dist/llm.js.map +1 -1
- package/dist/plugins.d.ts +27 -5
- package/dist/plugins.js +35 -6
- package/dist/plugins.js.map +1 -1
- package/dist/session/delegate-input.d.ts +9 -0
- package/dist/session/delegate-input.js +16 -0
- package/dist/session/delegate-input.js.map +1 -0
- package/dist/session/events.d.ts +43 -25
- package/dist/session/events.js +41 -0
- package/dist/session/events.js.map +1 -0
- package/dist/session/input-meta-types.d.ts +10 -0
- package/dist/session/input-meta.d.ts +13 -0
- package/dist/session/input-meta.js +45 -0
- package/dist/session/input-meta.js.map +1 -0
- package/dist/session/input.d.ts +4 -0
- package/dist/session/mapping.js +4 -2
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/runtime-input-emit.js +41 -0
- package/dist/session/runtime-input-emit.js.map +1 -0
- package/dist/session/runtime-input.js +5 -1
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-events.js +20 -6
- package/dist/session/session-events.js.map +1 -1
- package/dist/session/session-notification.js +3 -2
- package/dist/session/session-notification.js.map +1 -1
- package/dist/session/session-runtime-drain.js +3 -9
- package/dist/session/session-runtime-drain.js.map +1 -1
- package/dist/session/session-turn-processor.js +10 -20
- package/dist/session/session-turn-processor.js.map +1 -1
- package/dist/session/session.js +15 -8
- package/dist/session/session.js.map +1 -1
- package/package.json +6 -1
- package/dist/agent-child-runs.js +0 -16
- package/dist/agent-child-runs.js.map +0 -1
- package/dist/agent-host-capabilities.js +0 -9
- package/dist/agent-host-capabilities.js.map +0 -1
- package/dist/agent-validation.js +0 -35
- package/dist/agent-validation.js.map +0 -1
- package/dist/child-session-cleanups.js +0 -61
- package/dist/child-session-cleanups.js.map +0 -1
- package/dist/execution/run.js +0 -55
- package/dist/execution/run.js.map +0 -1
- package/dist/subagent-background-child-run-state.js +0 -51
- package/dist/subagent-background-child-run-state.js.map +0 -1
- package/dist/subagent-background-child-run.js +0 -103
- package/dist/subagent-background-child-run.js.map +0 -1
- package/dist/subagent-background-in-process.js +0 -98
- package/dist/subagent-background-in-process.js.map +0 -1
- package/dist/subagent-background-notification-inbox.js +0 -106
- package/dist/subagent-background-notification-inbox.js.map +0 -1
- package/dist/subagent-background-notify.js +0 -136
- package/dist/subagent-background-notify.js.map +0 -1
- package/dist/subagent-background-resume-group.js +0 -99
- package/dist/subagent-background-resume-group.js.map +0 -1
- package/dist/subagent-background-runner.js +0 -115
- package/dist/subagent-background-runner.js.map +0 -1
- package/dist/subagent-background-schedule.js +0 -43
- package/dist/subagent-background-schedule.js.map +0 -1
- package/dist/subagent-child-run.js +0 -68
- package/dist/subagent-child-run.js.map +0 -1
- package/dist/subagent-job-cancel.js +0 -84
- package/dist/subagent-job-cancel.js.map +0 -1
- package/dist/subagent-job-observer.js +0 -19
- package/dist/subagent-job-observer.js.map +0 -1
- package/dist/subagent-job-output.js +0 -87
- package/dist/subagent-job-output.js.map +0 -1
- package/dist/subagent-job-state.js +0 -66
- package/dist/subagent-job-state.js.map +0 -1
- package/dist/subagent-jobs.js +0 -96
- package/dist/subagent-jobs.js.map +0 -1
- package/dist/subagent-prompt-schema.js +0 -114
- package/dist/subagent-prompt-schema.js.map +0 -1
- package/dist/subagent-run.js +0 -111
- package/dist/subagent-run.js.map +0 -1
- package/dist/subagents.js +0 -125
- package/dist/subagents.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-job-observer.js","names":[],"sources":["../src/subagent-job-observer.ts"],"sourcesContent":["import type { AgentEvent } from \"./session/events\";\nimport type { RuntimeInputSink, SubagentJob } from \"./subagent-types\";\n\nexport function emitBackgroundJobUpdate(\n parentSession: RuntimeInputSink,\n job: SubagentJob,\n event: AgentEvent\n): Promise<void> {\n if (!isParentVisibleJobUpdate(event)) {\n return Promise.resolve();\n }\n\n return parentSession.emitObserverEvent({\n eventType: event.type,\n delegateToolCallId: job.delegateToolCallId,\n status: job.status,\n subagent: job.subagent,\n task_id: job.id,\n type: \"subagent-job-update\" as const,\n });\n}\n\nfunction isParentVisibleJobUpdate(event: AgentEvent): boolean {\n return (\n event.type === \"assistant-text\" ||\n event.type === \"tool-call\" ||\n event.type === \"tool-result\" ||\n event.type === \"turn-abort\" ||\n event.type === \"turn-error\"\n );\n}\n"],"mappings":";AAGA,SAAgB,wBACd,eACA,KACA,OACe;CACf,IAAI,CAAC,yBAAyB,KAAK,GACjC,OAAO,QAAQ,QAAQ;CAGzB,OAAO,cAAc,kBAAkB;EACrC,WAAW,MAAM;EACjB,oBAAoB,IAAI;EACxB,QAAQ,IAAI;EACZ,UAAU,IAAI;EACd,SAAS,IAAI;EACb,MAAM;CACR,CAAC;AACH;AAEA,SAAS,yBAAyB,OAA4B;CAC5D,OACE,MAAM,SAAS,oBACf,MAAM,SAAS,eACf,MAAM,SAAS,iBACf,MAAM,SAAS,gBACf,MAAM,SAAS;AAEnB"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { assertBackgroundTaskId, cleanupJob, isActiveJob } from "./subagent-job-state.js";
|
|
2
|
-
import { jsonSchema, tool } from "ai";
|
|
3
|
-
//#region src/subagent-job-output.ts
|
|
4
|
-
function createBackgroundOutputTool(jobs, executionHost, scope) {
|
|
5
|
-
return tool({
|
|
6
|
-
description: "Retrieve compact output for a background subagent job.",
|
|
7
|
-
execute: async (input, { abortSignal }) => {
|
|
8
|
-
assertBackgroundTaskId(input.task_id, "background_output");
|
|
9
|
-
const job = jobs.get(input.task_id);
|
|
10
|
-
if (!job) {
|
|
11
|
-
const durableOutput = await durableBackgroundOutput(input.task_id, executionHost, scope);
|
|
12
|
-
if (durableOutput) return durableOutput;
|
|
13
|
-
throw new Error(`Unknown background subagent task ${input.task_id}.`);
|
|
14
|
-
}
|
|
15
|
-
if (input.block === true && isActiveJob(job.status)) await waitForJob(job, input.timeout, abortSignal);
|
|
16
|
-
const output = await durableBackgroundOutput(input.task_id, job.executionHost ?? executionHost, scope, job.subagent) ?? {
|
|
17
|
-
result: job.result,
|
|
18
|
-
status: job.status,
|
|
19
|
-
subagent: job.subagent,
|
|
20
|
-
task_id: job.id
|
|
21
|
-
};
|
|
22
|
-
if (!(isActiveJob(job.status) || !job.settled)) {
|
|
23
|
-
if (await cleanupJob(job).then(() => true, () => false)) jobs.delete(job.id);
|
|
24
|
-
}
|
|
25
|
-
return output;
|
|
26
|
-
},
|
|
27
|
-
inputSchema: jsonSchema({
|
|
28
|
-
additionalProperties: false,
|
|
29
|
-
properties: {
|
|
30
|
-
block: { type: "boolean" },
|
|
31
|
-
task_id: { type: "string" },
|
|
32
|
-
timeout: {
|
|
33
|
-
minimum: 0,
|
|
34
|
-
type: "number"
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
required: ["task_id"],
|
|
38
|
-
type: "object"
|
|
39
|
-
})
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
async function durableBackgroundOutput(taskId, executionHost, scope, fallbackSubagent = "subagent") {
|
|
43
|
-
const record = await executionHost?.store.runs.get(`background:${taskId}`);
|
|
44
|
-
if (record?.kind !== "background-subagent") return null;
|
|
45
|
-
if (scope && !record.sessionKey.startsWith(scope.childSessionKeyPrefix)) return null;
|
|
46
|
-
return {
|
|
47
|
-
result: record.output,
|
|
48
|
-
status: backgroundStatus(record.status),
|
|
49
|
-
subagent: subagentName(record.output, fallbackSubagent),
|
|
50
|
-
task_id: taskId
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function backgroundStatus(status) {
|
|
54
|
-
if (status === "completed" || status === "cancelled" || status === "error") return status;
|
|
55
|
-
if (status === "running" || status === "leased") return "running";
|
|
56
|
-
return "pending";
|
|
57
|
-
}
|
|
58
|
-
function subagentName(output, fallback) {
|
|
59
|
-
if (typeof output === "object" && output !== null && "subagent" in output && typeof output.subagent === "string") return output.subagent;
|
|
60
|
-
return fallback;
|
|
61
|
-
}
|
|
62
|
-
async function waitForJob(job, timeout, abortSignal) {
|
|
63
|
-
if (abortSignal?.aborted) return;
|
|
64
|
-
const timeoutMs = Math.min(timeout ?? 6e4, 6e5);
|
|
65
|
-
let timeoutId;
|
|
66
|
-
let abortListener;
|
|
67
|
-
const abortPromise = abortSignal ? new Promise((resolve) => {
|
|
68
|
-
abortListener = resolve;
|
|
69
|
-
abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
70
|
-
}) : void 0;
|
|
71
|
-
try {
|
|
72
|
-
await Promise.race([
|
|
73
|
-
job.promise,
|
|
74
|
-
...abortPromise ? [abortPromise] : [],
|
|
75
|
-
new Promise((resolve) => {
|
|
76
|
-
timeoutId = setTimeout(resolve, timeoutMs);
|
|
77
|
-
})
|
|
78
|
-
]);
|
|
79
|
-
} finally {
|
|
80
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
81
|
-
if (abortListener) abortSignal?.removeEventListener("abort", abortListener);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
//#endregion
|
|
85
|
-
export { createBackgroundOutputTool };
|
|
86
|
-
|
|
87
|
-
//# sourceMappingURL=subagent-job-output.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-job-output.js","names":[],"sources":["../src/subagent-job-output.ts"],"sourcesContent":["import { jsonSchema, tool } from \"ai\";\nimport type { ExecutionHost, RunStatus } from \"./execution/types\";\nimport {\n assertBackgroundTaskId,\n cleanupJob,\n isActiveJob,\n} from \"./subagent-job-state\";\nimport type { BackgroundOutputInput, SubagentJob } from \"./subagent-types\";\n\ninterface BackgroundToolScope {\n readonly childSessionKeyPrefix: string;\n}\n\nexport function createBackgroundOutputTool(\n jobs: Map<string, SubagentJob>,\n executionHost?: ExecutionHost,\n scope?: BackgroundToolScope\n) {\n return tool<BackgroundOutputInput, unknown, Record<string, unknown>>({\n description: \"Retrieve compact output for a background subagent job.\",\n execute: async (input: BackgroundOutputInput, { abortSignal }) => {\n assertBackgroundTaskId(input.task_id, \"background_output\");\n const job = jobs.get(input.task_id);\n if (!job) {\n const durableOutput = await durableBackgroundOutput(\n input.task_id,\n executionHost,\n scope\n );\n if (durableOutput) {\n return durableOutput;\n }\n\n throw new Error(`Unknown background subagent task ${input.task_id}.`);\n }\n\n if (input.block === true && isActiveJob(job.status)) {\n await waitForJob(job, input.timeout, abortSignal);\n }\n\n const durableOutput = await durableBackgroundOutput(\n input.task_id,\n job.executionHost ?? executionHost,\n scope,\n job.subagent\n );\n const output = durableOutput ?? {\n result: job.result,\n status: job.status,\n subagent: job.subagent,\n task_id: job.id,\n };\n if (!(isActiveJob(job.status) || !job.settled)) {\n const cleaned = await cleanupJob(job).then(\n () => true,\n () => false\n );\n if (cleaned) {\n jobs.delete(job.id);\n }\n }\n\n return output;\n },\n inputSchema: jsonSchema<BackgroundOutputInput>({\n additionalProperties: false,\n properties: {\n block: { type: \"boolean\" },\n task_id: { type: \"string\" },\n timeout: { minimum: 0, type: \"number\" },\n },\n required: [\"task_id\"],\n type: \"object\",\n }),\n });\n}\n\nasync function durableBackgroundOutput(\n taskId: string,\n executionHost: ExecutionHost | undefined,\n scope: BackgroundToolScope | undefined,\n fallbackSubagent = \"subagent\"\n): Promise<Record<string, unknown> | null> {\n const record = await executionHost?.store.runs.get(`background:${taskId}`);\n if (record?.kind !== \"background-subagent\") {\n return null;\n }\n if (scope && !record.sessionKey.startsWith(scope.childSessionKeyPrefix)) {\n return null;\n }\n\n return {\n result: record.output,\n status: backgroundStatus(record.status),\n subagent: subagentName(record.output, fallbackSubagent),\n task_id: taskId,\n };\n}\n\nfunction backgroundStatus(status: RunStatus): string {\n if (status === \"completed\" || status === \"cancelled\" || status === \"error\") {\n return status;\n }\n\n if (status === \"running\" || status === \"leased\") {\n return \"running\";\n }\n\n return \"pending\";\n}\n\nfunction subagentName(output: unknown, fallback: string): string {\n if (\n typeof output === \"object\" &&\n output !== null &&\n \"subagent\" in output &&\n typeof output.subagent === \"string\"\n ) {\n return output.subagent;\n }\n\n return fallback;\n}\n\nasync function waitForJob(\n job: SubagentJob,\n timeout: number | undefined,\n abortSignal: AbortSignal | undefined\n) {\n if (abortSignal?.aborted) {\n return;\n }\n\n const timeoutMs = Math.min(timeout ?? 60_000, 600_000);\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let abortListener: (() => void) | undefined;\n const abortPromise = abortSignal\n ? new Promise<void>((resolve) => {\n abortListener = resolve;\n abortSignal.addEventListener(\"abort\", abortListener, { once: true });\n })\n : undefined;\n try {\n await Promise.race([\n job.promise,\n ...(abortPromise ? [abortPromise] : []),\n new Promise<void>((resolve) => {\n timeoutId = setTimeout(resolve, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n if (abortListener) {\n abortSignal?.removeEventListener(\"abort\", abortListener);\n }\n }\n}\n"],"mappings":";;;AAaA,SAAgB,2BACd,MACA,eACA,OACA;CACA,OAAO,KAA8D;EACnE,aAAa;EACb,SAAS,OAAO,OAA8B,EAAE,kBAAkB;GAChE,uBAAuB,MAAM,SAAS,mBAAmB;GACzD,MAAM,MAAM,KAAK,IAAI,MAAM,OAAO;GAClC,IAAI,CAAC,KAAK;IACR,MAAM,gBAAgB,MAAM,wBAC1B,MAAM,SACN,eACA,KACF;IACA,IAAI,eACF,OAAO;IAGT,MAAM,IAAI,MAAM,oCAAoC,MAAM,QAAQ,EAAE;GACtE;GAEA,IAAI,MAAM,UAAU,QAAQ,YAAY,IAAI,MAAM,GAChD,MAAM,WAAW,KAAK,MAAM,SAAS,WAAW;GASlD,MAAM,SAAS,MANa,wBAC1B,MAAM,SACN,IAAI,iBAAiB,eACrB,OACA,IAAI,QACN,KACgC;IAC9B,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACZ,UAAU,IAAI;IACd,SAAS,IAAI;GACf;GACA,IAAI,EAAE,YAAY,IAAI,MAAM,KAAK,CAAC,IAAI;QAKhC,MAJkB,WAAW,GAAG,EAAE,WAC9B,YACA,KACR,GAEE,KAAK,OAAO,IAAI,EAAE;GAAA;GAItB,OAAO;EACT;EACA,aAAa,WAAkC;GAC7C,sBAAsB;GACtB,YAAY;IACV,OAAO,EAAE,MAAM,UAAU;IACzB,SAAS,EAAE,MAAM,SAAS;IAC1B,SAAS;KAAE,SAAS;KAAG,MAAM;IAAS;GACxC;GACA,UAAU,CAAC,SAAS;GACpB,MAAM;EACR,CAAC;CACH,CAAC;AACH;AAEA,eAAe,wBACb,QACA,eACA,OACA,mBAAmB,YACsB;CACzC,MAAM,SAAS,MAAM,eAAe,MAAM,KAAK,IAAI,cAAc,QAAQ;CACzE,IAAI,QAAQ,SAAS,uBACnB,OAAO;CAET,IAAI,SAAS,CAAC,OAAO,WAAW,WAAW,MAAM,qBAAqB,GACpE,OAAO;CAGT,OAAO;EACL,QAAQ,OAAO;EACf,QAAQ,iBAAiB,OAAO,MAAM;EACtC,UAAU,aAAa,OAAO,QAAQ,gBAAgB;EACtD,SAAS;CACX;AACF;AAEA,SAAS,iBAAiB,QAA2B;CACnD,IAAI,WAAW,eAAe,WAAW,eAAe,WAAW,SACjE,OAAO;CAGT,IAAI,WAAW,aAAa,WAAW,UACrC,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,aAAa,QAAiB,UAA0B;CAC/D,IACE,OAAO,WAAW,YAClB,WAAW,QACX,cAAc,UACd,OAAO,OAAO,aAAa,UAE3B,OAAO,OAAO;CAGhB,OAAO;AACT;AAEA,eAAe,WACb,KACA,SACA,aACA;CACA,IAAI,aAAa,SACf;CAGF,MAAM,YAAY,KAAK,IAAI,WAAW,KAAQ,GAAO;CACrD,IAAI;CACJ,IAAI;CACJ,MAAM,eAAe,cACjB,IAAI,SAAe,YAAY;EAC7B,gBAAgB;EAChB,YAAY,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;CACrE,CAAC,IACD,KAAA;CACJ,IAAI;EACF,MAAM,QAAQ,KAAK;GACjB,IAAI;GACJ,GAAI,eAAe,CAAC,YAAY,IAAI,CAAC;GACrC,IAAI,SAAe,YAAY;IAC7B,YAAY,WAAW,SAAS,SAAS;GAC3C,CAAC;EACH,CAAC;CACH,UAAU;EACR,IAAI,WACF,aAAa,SAAS;EAExB,IAAI,eACF,aAAa,oBAAoB,SAAS,aAAa;CAE3D;AACF"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { updateBackgroundRunStatus } from "./subagent-background-child-run.js";
|
|
2
|
-
//#region src/subagent-job-state.ts
|
|
3
|
-
function assertBackgroundTaskId(value, toolName) {
|
|
4
|
-
if (value.startsWith("bg_")) return;
|
|
5
|
-
throw new Error(`${toolName} expects a background task_id starting with bg_, not a session key: ${value}`);
|
|
6
|
-
}
|
|
7
|
-
function isActiveJob(status) {
|
|
8
|
-
return status === "pending" || status === "running";
|
|
9
|
-
}
|
|
10
|
-
function hasBackgroundJobCapacity({ jobs, maxActiveJobs, maxRetainedJobs }) {
|
|
11
|
-
if (jobs.size >= maxRetainedJobs) return false;
|
|
12
|
-
let activeJobs = 0;
|
|
13
|
-
for (const job of jobs.values()) if (isActiveJob(job.status) || !job.settled) activeJobs += 1;
|
|
14
|
-
return activeJobs < maxActiveJobs;
|
|
15
|
-
}
|
|
16
|
-
function cancelJob(job) {
|
|
17
|
-
job.status = "cancelled";
|
|
18
|
-
job.abort();
|
|
19
|
-
const statusUpdate = updateBackgroundRunStatus(job, "cancelled");
|
|
20
|
-
job.promise = Promise.allSettled([job.promise, statusUpdate]).then(() => void 0);
|
|
21
|
-
}
|
|
22
|
-
async function cleanupJob(job) {
|
|
23
|
-
await job.cleanup();
|
|
24
|
-
job.unregisterCleanup?.();
|
|
25
|
-
}
|
|
26
|
-
function backgroundLaunchOutput(job) {
|
|
27
|
-
return {
|
|
28
|
-
message: [
|
|
29
|
-
`Background subagent job ${job.id} started.`,
|
|
30
|
-
`Please wait for <system-reminder> before checking task ${job.id}.`,
|
|
31
|
-
`Do NOT call background_output({ task_id: "${job.id}" }) now; wait for <system-reminder> first.`
|
|
32
|
-
].join(" "),
|
|
33
|
-
run_in_background: true,
|
|
34
|
-
status: job.status,
|
|
35
|
-
subagent: job.subagent,
|
|
36
|
-
task_id: job.id
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function backgroundCancelledLaunchOutput({ id, subagent }) {
|
|
40
|
-
return {
|
|
41
|
-
message: `Background subagent job ${id} was cancelled before it started.`,
|
|
42
|
-
run_in_background: true,
|
|
43
|
-
status: "cancelled",
|
|
44
|
-
subagent,
|
|
45
|
-
task_id: id
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function backgroundRunJobStatus(status) {
|
|
49
|
-
if (status === "cancelled" || status === "completed" || status === "error") return status;
|
|
50
|
-
if (status === "leased" || status === "running") return "running";
|
|
51
|
-
if (status === "needs-recovery" || status === "queued" || status === "suspended") return "pending";
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
function backgroundReplayOutput({ id, status, subagent }) {
|
|
55
|
-
return {
|
|
56
|
-
message: `Background subagent job ${id} was already ${status}. Reuse the existing task_id instead of launching it again.`,
|
|
57
|
-
run_in_background: true,
|
|
58
|
-
status,
|
|
59
|
-
subagent,
|
|
60
|
-
task_id: id
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
//#endregion
|
|
64
|
-
export { assertBackgroundTaskId, backgroundCancelledLaunchOutput, backgroundLaunchOutput, backgroundReplayOutput, backgroundRunJobStatus, cancelJob, cleanupJob, hasBackgroundJobCapacity, isActiveJob };
|
|
65
|
-
|
|
66
|
-
//# sourceMappingURL=subagent-job-state.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-job-state.js","names":[],"sources":["../src/subagent-job-state.ts"],"sourcesContent":["import type { RunStatus } from \"./execution/types\";\nimport { updateBackgroundRunStatus } from \"./subagent-background-child-run\";\nimport type { SubagentJob } from \"./subagent-types\";\n\nexport function assertBackgroundTaskId(value: string, toolName: string): void {\n if (value.startsWith(\"bg_\")) {\n return;\n }\n\n throw new Error(\n `${toolName} expects a background task_id starting with bg_, not a session key: ${value}`\n );\n}\n\nexport function isActiveJob(status: SubagentJob[\"status\"]): boolean {\n return status === \"pending\" || status === \"running\";\n}\n\nexport function hasBackgroundJobCapacity({\n jobs,\n maxActiveJobs,\n maxRetainedJobs,\n}: {\n readonly jobs: Map<string, SubagentJob>;\n readonly maxActiveJobs: number;\n readonly maxRetainedJobs: number;\n}): boolean {\n if (jobs.size >= maxRetainedJobs) {\n return false;\n }\n\n let activeJobs = 0;\n for (const job of jobs.values()) {\n if (isActiveJob(job.status) || !job.settled) {\n activeJobs += 1;\n }\n }\n\n return activeJobs < maxActiveJobs;\n}\n\nexport function cancelJob(job: SubagentJob): void {\n job.status = \"cancelled\";\n job.abort();\n const statusUpdate = updateBackgroundRunStatus(job, \"cancelled\");\n job.promise = Promise.allSettled([job.promise, statusUpdate]).then(\n () => undefined\n );\n}\n\nexport async function cleanupJob(job: SubagentJob): Promise<void> {\n await job.cleanup();\n job.unregisterCleanup?.();\n}\n\nexport function backgroundLaunchOutput(job: SubagentJob) {\n return {\n message: [\n `Background subagent job ${job.id} started.`,\n `Please wait for <system-reminder> before checking task ${job.id}.`,\n `Do NOT call background_output({ task_id: \"${job.id}\" }) now; wait for <system-reminder> first.`,\n ].join(\" \"),\n run_in_background: true,\n status: job.status,\n subagent: job.subagent,\n task_id: job.id,\n };\n}\n\nexport function backgroundCancelledLaunchOutput({\n id,\n subagent,\n}: {\n readonly id: string;\n readonly subagent?: string;\n}) {\n return {\n message: `Background subagent job ${id} was cancelled before it started.`,\n run_in_background: true,\n status: \"cancelled\",\n subagent,\n task_id: id,\n };\n}\n\nexport function backgroundRunJobStatus(\n status: RunStatus | undefined\n): Exclude<SubagentJob[\"status\"], \"aborted\"> | null {\n if (status === \"cancelled\" || status === \"completed\" || status === \"error\") {\n return status;\n }\n\n if (status === \"leased\" || status === \"running\") {\n return \"running\";\n }\n\n if (\n status === \"needs-recovery\" ||\n status === \"queued\" ||\n status === \"suspended\"\n ) {\n return \"pending\";\n }\n\n return null;\n}\n\nexport function backgroundReplayOutput({\n id,\n status,\n subagent,\n}: {\n readonly id: string;\n readonly status: Exclude<SubagentJob[\"status\"], \"aborted\">;\n readonly subagent: string;\n}) {\n return {\n message: `Background subagent job ${id} was already ${status}. Reuse the existing task_id instead of launching it again.`,\n run_in_background: true,\n status,\n subagent,\n task_id: id,\n };\n}\n"],"mappings":";;AAIA,SAAgB,uBAAuB,OAAe,UAAwB;CAC5E,IAAI,MAAM,WAAW,KAAK,GACxB;CAGF,MAAM,IAAI,MACR,GAAG,SAAS,sEAAsE,OACpF;AACF;AAEA,SAAgB,YAAY,QAAwC;CAClE,OAAO,WAAW,aAAa,WAAW;AAC5C;AAEA,SAAgB,yBAAyB,EACvC,MACA,eACA,mBAKU;CACV,IAAI,KAAK,QAAQ,iBACf,OAAO;CAGT,IAAI,aAAa;CACjB,KAAK,MAAM,OAAO,KAAK,OAAO,GAC5B,IAAI,YAAY,IAAI,MAAM,KAAK,CAAC,IAAI,SAClC,cAAc;CAIlB,OAAO,aAAa;AACtB;AAEA,SAAgB,UAAU,KAAwB;CAChD,IAAI,SAAS;CACb,IAAI,MAAM;CACV,MAAM,eAAe,0BAA0B,KAAK,WAAW;CAC/D,IAAI,UAAU,QAAQ,WAAW,CAAC,IAAI,SAAS,YAAY,CAAC,EAAE,WACtD,KAAA,CACR;AACF;AAEA,eAAsB,WAAW,KAAiC;CAChE,MAAM,IAAI,QAAQ;CAClB,IAAI,oBAAoB;AAC1B;AAEA,SAAgB,uBAAuB,KAAkB;CACvD,OAAO;EACL,SAAS;GACP,2BAA2B,IAAI,GAAG;GAClC,0DAA0D,IAAI,GAAG;GACjE,6CAA6C,IAAI,GAAG;EACtD,EAAE,KAAK,GAAG;EACV,mBAAmB;EACnB,QAAQ,IAAI;EACZ,UAAU,IAAI;EACd,SAAS,IAAI;CACf;AACF;AAEA,SAAgB,gCAAgC,EAC9C,IACA,YAIC;CACD,OAAO;EACL,SAAS,2BAA2B,GAAG;EACvC,mBAAmB;EACnB,QAAQ;EACR;EACA,SAAS;CACX;AACF;AAEA,SAAgB,uBACd,QACkD;CAClD,IAAI,WAAW,eAAe,WAAW,eAAe,WAAW,SACjE,OAAO;CAGT,IAAI,WAAW,YAAY,WAAW,WACpC,OAAO;CAGT,IACE,WAAW,oBACX,WAAW,YACX,WAAW,aAEX,OAAO;CAGT,OAAO;AACT;AAEA,SAAgB,uBAAuB,EACrC,IACA,QACA,YAKC;CACD,OAAO;EACL,SAAS,2BAA2B,GAAG,eAAe,OAAO;EAC7D,mBAAmB;EACnB;EACA;EACA,SAAS;CACX;AACF"}
|
package/dist/subagent-jobs.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { createBackgroundTaskId, createDurableBackgroundTaskId, getBackgroundChildRun, getOrCreateBackgroundChildRun } from "./subagent-background-child-run.js";
|
|
2
|
-
import { backgroundCancelledLaunchOutput, backgroundLaunchOutput, backgroundReplayOutput, backgroundRunJobStatus, hasBackgroundJobCapacity } from "./subagent-job-state.js";
|
|
3
|
-
import { startInProcessBackgroundJob } from "./subagent-background-in-process.js";
|
|
4
|
-
import { scheduleDurableBackgroundJob } from "./subagent-background-schedule.js";
|
|
5
|
-
//#region src/subagent-jobs.ts
|
|
6
|
-
const maxBackgroundJobs = 64;
|
|
7
|
-
const maxRetainedBackgroundJobs = maxBackgroundJobs * 4;
|
|
8
|
-
async function startBackgroundJob({ abortSignal, description, executionHost, jobs, groupId, groups = /* @__PURE__ */ new Map(), delegateToolCallId, parentSession, parentRunId, parentSessionKey, ownerNamespace, prompt, registerCleanup, sessionKey, subagent }) {
|
|
9
|
-
const existingChildRun = await getBackgroundChildRun({
|
|
10
|
-
delegateToolCallId,
|
|
11
|
-
executionHost,
|
|
12
|
-
parentRunId,
|
|
13
|
-
parentSessionKey,
|
|
14
|
-
prompt,
|
|
15
|
-
sessionKey
|
|
16
|
-
});
|
|
17
|
-
const id = existingChildRun?.publicTaskId ?? (executionHost ? await createDurableBackgroundTaskId({
|
|
18
|
-
delegateToolCallId,
|
|
19
|
-
prompt,
|
|
20
|
-
sessionKey
|
|
21
|
-
}) : createBackgroundTaskId());
|
|
22
|
-
const existingJob = jobs.get(id);
|
|
23
|
-
if (existingJob) return backgroundLaunchOutput(existingJob);
|
|
24
|
-
const replayedStatus = backgroundRunJobStatus(existingChildRun?.status);
|
|
25
|
-
if (existingChildRun?.publicTaskId && replayedStatus) return backgroundReplayOutput({
|
|
26
|
-
id: existingChildRun.publicTaskId,
|
|
27
|
-
status: replayedStatus,
|
|
28
|
-
subagent: subagent.name ?? "subagent"
|
|
29
|
-
});
|
|
30
|
-
if (!hasBackgroundJobCapacity({
|
|
31
|
-
jobs,
|
|
32
|
-
maxActiveJobs: maxBackgroundJobs,
|
|
33
|
-
maxRetainedJobs: maxRetainedBackgroundJobs
|
|
34
|
-
})) return {
|
|
35
|
-
message: "Background subagent job was not started because the background job limit is full.",
|
|
36
|
-
run_in_background: true,
|
|
37
|
-
status: "cancelled",
|
|
38
|
-
subagent: subagent.name,
|
|
39
|
-
task_id: id
|
|
40
|
-
};
|
|
41
|
-
if (abortSignal.aborted) return backgroundCancelledLaunchOutput({
|
|
42
|
-
id,
|
|
43
|
-
subagent: subagent.name
|
|
44
|
-
});
|
|
45
|
-
const childRun = executionHost ? existingChildRun ?? await getOrCreateBackgroundChildRun({
|
|
46
|
-
delegateToolCallId,
|
|
47
|
-
description,
|
|
48
|
-
executionHost,
|
|
49
|
-
groupId,
|
|
50
|
-
ownerNamespace,
|
|
51
|
-
parentRunId,
|
|
52
|
-
parentSessionKey,
|
|
53
|
-
prompt,
|
|
54
|
-
publicTaskId: id,
|
|
55
|
-
sessionKey,
|
|
56
|
-
subagent: subagent.name ?? "subagent"
|
|
57
|
-
}) : void 0;
|
|
58
|
-
if (executionHost?.capabilities.backgroundSubagents === "durable" && childRun) return backgroundLaunchOutput(await scheduleDurableBackgroundJob({
|
|
59
|
-
childRun,
|
|
60
|
-
delegateToolCallId,
|
|
61
|
-
description,
|
|
62
|
-
executionHost,
|
|
63
|
-
groupId,
|
|
64
|
-
groups,
|
|
65
|
-
id,
|
|
66
|
-
jobs,
|
|
67
|
-
parentRunId,
|
|
68
|
-
parentSession,
|
|
69
|
-
parentSessionKey,
|
|
70
|
-
ownerNamespace,
|
|
71
|
-
subagent: subagent.name ?? "subagent"
|
|
72
|
-
}));
|
|
73
|
-
return await startInProcessBackgroundJob({
|
|
74
|
-
abortSignal,
|
|
75
|
-
childRun,
|
|
76
|
-
delegateToolCallId,
|
|
77
|
-
description,
|
|
78
|
-
executionHost,
|
|
79
|
-
groupId,
|
|
80
|
-
groups,
|
|
81
|
-
id,
|
|
82
|
-
jobs,
|
|
83
|
-
parentRunId,
|
|
84
|
-
parentSession,
|
|
85
|
-
parentSessionKey,
|
|
86
|
-
ownerNamespace,
|
|
87
|
-
prompt,
|
|
88
|
-
registerCleanup,
|
|
89
|
-
sessionKey,
|
|
90
|
-
subagent
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { startBackgroundJob };
|
|
95
|
-
|
|
96
|
-
//# sourceMappingURL=subagent-jobs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-jobs.js","names":[],"sources":["../src/subagent-jobs.ts"],"sourcesContent":["import type { ExecutionHost } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\nimport {\n createBackgroundTaskId,\n createDurableBackgroundTaskId,\n getBackgroundChildRun,\n getOrCreateBackgroundChildRun,\n} from \"./subagent-background-child-run\";\nimport { startInProcessBackgroundJob } from \"./subagent-background-in-process\";\nimport { scheduleDurableBackgroundJob } from \"./subagent-background-schedule\";\nimport {\n backgroundCancelledLaunchOutput,\n backgroundLaunchOutput,\n backgroundReplayOutput,\n backgroundRunJobStatus,\n hasBackgroundJobCapacity,\n} from \"./subagent-job-state\";\nimport type {\n RuntimeInputSink,\n Subagent,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nconst maxBackgroundJobs = 64;\nconst maxRetainedBackgroundJobs = maxBackgroundJobs * 4;\n\nexport async function startBackgroundJob({\n abortSignal,\n description,\n executionHost,\n jobs,\n groupId,\n groups = new Map<string, SubagentJobGroup>(),\n delegateToolCallId,\n parentSession,\n parentRunId,\n parentSessionKey,\n ownerNamespace,\n prompt,\n registerCleanup,\n sessionKey,\n subagent,\n}: {\n readonly abortSignal: AbortSignal;\n readonly description?: string;\n readonly executionHost?: ExecutionHost;\n readonly jobs: Map<string, SubagentJob>;\n readonly groupId?: string;\n readonly groups?: Map<string, SubagentJobGroup>;\n readonly delegateToolCallId?: string;\n readonly parentSession: RuntimeInputSink;\n readonly parentRunId?: string;\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 existingChildRun = await getBackgroundChildRun({\n delegateToolCallId,\n executionHost,\n parentRunId,\n parentSessionKey,\n prompt,\n sessionKey,\n });\n const id =\n existingChildRun?.publicTaskId ??\n (executionHost\n ? await createDurableBackgroundTaskId({\n delegateToolCallId,\n prompt,\n sessionKey,\n })\n : createBackgroundTaskId());\n const existingJob = jobs.get(id);\n if (existingJob) {\n return backgroundLaunchOutput(existingJob);\n }\n const replayedStatus = backgroundRunJobStatus(existingChildRun?.status);\n if (existingChildRun?.publicTaskId && replayedStatus) {\n return backgroundReplayOutput({\n id: existingChildRun.publicTaskId,\n status: replayedStatus,\n subagent: subagent.name ?? \"subagent\",\n });\n }\n\n if (\n !hasBackgroundJobCapacity({\n jobs,\n maxActiveJobs: maxBackgroundJobs,\n maxRetainedJobs: maxRetainedBackgroundJobs,\n })\n ) {\n return {\n message:\n \"Background subagent job was not started because the background job limit is full.\",\n run_in_background: true,\n status: \"cancelled\",\n subagent: subagent.name,\n task_id: id,\n };\n }\n\n if (abortSignal.aborted) {\n return backgroundCancelledLaunchOutput({ id, subagent: subagent.name });\n }\n\n const childRun = executionHost\n ? (existingChildRun ??\n (await getOrCreateBackgroundChildRun({\n delegateToolCallId,\n description,\n executionHost,\n groupId,\n ownerNamespace,\n parentRunId,\n parentSessionKey,\n prompt,\n publicTaskId: id,\n sessionKey,\n subagent: subagent.name ?? \"subagent\",\n })))\n : undefined;\n if (\n executionHost?.capabilities.backgroundSubagents === \"durable\" &&\n childRun\n ) {\n const job = await scheduleDurableBackgroundJob({\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 subagent: subagent.name ?? \"subagent\",\n });\n return backgroundLaunchOutput(job);\n }\n return await 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}\n"],"mappings":";;;;;AAwBA,MAAM,oBAAoB;AAC1B,MAAM,4BAA4B,oBAAoB;AAEtD,eAAsB,mBAAmB,EACvC,aACA,aACA,eACA,MACA,SACA,yBAAS,IAAI,IAA8B,GAC3C,oBACA,eACA,aACA,kBACA,gBACA,QACA,iBACA,YACA,YAiBC;CACD,MAAM,mBAAmB,MAAM,sBAAsB;EACnD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,KACJ,kBAAkB,iBACjB,gBACG,MAAM,8BAA8B;EAClC;EACA;EACA;CACF,CAAC,IACD,uBAAuB;CAC7B,MAAM,cAAc,KAAK,IAAI,EAAE;CAC/B,IAAI,aACF,OAAO,uBAAuB,WAAW;CAE3C,MAAM,iBAAiB,uBAAuB,kBAAkB,MAAM;CACtE,IAAI,kBAAkB,gBAAgB,gBACpC,OAAO,uBAAuB;EAC5B,IAAI,iBAAiB;EACrB,QAAQ;EACR,UAAU,SAAS,QAAQ;CAC7B,CAAC;CAGH,IACE,CAAC,yBAAyB;EACxB;EACA,eAAe;EACf,iBAAiB;CACnB,CAAC,GAED,OAAO;EACL,SACE;EACF,mBAAmB;EACnB,QAAQ;EACR,UAAU,SAAS;EACnB,SAAS;CACX;CAGF,IAAI,YAAY,SACd,OAAO,gCAAgC;EAAE;EAAI,UAAU,SAAS;CAAK,CAAC;CAGxE,MAAM,WAAW,gBACZ,oBACA,MAAM,8BAA8B;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA,UAAU,SAAS,QAAQ;CAC7B,CAAC,IACD,KAAA;CACJ,IACE,eAAe,aAAa,wBAAwB,aACpD,UAiBA,OAAO,uBAAuB,MAfZ,6BAA6B;EAC7C;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,UAAU,SAAS,QAAQ;CAC7B,CAAC,CACgC;CAEnC,OAAO,MAAM,4BAA4B;EACvC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
//#region src/subagent-prompt-schema.ts
|
|
2
|
-
const contentArraySchema = {
|
|
3
|
-
items: { anyOf: [
|
|
4
|
-
{
|
|
5
|
-
additionalProperties: false,
|
|
6
|
-
properties: {
|
|
7
|
-
text: { type: "string" },
|
|
8
|
-
type: { const: "text" }
|
|
9
|
-
},
|
|
10
|
-
required: ["type", "text"],
|
|
11
|
-
type: "object"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
additionalProperties: false,
|
|
15
|
-
properties: {
|
|
16
|
-
image: { type: "string" },
|
|
17
|
-
mediaType: { type: "string" },
|
|
18
|
-
type: { const: "image" }
|
|
19
|
-
},
|
|
20
|
-
required: ["type", "image"],
|
|
21
|
-
type: "object"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
additionalProperties: false,
|
|
25
|
-
properties: {
|
|
26
|
-
data: { anyOf: [
|
|
27
|
-
{ type: "string" },
|
|
28
|
-
{
|
|
29
|
-
additionalProperties: false,
|
|
30
|
-
properties: {
|
|
31
|
-
data: { type: "string" },
|
|
32
|
-
type: { const: "data" }
|
|
33
|
-
},
|
|
34
|
-
required: ["type", "data"],
|
|
35
|
-
type: "object"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
additionalProperties: false,
|
|
39
|
-
properties: {
|
|
40
|
-
reference: {
|
|
41
|
-
additionalProperties: { type: "string" },
|
|
42
|
-
type: "object"
|
|
43
|
-
},
|
|
44
|
-
type: { const: "reference" }
|
|
45
|
-
},
|
|
46
|
-
required: ["type", "reference"],
|
|
47
|
-
type: "object"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
additionalProperties: false,
|
|
51
|
-
properties: {
|
|
52
|
-
text: { type: "string" },
|
|
53
|
-
type: { const: "text" }
|
|
54
|
-
},
|
|
55
|
-
required: ["type", "text"],
|
|
56
|
-
type: "object"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
additionalProperties: false,
|
|
60
|
-
properties: {
|
|
61
|
-
type: { const: "url" },
|
|
62
|
-
url: { type: "string" }
|
|
63
|
-
},
|
|
64
|
-
required: ["type", "url"],
|
|
65
|
-
type: "object"
|
|
66
|
-
}
|
|
67
|
-
] },
|
|
68
|
-
filename: { type: "string" },
|
|
69
|
-
mediaType: { type: "string" },
|
|
70
|
-
type: { const: "file" }
|
|
71
|
-
},
|
|
72
|
-
required: [
|
|
73
|
-
"type",
|
|
74
|
-
"data",
|
|
75
|
-
"mediaType"
|
|
76
|
-
],
|
|
77
|
-
type: "object"
|
|
78
|
-
}
|
|
79
|
-
] },
|
|
80
|
-
type: "array"
|
|
81
|
-
};
|
|
82
|
-
const delegatePromptSchema = { anyOf: [
|
|
83
|
-
{ type: "string" },
|
|
84
|
-
{
|
|
85
|
-
items: { type: "string" },
|
|
86
|
-
type: "array"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
additionalProperties: false,
|
|
90
|
-
properties: {
|
|
91
|
-
text: { anyOf: [{ type: "string" }, {
|
|
92
|
-
items: { type: "string" },
|
|
93
|
-
type: "array"
|
|
94
|
-
}] },
|
|
95
|
-
type: { const: "user-text" }
|
|
96
|
-
},
|
|
97
|
-
required: ["type", "text"],
|
|
98
|
-
type: "object"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
additionalProperties: false,
|
|
102
|
-
properties: {
|
|
103
|
-
content: contentArraySchema,
|
|
104
|
-
type: { const: "user-message" }
|
|
105
|
-
},
|
|
106
|
-
required: ["type", "content"],
|
|
107
|
-
type: "object"
|
|
108
|
-
},
|
|
109
|
-
contentArraySchema
|
|
110
|
-
] };
|
|
111
|
-
//#endregion
|
|
112
|
-
export { delegatePromptSchema };
|
|
113
|
-
|
|
114
|
-
//# sourceMappingURL=subagent-prompt-schema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-prompt-schema.js","names":[],"sources":["../src/subagent-prompt-schema.ts"],"sourcesContent":["const fileDataSchema = {\n anyOf: [\n { type: \"string\" },\n {\n additionalProperties: false,\n properties: {\n data: { type: \"string\" },\n type: { const: \"data\" },\n },\n required: [\"type\", \"data\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n reference: {\n additionalProperties: { type: \"string\" },\n type: \"object\",\n },\n type: { const: \"reference\" },\n },\n required: [\"type\", \"reference\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n text: { type: \"string\" },\n type: { const: \"text\" },\n },\n required: [\"type\", \"text\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n type: { const: \"url\" },\n url: { type: \"string\" },\n },\n required: [\"type\", \"url\"],\n type: \"object\",\n },\n ],\n};\n\nconst contentPartSchema = {\n anyOf: [\n {\n additionalProperties: false,\n properties: {\n text: { type: \"string\" },\n type: { const: \"text\" },\n },\n required: [\"type\", \"text\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n image: { type: \"string\" },\n mediaType: { type: \"string\" },\n type: { const: \"image\" },\n },\n required: [\"type\", \"image\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n data: fileDataSchema,\n filename: { type: \"string\" },\n mediaType: { type: \"string\" },\n type: { const: \"file\" },\n },\n required: [\"type\", \"data\", \"mediaType\"],\n type: \"object\",\n },\n ],\n};\n\nconst contentArraySchema = {\n items: contentPartSchema,\n type: \"array\",\n};\n\nexport const delegatePromptSchema = {\n anyOf: [\n { type: \"string\" },\n { items: { type: \"string\" }, type: \"array\" },\n {\n additionalProperties: false,\n properties: {\n text: {\n anyOf: [\n { type: \"string\" },\n { items: { type: \"string\" }, type: \"array\" },\n ],\n },\n type: { const: \"user-text\" },\n },\n required: [\"type\", \"text\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n properties: {\n content: contentArraySchema,\n type: { const: \"user-message\" },\n },\n required: [\"type\", \"content\"],\n type: \"object\",\n },\n contentArraySchema,\n ],\n};\n"],"mappings":";AAgFA,MAAM,qBAAqB;CACzB,OAAO,EAnCP,OAAO;EACL;GACE,sBAAsB;GACtB,YAAY;IACV,MAAM,EAAE,MAAM,SAAS;IACvB,MAAM,EAAE,OAAO,OAAO;GACxB;GACA,UAAU,CAAC,QAAQ,MAAM;GACzB,MAAM;EACR;EACA;GACE,sBAAsB;GACtB,YAAY;IACV,OAAO,EAAE,MAAM,SAAS;IACxB,WAAW,EAAE,MAAM,SAAS;IAC5B,MAAM,EAAE,OAAO,QAAQ;GACzB;GACA,UAAU,CAAC,QAAQ,OAAO;GAC1B,MAAM;EACR;EACA;GACE,sBAAsB;GACtB,YAAY;IACV,MAAM,EApEZ,OAAO;KACL,EAAE,MAAM,SAAS;KACjB;MACE,sBAAsB;MACtB,YAAY;OACV,MAAM,EAAE,MAAM,SAAS;OACvB,MAAM,EAAE,OAAO,OAAO;MACxB;MACA,UAAU,CAAC,QAAQ,MAAM;MACzB,MAAM;KACR;KACA;MACE,sBAAsB;MACtB,YAAY;OACV,WAAW;QACT,sBAAsB,EAAE,MAAM,SAAS;QACvC,MAAM;OACR;OACA,MAAM,EAAE,OAAO,YAAY;MAC7B;MACA,UAAU,CAAC,QAAQ,WAAW;MAC9B,MAAM;KACR;KACA;MACE,sBAAsB;MACtB,YAAY;OACV,MAAM,EAAE,MAAM,SAAS;OACvB,MAAM,EAAE,OAAO,OAAO;MACxB;MACA,UAAU,CAAC,QAAQ,MAAM;MACzB,MAAM;KACR;KACA;MACE,sBAAsB;MACtB,YAAY;OACV,MAAM,EAAE,OAAO,MAAM;OACrB,KAAK,EAAE,MAAM,SAAS;MACxB;MACA,UAAU,CAAC,QAAQ,KAAK;MACxB,MAAM;KACR;IACF,EA2ByB;IACnB,UAAU,EAAE,MAAM,SAAS;IAC3B,WAAW,EAAE,MAAM,SAAS;IAC5B,MAAM,EAAE,OAAO,OAAO;GACxB;GACA,UAAU;IAAC;IAAQ;IAAQ;GAAW;GACtC,MAAM;EACR;CACF,EAIuB;CACvB,MAAM;AACR;AAEA,MAAa,uBAAuB,EAClC,OAAO;CACL,EAAE,MAAM,SAAS;CACjB;EAAE,OAAO,EAAE,MAAM,SAAS;EAAG,MAAM;CAAQ;CAC3C;EACE,sBAAsB;EACtB,YAAY;GACV,MAAM,EACJ,OAAO,CACL,EAAE,MAAM,SAAS,GACjB;IAAE,OAAO,EAAE,MAAM,SAAS;IAAG,MAAM;GAAQ,CAC7C,EACF;GACA,MAAM,EAAE,OAAO,YAAY;EAC7B;EACA,UAAU,CAAC,QAAQ,MAAM;EACzB,MAAM;CACR;CACA;EACE,sBAAsB;EACtB,YAAY;GACV,SAAS;GACT,MAAM,EAAE,OAAO,eAAe;EAChC;EACA,UAAU,CAAC,QAAQ,SAAS;EAC5B,MAAM;CACR;CACA;AACF,EACF"}
|
package/dist/subagent-run.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
//#region src/subagent-run.ts
|
|
2
|
-
const maxCompactTextLength = 2e4;
|
|
3
|
-
const maxStoredEvents = 200;
|
|
4
|
-
const childSessionKeySuffixPattern = /^[A-Za-z0-9_-]{1,80}$/;
|
|
5
|
-
async function runBlockingDelegation({ abortSignal, prompt, sessionKey, subagent }) {
|
|
6
|
-
const childSession = subagent.session(sessionKey);
|
|
7
|
-
if (abortSignal?.aborted) return {
|
|
8
|
-
eventCount: 0,
|
|
9
|
-
result: "aborted",
|
|
10
|
-
run_in_background: false,
|
|
11
|
-
subagent: subagent.name ?? "subagent",
|
|
12
|
-
text: ""
|
|
13
|
-
};
|
|
14
|
-
const abort = () => childSession.interrupt();
|
|
15
|
-
abortSignal?.addEventListener("abort", abort, { once: true });
|
|
16
|
-
try {
|
|
17
|
-
return await collectSubagentRun(await childSession.send(prompt), subagent.name ?? "subagent");
|
|
18
|
-
} finally {
|
|
19
|
-
abortSignal?.removeEventListener("abort", abort);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async function collectSubagentRun(run, subagent) {
|
|
23
|
-
return (await collectSubagentRunWithEvents(run, subagent)).result;
|
|
24
|
-
}
|
|
25
|
-
async function collectSubagentRunWithEvents(run, subagent, onEvent) {
|
|
26
|
-
let eventCount = 0;
|
|
27
|
-
let result = "completed";
|
|
28
|
-
const events = [];
|
|
29
|
-
const textParts = [];
|
|
30
|
-
let textLength = 0;
|
|
31
|
-
let textTruncated = false;
|
|
32
|
-
try {
|
|
33
|
-
for await (const event of run.events()) {
|
|
34
|
-
eventCount += 1;
|
|
35
|
-
if (events.length < maxStoredEvents) events.push(event);
|
|
36
|
-
await onEvent?.(event);
|
|
37
|
-
if (event.type === "assistant-text") {
|
|
38
|
-
const appended = appendCompactText(textParts, textLength, event.text);
|
|
39
|
-
textLength = appended.length;
|
|
40
|
-
textTruncated ||= appended.truncated;
|
|
41
|
-
} else if (event.type === "turn-abort") result = "aborted";
|
|
42
|
-
else if (event.type === "turn-error") return {
|
|
43
|
-
retainedEvents: events,
|
|
44
|
-
result: {
|
|
45
|
-
error: event.message,
|
|
46
|
-
eventCount,
|
|
47
|
-
result: "error",
|
|
48
|
-
run_in_background: false,
|
|
49
|
-
subagent,
|
|
50
|
-
text: compactText(textParts, textTruncated)
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
} catch (error) {
|
|
55
|
-
return {
|
|
56
|
-
retainedEvents: events,
|
|
57
|
-
result: {
|
|
58
|
-
error: errorMessage(error),
|
|
59
|
-
eventCount,
|
|
60
|
-
result: "error",
|
|
61
|
-
run_in_background: false,
|
|
62
|
-
subagent,
|
|
63
|
-
text: compactText(textParts, textTruncated)
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
retainedEvents: events,
|
|
69
|
-
result: {
|
|
70
|
-
eventCount,
|
|
71
|
-
result,
|
|
72
|
-
run_in_background: false,
|
|
73
|
-
subagent,
|
|
74
|
-
text: compactText(textParts, textTruncated)
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function defaultChildSessionKey(parentAgentNamespace, parentSessionKey, subagent) {
|
|
79
|
-
return `parent:${parentAgentNamespace}:${parentSessionKey}:subagent:${subagent}`;
|
|
80
|
-
}
|
|
81
|
-
function scopedChildSessionKey({ parentAgentNamespace, parentSessionKey, sessionKey, subagent }) {
|
|
82
|
-
const base = defaultChildSessionKey(parentAgentNamespace, parentSessionKey, subagent);
|
|
83
|
-
if (!sessionKey) return base;
|
|
84
|
-
if (!childSessionKeySuffixPattern.test(sessionKey)) throw new Error("delegate sessionKey must be a short alphanumeric child-session suffix");
|
|
85
|
-
return `${base}:${sessionKey}`;
|
|
86
|
-
}
|
|
87
|
-
function compactText(parts, truncated) {
|
|
88
|
-
const text = parts.join("");
|
|
89
|
-
return truncated ? `${text}…[truncated]` : text;
|
|
90
|
-
}
|
|
91
|
-
function appendCompactText(parts, currentLength, next) {
|
|
92
|
-
if (currentLength >= maxCompactTextLength) return {
|
|
93
|
-
length: currentLength,
|
|
94
|
-
truncated: next.length > 0
|
|
95
|
-
};
|
|
96
|
-
const remaining = maxCompactTextLength - currentLength;
|
|
97
|
-
const chunk = next.length > remaining ? next.slice(0, remaining) : next;
|
|
98
|
-
parts.push(chunk);
|
|
99
|
-
return {
|
|
100
|
-
length: currentLength + chunk.length,
|
|
101
|
-
truncated: next.length > remaining
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function errorMessage(error) {
|
|
105
|
-
if (error instanceof Error) return error.message;
|
|
106
|
-
return String(error);
|
|
107
|
-
}
|
|
108
|
-
//#endregion
|
|
109
|
-
export { collectSubagentRunWithEvents, runBlockingDelegation, scopedChildSessionKey };
|
|
110
|
-
|
|
111
|
-
//# sourceMappingURL=subagent-run.js.map
|
package/dist/subagent-run.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-run.js","names":[],"sources":["../src/subagent-run.ts"],"sourcesContent":["import type { AgentEvent } from \"./session/events\";\nimport type { AgentInput } from \"./session/input\";\nimport type { AgentRun } from \"./session/run\";\nimport type {\n CompactSubagentResult,\n Subagent,\n SubagentRunResult,\n} from \"./subagent-types\";\n\nconst maxCompactTextLength = 20_000;\nconst maxStoredEvents = 200;\nconst childSessionKeySuffixPattern = /^[A-Za-z0-9_-]{1,80}$/;\n\nexport async function runBlockingDelegation({\n abortSignal,\n prompt,\n sessionKey,\n subagent,\n}: {\n readonly abortSignal?: AbortSignal;\n readonly prompt: AgentInput;\n readonly sessionKey: string;\n readonly subagent: Subagent;\n}): Promise<CompactSubagentResult> {\n const childSession = subagent.session(sessionKey);\n if (abortSignal?.aborted) {\n return {\n eventCount: 0,\n result: \"aborted\",\n run_in_background: false,\n subagent: subagent.name ?? \"subagent\",\n text: \"\",\n };\n }\n\n const abort = () => childSession.interrupt();\n abortSignal?.addEventListener(\"abort\", abort, { once: true });\n try {\n return await collectSubagentRun(\n await childSession.send(prompt),\n subagent.name ?? \"subagent\"\n );\n } finally {\n abortSignal?.removeEventListener(\"abort\", abort);\n }\n}\n\nexport async function collectSubagentRun(\n run: AgentRun,\n subagent: string\n): Promise<CompactSubagentResult> {\n return (await collectSubagentRunWithEvents(run, subagent)).result;\n}\n\nexport async function collectSubagentRunWithEvents(\n run: AgentRun,\n subagent: string,\n onEvent?: (event: AgentEvent) => Promise<void> | void\n): Promise<SubagentRunResult> {\n let eventCount = 0;\n let result: CompactSubagentResult[\"result\"] = \"completed\";\n const events: AgentEvent[] = [];\n const textParts: string[] = [];\n let textLength = 0;\n let textTruncated = false;\n\n try {\n for await (const event of run.events()) {\n eventCount += 1;\n if (events.length < maxStoredEvents) {\n events.push(event);\n }\n await onEvent?.(event);\n if (event.type === \"assistant-text\") {\n const appended = appendCompactText(textParts, textLength, event.text);\n textLength = appended.length;\n textTruncated ||= appended.truncated;\n } else if (event.type === \"turn-abort\") {\n result = \"aborted\";\n } else if (event.type === \"turn-error\") {\n return {\n retainedEvents: events,\n result: {\n error: event.message,\n eventCount,\n result: \"error\",\n run_in_background: false,\n subagent,\n text: compactText(textParts, textTruncated),\n },\n };\n }\n }\n } catch (error) {\n return {\n retainedEvents: events,\n result: {\n error: errorMessage(error),\n eventCount,\n result: \"error\",\n run_in_background: false,\n subagent,\n text: compactText(textParts, textTruncated),\n },\n };\n }\n\n return {\n retainedEvents: events,\n result: {\n eventCount,\n result,\n run_in_background: false,\n subagent,\n text: compactText(textParts, textTruncated),\n },\n };\n}\n\nexport function defaultChildSessionKey(\n parentAgentNamespace: string,\n parentSessionKey: string,\n subagent: string\n): string {\n return `parent:${parentAgentNamespace}:${parentSessionKey}:subagent:${subagent}`;\n}\n\nexport function scopedChildSessionKey({\n parentAgentNamespace,\n parentSessionKey,\n sessionKey,\n subagent,\n}: {\n readonly parentAgentNamespace: string;\n readonly parentSessionKey: string;\n readonly sessionKey?: string;\n readonly subagent: string;\n}): string {\n const base = defaultChildSessionKey(\n parentAgentNamespace,\n parentSessionKey,\n subagent\n );\n if (!sessionKey) {\n return base;\n }\n\n if (!childSessionKeySuffixPattern.test(sessionKey)) {\n throw new Error(\n \"delegate sessionKey must be a short alphanumeric child-session suffix\"\n );\n }\n\n return `${base}:${sessionKey}`;\n}\n\nfunction compactText(parts: readonly string[], truncated: boolean): string {\n const text = parts.join(\"\");\n return truncated ? `${text}…[truncated]` : text;\n}\n\nfunction appendCompactText(\n parts: string[],\n currentLength: number,\n next: string\n): { readonly length: number; readonly truncated: boolean } {\n if (currentLength >= maxCompactTextLength) {\n return { length: currentLength, truncated: next.length > 0 };\n }\n\n const remaining = maxCompactTextLength - currentLength;\n const chunk = next.length > remaining ? next.slice(0, remaining) : next;\n parts.push(chunk);\n return {\n length: currentLength + chunk.length,\n truncated: next.length > remaining,\n };\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":";AASA,MAAM,uBAAuB;AAC7B,MAAM,kBAAkB;AACxB,MAAM,+BAA+B;AAErC,eAAsB,sBAAsB,EAC1C,aACA,QACA,YACA,YAMiC;CACjC,MAAM,eAAe,SAAS,QAAQ,UAAU;CAChD,IAAI,aAAa,SACf,OAAO;EACL,YAAY;EACZ,QAAQ;EACR,mBAAmB;EACnB,UAAU,SAAS,QAAQ;EAC3B,MAAM;CACR;CAGF,MAAM,cAAc,aAAa,UAAU;CAC3C,aAAa,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CAC5D,IAAI;EACF,OAAO,MAAM,mBACX,MAAM,aAAa,KAAK,MAAM,GAC9B,SAAS,QAAQ,UACnB;CACF,UAAU;EACR,aAAa,oBAAoB,SAAS,KAAK;CACjD;AACF;AAEA,eAAsB,mBACpB,KACA,UACgC;CAChC,QAAQ,MAAM,6BAA6B,KAAK,QAAQ,GAAG;AAC7D;AAEA,eAAsB,6BACpB,KACA,UACA,SAC4B;CAC5B,IAAI,aAAa;CACjB,IAAI,SAA0C;CAC9C,MAAM,SAAuB,CAAC;CAC9B,MAAM,YAAsB,CAAC;CAC7B,IAAI,aAAa;CACjB,IAAI,gBAAgB;CAEpB,IAAI;EACF,WAAW,MAAM,SAAS,IAAI,OAAO,GAAG;GACtC,cAAc;GACd,IAAI,OAAO,SAAS,iBAClB,OAAO,KAAK,KAAK;GAEnB,MAAM,UAAU,KAAK;GACrB,IAAI,MAAM,SAAS,kBAAkB;IACnC,MAAM,WAAW,kBAAkB,WAAW,YAAY,MAAM,IAAI;IACpE,aAAa,SAAS;IACtB,kBAAkB,SAAS;GAC7B,OAAO,IAAI,MAAM,SAAS,cACxB,SAAS;QACJ,IAAI,MAAM,SAAS,cACxB,OAAO;IACL,gBAAgB;IAChB,QAAQ;KACN,OAAO,MAAM;KACb;KACA,QAAQ;KACR,mBAAmB;KACnB;KACA,MAAM,YAAY,WAAW,aAAa;IAC5C;GACF;EAEJ;CACF,SAAS,OAAO;EACd,OAAO;GACL,gBAAgB;GAChB,QAAQ;IACN,OAAO,aAAa,KAAK;IACzB;IACA,QAAQ;IACR,mBAAmB;IACnB;IACA,MAAM,YAAY,WAAW,aAAa;GAC5C;EACF;CACF;CAEA,OAAO;EACL,gBAAgB;EAChB,QAAQ;GACN;GACA;GACA,mBAAmB;GACnB;GACA,MAAM,YAAY,WAAW,aAAa;EAC5C;CACF;AACF;AAEA,SAAgB,uBACd,sBACA,kBACA,UACQ;CACR,OAAO,UAAU,qBAAqB,GAAG,iBAAiB,YAAY;AACxE;AAEA,SAAgB,sBAAsB,EACpC,sBACA,kBACA,YACA,YAMS;CACT,MAAM,OAAO,uBACX,sBACA,kBACA,QACF;CACA,IAAI,CAAC,YACH,OAAO;CAGT,IAAI,CAAC,6BAA6B,KAAK,UAAU,GAC/C,MAAM,IAAI,MACR,uEACF;CAGF,OAAO,GAAG,KAAK,GAAG;AACpB;AAEA,SAAS,YAAY,OAA0B,WAA4B;CACzE,MAAM,OAAO,MAAM,KAAK,EAAE;CAC1B,OAAO,YAAY,GAAG,KAAK,gBAAgB;AAC7C;AAEA,SAAS,kBACP,OACA,eACA,MAC0D;CAC1D,IAAI,iBAAiB,sBACnB,OAAO;EAAE,QAAQ;EAAe,WAAW,KAAK,SAAS;CAAE;CAG7D,MAAM,YAAY,uBAAuB;CACzC,MAAM,QAAQ,KAAK,SAAS,YAAY,KAAK,MAAM,GAAG,SAAS,IAAI;CACnE,MAAM,KAAK,KAAK;CAChB,OAAO;EACL,QAAQ,gBAAgB,MAAM;EAC9B,WAAW,KAAK,SAAS;CAC3B;AACF;AAEA,SAAS,aAAa,OAAwB;CAC5C,IAAI,iBAAiB,OACnB,OAAO,MAAM;CAGf,OAAO,OAAO,KAAK;AACrB"}
|