@axlsdk/axl 0.13.5 → 0.13.7

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
@@ -340,6 +340,7 @@ type ExecutionInfo = {
340
340
  startedAt: number;
341
341
  completedAt?: number;
342
342
  duration: number;
343
+ result?: unknown;
343
344
  error?: string;
344
345
  };
345
346
  type StreamEvent = {
@@ -349,10 +350,12 @@ type StreamEvent = {
349
350
  type: 'tool_call';
350
351
  name: string;
351
352
  args: unknown;
353
+ callId?: string;
352
354
  } | {
353
355
  type: 'tool_result';
354
356
  name: string;
355
357
  result: unknown;
358
+ callId?: string;
356
359
  } | {
357
360
  type: 'tool_approval';
358
361
  name: string;
@@ -382,7 +385,7 @@ type StreamEvent = {
382
385
  data: unknown;
383
386
  } | {
384
387
  type: 'error';
385
- error: Error;
388
+ message: string;
386
389
  };
387
390
  /** Record of an agent handoff event (persisted in session metadata). */
388
391
  type HandoffRecord = {
@@ -958,6 +961,7 @@ type WorkflowContextInit = {
958
961
  onToolCall?: (call: {
959
962
  name: string;
960
963
  args: unknown;
964
+ callId?: string;
961
965
  }) => void;
962
966
  pendingDecisions?: Map<string, (d: HumanDecision) => void>;
963
967
  budgetContext?: {
@@ -1369,10 +1373,13 @@ declare class AxlRuntime extends EventEmitter {
1369
1373
  executeWorkflow?: (input: unknown, runtime?: AxlRuntime) => Promise<{
1370
1374
  output: unknown;
1371
1375
  cost?: number;
1376
+ metadata?: Record<string, unknown>;
1372
1377
  }>;
1373
1378
  } | undefined;
1374
1379
  /** Run a registered eval by name. */
1375
- runRegisteredEval(name: string): Promise<unknown>;
1380
+ runRegisteredEval(name: string, options?: {
1381
+ metadata?: Record<string, unknown>;
1382
+ }): Promise<unknown>;
1376
1383
  /** Get all execution info (running + completed + historical). */
1377
1384
  getExecutions(): Promise<ExecutionInfo[]>;
1378
1385
  /**
@@ -1447,7 +1454,7 @@ declare class AxlRuntime extends EventEmitter {
1447
1454
  *
1448
1455
  * @see Spec Section 13.6
1449
1456
  */
1450
- evalCompare(baseline: unknown, candidate: unknown): Promise<unknown>;
1457
+ evalCompare(baseline: unknown, candidate: unknown, options?: unknown): Promise<unknown>;
1451
1458
  /**
1452
1459
  * Track cost across any runtime operations within the given function.
1453
1460
  * Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
@@ -1459,6 +1466,30 @@ declare class AxlRuntime extends EventEmitter {
1459
1466
  result: T;
1460
1467
  cost: number;
1461
1468
  }>;
1469
+ /**
1470
+ * Track cost and execution metadata across any runtime operations within the given function.
1471
+ * Uses AsyncLocalStorage to scope attribution to specific execution IDs,
1472
+ * making it correct with concurrent calls.
1473
+ *
1474
+ * Returns cost (same as `trackCost`) plus metadata extracted from trace events:
1475
+ * models (unique URIs), tokens (input/output/reasoning sums), and agent call count.
1476
+ *
1477
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
1478
+ */
1479
+ trackExecution<T>(fn: () => Promise<T>): Promise<{
1480
+ result: T;
1481
+ cost: number;
1482
+ metadata: {
1483
+ models: string[];
1484
+ modelCallCounts?: Record<string, number>;
1485
+ tokens: {
1486
+ input: number;
1487
+ output: number;
1488
+ reasoning: number;
1489
+ };
1490
+ agentCalls: number;
1491
+ };
1492
+ }>;
1462
1493
  /** Register an execution ID with the active cost scope for trackCost() attribution. */
1463
1494
  private registerWithCostScope;
1464
1495
  /**
package/dist/index.d.ts CHANGED
@@ -340,6 +340,7 @@ type ExecutionInfo = {
340
340
  startedAt: number;
341
341
  completedAt?: number;
342
342
  duration: number;
343
+ result?: unknown;
343
344
  error?: string;
344
345
  };
345
346
  type StreamEvent = {
@@ -349,10 +350,12 @@ type StreamEvent = {
349
350
  type: 'tool_call';
350
351
  name: string;
351
352
  args: unknown;
353
+ callId?: string;
352
354
  } | {
353
355
  type: 'tool_result';
354
356
  name: string;
355
357
  result: unknown;
358
+ callId?: string;
356
359
  } | {
357
360
  type: 'tool_approval';
358
361
  name: string;
@@ -382,7 +385,7 @@ type StreamEvent = {
382
385
  data: unknown;
383
386
  } | {
384
387
  type: 'error';
385
- error: Error;
388
+ message: string;
386
389
  };
387
390
  /** Record of an agent handoff event (persisted in session metadata). */
388
391
  type HandoffRecord = {
@@ -958,6 +961,7 @@ type WorkflowContextInit = {
958
961
  onToolCall?: (call: {
959
962
  name: string;
960
963
  args: unknown;
964
+ callId?: string;
961
965
  }) => void;
962
966
  pendingDecisions?: Map<string, (d: HumanDecision) => void>;
963
967
  budgetContext?: {
@@ -1369,10 +1373,13 @@ declare class AxlRuntime extends EventEmitter {
1369
1373
  executeWorkflow?: (input: unknown, runtime?: AxlRuntime) => Promise<{
1370
1374
  output: unknown;
1371
1375
  cost?: number;
1376
+ metadata?: Record<string, unknown>;
1372
1377
  }>;
1373
1378
  } | undefined;
1374
1379
  /** Run a registered eval by name. */
1375
- runRegisteredEval(name: string): Promise<unknown>;
1380
+ runRegisteredEval(name: string, options?: {
1381
+ metadata?: Record<string, unknown>;
1382
+ }): Promise<unknown>;
1376
1383
  /** Get all execution info (running + completed + historical). */
1377
1384
  getExecutions(): Promise<ExecutionInfo[]>;
1378
1385
  /**
@@ -1447,7 +1454,7 @@ declare class AxlRuntime extends EventEmitter {
1447
1454
  *
1448
1455
  * @see Spec Section 13.6
1449
1456
  */
1450
- evalCompare(baseline: unknown, candidate: unknown): Promise<unknown>;
1457
+ evalCompare(baseline: unknown, candidate: unknown, options?: unknown): Promise<unknown>;
1451
1458
  /**
1452
1459
  * Track cost across any runtime operations within the given function.
1453
1460
  * Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
@@ -1459,6 +1466,30 @@ declare class AxlRuntime extends EventEmitter {
1459
1466
  result: T;
1460
1467
  cost: number;
1461
1468
  }>;
1469
+ /**
1470
+ * Track cost and execution metadata across any runtime operations within the given function.
1471
+ * Uses AsyncLocalStorage to scope attribution to specific execution IDs,
1472
+ * making it correct with concurrent calls.
1473
+ *
1474
+ * Returns cost (same as `trackCost`) plus metadata extracted from trace events:
1475
+ * models (unique URIs), tokens (input/output/reasoning sums), and agent call count.
1476
+ *
1477
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
1478
+ */
1479
+ trackExecution<T>(fn: () => Promise<T>): Promise<{
1480
+ result: T;
1481
+ cost: number;
1482
+ metadata: {
1483
+ models: string[];
1484
+ modelCallCounts?: Record<string, number>;
1485
+ tokens: {
1486
+ input: number;
1487
+ output: number;
1488
+ reasoning: number;
1489
+ };
1490
+ agentCalls: number;
1491
+ };
1492
+ }>;
1462
1493
  /** Register an execution ID with the active cost scope for trackCost() attribution. */
1463
1494
  private registerWithCostScope;
1464
1495
  /**
package/dist/index.js CHANGED
@@ -2691,7 +2691,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2691
2691
  });
2692
2692
  continue;
2693
2693
  }
2694
- this.onToolCall?.({ name: toolName, args: toolArgs2 });
2694
+ this.onToolCall?.({ name: toolName, args: toolArgs2, callId: toolCall.id });
2695
2695
  const toolStart2 = Date.now();
2696
2696
  const executeOverride = async () => {
2697
2697
  let toolResult3;
@@ -2724,7 +2724,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2724
2724
  agent: agent2._name,
2725
2725
  tool: toolName,
2726
2726
  duration: Date.now() - toolStart2,
2727
- data: { args: toolArgs2, result: toolResult2 }
2727
+ data: { args: toolArgs2, result: toolResult2, callId: toolCall.id }
2728
2728
  });
2729
2729
  currentMessages.push({
2730
2730
  role: "tool",
@@ -2755,7 +2755,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2755
2755
  });
2756
2756
  continue;
2757
2757
  }
2758
- this.onToolCall?.({ name: toolName, args: toolArgs });
2758
+ this.onToolCall?.({ name: toolName, args: toolArgs, callId: toolCall.id });
2759
2759
  const toolStart = Date.now();
2760
2760
  if (tool2 && tool2.requireApproval) {
2761
2761
  const approvalFn = async () => {
@@ -2884,7 +2884,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2884
2884
  agent: agent2._name,
2885
2885
  tool: traceName,
2886
2886
  duration: Date.now() - toolStart,
2887
- data: { args: toolArgs, result: toolResult }
2887
+ data: { args: toolArgs, result: toolResult, callId: toolCall.id }
2888
2888
  });
2889
2889
  currentMessages.push({
2890
2890
  role: "tool",
@@ -4595,6 +4595,8 @@ var AxlStream = class _AxlStream extends Readable {
4595
4595
  this.bus.on("__reject", (error) => rejectPromise(error));
4596
4596
  this.bus.on("error", () => {
4597
4597
  });
4598
+ this.promise.catch(() => {
4599
+ });
4598
4600
  }
4599
4601
  static STREAM_EVENTS = /* @__PURE__ */ new Set([
4600
4602
  "token",
@@ -4740,9 +4742,16 @@ var AxlStream = class _AxlStream extends Readable {
4740
4742
  _error(error) {
4741
4743
  if (this.finished) return;
4742
4744
  this.finished = true;
4743
- const errorEvent = { type: "error", error };
4745
+ const errorEvent = { type: "error", message: error.message };
4744
4746
  this.bus.emit("error", errorEvent);
4747
+ this.push(errorEvent);
4745
4748
  this.push(null);
4749
+ const waiter = this.waiters.shift();
4750
+ if (waiter) {
4751
+ waiter({ value: errorEvent, done: false });
4752
+ } else {
4753
+ this.eventQueue.push(errorEvent);
4754
+ }
4746
4755
  for (const w of this.waiters) {
4747
4756
  w({ value: void 0, done: true });
4748
4757
  }
@@ -5411,7 +5420,7 @@ var AxlRuntime = class extends EventEmitter2 {
5411
5420
  return this.registeredEvals.get(name);
5412
5421
  }
5413
5422
  /** Run a registered eval by name. */
5414
- async runRegisteredEval(name) {
5423
+ async runRegisteredEval(name, options) {
5415
5424
  const entry = this.registeredEvals.get(name);
5416
5425
  if (!entry) throw new Error(`Eval "${name}" is not registered`);
5417
5426
  let result;
@@ -5426,10 +5435,18 @@ var AxlRuntime = class extends EventEmitter2 {
5426
5435
  }
5427
5436
  const originalExecuteFn = entry.executeWorkflow;
5428
5437
  const wrappedExecuteFn = async (input, runtime) => {
5429
- const { result: result2, cost: trackedCost } = await this.trackCost(async () => {
5438
+ const {
5439
+ result: result2,
5440
+ cost: trackedCost,
5441
+ metadata
5442
+ } = await this.trackExecution(async () => {
5430
5443
  return originalExecuteFn(input, runtime);
5431
5444
  });
5432
- return { output: result2.output, cost: result2.cost ?? trackedCost };
5445
+ return {
5446
+ output: result2.output,
5447
+ cost: result2.cost ?? trackedCost,
5448
+ metadata: result2.metadata ?? metadata
5449
+ };
5433
5450
  };
5434
5451
  result = await runEvalFn(entry.config, wrappedExecuteFn, this);
5435
5452
  } else {
@@ -5438,6 +5455,12 @@ var AxlRuntime = class extends EventEmitter2 {
5438
5455
  );
5439
5456
  }
5440
5457
  const resultObj = result;
5458
+ if (options?.metadata) {
5459
+ resultObj.metadata = {
5460
+ ...resultObj.metadata,
5461
+ ...options.metadata
5462
+ };
5463
+ }
5441
5464
  try {
5442
5465
  await this.saveEvalResult({
5443
5466
  id: resultObj.id ?? randomUUID2(),
@@ -5594,6 +5617,7 @@ var AxlRuntime = class extends EventEmitter2 {
5594
5617
  execInfo.status = "completed";
5595
5618
  execInfo.completedAt = Date.now();
5596
5619
  execInfo.duration = execInfo.completedAt - execInfo.startedAt;
5620
+ execInfo.result = output;
5597
5621
  ctx.log("workflow_end", {
5598
5622
  workflow: name,
5599
5623
  status: "completed",
@@ -5706,7 +5730,8 @@ var AxlRuntime = class extends EventEmitter2 {
5706
5730
  axlStream._push({
5707
5731
  type: "tool_result",
5708
5732
  name: event.tool ?? "",
5709
- result: event.data?.result
5733
+ result: event.data?.result,
5734
+ callId: event.data?.callId
5710
5735
  });
5711
5736
  }
5712
5737
  axlStream._push({ type: "step", step: event.step, data: event });
@@ -5715,7 +5740,12 @@ var AxlRuntime = class extends EventEmitter2 {
5715
5740
  axlStream._push({ type: "token", data: token });
5716
5741
  },
5717
5742
  onToolCall: (call) => {
5718
- axlStream._push({ type: "tool_call", name: call.name, args: call.args });
5743
+ axlStream._push({
5744
+ type: "tool_call",
5745
+ name: call.name,
5746
+ args: call.args,
5747
+ callId: call.callId
5748
+ });
5719
5749
  },
5720
5750
  onAgentStart: (info) => {
5721
5751
  axlStream._push({ type: "agent_start", agent: info.agent, model: info.model });
@@ -5749,6 +5779,7 @@ var AxlRuntime = class extends EventEmitter2 {
5749
5779
  execInfo.status = "completed";
5750
5780
  execInfo.completedAt = Date.now();
5751
5781
  execInfo.duration = execInfo.completedAt - execInfo.startedAt;
5782
+ execInfo.result = result;
5752
5783
  wfCtx.log("workflow_end", {
5753
5784
  workflow: name,
5754
5785
  status: "completed",
@@ -5965,10 +5996,10 @@ var AxlRuntime = class extends EventEmitter2 {
5965
5996
  );
5966
5997
  }
5967
5998
  const executeWorkflow = async (input) => {
5968
- const { result, cost } = await this.trackCost(async () => {
5999
+ const { result, cost, metadata } = await this.trackExecution(async () => {
5969
6000
  return this.execute(config.workflow, input);
5970
6001
  });
5971
- return { output: result, cost };
6002
+ return { output: result, cost, metadata };
5972
6003
  };
5973
6004
  return runEvalFn(config, executeWorkflow, this);
5974
6005
  }
@@ -5978,7 +6009,7 @@ var AxlRuntime = class extends EventEmitter2 {
5978
6009
  *
5979
6010
  * @see Spec Section 13.6
5980
6011
  */
5981
- async evalCompare(baseline, candidate) {
6012
+ async evalCompare(baseline, candidate, options) {
5982
6013
  let evalCompareFn;
5983
6014
  try {
5984
6015
  ({ evalCompare: evalCompareFn } = await import("@axlsdk/eval"));
@@ -5987,7 +6018,7 @@ var AxlRuntime = class extends EventEmitter2 {
5987
6018
  "axl-eval is required for AxlRuntime.evalCompare(). Install it with: npm install @axlsdk/eval"
5988
6019
  );
5989
6020
  }
5990
- return evalCompareFn(baseline, candidate);
6021
+ return evalCompareFn(baseline, candidate, options);
5991
6022
  }
5992
6023
  /**
5993
6024
  * Track cost across any runtime operations within the given function.
@@ -5997,24 +6028,58 @@ var AxlRuntime = class extends EventEmitter2 {
5997
6028
  * Works with both `createContext()` and `execute()` calls inside `fn`.
5998
6029
  */
5999
6030
  async trackCost(fn) {
6031
+ const { result, cost } = await this.trackExecution(fn);
6032
+ return { result, cost };
6033
+ }
6034
+ /**
6035
+ * Track cost and execution metadata across any runtime operations within the given function.
6036
+ * Uses AsyncLocalStorage to scope attribution to specific execution IDs,
6037
+ * making it correct with concurrent calls.
6038
+ *
6039
+ * Returns cost (same as `trackCost`) plus metadata extracted from trace events:
6040
+ * models (unique URIs), tokens (input/output/reasoning sums), and agent call count.
6041
+ *
6042
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
6043
+ */
6044
+ async trackExecution(fn) {
6000
6045
  const parentScope = costScopeStorage.getStore();
6001
6046
  const scope = {
6002
6047
  totalCost: 0,
6003
6048
  trackedIds: /* @__PURE__ */ new Set(),
6004
6049
  parent: parentScope
6005
6050
  };
6006
- const costListener = (event) => {
6007
- if (event.cost && scope.trackedIds.has(event.executionId)) {
6008
- scope.totalCost += event.cost;
6051
+ const modelCalls = /* @__PURE__ */ new Map();
6052
+ const tokens = { input: 0, output: 0, reasoning: 0 };
6053
+ let agentCalls = 0;
6054
+ const listener = (event) => {
6055
+ if (!scope.trackedIds.has(event.executionId)) return;
6056
+ if (event.cost) scope.totalCost += event.cost;
6057
+ if (event.type === "agent_call") {
6058
+ if (event.model) modelCalls.set(event.model, (modelCalls.get(event.model) ?? 0) + 1);
6059
+ agentCalls++;
6060
+ if (event.tokens) {
6061
+ tokens.input += event.tokens.input ?? 0;
6062
+ tokens.output += event.tokens.output ?? 0;
6063
+ tokens.reasoning += event.tokens.reasoning ?? 0;
6064
+ }
6009
6065
  }
6010
6066
  };
6011
6067
  this.setMaxListeners(this.getMaxListeners() + 1);
6012
- this.on("trace", costListener);
6068
+ this.on("trace", listener);
6013
6069
  try {
6014
6070
  const result = await costScopeStorage.run(scope, fn);
6015
- return { result, cost: scope.totalCost };
6071
+ return {
6072
+ result,
6073
+ cost: scope.totalCost,
6074
+ metadata: {
6075
+ models: [...modelCalls.keys()],
6076
+ modelCallCounts: modelCalls.size > 0 ? Object.fromEntries(modelCalls) : void 0,
6077
+ tokens,
6078
+ agentCalls
6079
+ }
6080
+ };
6016
6081
  } finally {
6017
- this.off("trace", costListener);
6082
+ this.off("trace", listener);
6018
6083
  this.setMaxListeners(this.getMaxListeners() - 1);
6019
6084
  }
6020
6085
  }