@axlsdk/axl 0.4.0 → 0.5.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/README.md +26 -0
- package/dist/index.cjs +144 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +173 -98
- package/dist/index.d.ts +173 -98
- package/dist/index.js +144 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ const researcher = agent({
|
|
|
43
43
|
model: 'openai:gpt-4o',
|
|
44
44
|
system: 'You are a research assistant.',
|
|
45
45
|
tools: [calculator],
|
|
46
|
+
thinking: 'high',
|
|
46
47
|
maxTurns: 10,
|
|
47
48
|
timeout: '30s',
|
|
48
49
|
temperature: 0.7,
|
|
@@ -61,6 +62,31 @@ const dynamicAgent = agent({
|
|
|
61
62
|
});
|
|
62
63
|
```
|
|
63
64
|
|
|
65
|
+
#### Thinking (cross-provider reasoning control)
|
|
66
|
+
|
|
67
|
+
The `thinking` parameter provides a unified way to control reasoning depth across all providers:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Simple levels — works on any provider
|
|
71
|
+
const reasoner = agent({
|
|
72
|
+
model: 'anthropic:claude-sonnet-4-5',
|
|
73
|
+
system: 'You are a careful analyst.',
|
|
74
|
+
thinking: 'high', // 'low' | 'medium' | 'high' | 'max'
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Explicit budget (in tokens)
|
|
78
|
+
const budgetReasoner = agent({
|
|
79
|
+
model: 'google:gemini-2.5-flash',
|
|
80
|
+
system: 'Think step by step.',
|
|
81
|
+
thinking: { budgetTokens: 5000 },
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Per-call override
|
|
85
|
+
const result = await reasoner.ask('Analyze this data', { thinking: 'low' });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each provider maps `thinking` to its native API: `reasoning_effort` (OpenAI), `budget_tokens` (Anthropic), `thinkingBudget` (Gemini). See [docs/providers.md](../../docs/providers.md) for the full mapping table.
|
|
89
|
+
|
|
64
90
|
### `workflow(config)`
|
|
65
91
|
|
|
66
92
|
Define a named workflow with typed input/output:
|
package/dist/index.cjs
CHANGED
|
@@ -331,6 +331,24 @@ function estimateOpenAICost(model, promptTokens, completionTokens, cachedTokens)
|
|
|
331
331
|
function isReasoningModel(model) {
|
|
332
332
|
return /^(o1|o3|o4-mini)/.test(model);
|
|
333
333
|
}
|
|
334
|
+
function thinkingToReasoningEffort(thinking) {
|
|
335
|
+
if (typeof thinking === "object") {
|
|
336
|
+
const budget = thinking.budgetTokens;
|
|
337
|
+
if (budget <= 1024) return "low";
|
|
338
|
+
if (budget <= 8192) return "medium";
|
|
339
|
+
return "high";
|
|
340
|
+
}
|
|
341
|
+
switch (thinking) {
|
|
342
|
+
case "low":
|
|
343
|
+
return "low";
|
|
344
|
+
case "medium":
|
|
345
|
+
return "medium";
|
|
346
|
+
case "high":
|
|
347
|
+
return "high";
|
|
348
|
+
case "max":
|
|
349
|
+
return "xhigh";
|
|
350
|
+
}
|
|
351
|
+
}
|
|
334
352
|
var OpenAIProvider = class {
|
|
335
353
|
name = "openai";
|
|
336
354
|
baseUrl;
|
|
@@ -433,7 +451,9 @@ var OpenAIProvider = class {
|
|
|
433
451
|
if (options.stop) body.stop = options.stop;
|
|
434
452
|
if (options.tools && options.tools.length > 0) {
|
|
435
453
|
body.tools = options.tools;
|
|
436
|
-
|
|
454
|
+
if (!reasoning) {
|
|
455
|
+
body.parallel_tool_calls = true;
|
|
456
|
+
}
|
|
437
457
|
}
|
|
438
458
|
if (options.toolChoice !== void 0) {
|
|
439
459
|
body.tool_choice = options.toolChoice;
|
|
@@ -441,8 +461,11 @@ var OpenAIProvider = class {
|
|
|
441
461
|
if (options.responseFormat) {
|
|
442
462
|
body.response_format = options.responseFormat;
|
|
443
463
|
}
|
|
444
|
-
if (
|
|
445
|
-
|
|
464
|
+
if (reasoning) {
|
|
465
|
+
const effort = options.thinking ? thinkingToReasoningEffort(options.thinking) : options.reasoningEffort;
|
|
466
|
+
if (effort) {
|
|
467
|
+
body.reasoning_effort = effort;
|
|
468
|
+
}
|
|
446
469
|
}
|
|
447
470
|
if (stream) {
|
|
448
471
|
body.stream_options = { include_usage: true };
|
|
@@ -633,8 +656,11 @@ var OpenAIResponsesProvider = class {
|
|
|
633
656
|
body.tool_choice = options.toolChoice;
|
|
634
657
|
}
|
|
635
658
|
}
|
|
636
|
-
if (
|
|
637
|
-
|
|
659
|
+
if (reasoning) {
|
|
660
|
+
const effort = options.thinking ? thinkingToReasoningEffort(options.thinking) : options.reasoningEffort;
|
|
661
|
+
if (effort) {
|
|
662
|
+
body.reasoning = { effort };
|
|
663
|
+
}
|
|
638
664
|
}
|
|
639
665
|
if (options.responseFormat) {
|
|
640
666
|
body.text = { format: this.mapResponseFormat(options.responseFormat) };
|
|
@@ -868,6 +894,24 @@ function estimateAnthropicCost(model, inputTokens, outputTokens, cacheReadTokens
|
|
|
868
894
|
const inputCost = (inputTokens - cacheRead - cacheWrite) * inputRate + cacheRead * inputRate * 0.1 + cacheWrite * inputRate * 1.25;
|
|
869
895
|
return inputCost + outputTokens * outputRate;
|
|
870
896
|
}
|
|
897
|
+
var THINKING_BUDGETS = {
|
|
898
|
+
low: 1024,
|
|
899
|
+
medium: 5e3,
|
|
900
|
+
high: 1e4,
|
|
901
|
+
// 30000 (not 32000) to stay under the 32K max_tokens limit on Opus 4/4.1.
|
|
902
|
+
// With auto-bump (+1024), max_tokens becomes 31024 which fits all models.
|
|
903
|
+
max: 3e4
|
|
904
|
+
};
|
|
905
|
+
function thinkingToBudgetTokens(thinking) {
|
|
906
|
+
if (typeof thinking === "string") return THINKING_BUDGETS[thinking] ?? 5e3;
|
|
907
|
+
return thinking.budgetTokens;
|
|
908
|
+
}
|
|
909
|
+
function supportsAdaptiveThinking(model) {
|
|
910
|
+
return model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6");
|
|
911
|
+
}
|
|
912
|
+
function supportsMaxEffort(model) {
|
|
913
|
+
return model.startsWith("claude-opus-4-6");
|
|
914
|
+
}
|
|
871
915
|
var AnthropicProvider = class {
|
|
872
916
|
name = "anthropic";
|
|
873
917
|
baseUrl;
|
|
@@ -957,7 +1001,7 @@ var AnthropicProvider = class {
|
|
|
957
1001
|
if (systemText) {
|
|
958
1002
|
body.system = systemText;
|
|
959
1003
|
}
|
|
960
|
-
if (options.temperature !== void 0) {
|
|
1004
|
+
if (options.temperature !== void 0 && !options.thinking) {
|
|
961
1005
|
body.temperature = options.temperature;
|
|
962
1006
|
}
|
|
963
1007
|
if (options.stop) {
|
|
@@ -966,6 +1010,23 @@ var AnthropicProvider = class {
|
|
|
966
1010
|
if (options.tools && options.tools.length > 0) {
|
|
967
1011
|
body.tools = options.tools.map((t) => this.mapToolDefinition(t));
|
|
968
1012
|
}
|
|
1013
|
+
if (options.toolChoice !== void 0) {
|
|
1014
|
+
body.tool_choice = this.mapToolChoice(options.toolChoice);
|
|
1015
|
+
}
|
|
1016
|
+
if (options.thinking) {
|
|
1017
|
+
if (typeof options.thinking === "string" && supportsAdaptiveThinking(options.model) && // 'max' effort is only supported on Opus 4.6; Sonnet 4.6 falls back to manual mode
|
|
1018
|
+
(options.thinking !== "max" || supportsMaxEffort(options.model))) {
|
|
1019
|
+
body.thinking = { type: "adaptive" };
|
|
1020
|
+
body.output_config = { effort: options.thinking };
|
|
1021
|
+
} else {
|
|
1022
|
+
const budgetTokens = thinkingToBudgetTokens(options.thinking);
|
|
1023
|
+
body.thinking = { type: "enabled", budget_tokens: budgetTokens };
|
|
1024
|
+
const currentMax = body.max_tokens;
|
|
1025
|
+
if (currentMax < budgetTokens + 1024) {
|
|
1026
|
+
body.max_tokens = budgetTokens + 1024;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
969
1030
|
if (options.responseFormat && options.responseFormat.type !== "text") {
|
|
970
1031
|
const jsonInstruction = "You must respond with valid JSON only. No markdown fences, no extra text.";
|
|
971
1032
|
body.system = body.system ? `${body.system}
|
|
@@ -1061,6 +1122,22 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
1061
1122
|
input_schema: tool2.function.parameters
|
|
1062
1123
|
};
|
|
1063
1124
|
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Map Axl's ToolChoice to Anthropic's tool_choice format.
|
|
1127
|
+
*
|
|
1128
|
+
* Axl (OpenAI format) → Anthropic format
|
|
1129
|
+
* 'auto' → { type: 'auto' }
|
|
1130
|
+
* 'none' → { type: 'none' }
|
|
1131
|
+
* 'required' → { type: 'any' }
|
|
1132
|
+
* { type:'function', function: { name } } → { type: 'tool', name }
|
|
1133
|
+
*/
|
|
1134
|
+
mapToolChoice(choice) {
|
|
1135
|
+
if (typeof choice === "string") {
|
|
1136
|
+
if (choice === "required") return { type: "any" };
|
|
1137
|
+
return { type: choice };
|
|
1138
|
+
}
|
|
1139
|
+
return { type: "tool", name: choice.function.name };
|
|
1140
|
+
}
|
|
1064
1141
|
// ---------------------------------------------------------------------------
|
|
1065
1142
|
// Internal: response parsing
|
|
1066
1143
|
// ---------------------------------------------------------------------------
|
|
@@ -1238,6 +1315,16 @@ function estimateGeminiCost(model, inputTokens, outputTokens, cachedTokens) {
|
|
|
1238
1315
|
const inputCost = (inputTokens - cached) * inputRate + cached * inputRate * 0.1;
|
|
1239
1316
|
return inputCost + outputTokens * outputRate;
|
|
1240
1317
|
}
|
|
1318
|
+
var THINKING_BUDGETS2 = {
|
|
1319
|
+
low: 1024,
|
|
1320
|
+
medium: 5e3,
|
|
1321
|
+
high: 1e4,
|
|
1322
|
+
max: 24576
|
|
1323
|
+
};
|
|
1324
|
+
function thinkingToBudgetTokens2(thinking) {
|
|
1325
|
+
if (typeof thinking === "string") return THINKING_BUDGETS2[thinking] ?? 5e3;
|
|
1326
|
+
return thinking.budgetTokens;
|
|
1327
|
+
}
|
|
1241
1328
|
var GeminiProvider = class {
|
|
1242
1329
|
name = "google";
|
|
1243
1330
|
baseUrl;
|
|
@@ -1351,6 +1438,17 @@ var GeminiProvider = class {
|
|
|
1351
1438
|
if (Object.keys(generationConfig).length > 0) {
|
|
1352
1439
|
body.generationConfig = generationConfig;
|
|
1353
1440
|
}
|
|
1441
|
+
if (options.thinking) {
|
|
1442
|
+
generationConfig.thinkingConfig = {
|
|
1443
|
+
thinkingBudget: thinkingToBudgetTokens2(options.thinking)
|
|
1444
|
+
};
|
|
1445
|
+
if (!body.generationConfig) {
|
|
1446
|
+
body.generationConfig = generationConfig;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
if (options.toolChoice !== void 0) {
|
|
1450
|
+
body.toolConfig = { functionCallingConfig: this.mapToolChoice(options.toolChoice) };
|
|
1451
|
+
}
|
|
1354
1452
|
return body;
|
|
1355
1453
|
}
|
|
1356
1454
|
/**
|
|
@@ -1442,6 +1540,25 @@ var GeminiProvider = class {
|
|
|
1442
1540
|
}
|
|
1443
1541
|
return merged;
|
|
1444
1542
|
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Map Axl's ToolChoice to Gemini's functionCallingConfig format.
|
|
1545
|
+
*
|
|
1546
|
+
* - 'auto' → { mode: 'AUTO' }
|
|
1547
|
+
* - 'none' → { mode: 'NONE' }
|
|
1548
|
+
* - 'required' → { mode: 'ANY' }
|
|
1549
|
+
* - { type: 'function', function: { name } } → { mode: 'ANY', allowedFunctionNames: [name] }
|
|
1550
|
+
*/
|
|
1551
|
+
mapToolChoice(choice) {
|
|
1552
|
+
if (typeof choice === "string") {
|
|
1553
|
+
const modeMap = {
|
|
1554
|
+
auto: "AUTO",
|
|
1555
|
+
none: "NONE",
|
|
1556
|
+
required: "ANY"
|
|
1557
|
+
};
|
|
1558
|
+
return { mode: modeMap[choice] ?? "AUTO" };
|
|
1559
|
+
}
|
|
1560
|
+
return { mode: "ANY", allowedFunctionNames: [choice.function.name] };
|
|
1561
|
+
}
|
|
1445
1562
|
mapToolDefinition(tool2) {
|
|
1446
1563
|
return {
|
|
1447
1564
|
name: tool2.function.name,
|
|
@@ -2024,7 +2141,13 @@ var WorkflowContext = class {
|
|
|
2024
2141
|
model: agent2.resolveModel(resolveCtx),
|
|
2025
2142
|
cost: costAfter - costBefore,
|
|
2026
2143
|
duration: Date.now() - startTime,
|
|
2027
|
-
promptVersion: agent2._config.version
|
|
2144
|
+
promptVersion: agent2._config.version,
|
|
2145
|
+
temperature: options?.temperature ?? agent2._config.temperature,
|
|
2146
|
+
maxTokens: options?.maxTokens ?? agent2._config.maxTokens ?? 4096,
|
|
2147
|
+
thinking: options?.thinking ?? agent2._config.thinking,
|
|
2148
|
+
reasoningEffort: options?.reasoningEffort ?? agent2._config.reasoningEffort,
|
|
2149
|
+
toolChoice: options?.toolChoice ?? agent2._config.toolChoice,
|
|
2150
|
+
stop: options?.stop ?? agent2._config.stop
|
|
2028
2151
|
});
|
|
2029
2152
|
return result;
|
|
2030
2153
|
});
|
|
@@ -2149,11 +2272,21 @@ Please fix and try again.`;
|
|
|
2149
2272
|
throw new TimeoutError("ctx.ask()", timeoutMs);
|
|
2150
2273
|
}
|
|
2151
2274
|
turns++;
|
|
2275
|
+
const thinking = options?.thinking ?? agent2._config.thinking;
|
|
2276
|
+
if (thinking && typeof thinking === "object" && thinking.budgetTokens <= 0) {
|
|
2277
|
+
throw new Error(
|
|
2278
|
+
`thinking.budgetTokens must be a positive number, got ${thinking.budgetTokens}`
|
|
2279
|
+
);
|
|
2280
|
+
}
|
|
2152
2281
|
const chatOptions = {
|
|
2153
2282
|
model,
|
|
2154
|
-
temperature: agent2._config.temperature,
|
|
2283
|
+
temperature: options?.temperature ?? agent2._config.temperature,
|
|
2155
2284
|
tools: toolDefs.length > 0 ? toolDefs : void 0,
|
|
2156
|
-
maxTokens: 4096,
|
|
2285
|
+
maxTokens: options?.maxTokens ?? agent2._config.maxTokens ?? 4096,
|
|
2286
|
+
thinking,
|
|
2287
|
+
reasoningEffort: options?.reasoningEffort ?? agent2._config.reasoningEffort,
|
|
2288
|
+
toolChoice: options?.toolChoice ?? agent2._config.toolChoice,
|
|
2289
|
+
stop: options?.stop ?? agent2._config.stop,
|
|
2157
2290
|
signal: this.currentSignal
|
|
2158
2291
|
};
|
|
2159
2292
|
if (options?.schema && toolDefs.length === 0) {
|
|
@@ -2252,10 +2385,11 @@ Please fix and try again.`;
|
|
|
2252
2385
|
}
|
|
2253
2386
|
}
|
|
2254
2387
|
const handoffStart = Date.now();
|
|
2388
|
+
const handoffOptions = options ? { schema: options.schema, retries: options.retries, metadata: options.metadata } : void 0;
|
|
2255
2389
|
const handoffFn = () => this.executeAgentCall(
|
|
2256
2390
|
descriptor.agent,
|
|
2257
2391
|
handoffPrompt,
|
|
2258
|
-
|
|
2392
|
+
handoffOptions,
|
|
2259
2393
|
0,
|
|
2260
2394
|
void 0,
|
|
2261
2395
|
void 0,
|