@axlsdk/axl 0.3.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/dist/index.js CHANGED
@@ -187,6 +187,24 @@ function estimateOpenAICost(model, promptTokens, completionTokens, cachedTokens)
187
187
  function isReasoningModel(model) {
188
188
  return /^(o1|o3|o4-mini)/.test(model);
189
189
  }
190
+ function thinkingToReasoningEffort(thinking) {
191
+ if (typeof thinking === "object") {
192
+ const budget = thinking.budgetTokens;
193
+ if (budget <= 1024) return "low";
194
+ if (budget <= 8192) return "medium";
195
+ return "high";
196
+ }
197
+ switch (thinking) {
198
+ case "low":
199
+ return "low";
200
+ case "medium":
201
+ return "medium";
202
+ case "high":
203
+ return "high";
204
+ case "max":
205
+ return "xhigh";
206
+ }
207
+ }
190
208
  var OpenAIProvider = class {
191
209
  name = "openai";
192
210
  baseUrl;
@@ -289,7 +307,9 @@ var OpenAIProvider = class {
289
307
  if (options.stop) body.stop = options.stop;
290
308
  if (options.tools && options.tools.length > 0) {
291
309
  body.tools = options.tools;
292
- body.parallel_tool_calls = true;
310
+ if (!reasoning) {
311
+ body.parallel_tool_calls = true;
312
+ }
293
313
  }
294
314
  if (options.toolChoice !== void 0) {
295
315
  body.tool_choice = options.toolChoice;
@@ -297,8 +317,11 @@ var OpenAIProvider = class {
297
317
  if (options.responseFormat) {
298
318
  body.response_format = options.responseFormat;
299
319
  }
300
- if (options.reasoningEffort) {
301
- body.reasoning_effort = options.reasoningEffort;
320
+ if (reasoning) {
321
+ const effort = options.thinking ? thinkingToReasoningEffort(options.thinking) : options.reasoningEffort;
322
+ if (effort) {
323
+ body.reasoning_effort = effort;
324
+ }
302
325
  }
303
326
  if (stream) {
304
327
  body.stream_options = { include_usage: true };
@@ -489,8 +512,11 @@ var OpenAIResponsesProvider = class {
489
512
  body.tool_choice = options.toolChoice;
490
513
  }
491
514
  }
492
- if (options.reasoningEffort) {
493
- body.reasoning = { effort: options.reasoningEffort };
515
+ if (reasoning) {
516
+ const effort = options.thinking ? thinkingToReasoningEffort(options.thinking) : options.reasoningEffort;
517
+ if (effort) {
518
+ body.reasoning = { effort };
519
+ }
494
520
  }
495
521
  if (options.responseFormat) {
496
522
  body.text = { format: this.mapResponseFormat(options.responseFormat) };
@@ -724,6 +750,24 @@ function estimateAnthropicCost(model, inputTokens, outputTokens, cacheReadTokens
724
750
  const inputCost = (inputTokens - cacheRead - cacheWrite) * inputRate + cacheRead * inputRate * 0.1 + cacheWrite * inputRate * 1.25;
725
751
  return inputCost + outputTokens * outputRate;
726
752
  }
753
+ var THINKING_BUDGETS = {
754
+ low: 1024,
755
+ medium: 5e3,
756
+ high: 1e4,
757
+ // 30000 (not 32000) to stay under the 32K max_tokens limit on Opus 4/4.1.
758
+ // With auto-bump (+1024), max_tokens becomes 31024 which fits all models.
759
+ max: 3e4
760
+ };
761
+ function thinkingToBudgetTokens(thinking) {
762
+ if (typeof thinking === "string") return THINKING_BUDGETS[thinking] ?? 5e3;
763
+ return thinking.budgetTokens;
764
+ }
765
+ function supportsAdaptiveThinking(model) {
766
+ return model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6");
767
+ }
768
+ function supportsMaxEffort(model) {
769
+ return model.startsWith("claude-opus-4-6");
770
+ }
727
771
  var AnthropicProvider = class {
728
772
  name = "anthropic";
729
773
  baseUrl;
@@ -813,7 +857,7 @@ var AnthropicProvider = class {
813
857
  if (systemText) {
814
858
  body.system = systemText;
815
859
  }
816
- if (options.temperature !== void 0) {
860
+ if (options.temperature !== void 0 && !options.thinking) {
817
861
  body.temperature = options.temperature;
818
862
  }
819
863
  if (options.stop) {
@@ -822,6 +866,23 @@ var AnthropicProvider = class {
822
866
  if (options.tools && options.tools.length > 0) {
823
867
  body.tools = options.tools.map((t) => this.mapToolDefinition(t));
824
868
  }
869
+ if (options.toolChoice !== void 0) {
870
+ body.tool_choice = this.mapToolChoice(options.toolChoice);
871
+ }
872
+ if (options.thinking) {
873
+ 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
874
+ (options.thinking !== "max" || supportsMaxEffort(options.model))) {
875
+ body.thinking = { type: "adaptive" };
876
+ body.output_config = { effort: options.thinking };
877
+ } else {
878
+ const budgetTokens = thinkingToBudgetTokens(options.thinking);
879
+ body.thinking = { type: "enabled", budget_tokens: budgetTokens };
880
+ const currentMax = body.max_tokens;
881
+ if (currentMax < budgetTokens + 1024) {
882
+ body.max_tokens = budgetTokens + 1024;
883
+ }
884
+ }
885
+ }
825
886
  if (options.responseFormat && options.responseFormat.type !== "text") {
826
887
  const jsonInstruction = "You must respond with valid JSON only. No markdown fences, no extra text.";
827
888
  body.system = body.system ? `${body.system}
@@ -917,6 +978,22 @@ ${jsonInstruction}` : jsonInstruction;
917
978
  input_schema: tool2.function.parameters
918
979
  };
919
980
  }
981
+ /**
982
+ * Map Axl's ToolChoice to Anthropic's tool_choice format.
983
+ *
984
+ * Axl (OpenAI format) → Anthropic format
985
+ * 'auto' → { type: 'auto' }
986
+ * 'none' → { type: 'none' }
987
+ * 'required' → { type: 'any' }
988
+ * { type:'function', function: { name } } → { type: 'tool', name }
989
+ */
990
+ mapToolChoice(choice) {
991
+ if (typeof choice === "string") {
992
+ if (choice === "required") return { type: "any" };
993
+ return { type: choice };
994
+ }
995
+ return { type: "tool", name: choice.function.name };
996
+ }
920
997
  // ---------------------------------------------------------------------------
921
998
  // Internal: response parsing
922
999
  // ---------------------------------------------------------------------------
@@ -1094,6 +1171,16 @@ function estimateGeminiCost(model, inputTokens, outputTokens, cachedTokens) {
1094
1171
  const inputCost = (inputTokens - cached) * inputRate + cached * inputRate * 0.1;
1095
1172
  return inputCost + outputTokens * outputRate;
1096
1173
  }
1174
+ var THINKING_BUDGETS2 = {
1175
+ low: 1024,
1176
+ medium: 5e3,
1177
+ high: 1e4,
1178
+ max: 24576
1179
+ };
1180
+ function thinkingToBudgetTokens2(thinking) {
1181
+ if (typeof thinking === "string") return THINKING_BUDGETS2[thinking] ?? 5e3;
1182
+ return thinking.budgetTokens;
1183
+ }
1097
1184
  var GeminiProvider = class {
1098
1185
  name = "google";
1099
1186
  baseUrl;
@@ -1207,6 +1294,17 @@ var GeminiProvider = class {
1207
1294
  if (Object.keys(generationConfig).length > 0) {
1208
1295
  body.generationConfig = generationConfig;
1209
1296
  }
1297
+ if (options.thinking) {
1298
+ generationConfig.thinkingConfig = {
1299
+ thinkingBudget: thinkingToBudgetTokens2(options.thinking)
1300
+ };
1301
+ if (!body.generationConfig) {
1302
+ body.generationConfig = generationConfig;
1303
+ }
1304
+ }
1305
+ if (options.toolChoice !== void 0) {
1306
+ body.toolConfig = { functionCallingConfig: this.mapToolChoice(options.toolChoice) };
1307
+ }
1210
1308
  return body;
1211
1309
  }
1212
1310
  /**
@@ -1298,6 +1396,25 @@ var GeminiProvider = class {
1298
1396
  }
1299
1397
  return merged;
1300
1398
  }
1399
+ /**
1400
+ * Map Axl's ToolChoice to Gemini's functionCallingConfig format.
1401
+ *
1402
+ * - 'auto' → { mode: 'AUTO' }
1403
+ * - 'none' → { mode: 'NONE' }
1404
+ * - 'required' → { mode: 'ANY' }
1405
+ * - { type: 'function', function: { name } } → { mode: 'ANY', allowedFunctionNames: [name] }
1406
+ */
1407
+ mapToolChoice(choice) {
1408
+ if (typeof choice === "string") {
1409
+ const modeMap = {
1410
+ auto: "AUTO",
1411
+ none: "NONE",
1412
+ required: "ANY"
1413
+ };
1414
+ return { mode: modeMap[choice] ?? "AUTO" };
1415
+ }
1416
+ return { mode: "ANY", allowedFunctionNames: [choice.function.name] };
1417
+ }
1301
1418
  mapToolDefinition(tool2) {
1302
1419
  return {
1303
1420
  name: tool2.function.name,
@@ -1746,6 +1863,15 @@ function zodToJsonSchema(schema) {
1746
1863
  function estimateTokens(text) {
1747
1864
  return Math.ceil(text.length / 4);
1748
1865
  }
1866
+ function stripMarkdownFences(text) {
1867
+ const trimmed = text.trim();
1868
+ if (trimmed.startsWith("```")) {
1869
+ const withoutOpening = trimmed.replace(/^```\w*\s*\n?/, "");
1870
+ const withoutClosing = withoutOpening.replace(/\n?```\s*$/, "");
1871
+ return withoutClosing.trim();
1872
+ }
1873
+ return trimmed;
1874
+ }
1749
1875
  function estimateMessagesTokens(messages) {
1750
1876
  let total = 0;
1751
1877
  for (const msg of messages) {
@@ -1871,7 +1997,13 @@ var WorkflowContext = class {
1871
1997
  model: agent2.resolveModel(resolveCtx),
1872
1998
  cost: costAfter - costBefore,
1873
1999
  duration: Date.now() - startTime,
1874
- promptVersion: agent2._config.version
2000
+ promptVersion: agent2._config.version,
2001
+ temperature: options?.temperature ?? agent2._config.temperature,
2002
+ maxTokens: options?.maxTokens ?? agent2._config.maxTokens ?? 4096,
2003
+ thinking: options?.thinking ?? agent2._config.thinking,
2004
+ reasoningEffort: options?.reasoningEffort ?? agent2._config.reasoningEffort,
2005
+ toolChoice: options?.toolChoice ?? agent2._config.toolChoice,
2006
+ stop: options?.stop ?? agent2._config.stop
1875
2007
  });
1876
2008
  return result;
1877
2009
  });
@@ -1996,11 +2128,21 @@ Please fix and try again.`;
1996
2128
  throw new TimeoutError("ctx.ask()", timeoutMs);
1997
2129
  }
1998
2130
  turns++;
2131
+ const thinking = options?.thinking ?? agent2._config.thinking;
2132
+ if (thinking && typeof thinking === "object" && thinking.budgetTokens <= 0) {
2133
+ throw new Error(
2134
+ `thinking.budgetTokens must be a positive number, got ${thinking.budgetTokens}`
2135
+ );
2136
+ }
1999
2137
  const chatOptions = {
2000
2138
  model,
2001
- temperature: agent2._config.temperature,
2139
+ temperature: options?.temperature ?? agent2._config.temperature,
2002
2140
  tools: toolDefs.length > 0 ? toolDefs : void 0,
2003
- maxTokens: 4096,
2141
+ maxTokens: options?.maxTokens ?? agent2._config.maxTokens ?? 4096,
2142
+ thinking,
2143
+ reasoningEffort: options?.reasoningEffort ?? agent2._config.reasoningEffort,
2144
+ toolChoice: options?.toolChoice ?? agent2._config.toolChoice,
2145
+ stop: options?.stop ?? agent2._config.stop,
2004
2146
  signal: this.currentSignal
2005
2147
  };
2006
2148
  if (options?.schema && toolDefs.length === 0) {
@@ -2099,10 +2241,11 @@ Please fix and try again.`;
2099
2241
  }
2100
2242
  }
2101
2243
  const handoffStart = Date.now();
2244
+ const handoffOptions = options ? { schema: options.schema, retries: options.retries, metadata: options.metadata } : void 0;
2102
2245
  const handoffFn = () => this.executeAgentCall(
2103
2246
  descriptor.agent,
2104
2247
  handoffPrompt,
2105
- options,
2248
+ handoffOptions,
2106
2249
  0,
2107
2250
  void 0,
2108
2251
  void 0,
@@ -2439,7 +2582,7 @@ Please fix and try again.`;
2439
2582
  }
2440
2583
  if (options?.schema) {
2441
2584
  try {
2442
- const parsed = JSON.parse(content);
2585
+ const parsed = JSON.parse(stripMarkdownFences(content));
2443
2586
  const validated = options.schema.parse(parsed);
2444
2587
  return validated;
2445
2588
  } catch (err) {