@axlsdk/axl 0.24.1 → 0.24.3
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/dist/index.cjs +228 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +228 -117
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -111,6 +111,12 @@ function isEventStreamOverflowError(error) {
|
|
|
111
111
|
function rethrowEventStreamOverflow(error) {
|
|
112
112
|
if (isEventStreamOverflowError(error)) throw error;
|
|
113
113
|
}
|
|
114
|
+
function isUnrecoverableError(error) {
|
|
115
|
+
return isEventStreamOverflowError(error) || isAdmissionDeniedError(error);
|
|
116
|
+
}
|
|
117
|
+
function rethrowUnrecoverable(error) {
|
|
118
|
+
if (isUnrecoverableError(error)) throw error;
|
|
119
|
+
}
|
|
114
120
|
function preserveErrorCause(error, cause) {
|
|
115
121
|
if (cause === void 0 || cause === error || "cause" in error) return error;
|
|
116
122
|
Object.defineProperty(error, "cause", {
|
|
@@ -120,12 +126,14 @@ function preserveErrorCause(error, cause) {
|
|
|
120
126
|
});
|
|
121
127
|
return error;
|
|
122
128
|
}
|
|
129
|
+
var TOOL_FAILURE_MARKER = /* @__PURE__ */ Symbol.for("axl.toolFailure.v1");
|
|
123
130
|
var ToolFailure = class extends AxlError {
|
|
124
131
|
modelMessage;
|
|
125
132
|
constructor(options) {
|
|
126
133
|
super(options.code ?? "TOOL_FAILURE", options.message);
|
|
127
134
|
this.name = "ToolFailure";
|
|
128
135
|
this.modelMessage = options.modelMessage;
|
|
136
|
+
Object.defineProperty(this, TOOL_FAILURE_MARKER, { value: true });
|
|
129
137
|
if (options.cause !== void 0) {
|
|
130
138
|
Object.defineProperty(this, "cause", {
|
|
131
139
|
configurable: true,
|
|
@@ -135,6 +143,13 @@ var ToolFailure = class extends AxlError {
|
|
|
135
143
|
}
|
|
136
144
|
}
|
|
137
145
|
};
|
|
146
|
+
function isToolFailureError(error) {
|
|
147
|
+
try {
|
|
148
|
+
return error instanceof ToolFailure || typeof error === "object" && error !== null && error[TOOL_FAILURE_MARKER] === true && typeof error.modelMessage === "string";
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
138
153
|
var ToolModelOutputError = class extends AxlError {
|
|
139
154
|
toolName;
|
|
140
155
|
cause;
|
|
@@ -316,7 +331,7 @@ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null
|
|
|
316
331
|
var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
|
|
317
332
|
var thisCopy = {
|
|
318
333
|
path: buildPath.startsWith("file:") ? fileURLToPath(buildPath) : buildPath,
|
|
319
|
-
version: true ? "0.24.
|
|
334
|
+
version: true ? "0.24.3" : "unknown"
|
|
320
335
|
};
|
|
321
336
|
function warnCrossCopy(other, joined) {
|
|
322
337
|
if (other === thisCopy) return;
|
|
@@ -417,10 +432,16 @@ var AccountingScope = class {
|
|
|
417
432
|
reasons = /* @__PURE__ */ new Map();
|
|
418
433
|
breakdown = { generation: 0, judging: 0, external: 0 };
|
|
419
434
|
provenance = /* @__PURE__ */ new Map();
|
|
435
|
+
modelCalls = /* @__PURE__ */ new Map();
|
|
436
|
+
modelTiming = /* @__PURE__ */ new Map();
|
|
437
|
+
diagnosticTokens = { input: 0, output: 0, reasoning: 0 };
|
|
438
|
+
agentCalls = 0;
|
|
439
|
+
captureTimingSamples;
|
|
420
440
|
constructor(options) {
|
|
421
441
|
this.parent = options.parent;
|
|
422
442
|
this.purpose = options.purpose;
|
|
423
443
|
this.admission = options.admission;
|
|
444
|
+
this.captureTimingSamples = options.captureTimingSamples === true;
|
|
424
445
|
}
|
|
425
446
|
get isFinalized() {
|
|
426
447
|
return this.finalized;
|
|
@@ -449,7 +470,7 @@ var AccountingScope = class {
|
|
|
449
470
|
else this.byKind.delete(op.kind);
|
|
450
471
|
this.denied += 1;
|
|
451
472
|
}
|
|
452
|
-
recordSettled(op, cost, provenance, usage) {
|
|
473
|
+
recordSettled(op, cost, provenance, usage, timing) {
|
|
453
474
|
this.seen.add(op.id);
|
|
454
475
|
this.openOps.delete(op.id);
|
|
455
476
|
this.settled += 1;
|
|
@@ -458,13 +479,57 @@ var AccountingScope = class {
|
|
|
458
479
|
else this.breakdown[op.purpose] += cost;
|
|
459
480
|
this.provenance.set(provenance, (this.provenance.get(provenance) ?? 0) + cost);
|
|
460
481
|
if (usage) this.addUsage(usage);
|
|
482
|
+
this.recordAgentCall(op, usage, timing);
|
|
461
483
|
}
|
|
462
|
-
recordUnknown(op, reason, usage) {
|
|
484
|
+
recordUnknown(op, reason, usage, timing) {
|
|
463
485
|
this.seen.add(op.id);
|
|
464
486
|
this.openOps.delete(op.id);
|
|
465
487
|
this.unknown += 1;
|
|
466
488
|
this.reasons.set(reason, (this.reasons.get(reason) ?? 0) + 1);
|
|
467
489
|
if (usage) this.addUsage(usage);
|
|
490
|
+
this.recordAgentCall(op, usage, timing);
|
|
491
|
+
}
|
|
492
|
+
recordAgentCall(op, usage, timing) {
|
|
493
|
+
if (!op.agentCall) return;
|
|
494
|
+
this.agentCalls++;
|
|
495
|
+
const model = op.diagnosticModelUri ?? op.model;
|
|
496
|
+
if (!model) return;
|
|
497
|
+
this.modelCalls.set(model, (this.modelCalls.get(model) ?? 0) + 1);
|
|
498
|
+
if (usage) {
|
|
499
|
+
const finite = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
500
|
+
this.diagnosticTokens.input += finite(usage.inputTokens);
|
|
501
|
+
this.diagnosticTokens.output += finite(usage.outputTokens);
|
|
502
|
+
this.diagnosticTokens.reasoning += finite(usage.reasoningTokens);
|
|
503
|
+
}
|
|
504
|
+
if (!timing) return;
|
|
505
|
+
let bucket = this.modelTiming.get(model);
|
|
506
|
+
if (!bucket) {
|
|
507
|
+
bucket = {
|
|
508
|
+
calls: 0,
|
|
509
|
+
queuedMs: 0,
|
|
510
|
+
retryMs: 0,
|
|
511
|
+
wireMs: 0,
|
|
512
|
+
...this.captureTimingSamples ? { samples: [] } : {}
|
|
513
|
+
};
|
|
514
|
+
this.modelTiming.set(model, bucket);
|
|
515
|
+
}
|
|
516
|
+
bucket.calls++;
|
|
517
|
+
bucket.queuedMs += timing.queuedMs;
|
|
518
|
+
bucket.retryMs += timing.retryMs;
|
|
519
|
+
bucket.wireMs += timing.wireMs;
|
|
520
|
+
bucket.samples?.push(timing);
|
|
521
|
+
if (timing.firstTokenMs != null) {
|
|
522
|
+
bucket.firstTokenMs = (bucket.firstTokenMs ?? 0) + timing.firstTokenMs;
|
|
523
|
+
bucket.firstTokenCalls = (bucket.firstTokenCalls ?? 0) + 1;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
toDiagnostics() {
|
|
527
|
+
return {
|
|
528
|
+
modelCallCounts: Object.fromEntries(this.modelCalls),
|
|
529
|
+
tokens: { ...this.diagnosticTokens },
|
|
530
|
+
agentCalls: this.agentCalls,
|
|
531
|
+
modelTiming: Object.fromEntries(this.modelTiming)
|
|
532
|
+
};
|
|
468
533
|
}
|
|
469
534
|
hasSeen(id) {
|
|
470
535
|
return this.seen.has(id);
|
|
@@ -536,14 +601,14 @@ function settleOperationUp(start, op, outcome) {
|
|
|
536
601
|
if (scope.isFinalized) return;
|
|
537
602
|
switch (outcome.outcome) {
|
|
538
603
|
case "settled":
|
|
539
|
-
scope.recordSettled(op, outcome.cost, outcome.provenance, outcome.usage);
|
|
604
|
+
scope.recordSettled(op, outcome.cost, outcome.provenance, outcome.usage, outcome.timing);
|
|
540
605
|
if (scope.admission && !chargedControllers.has(scope.admission)) {
|
|
541
606
|
chargedControllers.add(scope.admission);
|
|
542
607
|
recordSpend(scope.admission, outcome.cost);
|
|
543
608
|
}
|
|
544
609
|
break;
|
|
545
610
|
case "unknown":
|
|
546
|
-
scope.recordUnknown(op, outcome.reason, outcome.usage);
|
|
611
|
+
scope.recordUnknown(op, outcome.reason, outcome.usage, outcome.timing);
|
|
547
612
|
break;
|
|
548
613
|
case "retracted":
|
|
549
614
|
scope.recordRetracted(op);
|
|
@@ -595,6 +660,8 @@ function openOperation(descriptor) {
|
|
|
595
660
|
kind: descriptor.kind,
|
|
596
661
|
purpose: scope.purpose,
|
|
597
662
|
model: descriptor.model,
|
|
663
|
+
diagnosticModelUri: descriptor.diagnosticModelUri,
|
|
664
|
+
agentCall: descriptor.agentCall === true,
|
|
598
665
|
dispatched: false,
|
|
599
666
|
dispatchObservable: false
|
|
600
667
|
};
|
|
@@ -635,25 +702,31 @@ function openOperation(descriptor) {
|
|
|
635
702
|
outcome: "settled",
|
|
636
703
|
cost: input.cost,
|
|
637
704
|
provenance: input.provenance ?? "adapter_reported",
|
|
638
|
-
usage: input.usage
|
|
705
|
+
usage: input.usage,
|
|
706
|
+
timing: input.timing
|
|
639
707
|
});
|
|
640
708
|
return;
|
|
641
709
|
}
|
|
642
710
|
if (input.cost !== void 0 || input.usage !== void 0) {
|
|
643
|
-
finish({
|
|
711
|
+
finish({
|
|
712
|
+
outcome: "unknown",
|
|
713
|
+
reason: "unpriced_model",
|
|
714
|
+
usage: input.usage,
|
|
715
|
+
timing: input.timing
|
|
716
|
+
});
|
|
644
717
|
return;
|
|
645
718
|
}
|
|
646
|
-
handle.settleFailure();
|
|
719
|
+
handle.settleFailure(void 0, input.timing);
|
|
647
720
|
},
|
|
648
721
|
settleUnknown(reason, usage) {
|
|
649
722
|
finish({ outcome: "unknown", reason, usage });
|
|
650
723
|
},
|
|
651
|
-
settleFailure(usage) {
|
|
724
|
+
settleFailure(usage, timing) {
|
|
652
725
|
if (op.dispatchObservable && !op.dispatched) {
|
|
653
|
-
finish({ outcome: "settled", cost: 0, provenance: "adapter_reported", usage });
|
|
726
|
+
finish({ outcome: "settled", cost: 0, provenance: "adapter_reported", usage, timing });
|
|
654
727
|
return;
|
|
655
728
|
}
|
|
656
|
-
finish({ outcome: "unknown", reason: "usage_missing", usage });
|
|
729
|
+
finish({ outcome: "unknown", reason: "usage_missing", usage, timing });
|
|
657
730
|
},
|
|
658
731
|
run(fn) {
|
|
659
732
|
return runWithDispatchAdmission(handle.dispatchAdmission, fn);
|
|
@@ -666,7 +739,8 @@ async function runInAccountingScope(options, fn) {
|
|
|
666
739
|
const scope = new AccountingScope({
|
|
667
740
|
parent,
|
|
668
741
|
purpose: options.purpose ?? parent?.purpose ?? "generation",
|
|
669
|
-
admission: options.admission
|
|
742
|
+
admission: options.admission,
|
|
743
|
+
captureTimingSamples: options.captureTimingSamples
|
|
670
744
|
});
|
|
671
745
|
const inheritedGuard = sharedGuard.storage.getStore();
|
|
672
746
|
const enclosingGuard = inheritedGuard && (inheritedGuard.isActive?.() ?? true) ? inheritedGuard : void 0;
|
|
@@ -684,7 +758,8 @@ async function runInAccountingScope(options, fn) {
|
|
|
684
758
|
"The active @axlsdk/axl accounting scope uses an incompatible loaded copy; paid work was refused before dispatch."
|
|
685
759
|
)
|
|
686
760
|
},
|
|
687
|
-
accounting: scope.toAccounting()
|
|
761
|
+
accounting: scope.toAccounting(),
|
|
762
|
+
diagnostics: scope.toDiagnostics()
|
|
688
763
|
};
|
|
689
764
|
}
|
|
690
765
|
const markUninstrumented = () => {
|
|
@@ -708,10 +783,18 @@ async function runInAccountingScope(options, fn) {
|
|
|
708
783
|
() => accountingStorage.run(scope, fn)
|
|
709
784
|
);
|
|
710
785
|
scope.finalize();
|
|
711
|
-
return {
|
|
786
|
+
return {
|
|
787
|
+
outcome: { status: "fulfilled", value },
|
|
788
|
+
accounting: scope.toAccounting(),
|
|
789
|
+
diagnostics: scope.toDiagnostics()
|
|
790
|
+
};
|
|
712
791
|
} catch (error) {
|
|
713
792
|
scope.finalize();
|
|
714
|
-
return {
|
|
793
|
+
return {
|
|
794
|
+
outcome: { status: "rejected", error },
|
|
795
|
+
accounting: scope.toAccounting(),
|
|
796
|
+
diagnostics: scope.toDiagnostics()
|
|
797
|
+
};
|
|
715
798
|
}
|
|
716
799
|
}
|
|
717
800
|
function validateReportedCost(amountUsd) {
|
|
@@ -1090,10 +1173,12 @@ function toolArgumentIssues(error) {
|
|
|
1090
1173
|
}
|
|
1091
1174
|
return [{ path: [], code: "invalid_arguments", message: "Tool arguments are invalid." }];
|
|
1092
1175
|
}
|
|
1093
|
-
var TOOL_INTERNALS = /* @__PURE__ */
|
|
1176
|
+
var TOOL_INTERNALS = /* @__PURE__ */ Symbol.for("axl.tool.internals.v1");
|
|
1094
1177
|
function getToolInternals(tool2) {
|
|
1095
|
-
const internals = TOOL_INTERNALS
|
|
1096
|
-
if (!internals
|
|
1178
|
+
const internals = tool2[TOOL_INTERNALS];
|
|
1179
|
+
if (!internals || typeof internals.prepareInput !== "function" || typeof internals.executePrepared !== "function") {
|
|
1180
|
+
throw new Error(`Tool "${tool2.name}" was not created by a compatible tool()`);
|
|
1181
|
+
}
|
|
1097
1182
|
return internals;
|
|
1098
1183
|
}
|
|
1099
1184
|
function prepareToolInput(tool2, input) {
|
|
@@ -1140,8 +1225,7 @@ function tool(config) {
|
|
|
1140
1225
|
} catch (err) {
|
|
1141
1226
|
if (options?.signal?.aborted) options.signal.throwIfAborted();
|
|
1142
1227
|
if (isAbortError(err)) throw err;
|
|
1143
|
-
|
|
1144
|
-
rethrowEventStreamOverflow(err);
|
|
1228
|
+
rethrowUnrecoverable(err);
|
|
1145
1229
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
1146
1230
|
if (attempt === maxAttempts) break;
|
|
1147
1231
|
if (retryPolicy.on && !retryPolicy.on(lastError)) {
|
|
@@ -1194,9 +1278,11 @@ function tool(config) {
|
|
|
1194
1278
|
},
|
|
1195
1279
|
_execute: execute
|
|
1196
1280
|
};
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1281
|
+
Object.defineProperty(instance, TOOL_INTERNALS, {
|
|
1282
|
+
value: {
|
|
1283
|
+
prepareInput,
|
|
1284
|
+
executePrepared
|
|
1285
|
+
}
|
|
1200
1286
|
});
|
|
1201
1287
|
return instance;
|
|
1202
1288
|
}
|
|
@@ -1227,6 +1313,7 @@ async function resolveApiKey(source) {
|
|
|
1227
1313
|
// src/providers/default-endpoints.ts
|
|
1228
1314
|
var OPENAI_DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
1229
1315
|
var ANTHROPIC_DEFAULT_BASE_URL = "https://api.anthropic.com/v1";
|
|
1316
|
+
var GEMINI_DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
1230
1317
|
|
|
1231
1318
|
// src/providers/rate-limiter.ts
|
|
1232
1319
|
function sanitizeRateLimitConfig(config) {
|
|
@@ -1624,12 +1711,36 @@ var anthropicQuotaDialect = makeDialect(
|
|
|
1624
1711
|
return "unknown";
|
|
1625
1712
|
}
|
|
1626
1713
|
);
|
|
1714
|
+
var geminiQuotaDialect = makeDialect([], (error) => {
|
|
1715
|
+
if (error.code === "quota_exceeded") return "spend_cap";
|
|
1716
|
+
if (Array.isArray(error.details)) {
|
|
1717
|
+
for (const detail of error.details) {
|
|
1718
|
+
if (typeof detail !== "object" || detail === null) continue;
|
|
1719
|
+
const violations = detail.violations;
|
|
1720
|
+
if (!Array.isArray(violations)) continue;
|
|
1721
|
+
if (violations.some((violation) => {
|
|
1722
|
+
if (typeof violation !== "object" || violation === null) return false;
|
|
1723
|
+
const id = violation.quotaId;
|
|
1724
|
+
return typeof id === "string" && /perday|daily|spend|billing/i.test(id);
|
|
1725
|
+
}))
|
|
1726
|
+
return "spend_cap";
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
const message = error.message;
|
|
1730
|
+
if (typeof message === "string" && /monthly spending cap|spend(?:-based|ing)? (?:cap|limit)|prepay(?:ment)? credits? (?:are )?depleted/i.test(
|
|
1731
|
+
message
|
|
1732
|
+
)) {
|
|
1733
|
+
return "spend_cap";
|
|
1734
|
+
}
|
|
1735
|
+
return "unknown";
|
|
1736
|
+
});
|
|
1627
1737
|
var DIALECTS = /* @__PURE__ */ new Map([
|
|
1628
1738
|
["openai", { origin: new URL(OPENAI_DEFAULT_BASE_URL).origin, dialect: openaiQuotaDialect }],
|
|
1629
1739
|
[
|
|
1630
1740
|
"anthropic",
|
|
1631
1741
|
{ origin: new URL(ANTHROPIC_DEFAULT_BASE_URL).origin, dialect: anthropicQuotaDialect }
|
|
1632
|
-
]
|
|
1742
|
+
],
|
|
1743
|
+
["google", { origin: new URL(GEMINI_DEFAULT_BASE_URL).origin, dialect: geminiQuotaDialect }]
|
|
1633
1744
|
]);
|
|
1634
1745
|
function quotaDialectFor(family, origin) {
|
|
1635
1746
|
const entry = DIALECTS.get(family);
|
|
@@ -5820,7 +5931,7 @@ var GEMINI_PRICING = {
|
|
|
5820
5931
|
},
|
|
5821
5932
|
"gemini-3.8-flash": { input: 75e-8, cached: 75e-9, output: 375e-8 }
|
|
5822
5933
|
};
|
|
5823
|
-
var CANONICAL_GEMINI_BASE_URL =
|
|
5934
|
+
var CANONICAL_GEMINI_BASE_URL = GEMINI_DEFAULT_BASE_URL;
|
|
5824
5935
|
function isValidTokenCount2(value) {
|
|
5825
5936
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
5826
5937
|
}
|
|
@@ -6177,10 +6288,7 @@ var GeminiProvider = class {
|
|
|
6177
6288
|
axlRateGovernors;
|
|
6178
6289
|
constructor(options = {}) {
|
|
6179
6290
|
this.apiKeySource = options.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY ?? "";
|
|
6180
|
-
this.baseUrl = (options.baseUrl ??
|
|
6181
|
-
/\/$/,
|
|
6182
|
-
""
|
|
6183
|
-
);
|
|
6291
|
+
this.baseUrl = (options.baseUrl ?? GEMINI_DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
6184
6292
|
assertSafeProviderBaseUrl(
|
|
6185
6293
|
this.baseUrl,
|
|
6186
6294
|
"Google provider",
|
|
@@ -11379,6 +11487,34 @@ function toAccountingUsage(usage) {
|
|
|
11379
11487
|
cacheWriteTokens: usage.cache_write_tokens ?? 0
|
|
11380
11488
|
};
|
|
11381
11489
|
}
|
|
11490
|
+
function safeTiming(response) {
|
|
11491
|
+
try {
|
|
11492
|
+
const timing = response.timing;
|
|
11493
|
+
if (!timing) return void 0;
|
|
11494
|
+
const queuedMs = timing.queuedMs;
|
|
11495
|
+
const retryMs = timing.retryMs;
|
|
11496
|
+
const wireMs = timing.wireMs;
|
|
11497
|
+
if (![queuedMs, retryMs, wireMs].every((value) => Number.isFinite(value) && value >= 0)) {
|
|
11498
|
+
return void 0;
|
|
11499
|
+
}
|
|
11500
|
+
const attempts = timing.attempts;
|
|
11501
|
+
const ttfbMs = timing.ttfbMs;
|
|
11502
|
+
const rateLimitRetries = timing.rateLimitRetries;
|
|
11503
|
+
const firstTokenMs = timing.firstTokenMs;
|
|
11504
|
+
const valid = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
11505
|
+
return {
|
|
11506
|
+
queuedMs,
|
|
11507
|
+
retryMs,
|
|
11508
|
+
wireMs,
|
|
11509
|
+
...valid(attempts) ? { attempts } : {},
|
|
11510
|
+
...valid(ttfbMs) ? { ttfbMs } : {},
|
|
11511
|
+
...valid(rateLimitRetries) ? { rateLimitRetries } : {},
|
|
11512
|
+
...valid(firstTokenMs) ? { firstTokenMs } : {}
|
|
11513
|
+
};
|
|
11514
|
+
} catch {
|
|
11515
|
+
return void 0;
|
|
11516
|
+
}
|
|
11517
|
+
}
|
|
11382
11518
|
function composeLifecycle(caller, onDispatch) {
|
|
11383
11519
|
return {
|
|
11384
11520
|
onDispatch() {
|
|
@@ -11572,7 +11708,13 @@ var CaptureRecorder = class {
|
|
|
11572
11708
|
}
|
|
11573
11709
|
};
|
|
11574
11710
|
function openProviderOperation(raw, kind, options) {
|
|
11575
|
-
const handle = openOperation({
|
|
11711
|
+
const handle = openOperation({
|
|
11712
|
+
kind,
|
|
11713
|
+
model: options.model,
|
|
11714
|
+
diagnosticModelUri: options.accountingModelUri,
|
|
11715
|
+
provider: raw.name,
|
|
11716
|
+
agentCall: options.accountingModelUri !== void 0
|
|
11717
|
+
});
|
|
11576
11718
|
if (handle && raw.reportsRequestLifecycle === true) handle.markDispatchObservable();
|
|
11577
11719
|
return handle;
|
|
11578
11720
|
}
|
|
@@ -11589,7 +11731,8 @@ function createScopedProvider(raw) {
|
|
|
11589
11731
|
handle.settle({
|
|
11590
11732
|
cost: response.cost,
|
|
11591
11733
|
provenance: response.costProvenance,
|
|
11592
|
-
usage: toAccountingUsage(response.usage)
|
|
11734
|
+
usage: toAccountingUsage(response.usage),
|
|
11735
|
+
timing: safeTiming(response)
|
|
11593
11736
|
});
|
|
11594
11737
|
recorder?.end({ response });
|
|
11595
11738
|
return response;
|
|
@@ -11644,7 +11787,8 @@ function createScopedProvider(raw) {
|
|
|
11644
11787
|
handle?.settle({
|
|
11645
11788
|
cost: result.value.cost,
|
|
11646
11789
|
provenance: result.value.costProvenance,
|
|
11647
|
-
usage: toAccountingUsage(result.value.usage)
|
|
11790
|
+
usage: toAccountingUsage(result.value.usage),
|
|
11791
|
+
timing: safeTiming(result.value)
|
|
11648
11792
|
});
|
|
11649
11793
|
settled = true;
|
|
11650
11794
|
recorder?.end({
|
|
@@ -12077,13 +12221,6 @@ function eventError(error) {
|
|
|
12077
12221
|
return { name: "Error", message: "Unknown thrown value" };
|
|
12078
12222
|
}
|
|
12079
12223
|
}
|
|
12080
|
-
function isToolFailure(error) {
|
|
12081
|
-
try {
|
|
12082
|
-
return error instanceof ToolFailure;
|
|
12083
|
-
} catch {
|
|
12084
|
-
return false;
|
|
12085
|
-
}
|
|
12086
|
-
}
|
|
12087
12224
|
function cancellation(phase, error, result) {
|
|
12088
12225
|
let reason;
|
|
12089
12226
|
try {
|
|
@@ -12099,7 +12236,7 @@ function cancellation(phase, error, result) {
|
|
|
12099
12236
|
}
|
|
12100
12237
|
function failed(phase, error, options = {}) {
|
|
12101
12238
|
let modelMessage;
|
|
12102
|
-
if (
|
|
12239
|
+
if (isToolFailureError(error)) {
|
|
12103
12240
|
try {
|
|
12104
12241
|
modelMessage = typeof error.modelMessage === "string" ? error.modelMessage : void 0;
|
|
12105
12242
|
} catch {
|
|
@@ -12224,8 +12361,7 @@ async function executeAcceptedTool(options) {
|
|
|
12224
12361
|
}
|
|
12225
12362
|
}
|
|
12226
12363
|
} catch (error) {
|
|
12227
|
-
|
|
12228
|
-
if (isAdmissionDeniedError(error)) throw error;
|
|
12364
|
+
rethrowUnrecoverable(error);
|
|
12229
12365
|
const abort = cancellationError(signal, error);
|
|
12230
12366
|
if (abort !== void 0) return cancellation("handler", abort);
|
|
12231
12367
|
return failed("handler", error, { attempts });
|
|
@@ -13787,6 +13923,7 @@ ${appendedSchemaText}`;
|
|
|
13787
13923
|
const turnStart = Date.now();
|
|
13788
13924
|
const chatOptions = {
|
|
13789
13925
|
model,
|
|
13926
|
+
accountingModelUri: effectiveModelUri,
|
|
13790
13927
|
temperature: options?.temperature ?? agent2._config.temperature,
|
|
13791
13928
|
tools: toolDefs.length > 0 ? toolDefs : void 0,
|
|
13792
13929
|
maxTokens: options?.maxTokens ?? agent2._config.maxTokens ?? 4096,
|
|
@@ -14490,7 +14627,8 @@ ${appendedSchemaText}`;
|
|
|
14490
14627
|
metadata: this.metadata
|
|
14491
14628
|
});
|
|
14492
14629
|
} catch (err) {
|
|
14493
|
-
|
|
14630
|
+
rethrowUnrecoverable(err);
|
|
14631
|
+
if (this.currentSignal?.aborted) throw err;
|
|
14494
14632
|
validateErr = err;
|
|
14495
14633
|
const reason = err instanceof Error ? err.message : String(err);
|
|
14496
14634
|
validateResult = { valid: false, reason: `Validator error: ${reason}` };
|
|
@@ -15081,15 +15219,13 @@ ${summaryResponse.content}`
|
|
|
15081
15219
|
reject(new QuorumNotMet(quorum, successCount, results));
|
|
15082
15220
|
}
|
|
15083
15221
|
}).catch((err) => {
|
|
15084
|
-
if (
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
}
|
|
15222
|
+
if (settled) return;
|
|
15223
|
+
if (isUnrecoverableError(err) || parentSignal2?.aborted) {
|
|
15224
|
+
settled = true;
|
|
15225
|
+
controller.abort();
|
|
15226
|
+
reject(err);
|
|
15090
15227
|
return;
|
|
15091
15228
|
}
|
|
15092
|
-
if (settled) return;
|
|
15093
15229
|
const isAbort = err instanceof DOMException && err.name === "AbortError";
|
|
15094
15230
|
if (isAbort) {
|
|
15095
15231
|
completedCount++;
|
|
@@ -15112,7 +15248,8 @@ ${summaryResponse.content}`
|
|
|
15112
15248
|
const parentSignal = this.currentSignal;
|
|
15113
15249
|
const promises = Array.from({ length: n }, (_, i) => {
|
|
15114
15250
|
const run = () => fn(i).then((value) => ({ ok: true, value })).catch((err) => {
|
|
15115
|
-
|
|
15251
|
+
rethrowUnrecoverable(err);
|
|
15252
|
+
if (parentSignal?.aborted) throw err;
|
|
15116
15253
|
return {
|
|
15117
15254
|
ok: false,
|
|
15118
15255
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -15236,6 +15373,7 @@ ${summaryResponse.content}`
|
|
|
15236
15373
|
async verify(fn, schema, options) {
|
|
15237
15374
|
const maxRetries = options?.retries ?? 3;
|
|
15238
15375
|
let lastRetry = void 0;
|
|
15376
|
+
const scopeSignal = this.currentSignal;
|
|
15239
15377
|
const emitVerifyOutcome = (passed, attempts, lastError) => {
|
|
15240
15378
|
this.emitEvent({
|
|
15241
15379
|
type: "verify",
|
|
@@ -15258,25 +15396,24 @@ ${summaryResponse.content}`
|
|
|
15258
15396
|
try {
|
|
15259
15397
|
validateResult = await options.validate(parsed, { metadata: this.metadata });
|
|
15260
15398
|
} catch (err) {
|
|
15261
|
-
|
|
15399
|
+
rethrowUnrecoverable(err);
|
|
15400
|
+
if (scopeSignal?.aborted) throw err;
|
|
15262
15401
|
const reason = err instanceof Error ? err.message : String(err);
|
|
15263
15402
|
validateResult = { valid: false, reason: `Validator error: ${reason}` };
|
|
15264
15403
|
}
|
|
15265
15404
|
if (!validateResult.valid) {
|
|
15405
|
+
scopeSignal?.throwIfAborted();
|
|
15266
15406
|
const errorMsg = validateResult.reason ?? "Validation failed";
|
|
15267
15407
|
lastRetry = { error: errorMsg, output: rawOutput, parsed };
|
|
15268
|
-
if (attempt === maxRetries)
|
|
15269
|
-
emitVerifyOutcome(false, attempt + 1, errorMsg);
|
|
15270
|
-
if (options?.fallback !== void 0) return options.fallback;
|
|
15271
|
-
throw new ValidationError(parsed, errorMsg, maxRetries);
|
|
15272
|
-
}
|
|
15408
|
+
if (attempt === maxRetries) throw new ValidationError(parsed, errorMsg, maxRetries);
|
|
15273
15409
|
continue;
|
|
15274
15410
|
}
|
|
15275
15411
|
}
|
|
15276
15412
|
emitVerifyOutcome(true, attempt + 1);
|
|
15277
15413
|
return parsed;
|
|
15278
15414
|
} catch (err) {
|
|
15279
|
-
|
|
15415
|
+
rethrowUnrecoverable(err);
|
|
15416
|
+
if (scopeSignal?.aborted) throw err;
|
|
15280
15417
|
if (err instanceof ValidationError) {
|
|
15281
15418
|
lastRetry = {
|
|
15282
15419
|
error: err.reason,
|
|
@@ -15343,7 +15480,8 @@ ${summaryResponse.content}`
|
|
|
15343
15480
|
const unpriced = this.budgetContext.unpriced;
|
|
15344
15481
|
return { value, budgetExceeded: exceeded, totalCost, unpriced };
|
|
15345
15482
|
} catch (err) {
|
|
15346
|
-
|
|
15483
|
+
rethrowUnrecoverable(err);
|
|
15484
|
+
if (parentSignal?.aborted) throw err;
|
|
15347
15485
|
if (this.budgetContext.exceeded) {
|
|
15348
15486
|
return {
|
|
15349
15487
|
value: null,
|
|
@@ -15352,14 +15490,6 @@ ${summaryResponse.content}`
|
|
|
15352
15490
|
unpriced: this.budgetContext.unpriced
|
|
15353
15491
|
};
|
|
15354
15492
|
}
|
|
15355
|
-
if (err instanceof DOMException && err.name === "AbortError" && controller) {
|
|
15356
|
-
return {
|
|
15357
|
-
value: null,
|
|
15358
|
-
budgetExceeded: true,
|
|
15359
|
-
totalCost: this.budgetContext.totalCost,
|
|
15360
|
-
unpriced: this.budgetContext.unpriced
|
|
15361
|
-
};
|
|
15362
|
-
}
|
|
15363
15493
|
throw err;
|
|
15364
15494
|
} finally {
|
|
15365
15495
|
if (parentBudget) {
|
|
@@ -15475,7 +15605,8 @@ ${summaryResponse.content}`
|
|
|
15475
15605
|
return;
|
|
15476
15606
|
}
|
|
15477
15607
|
} catch (err) {
|
|
15478
|
-
|
|
15608
|
+
rethrowUnrecoverable(err);
|
|
15609
|
+
if (parentSignal?.aborted) throw err;
|
|
15479
15610
|
remaining--;
|
|
15480
15611
|
lastError = err instanceof Error ? err : new Error(`Validator error: ${String(err)}`);
|
|
15481
15612
|
if (remaining === 0 && !settled) {
|
|
@@ -15495,7 +15626,7 @@ ${summaryResponse.content}`
|
|
|
15495
15626
|
controller.abort();
|
|
15496
15627
|
resolve2(value);
|
|
15497
15628
|
}).catch((err) => {
|
|
15498
|
-
if (
|
|
15629
|
+
if (isUnrecoverableError(err)) {
|
|
15499
15630
|
if (!settled) {
|
|
15500
15631
|
settled = true;
|
|
15501
15632
|
controller.abort();
|
|
@@ -15504,6 +15635,12 @@ ${summaryResponse.content}`
|
|
|
15504
15635
|
throw err;
|
|
15505
15636
|
}
|
|
15506
15637
|
if (settled) return;
|
|
15638
|
+
if (parentSignal?.aborted) {
|
|
15639
|
+
settled = true;
|
|
15640
|
+
controller.abort();
|
|
15641
|
+
reject(err);
|
|
15642
|
+
return;
|
|
15643
|
+
}
|
|
15507
15644
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
15508
15645
|
remaining--;
|
|
15509
15646
|
if (remaining === 0 && !settled) {
|
|
@@ -15562,7 +15699,7 @@ ${summaryResponse.content}`
|
|
|
15562
15699
|
results[idx] = { ok: true, value };
|
|
15563
15700
|
successCount++;
|
|
15564
15701
|
} catch (err) {
|
|
15565
|
-
if (
|
|
15702
|
+
if (isUnrecoverableError(err)) {
|
|
15566
15703
|
settled = true;
|
|
15567
15704
|
controller?.abort();
|
|
15568
15705
|
reject(err);
|
|
@@ -15571,6 +15708,12 @@ ${summaryResponse.content}`
|
|
|
15571
15708
|
if (settled) {
|
|
15572
15709
|
return;
|
|
15573
15710
|
}
|
|
15711
|
+
if (parentSignal?.aborted) {
|
|
15712
|
+
settled = true;
|
|
15713
|
+
controller?.abort();
|
|
15714
|
+
reject(err);
|
|
15715
|
+
return;
|
|
15716
|
+
}
|
|
15574
15717
|
if (err instanceof DOMException && err.name === "AbortError" && controller?.signal.aborted) {
|
|
15575
15718
|
completedCount++;
|
|
15576
15719
|
return;
|
|
@@ -20541,8 +20684,9 @@ var AxlRuntime = class extends EventEmitter2 {
|
|
|
20541
20684
|
* new paid operations once known spend reaches the limit. Already-dispatched
|
|
20542
20685
|
* work still settles and is still counted.
|
|
20543
20686
|
*
|
|
20544
|
-
*
|
|
20545
|
-
*
|
|
20687
|
+
* Model metadata and timing share the settlement scope with accounting, so
|
|
20688
|
+
* they cross runtimes and compatible ESM/CJS copies. Workflow names and
|
|
20689
|
+
* captured traces still come from this runtime's events.
|
|
20546
20690
|
*/
|
|
20547
20691
|
async trackOutcome(fn, options) {
|
|
20548
20692
|
const parentScope = costScopeStorage.getStore();
|
|
@@ -20551,49 +20695,11 @@ var AxlRuntime = class extends EventEmitter2 {
|
|
|
20551
20695
|
trackedIds: /* @__PURE__ */ new Set(),
|
|
20552
20696
|
parent: parentScope
|
|
20553
20697
|
};
|
|
20554
|
-
const modelCalls = /* @__PURE__ */ new Map();
|
|
20555
|
-
const modelTiming = /* @__PURE__ */ new Map();
|
|
20556
|
-
const captureTimingSamples = options?.captureTimingSamples === true;
|
|
20557
20698
|
const workflowCalls = /* @__PURE__ */ new Map();
|
|
20558
|
-
const tokens = { input: 0, output: 0, reasoning: 0 };
|
|
20559
|
-
let agentCalls = 0;
|
|
20560
20699
|
const capturedTraces = options?.captureTraces ? [] : void 0;
|
|
20561
20700
|
const listener = (event) => {
|
|
20562
20701
|
if (!scope.trackedIds.has(event.executionId)) return;
|
|
20563
20702
|
scope.totalCost += eventCostContribution(event);
|
|
20564
|
-
if (event.type === "agent_call_end") {
|
|
20565
|
-
if (event.model) modelCalls.set(event.model, (modelCalls.get(event.model) ?? 0) + 1);
|
|
20566
|
-
agentCalls++;
|
|
20567
|
-
if (event.tokens) {
|
|
20568
|
-
tokens.input += event.tokens.input ?? 0;
|
|
20569
|
-
tokens.output += event.tokens.output ?? 0;
|
|
20570
|
-
tokens.reasoning += event.tokens.reasoning ?? 0;
|
|
20571
|
-
}
|
|
20572
|
-
const failed2 = event.data?.error != null;
|
|
20573
|
-
if (event.model && event.timing && !failed2) {
|
|
20574
|
-
const t = event.timing;
|
|
20575
|
-
let bucket = modelTiming.get(event.model);
|
|
20576
|
-
if (!bucket) {
|
|
20577
|
-
bucket = {
|
|
20578
|
-
calls: 0,
|
|
20579
|
-
queuedMs: 0,
|
|
20580
|
-
retryMs: 0,
|
|
20581
|
-
wireMs: 0,
|
|
20582
|
-
...captureTimingSamples ? { samples: [] } : {}
|
|
20583
|
-
};
|
|
20584
|
-
modelTiming.set(event.model, bucket);
|
|
20585
|
-
}
|
|
20586
|
-
bucket.calls++;
|
|
20587
|
-
bucket.samples?.push(t);
|
|
20588
|
-
bucket.queuedMs += t.queuedMs;
|
|
20589
|
-
bucket.retryMs += t.retryMs;
|
|
20590
|
-
bucket.wireMs += t.wireMs;
|
|
20591
|
-
if (t.firstTokenMs != null) {
|
|
20592
|
-
bucket.firstTokenMs = (bucket.firstTokenMs ?? 0) + t.firstTokenMs;
|
|
20593
|
-
bucket.firstTokenCalls = (bucket.firstTokenCalls ?? 0) + 1;
|
|
20594
|
-
}
|
|
20595
|
-
}
|
|
20596
|
-
}
|
|
20597
20703
|
if (event.type === "workflow_start" && event.workflow) {
|
|
20598
20704
|
workflowCalls.set(event.workflow, (workflowCalls.get(event.workflow) ?? 0) + 1);
|
|
20599
20705
|
}
|
|
@@ -20619,9 +20725,14 @@ var AxlRuntime = class extends EventEmitter2 {
|
|
|
20619
20725
|
this.on("trace", listener);
|
|
20620
20726
|
let outcome;
|
|
20621
20727
|
let accounting;
|
|
20728
|
+
let diagnostics;
|
|
20622
20729
|
try {
|
|
20623
|
-
({ outcome, accounting } = await runInAccountingScope(
|
|
20624
|
-
{
|
|
20730
|
+
({ outcome, accounting, diagnostics } = await runInAccountingScope(
|
|
20731
|
+
{
|
|
20732
|
+
purpose: options?.purpose,
|
|
20733
|
+
admission: options?.admission,
|
|
20734
|
+
captureTimingSamples: options?.captureTimingSamples
|
|
20735
|
+
},
|
|
20625
20736
|
() => (
|
|
20626
20737
|
// Capture wraps the cost scope rather than the other way round so a
|
|
20627
20738
|
// record can never be written for an operation the accounting scope
|
|
@@ -20645,13 +20756,13 @@ var AxlRuntime = class extends EventEmitter2 {
|
|
|
20645
20756
|
return {
|
|
20646
20757
|
...outcome,
|
|
20647
20758
|
accounting,
|
|
20648
|
-
...modelTiming.
|
|
20759
|
+
...Object.keys(diagnostics.modelTiming).length > 0 ? { modelTiming: diagnostics.modelTiming } : {},
|
|
20649
20760
|
...capturedTraces ? { traces: capturedTraces } : {},
|
|
20650
20761
|
metadata: {
|
|
20651
|
-
models:
|
|
20652
|
-
modelCallCounts:
|
|
20653
|
-
tokens,
|
|
20654
|
-
agentCalls,
|
|
20762
|
+
models: Object.keys(diagnostics.modelCallCounts),
|
|
20763
|
+
modelCallCounts: Object.keys(diagnostics.modelCallCounts).length > 0 ? diagnostics.modelCallCounts : void 0,
|
|
20764
|
+
tokens: diagnostics.tokens,
|
|
20765
|
+
agentCalls: diagnostics.agentCalls,
|
|
20655
20766
|
workflows: [...workflowCalls.keys()],
|
|
20656
20767
|
workflowCallCounts: workflowCalls.size > 0 ? Object.fromEntries(workflowCalls) : void 0
|
|
20657
20768
|
}
|