@axlsdk/axl 0.10.4 → 0.11.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
@@ -969,6 +969,12 @@ declare class WorkflowContext<TInput = unknown> {
969
969
  readonly input: TInput;
970
970
  readonly executionId: string;
971
971
  readonly metadata: Record<string, unknown>;
972
+ /**
973
+ * Total cost accumulated by agent calls in this context.
974
+ * Inside a `ctx.budget()` block, returns only that block's cost.
975
+ * After the block completes, the nested cost is rolled up into the parent total.
976
+ */
977
+ get totalCost(): number;
972
978
  private config;
973
979
  private providerRegistry;
974
980
  private sessionHistory;
@@ -1236,6 +1242,19 @@ declare class Session {
1236
1242
  type ExecuteOptions = {
1237
1243
  metadata?: Record<string, unknown>;
1238
1244
  };
1245
+ type CreateContextOptions = {
1246
+ metadata?: Record<string, unknown>;
1247
+ /** Cost budget for the context (e.g., '$0.50'). Enforced via finish_and_stop policy. */
1248
+ budget?: string;
1249
+ /** Abort signal for cancellation/timeouts. */
1250
+ signal?: AbortSignal;
1251
+ /** Prior conversation history for multi-turn eval testing. */
1252
+ sessionHistory?: ChatMessage[];
1253
+ /** Token streaming callback. */
1254
+ onToken?: (token: string) => void;
1255
+ /** Handler for tool approval requests. Called when an agent invokes a tool with requireApproval. */
1256
+ awaitHumanHandler?: (options: AwaitHumanOptions) => Promise<HumanDecision>;
1257
+ };
1239
1258
  /**
1240
1259
  * The main entry point for executing Axl workflows.
1241
1260
  * Manages workflow registration, provider resolution, state storage, tracing, MCP servers,
@@ -1320,13 +1339,11 @@ declare class AxlRuntime extends EventEmitter {
1320
1339
  /** Get all execution info (running + completed). */
1321
1340
  getExecutions(): ExecutionInfo[];
1322
1341
  /**
1323
- * Create a lightweight WorkflowContext for ad-hoc use (tool testing, prototyping).
1324
- * The context has access to the runtime's providers, state store, and MCP manager
1325
- * but no session history, streaming callbacks, or budget tracking.
1342
+ * Create a WorkflowContext for ad-hoc use (evals, tool testing, prototyping).
1343
+ * The context has access to the runtime's providers, state store, MCP manager,
1344
+ * and automatically emits trace events and tracks cost.
1326
1345
  */
1327
- createContext(options?: {
1328
- metadata?: Record<string, unknown>;
1329
- }): WorkflowContext;
1346
+ createContext(options?: CreateContextOptions): WorkflowContext;
1330
1347
  /** Register a custom provider instance. */
1331
1348
  registerProvider(name: string, provider: Provider): void;
1332
1349
  /** Execute a workflow and return the result. */
@@ -1385,6 +1402,19 @@ declare class AxlRuntime extends EventEmitter {
1385
1402
  * @see Spec Section 13.6
1386
1403
  */
1387
1404
  evalCompare(baseline: unknown, candidate: unknown): Promise<unknown>;
1405
+ /**
1406
+ * Track cost across any runtime operations within the given function.
1407
+ * Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
1408
+ * making it correct with concurrent calls.
1409
+ *
1410
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
1411
+ */
1412
+ trackCost<T>(fn: () => Promise<T>): Promise<{
1413
+ result: T;
1414
+ cost: number;
1415
+ }>;
1416
+ /** Register an execution ID with the active cost scope for trackCost() attribution. */
1417
+ private registerWithCostScope;
1388
1418
  /**
1389
1419
  * Handle trace event output based on configuration.
1390
1420
  *
@@ -1847,4 +1877,4 @@ declare class NoopSpanManager implements SpanManager {
1847
1877
  */
1848
1878
  declare function createSpanManager(config?: TelemetryConfig): Promise<SpanManager>;
1849
1879
 
1850
- export { type Agent, type AgentCallInfo, type AgentConfig, AnthropicProvider, type AskOptions, type AwaitHumanOptions, type AxlConfig, AxlError, AxlRuntime, AxlStream, BudgetExceededError, type BudgetOptions, type BudgetResult, type ChatMessage, type ChatOptions, type DelegateOptions, type Effort, type Embedder, type ExecutionInfo, type ExecutionState, GeminiProvider, type GuardrailBlockHandler, GuardrailError, type GuardrailResult, type GuardrailsConfig, type HandoffDescriptor, type HandoffRecord, type HumanDecision, InMemoryVectorStore, type InputGuardrail, type MapOptions, MaxTurnsError, McpManager, type McpServer, type McpServerConfig, type McpToolDefinition, type McpToolResult, type MemoryConfig, MemoryManager, MemoryStore, NoConsensus, NoopSpanManager, OpenAIEmbedder, OpenAIProvider, OpenAIResponsesProvider, type OutputGuardrail, type OutputValidator, type PendingDecision, type Provider, type ProviderAdapter, ProviderRegistry, type ProviderResponse, QuorumNotMet, type RaceOptions, type RecallOptions, RedisStore, type RememberOptions, type ResolvedThinkingOptions, type Result, type RetryPolicy, SQLiteStore, Session, type SessionOptions, type SpanHandle, type SpanManager, type SpawnOptions, SqliteVectorStore, type StateStore, type StreamChunk, type StreamEvent, type TelemetryConfig, TimeoutError, type Tool, type ToolCallMessage, type ToolChoice, type ToolConfig, ToolDenied, type ToolHooks, type TraceEvent, type ValidateResult, ValidationError, type VectorEntry, type VectorResult, type VectorStore, VerifyError, type VerifyOptions, type VerifyRetry, type VoteOptions, type Workflow, type WorkflowConfig, WorkflowContext, type WorkflowContextInit, agent, createSpanManager, defineConfig, resolveThinkingOptions, tool, workflow, zodToJsonSchema };
1880
+ export { type Agent, type AgentCallInfo, type AgentConfig, AnthropicProvider, type AskOptions, type AwaitHumanOptions, type AxlConfig, AxlError, AxlRuntime, AxlStream, BudgetExceededError, type BudgetOptions, type BudgetResult, type ChatMessage, type ChatOptions, type CreateContextOptions, type DelegateOptions, type Effort, type Embedder, type ExecutionInfo, type ExecutionState, GeminiProvider, type GuardrailBlockHandler, GuardrailError, type GuardrailResult, type GuardrailsConfig, type HandoffDescriptor, type HandoffRecord, type HumanDecision, InMemoryVectorStore, type InputGuardrail, type MapOptions, MaxTurnsError, McpManager, type McpServer, type McpServerConfig, type McpToolDefinition, type McpToolResult, type MemoryConfig, MemoryManager, MemoryStore, NoConsensus, NoopSpanManager, OpenAIEmbedder, OpenAIProvider, OpenAIResponsesProvider, type OutputGuardrail, type OutputValidator, type PendingDecision, type Provider, type ProviderAdapter, ProviderRegistry, type ProviderResponse, QuorumNotMet, type RaceOptions, type RecallOptions, RedisStore, type RememberOptions, type ResolvedThinkingOptions, type Result, type RetryPolicy, SQLiteStore, Session, type SessionOptions, type SpanHandle, type SpanManager, type SpawnOptions, SqliteVectorStore, type StateStore, type StreamChunk, type StreamEvent, type TelemetryConfig, TimeoutError, type Tool, type ToolCallMessage, type ToolChoice, type ToolConfig, ToolDenied, type ToolHooks, type TraceEvent, type ValidateResult, ValidationError, type VectorEntry, type VectorResult, type VectorStore, VerifyError, type VerifyOptions, type VerifyRetry, type VoteOptions, type Workflow, type WorkflowConfig, WorkflowContext, type WorkflowContextInit, agent, createSpanManager, defineConfig, resolveThinkingOptions, tool, workflow, zodToJsonSchema };
package/dist/index.d.ts CHANGED
@@ -969,6 +969,12 @@ declare class WorkflowContext<TInput = unknown> {
969
969
  readonly input: TInput;
970
970
  readonly executionId: string;
971
971
  readonly metadata: Record<string, unknown>;
972
+ /**
973
+ * Total cost accumulated by agent calls in this context.
974
+ * Inside a `ctx.budget()` block, returns only that block's cost.
975
+ * After the block completes, the nested cost is rolled up into the parent total.
976
+ */
977
+ get totalCost(): number;
972
978
  private config;
973
979
  private providerRegistry;
974
980
  private sessionHistory;
@@ -1236,6 +1242,19 @@ declare class Session {
1236
1242
  type ExecuteOptions = {
1237
1243
  metadata?: Record<string, unknown>;
1238
1244
  };
1245
+ type CreateContextOptions = {
1246
+ metadata?: Record<string, unknown>;
1247
+ /** Cost budget for the context (e.g., '$0.50'). Enforced via finish_and_stop policy. */
1248
+ budget?: string;
1249
+ /** Abort signal for cancellation/timeouts. */
1250
+ signal?: AbortSignal;
1251
+ /** Prior conversation history for multi-turn eval testing. */
1252
+ sessionHistory?: ChatMessage[];
1253
+ /** Token streaming callback. */
1254
+ onToken?: (token: string) => void;
1255
+ /** Handler for tool approval requests. Called when an agent invokes a tool with requireApproval. */
1256
+ awaitHumanHandler?: (options: AwaitHumanOptions) => Promise<HumanDecision>;
1257
+ };
1239
1258
  /**
1240
1259
  * The main entry point for executing Axl workflows.
1241
1260
  * Manages workflow registration, provider resolution, state storage, tracing, MCP servers,
@@ -1320,13 +1339,11 @@ declare class AxlRuntime extends EventEmitter {
1320
1339
  /** Get all execution info (running + completed). */
1321
1340
  getExecutions(): ExecutionInfo[];
1322
1341
  /**
1323
- * Create a lightweight WorkflowContext for ad-hoc use (tool testing, prototyping).
1324
- * The context has access to the runtime's providers, state store, and MCP manager
1325
- * but no session history, streaming callbacks, or budget tracking.
1342
+ * Create a WorkflowContext for ad-hoc use (evals, tool testing, prototyping).
1343
+ * The context has access to the runtime's providers, state store, MCP manager,
1344
+ * and automatically emits trace events and tracks cost.
1326
1345
  */
1327
- createContext(options?: {
1328
- metadata?: Record<string, unknown>;
1329
- }): WorkflowContext;
1346
+ createContext(options?: CreateContextOptions): WorkflowContext;
1330
1347
  /** Register a custom provider instance. */
1331
1348
  registerProvider(name: string, provider: Provider): void;
1332
1349
  /** Execute a workflow and return the result. */
@@ -1385,6 +1402,19 @@ declare class AxlRuntime extends EventEmitter {
1385
1402
  * @see Spec Section 13.6
1386
1403
  */
1387
1404
  evalCompare(baseline: unknown, candidate: unknown): Promise<unknown>;
1405
+ /**
1406
+ * Track cost across any runtime operations within the given function.
1407
+ * Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
1408
+ * making it correct with concurrent calls.
1409
+ *
1410
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
1411
+ */
1412
+ trackCost<T>(fn: () => Promise<T>): Promise<{
1413
+ result: T;
1414
+ cost: number;
1415
+ }>;
1416
+ /** Register an execution ID with the active cost scope for trackCost() attribution. */
1417
+ private registerWithCostScope;
1388
1418
  /**
1389
1419
  * Handle trace event output based on configuration.
1390
1420
  *
@@ -1847,4 +1877,4 @@ declare class NoopSpanManager implements SpanManager {
1847
1877
  */
1848
1878
  declare function createSpanManager(config?: TelemetryConfig): Promise<SpanManager>;
1849
1879
 
1850
- export { type Agent, type AgentCallInfo, type AgentConfig, AnthropicProvider, type AskOptions, type AwaitHumanOptions, type AxlConfig, AxlError, AxlRuntime, AxlStream, BudgetExceededError, type BudgetOptions, type BudgetResult, type ChatMessage, type ChatOptions, type DelegateOptions, type Effort, type Embedder, type ExecutionInfo, type ExecutionState, GeminiProvider, type GuardrailBlockHandler, GuardrailError, type GuardrailResult, type GuardrailsConfig, type HandoffDescriptor, type HandoffRecord, type HumanDecision, InMemoryVectorStore, type InputGuardrail, type MapOptions, MaxTurnsError, McpManager, type McpServer, type McpServerConfig, type McpToolDefinition, type McpToolResult, type MemoryConfig, MemoryManager, MemoryStore, NoConsensus, NoopSpanManager, OpenAIEmbedder, OpenAIProvider, OpenAIResponsesProvider, type OutputGuardrail, type OutputValidator, type PendingDecision, type Provider, type ProviderAdapter, ProviderRegistry, type ProviderResponse, QuorumNotMet, type RaceOptions, type RecallOptions, RedisStore, type RememberOptions, type ResolvedThinkingOptions, type Result, type RetryPolicy, SQLiteStore, Session, type SessionOptions, type SpanHandle, type SpanManager, type SpawnOptions, SqliteVectorStore, type StateStore, type StreamChunk, type StreamEvent, type TelemetryConfig, TimeoutError, type Tool, type ToolCallMessage, type ToolChoice, type ToolConfig, ToolDenied, type ToolHooks, type TraceEvent, type ValidateResult, ValidationError, type VectorEntry, type VectorResult, type VectorStore, VerifyError, type VerifyOptions, type VerifyRetry, type VoteOptions, type Workflow, type WorkflowConfig, WorkflowContext, type WorkflowContextInit, agent, createSpanManager, defineConfig, resolveThinkingOptions, tool, workflow, zodToJsonSchema };
1880
+ export { type Agent, type AgentCallInfo, type AgentConfig, AnthropicProvider, type AskOptions, type AwaitHumanOptions, type AxlConfig, AxlError, AxlRuntime, AxlStream, BudgetExceededError, type BudgetOptions, type BudgetResult, type ChatMessage, type ChatOptions, type CreateContextOptions, type DelegateOptions, type Effort, type Embedder, type ExecutionInfo, type ExecutionState, GeminiProvider, type GuardrailBlockHandler, GuardrailError, type GuardrailResult, type GuardrailsConfig, type HandoffDescriptor, type HandoffRecord, type HumanDecision, InMemoryVectorStore, type InputGuardrail, type MapOptions, MaxTurnsError, McpManager, type McpServer, type McpServerConfig, type McpToolDefinition, type McpToolResult, type MemoryConfig, MemoryManager, MemoryStore, NoConsensus, NoopSpanManager, OpenAIEmbedder, OpenAIProvider, OpenAIResponsesProvider, type OutputGuardrail, type OutputValidator, type PendingDecision, type Provider, type ProviderAdapter, ProviderRegistry, type ProviderResponse, QuorumNotMet, type RaceOptions, type RecallOptions, RedisStore, type RememberOptions, type ResolvedThinkingOptions, type Result, type RetryPolicy, SQLiteStore, Session, type SessionOptions, type SpanHandle, type SpanManager, type SpawnOptions, SqliteVectorStore, type StateStore, type StreamChunk, type StreamEvent, type TelemetryConfig, TimeoutError, type Tool, type ToolCallMessage, type ToolChoice, type ToolConfig, ToolDenied, type ToolHooks, type TraceEvent, type ValidateResult, ValidationError, type VectorEntry, type VectorResult, type VectorStore, VerifyError, type VerifyOptions, type VerifyRetry, type VoteOptions, type Workflow, type WorkflowConfig, WorkflowContext, type WorkflowContextInit, agent, createSpanManager, defineConfig, resolveThinkingOptions, tool, workflow, zodToJsonSchema };
package/dist/index.js CHANGED
@@ -2135,6 +2135,14 @@ var WorkflowContext = class _WorkflowContext {
2135
2135
  input;
2136
2136
  executionId;
2137
2137
  metadata;
2138
+ /**
2139
+ * Total cost accumulated by agent calls in this context.
2140
+ * Inside a `ctx.budget()` block, returns only that block's cost.
2141
+ * After the block completes, the nested cost is rolled up into the parent total.
2142
+ */
2143
+ get totalCost() {
2144
+ return this.budgetContext?.totalCost ?? 0;
2145
+ }
2138
2146
  config;
2139
2147
  providerRegistry;
2140
2148
  sessionHistory;
@@ -3634,6 +3642,11 @@ ${summaryResponse.content}`
3634
3642
  });
3635
3643
  return decision2;
3636
3644
  }
3645
+ if (!this.pendingDecisions) {
3646
+ throw new Error(
3647
+ "Tool requires approval but no approval handler is configured. Provide awaitHumanHandler to createContext() or use runtime.execute() with workflow infrastructure."
3648
+ );
3649
+ }
3637
3650
  if (this.stateStore) {
3638
3651
  await this.stateStore.savePendingDecision(this.executionId, {
3639
3652
  executionId: this.executionId,
@@ -3659,7 +3672,7 @@ ${summaryResponse.content}`
3659
3672
  data: { event: "await_human", channel: options.channel, prompt: options.prompt }
3660
3673
  });
3661
3674
  const decision = await new Promise((resolve) => {
3662
- this.pendingDecisions?.set(this.executionId, resolve);
3675
+ this.pendingDecisions.set(this.executionId, resolve);
3663
3676
  });
3664
3677
  if (this.stateStore) {
3665
3678
  await this.stateStore.saveExecutionState(this.executionId, {
@@ -3877,6 +3890,7 @@ function workflow(config) {
3877
3890
  // src/runtime.ts
3878
3891
  import { EventEmitter as EventEmitter2 } from "events";
3879
3892
  import { randomUUID as randomUUID2 } from "crypto";
3893
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3880
3894
  import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
3881
3895
  import { dirname } from "path";
3882
3896
 
@@ -5095,6 +5109,7 @@ function hashInput(input) {
5095
5109
  }
5096
5110
  return (hash >>> 0).toString(16);
5097
5111
  }
5112
+ var costScopeStorage = new AsyncLocalStorage2();
5098
5113
  var AxlRuntime = class extends EventEmitter2 {
5099
5114
  config;
5100
5115
  workflows = /* @__PURE__ */ new Map();
@@ -5240,8 +5255,14 @@ var AxlRuntime = class extends EventEmitter2 {
5240
5255
  "axl-eval is required for AxlRuntime.runRegisteredEval(). Install it with: npm install @axlsdk/eval"
5241
5256
  );
5242
5257
  }
5243
- const executeFn = entry.executeWorkflow;
5244
- return runEvalFn(entry.config, executeFn, void 0, this);
5258
+ const originalExecuteFn = entry.executeWorkflow;
5259
+ const wrappedExecuteFn = async (input, runtime) => {
5260
+ const { result, cost: trackedCost } = await this.trackCost(async () => {
5261
+ return originalExecuteFn(input, runtime);
5262
+ });
5263
+ return { output: result.output, cost: result.cost ?? trackedCost };
5264
+ };
5265
+ return runEvalFn(entry.config, wrappedExecuteFn, void 0, this);
5245
5266
  }
5246
5267
  return this.eval(
5247
5268
  entry.config
@@ -5252,21 +5273,38 @@ var AxlRuntime = class extends EventEmitter2 {
5252
5273
  return [...this.executions.values()];
5253
5274
  }
5254
5275
  /**
5255
- * Create a lightweight WorkflowContext for ad-hoc use (tool testing, prototyping).
5256
- * The context has access to the runtime's providers, state store, and MCP manager
5257
- * but no session history, streaming callbacks, or budget tracking.
5276
+ * Create a WorkflowContext for ad-hoc use (evals, tool testing, prototyping).
5277
+ * The context has access to the runtime's providers, state store, MCP manager,
5278
+ * and automatically emits trace events and tracks cost.
5258
5279
  */
5259
5280
  createContext(options) {
5281
+ const executionId = randomUUID2();
5282
+ const budgetLimit = options?.budget ? parseCost(options.budget) : Infinity;
5283
+ this.registerWithCostScope(executionId);
5260
5284
  return new WorkflowContext({
5261
5285
  input: void 0,
5262
- executionId: randomUUID2(),
5286
+ executionId,
5263
5287
  metadata: options?.metadata,
5264
5288
  config: this.config,
5265
5289
  providerRegistry: this.providerRegistry,
5266
5290
  stateStore: this.stateStore,
5267
5291
  mcpManager: this.mcpManager,
5268
5292
  spanManager: this.spanManager,
5269
- memoryManager: this.memoryManager
5293
+ memoryManager: this.memoryManager,
5294
+ sessionHistory: options?.sessionHistory,
5295
+ signal: options?.signal,
5296
+ onToken: options?.onToken,
5297
+ awaitHumanHandler: options?.awaitHumanHandler,
5298
+ onTrace: (event) => {
5299
+ this.emit("trace", event);
5300
+ this.outputTraceEvent(event);
5301
+ },
5302
+ budgetContext: {
5303
+ totalCost: 0,
5304
+ limit: budgetLimit,
5305
+ exceeded: false,
5306
+ policy: "finish_and_stop"
5307
+ }
5270
5308
  });
5271
5309
  }
5272
5310
  /** Register a custom provider instance. */
@@ -5285,6 +5323,7 @@ var AxlRuntime = class extends EventEmitter2 {
5285
5323
  const executionId = randomUUID2();
5286
5324
  const controller = new AbortController();
5287
5325
  this.abortControllers.set(executionId, controller);
5326
+ this.registerWithCostScope(executionId);
5288
5327
  const execInfo = {
5289
5328
  executionId,
5290
5329
  workflow: name,
@@ -5329,7 +5368,13 @@ var AxlRuntime = class extends EventEmitter2 {
5329
5368
  mcpManager: this.mcpManager,
5330
5369
  memoryManager: this.memoryManager,
5331
5370
  resumeMode: !!options?.metadata?.resumeMode,
5332
- spanManager: this.spanManager
5371
+ spanManager: this.spanManager,
5372
+ budgetContext: {
5373
+ totalCost: 0,
5374
+ limit: Infinity,
5375
+ exceeded: false,
5376
+ policy: "finish_and_stop"
5377
+ }
5333
5378
  });
5334
5379
  ctx.log("workflow_start", { workflow: name, executionId });
5335
5380
  return this.spanManager.withSpanAsync(
@@ -5384,6 +5429,7 @@ var AxlRuntime = class extends EventEmitter2 {
5384
5429
  const executionId = randomUUID2();
5385
5430
  this.abortControllers.set(executionId, controller);
5386
5431
  const sessionHistory = options?.metadata?.sessionHistory ?? void 0;
5432
+ this.registerWithCostScope(executionId);
5387
5433
  execInfo = {
5388
5434
  executionId,
5389
5435
  workflow: name,
@@ -5474,7 +5520,13 @@ var AxlRuntime = class extends EventEmitter2 {
5474
5520
  mcpManager: this.mcpManager,
5475
5521
  memoryManager: this.memoryManager,
5476
5522
  resumeMode: !!options?.metadata?.resumeMode,
5477
- spanManager: this.spanManager
5523
+ spanManager: this.spanManager,
5524
+ budgetContext: {
5525
+ totalCost: 0,
5526
+ limit: Infinity,
5527
+ exceeded: false,
5528
+ policy: "finish_and_stop"
5529
+ }
5478
5530
  });
5479
5531
  return this.spanManager.withSpanAsync(
5480
5532
  "axl.workflow.execute",
@@ -5646,28 +5698,21 @@ var AxlRuntime = class extends EventEmitter2 {
5646
5698
  * @see Spec Section 13.5
5647
5699
  */
5648
5700
  async eval(config) {
5649
- let runEval;
5701
+ let runEvalFn;
5650
5702
  try {
5651
- ({ runEval } = await import("@axlsdk/eval"));
5703
+ ({ runEval: runEvalFn } = await import("@axlsdk/eval"));
5652
5704
  } catch {
5653
5705
  throw new Error(
5654
5706
  "axl-eval is required for AxlRuntime.eval(). Install it with: npm install @axlsdk/eval"
5655
5707
  );
5656
5708
  }
5657
5709
  const executeWorkflow = async (input) => {
5658
- let cost = 0;
5659
- const costListener = (event) => {
5660
- if (event.cost) cost += event.cost;
5661
- };
5662
- this.on("trace", costListener);
5663
- try {
5664
- const output = await this.execute(config.workflow, input);
5665
- return { output, cost };
5666
- } finally {
5667
- this.off("trace", costListener);
5668
- }
5710
+ const { result, cost } = await this.trackCost(async () => {
5711
+ return this.execute(config.workflow, input);
5712
+ });
5713
+ return { output: result, cost };
5669
5714
  };
5670
- return runEval(config, executeWorkflow, void 0, this);
5715
+ return runEvalFn(config, executeWorkflow, void 0, this);
5671
5716
  }
5672
5717
  /**
5673
5718
  * Compare two evaluation results to detect regressions and improvements.
@@ -5686,6 +5731,46 @@ var AxlRuntime = class extends EventEmitter2 {
5686
5731
  }
5687
5732
  return evalCompareFn(baseline, candidate);
5688
5733
  }
5734
+ /**
5735
+ * Track cost across any runtime operations within the given function.
5736
+ * Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
5737
+ * making it correct with concurrent calls.
5738
+ *
5739
+ * Works with both `createContext()` and `execute()` calls inside `fn`.
5740
+ */
5741
+ async trackCost(fn) {
5742
+ const parentScope = costScopeStorage.getStore();
5743
+ const scope = {
5744
+ totalCost: 0,
5745
+ trackedIds: /* @__PURE__ */ new Set(),
5746
+ parent: parentScope
5747
+ };
5748
+ const costListener = (event) => {
5749
+ if (event.cost && scope.trackedIds.has(event.executionId)) {
5750
+ scope.totalCost += event.cost;
5751
+ }
5752
+ };
5753
+ this.setMaxListeners(this.getMaxListeners() + 1);
5754
+ this.on("trace", costListener);
5755
+ try {
5756
+ const result = await costScopeStorage.run(scope, fn);
5757
+ return { result, cost: scope.totalCost };
5758
+ } finally {
5759
+ this.off("trace", costListener);
5760
+ this.setMaxListeners(this.getMaxListeners() - 1);
5761
+ }
5762
+ }
5763
+ /** Register an execution ID with the active cost scope for trackCost() attribution. */
5764
+ registerWithCostScope(executionId) {
5765
+ const costScope = costScopeStorage.getStore();
5766
+ if (costScope) {
5767
+ let scope = costScope;
5768
+ while (scope) {
5769
+ scope.trackedIds.add(executionId);
5770
+ scope = scope.parent;
5771
+ }
5772
+ }
5773
+ }
5689
5774
  /**
5690
5775
  * Handle trace event output based on configuration.
5691
5776
  *