@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/README.md CHANGED
@@ -303,6 +303,8 @@ const result = await runtime.execute('my-workflow', { query: 'Hello' });
303
303
  const stream = runtime.stream('my-workflow', { query: 'Hello' });
304
304
  for await (const event of stream) {
305
305
  if (event.type === 'token') process.stdout.write(event.data);
306
+ if (event.type === 'error') console.error('Stream error:', event.message);
307
+ if (event.type === 'done') console.log('Result:', event.data);
306
308
  }
307
309
 
308
310
  // Sessions
package/dist/index.cjs CHANGED
@@ -2838,7 +2838,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2838
2838
  });
2839
2839
  continue;
2840
2840
  }
2841
- this.onToolCall?.({ name: toolName, args: toolArgs2 });
2841
+ this.onToolCall?.({ name: toolName, args: toolArgs2, callId: toolCall.id });
2842
2842
  const toolStart2 = Date.now();
2843
2843
  const executeOverride = async () => {
2844
2844
  let toolResult3;
@@ -2871,7 +2871,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2871
2871
  agent: agent2._name,
2872
2872
  tool: toolName,
2873
2873
  duration: Date.now() - toolStart2,
2874
- data: { args: toolArgs2, result: toolResult2 }
2874
+ data: { args: toolArgs2, result: toolResult2, callId: toolCall.id }
2875
2875
  });
2876
2876
  currentMessages.push({
2877
2877
  role: "tool",
@@ -2902,7 +2902,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
2902
2902
  });
2903
2903
  continue;
2904
2904
  }
2905
- this.onToolCall?.({ name: toolName, args: toolArgs });
2905
+ this.onToolCall?.({ name: toolName, args: toolArgs, callId: toolCall.id });
2906
2906
  const toolStart = Date.now();
2907
2907
  if (tool2 && tool2.requireApproval) {
2908
2908
  const approvalFn = async () => {
@@ -3031,7 +3031,7 @@ ${JSON.stringify(jsonSchema, null, 2)}`;
3031
3031
  agent: agent2._name,
3032
3032
  tool: traceName,
3033
3033
  duration: Date.now() - toolStart,
3034
- data: { args: toolArgs, result: toolResult }
3034
+ data: { args: toolArgs, result: toolResult, callId: toolCall.id }
3035
3035
  });
3036
3036
  currentMessages.push({
3037
3037
  role: "tool",
@@ -4742,6 +4742,8 @@ var AxlStream = class _AxlStream extends import_node_stream.Readable {
4742
4742
  this.bus.on("__reject", (error) => rejectPromise(error));
4743
4743
  this.bus.on("error", () => {
4744
4744
  });
4745
+ this.promise.catch(() => {
4746
+ });
4745
4747
  }
4746
4748
  static STREAM_EVENTS = /* @__PURE__ */ new Set([
4747
4749
  "token",
@@ -4887,9 +4889,16 @@ var AxlStream = class _AxlStream extends import_node_stream.Readable {
4887
4889
  _error(error) {
4888
4890
  if (this.finished) return;
4889
4891
  this.finished = true;
4890
- const errorEvent = { type: "error", error };
4892
+ const errorEvent = { type: "error", message: error.message };
4891
4893
  this.bus.emit("error", errorEvent);
4894
+ this.push(errorEvent);
4892
4895
  this.push(null);
4896
+ const waiter = this.waiters.shift();
4897
+ if (waiter) {
4898
+ waiter({ value: errorEvent, done: false });
4899
+ } else {
4900
+ this.eventQueue.push(errorEvent);
4901
+ }
4893
4902
  for (const w of this.waiters) {
4894
4903
  w({ value: void 0, done: true });
4895
4904
  }
@@ -5559,7 +5568,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5559
5568
  return this.registeredEvals.get(name);
5560
5569
  }
5561
5570
  /** Run a registered eval by name. */
5562
- async runRegisteredEval(name) {
5571
+ async runRegisteredEval(name, options) {
5563
5572
  const entry = this.registeredEvals.get(name);
5564
5573
  if (!entry) throw new Error(`Eval "${name}" is not registered`);
5565
5574
  let result;
@@ -5574,10 +5583,18 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5574
5583
  }
5575
5584
  const originalExecuteFn = entry.executeWorkflow;
5576
5585
  const wrappedExecuteFn = async (input, runtime) => {
5577
- const { result: result2, cost: trackedCost } = await this.trackCost(async () => {
5586
+ const {
5587
+ result: result2,
5588
+ cost: trackedCost,
5589
+ metadata
5590
+ } = await this.trackExecution(async () => {
5578
5591
  return originalExecuteFn(input, runtime);
5579
5592
  });
5580
- 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
+ };
5581
5598
  };
5582
5599
  result = await runEvalFn(entry.config, wrappedExecuteFn, this);
5583
5600
  } else {
@@ -5586,6 +5603,12 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5586
5603
  );
5587
5604
  }
5588
5605
  const resultObj = result;
5606
+ if (options?.metadata) {
5607
+ resultObj.metadata = {
5608
+ ...resultObj.metadata,
5609
+ ...options.metadata
5610
+ };
5611
+ }
5589
5612
  try {
5590
5613
  await this.saveEvalResult({
5591
5614
  id: resultObj.id ?? (0, import_node_crypto2.randomUUID)(),
@@ -5742,6 +5765,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5742
5765
  execInfo.status = "completed";
5743
5766
  execInfo.completedAt = Date.now();
5744
5767
  execInfo.duration = execInfo.completedAt - execInfo.startedAt;
5768
+ execInfo.result = output;
5745
5769
  ctx.log("workflow_end", {
5746
5770
  workflow: name,
5747
5771
  status: "completed",
@@ -5854,7 +5878,8 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5854
5878
  axlStream._push({
5855
5879
  type: "tool_result",
5856
5880
  name: event.tool ?? "",
5857
- result: event.data?.result
5881
+ result: event.data?.result,
5882
+ callId: event.data?.callId
5858
5883
  });
5859
5884
  }
5860
5885
  axlStream._push({ type: "step", step: event.step, data: event });
@@ -5863,7 +5888,12 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5863
5888
  axlStream._push({ type: "token", data: token });
5864
5889
  },
5865
5890
  onToolCall: (call) => {
5866
- axlStream._push({ type: "tool_call", name: call.name, args: call.args });
5891
+ axlStream._push({
5892
+ type: "tool_call",
5893
+ name: call.name,
5894
+ args: call.args,
5895
+ callId: call.callId
5896
+ });
5867
5897
  },
5868
5898
  onAgentStart: (info) => {
5869
5899
  axlStream._push({ type: "agent_start", agent: info.agent, model: info.model });
@@ -5897,6 +5927,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
5897
5927
  execInfo.status = "completed";
5898
5928
  execInfo.completedAt = Date.now();
5899
5929
  execInfo.duration = execInfo.completedAt - execInfo.startedAt;
5930
+ execInfo.result = result;
5900
5931
  wfCtx.log("workflow_end", {
5901
5932
  workflow: name,
5902
5933
  status: "completed",
@@ -6113,10 +6144,10 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6113
6144
  );
6114
6145
  }
6115
6146
  const executeWorkflow = async (input) => {
6116
- const { result, cost } = await this.trackCost(async () => {
6147
+ const { result, cost, metadata } = await this.trackExecution(async () => {
6117
6148
  return this.execute(config.workflow, input);
6118
6149
  });
6119
- return { output: result, cost };
6150
+ return { output: result, cost, metadata };
6120
6151
  };
6121
6152
  return runEvalFn(config, executeWorkflow, this);
6122
6153
  }
@@ -6126,7 +6157,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6126
6157
  *
6127
6158
  * @see Spec Section 13.6
6128
6159
  */
6129
- async evalCompare(baseline, candidate) {
6160
+ async evalCompare(baseline, candidate, options) {
6130
6161
  let evalCompareFn;
6131
6162
  try {
6132
6163
  ({ evalCompare: evalCompareFn } = await import("@axlsdk/eval"));
@@ -6135,7 +6166,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6135
6166
  "axl-eval is required for AxlRuntime.evalCompare(). Install it with: npm install @axlsdk/eval"
6136
6167
  );
6137
6168
  }
6138
- return evalCompareFn(baseline, candidate);
6169
+ return evalCompareFn(baseline, candidate, options);
6139
6170
  }
6140
6171
  /**
6141
6172
  * Track cost across any runtime operations within the given function.
@@ -6145,24 +6176,58 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
6145
6176
  * Works with both `createContext()` and `execute()` calls inside `fn`.
6146
6177
  */
6147
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) {
6148
6193
  const parentScope = costScopeStorage.getStore();
6149
6194
  const scope = {
6150
6195
  totalCost: 0,
6151
6196
  trackedIds: /* @__PURE__ */ new Set(),
6152
6197
  parent: parentScope
6153
6198
  };
6154
- const costListener = (event) => {
6155
- if (event.cost && scope.trackedIds.has(event.executionId)) {
6156
- 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
+ }
6157
6213
  }
6158
6214
  };
6159
6215
  this.setMaxListeners(this.getMaxListeners() + 1);
6160
- this.on("trace", costListener);
6216
+ this.on("trace", listener);
6161
6217
  try {
6162
6218
  const result = await costScopeStorage.run(scope, fn);
6163
- 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
+ };
6164
6229
  } finally {
6165
- this.off("trace", costListener);
6230
+ this.off("trace", listener);
6166
6231
  this.setMaxListeners(this.getMaxListeners() - 1);
6167
6232
  }
6168
6233
  }