@cuylabs/agent-core 0.8.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-CAA7FHIH.js → chunk-6HZBHFOL.js} +3 -103
- package/dist/chunk-CJI7PVS2.js +58 -0
- package/dist/{chunk-N6HWIEEA.js → chunk-CMYN2RCB.js} +278 -61
- package/dist/chunk-FII65CN7.js +117 -0
- package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
- package/dist/chunk-I6PKJ7XQ.js +292 -0
- package/dist/{chunk-BDBZ3SLK.js → chunk-ICZ66572.js} +48 -4
- package/dist/chunk-KYLPMBHD.js +316 -0
- package/dist/chunk-MXAP4UG6.js +2956 -0
- package/dist/{chunk-RZITT45F.js → chunk-N3VX7FEE.js} +39 -6
- package/dist/{chunk-YSLSEQ6B.js → chunk-NDZWXCBZ.js} +218 -95
- package/dist/{chunk-P6YF7USR.js → chunk-Q742PSH3.js} +23 -38
- package/dist/chunk-QAL3OMI3.js +943 -0
- package/dist/{chunk-RFEKJKTO.js → chunk-RN6WZEUF.js} +330 -280
- package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
- package/dist/chunk-SPBFQXOT.js +0 -0
- package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
- package/dist/chunk-SSFBF3US.js +602 -0
- package/dist/chunk-SZ2XBPTW.js +8 -0
- package/dist/chunk-T4UIX5D7.js +115 -0
- package/dist/chunk-TIHPYVAJ.js +102 -0
- package/dist/{chunk-YUUJK53A.js → chunk-TOTDGK3P.js} +1 -1
- package/dist/chunk-V4RFNEET.js +563 -0
- package/dist/chunk-VOUEJSW6.js +0 -0
- package/dist/{chunk-4BDA7DQY.js → chunk-WBPOZ7CL.js} +673 -273
- 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 -34
- package/dist/{runtime → execution}/index.js +18 -13
- package/dist/index-BCqEGzBj.d.ts +251 -0
- package/dist/index.d.ts +490 -122
- package/dist/index.js +2104 -615
- package/dist/{errors → inference/errors}/index.d.ts +2 -2
- package/dist/{errors → inference/errors}/index.js +1 -1
- package/dist/inference/index.d.ts +16 -23
- package/dist/inference/index.js +45 -16
- 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 -149
- package/dist/middleware/index.js +11 -3
- package/dist/model-messages-B4nK9D1-.d.ts +13 -0
- package/dist/models/index.d.ts +23 -18
- package/dist/models/index.js +48 -11
- package/dist/models/reasoning/index.d.ts +4 -0
- package/dist/{reasoning → models/reasoning}/index.js +3 -3
- package/dist/plugin/index.d.ts +458 -0
- package/dist/plugin/index.js +32 -0
- package/dist/profiles/index.d.ts +55 -0
- package/dist/profiles/index.js +30 -0
- package/dist/prompt/index.d.ts +8 -12
- package/dist/prompt/index.js +3 -2
- 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 +3 -3
- 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 +125 -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 +58 -53
- package/dist/builder-UpOWQMW3.d.ts +0 -34
- package/dist/chunk-7MUFEN4K.js +0 -559
- package/dist/chunk-7VKQ4WPB.js +0 -73
- package/dist/chunk-BFM2YHNM.js +0 -222
- package/dist/chunk-DWYX7ASF.js +0 -26
- package/dist/chunk-KUVSERLJ.js +0 -50
- package/dist/chunk-N7P4PN3O.js +0 -84
- package/dist/chunk-SDSBEQXG.js +0 -157
- package/dist/chunk-SQU2AJHO.js +0 -305
- package/dist/chunk-VBWWUHWI.js +0 -724
- 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-CWSchSql.d.ts +0 -1058
- package/dist/messages-BYWGn8TY.d.ts +0 -110
- package/dist/presets/index.d.ts +0 -53
- package/dist/presets/index.js +0 -28
- package/dist/reasoning/index.d.ts +0 -116
- package/dist/registry-DwYqsQkX.d.ts +0 -164
- package/dist/runner-e2YRcUoX.d.ts +0 -786
- package/dist/scope/index.d.ts +0 -10
- package/dist/scope/index.js +0 -14
- package/dist/session-manager-B_CWGTsl.d.ts +0 -274
- package/dist/signal/index.d.ts +0 -28
- package/dist/signal/index.js +0 -6
- package/dist/sub-agent/index.d.ts +0 -23
- package/dist/sub-agent/index.js +0 -15
- package/dist/tool-BHbyUAy3.d.ts +0 -150
- package/dist/tool-DLXAR9Ce.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-BnpEOYV-.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-KKDrdU9Y.d.ts +0 -325
- package/dist/types-QA4WhEfz.d.ts +0 -138
- package/dist/types-QKHHQLLq.d.ts +0 -336
- package/dist/types-YuWV4ag7.d.ts +0 -72
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Inference
|
|
6
|
-
} from "./chunk-N6HWIEEA.js";
|
|
7
|
-
import {
|
|
8
|
-
executeAgentToolCall
|
|
9
|
-
} from "./chunk-7VKQ4WPB.js";
|
|
2
|
+
Inference,
|
|
3
|
+
buildModelCallContext
|
|
4
|
+
} from "./chunk-CMYN2RCB.js";
|
|
10
5
|
import {
|
|
6
|
+
PRUNE_PROTECTED_TOOLS,
|
|
7
|
+
accumulateUsage,
|
|
11
8
|
currentScope,
|
|
9
|
+
executeAgentToolCall,
|
|
12
10
|
snapshotScope,
|
|
13
11
|
streamWithinScope,
|
|
14
12
|
withinScope
|
|
15
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5NVVNXPQ.js";
|
|
14
|
+
import {
|
|
15
|
+
LLMError
|
|
16
|
+
} from "./chunk-N3VX7FEE.js";
|
|
17
|
+
import {
|
|
18
|
+
extractModelId,
|
|
19
|
+
extractProvider
|
|
20
|
+
} from "./chunk-I6PKJ7XQ.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveCapability
|
|
23
|
+
} from "./chunk-FII65CN7.js";
|
|
24
|
+
import {
|
|
25
|
+
silentLogger
|
|
26
|
+
} from "./chunk-T4UIX5D7.js";
|
|
16
27
|
|
|
17
|
-
// src/
|
|
28
|
+
// src/execution/task/observer.ts
|
|
18
29
|
function defaultAgentTaskCheckpointStrategy(input) {
|
|
19
30
|
switch (input.event.type) {
|
|
20
31
|
case "step-finish":
|
|
@@ -32,18 +43,20 @@ function defaultAgentTaskCheckpointStrategy(input) {
|
|
|
32
43
|
}
|
|
33
44
|
}
|
|
34
45
|
|
|
35
|
-
// src/
|
|
46
|
+
// src/execution/task/runner.ts
|
|
36
47
|
import { randomUUID } from "crypto";
|
|
37
48
|
|
|
38
|
-
// src/
|
|
49
|
+
// src/execution/clone-usage.ts
|
|
50
|
+
function cloneUsage(usage) {
|
|
51
|
+
return { ...usage };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/execution/turn-state.ts
|
|
39
55
|
var EMPTY_USAGE = {
|
|
40
56
|
inputTokens: 0,
|
|
41
57
|
outputTokens: 0,
|
|
42
58
|
totalTokens: 0
|
|
43
59
|
};
|
|
44
|
-
function cloneUsage(usage) {
|
|
45
|
-
return { ...usage };
|
|
46
|
-
}
|
|
47
60
|
function normalizeUsage(usage) {
|
|
48
61
|
if (!usage) {
|
|
49
62
|
return cloneUsage(EMPTY_USAGE);
|
|
@@ -58,13 +71,14 @@ function removeActiveToolCall(toolCalls, toolCallId) {
|
|
|
58
71
|
return toolCalls.filter((toolCall) => toolCall.toolCallId !== toolCallId);
|
|
59
72
|
}
|
|
60
73
|
function createAgentTurnState(options) {
|
|
74
|
+
const restore = options.restoreFrom;
|
|
61
75
|
return {
|
|
62
76
|
sessionId: options.sessionId,
|
|
63
77
|
phase: "initializing",
|
|
64
|
-
step: 0,
|
|
65
|
-
response: "",
|
|
66
|
-
usage: cloneUsage(EMPTY_USAGE),
|
|
67
|
-
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,
|
|
68
82
|
activeToolCalls: [],
|
|
69
83
|
resolvedToolCalls: [],
|
|
70
84
|
startedAt: options.startedAt,
|
|
@@ -77,7 +91,8 @@ function advanceAgentTurnState(state, event, updatedAt, options = {}) {
|
|
|
77
91
|
usage: cloneUsage(state.usage),
|
|
78
92
|
activeToolCalls: state.activeToolCalls.map((toolCall) => ({ ...toolCall })),
|
|
79
93
|
resolvedToolCalls: state.resolvedToolCalls.map((toolCall) => ({
|
|
80
|
-
...toolCall
|
|
94
|
+
...toolCall,
|
|
95
|
+
...toolCall.metadata ? { metadata: structuredClone(toolCall.metadata) } : {}
|
|
81
96
|
})),
|
|
82
97
|
eventCount: state.eventCount + 1,
|
|
83
98
|
lastEvent: event,
|
|
@@ -122,6 +137,7 @@ function advanceAgentTurnState(state, event, updatedAt, options = {}) {
|
|
|
122
137
|
toolName: event.toolName,
|
|
123
138
|
outcome: "result",
|
|
124
139
|
value: event.result,
|
|
140
|
+
...event.metadata ? { metadata: structuredClone(event.metadata) } : {},
|
|
125
141
|
resolvedAt: updatedAt,
|
|
126
142
|
...options.toolReplayPolicy ? { replayPolicy: options.toolReplayPolicy } : {}
|
|
127
143
|
}
|
|
@@ -195,7 +211,8 @@ function failAgentTurnState(state, error, updatedAt) {
|
|
|
195
211
|
usage: cloneUsage(state.usage),
|
|
196
212
|
activeToolCalls: state.activeToolCalls.map((toolCall) => ({ ...toolCall })),
|
|
197
213
|
resolvedToolCalls: state.resolvedToolCalls.map((toolCall) => ({
|
|
198
|
-
...toolCall
|
|
214
|
+
...toolCall,
|
|
215
|
+
...toolCall.metadata ? { metadata: structuredClone(toolCall.metadata) } : {}
|
|
199
216
|
})),
|
|
200
217
|
phase: "failed",
|
|
201
218
|
error: error.message,
|
|
@@ -203,7 +220,7 @@ function failAgentTurnState(state, error, updatedAt) {
|
|
|
203
220
|
};
|
|
204
221
|
}
|
|
205
222
|
|
|
206
|
-
// src/
|
|
223
|
+
// src/execution/task/runner.ts
|
|
207
224
|
function normalizeNonEmpty(value, label) {
|
|
208
225
|
const normalized = value.trim();
|
|
209
226
|
if (!normalized) {
|
|
@@ -227,15 +244,14 @@ function buildRuntimeSessionId(prefix, key) {
|
|
|
227
244
|
function nowIso() {
|
|
228
245
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
229
246
|
}
|
|
230
|
-
async function notifyObservers(observers, invoke) {
|
|
247
|
+
async function notifyObservers(observers, invoke, logger) {
|
|
231
248
|
for (const observer of observers) {
|
|
232
249
|
try {
|
|
233
250
|
await invoke(observer);
|
|
234
251
|
} catch (error) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
);
|
|
252
|
+
logger.warn("observer error", {
|
|
253
|
+
error: error instanceof Error ? error.message : String(error)
|
|
254
|
+
});
|
|
239
255
|
}
|
|
240
256
|
}
|
|
241
257
|
}
|
|
@@ -243,11 +259,13 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
243
259
|
const prefix = options.sessionPrefix ?? "runtime";
|
|
244
260
|
const baseObservers = options.observers ?? [];
|
|
245
261
|
const checkpointStrategy = options.checkpointStrategy ?? defaultAgentTaskCheckpointStrategy;
|
|
262
|
+
const log = options.logger?.child("task-runner") ?? silentLogger;
|
|
246
263
|
return async (payload, context = {}) => {
|
|
247
264
|
const message = normalizeNonEmpty(payload.message, "payload.message");
|
|
248
265
|
const resolvedSessionId = payload.sessionId?.trim() || options.resolveSessionId?.(payload, context)?.trim() || buildRuntimeSessionId(prefix, context.fallbackSessionKey);
|
|
249
266
|
const sessionId = normalizeNonEmpty(resolvedSessionId, "sessionId");
|
|
250
267
|
const startedAt = nowIso();
|
|
268
|
+
const executionId = context.executionId?.trim() || `${sessionId}:${startedAt}`;
|
|
251
269
|
return withinScope(
|
|
252
270
|
{
|
|
253
271
|
kind: "task",
|
|
@@ -263,13 +281,20 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
263
281
|
payload,
|
|
264
282
|
context,
|
|
265
283
|
sessionId,
|
|
266
|
-
|
|
284
|
+
executionId,
|
|
285
|
+
startedAt: context.restoreFrom?.startedAt ?? startedAt,
|
|
267
286
|
scope: snapshotScope()
|
|
268
287
|
};
|
|
269
|
-
const toolCalls = [];
|
|
288
|
+
const toolCalls = context.restoreFrom?.toolCalls.map((tc) => ({ ...tc })) ?? [];
|
|
270
289
|
let turnState = createAgentTurnState({
|
|
271
290
|
sessionId,
|
|
272
|
-
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
|
|
273
298
|
});
|
|
274
299
|
const createSnapshot = () => ({
|
|
275
300
|
sessionId,
|
|
@@ -298,13 +323,13 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
298
323
|
};
|
|
299
324
|
await notifyObservers(baseObservers, async (observer) => {
|
|
300
325
|
await observer.onCheckpoint?.(checkpoint);
|
|
301
|
-
});
|
|
326
|
+
}, log);
|
|
302
327
|
};
|
|
303
328
|
await notifyObservers(baseObservers, async (observer) => {
|
|
304
329
|
await observer.onTaskStart?.(run, createSnapshot());
|
|
305
|
-
});
|
|
330
|
+
}, log);
|
|
306
331
|
await emitCheckpoint("task-start");
|
|
307
|
-
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);
|
|
308
333
|
try {
|
|
309
334
|
const processChatStream = async () => {
|
|
310
335
|
for await (const event of agent.chat(sessionId, message, {
|
|
@@ -318,7 +343,7 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
318
343
|
const snapshot = createSnapshot();
|
|
319
344
|
await notifyObservers(baseObservers, async (observer) => {
|
|
320
345
|
await observer.onTaskEvent?.(run, event, snapshot);
|
|
321
|
-
});
|
|
346
|
+
}, log);
|
|
322
347
|
const checkpointReason = checkpointStrategy({
|
|
323
348
|
run,
|
|
324
349
|
event,
|
|
@@ -345,14 +370,14 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
345
370
|
};
|
|
346
371
|
await notifyObservers(baseObservers, async (observer) => {
|
|
347
372
|
await observer.onTaskComplete?.(run, result, createSnapshot());
|
|
348
|
-
});
|
|
373
|
+
}, log);
|
|
349
374
|
return result;
|
|
350
375
|
} catch (error) {
|
|
351
376
|
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
352
377
|
turnState = failAgentTurnState(turnState, normalizedError, nowIso());
|
|
353
378
|
await notifyObservers(baseObservers, async (observer) => {
|
|
354
379
|
await observer.onTaskError?.(run, normalizedError, createSnapshot());
|
|
355
|
-
});
|
|
380
|
+
}, log);
|
|
356
381
|
await emitCheckpoint("task-error");
|
|
357
382
|
throw normalizedError;
|
|
358
383
|
}
|
|
@@ -361,50 +386,7 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
361
386
|
};
|
|
362
387
|
}
|
|
363
388
|
|
|
364
|
-
// src/
|
|
365
|
-
function convertAgentMessagesToModelMessages(messages) {
|
|
366
|
-
return messages.flatMap((message) => {
|
|
367
|
-
switch (message.role) {
|
|
368
|
-
case "user":
|
|
369
|
-
return [{ role: "user", content: message.content }];
|
|
370
|
-
case "assistant": {
|
|
371
|
-
if (message.toolCalls && message.toolCalls.length > 0) {
|
|
372
|
-
const toolCallParts = message.toolCalls.map(
|
|
373
|
-
(toolCall) => ({
|
|
374
|
-
type: "tool-call",
|
|
375
|
-
toolCallId: toolCall.toolCallId,
|
|
376
|
-
toolName: toolCall.toolName,
|
|
377
|
-
input: toolCall.args
|
|
378
|
-
})
|
|
379
|
-
);
|
|
380
|
-
return [{ role: "assistant", content: toolCallParts }];
|
|
381
|
-
}
|
|
382
|
-
return [{ role: "assistant", content: message.content }];
|
|
383
|
-
}
|
|
384
|
-
case "tool":
|
|
385
|
-
return [
|
|
386
|
-
{
|
|
387
|
-
role: "tool",
|
|
388
|
-
content: [
|
|
389
|
-
{
|
|
390
|
-
type: "tool-result",
|
|
391
|
-
toolCallId: message.toolCallId ?? "",
|
|
392
|
-
toolName: message.toolName ?? "",
|
|
393
|
-
output: {
|
|
394
|
-
type: "text",
|
|
395
|
-
value: typeof message.result === "string" ? message.result : JSON.stringify(message.result)
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
];
|
|
401
|
-
case "system":
|
|
402
|
-
return [{ role: "system", content: message.content }];
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// src/runtime/turn-engine/commit-batch.ts
|
|
389
|
+
// src/execution/turn-engine/commit-batch.ts
|
|
408
390
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
409
391
|
function createAgentTurnBoundaryEvent(boundary, metadata = {}) {
|
|
410
392
|
return {
|
|
@@ -433,13 +415,14 @@ function createAgentTurnStepCommitBatch(step, snapshot, options = {}) {
|
|
|
433
415
|
createdAt
|
|
434
416
|
};
|
|
435
417
|
const toolMessages = snapshot.toolResults.map(
|
|
436
|
-
({ toolCallId, toolName, result }) => ({
|
|
418
|
+
({ toolCallId, toolName, result, metadata }) => ({
|
|
437
419
|
id: options.toolMessageIds?.[toolCallId] ?? randomUUID2(),
|
|
438
420
|
role: "tool",
|
|
439
421
|
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
440
422
|
toolCallId,
|
|
441
423
|
toolName,
|
|
442
424
|
result,
|
|
425
|
+
...metadata ? { metadata } : {},
|
|
443
426
|
createdAt
|
|
444
427
|
})
|
|
445
428
|
);
|
|
@@ -511,7 +494,7 @@ function createAgentTurnOutputCommit(options) {
|
|
|
511
494
|
};
|
|
512
495
|
}
|
|
513
496
|
|
|
514
|
-
// src/
|
|
497
|
+
// src/execution/turn-engine/engine.ts
|
|
515
498
|
var AgentTurnEngine = class {
|
|
516
499
|
turnState;
|
|
517
500
|
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
@@ -552,6 +535,7 @@ var AgentTurnEngine = class {
|
|
|
552
535
|
toolCallId,
|
|
553
536
|
toolName,
|
|
554
537
|
result: resultData.result,
|
|
538
|
+
...resultData.metadata ? { metadata: resultData.metadata } : {},
|
|
555
539
|
...replayPolicy ? { replayPolicy } : {}
|
|
556
540
|
};
|
|
557
541
|
}).filter((result) => result !== void 0)
|
|
@@ -574,6 +558,7 @@ var AgentTurnEngine = class {
|
|
|
574
558
|
this.pendingToolResults.set(event.toolCallId, {
|
|
575
559
|
toolName: event.toolName,
|
|
576
560
|
result: event.result,
|
|
561
|
+
...event.metadata ? { metadata: event.metadata } : {},
|
|
577
562
|
replayPolicy: toolReplayPolicy
|
|
578
563
|
});
|
|
579
564
|
break;
|
|
@@ -616,7 +601,251 @@ function createAgentTurnEngine(options) {
|
|
|
616
601
|
return new AgentTurnEngine(options);
|
|
617
602
|
}
|
|
618
603
|
|
|
619
|
-
// 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
|
|
620
849
|
function prepareModelStep(options) {
|
|
621
850
|
const modelMessages = Array.from(options.toModelMessages(options.messages));
|
|
622
851
|
return {
|
|
@@ -625,6 +854,7 @@ function prepareModelStep(options) {
|
|
|
625
854
|
modelMessages,
|
|
626
855
|
inferenceInput: {
|
|
627
856
|
sessionID: options.sessionId,
|
|
857
|
+
turnID: options.turnTracker?.getCurrentTurnId?.() ?? void 0,
|
|
628
858
|
step: options.step,
|
|
629
859
|
model: options.config.model,
|
|
630
860
|
system: options.systemPrompts,
|
|
@@ -634,6 +864,7 @@ function prepareModelStep(options) {
|
|
|
634
864
|
mcpTools: options.mcpTools,
|
|
635
865
|
cwd: options.config.cwd,
|
|
636
866
|
host: options.host,
|
|
867
|
+
humanInputController: options.humanInputController,
|
|
637
868
|
temperature: options.config.temperature,
|
|
638
869
|
topP: options.config.topP,
|
|
639
870
|
maxOutputTokens: options.config.maxOutputTokens,
|
|
@@ -651,12 +882,15 @@ function prepareModelStep(options) {
|
|
|
651
882
|
doomLoopThreshold: options.config.doomLoopThreshold,
|
|
652
883
|
enforceDoomLoop: options.config.enforceDoomLoop,
|
|
653
884
|
onDoomLoop: options.config.onDoomLoop,
|
|
654
|
-
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
|
|
655
889
|
}
|
|
656
890
|
};
|
|
657
891
|
}
|
|
658
892
|
|
|
659
|
-
// src/
|
|
893
|
+
// src/execution/step-processing/doom-loop.ts
|
|
660
894
|
var DEFAULT_DOOM_LOOP_THRESHOLD = 3;
|
|
661
895
|
var DoomLoopError = class extends Error {
|
|
662
896
|
toolName;
|
|
@@ -733,7 +967,7 @@ async function recordToolCallAndCheckDoomLoop(options) {
|
|
|
733
967
|
options.warn?.(`[StepProcessing] ${doomError.message}`);
|
|
734
968
|
}
|
|
735
969
|
|
|
736
|
-
// src/
|
|
970
|
+
// src/execution/step-processing/overflow.ts
|
|
737
971
|
var ContextOverflowError = class extends Error {
|
|
738
972
|
inputTokens;
|
|
739
973
|
limit;
|
|
@@ -760,11 +994,23 @@ async function handleContextOverflow(options) {
|
|
|
760
994
|
}
|
|
761
995
|
}
|
|
762
996
|
|
|
763
|
-
// 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
|
+
}
|
|
764
1008
|
async function processStepStream(stream, options) {
|
|
765
1009
|
const { abort, onEvent } = options;
|
|
1010
|
+
const normalizeError = options.normalizeError ?? ((error2) => error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
766
1011
|
const doomLoopThreshold = options.doomLoopThreshold ?? DEFAULT_DOOM_LOOP_THRESHOLD;
|
|
767
1012
|
const maxSteps = options.maxSteps ?? 50;
|
|
1013
|
+
const log = options.logger;
|
|
768
1014
|
let stepCount = options.currentStep ?? 1;
|
|
769
1015
|
let sawStartStep = false;
|
|
770
1016
|
let text = "";
|
|
@@ -779,10 +1025,7 @@ async function processStepStream(stream, options) {
|
|
|
779
1025
|
try {
|
|
780
1026
|
for await (const rawChunk of stream.fullStream) {
|
|
781
1027
|
const chunk = rawChunk;
|
|
782
|
-
|
|
783
|
-
process.stderr.write(`[step-processing] Chunk received: ${chunk.type}
|
|
784
|
-
`);
|
|
785
|
-
}
|
|
1028
|
+
log?.debug(`Chunk received: ${chunk.type}`);
|
|
786
1029
|
abort.throwIfAborted();
|
|
787
1030
|
switch (chunk.type) {
|
|
788
1031
|
case "start-step":
|
|
@@ -838,19 +1081,23 @@ async function processStepStream(stream, options) {
|
|
|
838
1081
|
`)
|
|
839
1082
|
});
|
|
840
1083
|
break;
|
|
841
|
-
case "tool-result":
|
|
1084
|
+
case "tool-result": {
|
|
1085
|
+
const normalized = normalizeToolResultChunk(chunk.output);
|
|
842
1086
|
toolResults.push({
|
|
843
1087
|
toolName: chunk.toolName,
|
|
844
1088
|
toolCallId: chunk.toolCallId,
|
|
845
|
-
result:
|
|
1089
|
+
result: normalized.result,
|
|
1090
|
+
...normalized.metadata ? { metadata: normalized.metadata } : {}
|
|
846
1091
|
});
|
|
847
1092
|
await onEvent({
|
|
848
1093
|
type: "tool-result",
|
|
849
1094
|
toolName: chunk.toolName,
|
|
850
1095
|
toolCallId: chunk.toolCallId,
|
|
851
|
-
result:
|
|
1096
|
+
result: normalized.result,
|
|
1097
|
+
...normalized.metadata ? { metadata: normalized.metadata } : {}
|
|
852
1098
|
});
|
|
853
1099
|
break;
|
|
1100
|
+
}
|
|
854
1101
|
case "tool-error":
|
|
855
1102
|
await onEvent({
|
|
856
1103
|
type: "tool-error",
|
|
@@ -914,7 +1161,7 @@ async function processStepStream(stream, options) {
|
|
|
914
1161
|
}
|
|
915
1162
|
}
|
|
916
1163
|
} catch (caught) {
|
|
917
|
-
error =
|
|
1164
|
+
error = normalizeError(caught);
|
|
918
1165
|
await onEvent({ type: "status", status: "error" });
|
|
919
1166
|
await onEvent({ type: "error", error });
|
|
920
1167
|
}
|
|
@@ -934,21 +1181,22 @@ async function processStepStream(stream, options) {
|
|
|
934
1181
|
error
|
|
935
1182
|
};
|
|
936
1183
|
}
|
|
937
|
-
var processStream = processStepStream;
|
|
938
1184
|
|
|
939
|
-
// src/
|
|
940
|
-
function
|
|
1185
|
+
// src/execution/turn-runner/stream-step.ts
|
|
1186
|
+
function buildStepModelCallContext(options) {
|
|
941
1187
|
const input = options.preparedStep.inferenceInput;
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1188
|
+
const ctx = buildModelCallContext(input);
|
|
1189
|
+
if (input.step == null) {
|
|
1190
|
+
ctx.step = options.preparedStep.step;
|
|
1191
|
+
}
|
|
1192
|
+
return ctx;
|
|
1193
|
+
}
|
|
1194
|
+
function normalizeModelStepError(options, error) {
|
|
1195
|
+
const model = options.preparedStep.inferenceInput.model;
|
|
1196
|
+
return LLMError.from(error, {
|
|
1197
|
+
provider: extractProvider(model),
|
|
1198
|
+
model: extractModelId(model)
|
|
1199
|
+
});
|
|
952
1200
|
}
|
|
953
1201
|
async function* runModelStep(options) {
|
|
954
1202
|
return yield* streamWithinScope(
|
|
@@ -960,13 +1208,20 @@ async function* runModelStep(options) {
|
|
|
960
1208
|
},
|
|
961
1209
|
(async function* () {
|
|
962
1210
|
const { preparedStep, turnEngine, applyCommitBatch } = options;
|
|
963
|
-
const stream = await Inference.streamStep(preparedStep.inferenceInput);
|
|
964
1211
|
const eventQueue = [];
|
|
965
1212
|
let resolveNext = null;
|
|
966
1213
|
let streamDone = false;
|
|
967
1214
|
let streamError;
|
|
968
1215
|
const intervention = preparedStep.inferenceInput.intervention;
|
|
969
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
|
+
};
|
|
970
1225
|
if (intervention) {
|
|
971
1226
|
intervention.onApplied = (item) => {
|
|
972
1227
|
eventQueue.push({
|
|
@@ -979,10 +1234,26 @@ async function* runModelStep(options) {
|
|
|
979
1234
|
resolveNext = null;
|
|
980
1235
|
}
|
|
981
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
|
+
};
|
|
982
1248
|
}
|
|
1249
|
+
const stream = await Inference.streamStep({
|
|
1250
|
+
...preparedStep.inferenceInput,
|
|
1251
|
+
onEvent: emitQueuedEvent
|
|
1252
|
+
});
|
|
983
1253
|
const processPromise = processStepStream(stream, {
|
|
984
1254
|
sessionID: preparedStep.inferenceInput.sessionID,
|
|
985
1255
|
abort: preparedStep.inferenceInput.abort,
|
|
1256
|
+
normalizeError: (error) => normalizeModelStepError(options, error),
|
|
986
1257
|
currentStep: preparedStep.step,
|
|
987
1258
|
maxSteps: preparedStep.stepProcessing.maxSteps,
|
|
988
1259
|
doomLoopThreshold: preparedStep.stepProcessing.doomLoopThreshold ?? 3,
|
|
@@ -992,14 +1263,7 @@ async function* runModelStep(options) {
|
|
|
992
1263
|
contextTokenLimit: preparedStep.stepProcessing.contextTokenLimit,
|
|
993
1264
|
onContextOverflow: async () => {
|
|
994
1265
|
},
|
|
995
|
-
onEvent:
|
|
996
|
-
middleware?.emitEvent(event);
|
|
997
|
-
eventQueue.push(event);
|
|
998
|
-
if (resolveNext) {
|
|
999
|
-
resolveNext();
|
|
1000
|
-
resolveNext = null;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1266
|
+
onEvent: emitQueuedEvent
|
|
1003
1267
|
}).then((result2) => {
|
|
1004
1268
|
streamDone = true;
|
|
1005
1269
|
if (resolveNext) {
|
|
@@ -1052,7 +1316,7 @@ async function* runModelStep(options) {
|
|
|
1052
1316
|
usage: result.usage,
|
|
1053
1317
|
finishReason: result.finishReason
|
|
1054
1318
|
},
|
|
1055
|
-
|
|
1319
|
+
buildStepModelCallContext(options)
|
|
1056
1320
|
);
|
|
1057
1321
|
result.text = revised.text;
|
|
1058
1322
|
result.usage = revised.usage;
|
|
@@ -1063,8 +1327,7 @@ async function* runModelStep(options) {
|
|
|
1063
1327
|
);
|
|
1064
1328
|
}
|
|
1065
1329
|
|
|
1066
|
-
// src/
|
|
1067
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
1330
|
+
// src/execution/turn-runner/tool-batch.ts
|
|
1068
1331
|
function cloneToolResultRecord(options) {
|
|
1069
1332
|
return new Map(
|
|
1070
1333
|
options.snapshot.toolResults.map((toolResult) => [
|
|
@@ -1073,105 +1336,164 @@ function cloneToolResultRecord(options) {
|
|
|
1073
1336
|
])
|
|
1074
1337
|
);
|
|
1075
1338
|
}
|
|
1076
|
-
function
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
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
|
+
}
|
|
1083
1358
|
}
|
|
1084
|
-
function
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
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
|
+
}
|
|
1091
1434
|
}
|
|
1092
1435
|
async function runToolBatch(options) {
|
|
1093
1436
|
const toolResultsByCallId = cloneToolResultRecord(options);
|
|
1094
1437
|
const events = [];
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
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) {
|
|
1100
1448
|
const tool = options.tools[toolCall.toolName];
|
|
1101
|
-
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1102
1449
|
if (!tool) {
|
|
1103
|
-
|
|
1104
|
-
const event = createToolBatchErrorResult({
|
|
1105
|
-
toolCallId: toolCall.toolCallId,
|
|
1106
|
-
toolName: toolCall.toolName,
|
|
1107
|
-
errorMessage,
|
|
1108
|
-
replayPolicy: toolCall.replayPolicy
|
|
1109
|
-
});
|
|
1110
|
-
events.push(event);
|
|
1111
|
-
toolResultsByCallId.set(toolCall.toolCallId, {
|
|
1112
|
-
toolCallId: toolCall.toolCallId,
|
|
1113
|
-
toolName: toolCall.toolName,
|
|
1114
|
-
result: `Error: ${errorMessage}`,
|
|
1115
|
-
...toolCall.replayPolicy ? { replayPolicy: toolCall.replayPolicy } : {}
|
|
1116
|
-
});
|
|
1117
|
-
if (turnState) {
|
|
1118
|
-
turnState = advanceAgentTurnState(turnState, event, updatedAt, {
|
|
1119
|
-
...toolCall.replayPolicy ? { toolReplayPolicy: toolCall.replayPolicy } : {}
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1450
|
+
serialGroup.push({ toolCall });
|
|
1122
1451
|
continue;
|
|
1123
1452
|
}
|
|
1453
|
+
let safe = false;
|
|
1454
|
+
let initialized;
|
|
1124
1455
|
try {
|
|
1125
|
-
const
|
|
1126
|
-
toolName: toolCall.toolName,
|
|
1456
|
+
const result = await isParallelSafe(
|
|
1127
1457
|
tool,
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
});
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
toolCallId: toolCall.toolCallId,
|
|
1165
|
-
toolName: toolCall.toolName,
|
|
1166
|
-
result: `Error: ${errorMessage}`,
|
|
1167
|
-
...toolCall.replayPolicy ? { replayPolicy: toolCall.replayPolicy } : {}
|
|
1168
|
-
});
|
|
1169
|
-
if (turnState) {
|
|
1170
|
-
turnState = advanceAgentTurnState(turnState, event, updatedAt, {
|
|
1171
|
-
...toolCall.replayPolicy ? { toolReplayPolicy: toolCall.replayPolicy } : {}
|
|
1172
|
-
});
|
|
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;
|
|
1173
1494
|
}
|
|
1174
1495
|
}
|
|
1496
|
+
await executeBatchEntry(toolCall, options, accumulators, initialized);
|
|
1175
1497
|
}
|
|
1176
1498
|
return {
|
|
1177
1499
|
snapshot: {
|
|
@@ -1180,12 +1502,12 @@ async function runToolBatch(options) {
|
|
|
1180
1502
|
),
|
|
1181
1503
|
toolResults: options.snapshot.toolCalls.map((toolCall) => toolResultsByCallId.get(toolCall.toolCallId)).filter((toolResult) => toolResult !== void 0)
|
|
1182
1504
|
},
|
|
1183
|
-
...turnState ? { turnState } : {},
|
|
1505
|
+
...turnState.value ? { turnState: turnState.value } : {},
|
|
1184
1506
|
events
|
|
1185
1507
|
};
|
|
1186
1508
|
}
|
|
1187
1509
|
|
|
1188
|
-
// src/
|
|
1510
|
+
// src/execution/turn-runner/commit.ts
|
|
1189
1511
|
async function* commitStep(options) {
|
|
1190
1512
|
return yield* streamWithinScope(
|
|
1191
1513
|
{
|
|
@@ -1226,10 +1548,7 @@ async function* commitOutput(options) {
|
|
|
1226
1548
|
);
|
|
1227
1549
|
}
|
|
1228
1550
|
|
|
1229
|
-
// src/
|
|
1230
|
-
function cloneUsage2(usage) {
|
|
1231
|
-
return usage ? { ...usage } : void 0;
|
|
1232
|
-
}
|
|
1551
|
+
// src/execution/workflow-state.ts
|
|
1233
1552
|
function cloneMessageSnapshot(message) {
|
|
1234
1553
|
return {
|
|
1235
1554
|
...message,
|
|
@@ -1241,9 +1560,96 @@ function cloneMessageSnapshot(message) {
|
|
|
1241
1560
|
} : {},
|
|
1242
1561
|
...message.role === "assistant" && message.error ? {
|
|
1243
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
|
+
}))
|
|
1244
1608
|
} : {}
|
|
1245
1609
|
};
|
|
1246
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
|
|
1247
1653
|
function snapshotAgentWorkflowMessage(message) {
|
|
1248
1654
|
switch (message.role) {
|
|
1249
1655
|
case "user":
|
|
@@ -1281,6 +1687,7 @@ function snapshotAgentWorkflowMessage(message) {
|
|
|
1281
1687
|
toolCallId: message.toolCallId,
|
|
1282
1688
|
toolName: message.toolName,
|
|
1283
1689
|
result: message.result,
|
|
1690
|
+
...message.metadata ? { metadata: structuredClone(message.metadata) } : {},
|
|
1284
1691
|
...message.compactedAt !== void 0 ? { compactedAt: message.compactedAt } : {}
|
|
1285
1692
|
};
|
|
1286
1693
|
case "system":
|
|
@@ -1293,7 +1700,7 @@ function snapshotAgentWorkflowMessage(message) {
|
|
|
1293
1700
|
}
|
|
1294
1701
|
}
|
|
1295
1702
|
function snapshotAgentWorkflowMessages(messages) {
|
|
1296
|
-
return messages.map(snapshotAgentWorkflowMessage);
|
|
1703
|
+
return messages.map((message) => snapshotAgentWorkflowMessage(message));
|
|
1297
1704
|
}
|
|
1298
1705
|
function restoreAgentWorkflowMessage(snapshot) {
|
|
1299
1706
|
const createdAt = new Date(snapshot.createdAt);
|
|
@@ -1333,6 +1740,7 @@ function restoreAgentWorkflowMessage(snapshot) {
|
|
|
1333
1740
|
toolCallId: snapshot.toolCallId,
|
|
1334
1741
|
toolName: snapshot.toolName,
|
|
1335
1742
|
result: snapshot.result,
|
|
1743
|
+
...snapshot.metadata ? { metadata: structuredClone(snapshot.metadata) } : {},
|
|
1336
1744
|
...snapshot.compactedAt !== void 0 ? { compactedAt: snapshot.compactedAt } : {}
|
|
1337
1745
|
};
|
|
1338
1746
|
case "system":
|
|
@@ -1347,52 +1755,8 @@ function restoreAgentWorkflowMessage(snapshot) {
|
|
|
1347
1755
|
function restoreAgentWorkflowMessages(snapshots) {
|
|
1348
1756
|
return snapshots.map(restoreAgentWorkflowMessage);
|
|
1349
1757
|
}
|
|
1350
|
-
function createAgentWorkflowTurnState(options) {
|
|
1351
|
-
return {
|
|
1352
|
-
sessionId: options.sessionId,
|
|
1353
|
-
systemPrompts: [...options.systemPrompts ?? []],
|
|
1354
|
-
messages: (options.initialMessages ?? []).map(cloneMessageSnapshot),
|
|
1355
|
-
phase: "model-step",
|
|
1356
|
-
step: options.initialStep ?? 1,
|
|
1357
|
-
maxSteps: options.maxSteps,
|
|
1358
|
-
replayDecisions: {},
|
|
1359
|
-
startedAt: options.startedAt,
|
|
1360
|
-
updatedAt: options.startedAt
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
function cloneAgentWorkflowTurnState(state) {
|
|
1364
|
-
return {
|
|
1365
|
-
...state,
|
|
1366
|
-
systemPrompts: [...state.systemPrompts],
|
|
1367
|
-
messages: state.messages.map(cloneMessageSnapshot),
|
|
1368
|
-
...state.usage ? { usage: cloneUsage2(state.usage) } : {},
|
|
1369
|
-
...state.turnState ? { turnState: structuredClone(state.turnState) } : {},
|
|
1370
|
-
...state.lastModelStep ? { lastModelStep: structuredClone(state.lastModelStep) } : {},
|
|
1371
|
-
replayDecisions: Object.fromEntries(
|
|
1372
|
-
Object.entries(state.replayDecisions).map(([toolCallId, decision]) => [
|
|
1373
|
-
toolCallId,
|
|
1374
|
-
{ ...decision }
|
|
1375
|
-
])
|
|
1376
|
-
)
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
1758
|
|
|
1380
|
-
// src/
|
|
1381
|
-
function accumulateWorkflowUsage(current, next) {
|
|
1382
|
-
if (!next) {
|
|
1383
|
-
return current ? { ...current } : void 0;
|
|
1384
|
-
}
|
|
1385
|
-
if (!current) {
|
|
1386
|
-
return { ...next };
|
|
1387
|
-
}
|
|
1388
|
-
return {
|
|
1389
|
-
inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
|
|
1390
|
-
outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
|
|
1391
|
-
totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0),
|
|
1392
|
-
cacheReadTokens: (current.cacheReadTokens ?? 0) + (next.cacheReadTokens ?? 0),
|
|
1393
|
-
cacheWriteTokens: (current.cacheWriteTokens ?? 0) + (next.cacheWriteTokens ?? 0)
|
|
1394
|
-
};
|
|
1395
|
-
}
|
|
1759
|
+
// src/execution/workflow-planner/helpers.ts
|
|
1396
1760
|
function cloneRelevantReplayDecisions(state, snapshot) {
|
|
1397
1761
|
return Object.fromEntries(
|
|
1398
1762
|
snapshot.toolCalls.flatMap((toolCall) => {
|
|
@@ -1401,18 +1765,29 @@ function cloneRelevantReplayDecisions(state, snapshot) {
|
|
|
1401
1765
|
})
|
|
1402
1766
|
);
|
|
1403
1767
|
}
|
|
1404
|
-
function
|
|
1768
|
+
function findAllUnresolvedToolCalls(snapshot) {
|
|
1405
1769
|
const resolvedIds = new Set(
|
|
1406
1770
|
snapshot.toolResults.map((toolResult) => toolResult.toolCallId)
|
|
1407
1771
|
);
|
|
1408
|
-
return snapshot.toolCalls.
|
|
1772
|
+
return snapshot.toolCalls.filter(
|
|
1409
1773
|
(toolCall) => !resolvedIds.has(toolCall.toolCallId)
|
|
1410
1774
|
);
|
|
1411
1775
|
}
|
|
1412
1776
|
|
|
1413
|
-
// src/
|
|
1777
|
+
// src/execution/workflow-planner/plan.ts
|
|
1414
1778
|
function planNextAgentWorkflowOperation(state) {
|
|
1415
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
|
+
};
|
|
1416
1791
|
case "model-step":
|
|
1417
1792
|
return {
|
|
1418
1793
|
kind: "model-step",
|
|
@@ -1428,24 +1803,37 @@ function planNextAgentWorkflowOperation(state) {
|
|
|
1428
1803
|
`Workflow state for session '${state.sessionId}' is in tool-batch phase without a stepCommit snapshot`
|
|
1429
1804
|
);
|
|
1430
1805
|
}
|
|
1431
|
-
const
|
|
1806
|
+
const allUnresolved = findAllUnresolvedToolCalls(
|
|
1432
1807
|
state.lastModelStep.stepCommit
|
|
1433
1808
|
);
|
|
1434
|
-
if (
|
|
1809
|
+
if (allUnresolved.length === 0) {
|
|
1435
1810
|
throw new Error(
|
|
1436
1811
|
`Workflow state for session '${state.sessionId}' is in tool-batch phase without unresolved tool calls`
|
|
1437
1812
|
);
|
|
1438
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
|
+
}
|
|
1439
1827
|
return {
|
|
1440
|
-
kind: "tool-
|
|
1828
|
+
kind: "tool-batch",
|
|
1441
1829
|
step: state.step,
|
|
1442
1830
|
sessionId: state.sessionId,
|
|
1443
|
-
|
|
1831
|
+
toolCalls: allUnresolved.map((tc) => structuredClone(tc)),
|
|
1444
1832
|
turnState: state.turnState ? structuredClone(state.turnState) : void 0,
|
|
1445
|
-
|
|
1833
|
+
replayDecisions: cloneRelevantReplayDecisions(
|
|
1446
1834
|
state,
|
|
1447
1835
|
state.lastModelStep.stepCommit
|
|
1448
|
-
)
|
|
1836
|
+
)
|
|
1449
1837
|
};
|
|
1450
1838
|
}
|
|
1451
1839
|
case "step-commit":
|
|
@@ -1478,12 +1866,12 @@ function planNextAgentWorkflowOperation(state) {
|
|
|
1478
1866
|
}
|
|
1479
1867
|
}
|
|
1480
1868
|
|
|
1481
|
-
// src/
|
|
1869
|
+
// src/execution/workflow-planner/apply.ts
|
|
1482
1870
|
function applyAgentWorkflowModelStepResult(state, result, updatedAt) {
|
|
1483
1871
|
const next = cloneAgentWorkflowTurnState(state);
|
|
1484
1872
|
next.lastModelStep = structuredClone(result);
|
|
1485
1873
|
next.turnState = structuredClone(result.turnState);
|
|
1486
|
-
next.usage =
|
|
1874
|
+
next.usage = accumulateUsage(next.usage, result.usage);
|
|
1487
1875
|
next.updatedAt = updatedAt;
|
|
1488
1876
|
next.phase = result.finishReason === "tool-calls" ? "tool-batch" : "output-commit";
|
|
1489
1877
|
return next;
|
|
@@ -1550,6 +1938,10 @@ function applyAgentWorkflowCommitResult(state, result, updatedAt) {
|
|
|
1550
1938
|
];
|
|
1551
1939
|
next.updatedAt = updatedAt;
|
|
1552
1940
|
switch (state.phase) {
|
|
1941
|
+
case "input-commit":
|
|
1942
|
+
next.phase = "model-step";
|
|
1943
|
+
delete next.pendingInput;
|
|
1944
|
+
return next;
|
|
1553
1945
|
case "step-commit":
|
|
1554
1946
|
next.step = state.step + 1;
|
|
1555
1947
|
next.phase = "model-step";
|
|
@@ -1581,30 +1973,38 @@ function failAgentWorkflowTurnState(state, error, updatedAt) {
|
|
|
1581
1973
|
}
|
|
1582
1974
|
|
|
1583
1975
|
export {
|
|
1584
|
-
convertAgentMessagesToModelMessages,
|
|
1585
1976
|
createAgentTurnStepCommitBatch,
|
|
1586
1977
|
createAgentTurnState,
|
|
1587
1978
|
advanceAgentTurnState,
|
|
1588
1979
|
failAgentTurnState,
|
|
1589
1980
|
AgentTurnEngine,
|
|
1590
1981
|
createAgentTurnEngine,
|
|
1982
|
+
estimateTokens,
|
|
1983
|
+
estimateMessageTokens,
|
|
1984
|
+
estimateConversationTokens,
|
|
1985
|
+
DEFAULT_CONTEXT_LIMITS,
|
|
1986
|
+
getUsableTokenLimit,
|
|
1987
|
+
findCutPoint,
|
|
1988
|
+
ContextManager,
|
|
1591
1989
|
prepareModelStep,
|
|
1592
1990
|
DoomLoopError,
|
|
1593
1991
|
ContextOverflowError,
|
|
1594
1992
|
processStepStream,
|
|
1595
|
-
processStream,
|
|
1596
1993
|
runModelStep,
|
|
1597
1994
|
runToolBatch,
|
|
1598
1995
|
commitStep,
|
|
1599
1996
|
commitOutput,
|
|
1600
1997
|
defaultAgentTaskCheckpointStrategy,
|
|
1601
1998
|
createAgentTaskRunner,
|
|
1999
|
+
createAgentWorkflowTurnState,
|
|
2000
|
+
cloneAgentWorkflowTurnState,
|
|
2001
|
+
applyWorkflowInterventions,
|
|
2002
|
+
drainWorkflowInterventions,
|
|
2003
|
+
queueWorkflowFollowUps,
|
|
1602
2004
|
snapshotAgentWorkflowMessage,
|
|
1603
2005
|
snapshotAgentWorkflowMessages,
|
|
1604
2006
|
restoreAgentWorkflowMessage,
|
|
1605
2007
|
restoreAgentWorkflowMessages,
|
|
1606
|
-
createAgentWorkflowTurnState,
|
|
1607
|
-
cloneAgentWorkflowTurnState,
|
|
1608
2008
|
planNextAgentWorkflowOperation,
|
|
1609
2009
|
applyAgentWorkflowModelStepResult,
|
|
1610
2010
|
applyAgentWorkflowToolBatchResult,
|