@axlsdk/axl 0.13.6 → 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.cjs CHANGED
@@ -5568,7 +5568,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5568
5568
  return this.registeredEvals.get(name);
5569
5569
  }
5570
5570
  /** Run a registered eval by name. */
5571
- async runRegisteredEval(name) {
5571
+ async runRegisteredEval(name, options) {
5572
5572
  const entry = this.registeredEvals.get(name);
5573
5573
  if (!entry) throw new Error(`Eval "${name}" is not registered`);
5574
5574
  let result;
@@ -5583,10 +5583,18 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5583
5583
  }
5584
5584
  const originalExecuteFn = entry.executeWorkflow;
5585
5585
  const wrappedExecuteFn = async (input, runtime) => {
5586
- const { result: result2, cost: trackedCost } = await this.trackCost(async () => {
5586
+ const {
5587
+ result: result2,
5588
+ cost: trackedCost,
5589
+ metadata
5590
+ } = await this.trackExecution(async () => {
5587
5591
  return originalExecuteFn(input, runtime);
5588
5592
  });
5589
- return { output: result2.output, cost: result2.cost ?? trackedCost };
5593
+ return {
5594
+ output: result2.output,
5595
+ cost: result2.cost ?? trackedCost,
5596
+ metadata: result2.metadata ?? metadata
5597
+ };
5590
5598
  };
5591
5599
  result = await runEvalFn(entry.config, wrappedExecuteFn, this);
5592
5600
  } else {
@@ -5595,6 +5603,12 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5595
5603
  );
5596
5604
  }
5597
5605
  const resultObj = result;
5606
+ if (options?.metadata) {
5607
+ resultObj.metadata = {
5608
+ ...resultObj.metadata,
5609
+ ...options.metadata
5610
+ };
5611
+ }
5598
5612
  try {
5599
5613
  await this.saveEvalResult({
5600
5614
  id: resultObj.id ?? (0, import_node_crypto2.randomUUID)(),
@@ -6130,10 +6144,10 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6130
6144
  );
6131
6145
  }
6132
6146
  const executeWorkflow = async (input) => {
6133
- const { result, cost } = await this.trackCost(async () => {
6147
+ const { result, cost, metadata } = await this.trackExecution(async () => {
6134
6148
  return this.execute(config.workflow, input);
6135
6149
  });
6136
- return { output: result, cost };
6150
+ return { output: result, cost, metadata };
6137
6151
  };
6138
6152
  return runEvalFn(config, executeWorkflow, this);
6139
6153
  }
@@ -6143,7 +6157,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6143
6157
  *
6144
6158
  * @see Spec Section 13.6
6145
6159
  */
6146
- async evalCompare(baseline, candidate) {
6160
+ async evalCompare(baseline, candidate, options) {
6147
6161
  let evalCompareFn;
6148
6162
  try {
6149
6163
  ({ evalCompare: evalCompareFn } = await import("@axlsdk/eval"));
@@ -6152,7 +6166,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6152
6166
  "axl-eval is required for AxlRuntime.evalCompare(). Install it with: npm install @axlsdk/eval"
6153
6167
  );
6154
6168
  }
6155
- return evalCompareFn(baseline, candidate);
6169
+ return evalCompareFn(baseline, candidate, options);
6156
6170
  }
6157
6171
  /**
6158
6172
  * Track cost across any runtime operations within the given function.
@@ -6162,24 +6176,58 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6162
6176
  * Works with both `createContext()` and `execute()` calls inside `fn`.
6163
6177
  */
6164
6178
  async trackCost(fn) {
6179
+ const { result, cost } = await this.trackExecution(fn);
6180
+ return { result, cost };
6181
+ }
6182
+ /**
6183
+ * Track cost and execution metadata across any runtime operations within the given function.
6184
+ * Uses AsyncLocalStorage to scope attribution to specific execution IDs,
6185
+ * making it correct with concurrent calls.
6186
+ *
6187
+ * Returns cost (same as `trackCost`) plus metadata extracted from trace events:
6188
+ * models (unique URIs), tokens (input/output/reasoning sums), and agent call count.
6189
+ *
6190
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
6191
+ */
6192
+ async trackExecution(fn) {
6165
6193
  const parentScope = costScopeStorage.getStore();
6166
6194
  const scope = {
6167
6195
  totalCost: 0,
6168
6196
  trackedIds: /* @__PURE__ */ new Set(),
6169
6197
  parent: parentScope
6170
6198
  };
6171
- const costListener = (event) => {
6172
- if (event.cost && scope.trackedIds.has(event.executionId)) {
6173
- scope.totalCost += event.cost;
6199
+ const modelCalls = /* @__PURE__ */ new Map();
6200
+ const tokens = { input: 0, output: 0, reasoning: 0 };
6201
+ let agentCalls = 0;
6202
+ const listener = (event) => {
6203
+ if (!scope.trackedIds.has(event.executionId)) return;
6204
+ if (event.cost) scope.totalCost += event.cost;
6205
+ if (event.type === "agent_call") {
6206
+ if (event.model) modelCalls.set(event.model, (modelCalls.get(event.model) ?? 0) + 1);
6207
+ agentCalls++;
6208
+ if (event.tokens) {
6209
+ tokens.input += event.tokens.input ?? 0;
6210
+ tokens.output += event.tokens.output ?? 0;
6211
+ tokens.reasoning += event.tokens.reasoning ?? 0;
6212
+ }
6174
6213
  }
6175
6214
  };
6176
6215
  this.setMaxListeners(this.getMaxListeners() + 1);
6177
- this.on("trace", costListener);
6216
+ this.on("trace", listener);
6178
6217
  try {
6179
6218
  const result = await costScopeStorage.run(scope, fn);
6180
- return { result, cost: scope.totalCost };
6219
+ return {
6220
+ result,
6221
+ cost: scope.totalCost,
6222
+ metadata: {
6223
+ models: [...modelCalls.keys()],
6224
+ modelCallCounts: modelCalls.size > 0 ? Object.fromEntries(modelCalls) : void 0,
6225
+ tokens,
6226
+ agentCalls
6227
+ }
6228
+ };
6181
6229
  } finally {
6182
- this.off("trace", costListener);
6230
+ this.off("trace", listener);
6183
6231
  this.setMaxListeners(this.getMaxListeners() - 1);
6184
6232
  }
6185
6233
  }