@absolutejs/ai 0.0.23 → 0.0.25

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/ai/index.js CHANGED
@@ -292,12 +292,7 @@ var EFFORT_ORDER = [
292
292
  "high",
293
293
  "max"
294
294
  ];
295
- var ANTHROPIC_EFFORT = [
296
- /opus-4-[5-8]/,
297
- /sonnet-4-6/,
298
- /fable-5/,
299
- /mythos-5/
300
- ];
295
+ var ANTHROPIC_EFFORT = [/opus-4-[5-8]/, /sonnet-4-6/, /fable-5/, /mythos-5/];
301
296
  var ANTHROPIC_ADAPTIVE_ONLY = [];
302
297
  var ANTHROPIC_LEGACY_THINKING = [
303
298
  /sonnet-4-5/,
@@ -1526,7 +1521,7 @@ var gemini = (config2) => {
1526
1521
  var h2IfHttps4 = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
1527
1522
  var DEFAULT_BASE_URL4 = "https://api.anthropic.com";
1528
1523
  var API_VERSION = "2023-06-01";
1529
- var MAX_TOKENS = 8192;
1524
+ var DEFAULT_MAX_TOKENS = 32000;
1530
1525
  var EVENT_PREFIX_LENGTH2 = 7;
1531
1526
  var DATA_PREFIX_LENGTH2 = 6;
1532
1527
  var EMPTY_CHUNKS = [];
@@ -1577,16 +1572,42 @@ var mapToolDefinition2 = (tool) => ({
1577
1572
  input_schema: tool.input_schema,
1578
1573
  name: tool.name
1579
1574
  });
1580
- var buildRequestBody4 = (params) => {
1575
+ var cacheLastContentBlock = (msg) => {
1576
+ const cacheControl = { type: "ephemeral" };
1577
+ if (typeof msg.content === "string") {
1578
+ return {
1579
+ content: [
1580
+ { cache_control: cacheControl, text: msg.content, type: "text" }
1581
+ ],
1582
+ role: msg.role
1583
+ };
1584
+ }
1585
+ if (msg.content.length === 0)
1586
+ return msg;
1587
+ const blocks = [...msg.content];
1588
+ blocks[blocks.length - 1] = {
1589
+ ...blocks[blocks.length - 1],
1590
+ cache_control: cacheControl
1591
+ };
1592
+ return { content: blocks, role: msg.role };
1593
+ };
1594
+ var buildRequestBody4 = (params, configuredMax, promptCaching) => {
1581
1595
  const messages = params.messages.filter((msg) => msg.role !== "system").map(mapMessage);
1596
+ if (promptCaching && messages.length > 1) {
1597
+ const last = messages[messages.length - 1];
1598
+ if (last) {
1599
+ messages[messages.length - 1] = cacheLastContentBlock(last);
1600
+ }
1601
+ }
1602
+ const max = typeof params.maxTokens === "number" ? params.maxTokens : configuredMax;
1582
1603
  const body = {
1583
- max_tokens: MAX_TOKENS,
1604
+ max_tokens: max,
1584
1605
  messages,
1585
1606
  model: params.model,
1586
1607
  stream: true
1587
1608
  };
1588
1609
  if (params.systemPrompt) {
1589
- body.system = params.cacheSystemPrompt ? [
1610
+ body.system = promptCaching || params.cacheSystemPrompt ? [
1590
1611
  {
1591
1612
  cache_control: { type: "ephemeral" },
1592
1613
  text: params.systemPrompt,
@@ -1595,7 +1616,14 @@ var buildRequestBody4 = (params) => {
1595
1616
  ] : params.systemPrompt;
1596
1617
  }
1597
1618
  if (params.tools && params.tools.length > 0) {
1598
- body.tools = params.tools.map(mapToolDefinition2);
1619
+ const tools = params.tools.map(mapToolDefinition2);
1620
+ if (promptCaching) {
1621
+ tools[tools.length - 1] = {
1622
+ ...tools[tools.length - 1],
1623
+ cache_control: { type: "ephemeral" }
1624
+ };
1625
+ }
1626
+ body.tools = tools;
1599
1627
  if (params.toolChoice === "auto" || params.toolChoice === "none") {
1600
1628
  body.tool_choice = { type: params.toolChoice };
1601
1629
  } else if (params.toolChoice === "required") {
@@ -1604,8 +1632,6 @@ var buildRequestBody4 = (params) => {
1604
1632
  body.tool_choice = { name: params.toolChoice.name, type: "tool" };
1605
1633
  }
1606
1634
  }
1607
- if (typeof params.maxTokens === "number")
1608
- body.max_tokens = params.maxTokens;
1609
1635
  if (params.stopSequences && params.stopSequences.length > 0) {
1610
1636
  body.stop_sequences = params.stopSequences;
1611
1637
  }
@@ -1629,7 +1655,7 @@ var buildRequestBody4 = (params) => {
1629
1655
  const budget = resolveBudgetTokens(params.reasoning);
1630
1656
  if (budget) {
1631
1657
  body.thinking = { budget_tokens: budget, type: "enabled" };
1632
- body.max_tokens = Math.max(typeof body.max_tokens === "number" ? body.max_tokens : MAX_TOKENS, budget + MAX_TOKENS);
1658
+ body.max_tokens = Math.max(max, budget + max);
1633
1659
  }
1634
1660
  }
1635
1661
  return body;
@@ -1778,6 +1804,10 @@ var extractUsage4 = (usageRecord, existingUsage) => {
1778
1804
  var handleMessageDelta = (parsed, state) => {
1779
1805
  const deltaUsage = getRecord(parsed, "usage");
1780
1806
  state.usage = extractUsage4(deltaUsage, state.usage);
1807
+ const delta = getRecord(parsed, "delta");
1808
+ const stopReason = delta ? getString(delta, "stop_reason") : "";
1809
+ if (stopReason)
1810
+ state.stopReason = stopReason;
1781
1811
  };
1782
1812
  var handleMessageStart = (parsed, state) => {
1783
1813
  const message = getRecord(parsed, "message");
@@ -1820,7 +1850,11 @@ var processEvent = (eventType, parsed, state) => {
1820
1850
  return;
1821
1851
  }
1822
1852
  case "message_stop": {
1823
- return { type: "done", usage: state.usage };
1853
+ return {
1854
+ stopReason: state.stopReason,
1855
+ type: "done",
1856
+ usage: state.usage
1857
+ };
1824
1858
  }
1825
1859
  case "error": {
1826
1860
  handleError(parsed);
@@ -1896,6 +1930,7 @@ async function* parseSSEStream4(body, signal) {
1896
1930
  currentToolId: "",
1897
1931
  currentToolName: "",
1898
1932
  isThinkingBlock: false,
1933
+ stopReason: "",
1899
1934
  thinkingSignature: "",
1900
1935
  toolInputJson: "",
1901
1936
  usage: undefined
@@ -1906,8 +1941,8 @@ async function* parseSSEStream4(body, signal) {
1906
1941
  reader.releaseLock();
1907
1942
  }
1908
1943
  }
1909
- var fetchAndStream = async function* (baseUrl, config2, params) {
1910
- const body = buildRequestBody4(params);
1944
+ var fetchAndStream = async function* (baseUrl, config2, params, configuredMax, promptCaching) {
1945
+ const body = buildRequestBody4(params, configuredMax, promptCaching);
1911
1946
  const target = `${baseUrl}/v1/messages`;
1912
1947
  const response = await fetch(target, {
1913
1948
  ...h2IfHttps4(target),
@@ -1935,8 +1970,10 @@ var fetchAndStream = async function* (baseUrl, config2, params) {
1935
1970
  };
1936
1971
  var anthropic = (config2) => {
1937
1972
  const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL4;
1973
+ const configuredMax = config2.maxTokens ?? DEFAULT_MAX_TOKENS;
1974
+ const promptCaching = config2.promptCaching ?? true;
1938
1975
  return instrumentAIProvider({
1939
- stream: (params) => fetchAndStream(baseUrl, config2, params)
1976
+ stream: (params) => fetchAndStream(baseUrl, config2, params, configuredMax, promptCaching)
1940
1977
  }, "anthropic");
1941
1978
  };
1942
1979
 
@@ -2790,9 +2827,21 @@ var processChunk2 = function* (chunk, chunkState, renderers, options, fullRespon
2790
2827
  case "done":
2791
2828
  maybeFlushThinking(chunkState);
2792
2829
  chunkState.usage = chunk.usage;
2830
+ chunkState.stopReason = chunk.stopReason;
2793
2831
  break;
2794
2832
  }
2795
2833
  };
2834
+ var truncateToolResult = (result, max) => {
2835
+ if (result.length <= max)
2836
+ return result;
2837
+ const omitted = result.length - max;
2838
+ const headLen = Math.ceil(max / 2);
2839
+ const tailLen = max - headLen;
2840
+ const marker = `
2841
+ <result truncated to ${max} chars; ${omitted} omitted \u2014 re-read a narrower slice if needed>
2842
+ `;
2843
+ return result.slice(0, headLen) + marker + result.slice(result.length - tailLen);
2844
+ };
2796
2845
  var executeToolCalls = async function* (pendingToolCalls, options, renderers, turnState) {
2797
2846
  const toolResultBlocks = [];
2798
2847
  for (const toolCall of pendingToolCalls) {
@@ -2802,8 +2851,9 @@ var executeToolCalls = async function* (pendingToolCalls, options, renderers, tu
2802
2851
  turnState.allToolsHtml = turnState.allToolsHtml.replace(renderers.toolRunning(toolCall.name, toolCall.input), renderers.toolComplete(toolCall.name, result));
2803
2852
  yield { data: turnState.allToolsHtml, event: "tools" };
2804
2853
  options.onToolUse?.(toolCall.name, toolCall.input, result);
2854
+ const resultContent = options.maxToolResultChars !== undefined ? truncateToolResult(result, options.maxToolResultChars) : result;
2805
2855
  toolResultBlocks.push({
2806
- content: result,
2856
+ content: resultContent,
2807
2857
  tool_use_id: toolCall.id,
2808
2858
  type: "tool_result"
2809
2859
  });
@@ -2848,14 +2898,17 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2848
2898
  turn: 0
2849
2899
  };
2850
2900
  const toolDefs = options.tools ? buildToolDefinitions2(options.tools) : undefined;
2901
+ let runningTotalTokens = 0;
2851
2902
  for (;turnState.turn <= maxTurns && !signal.aborted; turnState.turn++) {
2852
2903
  const chunkState = {
2853
2904
  contentBlocks: [],
2854
2905
  currentThinking: null,
2855
2906
  pendingToolCalls: [],
2907
+ stopReason: undefined,
2856
2908
  usage: undefined
2857
2909
  };
2858
2910
  const stream = options.provider.stream({
2911
+ maxTokens: options.maxTokens,
2859
2912
  messages: turnState.currentMessages,
2860
2913
  model: options.model,
2861
2914
  reasoning: options.reasoning,
@@ -2864,6 +2917,29 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2864
2917
  tools: toolDefs
2865
2918
  });
2866
2919
  yield* consumeStream2(stream, chunkState, renderers, options, turnState, signal);
2920
+ options.onTurn?.(turnState.turn, chunkState.usage);
2921
+ runningTotalTokens += (chunkState.usage?.inputTokens ?? 0) + (chunkState.usage?.outputTokens ?? 0);
2922
+ if (chunkState.stopReason === "max_tokens") {
2923
+ yield {
2924
+ data: renderers.error(`Response truncated at max_tokens (output=${chunkState.usage?.outputTokens ?? "?"}). ` + `Raise maxTokens on the provider/options, split the request, or reduce upstream context.`),
2925
+ event: "status"
2926
+ };
2927
+ return;
2928
+ }
2929
+ if (options.maxTotalTokens && runningTotalTokens >= options.maxTotalTokens) {
2930
+ yield {
2931
+ data: renderers.error(`Stopped: token budget reached (${runningTotalTokens}/${options.maxTotalTokens} tokens over ` + `${turnState.turn} turns). Narrow the request or raise maxTotalTokens.`),
2932
+ event: "status"
2933
+ };
2934
+ return;
2935
+ }
2936
+ if (options.maxDurationMs && Date.now() - startTime >= options.maxDurationMs) {
2937
+ yield {
2938
+ data: renderers.error(`Stopped: time budget reached (${Math.round((Date.now() - startTime) / 1000)}s over ` + `${turnState.turn} turns). Narrow the request or raise maxDurationMs.`),
2939
+ event: "status"
2940
+ };
2941
+ return;
2942
+ }
2867
2943
  if (shouldStopToolLoop(chunkState, turnState, signal)) {
2868
2944
  return void (yield yieldCompletion(renderers, options, turnState.fullResponse, chunkState.usage, startTime));
2869
2945
  }
@@ -3253,7 +3329,12 @@ var toProviderTools = (tools) => Object.entries(tools).map(([name, definition])
3253
3329
  name
3254
3330
  }));
3255
3331
  var generateAIWithTools = async (options) => {
3256
- const { maxTurns = DEFAULT_TOOL_MAX_TURNS, onToolUse, tools, ...base } = options;
3332
+ const {
3333
+ maxTurns = DEFAULT_TOOL_MAX_TURNS,
3334
+ onToolUse,
3335
+ tools,
3336
+ ...base
3337
+ } = options;
3257
3338
  const providerTools = toProviderTools(tools);
3258
3339
  const toolCalls = [];
3259
3340
  let usage;
@@ -4283,5 +4364,5 @@ export {
4283
4364
  PROVIDER_STATUS_PAGES
4284
4365
  };
4285
4366
 
4286
- //# debugId=E077A15D83F1F94464756E2164756E21
4367
+ //# debugId=A76D544D382AA89A64756E2164756E21
4287
4368
  //# sourceMappingURL=index.js.map