@minpeter/pss-runtime 0.1.0-next.1 → 0.1.0-next.2
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 +169 -28
- package/dist/agent-child-runs.js +16 -0
- package/dist/agent-child-runs.js.map +1 -0
- package/dist/agent-host-capabilities.js +9 -0
- package/dist/agent-host-capabilities.js.map +1 -0
- package/dist/agent-host-session-store.js +12 -0
- package/dist/agent-host-session-store.js.map +1 -0
- package/dist/agent-loop.js +58 -28
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +8 -1
- package/dist/agent-namespace.js.map +1 -1
- package/dist/agent-options.d.ts +35 -0
- package/dist/agent-options.js +16 -0
- package/dist/agent-options.js.map +1 -0
- package/dist/agent-resume.js +143 -0
- package/dist/agent-resume.js.map +1 -0
- package/dist/agent-session-entry.d.ts +13 -0
- package/dist/agent-validation.js +2 -2
- package/dist/agent-validation.js.map +1 -1
- package/dist/agent.d.ts +5 -41
- package/dist/agent.js +81 -49
- package/dist/agent.js.map +1 -1
- package/dist/execution/host.js +14 -0
- package/dist/execution/host.js.map +1 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.js +3 -0
- package/dist/execution/memory-notifications.js +54 -0
- package/dist/execution/memory-notifications.js.map +1 -0
- package/dist/execution/memory-state.js +34 -0
- package/dist/execution/memory-state.js.map +1 -0
- package/dist/execution/memory-store.js +203 -0
- package/dist/execution/memory-store.js.map +1 -0
- package/dist/execution/memory.d.ts +7 -0
- package/dist/execution/memory.js +28 -0
- package/dist/execution/memory.js.map +1 -0
- package/dist/execution/run.js +55 -0
- package/dist/execution/run.js.map +1 -0
- package/dist/execution/types.d.ts +155 -0
- package/dist/index.d.ts +8 -5
- package/dist/llm-tool-execution.d.ts +35 -0
- package/dist/llm-tool-execution.js +126 -0
- package/dist/llm-tool-execution.js.map +1 -0
- package/dist/llm.d.ts +11 -15
- package/dist/llm.js +5 -3
- package/dist/llm.js.map +1 -1
- package/dist/plugins.d.ts +20 -0
- package/dist/plugins.js +14 -0
- package/dist/plugins.js.map +1 -0
- package/dist/session/events.d.ts +3 -0
- package/dist/session/runtime-input.js +5 -23
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-errors.js +1 -6
- package/dist/session/session-errors.js.map +1 -1
- package/dist/session/session-events.js +59 -0
- package/dist/session/session-events.js.map +1 -0
- package/dist/session/session-execution.js +88 -0
- package/dist/session/session-execution.js.map +1 -0
- package/dist/session/session-notification.js +58 -0
- package/dist/session/session-notification.js.map +1 -0
- package/dist/session/session-runtime-drain.js +2 -2
- package/dist/session/session-runtime-drain.js.map +1 -1
- package/dist/session/session-turn-processor.js +135 -0
- package/dist/session/session-turn-processor.js.map +1 -0
- package/dist/session/session.js +73 -101
- package/dist/session/session.js.map +1 -1
- package/dist/session/snapshot.js.map +1 -1
- package/dist/subagent-background-child-run-state.js +51 -0
- package/dist/subagent-background-child-run-state.js.map +1 -0
- package/dist/subagent-background-child-run.js +103 -0
- package/dist/subagent-background-child-run.js.map +1 -0
- package/dist/subagent-background-in-process.js +98 -0
- package/dist/subagent-background-in-process.js.map +1 -0
- package/dist/subagent-background-notification-inbox.js +106 -0
- package/dist/subagent-background-notification-inbox.js.map +1 -0
- package/dist/subagent-background-notify.js +136 -0
- package/dist/subagent-background-notify.js.map +1 -0
- package/dist/subagent-background-resume-group.js +99 -0
- package/dist/subagent-background-resume-group.js.map +1 -0
- package/dist/subagent-background-runner.js +115 -0
- package/dist/subagent-background-runner.js.map +1 -0
- package/dist/subagent-background-schedule.js +43 -0
- package/dist/subagent-background-schedule.js.map +1 -0
- package/dist/subagent-child-run.js +68 -0
- package/dist/subagent-child-run.js.map +1 -0
- package/dist/subagent-job-cancel.js +60 -4
- package/dist/subagent-job-cancel.js.map +1 -1
- package/dist/subagent-job-observer.js +19 -0
- package/dist/subagent-job-observer.js.map +1 -0
- package/dist/subagent-job-output.js +28 -4
- package/dist/subagent-job-output.js.map +1 -1
- package/dist/subagent-job-state.js +66 -0
- package/dist/subagent-job-state.js.map +1 -0
- package/dist/subagent-jobs.js +78 -133
- package/dist/subagent-jobs.js.map +1 -1
- package/dist/subagent-run.js +4 -4
- package/dist/subagent-run.js.map +1 -1
- package/dist/subagents.js +68 -35
- package/dist/subagents.js.map +1 -1
- package/package.json +11 -1
- package/dist/hooks.d.ts +0 -32
- /package/dist/session/{runtime-input.d.ts → session-execution.d.ts} +0 -0
package/dist/subagent-jobs.js
CHANGED
|
@@ -1,151 +1,96 @@
|
|
|
1
|
-
import {
|
|
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";
|
|
2
5
|
//#region src/subagent-jobs.ts
|
|
3
6
|
const maxBackgroundJobs = 64;
|
|
4
7
|
const maxRetainedBackgroundJobs = maxBackgroundJobs * 4;
|
|
5
|
-
function startBackgroundJob({ abortSignal, description, jobs, parentSession, prompt, registerCleanup, sessionKey, subagent }) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
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 {
|
|
9
35
|
message: "Background subagent job was not started because the background job limit is full.",
|
|
10
36
|
run_in_background: true,
|
|
11
37
|
status: "cancelled",
|
|
12
38
|
subagent: subagent.name,
|
|
13
39
|
task_id: id
|
|
14
40
|
};
|
|
15
|
-
if (abortSignal.aborted) return {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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,
|
|
30
61
|
description,
|
|
62
|
+
executionHost,
|
|
63
|
+
groupId,
|
|
64
|
+
groups,
|
|
31
65
|
id,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
settled: false,
|
|
35
|
-
status: "pending",
|
|
36
|
-
subagent: subagent.name ?? "subagent",
|
|
37
|
-
unregisterCleanup
|
|
38
|
-
};
|
|
39
|
-
job.promise = runBackgroundJob({
|
|
40
|
-
childSession,
|
|
41
|
-
job,
|
|
66
|
+
jobs,
|
|
67
|
+
parentRunId,
|
|
42
68
|
parentSession,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
parentSessionKey,
|
|
70
|
+
ownerNamespace,
|
|
71
|
+
subagent: subagent.name ?? "subagent"
|
|
72
|
+
}));
|
|
73
|
+
return await startInProcessBackgroundJob({
|
|
74
|
+
abortSignal,
|
|
75
|
+
childRun,
|
|
76
|
+
delegateToolCallId,
|
|
50
77
|
description,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
async function runBackgroundJob({ childSession, job, parentSession, prompt }) {
|
|
65
|
-
if (job.status === "cancelled") return;
|
|
66
|
-
job.status = "running";
|
|
67
|
-
try {
|
|
68
|
-
const { result } = await collectSubagentRunWithEvents(await childSession.send(prompt), job.subagent, (event) => emitJobUpdate(parentSession, job, event));
|
|
69
|
-
if (isCancelledJob(job)) return;
|
|
70
|
-
job.result = result;
|
|
71
|
-
job.status = result.result;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
if (isCancelledJob(job)) return;
|
|
74
|
-
const jobError = error instanceof Error ? error : new Error(String(error));
|
|
75
|
-
job.status = "error";
|
|
76
|
-
job.result = {
|
|
77
|
-
error: errorMessage(jobError),
|
|
78
|
-
eventCount: 0,
|
|
79
|
-
result: "error",
|
|
80
|
-
run_in_background: false,
|
|
81
|
-
subagent: job.subagent,
|
|
82
|
-
text: ""
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
if (isCancelledJob(job)) return;
|
|
86
|
-
parentSession.enqueueRuntimeInput({
|
|
87
|
-
text: [
|
|
88
|
-
"<system-reminder>",
|
|
89
|
-
"[SUBAGENT JOB RESULT READY]",
|
|
90
|
-
`Task ID: ${job.id}`,
|
|
91
|
-
`Subagent: ${job.subagent}`,
|
|
92
|
-
`Description: ${sanitizeReminderField(job.description ?? "")}`,
|
|
93
|
-
`Use background_output({ task_id: "${job.id}" }) to retrieve the result.`,
|
|
94
|
-
"</system-reminder>"
|
|
95
|
-
].join("\n"),
|
|
96
|
-
type: "user-text"
|
|
97
|
-
}, "turn-start");
|
|
98
|
-
parentSession.emitObserverEvent({
|
|
99
|
-
error: job.result?.error,
|
|
100
|
-
eventCount: job.result?.eventCount ?? 0,
|
|
101
|
-
status: job.result?.result ?? "error",
|
|
102
|
-
subagent: job.subagent,
|
|
103
|
-
task_id: job.id,
|
|
104
|
-
type: "subagent-job-end"
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
function emitJobUpdate(parentSession, job, event) {
|
|
108
|
-
parentSession.emitObserverEvent({
|
|
109
|
-
eventType: event.type,
|
|
110
|
-
status: job.status,
|
|
111
|
-
subagent: job.subagent,
|
|
112
|
-
task_id: job.id,
|
|
113
|
-
type: "subagent-job-update"
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
function assertBackgroundTaskId(value, toolName) {
|
|
117
|
-
if (value.startsWith("bg_")) return;
|
|
118
|
-
throw new Error(`${toolName} expects a background task_id starting with bg_, not a session key: ${value}`);
|
|
119
|
-
}
|
|
120
|
-
function errorMessage(error) {
|
|
121
|
-
if (error instanceof Error) return error.message;
|
|
122
|
-
return String(error);
|
|
123
|
-
}
|
|
124
|
-
function isActiveJob(status) {
|
|
125
|
-
return status === "pending" || status === "running";
|
|
126
|
-
}
|
|
127
|
-
function isCancelledJob(job) {
|
|
128
|
-
return job.status === "cancelled";
|
|
129
|
-
}
|
|
130
|
-
function hasJobCapacity(jobs) {
|
|
131
|
-
if (jobs.size >= maxRetainedBackgroundJobs) return false;
|
|
132
|
-
let activeJobs = 0;
|
|
133
|
-
for (const job of jobs.values()) if (isActiveJob(job.status) || !job.settled) activeJobs += 1;
|
|
134
|
-
return activeJobs < maxBackgroundJobs;
|
|
135
|
-
}
|
|
136
|
-
function cancelJob(job) {
|
|
137
|
-
job.status = "cancelled";
|
|
138
|
-
job.abort();
|
|
139
|
-
}
|
|
140
|
-
function cleanupJob(job) {
|
|
141
|
-
return job.cleanup().then(() => {
|
|
142
|
-
job.unregisterCleanup?.();
|
|
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
|
|
143
91
|
});
|
|
144
92
|
}
|
|
145
|
-
function sanitizeReminderField(value) {
|
|
146
|
-
return value.replaceAll("\r", " ").replaceAll("\n", " ").replaceAll("<", "<").replaceAll(">", ">");
|
|
147
|
-
}
|
|
148
93
|
//#endregion
|
|
149
|
-
export {
|
|
94
|
+
export { startBackgroundJob };
|
|
150
95
|
|
|
151
96
|
//# sourceMappingURL=subagent-jobs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-jobs.js","names":[],"sources":["../src/subagent-jobs.ts"],"sourcesContent":["import type {
|
|
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"}
|
package/dist/subagent-run.js
CHANGED
|
@@ -33,14 +33,14 @@ async function collectSubagentRunWithEvents(run, subagent, onEvent) {
|
|
|
33
33
|
for await (const event of run.events()) {
|
|
34
34
|
eventCount += 1;
|
|
35
35
|
if (events.length < maxStoredEvents) events.push(event);
|
|
36
|
-
onEvent?.(event);
|
|
36
|
+
await onEvent?.(event);
|
|
37
37
|
if (event.type === "assistant-text") {
|
|
38
38
|
const appended = appendCompactText(textParts, textLength, event.text);
|
|
39
39
|
textLength = appended.length;
|
|
40
40
|
textTruncated ||= appended.truncated;
|
|
41
41
|
} else if (event.type === "turn-abort") result = "aborted";
|
|
42
42
|
else if (event.type === "turn-error") return {
|
|
43
|
-
events,
|
|
43
|
+
retainedEvents: events,
|
|
44
44
|
result: {
|
|
45
45
|
error: event.message,
|
|
46
46
|
eventCount,
|
|
@@ -53,7 +53,7 @@ async function collectSubagentRunWithEvents(run, subagent, onEvent) {
|
|
|
53
53
|
}
|
|
54
54
|
} catch (error) {
|
|
55
55
|
return {
|
|
56
|
-
events,
|
|
56
|
+
retainedEvents: events,
|
|
57
57
|
result: {
|
|
58
58
|
error: errorMessage(error),
|
|
59
59
|
eventCount,
|
|
@@ -65,7 +65,7 @@ async function collectSubagentRunWithEvents(run, subagent, onEvent) {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
return {
|
|
68
|
-
events,
|
|
68
|
+
retainedEvents: events,
|
|
69
69
|
result: {
|
|
70
70
|
eventCount,
|
|
71
71
|
result,
|
package/dist/subagent-run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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) => 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 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 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 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 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,UAAU,KAAK;
|
|
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":"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"}
|
package/dist/subagents.js
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
+
import { scopedChildSessionKey } from "./subagent-run.js";
|
|
1
2
|
import { normalizeAgentInput } from "./session/input-normalization.js";
|
|
2
|
-
import {
|
|
3
|
-
import { startBackgroundJob } from "./subagent-jobs.js";
|
|
3
|
+
import { blockingSubagentDedupeKey, runBlockingChild } from "./subagent-child-run.js";
|
|
4
4
|
import { createBackgroundCancelTool } from "./subagent-job-cancel.js";
|
|
5
5
|
import { createBackgroundOutputTool } from "./subagent-job-output.js";
|
|
6
|
+
import { startBackgroundJob } from "./subagent-jobs.js";
|
|
6
7
|
import { delegatePromptSchema } from "./subagent-prompt-schema.js";
|
|
7
8
|
import { jsonSchema, tool } from "ai";
|
|
8
9
|
//#region src/subagents.ts
|
|
9
|
-
function createSubagentTools({ parentAgentNamespace, parentSession, parentSessionKey, registerChildSession, subagents }) {
|
|
10
|
+
function createSubagentTools({ backgroundSubagents, executionHost, parentAgentNamespace, parentSession, parentSessionKey, registerChildSession, subagents }) {
|
|
10
11
|
if (subagents.length === 0) return {};
|
|
11
12
|
const jobs = /* @__PURE__ */ new Map();
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const groups = /* @__PURE__ */ new Map();
|
|
14
|
+
const blockingRuns = /* @__PURE__ */ new Map();
|
|
15
|
+
const backgroundToolScope = { childSessionKeyPrefix: `parent:${parentAgentNamespace}:${parentSessionKey}:subagent:` };
|
|
16
|
+
const generatedTools = backgroundSubagents ? {
|
|
17
|
+
background_cancel: createBackgroundCancelTool(jobs, executionHost, backgroundToolScope),
|
|
18
|
+
background_output: createBackgroundOutputTool(jobs, executionHost, backgroundToolScope)
|
|
19
|
+
} : {};
|
|
16
20
|
for (const subagent of subagents) {
|
|
17
21
|
const name = subagent.name;
|
|
18
22
|
if (!name) continue;
|
|
19
23
|
generatedTools[`delegate_to_${name.replaceAll("-", "_")}`] = createDelegateTool({
|
|
20
24
|
jobs,
|
|
25
|
+
groups,
|
|
26
|
+
backgroundSubagents,
|
|
27
|
+
blockingRuns,
|
|
28
|
+
executionHost,
|
|
21
29
|
parentAgentNamespace,
|
|
22
30
|
parentSession,
|
|
23
31
|
parentSessionKey,
|
|
@@ -27,10 +35,10 @@ function createSubagentTools({ parentAgentNamespace, parentSession, parentSessio
|
|
|
27
35
|
}
|
|
28
36
|
return generatedTools;
|
|
29
37
|
}
|
|
30
|
-
function createDelegateTool({ jobs, parentAgentNamespace, parentSession, parentSessionKey, registerChildSession, subagent }) {
|
|
38
|
+
function createDelegateTool({ jobs, groups, backgroundSubagents, blockingRuns, executionHost, parentAgentNamespace, parentSession, parentSessionKey, registerChildSession, subagent }) {
|
|
31
39
|
return tool({
|
|
32
40
|
description: `Delegate work to ${subagent.name}: ${subagent.description}`,
|
|
33
|
-
execute: async (input, { abortSignal }) => {
|
|
41
|
+
execute: async (input, { abortSignal, toolCallId }) => {
|
|
34
42
|
const prompt = normalizeAgentInput(input.prompt);
|
|
35
43
|
const sessionKey = scopedChildSessionKey({
|
|
36
44
|
parentAgentNamespace,
|
|
@@ -38,54 +46,79 @@ function createDelegateTool({ jobs, parentAgentNamespace, parentSession, parentS
|
|
|
38
46
|
sessionKey: input.sessionKey,
|
|
39
47
|
subagent: subagent.name ?? "subagent"
|
|
40
48
|
});
|
|
41
|
-
if (input.run_in_background === true)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (input.run_in_background === true) {
|
|
50
|
+
if (!backgroundSubagents) throw new Error("Background subagent delegation is not available for this host.");
|
|
51
|
+
return await startBackgroundJob({
|
|
52
|
+
abortSignal: abortSignal ?? new AbortController().signal,
|
|
53
|
+
description: input.description,
|
|
54
|
+
executionHost,
|
|
55
|
+
groupId: parentSession.currentBackgroundGroupId?.(),
|
|
56
|
+
groups,
|
|
57
|
+
jobs,
|
|
58
|
+
delegateToolCallId: toolCallId,
|
|
59
|
+
parentSession,
|
|
60
|
+
parentRunId: parentSession.currentRunId?.() ?? parentAgentNamespace,
|
|
61
|
+
parentSessionKey,
|
|
62
|
+
ownerNamespace: parentAgentNamespace,
|
|
63
|
+
prompt,
|
|
64
|
+
registerCleanup: (cleanup) => registerChildSession(parentSessionKey, cleanup),
|
|
65
|
+
sessionKey,
|
|
66
|
+
subagent
|
|
67
|
+
});
|
|
68
|
+
}
|
|
51
69
|
registerChildSession(parentSessionKey, () => subagent.session(sessionKey).delete());
|
|
52
|
-
parentSession.emitObserverEvent({
|
|
70
|
+
await parentSession.emitObserverEvent({
|
|
53
71
|
description: input.description,
|
|
72
|
+
delegateToolCallId: toolCallId,
|
|
54
73
|
run_in_background: false,
|
|
55
74
|
subagent: subagent.name ?? "subagent",
|
|
56
75
|
type: "subagent-job-start"
|
|
57
76
|
});
|
|
58
|
-
const
|
|
77
|
+
const dedupeKey = blockingSubagentDedupeKey(parentAgentNamespace, toolCallId);
|
|
78
|
+
const result = blockingRuns.get(dedupeKey) ?? runBlockingChild({
|
|
59
79
|
abortSignal,
|
|
80
|
+
dedupeKey,
|
|
81
|
+
executionHost,
|
|
82
|
+
parentRunId: parentSession.currentRunId?.() ?? parentAgentNamespace,
|
|
60
83
|
prompt,
|
|
61
84
|
sessionKey,
|
|
62
85
|
subagent
|
|
63
86
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
blockingRuns.set(dedupeKey, result);
|
|
88
|
+
const awaitedResult = await result;
|
|
89
|
+
await parentSession.emitObserverEvent({
|
|
90
|
+
error: awaitedResult.error,
|
|
91
|
+
eventCount: awaitedResult.eventCount,
|
|
92
|
+
delegateToolCallId: toolCallId,
|
|
93
|
+
status: awaitedResult.result,
|
|
68
94
|
subagent: subagent.name ?? "subagent",
|
|
69
95
|
type: "subagent-job-end"
|
|
70
96
|
});
|
|
71
|
-
return
|
|
97
|
+
return awaitedResult;
|
|
72
98
|
},
|
|
73
99
|
inputSchema: jsonSchema({
|
|
74
100
|
additionalProperties: false,
|
|
75
|
-
properties:
|
|
76
|
-
description: { type: "string" },
|
|
77
|
-
prompt: delegatePromptSchema,
|
|
78
|
-
run_in_background: {
|
|
79
|
-
default: false,
|
|
80
|
-
type: "boolean"
|
|
81
|
-
},
|
|
82
|
-
sessionKey: { type: "string" }
|
|
83
|
-
},
|
|
101
|
+
properties: createDelegateToolProperties(backgroundSubagents),
|
|
84
102
|
required: ["prompt"],
|
|
85
103
|
type: "object"
|
|
86
104
|
})
|
|
87
105
|
});
|
|
88
106
|
}
|
|
107
|
+
function createDelegateToolProperties(backgroundSubagents) {
|
|
108
|
+
const baseProperties = {
|
|
109
|
+
description: { type: "string" },
|
|
110
|
+
prompt: delegatePromptSchema,
|
|
111
|
+
sessionKey: { type: "string" }
|
|
112
|
+
};
|
|
113
|
+
if (!backgroundSubagents) return baseProperties;
|
|
114
|
+
return {
|
|
115
|
+
...baseProperties,
|
|
116
|
+
run_in_background: {
|
|
117
|
+
default: false,
|
|
118
|
+
type: "boolean"
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
89
122
|
//#endregion
|
|
90
123
|
export { createSubagentTools };
|
|
91
124
|
|
package/dist/subagents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagents.js","names":[],"sources":["../src/subagents.ts"],"sourcesContent":["import { jsonSchema, type ToolSet, tool } from \"ai\";\nimport { normalizeAgentInput } from \"./session/input-normalization\";\nimport { createBackgroundCancelTool } from \"./subagent-job-cancel\";\nimport { createBackgroundOutputTool } from \"./subagent-job-output\";\nimport { startBackgroundJob } from \"./subagent-jobs\";\nimport { delegatePromptSchema } from \"./subagent-prompt-schema\";\nimport {
|
|
1
|
+
{"version":3,"file":"subagents.js","names":[],"sources":["../src/subagents.ts"],"sourcesContent":["import { jsonSchema, type ToolSet, tool } from \"ai\";\nimport type { ExecutionHost } from \"./execution/types\";\nimport { normalizeAgentInput } from \"./session/input-normalization\";\nimport {\n type BlockingSubagentRunCache,\n blockingSubagentDedupeKey,\n runBlockingChild,\n} from \"./subagent-child-run\";\nimport { createBackgroundCancelTool } from \"./subagent-job-cancel\";\nimport { createBackgroundOutputTool } from \"./subagent-job-output\";\nimport { startBackgroundJob } from \"./subagent-jobs\";\nimport { delegatePromptSchema } from \"./subagent-prompt-schema\";\nimport { scopedChildSessionKey } from \"./subagent-run\";\nimport type {\n CreateSubagentToolsOptions,\n DelegateInput,\n RuntimeInputSink,\n Subagent,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nexport function createSubagentTools({\n backgroundSubagents,\n executionHost,\n parentAgentNamespace,\n parentSession,\n parentSessionKey,\n registerChildSession,\n subagents,\n}: CreateSubagentToolsOptions): ToolSet {\n if (subagents.length === 0) {\n return {};\n }\n\n const jobs = new Map<string, SubagentJob>();\n const groups = new Map<string, SubagentJobGroup>();\n const blockingRuns: BlockingSubagentRunCache = new Map();\n const backgroundToolScope = {\n childSessionKeyPrefix: `parent:${parentAgentNamespace}:${parentSessionKey}:subagent:`,\n };\n const generatedTools: Record<string, unknown> = backgroundSubagents\n ? {\n background_cancel: createBackgroundCancelTool(\n jobs,\n executionHost,\n backgroundToolScope\n ),\n background_output: createBackgroundOutputTool(\n jobs,\n executionHost,\n backgroundToolScope\n ),\n }\n : {};\n\n for (const subagent of subagents) {\n const name = subagent.name;\n if (!name) {\n continue;\n }\n\n generatedTools[`delegate_to_${name.replaceAll(\"-\", \"_\")}`] =\n createDelegateTool({\n jobs,\n groups,\n backgroundSubagents,\n blockingRuns,\n executionHost,\n parentAgentNamespace,\n parentSession,\n parentSessionKey,\n registerChildSession,\n subagent,\n });\n }\n\n return generatedTools as ToolSet;\n}\n\nfunction createDelegateTool({\n jobs,\n groups,\n backgroundSubagents,\n blockingRuns,\n executionHost,\n parentAgentNamespace,\n parentSession,\n parentSessionKey,\n registerChildSession,\n subagent,\n}: {\n readonly jobs: Map<string, SubagentJob>;\n readonly groups: Map<string, SubagentJobGroup>;\n readonly backgroundSubagents: boolean;\n readonly blockingRuns: BlockingSubagentRunCache;\n readonly executionHost?: ExecutionHost;\n readonly parentAgentNamespace: string;\n readonly parentSession: RuntimeInputSink;\n readonly parentSessionKey: string;\n readonly registerChildSession: CreateSubagentToolsOptions[\"registerChildSession\"];\n readonly subagent: Subagent;\n}) {\n return tool<DelegateInput, unknown, Record<string, unknown>>({\n description: `Delegate work to ${subagent.name}: ${subagent.description}`,\n execute: async (input: DelegateInput, { abortSignal, toolCallId }) => {\n const prompt = normalizeAgentInput(input.prompt);\n const sessionKey = scopedChildSessionKey({\n parentAgentNamespace,\n parentSessionKey,\n sessionKey: input.sessionKey,\n subagent: subagent.name ?? \"subagent\",\n });\n if (input.run_in_background === true) {\n if (!backgroundSubagents) {\n throw new Error(\n \"Background subagent delegation is not available for this host.\"\n );\n }\n\n return await startBackgroundJob({\n abortSignal: abortSignal ?? new AbortController().signal,\n description: input.description,\n executionHost,\n groupId: parentSession.currentBackgroundGroupId?.(),\n groups,\n jobs,\n delegateToolCallId: toolCallId,\n parentSession,\n parentRunId: parentSession.currentRunId?.() ?? parentAgentNamespace,\n parentSessionKey,\n ownerNamespace: parentAgentNamespace,\n prompt,\n registerCleanup: (cleanup) =>\n registerChildSession(parentSessionKey, cleanup),\n sessionKey,\n subagent,\n });\n }\n\n registerChildSession(parentSessionKey, () =>\n subagent.session(sessionKey).delete()\n );\n await parentSession.emitObserverEvent({\n description: input.description,\n delegateToolCallId: toolCallId,\n run_in_background: false,\n subagent: subagent.name ?? \"subagent\",\n type: \"subagent-job-start\",\n });\n const dedupeKey = blockingSubagentDedupeKey(\n parentAgentNamespace,\n toolCallId\n );\n const existing = blockingRuns.get(dedupeKey);\n const result =\n existing ??\n runBlockingChild({\n abortSignal,\n dedupeKey,\n executionHost,\n parentRunId: parentSession.currentRunId?.() ?? parentAgentNamespace,\n prompt,\n sessionKey,\n subagent,\n });\n blockingRuns.set(dedupeKey, result);\n const awaitedResult = await result;\n await parentSession.emitObserverEvent({\n error: awaitedResult.error,\n eventCount: awaitedResult.eventCount,\n delegateToolCallId: toolCallId,\n status: awaitedResult.result,\n subagent: subagent.name ?? \"subagent\",\n type: \"subagent-job-end\",\n });\n return awaitedResult;\n },\n inputSchema: jsonSchema<DelegateInput>({\n additionalProperties: false,\n properties: createDelegateToolProperties(backgroundSubagents),\n required: [\"prompt\"],\n type: \"object\",\n }),\n });\n}\n\nfunction createDelegateToolProperties(backgroundSubagents: boolean) {\n const baseProperties = {\n description: { type: \"string\" },\n prompt: delegatePromptSchema,\n sessionKey: { type: \"string\" },\n };\n\n if (!backgroundSubagents) {\n return baseProperties;\n }\n\n return {\n ...baseProperties,\n run_in_background: { default: false, type: \"boolean\" },\n };\n}\n"],"mappings":";;;;;;;;;AAsBA,SAAgB,oBAAoB,EAClC,qBACA,eACA,sBACA,eACA,kBACA,sBACA,aACsC;CACtC,IAAI,UAAU,WAAW,GACvB,OAAO,CAAC;CAGV,MAAM,uBAAO,IAAI,IAAyB;CAC1C,MAAM,yBAAS,IAAI,IAA8B;CACjD,MAAM,+BAAyC,IAAI,IAAI;CACvD,MAAM,sBAAsB,EAC1B,uBAAuB,UAAU,qBAAqB,GAAG,iBAAiB,YAC5E;CACA,MAAM,iBAA0C,sBAC5C;EACE,mBAAmB,2BACjB,MACA,eACA,mBACF;EACA,mBAAmB,2BACjB,MACA,eACA,mBACF;CACF,IACA,CAAC;CAEL,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,OAAO,SAAS;EACtB,IAAI,CAAC,MACH;EAGF,eAAe,eAAe,KAAK,WAAW,KAAK,GAAG,OACpD,mBAAmB;GACjB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;CACL;CAEA,OAAO;AACT;AAEA,SAAS,mBAAmB,EAC1B,MACA,QACA,qBACA,cACA,eACA,sBACA,eACA,kBACA,sBACA,YAYC;CACD,OAAO,KAAsD;EAC3D,aAAa,oBAAoB,SAAS,KAAK,IAAI,SAAS;EAC5D,SAAS,OAAO,OAAsB,EAAE,aAAa,iBAAiB;GACpE,MAAM,SAAS,oBAAoB,MAAM,MAAM;GAC/C,MAAM,aAAa,sBAAsB;IACvC;IACA;IACA,YAAY,MAAM;IAClB,UAAU,SAAS,QAAQ;GAC7B,CAAC;GACD,IAAI,MAAM,sBAAsB,MAAM;IACpC,IAAI,CAAC,qBACH,MAAM,IAAI,MACR,gEACF;IAGF,OAAO,MAAM,mBAAmB;KAC9B,aAAa,eAAe,IAAI,gBAAgB,EAAE;KAClD,aAAa,MAAM;KACnB;KACA,SAAS,cAAc,2BAA2B;KAClD;KACA;KACA,oBAAoB;KACpB;KACA,aAAa,cAAc,eAAe,KAAK;KAC/C;KACA,gBAAgB;KAChB;KACA,kBAAkB,YAChB,qBAAqB,kBAAkB,OAAO;KAChD;KACA;IACF,CAAC;GACH;GAEA,qBAAqB,wBACnB,SAAS,QAAQ,UAAU,EAAE,OAAO,CACtC;GACA,MAAM,cAAc,kBAAkB;IACpC,aAAa,MAAM;IACnB,oBAAoB;IACpB,mBAAmB;IACnB,UAAU,SAAS,QAAQ;IAC3B,MAAM;GACR,CAAC;GACD,MAAM,YAAY,0BAChB,sBACA,UACF;GAEA,MAAM,SADW,aAAa,IAAI,SAEzB,KACP,iBAAiB;IACf;IACA;IACA;IACA,aAAa,cAAc,eAAe,KAAK;IAC/C;IACA;IACA;GACF,CAAC;GACH,aAAa,IAAI,WAAW,MAAM;GAClC,MAAM,gBAAgB,MAAM;GAC5B,MAAM,cAAc,kBAAkB;IACpC,OAAO,cAAc;IACrB,YAAY,cAAc;IAC1B,oBAAoB;IACpB,QAAQ,cAAc;IACtB,UAAU,SAAS,QAAQ;IAC3B,MAAM;GACR,CAAC;GACD,OAAO;EACT;EACA,aAAa,WAA0B;GACrC,sBAAsB;GACtB,YAAY,6BAA6B,mBAAmB;GAC5D,UAAU,CAAC,QAAQ;GACnB,MAAM;EACR,CAAC;CACH,CAAC;AACH;AAEA,SAAS,6BAA6B,qBAA8B;CAClE,MAAM,iBAAiB;EACrB,aAAa,EAAE,MAAM,SAAS;EAC9B,QAAQ;EACR,YAAY,EAAE,MAAM,SAAS;CAC/B;CAEA,IAAI,CAAC,qBACH,OAAO;CAGT,OAAO;EACL,GAAG;EACH,mBAAmB;GAAE,SAAS;GAAO,MAAM;EAAU;CACvD;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minpeter/pss-runtime",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.2",
|
|
4
4
|
"description": "Generic agent runtime for sessions, model loops, and synchronized run events.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,6 +20,16 @@
|
|
|
20
20
|
"@minpeter/pss-source": "./src/session/store/file.ts",
|
|
21
21
|
"types": "./dist/session/store/file.d.ts",
|
|
22
22
|
"import": "./dist/session/store/file.js"
|
|
23
|
+
},
|
|
24
|
+
"./execution": {
|
|
25
|
+
"@minpeter/pss-source": "./src/execution/index.ts",
|
|
26
|
+
"types": "./dist/execution/index.d.ts",
|
|
27
|
+
"import": "./dist/execution/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./execution/memory": {
|
|
30
|
+
"@minpeter/pss-source": "./src/execution/memory.ts",
|
|
31
|
+
"types": "./dist/execution/memory.d.ts",
|
|
32
|
+
"import": "./dist/execution/memory.js"
|
|
23
33
|
}
|
|
24
34
|
},
|
|
25
35
|
"files": [
|
package/dist/hooks.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { RuntimeLlmContext } from "./llm.js";
|
|
2
|
-
import { UserInput } from "./session/input.js";
|
|
3
|
-
|
|
4
|
-
//#region src/hooks.d.ts
|
|
5
|
-
type AgentTurnResult = "aborted" | "completed";
|
|
6
|
-
type AgentStepResult = "completed" | "continue";
|
|
7
|
-
type MaybePromise<T> = PromiseLike<T> | T;
|
|
8
|
-
interface AgentBeforeTurnContext {
|
|
9
|
-
readonly history: RuntimeLlmContext["history"];
|
|
10
|
-
readonly input: UserInput;
|
|
11
|
-
readonly signal: AbortSignal;
|
|
12
|
-
}
|
|
13
|
-
interface AgentAfterTurnContext extends AgentBeforeTurnContext {
|
|
14
|
-
readonly result: AgentTurnResult;
|
|
15
|
-
}
|
|
16
|
-
interface AgentBeforeStepContext {
|
|
17
|
-
readonly history: RuntimeLlmContext["history"];
|
|
18
|
-
readonly signal: AbortSignal;
|
|
19
|
-
readonly stepIndex: number;
|
|
20
|
-
}
|
|
21
|
-
interface AgentAfterStepContext extends AgentBeforeStepContext {
|
|
22
|
-
readonly result: AgentStepResult;
|
|
23
|
-
}
|
|
24
|
-
interface AgentHooks {
|
|
25
|
-
afterStep?(context: AgentAfterStepContext): MaybePromise<void>;
|
|
26
|
-
afterTurn?(context: AgentAfterTurnContext): MaybePromise<void>;
|
|
27
|
-
beforeStep?(context: AgentBeforeStepContext): MaybePromise<void>;
|
|
28
|
-
beforeTurn?(context: AgentBeforeTurnContext): MaybePromise<void>;
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
export { AgentAfterStepContext, AgentAfterTurnContext, AgentBeforeStepContext, AgentBeforeTurnContext, AgentHooks, AgentStepResult, AgentTurnResult };
|
|
32
|
-
//# sourceMappingURL=hooks.d.ts.map
|
|
File without changes
|