@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/README.md CHANGED
@@ -597,6 +597,11 @@ startup pass plus a periodic sweep. See
597
597
  [observability.md](../../docs/observability.md#captured-requests-opt-in) and
598
598
  [integration.md](../../docs/integration.md#diagnostic-artifact-storage).
599
599
 
600
+ Compatible loaded ESM/CJS copies share accounting, admission, and capture in
601
+ one JavaScript realm. Cross-copy work emits one warning identifying both copies;
602
+ see [accounting completeness](../../docs/observability.md#completeness-and-reasons)
603
+ for protocol compatibility and upgrade guidance.
604
+
600
605
  **Embedder cost attribution.** `OpenAIEmbedder` reports `{ tokens, cost, model }` on every embed call — computed from the response's `prompt_tokens` and a pricing table (`text-embedding-3-small` $0.02/1M, `-large` $0.13/1M, `ada-002` $0.10/1M). The cost flows through `runtime.trackExecution()` the same way agent-call cost does, counts against `ctx.budget()`, and shows up in Studio's Cost Dashboard under "Memory (Embedder)". See [observability.md](../../docs/observability.md#event-types) for the trace-event shape.
601
606
 
602
607
  **Custom `Embedder` implementations** (breaking change in 0.15.0 — `embed()` previously returned `Promise<number[][]>`):
@@ -1,5 +1,6 @@
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
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
5
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
6
  }) : x)(function(x) {
@@ -80,4 +81,4 @@ export {
80
81
  __require,
81
82
  OTelSpanManager
82
83
  };
83
- //# sourceMappingURL=chunk-O7Y6WXE2.js.map
84
+ //# sourceMappingURL=chunk-PJROX3XU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/telemetry/span-manager.ts"],"sourcesContent":["import type { SpanHandle, SpanManager, TelemetryConfig } from './types.js';\n\n/** Minimal interface for an OTel span. */\ninterface OTelSpan {\n setAttribute(key: string, value: string | number | boolean): void;\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): void;\n setStatus(status: { code: unknown; message?: string }): void;\n end(): void;\n}\n\n/** Minimal interface for an OTel tracer. */\ninterface OTelTracer {\n startActiveSpan<T>(\n name: string,\n options: { attributes: Record<string, string | number | boolean> },\n fn: (span: OTelSpan) => Promise<T>,\n ): Promise<T>;\n}\n\n/** Minimal interface for an OTel tracer provider. */\ninterface OTelTracerProvider {\n getTracer(name: string): OTelTracer;\n shutdown?(): Promise<void>;\n}\n\n/** Minimal interface for the @opentelemetry/api module. */\ninterface OTelApi {\n SpanStatusCode: { UNSET: unknown; OK: unknown; ERROR: unknown };\n trace: {\n getTracerProvider(): OTelTracerProvider;\n getActiveSpan?(): OTelSpan | undefined;\n };\n}\n\n/**\n * OpenTelemetry-backed SpanManager.\n * Dynamically imports @opentelemetry/api to avoid hard dependency.\n */\nexport class OTelSpanManager implements SpanManager {\n private tracer: OTelTracer;\n private otelApi: OTelApi;\n private tracerProvider: OTelTracerProvider;\n\n private constructor(otelApi: OTelApi, tracer: OTelTracer, tracerProvider: OTelTracerProvider) {\n this.otelApi = otelApi;\n this.tracer = tracer;\n this.tracerProvider = tracerProvider;\n }\n\n static async create(config: TelemetryConfig): Promise<OTelSpanManager> {\n let otelApi: OTelApi;\n try {\n otelApi = (await import('@opentelemetry/api')) as unknown as OTelApi;\n } catch {\n throw new Error(\n '@opentelemetry/api is required for telemetry. Install it with: npm install @opentelemetry/api',\n );\n }\n\n const tracerProvider =\n (config.tracerProvider as OTelTracerProvider | undefined) ??\n otelApi.trace.getTracerProvider();\n const serviceName = config.serviceName ?? 'axl';\n const tracer = tracerProvider.getTracer(serviceName);\n\n return new OTelSpanManager(otelApi, tracer, tracerProvider);\n }\n\n async withSpanAsync<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: (span: SpanHandle) => Promise<T>,\n ): Promise<T> {\n const otelApi = this.otelApi;\n\n return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan: OTelSpan) => {\n let statusWasSet = false;\n const handle: SpanHandle = {\n setAttribute(key: string, value: string | number | boolean) {\n otelSpan.setAttribute(key, value);\n },\n addEvent(eventName: string, attrs?: Record<string, string | number | boolean>) {\n otelSpan.addEvent(eventName, attrs);\n },\n setStatus(code: 'unset' | 'ok' | 'error', message?: string) {\n statusWasSet = true;\n const statusCode =\n code === 'ok'\n ? otelApi.SpanStatusCode.OK\n : code === 'error'\n ? otelApi.SpanStatusCode.ERROR\n : otelApi.SpanStatusCode.UNSET;\n otelSpan.setStatus({ code: statusCode, message });\n },\n end() {\n otelSpan.end();\n },\n };\n\n try {\n const result = await fn(handle);\n if (!statusWasSet) handle.setStatus('ok');\n return result;\n } catch (err) {\n // Error text can contain provider, prompt, or sensitive tool data.\n // Keep exported status structural; host diagnostics remain in Axl's\n // own error and redacted event channels.\n handle.setStatus('error');\n throw err;\n } finally {\n handle.end();\n }\n });\n }\n\n addEventToActiveSpan(name: string, attributes?: Record<string, string | number | boolean>): void {\n const activeSpan = this.otelApi.trace.getActiveSpan?.();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.tracerProvider && typeof this.tracerProvider.shutdown === 'function') {\n await this.tracerProvider.shutdown();\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAsCO,IAAM,kBAAN,MAAM,iBAAuC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAkB,QAAoB,gBAAoC;AAC5F,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,aAAa,OAAO,QAAmD;AACrE,QAAI;AACJ,QAAI;AACF,gBAAW,MAAM,OAAO,oBAAoB;AAAA,IAC9C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBACH,OAAO,kBACR,QAAQ,MAAM,kBAAkB;AAClC,UAAM,cAAc,OAAO,eAAe;AAC1C,UAAM,SAAS,eAAe,UAAU,WAAW;AAEnD,WAAO,IAAI,iBAAgB,SAAS,QAAQ,cAAc;AAAA,EAC5D;AAAA,EAEA,MAAM,cACJ,MACA,YACA,IACY;AACZ,UAAM,UAAU,KAAK;AAErB,WAAO,KAAK,OAAO,gBAAgB,MAAM,EAAE,WAAW,GAAG,OAAO,aAAuB;AACrF,UAAI,eAAe;AACnB,YAAM,SAAqB;AAAA,QACzB,aAAa,KAAa,OAAkC;AAC1D,mBAAS,aAAa,KAAK,KAAK;AAAA,QAClC;AAAA,QACA,SAAS,WAAmB,OAAmD;AAC7E,mBAAS,SAAS,WAAW,KAAK;AAAA,QACpC;AAAA,QACA,UAAU,MAAgC,SAAkB;AAC1D,yBAAe;AACf,gBAAM,aACJ,SAAS,OACL,QAAQ,eAAe,KACvB,SAAS,UACP,QAAQ,eAAe,QACvB,QAAQ,eAAe;AAC/B,mBAAS,UAAU,EAAE,MAAM,YAAY,QAAQ,CAAC;AAAA,QAClD;AAAA,QACA,MAAM;AACJ,mBAAS,IAAI;AAAA,QACf;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,MAAM;AAC9B,YAAI,CAAC,aAAc,QAAO,UAAU,IAAI;AACxC,eAAO;AAAA,MACT,SAAS,KAAK;AAIZ,eAAO,UAAU,OAAO;AACxB,cAAM;AAAA,MACR,UAAE;AACA,eAAO,IAAI;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,qBAAqB,MAAc,YAA8D;AAC/F,UAAM,aAAa,KAAK,QAAQ,MAAM,gBAAgB;AACtD,QAAI,YAAY;AACd,iBAAW,SAAS,MAAM,UAAU;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,QAAI,KAAK,kBAAkB,OAAO,KAAK,eAAe,aAAa,YAAY;AAC7E,YAAM,KAAK,eAAe,SAAS;AAAA,IACrC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/telemetry/span-manager.ts"],"sourcesContent":["import type { SpanHandle, SpanManager, TelemetryConfig } from './types.js';\n\n/** Minimal interface for an OTel span. */\ninterface OTelSpan {\n setAttribute(key: string, value: string | number | boolean): void;\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): void;\n setStatus(status: { code: unknown; message?: string }): void;\n end(): void;\n}\n\n/** Minimal interface for an OTel tracer. */\ninterface OTelTracer {\n startActiveSpan<T>(\n name: string,\n options: { attributes: Record<string, string | number | boolean> },\n fn: (span: OTelSpan) => Promise<T>,\n ): Promise<T>;\n}\n\n/** Minimal interface for an OTel tracer provider. */\ninterface OTelTracerProvider {\n getTracer(name: string): OTelTracer;\n shutdown?(): Promise<void>;\n}\n\n/** Minimal interface for the @opentelemetry/api module. */\ninterface OTelApi {\n SpanStatusCode: { UNSET: unknown; OK: unknown; ERROR: unknown };\n trace: {\n getTracerProvider(): OTelTracerProvider;\n getActiveSpan?(): OTelSpan | undefined;\n };\n}\n\n/**\n * OpenTelemetry-backed SpanManager.\n * Dynamically imports @opentelemetry/api to avoid hard dependency.\n */\nexport class OTelSpanManager implements SpanManager {\n private tracer: OTelTracer;\n private otelApi: OTelApi;\n private tracerProvider: OTelTracerProvider;\n\n private constructor(otelApi: OTelApi, tracer: OTelTracer, tracerProvider: OTelTracerProvider) {\n this.otelApi = otelApi;\n this.tracer = tracer;\n this.tracerProvider = tracerProvider;\n }\n\n static async create(config: TelemetryConfig): Promise<OTelSpanManager> {\n let otelApi: OTelApi;\n try {\n otelApi = (await import('@opentelemetry/api')) as unknown as OTelApi;\n } catch {\n throw new Error(\n '@opentelemetry/api is required for telemetry. Install it with: npm install @opentelemetry/api',\n );\n }\n\n const tracerProvider =\n (config.tracerProvider as OTelTracerProvider | undefined) ??\n otelApi.trace.getTracerProvider();\n const serviceName = config.serviceName ?? 'axl';\n const tracer = tracerProvider.getTracer(serviceName);\n\n return new OTelSpanManager(otelApi, tracer, tracerProvider);\n }\n\n async withSpanAsync<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: (span: SpanHandle) => Promise<T>,\n ): Promise<T> {\n const otelApi = this.otelApi;\n\n return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan: OTelSpan) => {\n let statusWasSet = false;\n const handle: SpanHandle = {\n setAttribute(key: string, value: string | number | boolean) {\n otelSpan.setAttribute(key, value);\n },\n addEvent(eventName: string, attrs?: Record<string, string | number | boolean>) {\n otelSpan.addEvent(eventName, attrs);\n },\n setStatus(code: 'unset' | 'ok' | 'error', message?: string) {\n statusWasSet = true;\n const statusCode =\n code === 'ok'\n ? otelApi.SpanStatusCode.OK\n : code === 'error'\n ? otelApi.SpanStatusCode.ERROR\n : otelApi.SpanStatusCode.UNSET;\n otelSpan.setStatus({ code: statusCode, message });\n },\n end() {\n otelSpan.end();\n },\n };\n\n try {\n const result = await fn(handle);\n if (!statusWasSet) handle.setStatus('ok');\n return result;\n } catch (err) {\n // Error text can contain provider, prompt, or sensitive tool data.\n // Keep exported status structural; host diagnostics remain in Axl's\n // own error and redacted event channels.\n handle.setStatus('error');\n throw err;\n } finally {\n handle.end();\n }\n });\n }\n\n addEventToActiveSpan(name: string, attributes?: Record<string, string | number | boolean>): void {\n const activeSpan = this.otelApi.trace.getActiveSpan?.();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.tracerProvider && typeof this.tracerProvider.shutdown === 'function') {\n await this.tracerProvider.shutdown();\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAsCO,IAAM,kBAAN,MAAM,iBAAuC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAkB,QAAoB,gBAAoC;AAC5F,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,aAAa,OAAO,QAAmD;AACrE,QAAI;AACJ,QAAI;AACF,gBAAW,MAAM,OAAO,oBAAoB;AAAA,IAC9C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBACH,OAAO,kBACR,QAAQ,MAAM,kBAAkB;AAClC,UAAM,cAAc,OAAO,eAAe;AAC1C,UAAM,SAAS,eAAe,UAAU,WAAW;AAEnD,WAAO,IAAI,iBAAgB,SAAS,QAAQ,cAAc;AAAA,EAC5D;AAAA,EAEA,MAAM,cACJ,MACA,YACA,IACY;AACZ,UAAM,UAAU,KAAK;AAErB,WAAO,KAAK,OAAO,gBAAgB,MAAM,EAAE,WAAW,GAAG,OAAO,aAAuB;AACrF,UAAI,eAAe;AACnB,YAAM,SAAqB;AAAA,QACzB,aAAa,KAAa,OAAkC;AAC1D,mBAAS,aAAa,KAAK,KAAK;AAAA,QAClC;AAAA,QACA,SAAS,WAAmB,OAAmD;AAC7E,mBAAS,SAAS,WAAW,KAAK;AAAA,QACpC;AAAA,QACA,UAAU,MAAgC,SAAkB;AAC1D,yBAAe;AACf,gBAAM,aACJ,SAAS,OACL,QAAQ,eAAe,KACvB,SAAS,UACP,QAAQ,eAAe,QACvB,QAAQ,eAAe;AAC/B,mBAAS,UAAU,EAAE,MAAM,YAAY,QAAQ,CAAC;AAAA,QAClD;AAAA,QACA,MAAM;AACJ,mBAAS,IAAI;AAAA,QACf;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,MAAM;AAC9B,YAAI,CAAC,aAAc,QAAO,UAAU,IAAI;AACxC,eAAO;AAAA,MACT,SAAS,KAAK;AAIZ,eAAO,UAAU,OAAO;AACxB,cAAM;AAAA,MACR,UAAE;AACA,eAAO,IAAI;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,qBAAqB,MAAc,YAA8D;AAC/F,UAAM,aAAa,KAAK,QAAQ,MAAM,gBAAgB;AACtD,QAAI,YAAY;AACd,iBAAW,SAAS,MAAM,UAAU;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,QAAI,KAAK,kBAAkB,OAAO,KAAK,eAAe,aAAa,YAAY;AAC7E,YAAM,KAAK,eAAe,SAAS;AAAA,IACrC;AAAA,EACF;AACF;","names":[]}
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ const __AXL_BUILD_PATH__ = __filename;
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
@@ -509,8 +510,62 @@ var ValidationError = class extends AxlError {
509
510
  }
510
511
  };
511
512
 
512
- // src/accounting.ts
513
+ // src/shared-context.ts
513
514
  var import_node_async_hooks = require("async_hooks");
515
+ var import_node_url = require("url");
516
+ var PROTOCOL = 1;
517
+ var CONTEXT_KEY = /* @__PURE__ */ Symbol.for(`axl.accounting.context.v${PROTOCOL}`);
518
+ var GUARD_KEY = /* @__PURE__ */ Symbol.for("axl.accounting.scopeGuard");
519
+ function createContext() {
520
+ let operationCounter = 0;
521
+ return {
522
+ protocol: PROTOCOL,
523
+ id: /* @__PURE__ */ Symbol("axl.accounting.context.instance"),
524
+ accounting: new import_node_async_hooks.AsyncLocalStorage(),
525
+ dispatch: new import_node_async_hooks.AsyncLocalStorage(),
526
+ capture: new import_node_async_hooks.AsyncLocalStorage(),
527
+ correlation: new import_node_async_hooks.AsyncLocalStorage(),
528
+ turn: new import_node_async_hooks.AsyncLocalStorage(),
529
+ nextOperationId: () => `op_${++operationCounter}`
530
+ };
531
+ }
532
+ function isStorage(value) {
533
+ return typeof value === "object" && value !== null && typeof value.getStore === "function" && typeof value.run === "function";
534
+ }
535
+ function isCompatible(value) {
536
+ if (typeof value !== "object" || value === null) return false;
537
+ const candidate = value;
538
+ 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";
539
+ }
540
+ var registry = globalThis;
541
+ var installed = registry[CONTEXT_KEY];
542
+ var sharedContext = installed === void 0 ? registry[CONTEXT_KEY] = createContext() : isCompatible(installed) ? installed : createContext();
543
+ var installedGuard = registry[GUARD_KEY];
544
+ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null && isStorage(installedGuard.storage) && installedGuard.warned instanceof WeakMap ? installedGuard : registry[GUARD_KEY] = {
545
+ storage: new import_node_async_hooks.AsyncLocalStorage(),
546
+ warned: /* @__PURE__ */ new WeakMap()
547
+ };
548
+ var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
549
+ var thisCopy = {
550
+ path: buildPath.startsWith("file:") ? (0, import_node_url.fileURLToPath)(buildPath) : buildPath,
551
+ version: true ? "0.24.1" : "unknown"
552
+ };
553
+ function warnCrossCopy(other, joined) {
554
+ if (other === thisCopy) return;
555
+ if (sharedGuard.warned.get(other)?.has(thisCopy)) return;
556
+ const fromThis = sharedGuard.warned.get(thisCopy) ?? /* @__PURE__ */ new WeakSet();
557
+ if (fromThis.has(other)) return;
558
+ fromThis.add(other);
559
+ sharedGuard.warned.set(thisCopy, fromThis);
560
+ try {
561
+ console.warn(
562
+ `[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.")
563
+ );
564
+ } catch {
565
+ }
566
+ }
567
+
568
+ // src/accounting.ts
514
569
  var RECORD_SPEND = /* @__PURE__ */ Symbol.for("axl.accounting.recordSpend");
515
570
  var AdmissionController = class {
516
571
  /** The configured USD threshold. Admission closes at `knownSpend >= limit`. */
@@ -572,10 +627,8 @@ function emptyUsage() {
572
627
  function isUsableCost(cost) {
573
628
  return typeof cost === "number" && Number.isFinite(cost) && cost >= 0;
574
629
  }
575
- var operationCounter = 0;
576
630
  function nextOperationId() {
577
- operationCounter += 1;
578
- return `op_${operationCounter}`;
631
+ return sharedContext.nextOperationId();
579
632
  }
580
633
  var AccountingScope = class {
581
634
  parent;
@@ -613,6 +666,11 @@ var AccountingScope = class {
613
666
  recordDenied() {
614
667
  this.denied += 1;
615
668
  }
669
+ /** A foreign protocol attempted work we cannot measure. Mark every live ancestor. */
670
+ markUninstrumented() {
671
+ if (this.finalized || this.reasons.has("uninstrumented")) return;
672
+ this.reasons.set("uninstrumented", 1);
673
+ }
616
674
  /** An already-open operation refused at the dispatch check: retract it. */
617
675
  recordRetracted(op) {
618
676
  this.seen.add(op.id);
@@ -665,7 +723,7 @@ var AccountingScope = class {
665
723
  version: 1,
666
724
  currency: "USD",
667
725
  knownCost: this.knownCost,
668
- completeness: this.unknown > 0 ? "incomplete" : "complete",
726
+ completeness: this.reasons.size > 0 ? "incomplete" : "complete",
669
727
  reasons: Object.fromEntries(this.reasons),
670
728
  usage: { ...this.usage },
671
729
  operations: {
@@ -680,8 +738,8 @@ var AccountingScope = class {
680
738
  };
681
739
  }
682
740
  };
683
- var accountingStorage = new import_node_async_hooks.AsyncLocalStorage();
684
- var dispatchAdmissionStorage = new import_node_async_hooks.AsyncLocalStorage();
741
+ var accountingStorage = sharedContext.accounting;
742
+ var dispatchAdmissionStorage = sharedContext.dispatch;
685
743
  function currentDispatchAdmission() {
686
744
  return dispatchAdmissionStorage.getStore();
687
745
  }
@@ -742,6 +800,17 @@ function admissionDenied(controller, descriptor) {
742
800
  });
743
801
  }
744
802
  function openOperation(descriptor) {
803
+ const inheritedGuard = sharedGuard.storage.getStore();
804
+ const guard = inheritedGuard && (inheritedGuard.isActive?.() ?? true) ? inheritedGuard : void 0;
805
+ if (guard && guard.contextId !== sharedContext.id) {
806
+ guard.markUninstrumented();
807
+ warnCrossCopy(guard.owner, false);
808
+ throw new AxlError(
809
+ "INCOMPATIBLE_ACCOUNTING_SCOPE",
810
+ "The active @axlsdk/axl accounting scope uses an incompatible loaded copy; paid work was refused before dispatch."
811
+ );
812
+ }
813
+ if (guard) warnCrossCopy(guard.owner, true);
745
814
  const scope = accountingStorage.getStore();
746
815
  if (!scope || scope.isFinalized) return void 0;
747
816
  const denier = denyingController(scope);
@@ -831,8 +900,45 @@ async function runInAccountingScope(options, fn) {
831
900
  purpose: options.purpose ?? parent?.purpose ?? "generation",
832
901
  admission: options.admission
833
902
  });
903
+ const inheritedGuard = sharedGuard.storage.getStore();
904
+ const enclosingGuard = inheritedGuard && (inheritedGuard.isActive?.() ?? true) ? inheritedGuard : void 0;
905
+ if (enclosingGuard)
906
+ warnCrossCopy(enclosingGuard.owner, enclosingGuard.contextId === sharedContext.id);
907
+ if (enclosingGuard && enclosingGuard.contextId !== sharedContext.id) {
908
+ enclosingGuard.markUninstrumented();
909
+ scope.markUninstrumented();
910
+ scope.finalize();
911
+ return {
912
+ outcome: {
913
+ status: "rejected",
914
+ error: new AxlError(
915
+ "INCOMPATIBLE_ACCOUNTING_SCOPE",
916
+ "The active @axlsdk/axl accounting scope uses an incompatible loaded copy; paid work was refused before dispatch."
917
+ )
918
+ },
919
+ accounting: scope.toAccounting()
920
+ };
921
+ }
922
+ const markUninstrumented = () => {
923
+ let current = scope;
924
+ while (current) {
925
+ if (!current.isFinalized) current.markUninstrumented();
926
+ current = current.parent;
927
+ }
928
+ };
929
+ const isActive = () => {
930
+ let current = scope;
931
+ while (current) {
932
+ if (!current.isFinalized) return true;
933
+ current = current.parent;
934
+ }
935
+ return false;
936
+ };
834
937
  try {
835
- const value = await accountingStorage.run(scope, fn);
938
+ const value = await sharedGuard.storage.run(
939
+ { contextId: sharedContext.id, owner: thisCopy, markUninstrumented, isActive },
940
+ () => accountingStorage.run(scope, fn)
941
+ );
836
942
  scope.finalize();
837
943
  return { outcome: { status: "fulfilled", value }, accounting: scope.toAccounting() };
838
944
  } catch (error) {
@@ -1266,7 +1372,7 @@ function tool(config) {
1266
1372
  } catch (err) {
1267
1373
  if (options?.signal?.aborted) options.signal.throwIfAborted();
1268
1374
  if (isAbortError(err)) throw err;
1269
- if (err instanceof AdmissionDeniedError) throw err;
1375
+ if (isAdmissionDeniedError(err)) throw err;
1270
1376
  rethrowEventStreamOverflow(err);
1271
1377
  lastError = err instanceof Error ? err : new Error(String(err));
1272
1378
  if (attempt === maxAttempts) break;
@@ -9020,7 +9126,7 @@ var TranscriptionProviderRegistry = class {
9020
9126
  };
9021
9127
 
9022
9128
  // src/context.ts
9023
- var import_node_async_hooks3 = require("async_hooks");
9129
+ var import_node_async_hooks2 = require("async_hooks");
9024
9130
  var import_node_crypto = require("crypto");
9025
9131
  var import_zod2 = require("zod");
9026
9132
 
@@ -11205,7 +11311,6 @@ function warnDiagnosticOnce(key, message, silent, docs = DOCS_URL) {
11205
11311
  var warnSchemaDiagnosticOnce = warnDiagnosticOnce;
11206
11312
 
11207
11313
  // src/diagnostics/capture.ts
11208
- var import_node_async_hooks2 = require("async_hooks");
11209
11314
  var DEFAULT_MAX_RECORD_BYTES = 256 * 1024;
11210
11315
  var DEFAULT_MAX_RUN_BYTES = 16 * 1024 * 1024;
11211
11316
  var DEFAULT_MAX_QUEUE_BYTES = 1024 * 1024;
@@ -11466,8 +11571,8 @@ function positive(value, fallback) {
11466
11571
  function describe(error) {
11467
11572
  return error instanceof Error ? error.message : String(error);
11468
11573
  }
11469
- var channelStorage = new import_node_async_hooks2.AsyncLocalStorage();
11470
- var correlationStorage = new import_node_async_hooks2.AsyncLocalStorage();
11574
+ var channelStorage = sharedContext.capture;
11575
+ var correlationStorage = sharedContext.correlation;
11471
11576
  function currentCaptureChannel() {
11472
11577
  return channelStorage.getStore();
11473
11578
  }
@@ -11483,7 +11588,7 @@ function runWithCaptureCorrelation(correlation, fn) {
11483
11588
  const merged = { ...correlationStorage.getStore(), ...correlation };
11484
11589
  return correlationStorage.run(merged, fn);
11485
11590
  }
11486
- var turnStorage = new import_node_async_hooks2.AsyncLocalStorage();
11591
+ var turnStorage = sharedContext.turn;
11487
11592
  function currentCaptureTurn() {
11488
11593
  return turnStorage.getStore()?.current;
11489
11594
  }
@@ -12352,7 +12457,7 @@ async function executeAcceptedTool(options) {
12352
12457
  }
12353
12458
  } catch (error) {
12354
12459
  rethrowEventStreamOverflow(error);
12355
- if (error instanceof AdmissionDeniedError) throw error;
12460
+ if (isAdmissionDeniedError(error)) throw error;
12356
12461
  const abort = cancellationError(signal, error);
12357
12462
  if (abort !== void 0) return cancellation("handler", abort);
12358
12463
  return failed("handler", error, { attempts });
@@ -12525,9 +12630,9 @@ function recordToolSpanOutcome(span, outcome) {
12525
12630
  }
12526
12631
 
12527
12632
  // src/context.ts
12528
- var signalStorage = new import_node_async_hooks3.AsyncLocalStorage();
12529
- var hardSignalStorage = new import_node_async_hooks3.AsyncLocalStorage();
12530
- var timeoutTrackerStorage = new import_node_async_hooks3.AsyncLocalStorage();
12633
+ var signalStorage = new import_node_async_hooks2.AsyncLocalStorage();
12634
+ var hardSignalStorage = new import_node_async_hooks2.AsyncLocalStorage();
12635
+ var timeoutTrackerStorage = new import_node_async_hooks2.AsyncLocalStorage();
12531
12636
  var MAX_TIMER_DELAY_MS = 2147483647;
12532
12637
  function composeAbortSignals(...signals) {
12533
12638
  const active = signals.filter((signal) => signal !== void 0);
@@ -12632,7 +12737,7 @@ function parseHumanDecision(value) {
12632
12737
  }
12633
12738
  return invalid3();
12634
12739
  }
12635
- var askStorage = new import_node_async_hooks3.AsyncLocalStorage();
12740
+ var askStorage = new import_node_async_hooks2.AsyncLocalStorage();
12636
12741
  var inlineSchemaCache = /* @__PURE__ */ new WeakMap();
12637
12742
  function zodToJsonSchema(schema) {
12638
12743
  const cached = inlineSchemaCache.get(schema);
@@ -16467,7 +16572,7 @@ ${summaryResponse.content}`
16467
16572
  try {
16468
16573
  result = await (transcriptionOperation ? transcriptionOperation.run(() => resolved.provider.transcribe(providerRequest)) : resolved.provider.transcribe(providerRequest));
16469
16574
  } catch (error) {
16470
- if (error instanceof AdmissionDeniedError) {
16575
+ if (isAdmissionDeniedError(error)) {
16471
16576
  transcriptionOperation?.settleFailure();
16472
16577
  throw error;
16473
16578
  }
@@ -16731,13 +16836,13 @@ function agent(config) {
16731
16836
  _config: config,
16732
16837
  _name: defaultName,
16733
16838
  async ask(prompt, options) {
16734
- const registry = new ProviderRegistry();
16839
+ const registry2 = new ProviderRegistry();
16735
16840
  const transcriptionRegistry = new TranscriptionProviderRegistry();
16736
16841
  const ctx = new WorkflowContext({
16737
16842
  input: prompt,
16738
16843
  executionId: (0, import_node_crypto2.randomUUID)(),
16739
16844
  config: {},
16740
- providerRegistry: registry,
16845
+ providerRegistry: registry2,
16741
16846
  transcriptionProviderRegistry: transcriptionRegistry
16742
16847
  });
16743
16848
  return ctx.ask(agentInstance, prompt, options);
@@ -16761,7 +16866,7 @@ function workflow(config) {
16761
16866
  // src/runtime.ts
16762
16867
  var import_node_events2 = require("events");
16763
16868
  var import_node_crypto4 = require("crypto");
16764
- var import_node_async_hooks4 = require("async_hooks");
16869
+ var import_node_async_hooks3 = require("async_hooks");
16765
16870
  var import_node_fs3 = require("fs");
16766
16871
  var import_node_path3 = require("path");
16767
16872
 
@@ -18941,7 +19046,7 @@ function assertNoRemovedObservationCallbacks(options) {
18941
19046
  `runtime.createContext() no longer accepts ${removed.join(", ")}. Observe ctx.events or use runtime.stream() instead. See docs/migration/stream-first-observation.md.`
18942
19047
  );
18943
19048
  }
18944
- var costScopeStorage = new import_node_async_hooks4.AsyncLocalStorage();
19049
+ var costScopeStorage = new import_node_async_hooks3.AsyncLocalStorage();
18945
19050
  function forwardAbortSignal(external, internal) {
18946
19051
  if (!external) return () => {
18947
19052
  };
@@ -20979,7 +21084,7 @@ function pickExport(mod, key) {
20979
21084
  // src/cli-internals.ts
20980
21085
  var import_node_path4 = require("path");
20981
21086
  var import_node_fs4 = require("fs");
20982
- var import_node_url = require("url");
21087
+ var import_node_url2 = require("url");
20983
21088
  var CONFIG_CANDIDATES = [
20984
21089
  "axl.config.mts",
20985
21090
  "axl.config.ts",
@@ -21021,7 +21126,7 @@ async function ensureTsxRegistered() {
21021
21126
  return tsxRegistered;
21022
21127
  }
21023
21128
  async function importModule(filePath, _parentURL) {
21024
- const url = (0, import_node_url.pathToFileURL)(filePath).href;
21129
+ const url = (0, import_node_url2.pathToFileURL)(filePath).href;
21025
21130
  if (!needsTsxLoader(filePath)) {
21026
21131
  return await import(url);
21027
21132
  }