@axlsdk/axl 0.19.1 → 0.20.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 +27 -11
- package/dist/{chunk-JBLQKU6X.js → chunk-NVPA4RY6.js} +6 -4
- package/dist/chunk-NVPA4RY6.js.map +1 -0
- package/dist/index.cjs +1838 -857
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +510 -257
- package/dist/index.d.ts +510 -257
- package/dist/index.js +1752 -780
- package/dist/index.js.map +1 -1
- package/dist/span-manager-74ZCGELO.js +7 -0
- package/package.json +2 -2
- package/dist/chunk-JBLQKU6X.js.map +0 -1
- package/dist/span-manager-3IKXXUTZ.js +0 -7
- /package/dist/{span-manager-3IKXXUTZ.js.map → span-manager-74ZCGELO.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -65,6 +65,7 @@ var init_span_manager = __esm({
|
|
|
65
65
|
async withSpanAsync(name, attributes, fn) {
|
|
66
66
|
const otelApi = this.otelApi;
|
|
67
67
|
return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan) => {
|
|
68
|
+
let statusWasSet = false;
|
|
68
69
|
const handle = {
|
|
69
70
|
setAttribute(key, value) {
|
|
70
71
|
otelSpan.setAttribute(key, value);
|
|
@@ -73,7 +74,8 @@ var init_span_manager = __esm({
|
|
|
73
74
|
otelSpan.addEvent(eventName, attrs);
|
|
74
75
|
},
|
|
75
76
|
setStatus(code, message) {
|
|
76
|
-
|
|
77
|
+
statusWasSet = true;
|
|
78
|
+
const statusCode = code === "ok" ? otelApi.SpanStatusCode.OK : code === "error" ? otelApi.SpanStatusCode.ERROR : otelApi.SpanStatusCode.UNSET;
|
|
77
79
|
otelSpan.setStatus({ code: statusCode, message });
|
|
78
80
|
},
|
|
79
81
|
end() {
|
|
@@ -82,10 +84,10 @@ var init_span_manager = __esm({
|
|
|
82
84
|
};
|
|
83
85
|
try {
|
|
84
86
|
const result = await fn(handle);
|
|
85
|
-
handle.setStatus("ok");
|
|
87
|
+
if (!statusWasSet) handle.setStatus("ok");
|
|
86
88
|
return result;
|
|
87
89
|
} catch (err) {
|
|
88
|
-
handle.setStatus("error"
|
|
90
|
+
handle.setStatus("error");
|
|
89
91
|
throw err;
|
|
90
92
|
} finally {
|
|
91
93
|
handle.end();
|
|
@@ -111,6 +113,8 @@ var init_span_manager = __esm({
|
|
|
111
113
|
var index_exports = {};
|
|
112
114
|
__export(index_exports, {
|
|
113
115
|
AXL_EVENT_TYPES: () => AXL_EVENT_TYPES,
|
|
116
|
+
AXL_EVENT_TYPES_V2: () => AXL_EVENT_TYPES_V2,
|
|
117
|
+
AXL_TOOL_LIFECYCLE_TYPES_V2: () => AXL_TOOL_LIFECYCLE_TYPES_V2,
|
|
114
118
|
AZURE_PROFILE: () => AZURE_PROFILE,
|
|
115
119
|
AnthropicProvider: () => AnthropicProvider,
|
|
116
120
|
AxlError: () => AxlError,
|
|
@@ -158,8 +162,9 @@ __export(index_exports, {
|
|
|
158
162
|
SqliteVectorStore: () => SqliteVectorStore,
|
|
159
163
|
ThinkTagScanner: () => ThinkTagScanner,
|
|
160
164
|
TimeoutError: () => TimeoutError,
|
|
161
|
-
|
|
165
|
+
ToolFailure: () => ToolFailure,
|
|
162
166
|
ToolModelOutputError: () => ToolModelOutputError,
|
|
167
|
+
UnsupportedEventSchemaVersionError: () => UnsupportedEventSchemaVersionError,
|
|
163
168
|
VLLM_PROFILE: () => VLLM_PROFILE,
|
|
164
169
|
ValidationError: () => ValidationError,
|
|
165
170
|
VerifyError: () => VerifyError,
|
|
@@ -174,6 +179,8 @@ __export(index_exports, {
|
|
|
174
179
|
extractJson: () => extractJson,
|
|
175
180
|
extractThinkTags: () => extractThinkTags,
|
|
176
181
|
findConfig: () => findConfig,
|
|
182
|
+
getEventSchemaVersion: () => getEventSchemaVersion,
|
|
183
|
+
getExecutionEventSchemaVersion: () => getExecutionEventSchemaVersion,
|
|
177
184
|
hasPositiveTokens: () => hasPositiveTokens,
|
|
178
185
|
importModule: () => importModule,
|
|
179
186
|
isCostBearingLeaf: () => isCostBearingLeaf,
|
|
@@ -182,6 +189,7 @@ __export(index_exports, {
|
|
|
182
189
|
isUnpricedLeaf: () => isUnpricedLeaf,
|
|
183
190
|
isUsableCost: () => isUsableCost,
|
|
184
191
|
needsTsxLoader: () => needsTsxLoader,
|
|
192
|
+
normalizeStoredExecution: () => normalizeStoredExecution,
|
|
185
193
|
openaiReasoningEmit: () => openaiReasoningEmit,
|
|
186
194
|
parsePartialJson: () => parsePartialJson,
|
|
187
195
|
pickDefault: () => pickDefault,
|
|
@@ -190,6 +198,7 @@ __export(index_exports, {
|
|
|
190
198
|
reasoningEffortEmit: () => reasoningEffortEmit,
|
|
191
199
|
reasoningObjectEmit: () => reasoningObjectEmit,
|
|
192
200
|
redactEvent: () => redactEvent,
|
|
201
|
+
redactHistoricalEvent: () => redactHistoricalEvent,
|
|
193
202
|
registerConditions: () => registerConditions,
|
|
194
203
|
resolveApiKey: () => resolveApiKey,
|
|
195
204
|
resolvePerModel: () => resolvePerModel,
|
|
@@ -203,128 +212,7 @@ __export(index_exports, {
|
|
|
203
212
|
module.exports = __toCommonJS(index_exports);
|
|
204
213
|
|
|
205
214
|
// src/tool.ts
|
|
206
|
-
var
|
|
207
|
-
function validateStringLengths(value, maxLen, path = "") {
|
|
208
|
-
if (typeof value === "string") {
|
|
209
|
-
if (value.length > maxLen) {
|
|
210
|
-
throw new Error(
|
|
211
|
-
`String argument${path ? ` at "${path}"` : ""} exceeds maximum length (${value.length} > ${maxLen})`
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
} else if (Array.isArray(value)) {
|
|
215
|
-
for (let i = 0; i < value.length; i++) {
|
|
216
|
-
validateStringLengths(value[i], maxLen, path ? `${path}[${i}]` : `[${i}]`);
|
|
217
|
-
}
|
|
218
|
-
} else if (value !== null && typeof value === "object") {
|
|
219
|
-
for (const [key, val] of Object.entries(value)) {
|
|
220
|
-
validateStringLengths(val, maxLen, path ? `${path}.${key}` : key);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
function sleep(ms) {
|
|
225
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
226
|
-
}
|
|
227
|
-
function getBackoffMs(attempt, strategy) {
|
|
228
|
-
switch (strategy) {
|
|
229
|
-
case "none":
|
|
230
|
-
return 0;
|
|
231
|
-
case "linear":
|
|
232
|
-
return attempt * 1e3;
|
|
233
|
-
case "exponential":
|
|
234
|
-
return Math.pow(2, attempt - 1) * 1e3;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
function tool(config) {
|
|
238
|
-
const retryPolicy = {
|
|
239
|
-
attempts: config.retry?.attempts ?? 1,
|
|
240
|
-
backoff: config.retry?.backoff ?? "exponential",
|
|
241
|
-
on: config.retry?.on
|
|
242
|
-
};
|
|
243
|
-
const maxStringLen = config.maxStringLength ?? DEFAULT_MAX_STRING_LENGTH;
|
|
244
|
-
const execute = async (input, ctx) => {
|
|
245
|
-
const parsed = config.input.parse(input);
|
|
246
|
-
if (maxStringLen > 0) {
|
|
247
|
-
validateStringLengths(parsed, maxStringLen);
|
|
248
|
-
}
|
|
249
|
-
const maxAttempts = retryPolicy.attempts ?? 1;
|
|
250
|
-
let lastError;
|
|
251
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
252
|
-
try {
|
|
253
|
-
return await config.handler(parsed, ctx);
|
|
254
|
-
} catch (err) {
|
|
255
|
-
lastError = err instanceof Error ? err : new Error(String(err));
|
|
256
|
-
if (attempt === maxAttempts) break;
|
|
257
|
-
if (retryPolicy.on && !retryPolicy.on(lastError)) {
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
const backoffMs = getBackoffMs(attempt, retryPolicy.backoff ?? "exponential");
|
|
261
|
-
if (backoffMs > 0) {
|
|
262
|
-
await sleep(backoffMs);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
throw lastError;
|
|
267
|
-
};
|
|
268
|
-
return {
|
|
269
|
-
name: config.name,
|
|
270
|
-
description: config.description,
|
|
271
|
-
inputSchema: config.input,
|
|
272
|
-
sensitive: config.sensitive ?? false,
|
|
273
|
-
retry: retryPolicy,
|
|
274
|
-
requireApproval: config.requireApproval ?? false,
|
|
275
|
-
hooks: config.hooks,
|
|
276
|
-
...config.toModelOutput !== void 0 ? { toModelOutput: config.toModelOutput } : {},
|
|
277
|
-
async run(ctx, input) {
|
|
278
|
-
const startTime = Date.now();
|
|
279
|
-
try {
|
|
280
|
-
let processedInput = input;
|
|
281
|
-
if (config.hooks?.before) {
|
|
282
|
-
processedInput = await config.hooks.before(processedInput, ctx);
|
|
283
|
-
}
|
|
284
|
-
let result = await execute(processedInput, ctx);
|
|
285
|
-
if (config.hooks?.after) {
|
|
286
|
-
result = await config.hooks.after(result, ctx);
|
|
287
|
-
}
|
|
288
|
-
ctx.log("tool_call_complete", {
|
|
289
|
-
tool: config.name,
|
|
290
|
-
duration: Date.now() - startTime
|
|
291
|
-
});
|
|
292
|
-
return result;
|
|
293
|
-
} catch (err) {
|
|
294
|
-
ctx.log("tool_call_error", {
|
|
295
|
-
tool: config.name,
|
|
296
|
-
error: err instanceof Error ? err.message : String(err),
|
|
297
|
-
duration: Date.now() - startTime
|
|
298
|
-
});
|
|
299
|
-
throw err;
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
_execute: execute
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// src/providers/types.ts
|
|
307
|
-
function resolveThinkingOptions(options) {
|
|
308
|
-
if (options.thinkingBudget !== void 0 && options.thinkingBudget < 0) {
|
|
309
|
-
throw new Error(`thinkingBudget must be non-negative, got ${options.thinkingBudget}`);
|
|
310
|
-
}
|
|
311
|
-
const effort = options.effort;
|
|
312
|
-
const thinkingBudget = options.thinkingBudget;
|
|
313
|
-
const hasBudgetOverride = thinkingBudget !== void 0 && thinkingBudget > 0;
|
|
314
|
-
return {
|
|
315
|
-
effort,
|
|
316
|
-
thinkingBudget,
|
|
317
|
-
includeThoughts: options.includeThoughts ?? false,
|
|
318
|
-
// Budget override wins: effort: 'none' + thinkingBudget: 5000 → thinking enabled
|
|
319
|
-
thinkingDisabled: (effort === "none" || thinkingBudget === 0) && !hasBudgetOverride,
|
|
320
|
-
activeEffort: effort && effort !== "none" ? effort : void 0,
|
|
321
|
-
hasBudgetOverride
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
async function resolveApiKey(source) {
|
|
325
|
-
if (typeof source === "function") return await source() ?? "";
|
|
326
|
-
return source ?? "";
|
|
327
|
-
}
|
|
215
|
+
var import_zod = require("zod");
|
|
328
216
|
|
|
329
217
|
// src/errors.ts
|
|
330
218
|
var AxlError = class extends Error {
|
|
@@ -335,6 +223,55 @@ var AxlError = class extends Error {
|
|
|
335
223
|
this.code = code;
|
|
336
224
|
}
|
|
337
225
|
};
|
|
226
|
+
var EventStreamOverflowError = class extends Error {
|
|
227
|
+
maxQueued;
|
|
228
|
+
eventType;
|
|
229
|
+
constructor(maxQueued, eventType, cause) {
|
|
230
|
+
super(
|
|
231
|
+
`AxlEventBus queue exceeded maxQueued=${maxQueued} (event type: ${eventType}). Consumer is too slow or the producer is unbounded. Configure \`maxQueued\`/\`onOverflow\` on the runtime, or set maxQueued: Infinity to disable.`
|
|
232
|
+
);
|
|
233
|
+
this.name = "EventStreamOverflowError";
|
|
234
|
+
this.maxQueued = maxQueued;
|
|
235
|
+
this.eventType = eventType;
|
|
236
|
+
if (cause !== void 0) {
|
|
237
|
+
Object.defineProperty(this, "cause", {
|
|
238
|
+
configurable: true,
|
|
239
|
+
enumerable: false,
|
|
240
|
+
value: cause
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
function isEventStreamOverflowError(error) {
|
|
246
|
+
return error instanceof EventStreamOverflowError;
|
|
247
|
+
}
|
|
248
|
+
function rethrowEventStreamOverflow(error) {
|
|
249
|
+
if (isEventStreamOverflowError(error)) throw error;
|
|
250
|
+
}
|
|
251
|
+
function preserveErrorCause(error, cause) {
|
|
252
|
+
if (cause === void 0 || cause === error || "cause" in error) return error;
|
|
253
|
+
Object.defineProperty(error, "cause", {
|
|
254
|
+
configurable: true,
|
|
255
|
+
enumerable: false,
|
|
256
|
+
value: cause
|
|
257
|
+
});
|
|
258
|
+
return error;
|
|
259
|
+
}
|
|
260
|
+
var ToolFailure = class extends AxlError {
|
|
261
|
+
modelMessage;
|
|
262
|
+
constructor(options) {
|
|
263
|
+
super(options.code ?? "TOOL_FAILURE", options.message);
|
|
264
|
+
this.name = "ToolFailure";
|
|
265
|
+
this.modelMessage = options.modelMessage;
|
|
266
|
+
if (options.cause !== void 0) {
|
|
267
|
+
Object.defineProperty(this, "cause", {
|
|
268
|
+
configurable: true,
|
|
269
|
+
enumerable: false,
|
|
270
|
+
value: options.cause
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
338
275
|
var ToolModelOutputError = class extends AxlError {
|
|
339
276
|
toolName;
|
|
340
277
|
cause;
|
|
@@ -440,19 +377,209 @@ var ValidationError = class extends AxlError {
|
|
|
440
377
|
this.retries = retries;
|
|
441
378
|
}
|
|
442
379
|
};
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
380
|
+
|
|
381
|
+
// src/tool.ts
|
|
382
|
+
var DEFAULT_MAX_STRING_LENGTH = 1e4;
|
|
383
|
+
var ToolStringLengthError = class extends Error {
|
|
384
|
+
constructor(path, actual, maximum) {
|
|
385
|
+
const renderedPath = path.reduce(
|
|
386
|
+
(current, part) => typeof part === "number" ? `${current}[${part}]` : current ? `${current}.${part}` : part,
|
|
387
|
+
""
|
|
388
|
+
);
|
|
447
389
|
super(
|
|
448
|
-
"
|
|
449
|
-
`Agent "${agentName}" attempted to call tool "${toolName}" which is not in its ACL`
|
|
390
|
+
`String argument${renderedPath ? ` at "${renderedPath}"` : ""} exceeds maximum length (${actual} > ${maximum})`
|
|
450
391
|
);
|
|
451
|
-
this.
|
|
452
|
-
this.
|
|
453
|
-
this.
|
|
392
|
+
this.path = path;
|
|
393
|
+
this.actual = actual;
|
|
394
|
+
this.maximum = maximum;
|
|
395
|
+
this.name = "ToolStringLengthError";
|
|
454
396
|
}
|
|
455
397
|
};
|
|
398
|
+
function validateStringLengths(value, maxLen, path = []) {
|
|
399
|
+
if (typeof value === "string") {
|
|
400
|
+
if (value.length > maxLen) {
|
|
401
|
+
throw new ToolStringLengthError(path, value.length, maxLen);
|
|
402
|
+
}
|
|
403
|
+
} else if (Array.isArray(value)) {
|
|
404
|
+
for (let i = 0; i < value.length; i++) {
|
|
405
|
+
validateStringLengths(value[i], maxLen, [...path, i]);
|
|
406
|
+
}
|
|
407
|
+
} else if (value !== null && typeof value === "object") {
|
|
408
|
+
for (const [key, val] of Object.entries(value)) {
|
|
409
|
+
validateStringLengths(val, maxLen, [...path, key]);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function sleep(ms, signal) {
|
|
414
|
+
if (!signal) return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
415
|
+
signal.throwIfAborted();
|
|
416
|
+
return new Promise((resolve2, reject) => {
|
|
417
|
+
const timeout = setTimeout(() => {
|
|
418
|
+
signal.removeEventListener("abort", onAbort);
|
|
419
|
+
resolve2();
|
|
420
|
+
}, ms);
|
|
421
|
+
const onAbort = () => {
|
|
422
|
+
clearTimeout(timeout);
|
|
423
|
+
reject(signal.reason);
|
|
424
|
+
};
|
|
425
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function isAbortError(error) {
|
|
429
|
+
try {
|
|
430
|
+
return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
431
|
+
} catch {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function toolArgumentIssues(error) {
|
|
436
|
+
if (error instanceof import_zod.ZodError) {
|
|
437
|
+
return error.issues.map((issue) => ({
|
|
438
|
+
path: issue.path.map((part) => typeof part === "symbol" ? String(part) : part),
|
|
439
|
+
code: issue.code,
|
|
440
|
+
message: issue.message
|
|
441
|
+
}));
|
|
442
|
+
}
|
|
443
|
+
if (error instanceof ToolStringLengthError) {
|
|
444
|
+
return [
|
|
445
|
+
{
|
|
446
|
+
path: error.path,
|
|
447
|
+
code: "too_big",
|
|
448
|
+
message: error.message
|
|
449
|
+
}
|
|
450
|
+
];
|
|
451
|
+
}
|
|
452
|
+
return [{ path: [], code: "invalid_arguments", message: "Tool arguments are invalid." }];
|
|
453
|
+
}
|
|
454
|
+
var TOOL_INTERNALS = /* @__PURE__ */ new WeakMap();
|
|
455
|
+
function getToolInternals(tool2) {
|
|
456
|
+
const internals = TOOL_INTERNALS.get(tool2);
|
|
457
|
+
if (!internals) throw new Error(`Tool "${tool2.name}" was not created by tool()`);
|
|
458
|
+
return internals;
|
|
459
|
+
}
|
|
460
|
+
function prepareToolInput(tool2, input) {
|
|
461
|
+
return getToolInternals(tool2).prepareInput(input);
|
|
462
|
+
}
|
|
463
|
+
function executePreparedTool(tool2, input, ctx, options) {
|
|
464
|
+
return getToolInternals(tool2).executePrepared(input, ctx, options);
|
|
465
|
+
}
|
|
466
|
+
function getBackoffMs(attempt, strategy) {
|
|
467
|
+
switch (strategy) {
|
|
468
|
+
case "none":
|
|
469
|
+
return 0;
|
|
470
|
+
case "linear":
|
|
471
|
+
return attempt * 1e3;
|
|
472
|
+
case "exponential":
|
|
473
|
+
return Math.pow(2, attempt - 1) * 1e3;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function tool(config) {
|
|
477
|
+
const retryPolicy = {
|
|
478
|
+
attempts: config.retry?.attempts ?? 1,
|
|
479
|
+
backoff: config.retry?.backoff ?? "exponential",
|
|
480
|
+
on: config.retry?.on
|
|
481
|
+
};
|
|
482
|
+
const maxStringLen = config.maxStringLength ?? DEFAULT_MAX_STRING_LENGTH;
|
|
483
|
+
const prepareInput = (input) => {
|
|
484
|
+
const parsed = config.input.parse(input);
|
|
485
|
+
if (maxStringLen > 0) {
|
|
486
|
+
validateStringLengths(parsed, maxStringLen);
|
|
487
|
+
}
|
|
488
|
+
return parsed;
|
|
489
|
+
};
|
|
490
|
+
const executePrepared = async (parsed, ctx, options) => {
|
|
491
|
+
const maxAttempts = retryPolicy.attempts ?? 1;
|
|
492
|
+
let lastError;
|
|
493
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
494
|
+
options?.signal?.throwIfAborted();
|
|
495
|
+
options?.onAttempt?.(attempt);
|
|
496
|
+
try {
|
|
497
|
+
const result = await config.handler(parsed, ctx);
|
|
498
|
+
if (options?.checkAfterHandlerAbort !== false) options?.signal?.throwIfAborted();
|
|
499
|
+
return result;
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (options?.signal?.aborted) options.signal.throwIfAborted();
|
|
502
|
+
if (isAbortError(err)) throw err;
|
|
503
|
+
rethrowEventStreamOverflow(err);
|
|
504
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
505
|
+
if (attempt === maxAttempts) break;
|
|
506
|
+
if (retryPolicy.on && !retryPolicy.on(lastError)) {
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
const backoffMs = getBackoffMs(attempt, retryPolicy.backoff ?? "exponential");
|
|
510
|
+
if (backoffMs > 0) {
|
|
511
|
+
await sleep(backoffMs, options?.signal);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
throw lastError;
|
|
516
|
+
};
|
|
517
|
+
const execute = async (input, ctx) => executePrepared(prepareInput(input), ctx);
|
|
518
|
+
const instance = {
|
|
519
|
+
name: config.name,
|
|
520
|
+
description: config.description,
|
|
521
|
+
inputSchema: config.input,
|
|
522
|
+
sensitive: config.sensitive ?? false,
|
|
523
|
+
retry: retryPolicy,
|
|
524
|
+
requireApproval: config.requireApproval ?? false,
|
|
525
|
+
hooks: config.hooks,
|
|
526
|
+
...config.toModelOutput !== void 0 ? { toModelOutput: config.toModelOutput } : {},
|
|
527
|
+
async run(ctx, input) {
|
|
528
|
+
const startTime = Date.now();
|
|
529
|
+
try {
|
|
530
|
+
let processedInput = input;
|
|
531
|
+
if (config.hooks?.before) {
|
|
532
|
+
processedInput = await config.hooks.before(processedInput, ctx);
|
|
533
|
+
}
|
|
534
|
+
let result = await execute(processedInput, ctx);
|
|
535
|
+
if (config.hooks?.after) {
|
|
536
|
+
result = await config.hooks.after(result, ctx);
|
|
537
|
+
}
|
|
538
|
+
ctx.log("tool_call_complete", {
|
|
539
|
+
tool: config.name,
|
|
540
|
+
duration: Date.now() - startTime
|
|
541
|
+
});
|
|
542
|
+
return result;
|
|
543
|
+
} catch (err) {
|
|
544
|
+
ctx.log("tool_call_error", {
|
|
545
|
+
tool: config.name,
|
|
546
|
+
error: err instanceof Error ? err.message : String(err),
|
|
547
|
+
duration: Date.now() - startTime
|
|
548
|
+
});
|
|
549
|
+
throw err;
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
_execute: execute
|
|
553
|
+
};
|
|
554
|
+
TOOL_INTERNALS.set(instance, {
|
|
555
|
+
prepareInput,
|
|
556
|
+
executePrepared
|
|
557
|
+
});
|
|
558
|
+
return instance;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/providers/types.ts
|
|
562
|
+
function resolveThinkingOptions(options) {
|
|
563
|
+
if (options.thinkingBudget !== void 0 && options.thinkingBudget < 0) {
|
|
564
|
+
throw new Error(`thinkingBudget must be non-negative, got ${options.thinkingBudget}`);
|
|
565
|
+
}
|
|
566
|
+
const effort = options.effort;
|
|
567
|
+
const thinkingBudget = options.thinkingBudget;
|
|
568
|
+
const hasBudgetOverride = thinkingBudget !== void 0 && thinkingBudget > 0;
|
|
569
|
+
return {
|
|
570
|
+
effort,
|
|
571
|
+
thinkingBudget,
|
|
572
|
+
includeThoughts: options.includeThoughts ?? false,
|
|
573
|
+
// Budget override wins: effort: 'none' + thinkingBudget: 5000 → thinking enabled
|
|
574
|
+
thinkingDisabled: (effort === "none" || thinkingBudget === 0) && !hasBudgetOverride,
|
|
575
|
+
activeEffort: effort && effort !== "none" ? effort : void 0,
|
|
576
|
+
hasBudgetOverride
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
async function resolveApiKey(source) {
|
|
580
|
+
if (typeof source === "function") return await source() ?? "";
|
|
581
|
+
return source ?? "";
|
|
582
|
+
}
|
|
456
583
|
|
|
457
584
|
// src/providers/errors.ts
|
|
458
585
|
var ProviderError = class extends AxlError {
|
|
@@ -561,7 +688,7 @@ function sleep2(ms, signal) {
|
|
|
561
688
|
);
|
|
562
689
|
});
|
|
563
690
|
}
|
|
564
|
-
function
|
|
691
|
+
function isAbortError2(err, signal) {
|
|
565
692
|
if (signal?.aborted) return true;
|
|
566
693
|
return typeof err === "object" && err !== null && "name" in err && err.name === "AbortError";
|
|
567
694
|
}
|
|
@@ -580,7 +707,7 @@ async function fetchWithRetry(input, init, opts) {
|
|
|
580
707
|
try {
|
|
581
708
|
res = await fetch(input, init);
|
|
582
709
|
} catch (err) {
|
|
583
|
-
if (
|
|
710
|
+
if (isAbortError2(err, init?.signal ?? void 0)) throw err;
|
|
584
711
|
if (attempt >= maxRetries) {
|
|
585
712
|
throw buildProviderError({
|
|
586
713
|
provider,
|
|
@@ -3262,7 +3389,7 @@ var defaultRegistry = new ProviderRegistry();
|
|
|
3262
3389
|
// src/context.ts
|
|
3263
3390
|
var import_node_async_hooks = require("async_hooks");
|
|
3264
3391
|
var import_node_crypto = require("crypto");
|
|
3265
|
-
var
|
|
3392
|
+
var import_zod2 = require("zod");
|
|
3266
3393
|
|
|
3267
3394
|
// src/partial-json.ts
|
|
3268
3395
|
var MAX_DEPTH = 256;
|
|
@@ -3881,9 +4008,9 @@ var AXL_EVENT_TYPES = [
|
|
|
3881
4008
|
// Tool invocation lifecycle
|
|
3882
4009
|
"tool_call_start",
|
|
3883
4010
|
"tool_call_end",
|
|
4011
|
+
"tool_call_rejected",
|
|
3884
4012
|
// Single-point tool events
|
|
3885
4013
|
"tool_approval",
|
|
3886
|
-
"tool_denied",
|
|
3887
4014
|
// Delegation
|
|
3888
4015
|
"delegate",
|
|
3889
4016
|
// Handoff (spans two asks; not AskScoped).
|
|
@@ -3914,7 +4041,7 @@ var AXL_EVENT_TYPES = [
|
|
|
3914
4041
|
"memory_remember",
|
|
3915
4042
|
"memory_recall",
|
|
3916
4043
|
"memory_forget",
|
|
3917
|
-
//
|
|
4044
|
+
// Scoped execution checkpoints (`ctx.checkpoint`)
|
|
3918
4045
|
"checkpoint_save",
|
|
3919
4046
|
"checkpoint_replay",
|
|
3920
4047
|
// Human-in-the-loop (`ctx.awaitHuman`)
|
|
@@ -3929,6 +4056,12 @@ var AXL_EVENT_TYPES = [
|
|
|
3929
4056
|
"done",
|
|
3930
4057
|
"error"
|
|
3931
4058
|
];
|
|
4059
|
+
var AXL_EVENT_TYPES_V2 = AXL_EVENT_TYPES;
|
|
4060
|
+
var AXL_TOOL_LIFECYCLE_TYPES_V2 = [
|
|
4061
|
+
"tool_call_start",
|
|
4062
|
+
"tool_call_end",
|
|
4063
|
+
"tool_call_rejected"
|
|
4064
|
+
];
|
|
3932
4065
|
|
|
3933
4066
|
// src/event-stream.ts
|
|
3934
4067
|
var STREAM_EVENTS = new Set(AXL_EVENT_TYPES);
|
|
@@ -3944,8 +4077,8 @@ var LIFECYCLE_TYPES = /* @__PURE__ */ new Set([
|
|
|
3944
4077
|
"agent_call_end",
|
|
3945
4078
|
"tool_call_start",
|
|
3946
4079
|
"tool_call_end",
|
|
4080
|
+
"tool_call_rejected",
|
|
3947
4081
|
"tool_approval",
|
|
3948
|
-
"tool_denied",
|
|
3949
4082
|
"handoff_start",
|
|
3950
4083
|
"handoff_return",
|
|
3951
4084
|
"delegate",
|
|
@@ -3959,18 +4092,6 @@ var LIFECYCLE_TYPES = /* @__PURE__ */ new Set([
|
|
|
3959
4092
|
"await_human",
|
|
3960
4093
|
"await_human_resolved"
|
|
3961
4094
|
]);
|
|
3962
|
-
var EventStreamOverflowError = class extends Error {
|
|
3963
|
-
maxQueued;
|
|
3964
|
-
eventType;
|
|
3965
|
-
constructor(maxQueued, eventType) {
|
|
3966
|
-
super(
|
|
3967
|
-
`AxlEventBus queue exceeded maxQueued=${maxQueued} (event type: ${eventType}). Consumer is too slow or the producer is unbounded. Configure \`maxQueued\`/\`onOverflow\` on the runtime, or set maxQueued: Infinity to disable.`
|
|
3968
|
-
);
|
|
3969
|
-
this.name = "EventStreamOverflowError";
|
|
3970
|
-
this.maxQueued = maxQueued;
|
|
3971
|
-
this.eventType = eventType;
|
|
3972
|
-
}
|
|
3973
|
-
};
|
|
3974
4095
|
var DEFAULT_MAX_QUEUED = 1e4;
|
|
3975
4096
|
var DEFAULT_OVERFLOW = "drop-oldest-non-terminal";
|
|
3976
4097
|
var AxlEventBus = class {
|
|
@@ -3981,6 +4102,7 @@ var AxlEventBus = class {
|
|
|
3981
4102
|
maxQueued;
|
|
3982
4103
|
onOverflow;
|
|
3983
4104
|
overflowWarned = false;
|
|
4105
|
+
droppedEvents = 0;
|
|
3984
4106
|
/** Callbacks fired exactly once when `_finish()` is called. Used by
|
|
3985
4107
|
* curated views (e.g., `partialObjects`) that are listener-based and
|
|
3986
4108
|
* need a termination signal independent of any synthetic `done` event. */
|
|
@@ -4026,6 +4148,10 @@ var AxlEventBus = class {
|
|
|
4026
4148
|
* can be 4 KB+ each, hence the more aggressive cleanup here).
|
|
4027
4149
|
*/
|
|
4028
4150
|
stringStreamByAsk = /* @__PURE__ */ new Map();
|
|
4151
|
+
/** Internal fan-out for `stringStream()` subscribers. Kept separate from
|
|
4152
|
+
* the public EventEmitter so strict curated-view overflow is a runtime
|
|
4153
|
+
* signal, not mistaken for (and swallowed as) a buggy user listener. */
|
|
4154
|
+
stringStreamSubscribers = /* @__PURE__ */ new Set();
|
|
4029
4155
|
/**
|
|
4030
4156
|
* Hook fired when an iterator obtained from `[Symbol.asyncIterator]`
|
|
4031
4157
|
* is `await using`-disposed. Set via the second constructor argument.
|
|
@@ -4059,6 +4185,12 @@ var AxlEventBus = class {
|
|
|
4059
4185
|
this.bus.on("error", () => {
|
|
4060
4186
|
});
|
|
4061
4187
|
}
|
|
4188
|
+
/** Machine-readable completeness across this bus's bounded iterable views.
|
|
4189
|
+
* EventEmitter listener delivery is independent and is not described by
|
|
4190
|
+
* this status. */
|
|
4191
|
+
get observationStatus() {
|
|
4192
|
+
return this.droppedEvents === 0 ? { complete: true } : { complete: false, reason: "queue_overflow", droppedEvents: this.droppedEvents };
|
|
4193
|
+
}
|
|
4062
4194
|
unknownEventWarned = false;
|
|
4063
4195
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4064
4196
|
on(event, handler) {
|
|
@@ -4371,7 +4503,7 @@ var AxlEventBus = class {
|
|
|
4371
4503
|
}
|
|
4372
4504
|
return {
|
|
4373
4505
|
[Symbol.asyncIterator]() {
|
|
4374
|
-
const pending =
|
|
4506
|
+
const pending = /* @__PURE__ */ new Map();
|
|
4375
4507
|
let resolveWaiter = null;
|
|
4376
4508
|
let finished = self.finished;
|
|
4377
4509
|
let unsubscribed = false;
|
|
@@ -4385,10 +4517,39 @@ var AxlEventBus = class {
|
|
|
4385
4517
|
if (filterPath !== void 0 && path !== filterPath) return false;
|
|
4386
4518
|
return true;
|
|
4387
4519
|
};
|
|
4520
|
+
const pendingKey = (askId, path) => JSON.stringify([askId, path]);
|
|
4521
|
+
const enqueue = (event) => {
|
|
4522
|
+
const key = pendingKey(event.askId, event.path);
|
|
4523
|
+
const existing = pending.get(key);
|
|
4524
|
+
if (existing) {
|
|
4525
|
+
pending.set(key, {
|
|
4526
|
+
...event,
|
|
4527
|
+
delta: existing.delta + event.delta
|
|
4528
|
+
});
|
|
4529
|
+
wakeWaiter();
|
|
4530
|
+
return;
|
|
4531
|
+
}
|
|
4532
|
+
if (pending.size >= self.maxQueued) {
|
|
4533
|
+
if (self.onOverflow === "throw") {
|
|
4534
|
+
self.droppedEvents++;
|
|
4535
|
+
throw new EventStreamOverflowError(self.maxQueued, "string_delta");
|
|
4536
|
+
}
|
|
4537
|
+
const oldest = pending.keys().next().value;
|
|
4538
|
+
if (oldest !== void 0) {
|
|
4539
|
+
pending.delete(oldest);
|
|
4540
|
+
self.droppedEvents++;
|
|
4541
|
+
}
|
|
4542
|
+
self.warnOverflow(
|
|
4543
|
+
"dropping oldest pending string field (stringStream subscriber is slower than producer)"
|
|
4544
|
+
);
|
|
4545
|
+
}
|
|
4546
|
+
pending.set(key, event);
|
|
4547
|
+
wakeWaiter();
|
|
4548
|
+
};
|
|
4388
4549
|
for (const [askId, paths] of self.stringStreamByAsk) {
|
|
4389
4550
|
for (const [path, acc] of paths) {
|
|
4390
4551
|
if (!matchesFilter(askId, path)) continue;
|
|
4391
|
-
|
|
4552
|
+
enqueue({
|
|
4392
4553
|
askId,
|
|
4393
4554
|
agent: acc.agent,
|
|
4394
4555
|
path,
|
|
@@ -4398,51 +4559,37 @@ var AxlEventBus = class {
|
|
|
4398
4559
|
});
|
|
4399
4560
|
}
|
|
4400
4561
|
}
|
|
4401
|
-
const
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
askId,
|
|
4410
|
-
agent: event.agent,
|
|
4411
|
-
path: event.data.path,
|
|
4412
|
-
delta: event.data.delta,
|
|
4413
|
-
accumulated,
|
|
4414
|
-
attempt: event.attempt
|
|
4415
|
-
});
|
|
4416
|
-
wakeWaiter();
|
|
4417
|
-
};
|
|
4418
|
-
self.bus.on("string_delta", handler);
|
|
4419
|
-
const pipelineHandler = (event) => {
|
|
4420
|
-
if (event.type !== "pipeline") return;
|
|
4421
|
-
if (event.status !== "failed") return;
|
|
4422
|
-
const askId = event.askId ?? "";
|
|
4423
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
4424
|
-
if (pending[i].askId === askId) pending.splice(i, 1);
|
|
4562
|
+
const subscriber = {
|
|
4563
|
+
push(event) {
|
|
4564
|
+
if (matchesFilter(event.askId, event.path)) enqueue(event);
|
|
4565
|
+
},
|
|
4566
|
+
reset(askId) {
|
|
4567
|
+
for (const [key, event] of pending) {
|
|
4568
|
+
if (event.askId === askId) pending.delete(key);
|
|
4569
|
+
}
|
|
4425
4570
|
}
|
|
4426
4571
|
};
|
|
4427
|
-
self.
|
|
4572
|
+
self.stringStreamSubscribers.add(subscriber);
|
|
4428
4573
|
const unsubscribe = () => {
|
|
4429
4574
|
if (unsubscribed) return;
|
|
4430
4575
|
unsubscribed = true;
|
|
4431
|
-
self.
|
|
4432
|
-
self.bus.off("pipeline", pipelineHandler);
|
|
4576
|
+
self.stringStreamSubscribers.delete(subscriber);
|
|
4433
4577
|
unsubscribeFinish();
|
|
4434
4578
|
};
|
|
4435
4579
|
const unsubscribeFinish = self._onFinish(() => {
|
|
4436
4580
|
finished = true;
|
|
4437
|
-
self.
|
|
4438
|
-
self.bus.off("pipeline", pipelineHandler);
|
|
4581
|
+
self.stringStreamSubscribers.delete(subscriber);
|
|
4439
4582
|
wakeWaiter();
|
|
4440
4583
|
});
|
|
4441
4584
|
return {
|
|
4442
4585
|
async next() {
|
|
4443
4586
|
while (true) {
|
|
4444
|
-
if (pending.
|
|
4445
|
-
|
|
4587
|
+
if (pending.size > 0) {
|
|
4588
|
+
const first = pending.entries().next().value;
|
|
4589
|
+
if (first) {
|
|
4590
|
+
pending.delete(first[0]);
|
|
4591
|
+
return { value: first[1], done: false };
|
|
4592
|
+
}
|
|
4446
4593
|
}
|
|
4447
4594
|
if (finished) {
|
|
4448
4595
|
unsubscribe();
|
|
@@ -4500,6 +4647,7 @@ var AxlEventBus = class {
|
|
|
4500
4647
|
*/
|
|
4501
4648
|
_push(event) {
|
|
4502
4649
|
if (this.finished) return;
|
|
4650
|
+
let overflowError;
|
|
4503
4651
|
if (event.type === "partial_object" && event.data?.object !== void 0) {
|
|
4504
4652
|
const askId = event.askId ?? "";
|
|
4505
4653
|
this.latestPartialByAsk.set(askId, {
|
|
@@ -4521,10 +4669,30 @@ var AxlEventBus = class {
|
|
|
4521
4669
|
text: (existing?.text ?? "") + event.data.delta,
|
|
4522
4670
|
attempt: event.attempt
|
|
4523
4671
|
});
|
|
4672
|
+
const accumulated = paths.get(event.data.path).text;
|
|
4673
|
+
for (const subscriber of this.stringStreamSubscribers) {
|
|
4674
|
+
try {
|
|
4675
|
+
subscriber.push({
|
|
4676
|
+
askId,
|
|
4677
|
+
agent: event.agent,
|
|
4678
|
+
path: event.data.path,
|
|
4679
|
+
delta: event.data.delta,
|
|
4680
|
+
accumulated,
|
|
4681
|
+
attempt: event.attempt
|
|
4682
|
+
});
|
|
4683
|
+
} catch (error) {
|
|
4684
|
+
if (isEventStreamOverflowError(error)) {
|
|
4685
|
+
overflowError ??= error;
|
|
4686
|
+
} else {
|
|
4687
|
+
throw error;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4524
4691
|
} else if (event.type === "pipeline" && event.status === "failed") {
|
|
4525
4692
|
const askId = event.askId ?? "";
|
|
4526
4693
|
this.latestPartialByAsk.delete(askId);
|
|
4527
4694
|
this.stringStreamByAsk.delete(askId);
|
|
4695
|
+
for (const subscriber of this.stringStreamSubscribers) subscriber.reset(askId);
|
|
4528
4696
|
} else if (event.type === "ask_end") {
|
|
4529
4697
|
this.stringStreamByAsk.delete(event.askId ?? "");
|
|
4530
4698
|
}
|
|
@@ -4539,39 +4707,57 @@ var AxlEventBus = class {
|
|
|
4539
4707
|
const waiter = this.waiters.shift();
|
|
4540
4708
|
if (waiter) {
|
|
4541
4709
|
waiter({ value: event, done: false });
|
|
4710
|
+
if (overflowError) throw overflowError;
|
|
4542
4711
|
return;
|
|
4543
4712
|
}
|
|
4544
4713
|
if (this.eventQueue.length >= this.maxQueued && !TERMINAL_TYPES.has(event.type)) {
|
|
4545
|
-
|
|
4714
|
+
try {
|
|
4715
|
+
this.handleOverflow(event);
|
|
4716
|
+
} catch (error) {
|
|
4717
|
+
if (isEventStreamOverflowError(error)) {
|
|
4718
|
+
overflowError ??= error;
|
|
4719
|
+
} else {
|
|
4720
|
+
throw error;
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
if (overflowError) throw overflowError;
|
|
4546
4724
|
return;
|
|
4547
4725
|
}
|
|
4548
4726
|
this.eventQueue.push(event);
|
|
4727
|
+
if (overflowError) throw overflowError;
|
|
4549
4728
|
}
|
|
4550
4729
|
/** Apply the overflow policy when the queue is at `maxQueued` and a
|
|
4551
4730
|
* non-terminal event arrives. Terminal events bypass this path entirely
|
|
4552
4731
|
* (checked by the caller). */
|
|
4553
4732
|
handleOverflow(event) {
|
|
4554
4733
|
if (this.onOverflow === "throw") {
|
|
4734
|
+
this.droppedEvents++;
|
|
4555
4735
|
throw new EventStreamOverflowError(this.maxQueued, event.type);
|
|
4556
4736
|
}
|
|
4557
4737
|
let droppedIdx = -1;
|
|
4558
4738
|
for (let i = 0; i < this.eventQueue.length; i++) {
|
|
4559
|
-
|
|
4739
|
+
const candidate = this.eventQueue[i];
|
|
4740
|
+
if (!TERMINAL_TYPES.has(candidate.type)) {
|
|
4560
4741
|
droppedIdx = i;
|
|
4561
4742
|
break;
|
|
4562
4743
|
}
|
|
4563
4744
|
}
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
`[axl] AxlEventBus queue exceeded maxQueued=${this.maxQueued}` + (droppedIdx >= 0 ? `; dropping oldest non-terminal events (consumer is slower than producer).` : `; queue is all terminals (preserved past cap so no terminal is lost).`) + ` This warning fires once per bus instance.`
|
|
4568
|
-
);
|
|
4569
|
-
}
|
|
4745
|
+
this.warnOverflow(
|
|
4746
|
+
droppedIdx >= 0 ? "dropping oldest non-terminal events (consumer is slower than producer)" : "queue contains only protected terminal events; preserving them past the cap"
|
|
4747
|
+
);
|
|
4570
4748
|
if (droppedIdx >= 0) {
|
|
4571
4749
|
this.eventQueue.splice(droppedIdx, 1);
|
|
4750
|
+
this.droppedEvents++;
|
|
4572
4751
|
}
|
|
4573
4752
|
this.eventQueue.push(event);
|
|
4574
4753
|
}
|
|
4754
|
+
warnOverflow(detail) {
|
|
4755
|
+
if (this.overflowWarned) return;
|
|
4756
|
+
this.overflowWarned = true;
|
|
4757
|
+
console.warn(
|
|
4758
|
+
`[axl] AxlEventBus queue exceeded maxQueued=${this.maxQueued}; ${detail}. This warning fires once per bus instance.`
|
|
4759
|
+
);
|
|
4760
|
+
}
|
|
4575
4761
|
/**
|
|
4576
4762
|
* Mark the bus as finished. Wakes any pending iterators with `done: true`
|
|
4577
4763
|
* and drops further `_push` calls. Idempotent.
|
|
@@ -4638,6 +4824,43 @@ var AxlEventBus = class {
|
|
|
4638
4824
|
}
|
|
4639
4825
|
};
|
|
4640
4826
|
|
|
4827
|
+
// src/event-schema.ts
|
|
4828
|
+
var UnsupportedEventSchemaVersionError = class extends Error {
|
|
4829
|
+
constructor(version) {
|
|
4830
|
+
super(`Unsupported Axl event schema version: ${String(version)}`);
|
|
4831
|
+
this.version = version;
|
|
4832
|
+
this.name = "UnsupportedEventSchemaVersionError";
|
|
4833
|
+
}
|
|
4834
|
+
};
|
|
4835
|
+
function getEventSchemaVersion(event) {
|
|
4836
|
+
const version = event.schemaVersion === void 0 ? 1 : event.schemaVersion;
|
|
4837
|
+
if (version !== 1 && version !== 2) throw new UnsupportedEventSchemaVersionError(version);
|
|
4838
|
+
return version;
|
|
4839
|
+
}
|
|
4840
|
+
function getExecutionEventSchemaVersion(execution) {
|
|
4841
|
+
const version = execution.eventSchemaVersion === void 0 ? 1 : execution.eventSchemaVersion;
|
|
4842
|
+
if (version !== 1 && version !== 2) throw new UnsupportedEventSchemaVersionError(version);
|
|
4843
|
+
return version;
|
|
4844
|
+
}
|
|
4845
|
+
function normalizeStoredExecution(execution) {
|
|
4846
|
+
const version = getExecutionEventSchemaVersion(execution);
|
|
4847
|
+
if (!Array.isArray(execution.events)) {
|
|
4848
|
+
throw new TypeError(`Execution ${execution.executionId} has a non-array events field`);
|
|
4849
|
+
}
|
|
4850
|
+
for (const event of execution.events) {
|
|
4851
|
+
const eventVersion = getEventSchemaVersion(event);
|
|
4852
|
+
if (eventVersion !== version) {
|
|
4853
|
+
throw new Error(
|
|
4854
|
+
`Execution ${execution.executionId} declares event schema v${version} but contains a v${eventVersion} event`
|
|
4855
|
+
);
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
if (version === 2) {
|
|
4859
|
+
return { ...execution, eventSchemaVersion: 2 };
|
|
4860
|
+
}
|
|
4861
|
+
return { ...execution, eventSchemaVersion: 1 };
|
|
4862
|
+
}
|
|
4863
|
+
|
|
4641
4864
|
// src/redaction.ts
|
|
4642
4865
|
var REDACTED = "[redacted]";
|
|
4643
4866
|
function walkObjectOneLevel(obj, preserveKeys) {
|
|
@@ -4688,7 +4911,7 @@ function redactMemory(event) {
|
|
|
4688
4911
|
};
|
|
4689
4912
|
}
|
|
4690
4913
|
var passthrough = (e) => e;
|
|
4691
|
-
var
|
|
4914
|
+
var LEGACY_REDACTION_RULES = {
|
|
4692
4915
|
workflow_start: (e) => e.data.input !== void 0 ? { ...e, data: { ...e.data, input: REDACTED } } : e,
|
|
4693
4916
|
workflow_end: (e) => {
|
|
4694
4917
|
const d = e.data;
|
|
@@ -4788,10 +5011,125 @@ var REDACTION_RULES = {
|
|
|
4788
5011
|
done: (e) => ({ ...e, data: { result: REDACTED } }),
|
|
4789
5012
|
error: (e) => ({ ...e, data: { ...e.data, message: REDACTED } })
|
|
4790
5013
|
};
|
|
5014
|
+
function redactLegacyEvent(event) {
|
|
5015
|
+
const rule = LEGACY_REDACTION_RULES[event.type];
|
|
5016
|
+
return rule(event);
|
|
5017
|
+
}
|
|
5018
|
+
function redactV2Outcome(outcome) {
|
|
5019
|
+
switch (outcome.status) {
|
|
5020
|
+
case "succeeded":
|
|
5021
|
+
return { ...outcome, result: REDACTED };
|
|
5022
|
+
case "denied":
|
|
5023
|
+
return outcome.reason === void 0 ? outcome : { ...outcome, reason: REDACTED };
|
|
5024
|
+
case "cancelled":
|
|
5025
|
+
return {
|
|
5026
|
+
...outcome,
|
|
5027
|
+
cancellation: {
|
|
5028
|
+
...outcome.cancellation,
|
|
5029
|
+
..."result" in outcome.cancellation ? { result: REDACTED } : {},
|
|
5030
|
+
...outcome.cancellation.reason !== void 0 ? { reason: REDACTED } : {}
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
case "failed": {
|
|
5034
|
+
const failure = outcome.failure;
|
|
5035
|
+
return {
|
|
5036
|
+
...outcome,
|
|
5037
|
+
failure: {
|
|
5038
|
+
...failure,
|
|
5039
|
+
..."result" in failure ? { result: REDACTED } : {},
|
|
5040
|
+
error: {
|
|
5041
|
+
...failure.error,
|
|
5042
|
+
message: REDACTED,
|
|
5043
|
+
...failure.error.cause !== void 0 ? { cause: REDACTED } : {}
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
function redactV2Rejection(data) {
|
|
5051
|
+
switch (data.reason) {
|
|
5052
|
+
case "unavailable":
|
|
5053
|
+
return data;
|
|
5054
|
+
case "invalid_json":
|
|
5055
|
+
return { ...data, message: REDACTED };
|
|
5056
|
+
case "invalid_arguments":
|
|
5057
|
+
return {
|
|
5058
|
+
...data,
|
|
5059
|
+
args: REDACTED,
|
|
5060
|
+
issues: data.issues.map((issue) => ({
|
|
5061
|
+
...issue,
|
|
5062
|
+
...issue.message !== void 0 ? { message: REDACTED } : {}
|
|
5063
|
+
}))
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
5066
|
+
}
|
|
5067
|
+
var V2_TOOL_REDACTION_RULES = {
|
|
5068
|
+
tool_call_start: (event) => ({
|
|
5069
|
+
...event,
|
|
5070
|
+
data: { ...event.data, args: REDACTED }
|
|
5071
|
+
}),
|
|
5072
|
+
tool_call_end: (event) => ({
|
|
5073
|
+
...event,
|
|
5074
|
+
data: {
|
|
5075
|
+
...event.data,
|
|
5076
|
+
args: REDACTED,
|
|
5077
|
+
outcome: redactV2Outcome(event.data.outcome)
|
|
5078
|
+
}
|
|
5079
|
+
}),
|
|
5080
|
+
tool_call_rejected: (event) => ({
|
|
5081
|
+
...event,
|
|
5082
|
+
data: redactV2Rejection(event.data)
|
|
5083
|
+
})
|
|
5084
|
+
};
|
|
5085
|
+
function reuseLegacyRule(type) {
|
|
5086
|
+
return LEGACY_REDACTION_RULES[type];
|
|
5087
|
+
}
|
|
5088
|
+
var COMMON_V2_REDACTION_RULES = {
|
|
5089
|
+
workflow_start: reuseLegacyRule("workflow_start"),
|
|
5090
|
+
workflow_end: reuseLegacyRule("workflow_end"),
|
|
5091
|
+
ask_start: reuseLegacyRule("ask_start"),
|
|
5092
|
+
ask_end: reuseLegacyRule("ask_end"),
|
|
5093
|
+
agent_call_start: reuseLegacyRule("agent_call_start"),
|
|
5094
|
+
agent_call_end: reuseLegacyRule("agent_call_end"),
|
|
5095
|
+
token: reuseLegacyRule("token"),
|
|
5096
|
+
tool_approval: reuseLegacyRule("tool_approval"),
|
|
5097
|
+
delegate: reuseLegacyRule("delegate"),
|
|
5098
|
+
handoff_start: reuseLegacyRule("handoff_start"),
|
|
5099
|
+
handoff_return: reuseLegacyRule("handoff_return"),
|
|
5100
|
+
pipeline: reuseLegacyRule("pipeline"),
|
|
5101
|
+
partial_object: reuseLegacyRule("partial_object"),
|
|
5102
|
+
string_delta: reuseLegacyRule("string_delta"),
|
|
5103
|
+
verify: reuseLegacyRule("verify"),
|
|
5104
|
+
schema_diagnostic: reuseLegacyRule("schema_diagnostic"),
|
|
5105
|
+
log: reuseLegacyRule("log"),
|
|
5106
|
+
memory_remember: reuseLegacyRule("memory_remember"),
|
|
5107
|
+
memory_recall: reuseLegacyRule("memory_recall"),
|
|
5108
|
+
memory_forget: reuseLegacyRule("memory_forget"),
|
|
5109
|
+
checkpoint_save: reuseLegacyRule("checkpoint_save"),
|
|
5110
|
+
checkpoint_replay: reuseLegacyRule("checkpoint_replay"),
|
|
5111
|
+
await_human: reuseLegacyRule("await_human"),
|
|
5112
|
+
await_human_resolved: reuseLegacyRule("await_human_resolved"),
|
|
5113
|
+
guardrail: reuseLegacyRule("guardrail"),
|
|
5114
|
+
schema_check: reuseLegacyRule("schema_check"),
|
|
5115
|
+
validate: reuseLegacyRule("validate"),
|
|
5116
|
+
done: reuseLegacyRule("done"),
|
|
5117
|
+
error: reuseLegacyRule("error")
|
|
5118
|
+
};
|
|
5119
|
+
var REDACTION_RULES = {
|
|
5120
|
+
...COMMON_V2_REDACTION_RULES,
|
|
5121
|
+
...V2_TOOL_REDACTION_RULES
|
|
5122
|
+
};
|
|
4791
5123
|
function redactEvent(event) {
|
|
4792
5124
|
const rule = REDACTION_RULES[event.type];
|
|
4793
5125
|
return rule(event);
|
|
4794
5126
|
}
|
|
5127
|
+
function redactHistoricalEvent(event) {
|
|
5128
|
+
if (getEventSchemaVersion(event) === 1) {
|
|
5129
|
+
return redactLegacyEvent(event);
|
|
5130
|
+
}
|
|
5131
|
+
return redactEvent(event);
|
|
5132
|
+
}
|
|
4795
5133
|
|
|
4796
5134
|
// src/schema-diagnostics.ts
|
|
4797
5135
|
var DEFAULT_SCHEMA_OVERSIZED_TOKENS = 4e3;
|
|
@@ -4991,148 +5329,626 @@ function normalize(value, path, stack) {
|
|
|
4991
5329
|
"accessor properties are not supported"
|
|
4992
5330
|
);
|
|
4993
5331
|
}
|
|
4994
|
-
if (typeof key === "symbol"
|
|
4995
|
-
throw invalid(`${path}[symbol]`, "
|
|
5332
|
+
if (typeof key === "symbol") {
|
|
5333
|
+
throw invalid(`${path}[symbol]`, "symbol keys are not supported");
|
|
5334
|
+
}
|
|
5335
|
+
}
|
|
5336
|
+
if (typeof descriptors.toJSON?.value === "function") {
|
|
5337
|
+
throw invalid(propertyPath(path, "toJSON"), "custom toJSON is not supported");
|
|
5338
|
+
}
|
|
5339
|
+
const array = Array.isArray(value);
|
|
5340
|
+
if (array && prototype !== Array.prototype && prototype !== null) {
|
|
5341
|
+
throw invalid(path, "array subclasses are not supported");
|
|
5342
|
+
}
|
|
5343
|
+
const inheritedToJSON = prototype === Array.prototype || prototype === Object.prototype ? Object.getOwnPropertyDescriptor(prototype, "toJSON") : void 0;
|
|
5344
|
+
if (typeof inheritedToJSON?.value === "function") {
|
|
5345
|
+
throw invalid(propertyPath(path, "toJSON"), "inherited custom toJSON is not supported");
|
|
5346
|
+
}
|
|
5347
|
+
const inheritedThen = prototype === Array.prototype || prototype === Object.prototype ? Object.getOwnPropertyDescriptor(prototype, "then") : void 0;
|
|
5348
|
+
if (typeof descriptors.then?.value === "function" || inheritedThen !== void 0 && (!("value" in inheritedThen) || typeof inheritedThen.value === "function")) {
|
|
5349
|
+
throw invalid(path, "thenable output is not supported");
|
|
5350
|
+
}
|
|
5351
|
+
stack.add(value);
|
|
5352
|
+
try {
|
|
5353
|
+
if (array) {
|
|
5354
|
+
const normalized2 = [];
|
|
5355
|
+
const length = descriptors.length?.value;
|
|
5356
|
+
if (!Number.isSafeInteger(length) || length < 0) {
|
|
5357
|
+
throw invalid(propertyPath(path, "length"), "array length is invalid");
|
|
5358
|
+
}
|
|
5359
|
+
for (let index = 0; index < length; index++) {
|
|
5360
|
+
const descriptor = descriptors[String(index)];
|
|
5361
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
5362
|
+
throw invalid(`${path}[${index}]`, "arrays must be dense data properties");
|
|
5363
|
+
}
|
|
5364
|
+
if (descriptor.value === void 0) {
|
|
5365
|
+
throw invalid(`${path}[${index}]`, "array values cannot be undefined");
|
|
5366
|
+
}
|
|
5367
|
+
normalized2.push(normalize(descriptor.value, `${path}[${index}]`, stack));
|
|
5368
|
+
}
|
|
5369
|
+
for (const key of Object.keys(descriptors)) {
|
|
5370
|
+
const descriptor = descriptors[key];
|
|
5371
|
+
if (!descriptor?.enumerable) continue;
|
|
5372
|
+
const index = Number(key);
|
|
5373
|
+
if (!Number.isInteger(index) || index < 0 || index >= length || String(index) !== key) {
|
|
5374
|
+
throw invalid(propertyPath(path, key), "non-index array properties are not supported");
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
Object.setPrototypeOf(normalized2, null);
|
|
5378
|
+
return normalized2;
|
|
5379
|
+
}
|
|
5380
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
5381
|
+
throw invalid(path, "only plain objects and null-prototype records are supported");
|
|
5382
|
+
}
|
|
5383
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
5384
|
+
for (const key of Object.keys(descriptors)) {
|
|
5385
|
+
const descriptor = descriptors[key];
|
|
5386
|
+
if (!descriptor?.enumerable) continue;
|
|
5387
|
+
if (!("value" in descriptor)) {
|
|
5388
|
+
throw invalid(propertyPath(path, key), "accessor properties are not supported");
|
|
5389
|
+
}
|
|
5390
|
+
if (descriptor.value === void 0) continue;
|
|
5391
|
+
normalized[key] = normalize(descriptor.value, propertyPath(path, key), stack);
|
|
5392
|
+
}
|
|
5393
|
+
return normalized;
|
|
5394
|
+
} finally {
|
|
5395
|
+
stack.delete(value);
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
function serializeToolModelOutput(toolName, output) {
|
|
5399
|
+
try {
|
|
5400
|
+
if (import_node_util.types.isPromise(output)) {
|
|
5401
|
+
void Promise.prototype.then.call(output, void 0, () => void 0);
|
|
5402
|
+
}
|
|
5403
|
+
if (typeof output === "string") return output;
|
|
5404
|
+
return JSON.stringify(normalize(output, "$", /* @__PURE__ */ new WeakSet()));
|
|
5405
|
+
} catch (cause) {
|
|
5406
|
+
throw new ToolModelOutputError(toolName, cause);
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
|
|
5410
|
+
// src/tool-invocation.ts
|
|
5411
|
+
var INVALID_JSON_MODEL_MESSAGE = "Error: Invalid JSON in tool arguments. Please provide valid JSON.";
|
|
5412
|
+
var INVALID_ARGUMENTS_MODEL_MESSAGE = "Error: Tool arguments are invalid. Correct the arguments and try again.";
|
|
5413
|
+
var SENSITIVE_SUCCESS_MESSAGE = "[REDACTED - sensitive tool output]";
|
|
5414
|
+
var SENSITIVE_FAILURE_MESSAGE = "[REDACTED - sensitive tool failure]";
|
|
5415
|
+
var MAX_MCP_MODEL_ERROR_LENGTH = 2e3;
|
|
5416
|
+
function cloneToolArguments(value) {
|
|
5417
|
+
try {
|
|
5418
|
+
return structuredClone(value);
|
|
5419
|
+
} catch {
|
|
5420
|
+
throw new Error("Prepared tool arguments must be structured-cloneable");
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
function parseToolInvocation(options) {
|
|
5424
|
+
const { toolCall, configuredTool, override, mcpCall, mcpTraceName, availableTools } = options;
|
|
5425
|
+
const requestedTool = toolCall.function.name;
|
|
5426
|
+
if (!override && !configuredTool && !mcpCall) {
|
|
5427
|
+
return {
|
|
5428
|
+
kind: "rejected",
|
|
5429
|
+
requestedTool,
|
|
5430
|
+
toolName: requestedTool,
|
|
5431
|
+
callId: toolCall.id,
|
|
5432
|
+
data: { reason: "unavailable", requestedTool, availableTools },
|
|
5433
|
+
modelMessage: `Tool "${requestedTool}" is not available. Available tools: ${availableTools.length > 0 ? availableTools.join(", ") : "none"}`
|
|
5434
|
+
};
|
|
5435
|
+
}
|
|
5436
|
+
let parsedArguments;
|
|
5437
|
+
try {
|
|
5438
|
+
parsedArguments = JSON.parse(toolCall.function.arguments);
|
|
5439
|
+
} catch {
|
|
5440
|
+
return {
|
|
5441
|
+
kind: "rejected",
|
|
5442
|
+
requestedTool,
|
|
5443
|
+
toolName: mcpTraceName ?? requestedTool,
|
|
5444
|
+
callId: toolCall.id,
|
|
5445
|
+
data: {
|
|
5446
|
+
reason: "invalid_json",
|
|
5447
|
+
requestedTool,
|
|
5448
|
+
message: "Tool arguments were not valid JSON."
|
|
5449
|
+
},
|
|
5450
|
+
modelMessage: INVALID_JSON_MODEL_MESSAGE
|
|
5451
|
+
};
|
|
5452
|
+
}
|
|
5453
|
+
if (typeof parsedArguments !== "object" || parsedArguments === null || Array.isArray(parsedArguments)) {
|
|
5454
|
+
return {
|
|
5455
|
+
kind: "rejected",
|
|
5456
|
+
requestedTool,
|
|
5457
|
+
toolName: mcpTraceName ?? requestedTool,
|
|
5458
|
+
callId: toolCall.id,
|
|
5459
|
+
data: {
|
|
5460
|
+
reason: "invalid_json",
|
|
5461
|
+
requestedTool,
|
|
5462
|
+
message: "Tool arguments must decode to a JSON object."
|
|
5463
|
+
},
|
|
5464
|
+
modelMessage: INVALID_JSON_MODEL_MESSAGE
|
|
5465
|
+
};
|
|
5466
|
+
}
|
|
5467
|
+
const source = override ? { kind: "override", execute: override } : configuredTool ? { kind: "local", tool: configuredTool } : { kind: "mcp", call: mcpCall };
|
|
5468
|
+
let preparedArguments = parsedArguments;
|
|
5469
|
+
if (source.kind === "local") {
|
|
5470
|
+
try {
|
|
5471
|
+
preparedArguments = prepareToolInput(source.tool, parsedArguments);
|
|
5472
|
+
} catch (error) {
|
|
5473
|
+
return {
|
|
5474
|
+
kind: "rejected",
|
|
5475
|
+
requestedTool,
|
|
5476
|
+
toolName: requestedTool,
|
|
5477
|
+
callId: toolCall.id,
|
|
5478
|
+
data: {
|
|
5479
|
+
reason: "invalid_arguments",
|
|
5480
|
+
requestedTool,
|
|
5481
|
+
args: parsedArguments,
|
|
5482
|
+
issues: toolArgumentIssues(error)
|
|
5483
|
+
},
|
|
5484
|
+
modelMessage: INVALID_ARGUMENTS_MODEL_MESSAGE
|
|
5485
|
+
};
|
|
4996
5486
|
}
|
|
4997
5487
|
}
|
|
4998
|
-
|
|
4999
|
-
|
|
5488
|
+
try {
|
|
5489
|
+
preparedArguments = cloneToolArguments(preparedArguments);
|
|
5490
|
+
} catch (error) {
|
|
5491
|
+
return {
|
|
5492
|
+
kind: "rejected",
|
|
5493
|
+
requestedTool,
|
|
5494
|
+
toolName: source.kind === "mcp" ? mcpTraceName ?? requestedTool : requestedTool,
|
|
5495
|
+
callId: toolCall.id,
|
|
5496
|
+
data: {
|
|
5497
|
+
reason: "invalid_arguments",
|
|
5498
|
+
requestedTool,
|
|
5499
|
+
args: parsedArguments,
|
|
5500
|
+
issues: toolArgumentIssues(error)
|
|
5501
|
+
},
|
|
5502
|
+
modelMessage: INVALID_ARGUMENTS_MODEL_MESSAGE
|
|
5503
|
+
};
|
|
5504
|
+
}
|
|
5505
|
+
return {
|
|
5506
|
+
requestedTool,
|
|
5507
|
+
toolName: source.kind === "mcp" ? mcpTraceName ?? requestedTool : requestedTool,
|
|
5508
|
+
callId: toolCall.id,
|
|
5509
|
+
args: preparedArguments,
|
|
5510
|
+
configuredTool,
|
|
5511
|
+
source
|
|
5512
|
+
};
|
|
5513
|
+
}
|
|
5514
|
+
function isAbortError3(error) {
|
|
5515
|
+
try {
|
|
5516
|
+
return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
5517
|
+
} catch {
|
|
5518
|
+
return false;
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
function normalizeAbortError(reason) {
|
|
5522
|
+
if (isAbortError3(reason)) return reason;
|
|
5523
|
+
const error = new Error("The operation was aborted");
|
|
5524
|
+
error.name = "AbortError";
|
|
5525
|
+
if (reason !== void 0) {
|
|
5526
|
+
Object.defineProperty(error, "cause", { value: reason, enumerable: false });
|
|
5527
|
+
}
|
|
5528
|
+
return error;
|
|
5529
|
+
}
|
|
5530
|
+
function cancellationError(signal, error) {
|
|
5531
|
+
if (signal?.aborted) return normalizeAbortError(signal.reason);
|
|
5532
|
+
return isAbortError3(error) ? normalizeAbortError(error) : void 0;
|
|
5533
|
+
}
|
|
5534
|
+
function eventError(error) {
|
|
5535
|
+
let isError = false;
|
|
5536
|
+
try {
|
|
5537
|
+
isError = error instanceof Error;
|
|
5538
|
+
} catch {
|
|
5539
|
+
}
|
|
5540
|
+
if (isError) {
|
|
5541
|
+
const read = (key) => {
|
|
5542
|
+
try {
|
|
5543
|
+
return Reflect.get(error, key);
|
|
5544
|
+
} catch {
|
|
5545
|
+
return void 0;
|
|
5546
|
+
}
|
|
5547
|
+
};
|
|
5548
|
+
const name = read("name");
|
|
5549
|
+
const message = read("message");
|
|
5550
|
+
const code = read("code");
|
|
5551
|
+
const cause = read("cause");
|
|
5552
|
+
return {
|
|
5553
|
+
name: typeof name === "string" ? name : "Error",
|
|
5554
|
+
message: typeof message === "string" ? message : "Unknown error",
|
|
5555
|
+
...typeof code === "string" ? { code } : {},
|
|
5556
|
+
...cause !== void 0 ? { cause } : {}
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
try {
|
|
5560
|
+
return { name: "Error", message: String(error) };
|
|
5561
|
+
} catch {
|
|
5562
|
+
return { name: "Error", message: "Unknown thrown value" };
|
|
5000
5563
|
}
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5564
|
+
}
|
|
5565
|
+
function isToolFailure(error) {
|
|
5566
|
+
try {
|
|
5567
|
+
return error instanceof ToolFailure;
|
|
5568
|
+
} catch {
|
|
5569
|
+
return false;
|
|
5004
5570
|
}
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5571
|
+
}
|
|
5572
|
+
function cancellation(phase, error, result) {
|
|
5573
|
+
let reason;
|
|
5574
|
+
try {
|
|
5575
|
+
reason = error instanceof Error && typeof error.message === "string" ? error.message : void 0;
|
|
5576
|
+
} catch {
|
|
5008
5577
|
}
|
|
5009
|
-
const
|
|
5010
|
-
|
|
5011
|
-
|
|
5578
|
+
const cancellation2 = phase === "after_handler" || phase === "after_hook" || phase === "projection" || phase === "serialization" ? { phase, result, ...reason ? { reason } : {} } : { phase, ...reason ? { reason } : {} };
|
|
5579
|
+
return {
|
|
5580
|
+
kind: "cancelled",
|
|
5581
|
+
cancellation: cancellation2,
|
|
5582
|
+
error: normalizeAbortError(error)
|
|
5583
|
+
};
|
|
5584
|
+
}
|
|
5585
|
+
function failed(phase, error, options = {}) {
|
|
5586
|
+
let modelMessage;
|
|
5587
|
+
if (isToolFailure(error)) {
|
|
5588
|
+
try {
|
|
5589
|
+
modelMessage = typeof error.modelMessage === "string" ? error.modelMessage : void 0;
|
|
5590
|
+
} catch {
|
|
5591
|
+
}
|
|
5012
5592
|
}
|
|
5013
|
-
|
|
5593
|
+
const toolFailure = modelMessage !== void 0;
|
|
5594
|
+
const common = {
|
|
5595
|
+
phase,
|
|
5596
|
+
kind: toolFailure ? "tool_failure" : "unexpected",
|
|
5597
|
+
disposition: toolFailure ? "continue" : "abort",
|
|
5598
|
+
error: eventError(error)
|
|
5599
|
+
};
|
|
5600
|
+
const failure = phase === "handler" ? { ...common, attempts: options.attempts ?? 1 } : phase === "after_hook" ? { ...common, result: options.result } : common;
|
|
5601
|
+
return {
|
|
5602
|
+
kind: "failed",
|
|
5603
|
+
failure,
|
|
5604
|
+
error,
|
|
5605
|
+
...modelMessage !== void 0 ? { modelMessage } : {}
|
|
5606
|
+
};
|
|
5607
|
+
}
|
|
5608
|
+
function mcpContent(result) {
|
|
5609
|
+
return result.content.map((content) => content.type === "text" ? content.text : `[${content.type}]`).join("\n");
|
|
5610
|
+
}
|
|
5611
|
+
function safeMcpModelError(content) {
|
|
5612
|
+
let normalized = "";
|
|
5613
|
+
for (const character of content) {
|
|
5614
|
+
const code = character.charCodeAt(0);
|
|
5615
|
+
normalized += code <= 31 && code !== 9 && code !== 10 && code !== 13 || code === 127 ? " " : character;
|
|
5616
|
+
}
|
|
5617
|
+
return `MCP tool error: ${normalized.slice(0, MAX_MCP_MODEL_ERROR_LENGTH)}`;
|
|
5618
|
+
}
|
|
5619
|
+
async function executeAcceptedTool(options) {
|
|
5620
|
+
const { invocation, context, signal, requestApproval, createChildContext } = options;
|
|
5621
|
+
let effectiveArgs = cloneToolArguments(invocation.args);
|
|
5622
|
+
if (invocation.source.kind === "local" && invocation.source.tool.requireApproval) {
|
|
5623
|
+
try {
|
|
5624
|
+
signal?.throwIfAborted();
|
|
5625
|
+
const approval = await requestApproval();
|
|
5626
|
+
signal?.throwIfAborted();
|
|
5627
|
+
if (!approval.approved) return { kind: "denied", reason: approval.reason };
|
|
5628
|
+
} catch (error) {
|
|
5629
|
+
rethrowEventStreamOverflow(error);
|
|
5630
|
+
const abort = cancellationError(signal, error);
|
|
5631
|
+
if (abort !== void 0) return cancellation("approval", abort);
|
|
5632
|
+
return {
|
|
5633
|
+
kind: "failed",
|
|
5634
|
+
failure: {
|
|
5635
|
+
phase: "approval",
|
|
5636
|
+
kind: "infrastructure",
|
|
5637
|
+
disposition: "abort",
|
|
5638
|
+
error: eventError(error)
|
|
5639
|
+
},
|
|
5640
|
+
error
|
|
5641
|
+
};
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
5644
|
+
if (invocation.source.kind === "local" && invocation.source.tool.hooks?.before) {
|
|
5645
|
+
try {
|
|
5646
|
+
signal?.throwIfAborted();
|
|
5647
|
+
effectiveArgs = await invocation.source.tool.hooks.before(effectiveArgs, context);
|
|
5648
|
+
signal?.throwIfAborted();
|
|
5649
|
+
} catch (error) {
|
|
5650
|
+
rethrowEventStreamOverflow(error);
|
|
5651
|
+
const abort = cancellationError(signal, error);
|
|
5652
|
+
if (abort !== void 0) return cancellation("before_hook", abort);
|
|
5653
|
+
return failed("before_hook", error);
|
|
5654
|
+
}
|
|
5655
|
+
}
|
|
5656
|
+
let result;
|
|
5657
|
+
let attempts = 1;
|
|
5014
5658
|
try {
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
for (let index = 0; index < length; index++) {
|
|
5022
|
-
const descriptor = descriptors[String(index)];
|
|
5023
|
-
if (!descriptor || !("value" in descriptor)) {
|
|
5024
|
-
throw invalid(`${path}[${index}]`, "arrays must be dense data properties");
|
|
5025
|
-
}
|
|
5026
|
-
if (descriptor.value === void 0) {
|
|
5027
|
-
throw invalid(`${path}[${index}]`, "array values cannot be undefined");
|
|
5028
|
-
}
|
|
5029
|
-
normalized2.push(normalize(descriptor.value, `${path}[${index}]`, stack));
|
|
5659
|
+
signal?.throwIfAborted();
|
|
5660
|
+
switch (invocation.source.kind) {
|
|
5661
|
+
case "override": {
|
|
5662
|
+
const executeOverride = invocation.source.execute;
|
|
5663
|
+
result = await executeOverride(effectiveArgs);
|
|
5664
|
+
break;
|
|
5030
5665
|
}
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5666
|
+
case "local":
|
|
5667
|
+
result = await executePreparedTool(
|
|
5668
|
+
invocation.source.tool,
|
|
5669
|
+
effectiveArgs,
|
|
5670
|
+
createChildContext(),
|
|
5671
|
+
{
|
|
5672
|
+
signal,
|
|
5673
|
+
onAttempt: (attempt) => attempts = attempt,
|
|
5674
|
+
checkAfterHandlerAbort: false
|
|
5675
|
+
}
|
|
5676
|
+
);
|
|
5677
|
+
break;
|
|
5678
|
+
case "mcp": {
|
|
5679
|
+
const mcpResult = await invocation.source.call(effectiveArgs);
|
|
5680
|
+
if (signal?.aborted) return cancellation("after_handler", signal.reason, mcpResult);
|
|
5681
|
+
if (mcpResult.isError) {
|
|
5682
|
+
const content = mcpContent(mcpResult);
|
|
5683
|
+
const error = new Error(content || "MCP tool returned an error");
|
|
5684
|
+
return {
|
|
5685
|
+
kind: "failed",
|
|
5686
|
+
failure: {
|
|
5687
|
+
phase: "handler",
|
|
5688
|
+
kind: "mcp_error",
|
|
5689
|
+
disposition: "continue",
|
|
5690
|
+
error: { name: "McpToolError", message: error.message, code: "MCP_TOOL_ERROR" },
|
|
5691
|
+
attempts: 1
|
|
5692
|
+
},
|
|
5693
|
+
error,
|
|
5694
|
+
modelMessage: safeMcpModelError(content)
|
|
5695
|
+
};
|
|
5037
5696
|
}
|
|
5697
|
+
result = mcpResult;
|
|
5698
|
+
break;
|
|
5038
5699
|
}
|
|
5039
|
-
Object.setPrototypeOf(normalized2, null);
|
|
5040
|
-
return normalized2;
|
|
5041
5700
|
}
|
|
5042
|
-
|
|
5043
|
-
|
|
5701
|
+
} catch (error) {
|
|
5702
|
+
rethrowEventStreamOverflow(error);
|
|
5703
|
+
const abort = cancellationError(signal, error);
|
|
5704
|
+
if (abort !== void 0) return cancellation("handler", abort);
|
|
5705
|
+
return failed("handler", error, { attempts });
|
|
5706
|
+
}
|
|
5707
|
+
if (signal?.aborted) return cancellation("after_handler", signal.reason, result);
|
|
5708
|
+
if (invocation.source.kind === "local" && invocation.source.tool.hooks?.after) {
|
|
5709
|
+
const rawResult = result;
|
|
5710
|
+
try {
|
|
5711
|
+
result = await invocation.source.tool.hooks.after(result, context);
|
|
5712
|
+
signal?.throwIfAborted();
|
|
5713
|
+
} catch (error) {
|
|
5714
|
+
rethrowEventStreamOverflow(error);
|
|
5715
|
+
const abort = cancellationError(signal, error);
|
|
5716
|
+
if (abort !== void 0) return cancellation("after_hook", abort, rawResult);
|
|
5717
|
+
return failed("after_hook", error, { result: rawResult });
|
|
5044
5718
|
}
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5719
|
+
}
|
|
5720
|
+
return { kind: "succeeded", result };
|
|
5721
|
+
}
|
|
5722
|
+
function prepareToolMessage(invocation, outcome) {
|
|
5723
|
+
const sensitive = invocation.configuredTool?.sensitive === true;
|
|
5724
|
+
if (outcome.kind === "denied") {
|
|
5725
|
+
return {
|
|
5726
|
+
ok: true,
|
|
5727
|
+
content: JSON.stringify({ error: "Tool request was denied by human approval." })
|
|
5728
|
+
};
|
|
5729
|
+
}
|
|
5730
|
+
if (outcome.kind === "failed") {
|
|
5731
|
+
if (outcome.failure.disposition !== "continue" || outcome.modelMessage === void 0) {
|
|
5732
|
+
throw new Error("Aborting tool failures cannot produce provider messages");
|
|
5733
|
+
}
|
|
5734
|
+
return { ok: true, content: sensitive ? SENSITIVE_FAILURE_MESSAGE : outcome.modelMessage };
|
|
5735
|
+
}
|
|
5736
|
+
if (outcome.kind !== "succeeded") {
|
|
5737
|
+
throw new Error("Cancelled tool calls cannot produce provider messages");
|
|
5738
|
+
}
|
|
5739
|
+
if (sensitive) return { ok: true, content: SENSITIVE_SUCCESS_MESSAGE };
|
|
5740
|
+
if (invocation.source.kind === "mcp") {
|
|
5741
|
+
try {
|
|
5742
|
+
return { ok: true, content: mcpContent(outcome.result) };
|
|
5743
|
+
} catch (error) {
|
|
5744
|
+
rethrowEventStreamOverflow(error);
|
|
5745
|
+
return { ok: false, phase: "serialization", error };
|
|
5746
|
+
}
|
|
5747
|
+
}
|
|
5748
|
+
if (invocation.configuredTool?.toModelOutput) {
|
|
5749
|
+
try {
|
|
5750
|
+
const project = invocation.configuredTool.toModelOutput;
|
|
5751
|
+
return {
|
|
5752
|
+
ok: true,
|
|
5753
|
+
content: serializeToolModelOutput(
|
|
5754
|
+
invocation.requestedTool,
|
|
5755
|
+
project(outcome.result)
|
|
5756
|
+
)
|
|
5757
|
+
};
|
|
5758
|
+
} catch (error) {
|
|
5759
|
+
rethrowEventStreamOverflow(error);
|
|
5760
|
+
if (error instanceof ToolModelOutputError && isEventStreamOverflowError(error.cause)) {
|
|
5761
|
+
throw error.cause;
|
|
5051
5762
|
}
|
|
5052
|
-
|
|
5053
|
-
|
|
5763
|
+
return {
|
|
5764
|
+
ok: false,
|
|
5765
|
+
phase: "projection",
|
|
5766
|
+
error: error instanceof ToolModelOutputError && error.toolName === invocation.requestedTool ? error : new ToolModelOutputError(invocation.requestedTool, error)
|
|
5767
|
+
};
|
|
5054
5768
|
}
|
|
5055
|
-
return normalized;
|
|
5056
|
-
} finally {
|
|
5057
|
-
stack.delete(value);
|
|
5058
5769
|
}
|
|
5059
|
-
}
|
|
5060
|
-
function serializeToolModelOutput(toolName, output) {
|
|
5061
5770
|
try {
|
|
5062
|
-
|
|
5063
|
-
|
|
5771
|
+
const content = JSON.stringify(outcome.result);
|
|
5772
|
+
if (content === void 0) throw new Error("Tool result is not JSON serializable");
|
|
5773
|
+
return { ok: true, content };
|
|
5774
|
+
} catch (error) {
|
|
5775
|
+
rethrowEventStreamOverflow(error);
|
|
5776
|
+
return { ok: false, phase: "serialization", error };
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
5779
|
+
async function settleAcceptedTool(options) {
|
|
5780
|
+
const internal = await executeAcceptedTool(options);
|
|
5781
|
+
if (internal.kind === "cancelled") {
|
|
5782
|
+
return {
|
|
5783
|
+
outcome: { status: "cancelled", cancellation: internal.cancellation },
|
|
5784
|
+
abortError: internal.error
|
|
5785
|
+
};
|
|
5786
|
+
}
|
|
5787
|
+
if (internal.kind === "failed" && internal.failure.disposition === "abort") {
|
|
5788
|
+
return {
|
|
5789
|
+
outcome: { status: "failed", failure: internal.failure },
|
|
5790
|
+
abortError: internal.error
|
|
5791
|
+
};
|
|
5792
|
+
}
|
|
5793
|
+
const result = internal.kind === "succeeded" ? internal.result : void 0;
|
|
5794
|
+
const outputPhase = internal.kind === "succeeded" && !options.invocation.configuredTool?.sensitive && options.invocation.source.kind !== "mcp" && options.invocation.configuredTool?.toModelOutput ? "projection" : "serialization";
|
|
5795
|
+
if (internal.kind === "succeeded" && options.signal?.aborted) {
|
|
5796
|
+
return {
|
|
5797
|
+
outcome: {
|
|
5798
|
+
status: "cancelled",
|
|
5799
|
+
cancellation: { phase: outputPhase, result }
|
|
5800
|
+
},
|
|
5801
|
+
abortError: normalizeAbortError(options.signal.reason)
|
|
5802
|
+
};
|
|
5803
|
+
}
|
|
5804
|
+
const prepared = prepareToolMessage(options.invocation, internal);
|
|
5805
|
+
if (internal.kind === "succeeded" && options.signal?.aborted) {
|
|
5806
|
+
return {
|
|
5807
|
+
outcome: {
|
|
5808
|
+
status: "cancelled",
|
|
5809
|
+
cancellation: { phase: outputPhase, result }
|
|
5810
|
+
},
|
|
5811
|
+
abortError: normalizeAbortError(options.signal.reason)
|
|
5812
|
+
};
|
|
5813
|
+
}
|
|
5814
|
+
if (!prepared.ok) {
|
|
5815
|
+
const outputAbort = cancellationError(options.signal, prepared.error) ?? (prepared.error instanceof ToolModelOutputError ? cancellationError(options.signal, prepared.error.cause) : void 0);
|
|
5816
|
+
if (outputAbort !== void 0) {
|
|
5817
|
+
return {
|
|
5818
|
+
outcome: {
|
|
5819
|
+
status: "cancelled",
|
|
5820
|
+
cancellation: { phase: prepared.phase, result }
|
|
5821
|
+
},
|
|
5822
|
+
abortError: outputAbort
|
|
5823
|
+
};
|
|
5064
5824
|
}
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5825
|
+
const failure = {
|
|
5826
|
+
phase: prepared.phase,
|
|
5827
|
+
kind: "output",
|
|
5828
|
+
disposition: "abort",
|
|
5829
|
+
error: eventError(prepared.error),
|
|
5830
|
+
result
|
|
5831
|
+
};
|
|
5832
|
+
return {
|
|
5833
|
+
outcome: { status: "failed", failure },
|
|
5834
|
+
abortError: prepared.error
|
|
5835
|
+
};
|
|
5836
|
+
}
|
|
5837
|
+
if (internal.kind === "succeeded") {
|
|
5838
|
+
return {
|
|
5839
|
+
outcome: { status: "succeeded", result: internal.result },
|
|
5840
|
+
providerContent: prepared.content
|
|
5841
|
+
};
|
|
5842
|
+
}
|
|
5843
|
+
if (internal.kind === "denied") {
|
|
5844
|
+
return {
|
|
5845
|
+
outcome: { status: "denied", ...internal.reason ? { reason: internal.reason } : {} },
|
|
5846
|
+
providerContent: prepared.content
|
|
5847
|
+
};
|
|
5848
|
+
}
|
|
5849
|
+
return {
|
|
5850
|
+
outcome: { status: "failed", failure: internal.failure },
|
|
5851
|
+
providerContent: prepared.content
|
|
5852
|
+
};
|
|
5853
|
+
}
|
|
5854
|
+
function recordToolSpanOutcome(span, outcome) {
|
|
5855
|
+
span.setAttribute("axl.tool.outcome", outcome.status);
|
|
5856
|
+
span.setAttribute("axl.tool.success", outcome.status === "succeeded");
|
|
5857
|
+
switch (outcome.status) {
|
|
5858
|
+
case "succeeded":
|
|
5859
|
+
span.setStatus("ok");
|
|
5860
|
+
return;
|
|
5861
|
+
case "denied":
|
|
5862
|
+
span.setStatus("unset");
|
|
5863
|
+
return;
|
|
5864
|
+
case "failed":
|
|
5865
|
+
span.setAttribute("axl.tool.phase", outcome.failure.phase);
|
|
5866
|
+
span.setStatus("error");
|
|
5867
|
+
return;
|
|
5868
|
+
case "cancelled":
|
|
5869
|
+
span.setAttribute("axl.tool.phase", outcome.cancellation.phase);
|
|
5870
|
+
span.setStatus("error");
|
|
5069
5871
|
}
|
|
5070
5872
|
}
|
|
5071
5873
|
|
|
5072
5874
|
// src/context.ts
|
|
5073
5875
|
var signalStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
5074
|
-
|
|
5075
|
-
|
|
5876
|
+
var DEFAULT_BRANCH_DRAIN_TIMEOUT_MS = 5e3;
|
|
5877
|
+
function resolveBranchDrainTimeoutMs(value) {
|
|
5878
|
+
const resolved = value === void 0 ? DEFAULT_BRANCH_DRAIN_TIMEOUT_MS : value;
|
|
5879
|
+
if (typeof resolved !== "number" || Number.isNaN(resolved) || !Number.isFinite(resolved) || resolved < 0) {
|
|
5880
|
+
throw new AxlError(
|
|
5881
|
+
"INVALID_CONFIG",
|
|
5882
|
+
`branchDrainTimeoutMs must be a non-negative finite number (got ${String(resolved)})`
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
return resolved;
|
|
5076
5886
|
}
|
|
5077
|
-
function
|
|
5887
|
+
function parseHumanDecision(value) {
|
|
5888
|
+
const invalid2 = () => {
|
|
5889
|
+
throw new AxlError(
|
|
5890
|
+
"INVALID_HUMAN_DECISION",
|
|
5891
|
+
"Human decision must be a plain object with a boolean approved field and only branch-appropriate string data"
|
|
5892
|
+
);
|
|
5893
|
+
};
|
|
5894
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) invalid2();
|
|
5895
|
+
let prototype;
|
|
5078
5896
|
try {
|
|
5079
|
-
|
|
5897
|
+
prototype = Object.getPrototypeOf(value);
|
|
5080
5898
|
} catch {
|
|
5081
|
-
return
|
|
5899
|
+
return invalid2();
|
|
5082
5900
|
}
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
}
|
|
5095
|
-
|
|
5901
|
+
if (prototype !== Object.prototype && prototype !== null) invalid2();
|
|
5902
|
+
let ownKeys;
|
|
5903
|
+
try {
|
|
5904
|
+
ownKeys = Reflect.ownKeys(value);
|
|
5905
|
+
} catch {
|
|
5906
|
+
return invalid2();
|
|
5907
|
+
}
|
|
5908
|
+
if (ownKeys.some(
|
|
5909
|
+
(key) => typeof key !== "string" || key !== "approved" && key !== "data" && key !== "reason"
|
|
5910
|
+
)) {
|
|
5911
|
+
invalid2();
|
|
5912
|
+
}
|
|
5913
|
+
const readDataProperty = (key) => {
|
|
5914
|
+
let descriptor;
|
|
5096
5915
|
try {
|
|
5097
|
-
|
|
5916
|
+
descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
5098
5917
|
} catch {
|
|
5099
|
-
|
|
5100
|
-
|
|
5918
|
+
return invalid2();
|
|
5919
|
+
}
|
|
5920
|
+
if (!descriptor) {
|
|
5921
|
+
if (ownKeys.includes(key)) invalid2();
|
|
5922
|
+
return { present: false, value: void 0 };
|
|
5923
|
+
}
|
|
5924
|
+
if (!ownKeys.includes(key)) return invalid2();
|
|
5925
|
+
if (!("value" in descriptor)) return invalid2();
|
|
5926
|
+
return { present: true, value: descriptor.value };
|
|
5927
|
+
};
|
|
5928
|
+
const approved = readDataProperty("approved");
|
|
5929
|
+
const data = readDataProperty("data");
|
|
5930
|
+
const reason = readDataProperty("reason");
|
|
5931
|
+
if (approved.present && approved.value === true && !reason.present) {
|
|
5932
|
+
if (data.value === void 0 || typeof data.value === "string") {
|
|
5933
|
+
return { approved: true, ...data.value === void 0 ? {} : { data: data.value } };
|
|
5101
5934
|
}
|
|
5102
|
-
} else {
|
|
5103
|
-
inspect();
|
|
5104
|
-
}
|
|
5105
|
-
span.setAttribute("axl.tool.success", !isError);
|
|
5106
|
-
if (isError) span.setStatus("error", errorMessage);
|
|
5107
|
-
}
|
|
5108
|
-
function prepareToolModelOutput(toolName, project) {
|
|
5109
|
-
let output;
|
|
5110
|
-
try {
|
|
5111
|
-
output = project();
|
|
5112
|
-
} catch (cause) {
|
|
5113
|
-
throw new ToolModelOutputError(toolName, cause);
|
|
5114
5935
|
}
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
beforeProjection();
|
|
5123
|
-
const project = configuredTool.toModelOutput;
|
|
5124
|
-
return prepareToolModelOutput(toolName, () => project(outcome.value));
|
|
5936
|
+
if (approved.present && approved.value === false && !data.present) {
|
|
5937
|
+
if (reason.value === void 0 || typeof reason.value === "string") {
|
|
5938
|
+
return {
|
|
5939
|
+
approved: false,
|
|
5940
|
+
...reason.value === void 0 ? {} : { reason: reason.value }
|
|
5941
|
+
};
|
|
5942
|
+
}
|
|
5125
5943
|
}
|
|
5126
|
-
|
|
5127
|
-
emitEnd();
|
|
5128
|
-
return content;
|
|
5944
|
+
return invalid2();
|
|
5129
5945
|
}
|
|
5130
5946
|
var askStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
5131
5947
|
var inlineSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
5132
5948
|
function zodToJsonSchema(schema) {
|
|
5133
5949
|
const cached = inlineSchemaCache.get(schema);
|
|
5134
5950
|
if (cached !== void 0) return cached;
|
|
5135
|
-
const result =
|
|
5951
|
+
const result = import_zod2.z.toJSONSchema(schema, { unrepresentable: "any" });
|
|
5136
5952
|
delete result.$schema;
|
|
5137
5953
|
Object.freeze(result);
|
|
5138
5954
|
inlineSchemaCache.set(schema, result);
|
|
@@ -5151,7 +5967,7 @@ var nativeSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
|
5151
5967
|
function deriveNativeSchema(schema) {
|
|
5152
5968
|
const cached = nativeSchemaCache.get(schema);
|
|
5153
5969
|
if (cached !== void 0) return cached;
|
|
5154
|
-
const json =
|
|
5970
|
+
const json = import_zod2.z.toJSONSchema(schema, { unrepresentable: "any", io: "input" });
|
|
5155
5971
|
delete json.$schema;
|
|
5156
5972
|
nativeSchemaCache.set(schema, json);
|
|
5157
5973
|
return json;
|
|
@@ -5159,7 +5975,7 @@ function deriveNativeSchema(schema) {
|
|
|
5159
5975
|
function renderSchemaForPrompt(schema) {
|
|
5160
5976
|
const cached = promptSchemaCache.get(schema);
|
|
5161
5977
|
if (cached !== void 0) return cached;
|
|
5162
|
-
const json =
|
|
5978
|
+
const json = import_zod2.z.toJSONSchema(schema, {
|
|
5163
5979
|
unrepresentable: "any",
|
|
5164
5980
|
io: "input",
|
|
5165
5981
|
reused: "ref"
|
|
@@ -5260,9 +6076,8 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5260
6076
|
providerRegistry;
|
|
5261
6077
|
sessionHistory;
|
|
5262
6078
|
onTrace;
|
|
5263
|
-
onToken;
|
|
5264
|
-
onToolCall;
|
|
5265
6079
|
pendingDecisions;
|
|
6080
|
+
awaitHumanClaims;
|
|
5266
6081
|
budgetContext;
|
|
5267
6082
|
stateStore;
|
|
5268
6083
|
/** Root step counter for this execution. Inherited by every ctx.ask()
|
|
@@ -5283,27 +6098,27 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5283
6098
|
* the caller-supplied key.
|
|
5284
6099
|
*/
|
|
5285
6100
|
autoCheckpointCounters;
|
|
5286
|
-
|
|
6101
|
+
branchDrainState;
|
|
6102
|
+
/** Root-shared idempotency guards for workflow lifecycle emission.
|
|
5287
6103
|
* Both `runtime.execute()` and `runtime.stream()` have paths where a
|
|
5288
6104
|
* post-emit side-effect (checkpoint deletion, state-store persistence)
|
|
5289
6105
|
* can throw AFTER `_emitWorkflowEnd({status: 'completed'})` has already
|
|
5290
6106
|
* fired — the outer catch would then fire `_emitWorkflowEnd({status:
|
|
5291
6107
|
* 'failed'})` for a second time. These flags make both emitters
|
|
5292
6108
|
* single-fire so consumers never see paired-then-conflicting terminal
|
|
5293
|
-
* events for one execution.
|
|
5294
|
-
|
|
5295
|
-
|
|
6109
|
+
* events for one execution. Sharing the state with child contexts also
|
|
6110
|
+
* suppresses late branch events after bounded finalization. */
|
|
6111
|
+
workflowLifecycleState;
|
|
5296
6112
|
signal;
|
|
5297
6113
|
summaryCache;
|
|
5298
6114
|
workflowName;
|
|
5299
6115
|
mcpManager;
|
|
5300
6116
|
spanManager;
|
|
5301
6117
|
memoryManager;
|
|
5302
|
-
resumeMode;
|
|
5303
6118
|
toolOverrides;
|
|
5304
6119
|
awaitHumanHandler;
|
|
5305
|
-
onAgentStart;
|
|
5306
6120
|
onAgentCallComplete;
|
|
6121
|
+
_onDecisionCleanupFailed;
|
|
5307
6122
|
/** Shared mutable slot for the lazy `AxlEventBus`. The slot is shared
|
|
5308
6123
|
* by reference across parent/child contexts so a late allocation
|
|
5309
6124
|
* (consumer subscribes after a child context exists) is visible
|
|
@@ -5312,6 +6127,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5312
6127
|
* contexts that never observe). */
|
|
5313
6128
|
_busRef;
|
|
5314
6129
|
_eventStreamOptions;
|
|
6130
|
+
_forceStreaming;
|
|
5315
6131
|
/** Removes the constructor-registered `'abort'` listener from
|
|
5316
6132
|
* `this.signal` so a long-lived signal (e.g., a request-scoped or
|
|
5317
6133
|
* process-wide signal reused across many `runtime.createContext()` /
|
|
@@ -5331,8 +6147,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5331
6147
|
* *between* asks. `ctx.events.partialObjects` is the coalescing view
|
|
5332
6148
|
* designed for streaming-structured-output UIs.
|
|
5333
6149
|
* - **Ad-hoc contexts** from `runtime.createContext()`: the same
|
|
5334
|
-
* iterable
|
|
5335
|
-
* `onAgentStart` callbacks.
|
|
6150
|
+
* iterable provides typed per-context observation.
|
|
5336
6151
|
* - **Cross-execution**: prefer `runtime.on('trace', …)` instead — that
|
|
5337
6152
|
* fans out across all executions, while `ctx.events` is per-context.
|
|
5338
6153
|
*
|
|
@@ -5347,9 +6162,9 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5347
6162
|
*
|
|
5348
6163
|
* **Subscribe before the first `ctx.ask()`.** The streaming code
|
|
5349
6164
|
* path inside `ctx.ask()` activates only when an observer is
|
|
5350
|
-
* present at the time the ask starts (`_streamingEnabled` —
|
|
5351
|
-
*
|
|
5352
|
-
*
|
|
6165
|
+
* present at the time the ask starts (`_streamingEnabled` — an explicit
|
|
6166
|
+
* runtime streaming mode or allocated `ctx.events`). If you allocate
|
|
6167
|
+
* `ctx.events` AFTER a `ctx.ask()` has
|
|
5353
6168
|
* begun, that in-flight ask will not stream `token` /
|
|
5354
6169
|
* `partial_object` events at all (the agent loop went through
|
|
5355
6170
|
* `provider.chat` instead of `provider.stream`). Subsequent asks
|
|
@@ -5388,18 +6203,16 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5388
6203
|
this._busRef.current?._finish();
|
|
5389
6204
|
this.abortListenerCleanup?.();
|
|
5390
6205
|
}
|
|
5391
|
-
/** True
|
|
5392
|
-
*
|
|
5393
|
-
*
|
|
5394
|
-
* been allocated (a workflow-handler consumer subscribed before
|
|
5395
|
-
* the ask). `ctx.ask` reads this to decide whether to enter the
|
|
6206
|
+
/** True when asks should use provider streaming: `runtime.stream()` set an
|
|
6207
|
+
* explicit internal mode or `ctx.events` has been allocated. `ctx.ask`
|
|
6208
|
+
* reads this to decide whether to enter the
|
|
5396
6209
|
* streaming code path; the gate is re-checked per ask, so a
|
|
5397
6210
|
* consumer subscribing AFTER the first ask started still gets
|
|
5398
6211
|
* streaming on the next one. The check `_busRef.current !== undefined`
|
|
5399
6212
|
* is a one-way flag — `_finish` does not unset the reference, so
|
|
5400
6213
|
* once an observer was present, every subsequent ask streams. */
|
|
5401
6214
|
get _streamingEnabled() {
|
|
5402
|
-
return this.
|
|
6215
|
+
return this._forceStreaming || this._busRef.current !== void 0;
|
|
5403
6216
|
}
|
|
5404
6217
|
constructor(init) {
|
|
5405
6218
|
this.input = init.input;
|
|
@@ -5409,9 +6222,8 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5409
6222
|
this.providerRegistry = init.providerRegistry;
|
|
5410
6223
|
this.sessionHistory = init.sessionHistory ?? [];
|
|
5411
6224
|
this.onTrace = init.onTrace;
|
|
5412
|
-
this.onToken = init.onToken;
|
|
5413
|
-
this.onToolCall = init.onToolCall;
|
|
5414
6225
|
this.pendingDecisions = init.pendingDecisions;
|
|
6226
|
+
this.awaitHumanClaims = init.awaitHumanClaims ?? /* @__PURE__ */ new Map();
|
|
5415
6227
|
this.budgetContext = init.budgetContext;
|
|
5416
6228
|
this.stateStore = init.stateStore;
|
|
5417
6229
|
this.signal = init.signal;
|
|
@@ -5419,13 +6231,13 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5419
6231
|
this.mcpManager = init.mcpManager;
|
|
5420
6232
|
this.spanManager = init.spanManager;
|
|
5421
6233
|
this.memoryManager = init.memoryManager;
|
|
5422
|
-
this.resumeMode = init.resumeMode ?? false;
|
|
5423
6234
|
this.toolOverrides = init.toolOverrides;
|
|
5424
6235
|
this.awaitHumanHandler = init.awaitHumanHandler;
|
|
5425
|
-
this.onAgentStart = init.onAgentStart;
|
|
5426
6236
|
this.onAgentCallComplete = init.onAgentCallComplete;
|
|
6237
|
+
this._onDecisionCleanupFailed = init._onDecisionCleanupFailed;
|
|
5427
6238
|
this._busRef = init._busRef ?? { current: void 0 };
|
|
5428
6239
|
this._eventStreamOptions = init.eventStreamOptions;
|
|
6240
|
+
this._forceStreaming = init._forceStreaming ?? false;
|
|
5429
6241
|
if (init._busRef === void 0 && this.signal && !this.signal.aborted) {
|
|
5430
6242
|
const signal = this.signal;
|
|
5431
6243
|
const onAbort = () => {
|
|
@@ -5441,6 +6253,15 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5441
6253
|
byAgent: /* @__PURE__ */ new Map(),
|
|
5442
6254
|
root: 0
|
|
5443
6255
|
};
|
|
6256
|
+
const branchDrainTimeoutMs = resolveBranchDrainTimeoutMs(init.branchDrainTimeoutMs);
|
|
6257
|
+
this.branchDrainState = init.branchDrainState ?? {
|
|
6258
|
+
pending: /* @__PURE__ */ new Set(),
|
|
6259
|
+
timeoutMs: branchDrainTimeoutMs
|
|
6260
|
+
};
|
|
6261
|
+
this.workflowLifecycleState = init.workflowLifecycleState ?? {
|
|
6262
|
+
startEmitted: false,
|
|
6263
|
+
endEmitted: false
|
|
6264
|
+
};
|
|
5444
6265
|
if (init.metadata?.summaryCache) {
|
|
5445
6266
|
this.summaryCache = init.metadata.summaryCache;
|
|
5446
6267
|
}
|
|
@@ -5449,16 +6270,9 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5449
6270
|
* Create a child context for nested agent invocations (e.g., agent-as-tool).
|
|
5450
6271
|
* Shares: budget tracking, abort signals, trace emission, provider registry,
|
|
5451
6272
|
* state store, span manager, memory manager, MCP manager, config,
|
|
5452
|
-
* awaitHuman handler, pending decisions, tool overrides,
|
|
5453
|
-
* streaming callbacks (onToken / onAgentStart / onToolCall).
|
|
6273
|
+
* awaitHuman handler, pending decisions, tool overrides, and event bus.
|
|
5454
6274
|
* Isolates: session history.
|
|
5455
6275
|
*
|
|
5456
|
-
* Streaming callbacks now propagate into nested asks because every callback
|
|
5457
|
-
* invocation carries `meta.askId`/`meta.parentAskId`/`meta.depth` so
|
|
5458
|
-
* consumers that want root-only behavior can filter on `meta.depth === 0`
|
|
5459
|
-
* instead of relying on the runtime to drop nested events. This is the
|
|
5460
|
-
* "nested ask visibility" fix from spec §3.2.
|
|
5461
|
-
*
|
|
5462
6276
|
* The shared step counter lives in `askStorage` (ALS), so there is no
|
|
5463
6277
|
* per-context counter to pass through anymore. Nested events are
|
|
5464
6278
|
* correlated to their parent via `parentAskId` (set on every nested ask
|
|
@@ -5479,12 +6293,11 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5479
6293
|
spanManager: this.spanManager,
|
|
5480
6294
|
memoryManager: this.memoryManager,
|
|
5481
6295
|
onTrace: this.onTrace,
|
|
5482
|
-
onToken: this.onToken,
|
|
5483
|
-
onToolCall: this.onToolCall,
|
|
5484
|
-
onAgentStart: this.onAgentStart,
|
|
5485
6296
|
onAgentCallComplete: this.onAgentCallComplete,
|
|
6297
|
+
_onDecisionCleanupFailed: this._onDecisionCleanupFailed,
|
|
5486
6298
|
awaitHumanHandler: this.awaitHumanHandler,
|
|
5487
6299
|
pendingDecisions: this.pendingDecisions,
|
|
6300
|
+
awaitHumanClaims: this.awaitHumanClaims,
|
|
5488
6301
|
toolOverrides: this.toolOverrides,
|
|
5489
6302
|
signal: this.signal,
|
|
5490
6303
|
workflowName: this.workflowName,
|
|
@@ -5492,12 +6305,15 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5492
6305
|
// emitted from `ctx.ask` / spawn / race / parallel / map in this
|
|
5493
6306
|
// child context don't collide with the parent's in the state store.
|
|
5494
6307
|
autoCheckpointCounters: this.autoCheckpointCounters,
|
|
6308
|
+
branchDrainState: this.branchDrainState,
|
|
6309
|
+
workflowLifecycleState: this.workflowLifecycleState,
|
|
5495
6310
|
// Share the parent's bus slot (mutable ref). Late allocation in
|
|
5496
6311
|
// either parent or child propagates because both read the same
|
|
5497
6312
|
// slot. Nested-ask events (agent-as-tool pattern) bubble up to
|
|
5498
6313
|
// the parent's iterator with `parentAskId`/`depth` correlation
|
|
5499
6314
|
// intact.
|
|
5500
6315
|
_busRef: this._busRef,
|
|
6316
|
+
_forceStreaming: this._forceStreaming,
|
|
5501
6317
|
eventStreamOptions: this._eventStreamOptions
|
|
5502
6318
|
// Isolated: sessionHistory (empty)
|
|
5503
6319
|
});
|
|
@@ -5510,28 +6326,194 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5510
6326
|
get currentSignal() {
|
|
5511
6327
|
return signalStorage.getStore() ?? this.signal;
|
|
5512
6328
|
}
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
6329
|
+
_registerBranchDrain(promise) {
|
|
6330
|
+
const state = this.branchDrainState;
|
|
6331
|
+
state.pending.add(promise);
|
|
6332
|
+
void promise.then(
|
|
6333
|
+
() => state.pending.delete(promise),
|
|
6334
|
+
(error) => {
|
|
6335
|
+
state.pending.delete(promise);
|
|
6336
|
+
if (!state.overflow && isEventStreamOverflowError(error)) {
|
|
6337
|
+
state.overflow = error;
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
);
|
|
6341
|
+
}
|
|
6342
|
+
/** Wait for race/quorum losers (including nested branch work) to settle.
|
|
6343
|
+
* Primitive calls still resolve as soon as their winner/quorum is known;
|
|
6344
|
+
* this is only the runtime's terminal/persistence barrier. */
|
|
6345
|
+
async _drainBranchWork() {
|
|
6346
|
+
const state = this.branchDrainState;
|
|
6347
|
+
state.deadline ??= Date.now() + state.timeoutMs;
|
|
6348
|
+
while (state.pending.size > 0) {
|
|
6349
|
+
const overflow2 = state.overflow;
|
|
6350
|
+
state.overflow = void 0;
|
|
6351
|
+
if (overflow2) throw overflow2;
|
|
6352
|
+
const remaining = state.deadline - Date.now();
|
|
6353
|
+
if (remaining <= 0) {
|
|
6354
|
+
return {
|
|
6355
|
+
complete: false,
|
|
6356
|
+
reason: "branch_drain_timeout",
|
|
6357
|
+
pendingContinuations: state.pending.size,
|
|
6358
|
+
timeoutMs: state.timeoutMs
|
|
6359
|
+
};
|
|
6360
|
+
}
|
|
6361
|
+
let timer;
|
|
6362
|
+
const settled = await Promise.race([
|
|
6363
|
+
Promise.allSettled([...state.pending]).then(() => true),
|
|
6364
|
+
new Promise((resolve2) => {
|
|
6365
|
+
timer = setTimeout(() => resolve2(false), remaining);
|
|
6366
|
+
})
|
|
6367
|
+
]);
|
|
6368
|
+
if (timer) clearTimeout(timer);
|
|
6369
|
+
if (!settled) {
|
|
6370
|
+
return {
|
|
6371
|
+
complete: false,
|
|
6372
|
+
reason: "branch_drain_timeout",
|
|
6373
|
+
pendingContinuations: state.pending.size,
|
|
6374
|
+
timeoutMs: state.timeoutMs
|
|
6375
|
+
};
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
const overflow = state.overflow;
|
|
6379
|
+
state.overflow = void 0;
|
|
6380
|
+
if (overflow) throw overflow;
|
|
6381
|
+
state.deadline = void 0;
|
|
6382
|
+
return { complete: true };
|
|
6383
|
+
}
|
|
6384
|
+
/** Resolve, execute, and observe one non-handoff tool request. Rejections
|
|
6385
|
+
* never start. Every accepted request emits one terminal event before a
|
|
6386
|
+
* continuation message or abort escapes this coordinator. */
|
|
6387
|
+
async observeToolInvocation(agent2, toolCall, currentMessages, availableTools) {
|
|
6388
|
+
const signal = this.currentSignal;
|
|
6389
|
+
signal?.throwIfAborted();
|
|
6390
|
+
const requestedTool = toolCall.function.name;
|
|
6391
|
+
const configuredTool = agent2._config.tools?.find(
|
|
6392
|
+
(candidate) => candidate.name === requestedTool
|
|
6393
|
+
);
|
|
6394
|
+
const override = this.toolOverrides?.get(requestedTool);
|
|
6395
|
+
const mcpManager = this.mcpManager;
|
|
6396
|
+
const mcpMatch = !configuredTool ? mcpManager?.getToolsForAgent(agent2._config.mcp, agent2._config.mcpTools).find(({ tool: tool2 }) => tool2.name === requestedTool) : void 0;
|
|
6397
|
+
const parsed = parseToolInvocation({
|
|
6398
|
+
toolCall,
|
|
6399
|
+
configuredTool,
|
|
6400
|
+
override,
|
|
6401
|
+
...mcpMatch && mcpManager ? {
|
|
6402
|
+
mcpCall: (args) => mcpManager.callTool(requestedTool, args, mcpMatch.server),
|
|
6403
|
+
mcpTraceName: `${mcpMatch.server}:${requestedTool}`
|
|
6404
|
+
} : {},
|
|
6405
|
+
availableTools
|
|
6406
|
+
});
|
|
6407
|
+
signal?.throwIfAborted();
|
|
6408
|
+
if ("kind" in parsed) {
|
|
6409
|
+
this.emitEvent({
|
|
6410
|
+
type: "tool_call_rejected",
|
|
6411
|
+
agent: agent2._name,
|
|
6412
|
+
tool: parsed.toolName,
|
|
6413
|
+
callId: parsed.callId,
|
|
6414
|
+
data: parsed.data
|
|
6415
|
+
});
|
|
6416
|
+
currentMessages.push({
|
|
6417
|
+
role: "tool",
|
|
6418
|
+
content: parsed.modelMessage,
|
|
6419
|
+
tool_call_id: parsed.callId
|
|
6420
|
+
});
|
|
6421
|
+
return;
|
|
6422
|
+
}
|
|
6423
|
+
const startArgs = cloneToolArguments(parsed.args);
|
|
6424
|
+
this.emitEvent({
|
|
6425
|
+
type: "tool_call_start",
|
|
6426
|
+
agent: agent2._name,
|
|
6427
|
+
tool: parsed.toolName,
|
|
6428
|
+
callId: parsed.callId,
|
|
6429
|
+
data: {
|
|
6430
|
+
args: startArgs,
|
|
6431
|
+
...parsed.requestedTool !== parsed.toolName ? { requestedTool: parsed.requestedTool } : {}
|
|
6432
|
+
}
|
|
6433
|
+
});
|
|
6434
|
+
const startedAt = Date.now();
|
|
6435
|
+
const requestApproval = async () => {
|
|
6436
|
+
const approve = async () => {
|
|
6437
|
+
const approvalArgs = cloneToolArguments(parsed.args);
|
|
6438
|
+
const decision = await this.awaitHuman({
|
|
6439
|
+
channel: "tool_approval",
|
|
6440
|
+
prompt: `Tool "${parsed.toolName}" wants to execute with args: ${JSON.stringify(parsed.args)}`,
|
|
6441
|
+
metadata: { toolName: parsed.toolName, args: approvalArgs, agent: agent2._name }
|
|
6442
|
+
});
|
|
6443
|
+
return decision.approved ? { approved: true } : { approved: false, reason: decision.reason ?? "Denied by human" };
|
|
5532
6444
|
};
|
|
6445
|
+
const approval = this.spanManager ? await this.spanManager.withSpanAsync(
|
|
6446
|
+
"axl.tool.approval",
|
|
6447
|
+
{ "axl.tool.name": parsed.toolName, "axl.agent.name": agent2._name },
|
|
6448
|
+
async (span) => {
|
|
6449
|
+
const value = await approve();
|
|
6450
|
+
span.setAttribute("axl.tool.approval.approved", value.approved);
|
|
6451
|
+
return value;
|
|
6452
|
+
}
|
|
6453
|
+
) : await approve();
|
|
6454
|
+
this.emitEvent({
|
|
6455
|
+
type: "tool_approval",
|
|
6456
|
+
agent: agent2._name,
|
|
6457
|
+
tool: parsed.toolName,
|
|
6458
|
+
callId: parsed.callId,
|
|
6459
|
+
data: {
|
|
6460
|
+
approved: approval.approved,
|
|
6461
|
+
args: cloneToolArguments(parsed.args),
|
|
6462
|
+
...approval.reason ? { reason: approval.reason } : {}
|
|
6463
|
+
}
|
|
6464
|
+
});
|
|
6465
|
+
return approval;
|
|
6466
|
+
};
|
|
6467
|
+
let terminalEmitted = false;
|
|
6468
|
+
const executeAndObserve = async (span) => {
|
|
6469
|
+
const settlement2 = await settleAcceptedTool({
|
|
6470
|
+
invocation: parsed,
|
|
6471
|
+
context: this,
|
|
6472
|
+
signal,
|
|
6473
|
+
requestApproval,
|
|
6474
|
+
createChildContext: () => this.createChildContext()
|
|
6475
|
+
});
|
|
6476
|
+
const duration = Date.now() - startedAt;
|
|
6477
|
+
span?.setAttribute("axl.tool.duration", duration);
|
|
6478
|
+
if (span) recordToolSpanOutcome(span, settlement2.outcome);
|
|
6479
|
+
if (terminalEmitted) {
|
|
6480
|
+
throw new Error(`Tool invocation ${parsed.callId} emitted more than one terminal event`);
|
|
6481
|
+
}
|
|
6482
|
+
terminalEmitted = true;
|
|
6483
|
+
try {
|
|
6484
|
+
this.emitEvent({
|
|
6485
|
+
type: "tool_call_end",
|
|
6486
|
+
agent: agent2._name,
|
|
6487
|
+
tool: parsed.toolName,
|
|
6488
|
+
callId: parsed.callId,
|
|
6489
|
+
duration,
|
|
6490
|
+
data: {
|
|
6491
|
+
args: cloneToolArguments(parsed.args),
|
|
6492
|
+
...parsed.requestedTool !== parsed.toolName ? { requestedTool: parsed.requestedTool } : {},
|
|
6493
|
+
outcome: settlement2.outcome
|
|
6494
|
+
}
|
|
6495
|
+
});
|
|
6496
|
+
} catch (error) {
|
|
6497
|
+
if (error instanceof Error && settlement2.abortError !== void 0) {
|
|
6498
|
+
throw preserveErrorCause(error, settlement2.abortError);
|
|
6499
|
+
}
|
|
6500
|
+
throw error;
|
|
6501
|
+
}
|
|
6502
|
+
return settlement2;
|
|
6503
|
+
};
|
|
6504
|
+
const settlement = this.spanManager ? await this.spanManager.withSpanAsync(
|
|
6505
|
+
"axl.tool.call",
|
|
6506
|
+
{ "axl.tool.name": parsed.toolName, "axl.agent.name": agent2._name },
|
|
6507
|
+
executeAndObserve
|
|
6508
|
+
) : await executeAndObserve();
|
|
6509
|
+
if (settlement.providerContent !== void 0) {
|
|
6510
|
+
currentMessages.push({
|
|
6511
|
+
role: "tool",
|
|
6512
|
+
content: settlement.providerContent,
|
|
6513
|
+
tool_call_id: parsed.callId
|
|
6514
|
+
});
|
|
5533
6515
|
}
|
|
5534
|
-
|
|
6516
|
+
if (settlement.abortError !== void 0) throw settlement.abortError;
|
|
5535
6517
|
}
|
|
5536
6518
|
// ── ctx.ask() ─────────────────────────────────────────────────────────
|
|
5537
6519
|
async ask(agent2, prompt, options) {
|
|
@@ -5560,18 +6542,21 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5560
6542
|
const resolveCtx = options?.metadata ? { metadata: { ...this.metadata, ...options.metadata } } : { metadata: this.metadata };
|
|
5561
6543
|
const usageCapture = {};
|
|
5562
6544
|
const doCall = async () => {
|
|
5563
|
-
const
|
|
6545
|
+
const result2 = await this.executeAgentCall(
|
|
5564
6546
|
agent2,
|
|
5565
6547
|
prompt,
|
|
5566
6548
|
options,
|
|
5567
6549
|
void 0,
|
|
5568
6550
|
usageCapture
|
|
5569
6551
|
);
|
|
5570
|
-
return
|
|
6552
|
+
return result2;
|
|
5571
6553
|
};
|
|
5572
6554
|
let outcome;
|
|
6555
|
+
let askFailure;
|
|
6556
|
+
let askFailed = false;
|
|
6557
|
+
let result;
|
|
5573
6558
|
try {
|
|
5574
|
-
|
|
6559
|
+
result = this.spanManager ? await this.spanManager.withSpanAsync(
|
|
5575
6560
|
"axl.agent.ask",
|
|
5576
6561
|
{
|
|
5577
6562
|
"axl.agent.name": agent2._name,
|
|
@@ -5623,43 +6608,41 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
5623
6608
|
stop: options?.stop ?? agent2._config.stop,
|
|
5624
6609
|
providerOptions: options?.providerOptions ?? agent2._config.providerOptions
|
|
5625
6610
|
});
|
|
5626
|
-
} catch (hookErr) {
|
|
5627
|
-
console.error(
|
|
5628
|
-
"[axl] onAgentCallComplete hook threw; ask outcome unchanged:",
|
|
5629
|
-
hookErr instanceof Error ? hookErr.message : String(hookErr)
|
|
5630
|
-
);
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5633
|
-
return result;
|
|
5634
|
-
} catch (err) {
|
|
5635
|
-
outcome = {
|
|
5636
|
-
ok: false,
|
|
5637
|
-
error: err instanceof Error ? err.message : String(err)
|
|
5638
|
-
};
|
|
5639
|
-
throw err;
|
|
5640
|
-
} finally {
|
|
5641
|
-
try {
|
|
5642
|
-
this.emitEvent({
|
|
5643
|
-
type: "ask_end",
|
|
5644
|
-
outcome: outcome ?? {
|
|
5645
|
-
ok: false,
|
|
5646
|
-
error: "ask_end emitted without outcome \u2014 internal bug"
|
|
5647
|
-
},
|
|
5648
|
-
cost: frame.askCost.value,
|
|
5649
|
-
...frame.askUnpriced ? { unpriced: true } : {},
|
|
5650
|
-
duration: Date.now() - askStart
|
|
5651
|
-
});
|
|
5652
|
-
} catch (emitErr) {
|
|
5653
|
-
if (emitErr instanceof EventStreamOverflowError && outcome && !outcome.ok) {
|
|
6611
|
+
} catch (hookErr) {
|
|
5654
6612
|
console.error(
|
|
5655
|
-
"[axl]
|
|
5656
|
-
|
|
6613
|
+
"[axl] onAgentCallComplete hook threw; ask outcome unchanged:",
|
|
6614
|
+
hookErr instanceof Error ? hookErr.message : String(hookErr)
|
|
5657
6615
|
);
|
|
5658
|
-
} else {
|
|
5659
|
-
throw emitErr;
|
|
5660
6616
|
}
|
|
5661
6617
|
}
|
|
6618
|
+
} catch (err) {
|
|
6619
|
+
askFailed = true;
|
|
6620
|
+
askFailure = err;
|
|
6621
|
+
outcome = {
|
|
6622
|
+
ok: false,
|
|
6623
|
+
error: err instanceof Error ? err.message : String(err)
|
|
6624
|
+
};
|
|
6625
|
+
}
|
|
6626
|
+
let terminalFailure;
|
|
6627
|
+
let terminalFailed = false;
|
|
6628
|
+
try {
|
|
6629
|
+
this.emitEvent({
|
|
6630
|
+
type: "ask_end",
|
|
6631
|
+
outcome: outcome ?? {
|
|
6632
|
+
ok: false,
|
|
6633
|
+
error: "ask_end emitted without outcome \u2014 internal bug"
|
|
6634
|
+
},
|
|
6635
|
+
cost: frame.askCost.value,
|
|
6636
|
+
...frame.askUnpriced ? { unpriced: true } : {},
|
|
6637
|
+
duration: Date.now() - askStart
|
|
6638
|
+
});
|
|
6639
|
+
} catch (error) {
|
|
6640
|
+
terminalFailed = true;
|
|
6641
|
+
terminalFailure = isEventStreamOverflowError(error) ? preserveErrorCause(error, askFailure) : error;
|
|
5662
6642
|
}
|
|
6643
|
+
if (terminalFailed) throw terminalFailure;
|
|
6644
|
+
if (askFailed) throw askFailure;
|
|
6645
|
+
return result;
|
|
5663
6646
|
});
|
|
5664
6647
|
},
|
|
5665
6648
|
{ agent: agentName }
|
|
@@ -5881,7 +6864,6 @@ ${appendedSchemaText}`;
|
|
|
5881
6864
|
}
|
|
5882
6865
|
} : { type: "json_object" };
|
|
5883
6866
|
}
|
|
5884
|
-
const callbackMeta = this.currentCallbackMeta(agent2._name);
|
|
5885
6867
|
const callParams = {
|
|
5886
6868
|
...chatOptions.temperature !== void 0 ? { temperature: chatOptions.temperature } : {},
|
|
5887
6869
|
maxTokens: chatOptions.maxTokens,
|
|
@@ -5920,7 +6902,6 @@ ${appendedSchemaText}`;
|
|
|
5920
6902
|
...messagesSnapshot ? { messages: messagesSnapshot } : {}
|
|
5921
6903
|
}
|
|
5922
6904
|
});
|
|
5923
|
-
this.onAgentStart?.({ agent: agent2._name, model: modelUri }, callbackMeta);
|
|
5924
6905
|
let response;
|
|
5925
6906
|
try {
|
|
5926
6907
|
this.currentSignal?.throwIfAborted();
|
|
@@ -5930,7 +6911,7 @@ ${appendedSchemaText}`;
|
|
|
5930
6911
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
5931
6912
|
let streamProviderMetadata;
|
|
5932
6913
|
let thinkingContent = "";
|
|
5933
|
-
const streamingObjectEnabled = !!options?.schema && toolDefs.length === 0 && options.schema instanceof
|
|
6914
|
+
const streamingObjectEnabled = !!options?.schema && toolDefs.length === 0 && options.schema instanceof import_zod2.z.ZodObject;
|
|
5934
6915
|
const currentAttempt = schemaRetries + 1;
|
|
5935
6916
|
const walker = streamingObjectEnabled ? new StreamingWalker({
|
|
5936
6917
|
onStringDelta: (path, delta) => {
|
|
@@ -5946,7 +6927,6 @@ ${appendedSchemaText}`;
|
|
|
5946
6927
|
if (chunk.type === "text_delta") {
|
|
5947
6928
|
content2 += chunk.content;
|
|
5948
6929
|
this.emitEvent({ type: "token", data: chunk.content });
|
|
5949
|
-
this.onToken?.(chunk.content, callbackMeta);
|
|
5950
6930
|
if (walker) {
|
|
5951
6931
|
walker.processChunk(chunk.content);
|
|
5952
6932
|
if (walker.consumeBoundary()) {
|
|
@@ -6056,6 +7036,7 @@ ${appendedSchemaText}`;
|
|
|
6056
7036
|
...retryReason ? { retryReason } : {}
|
|
6057
7037
|
}
|
|
6058
7038
|
});
|
|
7039
|
+
this.currentSignal?.throwIfAborted();
|
|
6059
7040
|
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
6060
7041
|
currentMessages.push({
|
|
6061
7042
|
role: "assistant",
|
|
@@ -6225,263 +7206,12 @@ ${appendedSchemaText}`;
|
|
|
6225
7206
|
return await handoffFn();
|
|
6226
7207
|
}
|
|
6227
7208
|
}
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
toolArgs2 = JSON.parse(toolCall.function.arguments);
|
|
6235
|
-
} catch {
|
|
6236
|
-
currentMessages.push({
|
|
6237
|
-
role: "tool",
|
|
6238
|
-
content: `Error: Invalid JSON in tool arguments. Please provide valid JSON.`,
|
|
6239
|
-
tool_call_id: toolCall.id
|
|
6240
|
-
});
|
|
6241
|
-
continue;
|
|
6242
|
-
}
|
|
6243
|
-
this.emitEvent({
|
|
6244
|
-
type: "tool_call_start",
|
|
6245
|
-
tool: toolName,
|
|
6246
|
-
callId: toolCall.id,
|
|
6247
|
-
data: { args: toolArgs2 }
|
|
6248
|
-
});
|
|
6249
|
-
this.onToolCall?.(
|
|
6250
|
-
{ name: toolName, args: toolArgs2, callId: toolCall.id },
|
|
6251
|
-
callbackMeta
|
|
6252
|
-
);
|
|
6253
|
-
const toolStart2 = Date.now();
|
|
6254
|
-
const suppressErrorShapeInspection2 = tool2?.sensitive === true || tool2?.toModelOutput !== void 0;
|
|
6255
|
-
const executeOverride = async () => {
|
|
6256
|
-
try {
|
|
6257
|
-
return { kind: "returned", value: await toolOverride(toolArgs2) };
|
|
6258
|
-
} catch (err) {
|
|
6259
|
-
return {
|
|
6260
|
-
kind: "thrown",
|
|
6261
|
-
value: { error: err instanceof Error ? err.message : String(err) }
|
|
6262
|
-
};
|
|
6263
|
-
}
|
|
6264
|
-
};
|
|
6265
|
-
const outcome = this.spanManager ? await this.spanManager.withSpanAsync(
|
|
6266
|
-
"axl.tool.call",
|
|
6267
|
-
{
|
|
6268
|
-
"axl.tool.name": toolName,
|
|
6269
|
-
"axl.agent.name": agent2._name
|
|
6270
|
-
},
|
|
6271
|
-
async (span) => {
|
|
6272
|
-
const result = await executeOverride();
|
|
6273
|
-
span.setAttribute("axl.tool.duration", Date.now() - toolStart2);
|
|
6274
|
-
recordToolSpanResult(span, result.value, suppressErrorShapeInspection2);
|
|
6275
|
-
return result;
|
|
6276
|
-
}
|
|
6277
|
-
) : await executeOverride();
|
|
6278
|
-
const toolResult2 = outcome.value;
|
|
6279
|
-
const resultContent2 = finalizeToolResult({
|
|
6280
|
-
toolName,
|
|
6281
|
-
configuredTool: tool2,
|
|
6282
|
-
outcome,
|
|
6283
|
-
legacyContent: () => tool2?.sensitive ? "[REDACTED - sensitive tool output]" : JSON.stringify(toolResult2),
|
|
6284
|
-
emitEnd: () => {
|
|
6285
|
-
const toolDuration2 = Date.now() - toolStart2;
|
|
6286
|
-
this.emitEvent({
|
|
6287
|
-
type: "tool_call_end",
|
|
6288
|
-
agent: agent2._name,
|
|
6289
|
-
tool: toolName,
|
|
6290
|
-
duration: toolDuration2,
|
|
6291
|
-
data: { args: toolArgs2, result: toolResult2, callId: toolCall.id }
|
|
6292
|
-
});
|
|
6293
|
-
},
|
|
6294
|
-
beforeProjection: () => this.currentSignal?.throwIfAborted()
|
|
6295
|
-
});
|
|
6296
|
-
currentMessages.push({
|
|
6297
|
-
role: "tool",
|
|
6298
|
-
content: resultContent2,
|
|
6299
|
-
tool_call_id: toolCall.id
|
|
6300
|
-
});
|
|
6301
|
-
continue;
|
|
6302
|
-
}
|
|
6303
|
-
if (!tool2 && !isMcpTool) {
|
|
6304
|
-
this.emitEvent({ type: "tool_denied", agent: agent2._name, tool: toolName });
|
|
6305
|
-
currentMessages.push({
|
|
6306
|
-
role: "tool",
|
|
6307
|
-
content: `Tool "${toolName}" is not available. Available tools: ${agent2._config.tools?.map((t) => t.name).join(", ") ?? "none"}`,
|
|
6308
|
-
tool_call_id: toolCall.id
|
|
6309
|
-
});
|
|
6310
|
-
continue;
|
|
6311
|
-
}
|
|
6312
|
-
let toolArgs;
|
|
6313
|
-
try {
|
|
6314
|
-
toolArgs = JSON.parse(toolCall.function.arguments);
|
|
6315
|
-
} catch {
|
|
6316
|
-
currentMessages.push({
|
|
6317
|
-
role: "tool",
|
|
6318
|
-
content: `Error: Invalid JSON in tool arguments. Please provide valid JSON.`,
|
|
6319
|
-
tool_call_id: toolCall.id
|
|
6320
|
-
});
|
|
6321
|
-
continue;
|
|
6322
|
-
}
|
|
6323
|
-
this.emitEvent({
|
|
6324
|
-
type: "tool_call_start",
|
|
6325
|
-
tool: toolName,
|
|
6326
|
-
callId: toolCall.id,
|
|
6327
|
-
data: { args: toolArgs }
|
|
6328
|
-
});
|
|
6329
|
-
this.onToolCall?.({ name: toolName, args: toolArgs, callId: toolCall.id }, callbackMeta);
|
|
6330
|
-
const toolStart = Date.now();
|
|
6331
|
-
const suppressErrorShapeInspection = tool2?.sensitive === true || tool2?.toModelOutput !== void 0;
|
|
6332
|
-
if (tool2 && tool2.requireApproval) {
|
|
6333
|
-
const approvalFn = async () => {
|
|
6334
|
-
const decision = await this.awaitHuman({
|
|
6335
|
-
channel: "tool_approval",
|
|
6336
|
-
prompt: `Tool "${toolName}" wants to execute with args: ${JSON.stringify(toolArgs)}`,
|
|
6337
|
-
metadata: { toolName, args: toolArgs, agent: agent2._name }
|
|
6338
|
-
});
|
|
6339
|
-
if (!decision.approved) {
|
|
6340
|
-
const reason = decision.reason ?? "Denied by human";
|
|
6341
|
-
currentMessages.push({
|
|
6342
|
-
role: "tool",
|
|
6343
|
-
content: JSON.stringify({ error: `Tool denied by human: ${reason}` }),
|
|
6344
|
-
tool_call_id: toolCall.id
|
|
6345
|
-
});
|
|
6346
|
-
return { approved: false, reason };
|
|
6347
|
-
}
|
|
6348
|
-
return { approved: true };
|
|
6349
|
-
};
|
|
6350
|
-
let approvalOutcome;
|
|
6351
|
-
if (this.spanManager) {
|
|
6352
|
-
approvalOutcome = await this.spanManager.withSpanAsync(
|
|
6353
|
-
"axl.tool.approval",
|
|
6354
|
-
{
|
|
6355
|
-
"axl.tool.name": toolName,
|
|
6356
|
-
"axl.agent.name": agent2._name
|
|
6357
|
-
},
|
|
6358
|
-
async (span) => {
|
|
6359
|
-
const result = await approvalFn();
|
|
6360
|
-
span.setAttribute("axl.tool.approval.approved", result.approved);
|
|
6361
|
-
return result;
|
|
6362
|
-
}
|
|
6363
|
-
);
|
|
6364
|
-
} else {
|
|
6365
|
-
approvalOutcome = await approvalFn();
|
|
6366
|
-
}
|
|
6367
|
-
this.emitEvent({
|
|
6368
|
-
type: "tool_approval",
|
|
6369
|
-
agent: agent2._name,
|
|
6370
|
-
tool: toolName,
|
|
6371
|
-
data: {
|
|
6372
|
-
approved: approvalOutcome.approved,
|
|
6373
|
-
args: toolArgs,
|
|
6374
|
-
...approvalOutcome.reason ? { reason: approvalOutcome.reason } : {}
|
|
6375
|
-
}
|
|
6376
|
-
});
|
|
6377
|
-
if (!approvalOutcome.approved) continue;
|
|
6378
|
-
}
|
|
6379
|
-
if (tool2 && tool2.hooks?.before) {
|
|
6380
|
-
try {
|
|
6381
|
-
toolArgs = await tool2.hooks.before(toolArgs, this);
|
|
6382
|
-
} catch (err) {
|
|
6383
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
6384
|
-
currentMessages.push({
|
|
6385
|
-
role: "tool",
|
|
6386
|
-
content: JSON.stringify({ error: `Before hook error: ${errorMsg}` }),
|
|
6387
|
-
tool_call_id: toolCall.id
|
|
6388
|
-
});
|
|
6389
|
-
continue;
|
|
6390
|
-
}
|
|
6391
|
-
}
|
|
6392
|
-
const executeTool = async () => {
|
|
6393
|
-
let outcome;
|
|
6394
|
-
let resultContent2;
|
|
6395
|
-
if (isMcpTool && this.mcpManager) {
|
|
6396
|
-
try {
|
|
6397
|
-
const mcpResult = await this.mcpManager.callTool(toolName, toolArgs);
|
|
6398
|
-
outcome = { kind: "returned", value: mcpResult };
|
|
6399
|
-
resultContent2 = mcpResult.content.map(
|
|
6400
|
-
(c) => c.type === "text" ? c.text : `[${c.type}]`
|
|
6401
|
-
).join("\n");
|
|
6402
|
-
if (mcpResult.isError) {
|
|
6403
|
-
resultContent2 = `Error: ${resultContent2}`;
|
|
6404
|
-
}
|
|
6405
|
-
} catch (err) {
|
|
6406
|
-
outcome = {
|
|
6407
|
-
kind: "thrown",
|
|
6408
|
-
value: { error: err instanceof Error ? err.message : String(err) }
|
|
6409
|
-
};
|
|
6410
|
-
resultContent2 = JSON.stringify(outcome.value);
|
|
6411
|
-
}
|
|
6412
|
-
} else if (tool2) {
|
|
6413
|
-
const childCtx = this.createChildContext();
|
|
6414
|
-
try {
|
|
6415
|
-
outcome = { kind: "returned", value: await tool2._execute(toolArgs, childCtx) };
|
|
6416
|
-
} catch (err) {
|
|
6417
|
-
outcome = {
|
|
6418
|
-
kind: "thrown",
|
|
6419
|
-
value: { error: err instanceof Error ? err.message : String(err) }
|
|
6420
|
-
};
|
|
6421
|
-
}
|
|
6422
|
-
if (outcome.kind === "returned" && tool2.hooks?.after && !(suppressErrorShapeInspection ? isErrorShapedSafely(outcome.value) : isErrorShaped(outcome.value))) {
|
|
6423
|
-
try {
|
|
6424
|
-
outcome = {
|
|
6425
|
-
kind: "returned",
|
|
6426
|
-
value: await tool2.hooks.after(outcome.value, this)
|
|
6427
|
-
};
|
|
6428
|
-
} catch (err) {
|
|
6429
|
-
outcome = {
|
|
6430
|
-
kind: "thrown",
|
|
6431
|
-
value: {
|
|
6432
|
-
error: `After hook error: ${err instanceof Error ? err.message : String(err)}`
|
|
6433
|
-
}
|
|
6434
|
-
};
|
|
6435
|
-
}
|
|
6436
|
-
}
|
|
6437
|
-
if (tool2.sensitive) {
|
|
6438
|
-
resultContent2 = "[REDACTED - sensitive tool output]";
|
|
6439
|
-
} else if (outcome.kind === "thrown" || tool2.toModelOutput === void 0) {
|
|
6440
|
-
resultContent2 = JSON.stringify(outcome.value);
|
|
6441
|
-
}
|
|
6442
|
-
} else {
|
|
6443
|
-
outcome = { kind: "returned", value: void 0 };
|
|
6444
|
-
resultContent2 = "Tool execution error";
|
|
6445
|
-
}
|
|
6446
|
-
return { outcome, resultContent: resultContent2 };
|
|
6447
|
-
};
|
|
6448
|
-
const traceName = isMcpTool && this.mcpManager ? this.mcpManager.getQualifiedName(toolName) ?? toolName : toolName;
|
|
6449
|
-
const execution = this.spanManager ? await this.spanManager.withSpanAsync(
|
|
6450
|
-
"axl.tool.call",
|
|
6451
|
-
{
|
|
6452
|
-
"axl.tool.name": traceName,
|
|
6453
|
-
"axl.agent.name": agent2._name
|
|
6454
|
-
},
|
|
6455
|
-
async (span) => {
|
|
6456
|
-
const r = await executeTool();
|
|
6457
|
-
span.setAttribute("axl.tool.duration", Date.now() - toolStart);
|
|
6458
|
-
recordToolSpanResult(span, r.outcome.value, suppressErrorShapeInspection);
|
|
6459
|
-
return r;
|
|
6460
|
-
}
|
|
6461
|
-
) : await executeTool();
|
|
6462
|
-
const toolResult = execution.outcome.value;
|
|
6463
|
-
const toolDuration = Date.now() - toolStart;
|
|
6464
|
-
const resultContent = finalizeToolResult({
|
|
6465
|
-
toolName,
|
|
6466
|
-
configuredTool: tool2,
|
|
6467
|
-
outcome: execution.outcome,
|
|
6468
|
-
legacyContent: () => execution.resultContent,
|
|
6469
|
-
emitEnd: () => {
|
|
6470
|
-
this.emitEvent({
|
|
6471
|
-
type: "tool_call_end",
|
|
6472
|
-
agent: agent2._name,
|
|
6473
|
-
tool: traceName,
|
|
6474
|
-
duration: toolDuration,
|
|
6475
|
-
data: { args: toolArgs, result: toolResult, callId: toolCall.id }
|
|
6476
|
-
});
|
|
6477
|
-
},
|
|
6478
|
-
beforeProjection: () => this.currentSignal?.throwIfAborted()
|
|
6479
|
-
});
|
|
6480
|
-
currentMessages.push({
|
|
6481
|
-
role: "tool",
|
|
6482
|
-
content: resultContent,
|
|
6483
|
-
tool_call_id: toolCall.id
|
|
6484
|
-
});
|
|
7209
|
+
await this.observeToolInvocation(
|
|
7210
|
+
agent2,
|
|
7211
|
+
toolCall,
|
|
7212
|
+
currentMessages,
|
|
7213
|
+
toolDefs.map((tool2) => tool2.function.name)
|
|
7214
|
+
);
|
|
6485
7215
|
}
|
|
6486
7216
|
continue;
|
|
6487
7217
|
}
|
|
@@ -6601,7 +7331,7 @@ ${appendedSchemaText}`;
|
|
|
6601
7331
|
pendingRetryReason = "schema";
|
|
6602
7332
|
continue;
|
|
6603
7333
|
}
|
|
6604
|
-
const zodErr = schemaErr instanceof
|
|
7334
|
+
const zodErr = schemaErr instanceof import_zod2.ZodError ? schemaErr : new import_zod2.ZodError([
|
|
6605
7335
|
{
|
|
6606
7336
|
code: "custom",
|
|
6607
7337
|
path: [],
|
|
@@ -6618,6 +7348,7 @@ ${appendedSchemaText}`;
|
|
|
6618
7348
|
metadata: this.metadata
|
|
6619
7349
|
});
|
|
6620
7350
|
} catch (err) {
|
|
7351
|
+
rethrowEventStreamOverflow(err);
|
|
6621
7352
|
const reason = err instanceof Error ? err.message : String(err);
|
|
6622
7353
|
validateResult = { valid: false, reason: `Validator error: ${reason}` };
|
|
6623
7354
|
}
|
|
@@ -6786,7 +7517,7 @@ ${appendedSchemaText}`;
|
|
|
6786
7517
|
);
|
|
6787
7518
|
}
|
|
6788
7519
|
}
|
|
6789
|
-
const rootIsObject = schema instanceof
|
|
7520
|
+
const rootIsObject = schema instanceof import_zod2.z.ZodObject;
|
|
6790
7521
|
const hasTools = toolDefs.length > 0;
|
|
6791
7522
|
if (this._streamingEnabled && (!rootIsObject || hasTools)) {
|
|
6792
7523
|
const cause = !rootIsObject ? "non-object" : "tools";
|
|
@@ -6954,12 +7685,12 @@ ${summaryResponse.content}`
|
|
|
6954
7685
|
* Execute a function with checkpoint-replay semantics.
|
|
6955
7686
|
*
|
|
6956
7687
|
* On first execution, runs `fn()`, saves the result under `name`, and
|
|
6957
|
-
* returns it.
|
|
6958
|
-
* without re-executing.
|
|
6959
|
-
*
|
|
7688
|
+
* returns it. A later evaluation in the same explicit execution scope
|
|
7689
|
+
* returns the saved result without re-executing. Axl does not restart or
|
|
7690
|
+
* resume workflow continuations across processes.
|
|
6960
7691
|
*
|
|
6961
7692
|
* `name` must be a stable, caller-supplied identifier — the same call
|
|
6962
|
-
* site MUST pass the same name across
|
|
7693
|
+
* site MUST pass the same name across evaluations of the same execution for
|
|
6963
7694
|
* replay to work. Names are scoped to a single execution and must be
|
|
6964
7695
|
* unique within it; reusing a name (e.g. inside a loop) gives
|
|
6965
7696
|
* last-write-wins behavior. For loops, compose names from the iterator:
|
|
@@ -7082,6 +7813,7 @@ ${summaryResponse.content}`
|
|
|
7082
7813
|
for (let i = 0; i < n; i++) {
|
|
7083
7814
|
const index = i;
|
|
7084
7815
|
const p = signalStorage.run(composedSignal, () => fn(index));
|
|
7816
|
+
this._registerBranchDrain(p);
|
|
7085
7817
|
p.then((value) => {
|
|
7086
7818
|
if (settled) return;
|
|
7087
7819
|
results[index] = { ok: true, value };
|
|
@@ -7096,6 +7828,14 @@ ${summaryResponse.content}`
|
|
|
7096
7828
|
reject(new QuorumNotMet(quorum, successCount, results));
|
|
7097
7829
|
}
|
|
7098
7830
|
}).catch((err) => {
|
|
7831
|
+
if (isEventStreamOverflowError(err)) {
|
|
7832
|
+
if (!settled) {
|
|
7833
|
+
settled = true;
|
|
7834
|
+
controller.abort();
|
|
7835
|
+
reject(err);
|
|
7836
|
+
}
|
|
7837
|
+
return;
|
|
7838
|
+
}
|
|
7099
7839
|
if (settled) return;
|
|
7100
7840
|
const isAbort = err instanceof DOMException && err.name === "AbortError";
|
|
7101
7841
|
if (isAbort) {
|
|
@@ -7118,14 +7858,16 @@ ${summaryResponse.content}`
|
|
|
7118
7858
|
}
|
|
7119
7859
|
const parentSignal = this.currentSignal;
|
|
7120
7860
|
const promises = Array.from({ length: n }, (_, i) => {
|
|
7121
|
-
const run = () => fn(i).then((value) => ({ ok: true, value })).catch(
|
|
7122
|
-
(err)
|
|
7861
|
+
const run = () => fn(i).then((value) => ({ ok: true, value })).catch((err) => {
|
|
7862
|
+
rethrowEventStreamOverflow(err);
|
|
7863
|
+
return {
|
|
7123
7864
|
ok: false,
|
|
7124
7865
|
error: err instanceof Error ? err.message : String(err)
|
|
7125
|
-
}
|
|
7126
|
-
);
|
|
7866
|
+
};
|
|
7867
|
+
});
|
|
7127
7868
|
return parentSignal ? signalStorage.run(parentSignal, run) : run();
|
|
7128
7869
|
});
|
|
7870
|
+
for (const promise of promises) this._registerBranchDrain(promise);
|
|
7129
7871
|
return Promise.all(promises);
|
|
7130
7872
|
}
|
|
7131
7873
|
// ── ctx.vote() ────────────────────────────────────────────────────────
|
|
@@ -7263,6 +8005,7 @@ ${summaryResponse.content}`
|
|
|
7263
8005
|
try {
|
|
7264
8006
|
validateResult = await options.validate(parsed, { metadata: this.metadata });
|
|
7265
8007
|
} catch (err) {
|
|
8008
|
+
rethrowEventStreamOverflow(err);
|
|
7266
8009
|
const reason = err instanceof Error ? err.message : String(err);
|
|
7267
8010
|
validateResult = { valid: false, reason: `Validator error: ${reason}` };
|
|
7268
8011
|
}
|
|
@@ -7280,6 +8023,7 @@ ${summaryResponse.content}`
|
|
|
7280
8023
|
emitVerifyOutcome(true, attempt + 1);
|
|
7281
8024
|
return parsed;
|
|
7282
8025
|
} catch (err) {
|
|
8026
|
+
rethrowEventStreamOverflow(err);
|
|
7283
8027
|
if (err instanceof ValidationError) {
|
|
7284
8028
|
lastRetry = {
|
|
7285
8029
|
error: err.reason,
|
|
@@ -7302,12 +8046,12 @@ ${summaryResponse.content}`
|
|
|
7302
8046
|
}
|
|
7303
8047
|
continue;
|
|
7304
8048
|
}
|
|
7305
|
-
const errorMsg = err instanceof
|
|
8049
|
+
const errorMsg = err instanceof import_zod2.ZodError ? err.message : err instanceof Error ? err.message : String(err);
|
|
7306
8050
|
lastRetry = { error: errorMsg, output: rawOutput };
|
|
7307
8051
|
if (attempt === maxRetries) {
|
|
7308
8052
|
emitVerifyOutcome(false, attempt + 1, errorMsg);
|
|
7309
8053
|
if (options?.fallback !== void 0) return options.fallback;
|
|
7310
|
-
const zodErr = err instanceof
|
|
8054
|
+
const zodErr = err instanceof import_zod2.ZodError ? err : new import_zod2.ZodError([{ code: "custom", path: [], message: errorMsg }]);
|
|
7311
8055
|
throw new VerifyError(rawOutput, zodErr, maxRetries);
|
|
7312
8056
|
}
|
|
7313
8057
|
}
|
|
@@ -7316,7 +8060,7 @@ ${summaryResponse.content}`
|
|
|
7316
8060
|
if (options?.fallback !== void 0) return options.fallback;
|
|
7317
8061
|
throw new VerifyError(
|
|
7318
8062
|
lastRetry?.output,
|
|
7319
|
-
new
|
|
8063
|
+
new import_zod2.ZodError([{ code: "custom", path: [], message: "Verify failed" }]),
|
|
7320
8064
|
maxRetries
|
|
7321
8065
|
);
|
|
7322
8066
|
}
|
|
@@ -7346,6 +8090,7 @@ ${summaryResponse.content}`
|
|
|
7346
8090
|
const unpriced = this.budgetContext.unpriced;
|
|
7347
8091
|
return { value, budgetExceeded: exceeded, totalCost, unpriced };
|
|
7348
8092
|
} catch (err) {
|
|
8093
|
+
rethrowEventStreamOverflow(err);
|
|
7349
8094
|
if (this.budgetContext.exceeded) {
|
|
7350
8095
|
return {
|
|
7351
8096
|
value: null,
|
|
@@ -7446,7 +8191,8 @@ ${summaryResponse.content}`
|
|
|
7446
8191
|
let remaining = fns.length;
|
|
7447
8192
|
for (const fn of fns) {
|
|
7448
8193
|
const p = signalStorage.run(composedSignal, fn);
|
|
7449
|
-
|
|
8194
|
+
this._registerBranchDrain(p);
|
|
8195
|
+
const continuation = p.then(async (value) => {
|
|
7450
8196
|
if (settled) return;
|
|
7451
8197
|
if (schema) {
|
|
7452
8198
|
const parsed = schema.safeParse(value);
|
|
@@ -7476,6 +8222,7 @@ ${summaryResponse.content}`
|
|
|
7476
8222
|
return;
|
|
7477
8223
|
}
|
|
7478
8224
|
} catch (err) {
|
|
8225
|
+
rethrowEventStreamOverflow(err);
|
|
7479
8226
|
remaining--;
|
|
7480
8227
|
lastError = err instanceof Error ? err : new Error(`Validator error: ${String(err)}`);
|
|
7481
8228
|
if (remaining === 0 && !settled) {
|
|
@@ -7495,6 +8242,14 @@ ${summaryResponse.content}`
|
|
|
7495
8242
|
controller.abort();
|
|
7496
8243
|
resolve2(value);
|
|
7497
8244
|
}).catch((err) => {
|
|
8245
|
+
if (isEventStreamOverflowError(err)) {
|
|
8246
|
+
if (!settled) {
|
|
8247
|
+
settled = true;
|
|
8248
|
+
controller.abort();
|
|
8249
|
+
reject(err);
|
|
8250
|
+
}
|
|
8251
|
+
throw err;
|
|
8252
|
+
}
|
|
7498
8253
|
if (settled) return;
|
|
7499
8254
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
7500
8255
|
remaining--;
|
|
@@ -7511,6 +8266,7 @@ ${summaryResponse.content}`
|
|
|
7511
8266
|
reject(lastError);
|
|
7512
8267
|
}
|
|
7513
8268
|
});
|
|
8269
|
+
this._registerBranchDrain(continuation);
|
|
7514
8270
|
}
|
|
7515
8271
|
});
|
|
7516
8272
|
}
|
|
@@ -7549,9 +8305,19 @@ ${summaryResponse.content}`
|
|
|
7549
8305
|
const idx = nextIndex++;
|
|
7550
8306
|
try {
|
|
7551
8307
|
const value = mapSignal ? await signalStorage.run(mapSignal, () => fn(items[idx], idx)) : await fn(items[idx], idx);
|
|
8308
|
+
if (settled) return;
|
|
7552
8309
|
results[idx] = { ok: true, value };
|
|
7553
8310
|
successCount++;
|
|
7554
8311
|
} catch (err) {
|
|
8312
|
+
if (isEventStreamOverflowError(err)) {
|
|
8313
|
+
settled = true;
|
|
8314
|
+
controller?.abort();
|
|
8315
|
+
reject(err);
|
|
8316
|
+
throw err;
|
|
8317
|
+
}
|
|
8318
|
+
if (settled) {
|
|
8319
|
+
return;
|
|
8320
|
+
}
|
|
7555
8321
|
if (err instanceof DOMException && err.name === "AbortError" && controller?.signal.aborted) {
|
|
7556
8322
|
completedCount++;
|
|
7557
8323
|
return;
|
|
@@ -7577,7 +8343,9 @@ ${summaryResponse.content}`
|
|
|
7577
8343
|
};
|
|
7578
8344
|
const workers = Math.min(concurrency, items.length);
|
|
7579
8345
|
for (let i = 0; i < workers; i++) {
|
|
7580
|
-
runNext()
|
|
8346
|
+
const worker = runNext();
|
|
8347
|
+
this._registerBranchDrain(worker);
|
|
8348
|
+
worker.catch((err) => {
|
|
7581
8349
|
if (!settled) reject(err);
|
|
7582
8350
|
});
|
|
7583
8351
|
}
|
|
@@ -7603,12 +8371,44 @@ ${summaryResponse.content}`
|
|
|
7603
8371
|
return this._awaitHumanImpl(options);
|
|
7604
8372
|
}
|
|
7605
8373
|
async _awaitHumanImpl(options) {
|
|
8374
|
+
const branchSignal = this.currentSignal;
|
|
8375
|
+
const makeAbortError = (reason) => {
|
|
8376
|
+
if (typeof DOMException !== "undefined") {
|
|
8377
|
+
return new DOMException(
|
|
8378
|
+
typeof reason === "string" ? reason : "awaitHuman aborted",
|
|
8379
|
+
"AbortError"
|
|
8380
|
+
);
|
|
8381
|
+
}
|
|
8382
|
+
const err = new Error(typeof reason === "string" ? reason : "awaitHuman aborted");
|
|
8383
|
+
err.name = "AbortError";
|
|
8384
|
+
return err;
|
|
8385
|
+
};
|
|
8386
|
+
const awaitWithAbort = async (promise, signal2 = branchSignal) => {
|
|
8387
|
+
if (!signal2) return promise;
|
|
8388
|
+
if (signal2.aborted) throw makeAbortError(signal2.reason);
|
|
8389
|
+
let onAbort;
|
|
8390
|
+
try {
|
|
8391
|
+
return await Promise.race([
|
|
8392
|
+
promise,
|
|
8393
|
+
new Promise((_, reject) => {
|
|
8394
|
+
onAbort = () => reject(makeAbortError(signal2.reason));
|
|
8395
|
+
signal2.addEventListener("abort", onAbort, { once: true });
|
|
8396
|
+
})
|
|
8397
|
+
]);
|
|
8398
|
+
} finally {
|
|
8399
|
+
if (onAbort) signal2.removeEventListener("abort", onAbort);
|
|
8400
|
+
}
|
|
8401
|
+
};
|
|
7606
8402
|
if (this.awaitHumanHandler) {
|
|
8403
|
+
if (branchSignal?.aborted) throw makeAbortError(branchSignal.reason);
|
|
7607
8404
|
this.emitEvent({
|
|
7608
8405
|
type: "await_human",
|
|
7609
8406
|
data: { channel: options.channel, prompt: options.prompt }
|
|
7610
8407
|
});
|
|
7611
|
-
|
|
8408
|
+
if (branchSignal?.aborted) throw makeAbortError(branchSignal.reason);
|
|
8409
|
+
const decision2 = parseHumanDecision(
|
|
8410
|
+
await awaitWithAbort(Promise.resolve(this.awaitHumanHandler(options)))
|
|
8411
|
+
);
|
|
7612
8412
|
this.emitEvent({
|
|
7613
8413
|
type: "await_human_resolved",
|
|
7614
8414
|
data: { channel: options.channel, decision: decision2 }
|
|
@@ -7620,68 +8420,126 @@ ${summaryResponse.content}`
|
|
|
7620
8420
|
"Tool requires approval but no approval handler is configured. Provide awaitHumanHandler to createContext() or use runtime.execute() with workflow infrastructure."
|
|
7621
8421
|
);
|
|
7622
8422
|
}
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
awaitHumanPrompt: options.prompt
|
|
7640
|
-
}
|
|
7641
|
-
});
|
|
7642
|
-
}
|
|
7643
|
-
this.emitEvent({
|
|
7644
|
-
type: "await_human",
|
|
7645
|
-
data: { channel: options.channel, prompt: options.prompt }
|
|
8423
|
+
const existingClaim = this.awaitHumanClaims.get(this.executionId);
|
|
8424
|
+
if (existingClaim) {
|
|
8425
|
+
const error = new AxlError(
|
|
8426
|
+
"CONCURRENT_HUMAN_DECISION_UNSUPPORTED",
|
|
8427
|
+
`Execution "${this.executionId}" already has an active human decision. Concurrent awaitHuman calls require request-scoped decision identifiers.`
|
|
8428
|
+
);
|
|
8429
|
+
existingClaim.abort(error);
|
|
8430
|
+
throw error;
|
|
8431
|
+
}
|
|
8432
|
+
const claimController = new AbortController();
|
|
8433
|
+
this.awaitHumanClaims.set(this.executionId, claimController);
|
|
8434
|
+
const signal = branchSignal ? AbortSignal.any([branchSignal, claimController.signal]) : claimController.signal;
|
|
8435
|
+
let saveAttempted = false;
|
|
8436
|
+
let markReady;
|
|
8437
|
+
const ready = new Promise((resolve2) => {
|
|
8438
|
+
markReady = resolve2;
|
|
7646
8439
|
});
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
8440
|
+
let markCleanupFinished;
|
|
8441
|
+
const cleanupFinished = new Promise((resolve2) => {
|
|
8442
|
+
markCleanupFinished = resolve2;
|
|
8443
|
+
});
|
|
8444
|
+
let resolveDecision;
|
|
8445
|
+
let rejectDecision;
|
|
8446
|
+
const decisionPromise = new Promise((resolve2, reject) => {
|
|
8447
|
+
resolveDecision = resolve2;
|
|
8448
|
+
rejectDecision = reject;
|
|
8449
|
+
});
|
|
8450
|
+
void decisionPromise.catch(() => {
|
|
8451
|
+
});
|
|
8452
|
+
const registeredResolver = {
|
|
8453
|
+
resolve: resolveDecision,
|
|
8454
|
+
ready,
|
|
8455
|
+
state: "preparing",
|
|
8456
|
+
cancelled: false,
|
|
8457
|
+
cleanupFinished
|
|
7657
8458
|
};
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
8459
|
+
this.pendingDecisions.set(this.executionId, registeredResolver);
|
|
8460
|
+
const abortListener = () => {
|
|
8461
|
+
registeredResolver.cancelled = true;
|
|
8462
|
+
markReady();
|
|
8463
|
+
rejectDecision(makeAbortError(signal.reason));
|
|
8464
|
+
};
|
|
8465
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
8466
|
+
let decision;
|
|
8467
|
+
try {
|
|
8468
|
+
if (signal.aborted) throw makeAbortError(signal.reason);
|
|
8469
|
+
if (this.stateStore) {
|
|
8470
|
+
saveAttempted = true;
|
|
8471
|
+
await this.stateStore.savePendingDecision(this.executionId, {
|
|
8472
|
+
executionId: this.executionId,
|
|
8473
|
+
channel: options.channel,
|
|
8474
|
+
prompt: options.prompt,
|
|
8475
|
+
metadata: options.metadata,
|
|
8476
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8477
|
+
});
|
|
7662
8478
|
}
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
8479
|
+
if (signal.aborted) throw makeAbortError(signal.reason);
|
|
8480
|
+
this.emitEvent({
|
|
8481
|
+
type: "await_human",
|
|
8482
|
+
data: { channel: options.channel, prompt: options.prompt }
|
|
8483
|
+
});
|
|
8484
|
+
registeredResolver.state = "pending";
|
|
8485
|
+
markReady();
|
|
8486
|
+
decision = await decisionPromise;
|
|
8487
|
+
} catch (error) {
|
|
8488
|
+
if (registeredResolver.state === "preparing") {
|
|
8489
|
+
registeredResolver.state = "failed";
|
|
8490
|
+
markReady();
|
|
8491
|
+
}
|
|
8492
|
+
let needsCompensation = saveAttempted;
|
|
8493
|
+
const inFlightResolution = registeredResolver.resolution;
|
|
8494
|
+
if (registeredResolver.state === "resolving" && inFlightResolution) {
|
|
8495
|
+
needsCompensation = !await inFlightResolution;
|
|
8496
|
+
} else if (registeredResolver.state === "resolved") {
|
|
8497
|
+
needsCompensation = false;
|
|
8498
|
+
}
|
|
8499
|
+
if (this.stateStore && needsCompensation) {
|
|
8500
|
+
try {
|
|
8501
|
+
await this.stateStore.resolveDecision(this.executionId, {
|
|
8502
|
+
approved: false,
|
|
8503
|
+
reason: "Execution aborted while awaiting approval"
|
|
8504
|
+
});
|
|
8505
|
+
} catch (cleanupError) {
|
|
8506
|
+
if (error instanceof Error && Object.isExtensible(error)) {
|
|
8507
|
+
Object.defineProperty(error, "cleanupError", {
|
|
8508
|
+
configurable: true,
|
|
8509
|
+
enumerable: false,
|
|
8510
|
+
value: cleanupError
|
|
8511
|
+
});
|
|
8512
|
+
}
|
|
8513
|
+
try {
|
|
8514
|
+
this._onDecisionCleanupFailed?.({
|
|
8515
|
+
executionId: this.executionId,
|
|
8516
|
+
...this.workflowName ? { workflow: this.workflowName } : {},
|
|
8517
|
+
operation: "resolveDecision_compensation",
|
|
8518
|
+
error: cleanupError
|
|
8519
|
+
});
|
|
8520
|
+
} catch (observerError) {
|
|
8521
|
+
console.error(
|
|
8522
|
+
"[axl] decision_cleanup_failed listener threw; workflow outcome unchanged:",
|
|
8523
|
+
observerError instanceof Error ? observerError.message : String(observerError)
|
|
8524
|
+
);
|
|
8525
|
+
}
|
|
7668
8526
|
}
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
8527
|
+
}
|
|
8528
|
+
throw error;
|
|
8529
|
+
} finally {
|
|
8530
|
+
signal.removeEventListener("abort", abortListener);
|
|
8531
|
+
if (this.pendingDecisions.get(this.executionId) === registeredResolver) {
|
|
8532
|
+
this.pendingDecisions.delete(this.executionId);
|
|
8533
|
+
}
|
|
8534
|
+
if (this.awaitHumanClaims.get(this.executionId) === claimController) {
|
|
8535
|
+
this.awaitHumanClaims.delete(this.executionId);
|
|
8536
|
+
}
|
|
8537
|
+
markCleanupFinished();
|
|
8538
|
+
}
|
|
7673
8539
|
this.emitEvent({
|
|
7674
8540
|
type: "await_human_resolved",
|
|
7675
8541
|
data: { channel: options.channel, decision }
|
|
7676
8542
|
});
|
|
7677
|
-
if (this.stateStore) {
|
|
7678
|
-
await this.stateStore.saveExecutionState(this.executionId, {
|
|
7679
|
-
workflow: this.workflowName ?? "unknown",
|
|
7680
|
-
input: this.input,
|
|
7681
|
-
step: this.stepRefRoot.value,
|
|
7682
|
-
status: "running"
|
|
7683
|
-
});
|
|
7684
|
-
}
|
|
7685
8543
|
return decision;
|
|
7686
8544
|
}
|
|
7687
8545
|
/**
|
|
@@ -7733,8 +8591,8 @@ ${summaryResponse.content}`
|
|
|
7733
8591
|
// Internal: the runtime is the only caller, user workflows never call these.
|
|
7734
8592
|
/** @internal — idempotent; no-ops on second+ call within one ctx. */
|
|
7735
8593
|
_emitWorkflowStart(input) {
|
|
7736
|
-
if (this.
|
|
7737
|
-
this.
|
|
8594
|
+
if (this.workflowLifecycleState.startEmitted) return;
|
|
8595
|
+
this.workflowLifecycleState.startEmitted = true;
|
|
7738
8596
|
this.emitEvent({
|
|
7739
8597
|
type: "workflow_start",
|
|
7740
8598
|
workflow: this.workflowName,
|
|
@@ -7750,8 +8608,8 @@ ${summaryResponse.content}`
|
|
|
7750
8608
|
* status. First-wins semantics: the completed event stands, the
|
|
7751
8609
|
* inner side-effect failure propagates as a normal thrown error. */
|
|
7752
8610
|
_emitWorkflowEnd(info) {
|
|
7753
|
-
if (this.
|
|
7754
|
-
this.
|
|
8611
|
+
if (this.workflowLifecycleState.endEmitted) return;
|
|
8612
|
+
this.workflowLifecycleState.endEmitted = true;
|
|
7755
8613
|
this.emitEvent({
|
|
7756
8614
|
type: "workflow_end",
|
|
7757
8615
|
workflow: this.workflowName,
|
|
@@ -7761,7 +8619,8 @@ ${summaryResponse.content}`
|
|
|
7761
8619
|
duration: info.duration,
|
|
7762
8620
|
...info.result !== void 0 ? { result: info.result } : {},
|
|
7763
8621
|
...info.error !== void 0 ? { error: info.error } : {},
|
|
7764
|
-
...info.aborted ? { aborted: true } : {}
|
|
8622
|
+
...info.aborted ? { aborted: true } : {},
|
|
8623
|
+
...info.observation ? { observation: info.observation } : {}
|
|
7765
8624
|
}
|
|
7766
8625
|
});
|
|
7767
8626
|
}
|
|
@@ -8050,6 +8909,7 @@ ${summaryResponse.content}`
|
|
|
8050
8909
|
* consumer sites via the `type` discriminator.
|
|
8051
8910
|
*/
|
|
8052
8911
|
emitEvent(partial) {
|
|
8912
|
+
if (this.workflowLifecycleState.endEmitted && partial.type !== "workflow_end") return;
|
|
8053
8913
|
const data = partial.data;
|
|
8054
8914
|
const frame = askStorage.getStore();
|
|
8055
8915
|
const step = (frame?.stepRef ?? this.stepRefRoot).value++;
|
|
@@ -8075,6 +8935,7 @@ ${summaryResponse.content}`
|
|
|
8075
8935
|
}
|
|
8076
8936
|
}
|
|
8077
8937
|
const event = {
|
|
8938
|
+
schemaVersion: 2,
|
|
8078
8939
|
executionId: this.executionId,
|
|
8079
8940
|
step,
|
|
8080
8941
|
timestamp: Date.now(),
|
|
@@ -8095,13 +8956,13 @@ ${summaryResponse.content}`
|
|
|
8095
8956
|
...partial,
|
|
8096
8957
|
data
|
|
8097
8958
|
};
|
|
8098
|
-
const finalEvent = this.config.trace?.redact ?
|
|
8959
|
+
const finalEvent = this.config.trace?.redact ? redactHistoricalEvent(event) : event;
|
|
8099
8960
|
let overflowErr;
|
|
8100
8961
|
if (this.onTrace) {
|
|
8101
8962
|
try {
|
|
8102
8963
|
this.onTrace(finalEvent);
|
|
8103
8964
|
} catch (err) {
|
|
8104
|
-
if (err
|
|
8965
|
+
if (isEventStreamOverflowError(err)) {
|
|
8105
8966
|
overflowErr = err;
|
|
8106
8967
|
} else {
|
|
8107
8968
|
console.error(
|
|
@@ -8116,7 +8977,7 @@ ${summaryResponse.content}`
|
|
|
8116
8977
|
try {
|
|
8117
8978
|
bus._push(finalEvent);
|
|
8118
8979
|
} catch (err) {
|
|
8119
|
-
if (err
|
|
8980
|
+
if (isEventStreamOverflowError(err)) {
|
|
8120
8981
|
if (!overflowErr) {
|
|
8121
8982
|
overflowErr = err;
|
|
8122
8983
|
} else {
|
|
@@ -8303,26 +9164,31 @@ var MemoryStore = class {
|
|
|
8303
9164
|
}
|
|
8304
9165
|
// ── Execution History ──────────────────────────────────────────────
|
|
8305
9166
|
async saveExecution(execution) {
|
|
8306
|
-
|
|
9167
|
+
const normalized = normalizeStoredExecution({
|
|
9168
|
+
...execution,
|
|
9169
|
+
eventSchemaVersion: getExecutionEventSchemaVersion(execution)
|
|
9170
|
+
});
|
|
9171
|
+
this.executionHistory.set(execution.executionId, structuredClone(normalized));
|
|
8307
9172
|
}
|
|
8308
9173
|
async getExecution(executionId) {
|
|
8309
9174
|
const exec = this.executionHistory.get(executionId);
|
|
8310
|
-
return exec ? structuredClone(exec) : null;
|
|
9175
|
+
return exec ? normalizeStoredExecution(structuredClone(exec)) : null;
|
|
8311
9176
|
}
|
|
8312
9177
|
async listExecutions(limit) {
|
|
8313
9178
|
const sorted = [...this.executionHistory.values()].sort((a, b) => b.startedAt - a.startedAt);
|
|
8314
9179
|
const result = limit ? sorted.slice(0, limit) : sorted;
|
|
8315
|
-
return result.map((e) => structuredClone(e));
|
|
9180
|
+
return result.map((e) => normalizeStoredExecution(structuredClone(e)));
|
|
8316
9181
|
}
|
|
8317
9182
|
async deleteExecution(executionId) {
|
|
8318
|
-
const
|
|
8319
|
-
this.checkpoints.delete(executionId);
|
|
8320
|
-
this.executionStates.delete(executionId);
|
|
8321
|
-
this.streamingEvents.delete(executionId);
|
|
8322
|
-
|
|
9183
|
+
const removedHistory = this.executionHistory.delete(executionId);
|
|
9184
|
+
const removedCheckpoints = this.checkpoints.delete(executionId);
|
|
9185
|
+
const removedState = this.executionStates.delete(executionId);
|
|
9186
|
+
const removedStreaming = this.streamingEvents.delete(executionId);
|
|
9187
|
+
const removedDecision = this.decisions.delete(executionId);
|
|
9188
|
+
if (removedDecision) {
|
|
8323
9189
|
this.persistAwaitHumanState();
|
|
8324
9190
|
}
|
|
8325
|
-
return
|
|
9191
|
+
return removedHistory || removedCheckpoints || removedState || removedStreaming || removedDecision;
|
|
8326
9192
|
}
|
|
8327
9193
|
// ── Eval History ──────────────────────────────────────────────────
|
|
8328
9194
|
async saveEvalResult(entry) {
|
|
@@ -8428,16 +9294,23 @@ function rowToExecutionInfo(row) {
|
|
|
8428
9294
|
startedAt: row.started_at,
|
|
8429
9295
|
completedAt: row.completed_at ?? void 0,
|
|
8430
9296
|
duration: row.duration,
|
|
8431
|
-
|
|
8432
|
-
|
|
9297
|
+
events: safeJsonParse(row.events) ?? [],
|
|
9298
|
+
...row.event_schema_version != null ? { eventSchemaVersion: row.event_schema_version } : {}
|
|
8433
9299
|
};
|
|
9300
|
+
if (row.error != null) info.error = row.error;
|
|
8434
9301
|
if (row.metadata != null) {
|
|
8435
9302
|
const parsed = safeJsonParse(row.metadata);
|
|
8436
9303
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8437
9304
|
info.metadata = parsed;
|
|
8438
9305
|
}
|
|
8439
9306
|
}
|
|
8440
|
-
|
|
9307
|
+
if (row.observation != null) {
|
|
9308
|
+
const parsed = safeJsonParse(row.observation);
|
|
9309
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9310
|
+
info.observation = parsed;
|
|
9311
|
+
}
|
|
9312
|
+
}
|
|
9313
|
+
return normalizeStoredExecution(info);
|
|
8441
9314
|
}
|
|
8442
9315
|
var SQLiteStore = class {
|
|
8443
9316
|
db;
|
|
@@ -8477,6 +9350,10 @@ var SQLiteStore = class {
|
|
|
8477
9350
|
* column (TEXT, nullable, JSON-serialized) so caller-supplied
|
|
8478
9351
|
* `ExecuteOptions.metadata` round-trips through history. Existing
|
|
8479
9352
|
* rows get `NULL`, deserialized as `metadata: undefined`.
|
|
9353
|
+
* - v4 (event schema): add `execution_history.event_schema_version`.
|
|
9354
|
+
* Existing rows remain `NULL`, the documented v1 sentinel.
|
|
9355
|
+
* - v5 (observation completeness): add `execution_history.observation`.
|
|
9356
|
+
* Existing rows remain `NULL`, meaning they predate the contract.
|
|
8480
9357
|
*
|
|
8481
9358
|
* Applied BEFORE `initTables()` so the subsequent `CREATE TABLE
|
|
8482
9359
|
* IF NOT EXISTS` runs against the post-migration column name. Fresh
|
|
@@ -8494,7 +9371,7 @@ var SQLiteStore = class {
|
|
|
8494
9371
|
* transactional re-read costs nothing.
|
|
8495
9372
|
*/
|
|
8496
9373
|
migrate() {
|
|
8497
|
-
const TARGET_VERSION =
|
|
9374
|
+
const TARGET_VERSION = 5;
|
|
8498
9375
|
const current = this.db.pragma("user_version", { simple: true });
|
|
8499
9376
|
if (current >= TARGET_VERSION) return;
|
|
8500
9377
|
this.db.exec("BEGIN IMMEDIATE");
|
|
@@ -8522,6 +9399,18 @@ var SQLiteStore = class {
|
|
|
8522
9399
|
this.db.exec("ALTER TABLE execution_history ADD COLUMN metadata TEXT");
|
|
8523
9400
|
}
|
|
8524
9401
|
}
|
|
9402
|
+
if (committed < 4) {
|
|
9403
|
+
const cols = this.db.pragma("table_info(execution_history)");
|
|
9404
|
+
if (cols.length > 0 && !cols.some((c) => c.name === "event_schema_version")) {
|
|
9405
|
+
this.db.exec("ALTER TABLE execution_history ADD COLUMN event_schema_version INTEGER");
|
|
9406
|
+
}
|
|
9407
|
+
}
|
|
9408
|
+
if (committed < 5) {
|
|
9409
|
+
const cols = this.db.pragma("table_info(execution_history)");
|
|
9410
|
+
if (cols.length > 0 && !cols.some((c) => c.name === "observation")) {
|
|
9411
|
+
this.db.exec("ALTER TABLE execution_history ADD COLUMN observation TEXT");
|
|
9412
|
+
}
|
|
9413
|
+
}
|
|
8525
9414
|
this.db.pragma(`user_version = ${TARGET_VERSION}`);
|
|
8526
9415
|
this.db.exec("COMMIT");
|
|
8527
9416
|
} catch (err) {
|
|
@@ -8585,7 +9474,9 @@ var SQLiteStore = class {
|
|
|
8585
9474
|
duration INTEGER NOT NULL DEFAULT 0,
|
|
8586
9475
|
error TEXT,
|
|
8587
9476
|
events TEXT NOT NULL,
|
|
8588
|
-
metadata TEXT
|
|
9477
|
+
metadata TEXT,
|
|
9478
|
+
event_schema_version INTEGER,
|
|
9479
|
+
observation TEXT
|
|
8589
9480
|
);
|
|
8590
9481
|
|
|
8591
9482
|
CREATE TABLE IF NOT EXISTS eval_history (
|
|
@@ -8670,7 +9561,7 @@ var SQLiteStore = class {
|
|
|
8670
9561
|
const stmt = this.db.prepare("DELETE FROM decisions WHERE execution_id = ?");
|
|
8671
9562
|
stmt.run(executionId);
|
|
8672
9563
|
}
|
|
8673
|
-
// ──
|
|
9564
|
+
// ── Legacy application-managed execution state ────────────────────────
|
|
8674
9565
|
async saveExecutionState(executionId, state) {
|
|
8675
9566
|
const stmt = this.db.prepare(
|
|
8676
9567
|
"INSERT OR REPLACE INTO execution_state (execution_id, workflow, input, step, status, metadata) VALUES (?, ?, ?, ?, ?, ?)"
|
|
@@ -8705,19 +9596,25 @@ var SQLiteStore = class {
|
|
|
8705
9596
|
}
|
|
8706
9597
|
// ── Execution History ────────────────────────────────────────────────────
|
|
8707
9598
|
async saveExecution(execution) {
|
|
9599
|
+
const normalized = normalizeStoredExecution({
|
|
9600
|
+
...execution,
|
|
9601
|
+
eventSchemaVersion: getExecutionEventSchemaVersion(execution)
|
|
9602
|
+
});
|
|
8708
9603
|
this.db.prepare(
|
|
8709
|
-
"INSERT OR REPLACE INTO execution_history (execution_id, workflow, status, total_cost, started_at, completed_at, duration, error, events, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
9604
|
+
"INSERT OR REPLACE INTO execution_history (execution_id, workflow, status, total_cost, started_at, completed_at, duration, error, events, metadata, event_schema_version, observation) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
8710
9605
|
).run(
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
JSON.stringify(
|
|
8720
|
-
|
|
9606
|
+
normalized.executionId,
|
|
9607
|
+
normalized.workflow,
|
|
9608
|
+
normalized.status,
|
|
9609
|
+
normalized.totalCost,
|
|
9610
|
+
normalized.startedAt,
|
|
9611
|
+
normalized.completedAt ?? null,
|
|
9612
|
+
normalized.duration,
|
|
9613
|
+
normalized.error ?? null,
|
|
9614
|
+
JSON.stringify(normalized.events),
|
|
9615
|
+
normalized.metadata !== void 0 ? JSON.stringify(normalized.metadata) : null,
|
|
9616
|
+
normalized.eventSchemaVersion,
|
|
9617
|
+
normalized.observation !== void 0 ? JSON.stringify(normalized.observation) : null
|
|
8721
9618
|
);
|
|
8722
9619
|
}
|
|
8723
9620
|
async getExecution(executionId) {
|
|
@@ -8731,11 +9628,11 @@ var SQLiteStore = class {
|
|
|
8731
9628
|
}
|
|
8732
9629
|
async deleteExecution(executionId) {
|
|
8733
9630
|
const tx = this.db.transaction(() => {
|
|
8734
|
-
const
|
|
8735
|
-
this.db.prepare("DELETE FROM checkpoints WHERE execution_id = ?").run(executionId);
|
|
8736
|
-
this.db.prepare("DELETE FROM execution_state WHERE execution_id = ?").run(executionId);
|
|
8737
|
-
this.db.prepare("DELETE FROM decisions WHERE execution_id = ?").run(executionId);
|
|
8738
|
-
return
|
|
9631
|
+
const historyResult = this.db.prepare("DELETE FROM execution_history WHERE execution_id = ?").run(executionId);
|
|
9632
|
+
const checkpointsResult = this.db.prepare("DELETE FROM checkpoints WHERE execution_id = ?").run(executionId);
|
|
9633
|
+
const stateResult = this.db.prepare("DELETE FROM execution_state WHERE execution_id = ?").run(executionId);
|
|
9634
|
+
const decisionsResult = this.db.prepare("DELETE FROM decisions WHERE execution_id = ?").run(executionId);
|
|
9635
|
+
return historyResult.changes + checkpointsResult.changes + stateResult.changes + decisionsResult.changes > 0;
|
|
8739
9636
|
});
|
|
8740
9637
|
return tx();
|
|
8741
9638
|
}
|
|
@@ -9061,6 +9958,11 @@ var AxlStream = class extends import_node_stream.Readable {
|
|
|
9061
9958
|
get lifecycle() {
|
|
9062
9959
|
return this.events.lifecycle;
|
|
9063
9960
|
}
|
|
9961
|
+
/** Completeness of this stream's iterator queue. Check after consumption
|
|
9962
|
+
* before treating an unmatched lifecycle event as a producer defect. */
|
|
9963
|
+
get observationStatus() {
|
|
9964
|
+
return this.events.observationStatus;
|
|
9965
|
+
}
|
|
9064
9966
|
/** Coalescing iterator over `partial_object` events — yields the latest
|
|
9065
9967
|
* object payload per `askId`. Designed for streaming-structured-output
|
|
9066
9968
|
* UIs: when the producer outpaces the consumer, intermediate snapshots
|
|
@@ -9159,6 +10061,7 @@ var AxlStream = class extends import_node_stream.Readable {
|
|
|
9159
10061
|
if (this.events.isFinished) return;
|
|
9160
10062
|
this.result = result;
|
|
9161
10063
|
const doneEvent = {
|
|
10064
|
+
schemaVersion: 2,
|
|
9162
10065
|
type: "done",
|
|
9163
10066
|
executionId,
|
|
9164
10067
|
step: Number.MAX_SAFE_INTEGER,
|
|
@@ -9177,6 +10080,7 @@ var AxlStream = class extends import_node_stream.Readable {
|
|
|
9177
10080
|
_error(error, executionId) {
|
|
9178
10081
|
if (this.events.isFinished) return;
|
|
9179
10082
|
const errorEvent = {
|
|
10083
|
+
schemaVersion: 2,
|
|
9180
10084
|
type: "error",
|
|
9181
10085
|
executionId,
|
|
9182
10086
|
step: Number.MAX_SAFE_INTEGER,
|
|
@@ -9777,11 +10681,7 @@ var STREAMING_EXCLUDED_TYPES = /* @__PURE__ */ new Set([
|
|
|
9777
10681
|
"partial_object",
|
|
9778
10682
|
"string_delta"
|
|
9779
10683
|
]);
|
|
9780
|
-
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
9781
|
-
"sessionId",
|
|
9782
|
-
"sessionHistory",
|
|
9783
|
-
"resumeMode"
|
|
9784
|
-
]);
|
|
10684
|
+
var INTERNAL_METADATA_KEYS = /* @__PURE__ */ new Set(["sessionId", "sessionHistory"]);
|
|
9785
10685
|
function liftPersistedMetadata(metadata) {
|
|
9786
10686
|
if (!metadata) return void 0;
|
|
9787
10687
|
const filtered = {};
|
|
@@ -9899,7 +10799,7 @@ var StreamingFlusher = class {
|
|
|
9899
10799
|
await Promise.allSettled(pendings);
|
|
9900
10800
|
}
|
|
9901
10801
|
};
|
|
9902
|
-
function
|
|
10802
|
+
function isAbortError4(err) {
|
|
9903
10803
|
return typeof err === "object" && err !== null && err.name === "AbortError";
|
|
9904
10804
|
}
|
|
9905
10805
|
function pushEventBounded(execInfo, event, cap) {
|
|
@@ -9911,7 +10811,18 @@ function pushEventBounded(execInfo, event, cap) {
|
|
|
9911
10811
|
const last = execInfo.events[execInfo.events.length - 1];
|
|
9912
10812
|
const alreadyTruncated = last?.type === "log" && typeof last.data === "object" && last.data !== null && last.data.event === "events_truncated";
|
|
9913
10813
|
if (!alreadyTruncated) {
|
|
10814
|
+
if (execInfo.observation?.complete !== false) {
|
|
10815
|
+
execInfo.observation = {
|
|
10816
|
+
complete: false,
|
|
10817
|
+
reason: "persistence_truncated",
|
|
10818
|
+
maxEvents: cap
|
|
10819
|
+
};
|
|
10820
|
+
}
|
|
10821
|
+
if (event.type === "workflow_end") {
|
|
10822
|
+
event.data.observation = execInfo.observation;
|
|
10823
|
+
}
|
|
9914
10824
|
execInfo.events[execInfo.events.length - 1] = {
|
|
10825
|
+
schemaVersion: 2,
|
|
9915
10826
|
type: "log",
|
|
9916
10827
|
executionId: event.executionId,
|
|
9917
10828
|
step: event.step,
|
|
@@ -9940,7 +10851,9 @@ function boundRecoveredEvents(events, cap) {
|
|
|
9940
10851
|
const last = truncated[truncated.length - 1];
|
|
9941
10852
|
const alreadyTruncated = last?.type === "log" && typeof last.data === "object" && last.data !== null && last.data.event === "events_truncated";
|
|
9942
10853
|
if (!alreadyTruncated) {
|
|
10854
|
+
const version = getEventSchemaVersion(events[0] ?? {});
|
|
9943
10855
|
truncated[truncated.length - 1] = {
|
|
10856
|
+
...version === 2 ? { schemaVersion: 2 } : {},
|
|
9944
10857
|
type: "log",
|
|
9945
10858
|
executionId: events[0]?.executionId ?? "",
|
|
9946
10859
|
step: last?.step ?? 0,
|
|
@@ -9954,6 +10867,16 @@ function boundRecoveredEvents(events, cap) {
|
|
|
9954
10867
|
}
|
|
9955
10868
|
return truncated;
|
|
9956
10869
|
}
|
|
10870
|
+
var REMOVED_OBSERVATION_CALLBACKS = ["onToken", "onToolCall", "onAgentStart"];
|
|
10871
|
+
function assertNoRemovedObservationCallbacks(options) {
|
|
10872
|
+
if (options === null || typeof options !== "object") return;
|
|
10873
|
+
const removed = REMOVED_OBSERVATION_CALLBACKS.filter((key) => Object.hasOwn(options, key));
|
|
10874
|
+
if (removed.length === 0) return;
|
|
10875
|
+
throw new AxlError(
|
|
10876
|
+
"INVALID_CONFIG",
|
|
10877
|
+
`runtime.createContext() no longer accepts ${removed.join(", ")}. Observe ctx.events or use runtime.stream() instead. See docs/migration/stream-first-observation.md.`
|
|
10878
|
+
);
|
|
10879
|
+
}
|
|
9957
10880
|
var costScopeStorage = new import_node_async_hooks2.AsyncLocalStorage();
|
|
9958
10881
|
function forwardAbortSignal(external, internal) {
|
|
9959
10882
|
if (!external) return () => {
|
|
@@ -10115,9 +11038,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10115
11038
|
* → parse output → emit `workflow_end` → delete checkpoints → persist.
|
|
10116
11039
|
*
|
|
10117
11040
|
* Shared between `execute()` and `stream()`. Centralizes the
|
|
10118
|
-
* "start iff end" pairing invariant
|
|
10119
|
-
* (e.g., `resumeExecution`) can inherit correct behavior by routing
|
|
10120
|
-
* through this helper. Also factors out the AbortError detection.
|
|
11041
|
+
* "start iff end" pairing invariant and AbortError detection.
|
|
10121
11042
|
*
|
|
10122
11043
|
* Side effects on `execInfo`: sets `status` / `completedAt` /
|
|
10123
11044
|
* `duration` / `result` (or `error`) before emitting `workflow_end`.
|
|
@@ -10141,18 +11062,23 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10141
11062
|
*/
|
|
10142
11063
|
async runWorkflowBody(args) {
|
|
10143
11064
|
const { workflow: workflow2, ctx, execInfo, validated, span, cleanupAbortForwarder } = args;
|
|
11065
|
+
let observation = execInfo.observation ?? { complete: true };
|
|
10144
11066
|
try {
|
|
10145
11067
|
ctx._emitWorkflowStart(validated);
|
|
10146
11068
|
const raw = await workflow2.handler(ctx);
|
|
11069
|
+
const drainedObservation = await ctx._drainBranchWork();
|
|
11070
|
+
observation = drainedObservation.complete === false ? drainedObservation : execInfo.observation ?? drainedObservation;
|
|
10147
11071
|
const result = workflow2.outputSchema ? workflow2.outputSchema.parse(raw) : raw;
|
|
10148
11072
|
execInfo.status = "completed";
|
|
10149
11073
|
execInfo.completedAt = Date.now();
|
|
10150
11074
|
execInfo.duration = execInfo.completedAt - execInfo.startedAt;
|
|
10151
11075
|
execInfo.result = result;
|
|
11076
|
+
execInfo.observation = observation;
|
|
10152
11077
|
ctx._emitWorkflowEnd({
|
|
10153
11078
|
status: "completed",
|
|
10154
11079
|
duration: execInfo.duration,
|
|
10155
|
-
result
|
|
11080
|
+
result,
|
|
11081
|
+
observation
|
|
10156
11082
|
});
|
|
10157
11083
|
if (this.stateStore.deleteCheckpoints) {
|
|
10158
11084
|
await this.stateStore.deleteCheckpoints(execInfo.executionId);
|
|
@@ -10162,19 +11088,28 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10162
11088
|
this.persistExecution(execInfo);
|
|
10163
11089
|
return result;
|
|
10164
11090
|
} catch (err) {
|
|
10165
|
-
|
|
11091
|
+
let terminalError = err;
|
|
11092
|
+
try {
|
|
11093
|
+
const drainedObservation = await ctx._drainBranchWork();
|
|
11094
|
+
observation = drainedObservation.complete === false ? drainedObservation : execInfo.observation ?? drainedObservation;
|
|
11095
|
+
} catch (drainErr) {
|
|
11096
|
+
terminalError = drainErr instanceof Error ? preserveErrorCause(drainErr, terminalError) : drainErr;
|
|
11097
|
+
}
|
|
11098
|
+
const aborted = isAbortError4(terminalError);
|
|
10166
11099
|
execInfo.status = "failed";
|
|
10167
11100
|
execInfo.completedAt = Date.now();
|
|
10168
11101
|
execInfo.duration = execInfo.completedAt - execInfo.startedAt;
|
|
10169
|
-
execInfo.error =
|
|
11102
|
+
execInfo.error = terminalError instanceof Error ? terminalError.message : String(terminalError);
|
|
11103
|
+
execInfo.observation = observation;
|
|
10170
11104
|
ctx._emitWorkflowEnd({
|
|
10171
11105
|
status: "failed",
|
|
10172
11106
|
duration: execInfo.duration,
|
|
10173
11107
|
error: execInfo.error,
|
|
10174
|
-
...aborted ? { aborted: true } : {}
|
|
11108
|
+
...aborted ? { aborted: true } : {},
|
|
11109
|
+
observation
|
|
10175
11110
|
});
|
|
10176
11111
|
this.persistExecution(execInfo);
|
|
10177
|
-
throw
|
|
11112
|
+
throw terminalError;
|
|
10178
11113
|
} finally {
|
|
10179
11114
|
this.abortControllers.delete(execInfo.executionId);
|
|
10180
11115
|
cleanupAbortForwarder?.();
|
|
@@ -10362,13 +11297,13 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10362
11297
|
return result;
|
|
10363
11298
|
}
|
|
10364
11299
|
/** Get all execution info (running + completed + historical). */
|
|
10365
|
-
/** Normalize an
|
|
10366
|
-
*
|
|
11300
|
+
/** Normalize an execution loaded from a `StateStore` so the
|
|
11301
|
+
* historical event union holds for downstream consumers
|
|
10367
11302
|
* (Studio aggregators, REST routes, redaction). Custom or legacy stores
|
|
10368
11303
|
* may persist rows without `events` (or with a non-array value) — without
|
|
10369
11304
|
* this guard, a single malformed row crashes every iterator over
|
|
10370
|
-
* `exec.events` and takes down dependent features.
|
|
10371
|
-
*
|
|
11305
|
+
* `exec.events` and takes down dependent features. Returns a normalized
|
|
11306
|
+
* copy; logs at most one warning per `executionId`. */
|
|
10372
11307
|
normalizeStoredExecution(exec) {
|
|
10373
11308
|
if (!Array.isArray(exec.events)) {
|
|
10374
11309
|
if (!this.warnedMalformedExecutions.has(exec.executionId)) {
|
|
@@ -10377,9 +11312,9 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10377
11312
|
`[axl] StateStore returned execution ${exec.executionId} with non-array events (got ${exec.events === null ? "null" : typeof exec.events}); coercing to []`
|
|
10378
11313
|
);
|
|
10379
11314
|
}
|
|
10380
|
-
exec
|
|
11315
|
+
return normalizeStoredExecution({ ...exec, events: [] });
|
|
10381
11316
|
}
|
|
10382
|
-
return exec;
|
|
11317
|
+
return normalizeStoredExecution(exec);
|
|
10383
11318
|
}
|
|
10384
11319
|
async getExecutions() {
|
|
10385
11320
|
if (!this.historicalExecutionsLoadPromise && this.stateStore.listExecutions) {
|
|
@@ -10389,8 +11324,9 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10389
11324
|
this.historicalExecutions.set(exec.executionId, this.normalizeStoredExecution(exec));
|
|
10390
11325
|
}
|
|
10391
11326
|
}
|
|
10392
|
-
}).catch(() => {
|
|
11327
|
+
}).catch((error) => {
|
|
10393
11328
|
this.historicalExecutionsLoadPromise = null;
|
|
11329
|
+
throw error;
|
|
10394
11330
|
});
|
|
10395
11331
|
}
|
|
10396
11332
|
if (this.historicalExecutionsLoadPromise) {
|
|
@@ -10408,6 +11344,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10408
11344
|
* and automatically emits trace events and tracks cost.
|
|
10409
11345
|
*/
|
|
10410
11346
|
createContext(options) {
|
|
11347
|
+
assertNoRemovedObservationCallbacks(options);
|
|
10411
11348
|
const executionId = (0, import_node_crypto3.randomUUID)();
|
|
10412
11349
|
const budgetLimit = options?.budget ? parseCost(options.budget) : Infinity;
|
|
10413
11350
|
this.registerWithCostScope(executionId);
|
|
@@ -10423,10 +11360,8 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10423
11360
|
memoryManager: this.memoryManager,
|
|
10424
11361
|
sessionHistory: options?.sessionHistory,
|
|
10425
11362
|
signal: options?.signal,
|
|
10426
|
-
onToken: options?.onToken,
|
|
10427
|
-
onToolCall: options?.onToolCall,
|
|
10428
|
-
onAgentStart: options?.onAgentStart,
|
|
10429
11363
|
awaitHumanHandler: options?.awaitHumanHandler,
|
|
11364
|
+
_onDecisionCleanupFailed: (event) => this.emit("decision_cleanup_failed", event),
|
|
10430
11365
|
eventStreamOptions: options?.events,
|
|
10431
11366
|
onTrace: (event) => {
|
|
10432
11367
|
this.emit("trace", event);
|
|
@@ -10460,6 +11395,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10460
11395
|
);
|
|
10461
11396
|
}
|
|
10462
11397
|
const validated = workflow2.inputSchema.parse(input);
|
|
11398
|
+
const branchDrainTimeoutMs = resolveBranchDrainTimeoutMs(options?.branchDrainTimeoutMs);
|
|
10463
11399
|
const executionId = (0, import_node_crypto3.randomUUID)();
|
|
10464
11400
|
const controller = new AbortController();
|
|
10465
11401
|
this.abortControllers.set(executionId, controller);
|
|
@@ -10472,11 +11408,13 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10472
11408
|
executionId,
|
|
10473
11409
|
workflow: name,
|
|
10474
11410
|
status: "running",
|
|
11411
|
+
eventSchemaVersion: 2,
|
|
10475
11412
|
events: [],
|
|
10476
11413
|
totalCost: 0,
|
|
10477
11414
|
unpriced: false,
|
|
10478
11415
|
startedAt: Date.now(),
|
|
10479
11416
|
duration: 0,
|
|
11417
|
+
observation: { complete: true },
|
|
10480
11418
|
metadata: liftPersistedMetadata(options?.metadata)
|
|
10481
11419
|
};
|
|
10482
11420
|
this.executions.set(executionId, execInfo);
|
|
@@ -10490,6 +11428,8 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10490
11428
|
sessionHistory,
|
|
10491
11429
|
signal: controller.signal,
|
|
10492
11430
|
eventStreamOptions: options?.events,
|
|
11431
|
+
branchDrainTimeoutMs,
|
|
11432
|
+
_onDecisionCleanupFailed: (event) => this.emit("decision_cleanup_failed", event),
|
|
10493
11433
|
onTrace: (event) => {
|
|
10494
11434
|
pushEventBounded(execInfo, event, this.maxEventsPerExecution);
|
|
10495
11435
|
execInfo.totalCost += eventCostContribution(event);
|
|
@@ -10534,7 +11474,6 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10534
11474
|
workflowName: name,
|
|
10535
11475
|
mcpManager: this.mcpManager,
|
|
10536
11476
|
memoryManager: this.memoryManager,
|
|
10537
|
-
resumeMode: !!options?.metadata?.resumeMode,
|
|
10538
11477
|
spanManager: this.spanManager,
|
|
10539
11478
|
budgetContext: {
|
|
10540
11479
|
totalCost: 0,
|
|
@@ -10565,6 +11504,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10565
11504
|
}
|
|
10566
11505
|
/** Execute a workflow and return a stream. */
|
|
10567
11506
|
stream(name, input, options) {
|
|
11507
|
+
const branchDrainTimeoutMs = resolveBranchDrainTimeoutMs(options?.branchDrainTimeoutMs);
|
|
10568
11508
|
const axlStream = new AxlStream(options?.events);
|
|
10569
11509
|
const controller = new AbortController();
|
|
10570
11510
|
axlStream.on("close", () => controller.abort());
|
|
@@ -10585,11 +11525,13 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10585
11525
|
executionId,
|
|
10586
11526
|
workflow: name,
|
|
10587
11527
|
status: "running",
|
|
11528
|
+
eventSchemaVersion: 2,
|
|
10588
11529
|
events: [],
|
|
10589
11530
|
totalCost: 0,
|
|
10590
11531
|
unpriced: false,
|
|
10591
11532
|
startedAt: Date.now(),
|
|
10592
11533
|
duration: 0,
|
|
11534
|
+
observation: { complete: true },
|
|
10593
11535
|
metadata: liftPersistedMetadata(options?.metadata)
|
|
10594
11536
|
};
|
|
10595
11537
|
this.executions.set(executionId, execInfo);
|
|
@@ -10602,12 +11544,11 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10602
11544
|
sessionHistory,
|
|
10603
11545
|
signal: controller.signal,
|
|
10604
11546
|
eventStreamOptions: options?.events,
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
//
|
|
10608
|
-
//
|
|
10609
|
-
|
|
10610
|
-
},
|
|
11547
|
+
branchDrainTimeoutMs,
|
|
11548
|
+
_onDecisionCleanupFailed: (event) => this.emit("decision_cleanup_failed", event),
|
|
11549
|
+
// Transport mode is explicit internal state. It is inherited by child
|
|
11550
|
+
// contexts and does not allocate an unconsumed ctx.events queue.
|
|
11551
|
+
_forceStreaming: true,
|
|
10611
11552
|
onTrace: (event) => {
|
|
10612
11553
|
pushEventBounded(execInfo, event, this.maxEventsPerExecution);
|
|
10613
11554
|
execInfo.totalCost += eventCostContribution(event);
|
|
@@ -10653,7 +11594,6 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10653
11594
|
workflowName: name,
|
|
10654
11595
|
mcpManager: this.mcpManager,
|
|
10655
11596
|
memoryManager: this.memoryManager,
|
|
10656
|
-
resumeMode: !!options?.metadata?.resumeMode,
|
|
10657
11597
|
spanManager: this.spanManager,
|
|
10658
11598
|
budgetContext: {
|
|
10659
11599
|
totalCost: 0,
|
|
@@ -10817,6 +11757,12 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10817
11757
|
await this.stateStore.finalizeStreamingEvents?.(id);
|
|
10818
11758
|
continue;
|
|
10819
11759
|
}
|
|
11760
|
+
const eventSchemaVersion = getEventSchemaVersion(events[0]);
|
|
11761
|
+
for (const event of events) {
|
|
11762
|
+
if (getEventSchemaVersion(event) !== eventSchemaVersion) {
|
|
11763
|
+
throw new Error(`Streaming buffer ${id} contains mixed event schema versions`);
|
|
11764
|
+
}
|
|
11765
|
+
}
|
|
10820
11766
|
const boundedEvents = boundRecoveredEvents(events, this.maxEventsPerExecution);
|
|
10821
11767
|
const workflowStartEvent = boundedEvents.find((e) => e.type === "workflow_start");
|
|
10822
11768
|
const lastEvent = boundedEvents[boundedEvents.length - 1];
|
|
@@ -10825,7 +11771,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10825
11771
|
const workflowName = workflowStartEvent?.workflow ?? RECOVERED_UNKNOWN_WORKFLOW;
|
|
10826
11772
|
const totalCost = boundedEvents.reduce((sum, e) => sum + eventCostContribution(e), 0);
|
|
10827
11773
|
const unpriced = boundedEvents.some(isUnpricedLeaf);
|
|
10828
|
-
const
|
|
11774
|
+
const executionBase = {
|
|
10829
11775
|
executionId: id,
|
|
10830
11776
|
workflow: workflowName,
|
|
10831
11777
|
status: "failed",
|
|
@@ -10837,6 +11783,16 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10837
11783
|
duration: completedAt - startedAt,
|
|
10838
11784
|
error: "process terminated (recovered from streaming buffer)"
|
|
10839
11785
|
};
|
|
11786
|
+
const synthesized = eventSchemaVersion === 2 ? {
|
|
11787
|
+
...executionBase,
|
|
11788
|
+
eventSchemaVersion: 2,
|
|
11789
|
+
events: boundedEvents,
|
|
11790
|
+
observation: { complete: false, reason: "process_interrupted" }
|
|
11791
|
+
} : {
|
|
11792
|
+
...executionBase,
|
|
11793
|
+
eventSchemaVersion: 1,
|
|
11794
|
+
events: boundedEvents
|
|
11795
|
+
};
|
|
10840
11796
|
if (this.stateStore.saveExecution) {
|
|
10841
11797
|
try {
|
|
10842
11798
|
await this.stateStore.saveExecution(synthesized);
|
|
@@ -10917,7 +11873,8 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10917
11873
|
*/
|
|
10918
11874
|
async deleteExecution(id) {
|
|
10919
11875
|
const wasActive = this.executions.has(id);
|
|
10920
|
-
const
|
|
11876
|
+
const pendingDecisionResolver = this.pendingDecisionResolvers.get(id);
|
|
11877
|
+
const hadPendingDecision = pendingDecisionResolver !== void 0;
|
|
10921
11878
|
if (wasActive) {
|
|
10922
11879
|
this.pendingDeletedExecutions.add(id);
|
|
10923
11880
|
this.streamableExecutionIds.delete(id);
|
|
@@ -10926,8 +11883,12 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
10926
11883
|
controller.abort();
|
|
10927
11884
|
}
|
|
10928
11885
|
}
|
|
10929
|
-
if (
|
|
10930
|
-
|
|
11886
|
+
if (pendingDecisionResolver) pendingDecisionResolver.cancelled = true;
|
|
11887
|
+
if (pendingDecisionResolver) {
|
|
11888
|
+
await pendingDecisionResolver.cleanupFinished;
|
|
11889
|
+
if (this.pendingDecisionResolvers.get(id) === pendingDecisionResolver) {
|
|
11890
|
+
this.pendingDecisionResolvers.delete(id);
|
|
11891
|
+
}
|
|
10931
11892
|
}
|
|
10932
11893
|
const existing = await this.getExecution(id);
|
|
10933
11894
|
const workflow2 = existing?.workflow;
|
|
@@ -11005,60 +11966,68 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
11005
11966
|
}
|
|
11006
11967
|
/** Resolve a pending human decision. */
|
|
11007
11968
|
async resolveDecision(executionId, decision) {
|
|
11008
|
-
|
|
11969
|
+
decision = parseHumanDecision(decision);
|
|
11970
|
+
let resolver = this.pendingDecisionResolvers.get(executionId);
|
|
11009
11971
|
if (resolver) {
|
|
11010
|
-
resolver
|
|
11011
|
-
|
|
11972
|
+
if (resolver.cancelled) {
|
|
11973
|
+
throw new AxlError(
|
|
11974
|
+
"PENDING_DECISION_NOT_FOUND",
|
|
11975
|
+
`The pending human decision for execution "${executionId}" is no longer active.`
|
|
11976
|
+
);
|
|
11977
|
+
}
|
|
11978
|
+
await resolver.ready;
|
|
11979
|
+
if (resolver.cancelled || resolver.state !== "pending" || this.pendingDecisionResolvers.get(executionId) !== resolver) {
|
|
11980
|
+
throw new AxlError(
|
|
11981
|
+
"PENDING_DECISION_NOT_FOUND",
|
|
11982
|
+
`The pending human decision for execution "${executionId}" is no longer active.`
|
|
11983
|
+
);
|
|
11984
|
+
}
|
|
11012
11985
|
}
|
|
11013
|
-
await this.stateStore.resolveDecision(executionId, decision);
|
|
11014
11986
|
if (!resolver) {
|
|
11015
|
-
const
|
|
11016
|
-
|
|
11017
|
-
|
|
11987
|
+
const pending = await this.stateStore.getPendingDecisions();
|
|
11988
|
+
resolver = this.pendingDecisionResolvers.get(executionId);
|
|
11989
|
+
if (resolver) {
|
|
11990
|
+
if (resolver.cancelled) {
|
|
11991
|
+
throw new AxlError(
|
|
11992
|
+
"PENDING_DECISION_NOT_FOUND",
|
|
11993
|
+
`The pending human decision for execution "${executionId}" is no longer active.`
|
|
11994
|
+
);
|
|
11995
|
+
}
|
|
11996
|
+
await resolver.ready;
|
|
11997
|
+
if (resolver.cancelled || resolver.state !== "pending" || this.pendingDecisionResolvers.get(executionId) !== resolver) {
|
|
11998
|
+
throw new AxlError(
|
|
11999
|
+
"PENDING_DECISION_NOT_FOUND",
|
|
12000
|
+
`The pending human decision for execution "${executionId}" is no longer active.`
|
|
12001
|
+
);
|
|
12002
|
+
}
|
|
12003
|
+
} else if (!pending.some((request) => request.executionId === executionId)) {
|
|
12004
|
+
throw new AxlError(
|
|
12005
|
+
"PENDING_DECISION_NOT_FOUND",
|
|
12006
|
+
`No pending human decision exists for execution "${executionId}".`
|
|
12007
|
+
);
|
|
12008
|
+
} else {
|
|
12009
|
+
throw new AxlError(
|
|
12010
|
+
"CROSS_PROCESS_RESUME_UNSUPPORTED",
|
|
12011
|
+
`Execution "${executionId}" is not awaiting a decision in this runtime. Cross-process approval replay requires a durable decision/lease lineage and is not yet supported; any persisted pending request was preserved.`
|
|
12012
|
+
);
|
|
11018
12013
|
}
|
|
11019
12014
|
}
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
* Re-runs the workflow from scratch; the workflow should use checkpoint-replay
|
|
11024
|
-
* to skip already-completed steps and pick up from the awaitHuman point.
|
|
11025
|
-
*/
|
|
11026
|
-
async resumeExecution(executionId) {
|
|
11027
|
-
const state = await this.stateStore.getExecutionState(executionId);
|
|
11028
|
-
if (!state) {
|
|
11029
|
-
throw new Error(`No execution state found for "${executionId}"`);
|
|
11030
|
-
}
|
|
11031
|
-
const workflow2 = this.workflows.get(state.workflow);
|
|
11032
|
-
if (!workflow2) {
|
|
11033
|
-
throw new Error(
|
|
11034
|
-
`Workflow "${state.workflow}" not registered. Cannot resume execution "${executionId}".`
|
|
11035
|
-
);
|
|
11036
|
-
}
|
|
11037
|
-
return this.execute(state.workflow, state.input, {
|
|
11038
|
-
metadata: { ...state.metadata, resumedFrom: executionId, resumeMode: true }
|
|
12015
|
+
let finishResolution;
|
|
12016
|
+
const resolutionFinished = new Promise((resolve2) => {
|
|
12017
|
+
finishResolution = resolve2;
|
|
11039
12018
|
});
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
await this.resumeExecution(executionId);
|
|
11052
|
-
resumed.push(executionId);
|
|
11053
|
-
} catch (err) {
|
|
11054
|
-
this.emit("error", {
|
|
11055
|
-
type: "resume_failed",
|
|
11056
|
-
executionId,
|
|
11057
|
-
error: err instanceof Error ? err.message : String(err)
|
|
11058
|
-
});
|
|
11059
|
-
}
|
|
12019
|
+
resolver.state = "resolving";
|
|
12020
|
+
resolver.resolution = resolutionFinished;
|
|
12021
|
+
try {
|
|
12022
|
+
await this.stateStore.resolveDecision(executionId, decision);
|
|
12023
|
+
resolver.state = "resolved";
|
|
12024
|
+
finishResolution(true);
|
|
12025
|
+
resolver.resolve(decision);
|
|
12026
|
+
} catch (error) {
|
|
12027
|
+
resolver.state = "pending";
|
|
12028
|
+
finishResolution(false);
|
|
12029
|
+
throw error;
|
|
11060
12030
|
}
|
|
11061
|
-
return resumed;
|
|
11062
12031
|
}
|
|
11063
12032
|
/**
|
|
11064
12033
|
* Summarize a list of chat messages into a concise summary string.
|
|
@@ -11960,28 +12929,32 @@ var RedisStore = class _RedisStore {
|
|
|
11960
12929
|
async saveExecution(execution) {
|
|
11961
12930
|
const ttl = this.ttlFor("executionHistory");
|
|
11962
12931
|
const setOptions = ttl !== void 0 ? { EX: ttl } : void 0;
|
|
11963
|
-
|
|
12932
|
+
const storedExecution = normalizeStoredExecution({
|
|
12933
|
+
...execution,
|
|
12934
|
+
eventSchemaVersion: getExecutionEventSchemaVersion(execution)
|
|
12935
|
+
});
|
|
12936
|
+
await this.client.multi().sAdd(this.execHistorySetKey(), execution.executionId).set(this.execHistoryKey(execution.executionId), JSON.stringify(storedExecution), setOptions).zAdd(this.execHistoryZsetKey(), {
|
|
11964
12937
|
score: execution.startedAt,
|
|
11965
12938
|
value: execution.executionId
|
|
11966
12939
|
}).exec();
|
|
11967
12940
|
}
|
|
11968
12941
|
async getExecution(executionId) {
|
|
11969
12942
|
const raw = await this.client.get(this.execHistoryKey(executionId));
|
|
11970
|
-
return raw ? JSON.parse(raw) : null;
|
|
12943
|
+
return raw ? normalizeStoredExecution(JSON.parse(raw)) : null;
|
|
11971
12944
|
}
|
|
11972
12945
|
async listExecutions(limit) {
|
|
11973
|
-
|
|
12946
|
+
const executions = await this.listHistoryByZset(
|
|
11974
12947
|
this.execHistorySetKey(),
|
|
11975
12948
|
this.execHistoryZsetKey(),
|
|
11976
12949
|
(id) => this.execHistoryKey(id),
|
|
11977
12950
|
(a, b) => b.startedAt - a.startedAt,
|
|
11978
12951
|
limit
|
|
11979
12952
|
);
|
|
12953
|
+
return executions.map(normalizeStoredExecution);
|
|
11980
12954
|
}
|
|
11981
12955
|
async deleteExecution(executionId) {
|
|
11982
|
-
const
|
|
11983
|
-
|
|
11984
|
-
return deleted > 0;
|
|
12956
|
+
const results = await this.client.multi().sRem(this.execHistorySetKey(), executionId).del(this.execHistoryKey(executionId)).zRem(this.execHistoryZsetKey(), executionId).del(this.checkpointKey(executionId)).del(this.executionStateKey(executionId)).sRem(this.pendingExecSetKey(), executionId).del(this.streamingEventsKey(executionId)).sRem(this.streamingIdsKey(), executionId).hDel(this.decisionsKey(), executionId).exec();
|
|
12957
|
+
return results.some((result) => typeof result === "number" && result > 0);
|
|
11985
12958
|
}
|
|
11986
12959
|
// ── Eval History ────────────────────────────────────────────────────
|
|
11987
12960
|
async saveEvalResult(entry) {
|
|
@@ -12073,14 +13046,15 @@ var RedisStore = class _RedisStore {
|
|
|
12073
13046
|
async getStreamingEvents(executionId) {
|
|
12074
13047
|
const raws = await this.client.lRange(this.streamingEventsKey(executionId), 0, -1);
|
|
12075
13048
|
if (raws.length === 0) return [];
|
|
12076
|
-
|
|
12077
|
-
for (const raw of raws) {
|
|
13049
|
+
return raws.map((raw, index) => {
|
|
12078
13050
|
try {
|
|
12079
|
-
|
|
12080
|
-
} catch {
|
|
13051
|
+
return JSON.parse(raw);
|
|
13052
|
+
} catch (error) {
|
|
13053
|
+
throw new Error(`Streaming buffer ${executionId} contains invalid JSON at index ${index}`, {
|
|
13054
|
+
cause: error
|
|
13055
|
+
});
|
|
12081
13056
|
}
|
|
12082
|
-
}
|
|
12083
|
-
return events;
|
|
13057
|
+
});
|
|
12084
13058
|
}
|
|
12085
13059
|
/** Close the Redis connection. */
|
|
12086
13060
|
async close() {
|
|
@@ -12292,6 +13266,8 @@ function cosineSimilarity2(a, b) {
|
|
|
12292
13266
|
// Annotate the CommonJS export names for ESM import in node:
|
|
12293
13267
|
0 && (module.exports = {
|
|
12294
13268
|
AXL_EVENT_TYPES,
|
|
13269
|
+
AXL_EVENT_TYPES_V2,
|
|
13270
|
+
AXL_TOOL_LIFECYCLE_TYPES_V2,
|
|
12295
13271
|
AZURE_PROFILE,
|
|
12296
13272
|
AnthropicProvider,
|
|
12297
13273
|
AxlError,
|
|
@@ -12339,8 +13315,9 @@ function cosineSimilarity2(a, b) {
|
|
|
12339
13315
|
SqliteVectorStore,
|
|
12340
13316
|
ThinkTagScanner,
|
|
12341
13317
|
TimeoutError,
|
|
12342
|
-
|
|
13318
|
+
ToolFailure,
|
|
12343
13319
|
ToolModelOutputError,
|
|
13320
|
+
UnsupportedEventSchemaVersionError,
|
|
12344
13321
|
VLLM_PROFILE,
|
|
12345
13322
|
ValidationError,
|
|
12346
13323
|
VerifyError,
|
|
@@ -12355,6 +13332,8 @@ function cosineSimilarity2(a, b) {
|
|
|
12355
13332
|
extractJson,
|
|
12356
13333
|
extractThinkTags,
|
|
12357
13334
|
findConfig,
|
|
13335
|
+
getEventSchemaVersion,
|
|
13336
|
+
getExecutionEventSchemaVersion,
|
|
12358
13337
|
hasPositiveTokens,
|
|
12359
13338
|
importModule,
|
|
12360
13339
|
isCostBearingLeaf,
|
|
@@ -12363,6 +13342,7 @@ function cosineSimilarity2(a, b) {
|
|
|
12363
13342
|
isUnpricedLeaf,
|
|
12364
13343
|
isUsableCost,
|
|
12365
13344
|
needsTsxLoader,
|
|
13345
|
+
normalizeStoredExecution,
|
|
12366
13346
|
openaiReasoningEmit,
|
|
12367
13347
|
parsePartialJson,
|
|
12368
13348
|
pickDefault,
|
|
@@ -12371,6 +13351,7 @@ function cosineSimilarity2(a, b) {
|
|
|
12371
13351
|
reasoningEffortEmit,
|
|
12372
13352
|
reasoningObjectEmit,
|
|
12373
13353
|
redactEvent,
|
|
13354
|
+
redactHistoricalEvent,
|
|
12374
13355
|
registerConditions,
|
|
12375
13356
|
resolveApiKey,
|
|
12376
13357
|
resolvePerModel,
|