@axlsdk/axl 0.24.0 → 0.24.1

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.d.cts CHANGED
@@ -158,8 +158,9 @@ declare function summarizeModelInput(input: ModelInput): string;
158
158
  *
159
159
  * - `'complete'` — every operation in the scope reached a terminal state with a
160
160
  * usable charge (including known $0).
161
- * - `'incomplete'` — at least one operation settled without a usable charge;
162
- * `knownCost` is a lower bound and `reasons` says why.
161
+ * - `'incomplete'` — at least one operation lacked a usable charge, or the
162
+ * scope detected work from an incompatible loaded copy; `knownCost` is a
163
+ * lower bound and `reasons` says why.
163
164
  * - `'unverified'` — reserved for READERS of artifacts that carry no
164
165
  * accounting at all (legacy eval results). A live scope never produces it.
165
166
  */
@@ -185,9 +186,8 @@ type AccountingReason =
185
186
  /** An external operation finished without calling `report.setCost()`. */
186
187
  | 'external_unreported'
187
188
  /**
188
- * A consumer ran work with no accounting scope available (e.g. `@axlsdk/eval`
189
- * driving a runtime that predates `trackOutcome`). Core defines the name only
190
- * — no core producer emits it.
189
+ * A consumer ran work with no accounting scope available, or another loaded
190
+ * copy attempted work under a scope whose accounting protocol it cannot join.
191
191
  */
192
192
  | 'uninstrumented';
193
193
  /** The instrumented boundaries that can open an operation. */
@@ -216,7 +216,7 @@ type Accounting = {
216
216
  /** Sum of settled, usable, disjoint charges. Never includes caller aggregates. */
217
217
  knownCost: number;
218
218
  completeness: AccountingCompleteness;
219
- /** Reason → count of operations carrying it. Empty object when complete. */
219
+ /** Reason → count of unresolved operations or coverage failures. */
220
220
  reasons: Partial<Record<AccountingReason, number>>;
221
221
  usage: AccountingUsage;
222
222
  operations: {
@@ -229,7 +229,7 @@ type Accounting = {
229
229
  total: number;
230
230
  /** Terminal with a usable cost, including a known $0. */
231
231
  settled: number;
232
- /** Terminal or abandoned without a usable cost. Drives `completeness`. */
232
+ /** Terminal or abandoned without a usable cost. Coverage failures can also make `incomplete`. */
233
233
  unknown: number;
234
234
  /** Refused admission — never dispatched, contributes nothing anywhere. */
235
235
  denied: number;
package/dist/index.d.ts CHANGED
@@ -158,8 +158,9 @@ declare function summarizeModelInput(input: ModelInput): string;
158
158
  *
159
159
  * - `'complete'` — every operation in the scope reached a terminal state with a
160
160
  * usable charge (including known $0).
161
- * - `'incomplete'` — at least one operation settled without a usable charge;
162
- * `knownCost` is a lower bound and `reasons` says why.
161
+ * - `'incomplete'` — at least one operation lacked a usable charge, or the
162
+ * scope detected work from an incompatible loaded copy; `knownCost` is a
163
+ * lower bound and `reasons` says why.
163
164
  * - `'unverified'` — reserved for READERS of artifacts that carry no
164
165
  * accounting at all (legacy eval results). A live scope never produces it.
165
166
  */
@@ -185,9 +186,8 @@ type AccountingReason =
185
186
  /** An external operation finished without calling `report.setCost()`. */
186
187
  | 'external_unreported'
187
188
  /**
188
- * A consumer ran work with no accounting scope available (e.g. `@axlsdk/eval`
189
- * driving a runtime that predates `trackOutcome`). Core defines the name only
190
- * — no core producer emits it.
189
+ * A consumer ran work with no accounting scope available, or another loaded
190
+ * copy attempted work under a scope whose accounting protocol it cannot join.
191
191
  */
192
192
  | 'uninstrumented';
193
193
  /** The instrumented boundaries that can open an operation. */
@@ -216,7 +216,7 @@ type Accounting = {
216
216
  /** Sum of settled, usable, disjoint charges. Never includes caller aggregates. */
217
217
  knownCost: number;
218
218
  completeness: AccountingCompleteness;
219
- /** Reason → count of operations carrying it. Empty object when complete. */
219
+ /** Reason → count of unresolved operations or coverage failures. */
220
220
  reasons: Partial<Record<AccountingReason, number>>;
221
221
  usage: AccountingUsage;
222
222
  operations: {
@@ -229,7 +229,7 @@ type Accounting = {
229
229
  total: number;
230
230
  /** Terminal with a usable cost, including a known $0. */
231
231
  settled: number;
232
- /** Terminal or abandoned without a usable cost. Drives `completeness`. */
232
+ /** Terminal or abandoned without a usable cost. Coverage failures can also make `incomplete`. */
233
233
  unknown: number;
234
234
  /** Refused admission — never dispatched, contributes nothing anywhere. */
235
235
  denied: number;
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { createRequire as __axlCreateRequire } from 'node:module';
2
2
  const require = __axlCreateRequire(import.meta.url);
3
+ const __AXL_BUILD_PATH__ = import.meta.url;
3
4
  import {
4
5
  __require
5
- } from "./chunk-O7Y6WXE2.js";
6
+ } from "./chunk-PJROX3XU.js";
6
7
 
7
8
  // src/tool.ts
8
9
  import { ZodError } from "zod";
@@ -277,8 +278,62 @@ var ValidationError = class extends AxlError {
277
278
  }
278
279
  };
279
280
 
280
- // src/accounting.ts
281
+ // src/shared-context.ts
281
282
  import { AsyncLocalStorage } from "async_hooks";
283
+ import { fileURLToPath } from "url";
284
+ var PROTOCOL = 1;
285
+ var CONTEXT_KEY = /* @__PURE__ */ Symbol.for(`axl.accounting.context.v${PROTOCOL}`);
286
+ var GUARD_KEY = /* @__PURE__ */ Symbol.for("axl.accounting.scopeGuard");
287
+ function createContext() {
288
+ let operationCounter = 0;
289
+ return {
290
+ protocol: PROTOCOL,
291
+ id: /* @__PURE__ */ Symbol("axl.accounting.context.instance"),
292
+ accounting: new AsyncLocalStorage(),
293
+ dispatch: new AsyncLocalStorage(),
294
+ capture: new AsyncLocalStorage(),
295
+ correlation: new AsyncLocalStorage(),
296
+ turn: new AsyncLocalStorage(),
297
+ nextOperationId: () => `op_${++operationCounter}`
298
+ };
299
+ }
300
+ function isStorage(value) {
301
+ return typeof value === "object" && value !== null && typeof value.getStore === "function" && typeof value.run === "function";
302
+ }
303
+ function isCompatible(value) {
304
+ if (typeof value !== "object" || value === null) return false;
305
+ const candidate = value;
306
+ return candidate.protocol === PROTOCOL && typeof candidate.id === "symbol" && isStorage(candidate.accounting) && isStorage(candidate.dispatch) && isStorage(candidate.capture) && isStorage(candidate.correlation) && isStorage(candidate.turn) && typeof candidate.nextOperationId === "function";
307
+ }
308
+ var registry = globalThis;
309
+ var installed = registry[CONTEXT_KEY];
310
+ var sharedContext = installed === void 0 ? registry[CONTEXT_KEY] = createContext() : isCompatible(installed) ? installed : createContext();
311
+ var installedGuard = registry[GUARD_KEY];
312
+ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null && isStorage(installedGuard.storage) && installedGuard.warned instanceof WeakMap ? installedGuard : registry[GUARD_KEY] = {
313
+ storage: new AsyncLocalStorage(),
314
+ warned: /* @__PURE__ */ new WeakMap()
315
+ };
316
+ var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
317
+ var thisCopy = {
318
+ path: buildPath.startsWith("file:") ? fileURLToPath(buildPath) : buildPath,
319
+ version: true ? "0.24.1" : "unknown"
320
+ };
321
+ function warnCrossCopy(other, joined) {
322
+ if (other === thisCopy) return;
323
+ if (sharedGuard.warned.get(other)?.has(thisCopy)) return;
324
+ const fromThis = sharedGuard.warned.get(thisCopy) ?? /* @__PURE__ */ new WeakSet();
325
+ if (fromThis.has(other)) return;
326
+ fromThis.add(other);
327
+ sharedGuard.warned.set(thisCopy, fromThis);
328
+ try {
329
+ console.warn(
330
+ `[axl] Cross-copy accounting: ${other.path} (v${other.version}) and ${thisCopy.path} (v${thisCopy.version}). ` + (joined ? "Shared accounting, admission, and request capture context joined." : "Accounting protocols could not join; paid work is refused and the active scope is incomplete.")
331
+ );
332
+ } catch {
333
+ }
334
+ }
335
+
336
+ // src/accounting.ts
282
337
  var RECORD_SPEND = /* @__PURE__ */ Symbol.for("axl.accounting.recordSpend");
283
338
  var AdmissionController = class {
284
339
  /** The configured USD threshold. Admission closes at `knownSpend >= limit`. */
@@ -340,10 +395,8 @@ function emptyUsage() {
340
395
  function isUsableCost(cost) {
341
396
  return typeof cost === "number" && Number.isFinite(cost) && cost >= 0;
342
397
  }
343
- var operationCounter = 0;
344
398
  function nextOperationId() {
345
- operationCounter += 1;
346
- return `op_${operationCounter}`;
399
+ return sharedContext.nextOperationId();
347
400
  }
348
401
  var AccountingScope = class {
349
402
  parent;
@@ -381,6 +434,11 @@ var AccountingScope = class {
381
434
  recordDenied() {
382
435
  this.denied += 1;
383
436
  }
437
+ /** A foreign protocol attempted work we cannot measure. Mark every live ancestor. */
438
+ markUninstrumented() {
439
+ if (this.finalized || this.reasons.has("uninstrumented")) return;
440
+ this.reasons.set("uninstrumented", 1);
441
+ }
384
442
  /** An already-open operation refused at the dispatch check: retract it. */
385
443
  recordRetracted(op) {
386
444
  this.seen.add(op.id);
@@ -433,7 +491,7 @@ var AccountingScope = class {
433
491
  version: 1,
434
492
  currency: "USD",
435
493
  knownCost: this.knownCost,
436
- completeness: this.unknown > 0 ? "incomplete" : "complete",
494
+ completeness: this.reasons.size > 0 ? "incomplete" : "complete",
437
495
  reasons: Object.fromEntries(this.reasons),
438
496
  usage: { ...this.usage },
439
497
  operations: {
@@ -448,8 +506,8 @@ var AccountingScope = class {
448
506
  };
449
507
  }
450
508
  };
451
- var accountingStorage = new AsyncLocalStorage();
452
- var dispatchAdmissionStorage = new AsyncLocalStorage();
509
+ var accountingStorage = sharedContext.accounting;
510
+ var dispatchAdmissionStorage = sharedContext.dispatch;
453
511
  function currentDispatchAdmission() {
454
512
  return dispatchAdmissionStorage.getStore();
455
513
  }
@@ -510,6 +568,17 @@ function admissionDenied(controller, descriptor) {
510
568
  });
511
569
  }
512
570
  function openOperation(descriptor) {
571
+ const inheritedGuard = sharedGuard.storage.getStore();
572
+ const guard = inheritedGuard && (inheritedGuard.isActive?.() ?? true) ? inheritedGuard : void 0;
573
+ if (guard && guard.contextId !== sharedContext.id) {
574
+ guard.markUninstrumented();
575
+ warnCrossCopy(guard.owner, false);
576
+ throw new AxlError(
577
+ "INCOMPATIBLE_ACCOUNTING_SCOPE",
578
+ "The active @axlsdk/axl accounting scope uses an incompatible loaded copy; paid work was refused before dispatch."
579
+ );
580
+ }
581
+ if (guard) warnCrossCopy(guard.owner, true);
513
582
  const scope = accountingStorage.getStore();
514
583
  if (!scope || scope.isFinalized) return void 0;
515
584
  const denier = denyingController(scope);
@@ -599,8 +668,45 @@ async function runInAccountingScope(options, fn) {
599
668
  purpose: options.purpose ?? parent?.purpose ?? "generation",
600
669
  admission: options.admission
601
670
  });
671
+ const inheritedGuard = sharedGuard.storage.getStore();
672
+ const enclosingGuard = inheritedGuard && (inheritedGuard.isActive?.() ?? true) ? inheritedGuard : void 0;
673
+ if (enclosingGuard)
674
+ warnCrossCopy(enclosingGuard.owner, enclosingGuard.contextId === sharedContext.id);
675
+ if (enclosingGuard && enclosingGuard.contextId !== sharedContext.id) {
676
+ enclosingGuard.markUninstrumented();
677
+ scope.markUninstrumented();
678
+ scope.finalize();
679
+ return {
680
+ outcome: {
681
+ status: "rejected",
682
+ error: new AxlError(
683
+ "INCOMPATIBLE_ACCOUNTING_SCOPE",
684
+ "The active @axlsdk/axl accounting scope uses an incompatible loaded copy; paid work was refused before dispatch."
685
+ )
686
+ },
687
+ accounting: scope.toAccounting()
688
+ };
689
+ }
690
+ const markUninstrumented = () => {
691
+ let current = scope;
692
+ while (current) {
693
+ if (!current.isFinalized) current.markUninstrumented();
694
+ current = current.parent;
695
+ }
696
+ };
697
+ const isActive = () => {
698
+ let current = scope;
699
+ while (current) {
700
+ if (!current.isFinalized) return true;
701
+ current = current.parent;
702
+ }
703
+ return false;
704
+ };
602
705
  try {
603
- const value = await accountingStorage.run(scope, fn);
706
+ const value = await sharedGuard.storage.run(
707
+ { contextId: sharedContext.id, owner: thisCopy, markUninstrumented, isActive },
708
+ () => accountingStorage.run(scope, fn)
709
+ );
604
710
  scope.finalize();
605
711
  return { outcome: { status: "fulfilled", value }, accounting: scope.toAccounting() };
606
712
  } catch (error) {
@@ -1034,7 +1140,7 @@ function tool(config) {
1034
1140
  } catch (err) {
1035
1141
  if (options?.signal?.aborted) options.signal.throwIfAborted();
1036
1142
  if (isAbortError(err)) throw err;
1037
- if (err instanceof AdmissionDeniedError) throw err;
1143
+ if (isAdmissionDeniedError(err)) throw err;
1038
1144
  rethrowEventStreamOverflow(err);
1039
1145
  lastError = err instanceof Error ? err : new Error(String(err));
1040
1146
  if (attempt === maxAttempts) break;
@@ -8788,7 +8894,7 @@ var TranscriptionProviderRegistry = class {
8788
8894
  };
8789
8895
 
8790
8896
  // src/context.ts
8791
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
8897
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
8792
8898
  import { randomUUID } from "crypto";
8793
8899
  import { z, ZodError as ZodError2 } from "zod";
8794
8900
 
@@ -10973,7 +11079,6 @@ function warnDiagnosticOnce(key, message, silent, docs = DOCS_URL) {
10973
11079
  var warnSchemaDiagnosticOnce = warnDiagnosticOnce;
10974
11080
 
10975
11081
  // src/diagnostics/capture.ts
10976
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
10977
11082
  var DEFAULT_MAX_RECORD_BYTES = 256 * 1024;
10978
11083
  var DEFAULT_MAX_RUN_BYTES = 16 * 1024 * 1024;
10979
11084
  var DEFAULT_MAX_QUEUE_BYTES = 1024 * 1024;
@@ -11234,8 +11339,8 @@ function positive(value, fallback) {
11234
11339
  function describe(error) {
11235
11340
  return error instanceof Error ? error.message : String(error);
11236
11341
  }
11237
- var channelStorage = new AsyncLocalStorage2();
11238
- var correlationStorage = new AsyncLocalStorage2();
11342
+ var channelStorage = sharedContext.capture;
11343
+ var correlationStorage = sharedContext.correlation;
11239
11344
  function currentCaptureChannel() {
11240
11345
  return channelStorage.getStore();
11241
11346
  }
@@ -11251,7 +11356,7 @@ function runWithCaptureCorrelation(correlation, fn) {
11251
11356
  const merged = { ...correlationStorage.getStore(), ...correlation };
11252
11357
  return correlationStorage.run(merged, fn);
11253
11358
  }
11254
- var turnStorage = new AsyncLocalStorage2();
11359
+ var turnStorage = sharedContext.turn;
11255
11360
  function currentCaptureTurn() {
11256
11361
  return turnStorage.getStore()?.current;
11257
11362
  }
@@ -12120,7 +12225,7 @@ async function executeAcceptedTool(options) {
12120
12225
  }
12121
12226
  } catch (error) {
12122
12227
  rethrowEventStreamOverflow(error);
12123
- if (error instanceof AdmissionDeniedError) throw error;
12228
+ if (isAdmissionDeniedError(error)) throw error;
12124
12229
  const abort = cancellationError(signal, error);
12125
12230
  if (abort !== void 0) return cancellation("handler", abort);
12126
12231
  return failed("handler", error, { attempts });
@@ -12293,9 +12398,9 @@ function recordToolSpanOutcome(span, outcome) {
12293
12398
  }
12294
12399
 
12295
12400
  // src/context.ts
12296
- var signalStorage = new AsyncLocalStorage3();
12297
- var hardSignalStorage = new AsyncLocalStorage3();
12298
- var timeoutTrackerStorage = new AsyncLocalStorage3();
12401
+ var signalStorage = new AsyncLocalStorage2();
12402
+ var hardSignalStorage = new AsyncLocalStorage2();
12403
+ var timeoutTrackerStorage = new AsyncLocalStorage2();
12299
12404
  var MAX_TIMER_DELAY_MS = 2147483647;
12300
12405
  function composeAbortSignals(...signals) {
12301
12406
  const active = signals.filter((signal) => signal !== void 0);
@@ -12400,7 +12505,7 @@ function parseHumanDecision(value) {
12400
12505
  }
12401
12506
  return invalid3();
12402
12507
  }
12403
- var askStorage = new AsyncLocalStorage3();
12508
+ var askStorage = new AsyncLocalStorage2();
12404
12509
  var inlineSchemaCache = /* @__PURE__ */ new WeakMap();
12405
12510
  function zodToJsonSchema(schema) {
12406
12511
  const cached = inlineSchemaCache.get(schema);
@@ -16235,7 +16340,7 @@ ${summaryResponse.content}`
16235
16340
  try {
16236
16341
  result = await (transcriptionOperation ? transcriptionOperation.run(() => resolved.provider.transcribe(providerRequest)) : resolved.provider.transcribe(providerRequest));
16237
16342
  } catch (error) {
16238
- if (error instanceof AdmissionDeniedError) {
16343
+ if (isAdmissionDeniedError(error)) {
16239
16344
  transcriptionOperation?.settleFailure();
16240
16345
  throw error;
16241
16346
  }
@@ -16499,13 +16604,13 @@ function agent(config) {
16499
16604
  _config: config,
16500
16605
  _name: defaultName,
16501
16606
  async ask(prompt, options) {
16502
- const registry = new ProviderRegistry();
16607
+ const registry2 = new ProviderRegistry();
16503
16608
  const transcriptionRegistry = new TranscriptionProviderRegistry();
16504
16609
  const ctx = new WorkflowContext({
16505
16610
  input: prompt,
16506
16611
  executionId: randomUUID2(),
16507
16612
  config: {},
16508
- providerRegistry: registry,
16613
+ providerRegistry: registry2,
16509
16614
  transcriptionProviderRegistry: transcriptionRegistry
16510
16615
  });
16511
16616
  return ctx.ask(agentInstance, prompt, options);
@@ -16529,7 +16634,7 @@ function workflow(config) {
16529
16634
  // src/runtime.ts
16530
16635
  import { EventEmitter as EventEmitter2 } from "events";
16531
16636
  import { randomUUID as randomUUID4 } from "crypto";
16532
- import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
16637
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
16533
16638
  import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
16534
16639
  import { dirname } from "path";
16535
16640
 
@@ -18491,7 +18596,7 @@ async function createSpanManager(config) {
18491
18596
  if (!config?.enabled) {
18492
18597
  return new NoopSpanManager();
18493
18598
  }
18494
- const { OTelSpanManager } = await import("./span-manager-WZHJOY7N.js");
18599
+ const { OTelSpanManager } = await import("./span-manager-L4H6ZCRQ.js");
18495
18600
  return OTelSpanManager.create(config);
18496
18601
  }
18497
18602
 
@@ -18718,7 +18823,7 @@ function assertNoRemovedObservationCallbacks(options) {
18718
18823
  `runtime.createContext() no longer accepts ${removed.join(", ")}. Observe ctx.events or use runtime.stream() instead. See docs/migration/stream-first-observation.md.`
18719
18824
  );
18720
18825
  }
18721
- var costScopeStorage = new AsyncLocalStorage4();
18826
+ var costScopeStorage = new AsyncLocalStorage3();
18722
18827
  function forwardAbortSignal(external, internal) {
18723
18828
  if (!external) return () => {
18724
18829
  };