@axlsdk/axl 0.10.4 → 0.11.0
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 +109 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -7
- package/dist/index.d.ts +37 -7
- package/dist/index.js +109 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2281,6 +2281,14 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
2281
2281
|
input;
|
|
2282
2282
|
executionId;
|
|
2283
2283
|
metadata;
|
|
2284
|
+
/**
|
|
2285
|
+
* Total cost accumulated by agent calls in this context.
|
|
2286
|
+
* Inside a `ctx.budget()` block, returns only that block's cost.
|
|
2287
|
+
* After the block completes, the nested cost is rolled up into the parent total.
|
|
2288
|
+
*/
|
|
2289
|
+
get totalCost() {
|
|
2290
|
+
return this.budgetContext?.totalCost ?? 0;
|
|
2291
|
+
}
|
|
2284
2292
|
config;
|
|
2285
2293
|
providerRegistry;
|
|
2286
2294
|
sessionHistory;
|
|
@@ -3780,6 +3788,11 @@ ${summaryResponse.content}`
|
|
|
3780
3788
|
});
|
|
3781
3789
|
return decision2;
|
|
3782
3790
|
}
|
|
3791
|
+
if (!this.pendingDecisions) {
|
|
3792
|
+
throw new Error(
|
|
3793
|
+
"Tool requires approval but no approval handler is configured. Provide awaitHumanHandler to createContext() or use runtime.execute() with workflow infrastructure."
|
|
3794
|
+
);
|
|
3795
|
+
}
|
|
3783
3796
|
if (this.stateStore) {
|
|
3784
3797
|
await this.stateStore.savePendingDecision(this.executionId, {
|
|
3785
3798
|
executionId: this.executionId,
|
|
@@ -3805,7 +3818,7 @@ ${summaryResponse.content}`
|
|
|
3805
3818
|
data: { event: "await_human", channel: options.channel, prompt: options.prompt }
|
|
3806
3819
|
});
|
|
3807
3820
|
const decision = await new Promise((resolve) => {
|
|
3808
|
-
this.pendingDecisions
|
|
3821
|
+
this.pendingDecisions.set(this.executionId, resolve);
|
|
3809
3822
|
});
|
|
3810
3823
|
if (this.stateStore) {
|
|
3811
3824
|
await this.stateStore.saveExecutionState(this.executionId, {
|
|
@@ -4023,6 +4036,7 @@ function workflow(config) {
|
|
|
4023
4036
|
// src/runtime.ts
|
|
4024
4037
|
var import_node_events2 = require("events");
|
|
4025
4038
|
var import_node_crypto2 = require("crypto");
|
|
4039
|
+
var import_node_async_hooks2 = require("async_hooks");
|
|
4026
4040
|
var import_node_fs2 = require("fs");
|
|
4027
4041
|
var import_node_path2 = require("path");
|
|
4028
4042
|
|
|
@@ -5242,6 +5256,7 @@ function hashInput(input) {
|
|
|
5242
5256
|
}
|
|
5243
5257
|
return (hash >>> 0).toString(16);
|
|
5244
5258
|
}
|
|
5259
|
+
var costScopeStorage = new import_node_async_hooks2.AsyncLocalStorage();
|
|
5245
5260
|
var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
5246
5261
|
config;
|
|
5247
5262
|
workflows = /* @__PURE__ */ new Map();
|
|
@@ -5387,8 +5402,14 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5387
5402
|
"axl-eval is required for AxlRuntime.runRegisteredEval(). Install it with: npm install @axlsdk/eval"
|
|
5388
5403
|
);
|
|
5389
5404
|
}
|
|
5390
|
-
const
|
|
5391
|
-
|
|
5405
|
+
const originalExecuteFn = entry.executeWorkflow;
|
|
5406
|
+
const wrappedExecuteFn = async (input, runtime) => {
|
|
5407
|
+
const { result, cost: trackedCost } = await this.trackCost(async () => {
|
|
5408
|
+
return originalExecuteFn(input, runtime);
|
|
5409
|
+
});
|
|
5410
|
+
return { output: result.output, cost: result.cost ?? trackedCost };
|
|
5411
|
+
};
|
|
5412
|
+
return runEvalFn(entry.config, wrappedExecuteFn, void 0, this);
|
|
5392
5413
|
}
|
|
5393
5414
|
return this.eval(
|
|
5394
5415
|
entry.config
|
|
@@ -5399,21 +5420,38 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5399
5420
|
return [...this.executions.values()];
|
|
5400
5421
|
}
|
|
5401
5422
|
/**
|
|
5402
|
-
* Create a
|
|
5403
|
-
* The context has access to the runtime's providers, state store,
|
|
5404
|
-
*
|
|
5423
|
+
* Create a WorkflowContext for ad-hoc use (evals, tool testing, prototyping).
|
|
5424
|
+
* The context has access to the runtime's providers, state store, MCP manager,
|
|
5425
|
+
* and automatically emits trace events and tracks cost.
|
|
5405
5426
|
*/
|
|
5406
5427
|
createContext(options) {
|
|
5428
|
+
const executionId = (0, import_node_crypto2.randomUUID)();
|
|
5429
|
+
const budgetLimit = options?.budget ? parseCost(options.budget) : Infinity;
|
|
5430
|
+
this.registerWithCostScope(executionId);
|
|
5407
5431
|
return new WorkflowContext({
|
|
5408
5432
|
input: void 0,
|
|
5409
|
-
executionId
|
|
5433
|
+
executionId,
|
|
5410
5434
|
metadata: options?.metadata,
|
|
5411
5435
|
config: this.config,
|
|
5412
5436
|
providerRegistry: this.providerRegistry,
|
|
5413
5437
|
stateStore: this.stateStore,
|
|
5414
5438
|
mcpManager: this.mcpManager,
|
|
5415
5439
|
spanManager: this.spanManager,
|
|
5416
|
-
memoryManager: this.memoryManager
|
|
5440
|
+
memoryManager: this.memoryManager,
|
|
5441
|
+
sessionHistory: options?.sessionHistory,
|
|
5442
|
+
signal: options?.signal,
|
|
5443
|
+
onToken: options?.onToken,
|
|
5444
|
+
awaitHumanHandler: options?.awaitHumanHandler,
|
|
5445
|
+
onTrace: (event) => {
|
|
5446
|
+
this.emit("trace", event);
|
|
5447
|
+
this.outputTraceEvent(event);
|
|
5448
|
+
},
|
|
5449
|
+
budgetContext: {
|
|
5450
|
+
totalCost: 0,
|
|
5451
|
+
limit: budgetLimit,
|
|
5452
|
+
exceeded: false,
|
|
5453
|
+
policy: "finish_and_stop"
|
|
5454
|
+
}
|
|
5417
5455
|
});
|
|
5418
5456
|
}
|
|
5419
5457
|
/** Register a custom provider instance. */
|
|
@@ -5432,6 +5470,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5432
5470
|
const executionId = (0, import_node_crypto2.randomUUID)();
|
|
5433
5471
|
const controller = new AbortController();
|
|
5434
5472
|
this.abortControllers.set(executionId, controller);
|
|
5473
|
+
this.registerWithCostScope(executionId);
|
|
5435
5474
|
const execInfo = {
|
|
5436
5475
|
executionId,
|
|
5437
5476
|
workflow: name,
|
|
@@ -5476,7 +5515,13 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5476
5515
|
mcpManager: this.mcpManager,
|
|
5477
5516
|
memoryManager: this.memoryManager,
|
|
5478
5517
|
resumeMode: !!options?.metadata?.resumeMode,
|
|
5479
|
-
spanManager: this.spanManager
|
|
5518
|
+
spanManager: this.spanManager,
|
|
5519
|
+
budgetContext: {
|
|
5520
|
+
totalCost: 0,
|
|
5521
|
+
limit: Infinity,
|
|
5522
|
+
exceeded: false,
|
|
5523
|
+
policy: "finish_and_stop"
|
|
5524
|
+
}
|
|
5480
5525
|
});
|
|
5481
5526
|
ctx.log("workflow_start", { workflow: name, executionId });
|
|
5482
5527
|
return this.spanManager.withSpanAsync(
|
|
@@ -5531,6 +5576,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5531
5576
|
const executionId = (0, import_node_crypto2.randomUUID)();
|
|
5532
5577
|
this.abortControllers.set(executionId, controller);
|
|
5533
5578
|
const sessionHistory = options?.metadata?.sessionHistory ?? void 0;
|
|
5579
|
+
this.registerWithCostScope(executionId);
|
|
5534
5580
|
execInfo = {
|
|
5535
5581
|
executionId,
|
|
5536
5582
|
workflow: name,
|
|
@@ -5621,7 +5667,13 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5621
5667
|
mcpManager: this.mcpManager,
|
|
5622
5668
|
memoryManager: this.memoryManager,
|
|
5623
5669
|
resumeMode: !!options?.metadata?.resumeMode,
|
|
5624
|
-
spanManager: this.spanManager
|
|
5670
|
+
spanManager: this.spanManager,
|
|
5671
|
+
budgetContext: {
|
|
5672
|
+
totalCost: 0,
|
|
5673
|
+
limit: Infinity,
|
|
5674
|
+
exceeded: false,
|
|
5675
|
+
policy: "finish_and_stop"
|
|
5676
|
+
}
|
|
5625
5677
|
});
|
|
5626
5678
|
return this.spanManager.withSpanAsync(
|
|
5627
5679
|
"axl.workflow.execute",
|
|
@@ -5793,28 +5845,21 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5793
5845
|
* @see Spec Section 13.5
|
|
5794
5846
|
*/
|
|
5795
5847
|
async eval(config) {
|
|
5796
|
-
let
|
|
5848
|
+
let runEvalFn;
|
|
5797
5849
|
try {
|
|
5798
|
-
({ runEval } = await import("@axlsdk/eval"));
|
|
5850
|
+
({ runEval: runEvalFn } = await import("@axlsdk/eval"));
|
|
5799
5851
|
} catch {
|
|
5800
5852
|
throw new Error(
|
|
5801
5853
|
"axl-eval is required for AxlRuntime.eval(). Install it with: npm install @axlsdk/eval"
|
|
5802
5854
|
);
|
|
5803
5855
|
}
|
|
5804
5856
|
const executeWorkflow = async (input) => {
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
};
|
|
5809
|
-
this.on("trace", costListener);
|
|
5810
|
-
try {
|
|
5811
|
-
const output = await this.execute(config.workflow, input);
|
|
5812
|
-
return { output, cost };
|
|
5813
|
-
} finally {
|
|
5814
|
-
this.off("trace", costListener);
|
|
5815
|
-
}
|
|
5857
|
+
const { result, cost } = await this.trackCost(async () => {
|
|
5858
|
+
return this.execute(config.workflow, input);
|
|
5859
|
+
});
|
|
5860
|
+
return { output: result, cost };
|
|
5816
5861
|
};
|
|
5817
|
-
return
|
|
5862
|
+
return runEvalFn(config, executeWorkflow, void 0, this);
|
|
5818
5863
|
}
|
|
5819
5864
|
/**
|
|
5820
5865
|
* Compare two evaluation results to detect regressions and improvements.
|
|
@@ -5833,6 +5878,46 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
|
|
|
5833
5878
|
}
|
|
5834
5879
|
return evalCompareFn(baseline, candidate);
|
|
5835
5880
|
}
|
|
5881
|
+
/**
|
|
5882
|
+
* Track cost across any runtime operations within the given function.
|
|
5883
|
+
* Uses AsyncLocalStorage to scope cost attribution to specific execution IDs,
|
|
5884
|
+
* making it correct with concurrent calls.
|
|
5885
|
+
*
|
|
5886
|
+
* Works with both `createContext()` and `execute()` calls inside `fn`.
|
|
5887
|
+
*/
|
|
5888
|
+
async trackCost(fn) {
|
|
5889
|
+
const parentScope = costScopeStorage.getStore();
|
|
5890
|
+
const scope = {
|
|
5891
|
+
totalCost: 0,
|
|
5892
|
+
trackedIds: /* @__PURE__ */ new Set(),
|
|
5893
|
+
parent: parentScope
|
|
5894
|
+
};
|
|
5895
|
+
const costListener = (event) => {
|
|
5896
|
+
if (event.cost && scope.trackedIds.has(event.executionId)) {
|
|
5897
|
+
scope.totalCost += event.cost;
|
|
5898
|
+
}
|
|
5899
|
+
};
|
|
5900
|
+
this.setMaxListeners(this.getMaxListeners() + 1);
|
|
5901
|
+
this.on("trace", costListener);
|
|
5902
|
+
try {
|
|
5903
|
+
const result = await costScopeStorage.run(scope, fn);
|
|
5904
|
+
return { result, cost: scope.totalCost };
|
|
5905
|
+
} finally {
|
|
5906
|
+
this.off("trace", costListener);
|
|
5907
|
+
this.setMaxListeners(this.getMaxListeners() - 1);
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
/** Register an execution ID with the active cost scope for trackCost() attribution. */
|
|
5911
|
+
registerWithCostScope(executionId) {
|
|
5912
|
+
const costScope = costScopeStorage.getStore();
|
|
5913
|
+
if (costScope) {
|
|
5914
|
+
let scope = costScope;
|
|
5915
|
+
while (scope) {
|
|
5916
|
+
scope.trackedIds.add(executionId);
|
|
5917
|
+
scope = scope.parent;
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5836
5921
|
/**
|
|
5837
5922
|
* Handle trace event output based on configuration.
|
|
5838
5923
|
*
|