@cuylabs/agent-core 0.9.0 → 0.10.0
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 +33 -17
- package/dist/chunk-2O4MCSQS.js +780 -0
- package/dist/chunk-2TTOLHBT.js +198 -0
- package/dist/chunk-5FMSGQVX.js +281 -0
- package/dist/chunk-5NVVNXPQ.js +288 -0
- package/dist/{chunk-EKR6PKXU.js → chunk-6HZBHFOL.js} +3 -3
- package/dist/chunk-CJI7PVS2.js +58 -0
- package/dist/{chunk-WKHDSSXG.js → chunk-CMYN2RCB.js} +146 -46
- package/dist/chunk-FII65CN7.js +117 -0
- package/dist/{chunk-UHCJEM2E.js → chunk-ICZ66572.js} +13 -6
- package/dist/chunk-KYLPMBHD.js +316 -0
- package/dist/chunk-MXAP4UG6.js +2956 -0
- package/dist/{chunk-4QFNWPIF.js → chunk-N3VX7FEE.js} +35 -2
- package/dist/{chunk-MAZ5DY5B.js → chunk-NDZWXCBZ.js} +213 -78
- package/dist/{chunk-MHKK374K.js → chunk-Q742PSH3.js} +11 -27
- package/dist/{chunk-WGZAPU6N.js → chunk-QAL3OMI3.js} +15 -1
- package/dist/{chunk-UDCZ673N.js → chunk-RN6WZEUF.js} +27 -23
- package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
- package/dist/chunk-SPBFQXOT.js +0 -0
- package/dist/chunk-SSFBF3US.js +602 -0
- package/dist/chunk-SZ2XBPTW.js +8 -0
- package/dist/chunk-T4UIX5D7.js +115 -0
- package/dist/{chunk-IYWQOJMQ.js → chunk-TIHPYVAJ.js} +34 -34
- package/dist/{chunk-RKEW5WXI.js → chunk-TOTDGK3P.js} +1 -1
- package/dist/chunk-V4RFNEET.js +563 -0
- package/dist/chunk-VOUEJSW6.js +0 -0
- package/dist/{chunk-J4QDGZIA.js → chunk-WBPOZ7CL.js} +659 -275
- package/dist/chunk-X4VN4GIJ.js +185 -0
- package/dist/dispatch/index.d.ts +93 -0
- package/dist/dispatch/index.js +37 -0
- package/dist/events/index.d.ts +93 -0
- package/dist/events/index.js +6 -0
- package/dist/{runtime → execution}/index.d.ts +120 -35
- package/dist/{runtime → execution}/index.js +17 -11
- package/dist/index.d.ts +489 -115
- package/dist/index.js +1665 -462
- package/dist/inference/errors/index.js +1 -1
- package/dist/inference/index.d.ts +13 -21
- package/dist/inference/index.js +15 -12
- package/dist/instance-BqV2D5pc.d.ts +5723 -0
- package/dist/logger/index.d.ts +50 -0
- package/dist/logger/index.js +11 -0
- package/dist/mcp/index.d.ts +5 -9
- package/dist/mcp/index.js +2 -3
- package/dist/middleware/index.d.ts +10 -150
- package/dist/middleware/index.js +10 -2
- package/dist/model-messages-B4nK9D1-.d.ts +13 -0
- package/dist/models/index.d.ts +5 -2
- package/dist/models/index.js +2 -1
- package/dist/models/reasoning/index.js +2 -1
- package/dist/plugin/index.d.ts +55 -11
- package/dist/plugin/index.js +1 -1
- package/dist/profiles/index.d.ts +55 -0
- package/dist/{presets → profiles}/index.js +10 -10
- package/dist/prompt/index.d.ts +8 -13
- package/dist/safety/index.d.ts +109 -14
- package/dist/safety/index.js +59 -3
- package/dist/sandbox/index.d.ts +81 -0
- package/dist/sandbox/index.js +1 -0
- package/dist/skill/index.d.ts +10 -8
- package/dist/skill/index.js +2 -2
- package/dist/storage/index.d.ts +12 -4
- package/dist/storage/index.js +1 -1
- package/dist/subagents/index.d.ts +177 -0
- package/dist/subagents/index.js +78 -0
- package/dist/team/index.d.ts +544 -0
- package/dist/team/index.js +41 -0
- package/dist/tool/host/index.d.ts +41 -0
- package/dist/tool/host/index.js +10 -0
- package/dist/tool/index.d.ts +111 -21
- package/dist/tool/index.js +20 -13
- package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
- package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
- package/dist/types-RSCv7nQ4.d.ts +59 -0
- package/package.json +46 -47
- package/dist/builder-BgZ_j4Vs.d.ts +0 -35
- package/dist/chunk-5ARZJWD2.js +0 -259
- package/dist/chunk-DXFBQMXP.js +0 -53
- package/dist/chunk-H3FUYU52.js +0 -81
- package/dist/chunk-JLXG2SH7.js +0 -905
- package/dist/chunk-N7P4PN3O.js +0 -84
- package/dist/chunk-OFDKHNCX.js +0 -727
- package/dist/chunk-SDSBEQXG.js +0 -157
- package/dist/chunk-VEKUXUVF.js +0 -41
- package/dist/chunk-VNQBHPCT.js +0 -398
- package/dist/chunk-WWYYNWEW.js +0 -259
- package/dist/context/index.d.ts +0 -259
- package/dist/context/index.js +0 -26
- package/dist/events-CE72w8W4.d.ts +0 -149
- package/dist/host/index.d.ts +0 -45
- package/dist/host/index.js +0 -8
- package/dist/index-DQuTZ8xL.d.ts +0 -1335
- package/dist/messages-BYWGn8TY.d.ts +0 -110
- package/dist/presets/index.d.ts +0 -53
- package/dist/registry-DwYqsQkX.d.ts +0 -164
- package/dist/runner-CI-XeR16.d.ts +0 -91
- package/dist/scope/index.d.ts +0 -10
- package/dist/scope/index.js +0 -14
- package/dist/session-manager-KbYt2WUh.d.ts +0 -282
- package/dist/signal/index.d.ts +0 -28
- package/dist/signal/index.js +0 -6
- package/dist/sub-agent/index.d.ts +0 -24
- package/dist/sub-agent/index.js +0 -32
- package/dist/tool-CZWN3KbO.d.ts +0 -141
- package/dist/tool-DkhSCV2Y.d.ts +0 -145
- package/dist/tracker-DClqYqTj.d.ts +0 -96
- package/dist/tracking/index.d.ts +0 -111
- package/dist/tracking/index.js +0 -20
- package/dist/types-BfNpU8NS.d.ts +0 -270
- package/dist/types-BlOKk-Bb.d.ts +0 -330
- package/dist/types-BlZwmnuW.d.ts +0 -50
- package/dist/types-CQL-SvTn.d.ts +0 -29
- package/dist/types-CWm-7rvB.d.ts +0 -55
- package/dist/types-DTSkxakL.d.ts +0 -651
- package/dist/types-DmDwi2zI.d.ts +0 -339
- package/dist/types-YuWV4ag7.d.ts +0 -72
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Inference
|
|
6
|
-
} from "./chunk-WKHDSSXG.js";
|
|
7
|
-
import {
|
|
8
|
-
executeAgentToolCall
|
|
9
|
-
} from "./chunk-H3FUYU52.js";
|
|
10
|
-
import {
|
|
11
|
-
LLMError
|
|
12
|
-
} from "./chunk-4QFNWPIF.js";
|
|
2
|
+
Inference,
|
|
3
|
+
buildModelCallContext
|
|
4
|
+
} from "./chunk-CMYN2RCB.js";
|
|
13
5
|
import {
|
|
6
|
+
PRUNE_PROTECTED_TOOLS,
|
|
7
|
+
accumulateUsage,
|
|
14
8
|
currentScope,
|
|
9
|
+
executeAgentToolCall,
|
|
15
10
|
snapshotScope,
|
|
16
11
|
streamWithinScope,
|
|
17
12
|
withinScope
|
|
18
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5NVVNXPQ.js";
|
|
14
|
+
import {
|
|
15
|
+
LLMError
|
|
16
|
+
} from "./chunk-N3VX7FEE.js";
|
|
19
17
|
import {
|
|
20
18
|
extractModelId,
|
|
21
19
|
extractProvider
|
|
22
20
|
} from "./chunk-I6PKJ7XQ.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveCapability
|
|
23
|
+
} from "./chunk-FII65CN7.js";
|
|
24
|
+
import {
|
|
25
|
+
silentLogger
|
|
26
|
+
} from "./chunk-T4UIX5D7.js";
|
|
23
27
|
|
|
24
|
-
// src/
|
|
28
|
+
// src/execution/task/observer.ts
|
|
25
29
|
function defaultAgentTaskCheckpointStrategy(input) {
|
|
26
30
|
switch (input.event.type) {
|
|
27
31
|
case "step-finish":
|
|
@@ -39,18 +43,20 @@ function defaultAgentTaskCheckpointStrategy(input) {
|
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
// src/
|
|
46
|
+
// src/execution/task/runner.ts
|
|
43
47
|
import { randomUUID } from "crypto";
|
|
44
48
|
|
|
45
|
-
// src/
|
|
49
|
+
// src/execution/clone-usage.ts
|
|
50
|
+
function cloneUsage(usage) {
|
|
51
|
+
return { ...usage };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/execution/turn-state.ts
|
|
46
55
|
var EMPTY_USAGE = {
|
|
47
56
|
inputTokens: 0,
|
|
48
57
|
outputTokens: 0,
|
|
49
58
|
totalTokens: 0
|
|
50
59
|
};
|
|
51
|
-
function cloneUsage(usage) {
|
|
52
|
-
return { ...usage };
|
|
53
|
-
}
|
|
54
60
|
function normalizeUsage(usage) {
|
|
55
61
|
if (!usage) {
|
|
56
62
|
return cloneUsage(EMPTY_USAGE);
|
|
@@ -65,13 +71,14 @@ function removeActiveToolCall(toolCalls, toolCallId) {
|
|
|
65
71
|
return toolCalls.filter((toolCall) => toolCall.toolCallId !== toolCallId);
|
|
66
72
|
}
|
|
67
73
|
function createAgentTurnState(options) {
|
|
74
|
+
const restore = options.restoreFrom;
|
|
68
75
|
return {
|
|
69
76
|
sessionId: options.sessionId,
|
|
70
77
|
phase: "initializing",
|
|
71
|
-
step: 0,
|
|
72
|
-
response: "",
|
|
73
|
-
usage: cloneUsage(EMPTY_USAGE),
|
|
74
|
-
eventCount: 0,
|
|
78
|
+
step: restore?.step ?? 0,
|
|
79
|
+
response: restore?.response ?? "",
|
|
80
|
+
usage: restore?.usage ? cloneUsage(restore.usage) : cloneUsage(EMPTY_USAGE),
|
|
81
|
+
eventCount: restore?.eventCount ?? 0,
|
|
75
82
|
activeToolCalls: [],
|
|
76
83
|
resolvedToolCalls: [],
|
|
77
84
|
startedAt: options.startedAt,
|
|
@@ -84,7 +91,8 @@ function advanceAgentTurnState(state, event, updatedAt, options = {}) {
|
|
|
84
91
|
usage: cloneUsage(state.usage),
|
|
85
92
|
activeToolCalls: state.activeToolCalls.map((toolCall) => ({ ...toolCall })),
|
|
86
93
|
resolvedToolCalls: state.resolvedToolCalls.map((toolCall) => ({
|
|
87
|
-
...toolCall
|
|
94
|
+
...toolCall,
|
|
95
|
+
...toolCall.metadata ? { metadata: structuredClone(toolCall.metadata) } : {}
|
|
88
96
|
})),
|
|
89
97
|
eventCount: state.eventCount + 1,
|
|
90
98
|
lastEvent: event,
|
|
@@ -129,6 +137,7 @@ function advanceAgentTurnState(state, event, updatedAt, options = {}) {
|
|
|
129
137
|
toolName: event.toolName,
|
|
130
138
|
outcome: "result",
|
|
131
139
|
value: event.result,
|
|
140
|
+
...event.metadata ? { metadata: structuredClone(event.metadata) } : {},
|
|
132
141
|
resolvedAt: updatedAt,
|
|
133
142
|
...options.toolReplayPolicy ? { replayPolicy: options.toolReplayPolicy } : {}
|
|
134
143
|
}
|
|
@@ -202,7 +211,8 @@ function failAgentTurnState(state, error, updatedAt) {
|
|
|
202
211
|
usage: cloneUsage(state.usage),
|
|
203
212
|
activeToolCalls: state.activeToolCalls.map((toolCall) => ({ ...toolCall })),
|
|
204
213
|
resolvedToolCalls: state.resolvedToolCalls.map((toolCall) => ({
|
|
205
|
-
...toolCall
|
|
214
|
+
...toolCall,
|
|
215
|
+
...toolCall.metadata ? { metadata: structuredClone(toolCall.metadata) } : {}
|
|
206
216
|
})),
|
|
207
217
|
phase: "failed",
|
|
208
218
|
error: error.message,
|
|
@@ -210,7 +220,7 @@ function failAgentTurnState(state, error, updatedAt) {
|
|
|
210
220
|
};
|
|
211
221
|
}
|
|
212
222
|
|
|
213
|
-
// src/
|
|
223
|
+
// src/execution/task/runner.ts
|
|
214
224
|
function normalizeNonEmpty(value, label) {
|
|
215
225
|
const normalized = value.trim();
|
|
216
226
|
if (!normalized) {
|
|
@@ -234,15 +244,14 @@ function buildRuntimeSessionId(prefix, key) {
|
|
|
234
244
|
function nowIso() {
|
|
235
245
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
236
246
|
}
|
|
237
|
-
async function notifyObservers(observers, invoke) {
|
|
247
|
+
async function notifyObservers(observers, invoke, logger) {
|
|
238
248
|
for (const observer of observers) {
|
|
239
249
|
try {
|
|
240
250
|
await invoke(observer);
|
|
241
251
|
} catch (error) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
252
|
+
logger.warn("observer error", {
|
|
253
|
+
error: error instanceof Error ? error.message : String(error)
|
|
254
|
+
});
|
|
246
255
|
}
|
|
247
256
|
}
|
|
248
257
|
}
|
|
@@ -250,11 +259,13 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
250
259
|
const prefix = options.sessionPrefix ?? "runtime";
|
|
251
260
|
const baseObservers = options.observers ?? [];
|
|
252
261
|
const checkpointStrategy = options.checkpointStrategy ?? defaultAgentTaskCheckpointStrategy;
|
|
262
|
+
const log = options.logger?.child("task-runner") ?? silentLogger;
|
|
253
263
|
return async (payload, context = {}) => {
|
|
254
264
|
const message = normalizeNonEmpty(payload.message, "payload.message");
|
|
255
265
|
const resolvedSessionId = payload.sessionId?.trim() || options.resolveSessionId?.(payload, context)?.trim() || buildRuntimeSessionId(prefix, context.fallbackSessionKey);
|
|
256
266
|
const sessionId = normalizeNonEmpty(resolvedSessionId, "sessionId");
|
|
257
267
|
const startedAt = nowIso();
|
|
268
|
+
const executionId = context.executionId?.trim() || `${sessionId}:${startedAt}`;
|
|
258
269
|
return withinScope(
|
|
259
270
|
{
|
|
260
271
|
kind: "task",
|
|
@@ -270,13 +281,20 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
270
281
|
payload,
|
|
271
282
|
context,
|
|
272
283
|
sessionId,
|
|
273
|
-
|
|
284
|
+
executionId,
|
|
285
|
+
startedAt: context.restoreFrom?.startedAt ?? startedAt,
|
|
274
286
|
scope: snapshotScope()
|
|
275
287
|
};
|
|
276
|
-
const toolCalls = [];
|
|
288
|
+
const toolCalls = context.restoreFrom?.toolCalls.map((tc) => ({ ...tc })) ?? [];
|
|
277
289
|
let turnState = createAgentTurnState({
|
|
278
290
|
sessionId,
|
|
279
|
-
startedAt
|
|
291
|
+
startedAt: context.restoreFrom?.startedAt ?? startedAt,
|
|
292
|
+
restoreFrom: context.restoreFrom ? {
|
|
293
|
+
response: context.restoreFrom.response,
|
|
294
|
+
usage: { ...context.restoreFrom.usage },
|
|
295
|
+
step: context.restoreFrom.step,
|
|
296
|
+
eventCount: context.restoreFrom.eventCount
|
|
297
|
+
} : void 0
|
|
280
298
|
});
|
|
281
299
|
const createSnapshot = () => ({
|
|
282
300
|
sessionId,
|
|
@@ -305,13 +323,13 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
305
323
|
};
|
|
306
324
|
await notifyObservers(baseObservers, async (observer) => {
|
|
307
325
|
await observer.onCheckpoint?.(checkpoint);
|
|
308
|
-
});
|
|
326
|
+
}, log);
|
|
309
327
|
};
|
|
310
328
|
await notifyObservers(baseObservers, async (observer) => {
|
|
311
329
|
await observer.onTaskStart?.(run, createSnapshot());
|
|
312
|
-
});
|
|
330
|
+
}, log);
|
|
313
331
|
await emitCheckpoint("task-start");
|
|
314
|
-
const activateCtx = baseObservers.find((o) => o.activateContext)?.activateContext?.bind(void 0, sessionId);
|
|
332
|
+
const activateCtx = baseObservers.find((o) => o.activateContext)?.activateContext?.bind(void 0, sessionId, executionId);
|
|
315
333
|
try {
|
|
316
334
|
const processChatStream = async () => {
|
|
317
335
|
for await (const event of agent.chat(sessionId, message, {
|
|
@@ -325,7 +343,7 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
325
343
|
const snapshot = createSnapshot();
|
|
326
344
|
await notifyObservers(baseObservers, async (observer) => {
|
|
327
345
|
await observer.onTaskEvent?.(run, event, snapshot);
|
|
328
|
-
});
|
|
346
|
+
}, log);
|
|
329
347
|
const checkpointReason = checkpointStrategy({
|
|
330
348
|
run,
|
|
331
349
|
event,
|
|
@@ -352,14 +370,14 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
352
370
|
};
|
|
353
371
|
await notifyObservers(baseObservers, async (observer) => {
|
|
354
372
|
await observer.onTaskComplete?.(run, result, createSnapshot());
|
|
355
|
-
});
|
|
373
|
+
}, log);
|
|
356
374
|
return result;
|
|
357
375
|
} catch (error) {
|
|
358
376
|
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
359
377
|
turnState = failAgentTurnState(turnState, normalizedError, nowIso());
|
|
360
378
|
await notifyObservers(baseObservers, async (observer) => {
|
|
361
379
|
await observer.onTaskError?.(run, normalizedError, createSnapshot());
|
|
362
|
-
});
|
|
380
|
+
}, log);
|
|
363
381
|
await emitCheckpoint("task-error");
|
|
364
382
|
throw normalizedError;
|
|
365
383
|
}
|
|
@@ -368,50 +386,7 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
368
386
|
};
|
|
369
387
|
}
|
|
370
388
|
|
|
371
|
-
// src/
|
|
372
|
-
function convertAgentMessagesToModelMessages(messages) {
|
|
373
|
-
return messages.flatMap((message) => {
|
|
374
|
-
switch (message.role) {
|
|
375
|
-
case "user":
|
|
376
|
-
return [{ role: "user", content: message.content }];
|
|
377
|
-
case "assistant": {
|
|
378
|
-
if (message.toolCalls && message.toolCalls.length > 0) {
|
|
379
|
-
const toolCallParts = message.toolCalls.map(
|
|
380
|
-
(toolCall) => ({
|
|
381
|
-
type: "tool-call",
|
|
382
|
-
toolCallId: toolCall.toolCallId,
|
|
383
|
-
toolName: toolCall.toolName,
|
|
384
|
-
input: toolCall.args
|
|
385
|
-
})
|
|
386
|
-
);
|
|
387
|
-
return [{ role: "assistant", content: toolCallParts }];
|
|
388
|
-
}
|
|
389
|
-
return [{ role: "assistant", content: message.content }];
|
|
390
|
-
}
|
|
391
|
-
case "tool":
|
|
392
|
-
return [
|
|
393
|
-
{
|
|
394
|
-
role: "tool",
|
|
395
|
-
content: [
|
|
396
|
-
{
|
|
397
|
-
type: "tool-result",
|
|
398
|
-
toolCallId: message.toolCallId ?? "",
|
|
399
|
-
toolName: message.toolName ?? "",
|
|
400
|
-
output: {
|
|
401
|
-
type: "text",
|
|
402
|
-
value: typeof message.result === "string" ? message.result : JSON.stringify(message.result)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
]
|
|
406
|
-
}
|
|
407
|
-
];
|
|
408
|
-
case "system":
|
|
409
|
-
return [{ role: "system", content: message.content }];
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// src/runtime/turn-engine/commit-batch.ts
|
|
389
|
+
// src/execution/turn-engine/commit-batch.ts
|
|
415
390
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
416
391
|
function createAgentTurnBoundaryEvent(boundary, metadata = {}) {
|
|
417
392
|
return {
|
|
@@ -440,13 +415,14 @@ function createAgentTurnStepCommitBatch(step, snapshot, options = {}) {
|
|
|
440
415
|
createdAt
|
|
441
416
|
};
|
|
442
417
|
const toolMessages = snapshot.toolResults.map(
|
|
443
|
-
({ toolCallId, toolName, result }) => ({
|
|
418
|
+
({ toolCallId, toolName, result, metadata }) => ({
|
|
444
419
|
id: options.toolMessageIds?.[toolCallId] ?? randomUUID2(),
|
|
445
420
|
role: "tool",
|
|
446
421
|
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
447
422
|
toolCallId,
|
|
448
423
|
toolName,
|
|
449
424
|
result,
|
|
425
|
+
...metadata ? { metadata } : {},
|
|
450
426
|
createdAt
|
|
451
427
|
})
|
|
452
428
|
);
|
|
@@ -518,7 +494,7 @@ function createAgentTurnOutputCommit(options) {
|
|
|
518
494
|
};
|
|
519
495
|
}
|
|
520
496
|
|
|
521
|
-
// src/
|
|
497
|
+
// src/execution/turn-engine/engine.ts
|
|
522
498
|
var AgentTurnEngine = class {
|
|
523
499
|
turnState;
|
|
524
500
|
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
@@ -559,6 +535,7 @@ var AgentTurnEngine = class {
|
|
|
559
535
|
toolCallId,
|
|
560
536
|
toolName,
|
|
561
537
|
result: resultData.result,
|
|
538
|
+
...resultData.metadata ? { metadata: resultData.metadata } : {},
|
|
562
539
|
...replayPolicy ? { replayPolicy } : {}
|
|
563
540
|
};
|
|
564
541
|
}).filter((result) => result !== void 0)
|
|
@@ -581,6 +558,7 @@ var AgentTurnEngine = class {
|
|
|
581
558
|
this.pendingToolResults.set(event.toolCallId, {
|
|
582
559
|
toolName: event.toolName,
|
|
583
560
|
result: event.result,
|
|
561
|
+
...event.metadata ? { metadata: event.metadata } : {},
|
|
584
562
|
replayPolicy: toolReplayPolicy
|
|
585
563
|
});
|
|
586
564
|
break;
|
|
@@ -623,7 +601,251 @@ function createAgentTurnEngine(options) {
|
|
|
623
601
|
return new AgentTurnEngine(options);
|
|
624
602
|
}
|
|
625
603
|
|
|
626
|
-
// src/
|
|
604
|
+
// src/agent/context/estimation.ts
|
|
605
|
+
function estimateTokens(text) {
|
|
606
|
+
return Math.ceil(text.length / 4);
|
|
607
|
+
}
|
|
608
|
+
function estimateMessageTokens(message) {
|
|
609
|
+
if (typeof message.content === "string") {
|
|
610
|
+
return estimateTokens(message.content);
|
|
611
|
+
}
|
|
612
|
+
if (Array.isArray(message.content)) {
|
|
613
|
+
let total = 0;
|
|
614
|
+
for (const part of message.content) {
|
|
615
|
+
if (typeof part === "string") {
|
|
616
|
+
total += estimateTokens(part);
|
|
617
|
+
} else if ("text" in part && typeof part.text === "string") {
|
|
618
|
+
total += estimateTokens(part.text);
|
|
619
|
+
} else if ("type" in part && part.type === "image") {
|
|
620
|
+
total += 765;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return total;
|
|
624
|
+
}
|
|
625
|
+
return 0;
|
|
626
|
+
}
|
|
627
|
+
function estimateConversationTokens(messages) {
|
|
628
|
+
let total = 0;
|
|
629
|
+
for (const message of messages) {
|
|
630
|
+
total += estimateMessageTokens(message);
|
|
631
|
+
total += 4;
|
|
632
|
+
}
|
|
633
|
+
return total;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/agent/context/pruning.ts
|
|
637
|
+
var DEFAULT_CONTEXT_LIMITS = {
|
|
638
|
+
contextWindow: 128e3,
|
|
639
|
+
reserveTokens: 16e3,
|
|
640
|
+
// Reserve for output
|
|
641
|
+
protectedTokens: 4e4,
|
|
642
|
+
// Keep recent 40 k tokens
|
|
643
|
+
pruneMinimum: 2e4
|
|
644
|
+
// Don't prune until 20 k tokens
|
|
645
|
+
};
|
|
646
|
+
function getUsableTokenLimit(limits) {
|
|
647
|
+
return limits.contextWindow - limits.reserveTokens;
|
|
648
|
+
}
|
|
649
|
+
function isContextOverflowing(tokens, limits = DEFAULT_CONTEXT_LIMITS) {
|
|
650
|
+
return tokens > getUsableTokenLimit(limits);
|
|
651
|
+
}
|
|
652
|
+
function shouldPruneContext(tokens, limits = DEFAULT_CONTEXT_LIMITS) {
|
|
653
|
+
if (tokens < limits.pruneMinimum) return false;
|
|
654
|
+
return isContextOverflowing(tokens, limits);
|
|
655
|
+
}
|
|
656
|
+
function findCutPoint(messages, protectedTokens = DEFAULT_CONTEXT_LIMITS.protectedTokens) {
|
|
657
|
+
if (messages.length === 0) return 0;
|
|
658
|
+
let tokensFromEnd = 0;
|
|
659
|
+
let cutIndex = messages.length;
|
|
660
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
661
|
+
tokensFromEnd += estimateMessageTokens(messages[i]);
|
|
662
|
+
if (tokensFromEnd >= protectedTokens) {
|
|
663
|
+
cutIndex = i;
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (cutIndex <= 1) return 0;
|
|
668
|
+
const startIndex = cutIndex >= messages.length ? messages.length - 1 : cutIndex;
|
|
669
|
+
for (let i = startIndex; i >= 1; i--) {
|
|
670
|
+
const msg = messages[i];
|
|
671
|
+
const prevMsg = messages[i - 1];
|
|
672
|
+
if (!msg || !prevMsg) continue;
|
|
673
|
+
if (msg.role === "tool") continue;
|
|
674
|
+
if (prevMsg.role === "assistant" || prevMsg.role === "user") {
|
|
675
|
+
return i;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return 0;
|
|
679
|
+
}
|
|
680
|
+
function pruneToolResults(messages, protectedTokens = DEFAULT_CONTEXT_LIMITS.protectedTokens, options) {
|
|
681
|
+
const protectedToolSet = /* @__PURE__ */ new Set([
|
|
682
|
+
...PRUNE_PROTECTED_TOOLS,
|
|
683
|
+
...options?.protectedTools ?? []
|
|
684
|
+
]);
|
|
685
|
+
let tokensFromEnd = 0;
|
|
686
|
+
const tokenPositions = [];
|
|
687
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
688
|
+
tokensFromEnd += estimateMessageTokens(messages[i]);
|
|
689
|
+
tokenPositions[i] = tokensFromEnd;
|
|
690
|
+
}
|
|
691
|
+
return messages.map((msg, i) => {
|
|
692
|
+
if (tokenPositions[i] < protectedTokens) return msg;
|
|
693
|
+
if (!("role" in msg) || msg.role !== "tool") return msg;
|
|
694
|
+
const toolMsg = msg;
|
|
695
|
+
if ("compactedAt" in toolMsg && toolMsg.compactedAt) return msg;
|
|
696
|
+
if (toolMsg.toolName && protectedToolSet.has(toolMsg.toolName)) return msg;
|
|
697
|
+
const currentTokens = estimateTokens(toolMsg.content);
|
|
698
|
+
if (currentTokens < 500) return msg;
|
|
699
|
+
return {
|
|
700
|
+
...toolMsg,
|
|
701
|
+
content: `[Output pruned - was ${currentTokens} tokens]`,
|
|
702
|
+
compactedAt: Date.now()
|
|
703
|
+
};
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// src/agent/context/summarization.ts
|
|
708
|
+
import { generateText } from "ai";
|
|
709
|
+
var DEFAULT_SUMMARY_PROMPT = `You are summarizing a conversation to continue it with context.
|
|
710
|
+
|
|
711
|
+
Create a structured summary that captures:
|
|
712
|
+
1. **Goal**: What the user is trying to accomplish
|
|
713
|
+
2. **Progress**: What has been done so far
|
|
714
|
+
3. **Decisions**: Key decisions made during the conversation
|
|
715
|
+
4. **Current State**: Where we left off
|
|
716
|
+
5. **Next Steps**: What should happen next
|
|
717
|
+
|
|
718
|
+
Be concise but comprehensive. Include specific file paths, function names, and technical details that would be lost otherwise.
|
|
719
|
+
|
|
720
|
+
Format as a clear summary that could be given to another assistant to continue the work.`;
|
|
721
|
+
async function generateSummary(messages, options) {
|
|
722
|
+
const conversationText = messages.map((m) => {
|
|
723
|
+
const role = m.role.toUpperCase();
|
|
724
|
+
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
725
|
+
return `[${role}]: ${content}`;
|
|
726
|
+
}).join("\n\n");
|
|
727
|
+
const prompt = options.customPrompt || DEFAULT_SUMMARY_PROMPT;
|
|
728
|
+
const { text } = await generateText({
|
|
729
|
+
model: options.model,
|
|
730
|
+
maxOutputTokens: options.maxTokens ?? 2e3,
|
|
731
|
+
system: prompt,
|
|
732
|
+
prompt: `Summarize this conversation:
|
|
733
|
+
|
|
734
|
+
${conversationText}`
|
|
735
|
+
});
|
|
736
|
+
return text;
|
|
737
|
+
}
|
|
738
|
+
async function pruneContext(messages, options = {}) {
|
|
739
|
+
const limits = options.limits ?? DEFAULT_CONTEXT_LIMITS;
|
|
740
|
+
let currentMessages = [...messages];
|
|
741
|
+
let tokensRemoved = 0;
|
|
742
|
+
let removedCount = 0;
|
|
743
|
+
let summarized = false;
|
|
744
|
+
let summary;
|
|
745
|
+
const initialTokens = estimateConversationTokens(currentMessages);
|
|
746
|
+
if (!shouldPruneContext(initialTokens, limits)) {
|
|
747
|
+
return { messages: currentMessages, removedCount: 0, tokensRemoved: 0, summarized: false };
|
|
748
|
+
}
|
|
749
|
+
const prunedMessages = pruneToolResults(currentMessages, limits.protectedTokens);
|
|
750
|
+
const afterPruneTokens = estimateConversationTokens(prunedMessages);
|
|
751
|
+
tokensRemoved = initialTokens - afterPruneTokens;
|
|
752
|
+
currentMessages = prunedMessages;
|
|
753
|
+
if (!isContextOverflowing(afterPruneTokens, limits)) {
|
|
754
|
+
return { messages: currentMessages, removedCount: 0, tokensRemoved, summarized: false };
|
|
755
|
+
}
|
|
756
|
+
const cutIndex = findCutPoint(currentMessages, limits.protectedTokens);
|
|
757
|
+
if (cutIndex === 0) {
|
|
758
|
+
return { messages: currentMessages, removedCount: 0, tokensRemoved, summarized: false };
|
|
759
|
+
}
|
|
760
|
+
const toSummarize = currentMessages.slice(0, cutIndex);
|
|
761
|
+
const toKeep = currentMessages.slice(cutIndex);
|
|
762
|
+
removedCount = toSummarize.length;
|
|
763
|
+
tokensRemoved += estimateConversationTokens(toSummarize);
|
|
764
|
+
if (options.model) {
|
|
765
|
+
summary = await generateSummary(toSummarize, {
|
|
766
|
+
model: options.model,
|
|
767
|
+
customPrompt: options.summaryPrompt
|
|
768
|
+
});
|
|
769
|
+
summarized = true;
|
|
770
|
+
const summaryMessage = {
|
|
771
|
+
id: crypto.randomUUID(),
|
|
772
|
+
role: "system",
|
|
773
|
+
content: `## Previous Conversation Summary
|
|
774
|
+
|
|
775
|
+
${summary}`,
|
|
776
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
777
|
+
};
|
|
778
|
+
currentMessages = [summaryMessage, ...toKeep];
|
|
779
|
+
} else {
|
|
780
|
+
currentMessages = toKeep;
|
|
781
|
+
}
|
|
782
|
+
return { messages: currentMessages, removedCount, tokensRemoved, summarized, summary };
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/agent/context/manager.ts
|
|
786
|
+
var ContextManager = class {
|
|
787
|
+
limits;
|
|
788
|
+
model;
|
|
789
|
+
summaryPrompt;
|
|
790
|
+
constructor(options) {
|
|
791
|
+
this.limits = { ...DEFAULT_CONTEXT_LIMITS, ...options?.limits };
|
|
792
|
+
this.model = options?.model;
|
|
793
|
+
this.summaryPrompt = options?.summaryPrompt;
|
|
794
|
+
}
|
|
795
|
+
/** Get a copy of the current context limits. */
|
|
796
|
+
getLimits() {
|
|
797
|
+
return { ...this.limits };
|
|
798
|
+
}
|
|
799
|
+
/** Update context limits (e.g. when switching models). */
|
|
800
|
+
setLimits(limits) {
|
|
801
|
+
this.limits = { ...this.limits, ...limits };
|
|
802
|
+
}
|
|
803
|
+
/** Set the model used for summarisation. */
|
|
804
|
+
setModel(model) {
|
|
805
|
+
this.model = model;
|
|
806
|
+
}
|
|
807
|
+
/** Estimate total tokens for a message array. */
|
|
808
|
+
estimateTokens(messages) {
|
|
809
|
+
return estimateConversationTokens(messages);
|
|
810
|
+
}
|
|
811
|
+
/** Check whether the context is overflowing. */
|
|
812
|
+
isOverflowing(messages) {
|
|
813
|
+
const tokens = this.estimateTokens(messages);
|
|
814
|
+
return isContextOverflowing(tokens, this.limits);
|
|
815
|
+
}
|
|
816
|
+
/** Check whether pruning should be triggered. */
|
|
817
|
+
shouldPrune(messages) {
|
|
818
|
+
const tokens = this.estimateTokens(messages);
|
|
819
|
+
return shouldPruneContext(tokens, this.limits);
|
|
820
|
+
}
|
|
821
|
+
/** Prune context to fit within limits. */
|
|
822
|
+
async prune(messages) {
|
|
823
|
+
return pruneContext(messages, {
|
|
824
|
+
model: this.model,
|
|
825
|
+
limits: this.limits,
|
|
826
|
+
summaryPrompt: this.summaryPrompt
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Get a snapshot of token statistics.
|
|
831
|
+
*
|
|
832
|
+
* Useful for dashboards, logging, or deciding whether to prune.
|
|
833
|
+
*/
|
|
834
|
+
getStats(messages) {
|
|
835
|
+
const tokens = this.estimateTokens(messages);
|
|
836
|
+
const limit = getUsableTokenLimit(this.limits);
|
|
837
|
+
return {
|
|
838
|
+
tokens,
|
|
839
|
+
limit,
|
|
840
|
+
available: Math.max(0, limit - tokens),
|
|
841
|
+
utilizationPercent: Math.round(tokens / limit * 100),
|
|
842
|
+
isOverflowing: isContextOverflowing(tokens, this.limits),
|
|
843
|
+
shouldPrune: shouldPruneContext(tokens, this.limits)
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// src/execution/turn-runner/prepare.ts
|
|
627
849
|
function prepareModelStep(options) {
|
|
628
850
|
const modelMessages = Array.from(options.toModelMessages(options.messages));
|
|
629
851
|
return {
|
|
@@ -632,6 +854,7 @@ function prepareModelStep(options) {
|
|
|
632
854
|
modelMessages,
|
|
633
855
|
inferenceInput: {
|
|
634
856
|
sessionID: options.sessionId,
|
|
857
|
+
turnID: options.turnTracker?.getCurrentTurnId?.() ?? void 0,
|
|
635
858
|
step: options.step,
|
|
636
859
|
model: options.config.model,
|
|
637
860
|
system: options.systemPrompts,
|
|
@@ -641,6 +864,7 @@ function prepareModelStep(options) {
|
|
|
641
864
|
mcpTools: options.mcpTools,
|
|
642
865
|
cwd: options.config.cwd,
|
|
643
866
|
host: options.host,
|
|
867
|
+
humanInputController: options.humanInputController,
|
|
644
868
|
temperature: options.config.temperature,
|
|
645
869
|
topP: options.config.topP,
|
|
646
870
|
maxOutputTokens: options.config.maxOutputTokens,
|
|
@@ -658,12 +882,15 @@ function prepareModelStep(options) {
|
|
|
658
882
|
doomLoopThreshold: options.config.doomLoopThreshold,
|
|
659
883
|
enforceDoomLoop: options.config.enforceDoomLoop,
|
|
660
884
|
onDoomLoop: options.config.onDoomLoop,
|
|
661
|
-
contextTokenLimit: options.config.contextWindow ?
|
|
885
|
+
contextTokenLimit: options.config.contextWindow ? getUsableTokenLimit({
|
|
886
|
+
contextWindow: options.config.contextWindow,
|
|
887
|
+
reserveTokens: options.config.reserveTokens ?? DEFAULT_CONTEXT_LIMITS.reserveTokens
|
|
888
|
+
}) : void 0
|
|
662
889
|
}
|
|
663
890
|
};
|
|
664
891
|
}
|
|
665
892
|
|
|
666
|
-
// src/
|
|
893
|
+
// src/execution/step-processing/doom-loop.ts
|
|
667
894
|
var DEFAULT_DOOM_LOOP_THRESHOLD = 3;
|
|
668
895
|
var DoomLoopError = class extends Error {
|
|
669
896
|
toolName;
|
|
@@ -740,7 +967,7 @@ async function recordToolCallAndCheckDoomLoop(options) {
|
|
|
740
967
|
options.warn?.(`[StepProcessing] ${doomError.message}`);
|
|
741
968
|
}
|
|
742
969
|
|
|
743
|
-
// src/
|
|
970
|
+
// src/execution/step-processing/overflow.ts
|
|
744
971
|
var ContextOverflowError = class extends Error {
|
|
745
972
|
inputTokens;
|
|
746
973
|
limit;
|
|
@@ -767,12 +994,23 @@ async function handleContextOverflow(options) {
|
|
|
767
994
|
}
|
|
768
995
|
}
|
|
769
996
|
|
|
770
|
-
// src/
|
|
997
|
+
// src/execution/step-processing/process.ts
|
|
998
|
+
function normalizeToolResultChunk(output) {
|
|
999
|
+
if (output && typeof output === "object" && "__cuylabsAgentToolResult" in output && output.__cuylabsAgentToolResult === true) {
|
|
1000
|
+
const structured = output;
|
|
1001
|
+
return {
|
|
1002
|
+
result: structured.output,
|
|
1003
|
+
...structured.metadata ? { metadata: structured.metadata } : {}
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
return { result: output };
|
|
1007
|
+
}
|
|
771
1008
|
async function processStepStream(stream, options) {
|
|
772
1009
|
const { abort, onEvent } = options;
|
|
773
1010
|
const normalizeError = options.normalizeError ?? ((error2) => error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
774
1011
|
const doomLoopThreshold = options.doomLoopThreshold ?? DEFAULT_DOOM_LOOP_THRESHOLD;
|
|
775
1012
|
const maxSteps = options.maxSteps ?? 50;
|
|
1013
|
+
const log = options.logger;
|
|
776
1014
|
let stepCount = options.currentStep ?? 1;
|
|
777
1015
|
let sawStartStep = false;
|
|
778
1016
|
let text = "";
|
|
@@ -787,10 +1025,7 @@ async function processStepStream(stream, options) {
|
|
|
787
1025
|
try {
|
|
788
1026
|
for await (const rawChunk of stream.fullStream) {
|
|
789
1027
|
const chunk = rawChunk;
|
|
790
|
-
|
|
791
|
-
process.stderr.write(`[step-processing] Chunk received: ${chunk.type}
|
|
792
|
-
`);
|
|
793
|
-
}
|
|
1028
|
+
log?.debug(`Chunk received: ${chunk.type}`);
|
|
794
1029
|
abort.throwIfAborted();
|
|
795
1030
|
switch (chunk.type) {
|
|
796
1031
|
case "start-step":
|
|
@@ -846,19 +1081,23 @@ async function processStepStream(stream, options) {
|
|
|
846
1081
|
`)
|
|
847
1082
|
});
|
|
848
1083
|
break;
|
|
849
|
-
case "tool-result":
|
|
1084
|
+
case "tool-result": {
|
|
1085
|
+
const normalized = normalizeToolResultChunk(chunk.output);
|
|
850
1086
|
toolResults.push({
|
|
851
1087
|
toolName: chunk.toolName,
|
|
852
1088
|
toolCallId: chunk.toolCallId,
|
|
853
|
-
result:
|
|
1089
|
+
result: normalized.result,
|
|
1090
|
+
...normalized.metadata ? { metadata: normalized.metadata } : {}
|
|
854
1091
|
});
|
|
855
1092
|
await onEvent({
|
|
856
1093
|
type: "tool-result",
|
|
857
1094
|
toolName: chunk.toolName,
|
|
858
1095
|
toolCallId: chunk.toolCallId,
|
|
859
|
-
result:
|
|
1096
|
+
result: normalized.result,
|
|
1097
|
+
...normalized.metadata ? { metadata: normalized.metadata } : {}
|
|
860
1098
|
});
|
|
861
1099
|
break;
|
|
1100
|
+
}
|
|
862
1101
|
case "tool-error":
|
|
863
1102
|
await onEvent({
|
|
864
1103
|
type: "tool-error",
|
|
@@ -942,21 +1181,15 @@ async function processStepStream(stream, options) {
|
|
|
942
1181
|
error
|
|
943
1182
|
};
|
|
944
1183
|
}
|
|
945
|
-
var processStream = processStepStream;
|
|
946
1184
|
|
|
947
|
-
// src/
|
|
948
|
-
function
|
|
1185
|
+
// src/execution/turn-runner/stream-step.ts
|
|
1186
|
+
function buildStepModelCallContext(options) {
|
|
949
1187
|
const input = options.preparedStep.inferenceInput;
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
model: input.model,
|
|
956
|
-
toolNames: Object.keys(input.tools),
|
|
957
|
-
mcpToolNames: Object.keys(input.mcpTools ?? {}),
|
|
958
|
-
scope: snapshotScope()
|
|
959
|
-
};
|
|
1188
|
+
const ctx = buildModelCallContext(input);
|
|
1189
|
+
if (input.step == null) {
|
|
1190
|
+
ctx.step = options.preparedStep.step;
|
|
1191
|
+
}
|
|
1192
|
+
return ctx;
|
|
960
1193
|
}
|
|
961
1194
|
function normalizeModelStepError(options, error) {
|
|
962
1195
|
const model = options.preparedStep.inferenceInput.model;
|
|
@@ -975,13 +1208,20 @@ async function* runModelStep(options) {
|
|
|
975
1208
|
},
|
|
976
1209
|
(async function* () {
|
|
977
1210
|
const { preparedStep, turnEngine, applyCommitBatch } = options;
|
|
978
|
-
const stream = await Inference.streamStep(preparedStep.inferenceInput);
|
|
979
1211
|
const eventQueue = [];
|
|
980
1212
|
let resolveNext = null;
|
|
981
1213
|
let streamDone = false;
|
|
982
1214
|
let streamError;
|
|
983
1215
|
const intervention = preparedStep.inferenceInput.intervention;
|
|
984
1216
|
const middleware = preparedStep.inferenceInput.middleware;
|
|
1217
|
+
const emitQueuedEvent = async (event) => {
|
|
1218
|
+
middleware?.emitEvent(event);
|
|
1219
|
+
eventQueue.push(event);
|
|
1220
|
+
if (resolveNext) {
|
|
1221
|
+
resolveNext();
|
|
1222
|
+
resolveNext = null;
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
985
1225
|
if (intervention) {
|
|
986
1226
|
intervention.onApplied = (item) => {
|
|
987
1227
|
eventQueue.push({
|
|
@@ -994,7 +1234,22 @@ async function* runModelStep(options) {
|
|
|
994
1234
|
resolveNext = null;
|
|
995
1235
|
}
|
|
996
1236
|
};
|
|
1237
|
+
intervention.onDeferredQueued = (item) => {
|
|
1238
|
+
eventQueue.push({
|
|
1239
|
+
type: "follow-up-queued",
|
|
1240
|
+
id: item.id,
|
|
1241
|
+
message: item.message
|
|
1242
|
+
});
|
|
1243
|
+
if (resolveNext) {
|
|
1244
|
+
resolveNext();
|
|
1245
|
+
resolveNext = null;
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
997
1248
|
}
|
|
1249
|
+
const stream = await Inference.streamStep({
|
|
1250
|
+
...preparedStep.inferenceInput,
|
|
1251
|
+
onEvent: emitQueuedEvent
|
|
1252
|
+
});
|
|
998
1253
|
const processPromise = processStepStream(stream, {
|
|
999
1254
|
sessionID: preparedStep.inferenceInput.sessionID,
|
|
1000
1255
|
abort: preparedStep.inferenceInput.abort,
|
|
@@ -1008,14 +1263,7 @@ async function* runModelStep(options) {
|
|
|
1008
1263
|
contextTokenLimit: preparedStep.stepProcessing.contextTokenLimit,
|
|
1009
1264
|
onContextOverflow: async () => {
|
|
1010
1265
|
},
|
|
1011
|
-
onEvent:
|
|
1012
|
-
middleware?.emitEvent(event);
|
|
1013
|
-
eventQueue.push(event);
|
|
1014
|
-
if (resolveNext) {
|
|
1015
|
-
resolveNext();
|
|
1016
|
-
resolveNext = null;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1266
|
+
onEvent: emitQueuedEvent
|
|
1019
1267
|
}).then((result2) => {
|
|
1020
1268
|
streamDone = true;
|
|
1021
1269
|
if (resolveNext) {
|
|
@@ -1068,7 +1316,7 @@ async function* runModelStep(options) {
|
|
|
1068
1316
|
usage: result.usage,
|
|
1069
1317
|
finishReason: result.finishReason
|
|
1070
1318
|
},
|
|
1071
|
-
|
|
1319
|
+
buildStepModelCallContext(options)
|
|
1072
1320
|
);
|
|
1073
1321
|
result.text = revised.text;
|
|
1074
1322
|
result.usage = revised.usage;
|
|
@@ -1079,8 +1327,7 @@ async function* runModelStep(options) {
|
|
|
1079
1327
|
);
|
|
1080
1328
|
}
|
|
1081
1329
|
|
|
1082
|
-
// src/
|
|
1083
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
1330
|
+
// src/execution/turn-runner/tool-batch.ts
|
|
1084
1331
|
function cloneToolResultRecord(options) {
|
|
1085
1332
|
return new Map(
|
|
1086
1333
|
options.snapshot.toolResults.map((toolResult) => [
|
|
@@ -1089,105 +1336,164 @@ function cloneToolResultRecord(options) {
|
|
|
1089
1336
|
])
|
|
1090
1337
|
);
|
|
1091
1338
|
}
|
|
1092
|
-
function
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1339
|
+
function recordToolResult(toolCall, event, result, accumulators, metadata) {
|
|
1340
|
+
accumulators.events.push(event);
|
|
1341
|
+
accumulators.toolResultsByCallId.set(toolCall.toolCallId, {
|
|
1342
|
+
toolCallId: toolCall.toolCallId,
|
|
1343
|
+
toolName: toolCall.toolName,
|
|
1344
|
+
result,
|
|
1345
|
+
...metadata ? { metadata } : {},
|
|
1346
|
+
...toolCall.replayPolicy ? { replayPolicy: toolCall.replayPolicy } : {}
|
|
1347
|
+
});
|
|
1348
|
+
if (accumulators.turnState.value) {
|
|
1349
|
+
accumulators.turnState.value = advanceAgentTurnState(
|
|
1350
|
+
accumulators.turnState.value,
|
|
1351
|
+
event,
|
|
1352
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
1353
|
+
{
|
|
1354
|
+
...toolCall.replayPolicy ? { toolReplayPolicy: toolCall.replayPolicy } : {}
|
|
1355
|
+
}
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1099
1358
|
}
|
|
1100
|
-
function
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1359
|
+
async function isParallelSafe(tool, args, cwd) {
|
|
1360
|
+
const initialized = await tool.init({ cwd });
|
|
1361
|
+
const cap = initialized.capabilities?.parallelSafe;
|
|
1362
|
+
const safe = resolveCapability(
|
|
1363
|
+
cap,
|
|
1364
|
+
args,
|
|
1365
|
+
/* fallback */
|
|
1366
|
+
false
|
|
1367
|
+
);
|
|
1368
|
+
return { safe, initialized };
|
|
1369
|
+
}
|
|
1370
|
+
async function executeBatchEntry(toolCall, options, accumulators, preInitialized) {
|
|
1371
|
+
const tool = options.tools[toolCall.toolName];
|
|
1372
|
+
if (!tool) {
|
|
1373
|
+
const errorMessage = `Tool '${toolCall.toolName}' is not registered`;
|
|
1374
|
+
recordToolResult(
|
|
1375
|
+
toolCall,
|
|
1376
|
+
{
|
|
1377
|
+
type: "tool-error",
|
|
1378
|
+
toolName: toolCall.toolName,
|
|
1379
|
+
toolCallId: toolCall.toolCallId,
|
|
1380
|
+
error: errorMessage
|
|
1381
|
+
},
|
|
1382
|
+
`Error: ${errorMessage}`,
|
|
1383
|
+
accumulators
|
|
1384
|
+
);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
try {
|
|
1388
|
+
const executed = await executeAgentToolCall({
|
|
1389
|
+
toolName: toolCall.toolName,
|
|
1390
|
+
tool,
|
|
1391
|
+
toolCallId: toolCall.toolCallId,
|
|
1392
|
+
params: toolCall.args,
|
|
1393
|
+
cwd: options.cwd,
|
|
1394
|
+
abort: options.abort,
|
|
1395
|
+
sessionID: options.sessionId,
|
|
1396
|
+
turnID: options.turnTracker?.getCurrentTurnId?.() ?? void 0,
|
|
1397
|
+
messageID: toolCall.toolCallId,
|
|
1398
|
+
...options.host ? { host: options.host } : {},
|
|
1399
|
+
...options.humanInputController ? { humanInputController: options.humanInputController } : {},
|
|
1400
|
+
...options.turnTracker ? { turnTracker: options.turnTracker } : {},
|
|
1401
|
+
...options.middleware ? { middleware: options.middleware } : {},
|
|
1402
|
+
onEvent: async (event) => {
|
|
1403
|
+
accumulators.events.push(event);
|
|
1404
|
+
},
|
|
1405
|
+
...preInitialized ? { initialized: preInitialized } : {}
|
|
1406
|
+
});
|
|
1407
|
+
recordToolResult(
|
|
1408
|
+
toolCall,
|
|
1409
|
+
{
|
|
1410
|
+
type: "tool-result",
|
|
1411
|
+
toolName: toolCall.toolName,
|
|
1412
|
+
toolCallId: toolCall.toolCallId,
|
|
1413
|
+
result: executed.output,
|
|
1414
|
+
...executed.metadata ? { metadata: executed.metadata } : {}
|
|
1415
|
+
},
|
|
1416
|
+
executed.output,
|
|
1417
|
+
accumulators,
|
|
1418
|
+
executed.metadata
|
|
1419
|
+
);
|
|
1420
|
+
} catch (error) {
|
|
1421
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1422
|
+
recordToolResult(
|
|
1423
|
+
toolCall,
|
|
1424
|
+
{
|
|
1425
|
+
type: "tool-error",
|
|
1426
|
+
toolName: toolCall.toolName,
|
|
1427
|
+
toolCallId: toolCall.toolCallId,
|
|
1428
|
+
error: errorMessage
|
|
1429
|
+
},
|
|
1430
|
+
`Error: ${errorMessage}`,
|
|
1431
|
+
accumulators
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1107
1434
|
}
|
|
1108
1435
|
async function runToolBatch(options) {
|
|
1109
1436
|
const toolResultsByCallId = cloneToolResultRecord(options);
|
|
1110
1437
|
const events = [];
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1438
|
+
const turnState = {
|
|
1439
|
+
value: options.turnState ? structuredClone(options.turnState) : void 0
|
|
1440
|
+
};
|
|
1441
|
+
const accumulators = { events, toolResultsByCallId, turnState };
|
|
1442
|
+
const pending = options.snapshot.toolCalls.filter(
|
|
1443
|
+
(tc) => !toolResultsByCallId.has(tc.toolCallId)
|
|
1444
|
+
);
|
|
1445
|
+
const parallelGroup = [];
|
|
1446
|
+
const serialGroup = [];
|
|
1447
|
+
for (const toolCall of pending) {
|
|
1116
1448
|
const tool = options.tools[toolCall.toolName];
|
|
1117
|
-
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1118
1449
|
if (!tool) {
|
|
1119
|
-
|
|
1120
|
-
const event = createToolBatchErrorResult({
|
|
1121
|
-
toolCallId: toolCall.toolCallId,
|
|
1122
|
-
toolName: toolCall.toolName,
|
|
1123
|
-
errorMessage,
|
|
1124
|
-
replayPolicy: toolCall.replayPolicy
|
|
1125
|
-
});
|
|
1126
|
-
events.push(event);
|
|
1127
|
-
toolResultsByCallId.set(toolCall.toolCallId, {
|
|
1128
|
-
toolCallId: toolCall.toolCallId,
|
|
1129
|
-
toolName: toolCall.toolName,
|
|
1130
|
-
result: `Error: ${errorMessage}`,
|
|
1131
|
-
...toolCall.replayPolicy ? { replayPolicy: toolCall.replayPolicy } : {}
|
|
1132
|
-
});
|
|
1133
|
-
if (turnState) {
|
|
1134
|
-
turnState = advanceAgentTurnState(turnState, event, updatedAt, {
|
|
1135
|
-
...toolCall.replayPolicy ? { toolReplayPolicy: toolCall.replayPolicy } : {}
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1450
|
+
serialGroup.push({ toolCall });
|
|
1138
1451
|
continue;
|
|
1139
1452
|
}
|
|
1453
|
+
let safe = false;
|
|
1454
|
+
let initialized;
|
|
1140
1455
|
try {
|
|
1141
|
-
const
|
|
1142
|
-
toolName: toolCall.toolName,
|
|
1456
|
+
const result = await isParallelSafe(
|
|
1143
1457
|
tool,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
toolCallId: toolCall.toolCallId,
|
|
1181
|
-
toolName: toolCall.toolName,
|
|
1182
|
-
result: `Error: ${errorMessage}`,
|
|
1183
|
-
...toolCall.replayPolicy ? { replayPolicy: toolCall.replayPolicy } : {}
|
|
1184
|
-
});
|
|
1185
|
-
if (turnState) {
|
|
1186
|
-
turnState = advanceAgentTurnState(turnState, event, updatedAt, {
|
|
1187
|
-
...toolCall.replayPolicy ? { toolReplayPolicy: toolCall.replayPolicy } : {}
|
|
1188
|
-
});
|
|
1458
|
+
toolCall.args,
|
|
1459
|
+
options.cwd
|
|
1460
|
+
);
|
|
1461
|
+
safe = result.safe;
|
|
1462
|
+
initialized = result.initialized;
|
|
1463
|
+
} catch {
|
|
1464
|
+
}
|
|
1465
|
+
if (safe && initialized) {
|
|
1466
|
+
parallelGroup.push({ toolCall, initialized });
|
|
1467
|
+
} else {
|
|
1468
|
+
serialGroup.push({ toolCall, initialized });
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (parallelGroup.length > 0) {
|
|
1472
|
+
await Promise.all(
|
|
1473
|
+
parallelGroup.map(
|
|
1474
|
+
({ toolCall, initialized }) => executeBatchEntry(toolCall, options, accumulators, initialized)
|
|
1475
|
+
)
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1478
|
+
for (const { toolCall, initialized } of serialGroup) {
|
|
1479
|
+
if (options.intervention?.hasPending && initialized) {
|
|
1480
|
+
const interruptPolicy = initialized.capabilities?.onInterrupt ?? "finish";
|
|
1481
|
+
if (interruptPolicy === "cancel") {
|
|
1482
|
+
recordToolResult(
|
|
1483
|
+
toolCall,
|
|
1484
|
+
{
|
|
1485
|
+
type: "tool-error",
|
|
1486
|
+
toolName: toolCall.toolName,
|
|
1487
|
+
toolCallId: toolCall.toolCallId,
|
|
1488
|
+
error: "Tool cancelled: user sent a new message"
|
|
1489
|
+
},
|
|
1490
|
+
"Error: Tool cancelled: user sent a new message",
|
|
1491
|
+
accumulators
|
|
1492
|
+
);
|
|
1493
|
+
continue;
|
|
1189
1494
|
}
|
|
1190
1495
|
}
|
|
1496
|
+
await executeBatchEntry(toolCall, options, accumulators, initialized);
|
|
1191
1497
|
}
|
|
1192
1498
|
return {
|
|
1193
1499
|
snapshot: {
|
|
@@ -1196,12 +1502,12 @@ async function runToolBatch(options) {
|
|
|
1196
1502
|
),
|
|
1197
1503
|
toolResults: options.snapshot.toolCalls.map((toolCall) => toolResultsByCallId.get(toolCall.toolCallId)).filter((toolResult) => toolResult !== void 0)
|
|
1198
1504
|
},
|
|
1199
|
-
...turnState ? { turnState } : {},
|
|
1505
|
+
...turnState.value ? { turnState: turnState.value } : {},
|
|
1200
1506
|
events
|
|
1201
1507
|
};
|
|
1202
1508
|
}
|
|
1203
1509
|
|
|
1204
|
-
// src/
|
|
1510
|
+
// src/execution/turn-runner/commit.ts
|
|
1205
1511
|
async function* commitStep(options) {
|
|
1206
1512
|
return yield* streamWithinScope(
|
|
1207
1513
|
{
|
|
@@ -1242,10 +1548,7 @@ async function* commitOutput(options) {
|
|
|
1242
1548
|
);
|
|
1243
1549
|
}
|
|
1244
1550
|
|
|
1245
|
-
// src/
|
|
1246
|
-
function cloneUsage2(usage) {
|
|
1247
|
-
return usage ? { ...usage } : void 0;
|
|
1248
|
-
}
|
|
1551
|
+
// src/execution/workflow-state.ts
|
|
1249
1552
|
function cloneMessageSnapshot(message) {
|
|
1250
1553
|
return {
|
|
1251
1554
|
...message,
|
|
@@ -1257,9 +1560,96 @@ function cloneMessageSnapshot(message) {
|
|
|
1257
1560
|
} : {},
|
|
1258
1561
|
...message.role === "assistant" && message.error ? {
|
|
1259
1562
|
error: { ...message.error }
|
|
1563
|
+
} : {},
|
|
1564
|
+
...message.role === "tool" && message.metadata ? {
|
|
1565
|
+
metadata: structuredClone(message.metadata)
|
|
1566
|
+
} : {}
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
function createAgentWorkflowTurnState(options) {
|
|
1570
|
+
const pendingInput = options.initialInput ? cloneMessageSnapshot(options.initialInput) : void 0;
|
|
1571
|
+
return {
|
|
1572
|
+
sessionId: options.sessionId,
|
|
1573
|
+
systemPrompts: [...options.systemPrompts ?? []],
|
|
1574
|
+
messages: (options.initialMessages ?? []).map(cloneMessageSnapshot),
|
|
1575
|
+
phase: pendingInput ? "input-commit" : "model-step",
|
|
1576
|
+
...pendingInput ? { pendingInput } : {},
|
|
1577
|
+
step: options.initialStep ?? 1,
|
|
1578
|
+
maxSteps: options.maxSteps,
|
|
1579
|
+
replayDecisions: {},
|
|
1580
|
+
startedAt: options.startedAt,
|
|
1581
|
+
updatedAt: options.startedAt
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
function cloneAgentWorkflowTurnState(state) {
|
|
1585
|
+
return {
|
|
1586
|
+
...state,
|
|
1587
|
+
systemPrompts: [...state.systemPrompts],
|
|
1588
|
+
messages: state.messages.map(cloneMessageSnapshot),
|
|
1589
|
+
...state.pendingInput ? { pendingInput: cloneMessageSnapshot(state.pendingInput) } : {},
|
|
1590
|
+
...state.usage ? { usage: cloneUsage(state.usage) } : {},
|
|
1591
|
+
...state.turnState ? { turnState: structuredClone(state.turnState) } : {},
|
|
1592
|
+
...state.lastModelStep ? { lastModelStep: structuredClone(state.lastModelStep) } : {},
|
|
1593
|
+
replayDecisions: Object.fromEntries(
|
|
1594
|
+
Object.entries(state.replayDecisions).map(([toolCallId, decision]) => [
|
|
1595
|
+
toolCallId,
|
|
1596
|
+
{ ...decision }
|
|
1597
|
+
])
|
|
1598
|
+
),
|
|
1599
|
+
...state.pendingInterventions?.length ? {
|
|
1600
|
+
pendingInterventions: state.pendingInterventions.map(
|
|
1601
|
+
(intervention) => ({ ...intervention })
|
|
1602
|
+
)
|
|
1603
|
+
} : {},
|
|
1604
|
+
...state.queuedFollowUps?.length ? {
|
|
1605
|
+
queuedFollowUps: state.queuedFollowUps.map((intervention) => ({
|
|
1606
|
+
...intervention
|
|
1607
|
+
}))
|
|
1260
1608
|
} : {}
|
|
1261
1609
|
};
|
|
1262
1610
|
}
|
|
1611
|
+
function applyWorkflowInterventions(state, interventions, updatedAt) {
|
|
1612
|
+
if (interventions.length === 0) {
|
|
1613
|
+
return state;
|
|
1614
|
+
}
|
|
1615
|
+
const injected = interventions.map((intervention) => ({
|
|
1616
|
+
id: intervention.id,
|
|
1617
|
+
role: "user",
|
|
1618
|
+
createdAt: intervention.createdAt,
|
|
1619
|
+
content: intervention.message
|
|
1620
|
+
}));
|
|
1621
|
+
return {
|
|
1622
|
+
...state,
|
|
1623
|
+
messages: [...state.messages, ...injected],
|
|
1624
|
+
pendingInterventions: void 0,
|
|
1625
|
+
updatedAt
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
function drainWorkflowInterventions(state, updatedAt) {
|
|
1629
|
+
if (!state.pendingInterventions?.length) {
|
|
1630
|
+
return state;
|
|
1631
|
+
}
|
|
1632
|
+
return applyWorkflowInterventions(
|
|
1633
|
+
state,
|
|
1634
|
+
state.pendingInterventions,
|
|
1635
|
+
updatedAt
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
function queueWorkflowFollowUps(state, followUps, updatedAt) {
|
|
1639
|
+
if (followUps.length === 0) {
|
|
1640
|
+
return state;
|
|
1641
|
+
}
|
|
1642
|
+
return {
|
|
1643
|
+
...state,
|
|
1644
|
+
queuedFollowUps: [
|
|
1645
|
+
...state.queuedFollowUps ?? [],
|
|
1646
|
+
...followUps.map((followUp) => ({ ...followUp }))
|
|
1647
|
+
],
|
|
1648
|
+
updatedAt
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// src/execution/workflow-snapshot.ts
|
|
1263
1653
|
function snapshotAgentWorkflowMessage(message) {
|
|
1264
1654
|
switch (message.role) {
|
|
1265
1655
|
case "user":
|
|
@@ -1297,6 +1687,7 @@ function snapshotAgentWorkflowMessage(message) {
|
|
|
1297
1687
|
toolCallId: message.toolCallId,
|
|
1298
1688
|
toolName: message.toolName,
|
|
1299
1689
|
result: message.result,
|
|
1690
|
+
...message.metadata ? { metadata: structuredClone(message.metadata) } : {},
|
|
1300
1691
|
...message.compactedAt !== void 0 ? { compactedAt: message.compactedAt } : {}
|
|
1301
1692
|
};
|
|
1302
1693
|
case "system":
|
|
@@ -1309,7 +1700,7 @@ function snapshotAgentWorkflowMessage(message) {
|
|
|
1309
1700
|
}
|
|
1310
1701
|
}
|
|
1311
1702
|
function snapshotAgentWorkflowMessages(messages) {
|
|
1312
|
-
return messages.map(snapshotAgentWorkflowMessage);
|
|
1703
|
+
return messages.map((message) => snapshotAgentWorkflowMessage(message));
|
|
1313
1704
|
}
|
|
1314
1705
|
function restoreAgentWorkflowMessage(snapshot) {
|
|
1315
1706
|
const createdAt = new Date(snapshot.createdAt);
|
|
@@ -1349,6 +1740,7 @@ function restoreAgentWorkflowMessage(snapshot) {
|
|
|
1349
1740
|
toolCallId: snapshot.toolCallId,
|
|
1350
1741
|
toolName: snapshot.toolName,
|
|
1351
1742
|
result: snapshot.result,
|
|
1743
|
+
...snapshot.metadata ? { metadata: structuredClone(snapshot.metadata) } : {},
|
|
1352
1744
|
...snapshot.compactedAt !== void 0 ? { compactedAt: snapshot.compactedAt } : {}
|
|
1353
1745
|
};
|
|
1354
1746
|
case "system":
|
|
@@ -1363,52 +1755,8 @@ function restoreAgentWorkflowMessage(snapshot) {
|
|
|
1363
1755
|
function restoreAgentWorkflowMessages(snapshots) {
|
|
1364
1756
|
return snapshots.map(restoreAgentWorkflowMessage);
|
|
1365
1757
|
}
|
|
1366
|
-
function createAgentWorkflowTurnState(options) {
|
|
1367
|
-
return {
|
|
1368
|
-
sessionId: options.sessionId,
|
|
1369
|
-
systemPrompts: [...options.systemPrompts ?? []],
|
|
1370
|
-
messages: (options.initialMessages ?? []).map(cloneMessageSnapshot),
|
|
1371
|
-
phase: "model-step",
|
|
1372
|
-
step: options.initialStep ?? 1,
|
|
1373
|
-
maxSteps: options.maxSteps,
|
|
1374
|
-
replayDecisions: {},
|
|
1375
|
-
startedAt: options.startedAt,
|
|
1376
|
-
updatedAt: options.startedAt
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
function cloneAgentWorkflowTurnState(state) {
|
|
1380
|
-
return {
|
|
1381
|
-
...state,
|
|
1382
|
-
systemPrompts: [...state.systemPrompts],
|
|
1383
|
-
messages: state.messages.map(cloneMessageSnapshot),
|
|
1384
|
-
...state.usage ? { usage: cloneUsage2(state.usage) } : {},
|
|
1385
|
-
...state.turnState ? { turnState: structuredClone(state.turnState) } : {},
|
|
1386
|
-
...state.lastModelStep ? { lastModelStep: structuredClone(state.lastModelStep) } : {},
|
|
1387
|
-
replayDecisions: Object.fromEntries(
|
|
1388
|
-
Object.entries(state.replayDecisions).map(([toolCallId, decision]) => [
|
|
1389
|
-
toolCallId,
|
|
1390
|
-
{ ...decision }
|
|
1391
|
-
])
|
|
1392
|
-
)
|
|
1393
|
-
};
|
|
1394
|
-
}
|
|
1395
1758
|
|
|
1396
|
-
// src/
|
|
1397
|
-
function accumulateWorkflowUsage(current, next) {
|
|
1398
|
-
if (!next) {
|
|
1399
|
-
return current ? { ...current } : void 0;
|
|
1400
|
-
}
|
|
1401
|
-
if (!current) {
|
|
1402
|
-
return { ...next };
|
|
1403
|
-
}
|
|
1404
|
-
return {
|
|
1405
|
-
inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
|
|
1406
|
-
outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
|
|
1407
|
-
totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0),
|
|
1408
|
-
cacheReadTokens: (current.cacheReadTokens ?? 0) + (next.cacheReadTokens ?? 0),
|
|
1409
|
-
cacheWriteTokens: (current.cacheWriteTokens ?? 0) + (next.cacheWriteTokens ?? 0)
|
|
1410
|
-
};
|
|
1411
|
-
}
|
|
1759
|
+
// src/execution/workflow-planner/helpers.ts
|
|
1412
1760
|
function cloneRelevantReplayDecisions(state, snapshot) {
|
|
1413
1761
|
return Object.fromEntries(
|
|
1414
1762
|
snapshot.toolCalls.flatMap((toolCall) => {
|
|
@@ -1417,18 +1765,29 @@ function cloneRelevantReplayDecisions(state, snapshot) {
|
|
|
1417
1765
|
})
|
|
1418
1766
|
);
|
|
1419
1767
|
}
|
|
1420
|
-
function
|
|
1768
|
+
function findAllUnresolvedToolCalls(snapshot) {
|
|
1421
1769
|
const resolvedIds = new Set(
|
|
1422
1770
|
snapshot.toolResults.map((toolResult) => toolResult.toolCallId)
|
|
1423
1771
|
);
|
|
1424
|
-
return snapshot.toolCalls.
|
|
1772
|
+
return snapshot.toolCalls.filter(
|
|
1425
1773
|
(toolCall) => !resolvedIds.has(toolCall.toolCallId)
|
|
1426
1774
|
);
|
|
1427
1775
|
}
|
|
1428
1776
|
|
|
1429
|
-
// src/
|
|
1777
|
+
// src/execution/workflow-planner/plan.ts
|
|
1430
1778
|
function planNextAgentWorkflowOperation(state) {
|
|
1431
1779
|
switch (state.phase) {
|
|
1780
|
+
case "input-commit":
|
|
1781
|
+
if (!state.pendingInput) {
|
|
1782
|
+
throw new Error(
|
|
1783
|
+
`Workflow state for session '${state.sessionId}' is in input-commit phase without a pending input message`
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
return {
|
|
1787
|
+
kind: "input-commit",
|
|
1788
|
+
sessionId: state.sessionId,
|
|
1789
|
+
messages: [structuredClone(state.pendingInput)]
|
|
1790
|
+
};
|
|
1432
1791
|
case "model-step":
|
|
1433
1792
|
return {
|
|
1434
1793
|
kind: "model-step",
|
|
@@ -1444,24 +1803,37 @@ function planNextAgentWorkflowOperation(state) {
|
|
|
1444
1803
|
`Workflow state for session '${state.sessionId}' is in tool-batch phase without a stepCommit snapshot`
|
|
1445
1804
|
);
|
|
1446
1805
|
}
|
|
1447
|
-
const
|
|
1806
|
+
const allUnresolved = findAllUnresolvedToolCalls(
|
|
1448
1807
|
state.lastModelStep.stepCommit
|
|
1449
1808
|
);
|
|
1450
|
-
if (
|
|
1809
|
+
if (allUnresolved.length === 0) {
|
|
1451
1810
|
throw new Error(
|
|
1452
1811
|
`Workflow state for session '${state.sessionId}' is in tool-batch phase without unresolved tool calls`
|
|
1453
1812
|
);
|
|
1454
1813
|
}
|
|
1814
|
+
if (allUnresolved.length === 1) {
|
|
1815
|
+
return {
|
|
1816
|
+
kind: "tool-call",
|
|
1817
|
+
step: state.step,
|
|
1818
|
+
sessionId: state.sessionId,
|
|
1819
|
+
toolCall: structuredClone(allUnresolved[0]),
|
|
1820
|
+
turnState: state.turnState ? structuredClone(state.turnState) : void 0,
|
|
1821
|
+
replayDecision: cloneRelevantReplayDecisions(
|
|
1822
|
+
state,
|
|
1823
|
+
state.lastModelStep.stepCommit
|
|
1824
|
+
)[allUnresolved[0].toolCallId]
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1455
1827
|
return {
|
|
1456
|
-
kind: "tool-
|
|
1828
|
+
kind: "tool-batch",
|
|
1457
1829
|
step: state.step,
|
|
1458
1830
|
sessionId: state.sessionId,
|
|
1459
|
-
|
|
1831
|
+
toolCalls: allUnresolved.map((tc) => structuredClone(tc)),
|
|
1460
1832
|
turnState: state.turnState ? structuredClone(state.turnState) : void 0,
|
|
1461
|
-
|
|
1833
|
+
replayDecisions: cloneRelevantReplayDecisions(
|
|
1462
1834
|
state,
|
|
1463
1835
|
state.lastModelStep.stepCommit
|
|
1464
|
-
)
|
|
1836
|
+
)
|
|
1465
1837
|
};
|
|
1466
1838
|
}
|
|
1467
1839
|
case "step-commit":
|
|
@@ -1494,12 +1866,12 @@ function planNextAgentWorkflowOperation(state) {
|
|
|
1494
1866
|
}
|
|
1495
1867
|
}
|
|
1496
1868
|
|
|
1497
|
-
// src/
|
|
1869
|
+
// src/execution/workflow-planner/apply.ts
|
|
1498
1870
|
function applyAgentWorkflowModelStepResult(state, result, updatedAt) {
|
|
1499
1871
|
const next = cloneAgentWorkflowTurnState(state);
|
|
1500
1872
|
next.lastModelStep = structuredClone(result);
|
|
1501
1873
|
next.turnState = structuredClone(result.turnState);
|
|
1502
|
-
next.usage =
|
|
1874
|
+
next.usage = accumulateUsage(next.usage, result.usage);
|
|
1503
1875
|
next.updatedAt = updatedAt;
|
|
1504
1876
|
next.phase = result.finishReason === "tool-calls" ? "tool-batch" : "output-commit";
|
|
1505
1877
|
return next;
|
|
@@ -1566,6 +1938,10 @@ function applyAgentWorkflowCommitResult(state, result, updatedAt) {
|
|
|
1566
1938
|
];
|
|
1567
1939
|
next.updatedAt = updatedAt;
|
|
1568
1940
|
switch (state.phase) {
|
|
1941
|
+
case "input-commit":
|
|
1942
|
+
next.phase = "model-step";
|
|
1943
|
+
delete next.pendingInput;
|
|
1944
|
+
return next;
|
|
1569
1945
|
case "step-commit":
|
|
1570
1946
|
next.step = state.step + 1;
|
|
1571
1947
|
next.phase = "model-step";
|
|
@@ -1597,30 +1973,38 @@ function failAgentWorkflowTurnState(state, error, updatedAt) {
|
|
|
1597
1973
|
}
|
|
1598
1974
|
|
|
1599
1975
|
export {
|
|
1600
|
-
convertAgentMessagesToModelMessages,
|
|
1601
1976
|
createAgentTurnStepCommitBatch,
|
|
1602
1977
|
createAgentTurnState,
|
|
1603
1978
|
advanceAgentTurnState,
|
|
1604
1979
|
failAgentTurnState,
|
|
1605
1980
|
AgentTurnEngine,
|
|
1606
1981
|
createAgentTurnEngine,
|
|
1982
|
+
estimateTokens,
|
|
1983
|
+
estimateMessageTokens,
|
|
1984
|
+
estimateConversationTokens,
|
|
1985
|
+
DEFAULT_CONTEXT_LIMITS,
|
|
1986
|
+
getUsableTokenLimit,
|
|
1987
|
+
findCutPoint,
|
|
1988
|
+
ContextManager,
|
|
1607
1989
|
prepareModelStep,
|
|
1608
1990
|
DoomLoopError,
|
|
1609
1991
|
ContextOverflowError,
|
|
1610
1992
|
processStepStream,
|
|
1611
|
-
processStream,
|
|
1612
1993
|
runModelStep,
|
|
1613
1994
|
runToolBatch,
|
|
1614
1995
|
commitStep,
|
|
1615
1996
|
commitOutput,
|
|
1616
1997
|
defaultAgentTaskCheckpointStrategy,
|
|
1617
1998
|
createAgentTaskRunner,
|
|
1999
|
+
createAgentWorkflowTurnState,
|
|
2000
|
+
cloneAgentWorkflowTurnState,
|
|
2001
|
+
applyWorkflowInterventions,
|
|
2002
|
+
drainWorkflowInterventions,
|
|
2003
|
+
queueWorkflowFollowUps,
|
|
1618
2004
|
snapshotAgentWorkflowMessage,
|
|
1619
2005
|
snapshotAgentWorkflowMessages,
|
|
1620
2006
|
restoreAgentWorkflowMessage,
|
|
1621
2007
|
restoreAgentWorkflowMessages,
|
|
1622
|
-
createAgentWorkflowTurnState,
|
|
1623
|
-
cloneAgentWorkflowTurnState,
|
|
1624
2008
|
planNextAgentWorkflowOperation,
|
|
1625
2009
|
applyAgentWorkflowModelStepResult,
|
|
1626
2010
|
applyAgentWorkflowToolBatchResult,
|