@absolutejs/ai 0.0.16 → 0.0.18

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
@@ -43,6 +43,111 @@ async function* tapStream(source, params, providerName) {
43
43
  }
44
44
  }
45
45
 
46
+ // src/ai/providers/reasoning.ts
47
+ var EFFORT_ORDER = [
48
+ "minimal",
49
+ "low",
50
+ "medium",
51
+ "high",
52
+ "max"
53
+ ];
54
+ var ANTHROPIC_EFFORT = [
55
+ /opus-4-[5-8]/,
56
+ /sonnet-4-6/,
57
+ /fable-5/,
58
+ /mythos-5/
59
+ ];
60
+ var ANTHROPIC_ADAPTIVE_ONLY = [];
61
+ var ANTHROPIC_LEGACY_THINKING = [
62
+ /sonnet-4-5/,
63
+ /sonnet-4-0/,
64
+ /sonnet-4-2025/,
65
+ /opus-4-0/,
66
+ /opus-4-1/,
67
+ /opus-4-2025/,
68
+ /3-7-sonnet/
69
+ ];
70
+ var ANTHROPIC_NO_SAMPLING = [/opus-4-[78]/, /fable-5/, /mythos-5/];
71
+ var ANTHROPIC_MAX_EFFORT = [
72
+ /opus-4-[678]/,
73
+ /sonnet-4-6/,
74
+ /fable-5/,
75
+ /mythos-5/
76
+ ];
77
+ var OPENAI_REASONING = [/(^|[^a-z])o[1345](-|$)/, /gpt-5/];
78
+ var OPENAI_MINIMAL_EFFORT = [/gpt-5/];
79
+ var matches = (model, patterns) => patterns.some((pattern) => pattern.test(model));
80
+ var anthropicReasoningMode = (model) => {
81
+ if (matches(model, ANTHROPIC_EFFORT))
82
+ return "effort";
83
+ if (matches(model, ANTHROPIC_ADAPTIVE_ONLY))
84
+ return "adaptive";
85
+ if (matches(model, ANTHROPIC_LEGACY_THINKING))
86
+ return "legacy";
87
+ return "none";
88
+ };
89
+ var anthropicSupportsSampling = (model) => !matches(model, ANTHROPIC_NO_SAMPLING);
90
+ var isOpenAIReasoningModel = (model) => matches(model, OPENAI_REASONING);
91
+ var EFFORT_BUDGET = {
92
+ high: 16384,
93
+ low: 2048,
94
+ max: 32768,
95
+ medium: 8192,
96
+ minimal: 1024
97
+ };
98
+ var budgetToEffort = (budget) => {
99
+ if (budget <= 2048)
100
+ return "low";
101
+ if (budget <= 8192)
102
+ return "medium";
103
+ if (budget <= 16384)
104
+ return "high";
105
+ return "max";
106
+ };
107
+ var resolveEffort = (reasoning) => {
108
+ if (reasoning.effort)
109
+ return reasoning.effort;
110
+ if (typeof reasoning.budgetTokens === "number") {
111
+ return budgetToEffort(reasoning.budgetTokens);
112
+ }
113
+ return null;
114
+ };
115
+ var resolveBudgetTokens = (reasoning) => {
116
+ if (typeof reasoning.budgetTokens === "number")
117
+ return reasoning.budgetTokens;
118
+ if (reasoning.effort)
119
+ return EFFORT_BUDGET[reasoning.effort];
120
+ return null;
121
+ };
122
+ var clampEffort = (effort, allowed) => {
123
+ if (allowed.includes(effort))
124
+ return effort;
125
+ const idx = EFFORT_ORDER.indexOf(effort);
126
+ for (let lower = idx - 1;lower >= 0; lower -= 1) {
127
+ const candidate = EFFORT_ORDER[lower];
128
+ if (candidate && allowed.includes(candidate))
129
+ return candidate;
130
+ }
131
+ return allowed[0] ?? effort;
132
+ };
133
+ var anthropicEffortValue = (model, reasoning) => {
134
+ const effort = resolveEffort(reasoning);
135
+ if (!effort)
136
+ return null;
137
+ const allowed = matches(model, ANTHROPIC_MAX_EFFORT) ? ["low", "medium", "high", "max"] : ["low", "medium", "high"];
138
+ return clampEffort(effort, allowed);
139
+ };
140
+ var openaiEffortValue = (model, reasoning) => {
141
+ if (!isOpenAIReasoningModel(model))
142
+ return null;
143
+ const effort = resolveEffort(reasoning);
144
+ if (!effort)
145
+ return null;
146
+ const allowed = matches(model, OPENAI_MINIMAL_EFFORT) ? ["minimal", "low", "medium", "high"] : ["low", "medium", "high"];
147
+ const requested = effort === "max" ? "high" : effort;
148
+ return clampEffort(requested, allowed);
149
+ };
150
+
46
151
  // src/ai/providers/openai.ts
47
152
  var h2IfHttps = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
48
153
  var DEFAULT_BASE_URL = "https://api.openai.com";
@@ -169,12 +274,24 @@ var buildRequestBody = (params) => {
169
274
  body.parallel_tool_calls = params.parallelToolCalls;
170
275
  }
171
276
  }
172
- if (typeof params.temperature === "number")
173
- body.temperature = params.temperature;
174
- if (typeof params.topP === "number")
175
- body.top_p = params.topP;
176
- if (typeof params.maxTokens === "number")
177
- body.max_tokens = params.maxTokens;
277
+ if (isOpenAIReasoningModel(params.model)) {
278
+ if (typeof params.maxTokens === "number") {
279
+ body.max_completion_tokens = params.maxTokens;
280
+ }
281
+ if (params.reasoning) {
282
+ const effort = openaiEffortValue(params.model, params.reasoning);
283
+ if (effort)
284
+ body.reasoning_effort = effort;
285
+ }
286
+ } else {
287
+ if (typeof params.temperature === "number") {
288
+ body.temperature = params.temperature;
289
+ }
290
+ if (typeof params.topP === "number")
291
+ body.top_p = params.topP;
292
+ if (typeof params.maxTokens === "number")
293
+ body.max_tokens = params.maxTokens;
294
+ }
178
295
  if (params.stopSequences && params.stopSequences.length > 0)
179
296
  body.stop = params.stopSequences;
180
297
  if (typeof params.seed === "number")
@@ -591,11 +708,14 @@ var buildRequestBody2 = (params, isImageModel) => {
591
708
  };
592
709
  }
593
710
  }
594
- if (params.thinking) {
595
- body.reasoning = {
596
- effort: "high",
597
- summary: "auto"
598
- };
711
+ if (params.reasoning && isOpenAIReasoningModel(params.model)) {
712
+ const effort = openaiEffortValue(params.model, params.reasoning);
713
+ if (effort) {
714
+ body.reasoning = {
715
+ effort,
716
+ summary: "auto"
717
+ };
718
+ }
599
719
  }
600
720
  return body;
601
721
  };
@@ -1221,7 +1341,13 @@ var buildRequestBody4 = (params) => {
1221
1341
  stream: true
1222
1342
  };
1223
1343
  if (params.systemPrompt) {
1224
- body.system = params.systemPrompt;
1344
+ body.system = params.cacheSystemPrompt ? [
1345
+ {
1346
+ cache_control: { type: "ephemeral" },
1347
+ text: params.systemPrompt,
1348
+ type: "text"
1349
+ }
1350
+ ] : params.systemPrompt;
1225
1351
  }
1226
1352
  if (params.tools && params.tools.length > 0) {
1227
1353
  body.tools = params.tools.map(mapToolDefinition2);
@@ -1233,18 +1359,33 @@ var buildRequestBody4 = (params) => {
1233
1359
  body.tool_choice = { name: params.toolChoice.name, type: "tool" };
1234
1360
  }
1235
1361
  }
1236
- if (typeof params.temperature === "number")
1237
- body.temperature = params.temperature;
1238
- if (typeof params.topP === "number")
1239
- body.top_p = params.topP;
1240
1362
  if (typeof params.maxTokens === "number")
1241
1363
  body.max_tokens = params.maxTokens;
1242
1364
  if (params.stopSequences && params.stopSequences.length > 0) {
1243
1365
  body.stop_sequences = params.stopSequences;
1244
1366
  }
1245
- if (params.thinking) {
1246
- body.thinking = params.thinking;
1247
- body.max_tokens = Math.max(typeof body.max_tokens === "number" ? body.max_tokens : MAX_TOKENS, params.thinking.budget_tokens + MAX_TOKENS);
1367
+ const mode = params.reasoning ? anthropicReasoningMode(params.model) : "none";
1368
+ const thinkingActive = mode !== "none";
1369
+ if (!thinkingActive && anthropicSupportsSampling(params.model)) {
1370
+ if (typeof params.temperature === "number") {
1371
+ body.temperature = params.temperature;
1372
+ }
1373
+ if (typeof params.topP === "number")
1374
+ body.top_p = params.topP;
1375
+ }
1376
+ if (mode === "effort" || mode === "adaptive") {
1377
+ body.thinking = { type: "adaptive" };
1378
+ if (mode === "effort" && params.reasoning) {
1379
+ const effort = anthropicEffortValue(params.model, params.reasoning);
1380
+ if (effort)
1381
+ body.output_config = { effort };
1382
+ }
1383
+ } else if (mode === "legacy" && params.reasoning) {
1384
+ const budget = resolveBudgetTokens(params.reasoning);
1385
+ if (budget) {
1386
+ body.thinking = { budget_tokens: budget, type: "enabled" };
1387
+ body.max_tokens = Math.max(typeof body.max_tokens === "number" ? body.max_tokens : MAX_TOKENS, budget + MAX_TOKENS);
1388
+ }
1248
1389
  }
1249
1390
  return body;
1250
1391
  };
@@ -1383,6 +1524,8 @@ var extractUsage4 = (usageRecord, existingUsage) => {
1383
1524
  return existingUsage;
1384
1525
  }
1385
1526
  return {
1527
+ cacheReadInputTokens: getNumber(usageRecord, "cache_read_input_tokens") || existingUsage?.cacheReadInputTokens || 0,
1528
+ cacheWriteInputTokens: getNumber(usageRecord, "cache_creation_input_tokens") || existingUsage?.cacheWriteInputTokens || 0,
1386
1529
  inputTokens: getNumber(usageRecord, "input_tokens") || existingUsage?.inputTokens || 0,
1387
1530
  outputTokens: getNumber(usageRecord, "output_tokens") || existingUsage?.outputTokens || 0
1388
1531
  };
@@ -1893,7 +2036,6 @@ var WS_OPEN = 1;
1893
2036
  var BACKPRESSURE_THRESHOLD = 1048576;
1894
2037
  var BACKPRESSURE_DELAY = 10;
1895
2038
  var DEFAULT_MAX_TURNS = 10;
1896
- var DEFAULT_THINKING_BUDGET = 1e4;
1897
2039
  var INITIAL_TURN = 0;
1898
2040
  var delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
1899
2041
  var checkBackpressure = async (socket) => {
@@ -2075,16 +2217,12 @@ var processToolTurn = async (socket, options, state, messageId, conversationId,
2075
2217
  role: "user"
2076
2218
  });
2077
2219
  const toolDefs = options.tools ? buildToolDefinitions(options.tools) : undefined;
2078
- const thinkingConfig = options.thinking ? {
2079
- budget_tokens: typeof options.thinking === "object" ? options.thinking.budgetTokens : DEFAULT_THINKING_BUDGET,
2080
- type: "enabled"
2081
- } : undefined;
2082
2220
  const stream = options.provider.stream({
2083
2221
  messages: state.currentMessages,
2084
2222
  model: options.model,
2223
+ reasoning: options.reasoning,
2085
2224
  signal,
2086
2225
  systemPrompt: options.systemPrompt,
2087
- thinking: thinkingConfig,
2088
2226
  tools: toolDefs
2089
2227
  });
2090
2228
  await consumeToolStream(stream, state, options, socket, messageId, conversationId, signal);
@@ -2163,16 +2301,12 @@ var processStreamTextChunk = async (chunk, options, socket, messageId, conversat
2163
2301
  };
2164
2302
  var processStream = async (socket, options, messages, messageId, conversationId, signal, startTime) => {
2165
2303
  const toolDefs = options.tools ? buildToolDefinitions(options.tools) : undefined;
2166
- const thinkingConfig = options.thinking ? {
2167
- budget_tokens: typeof options.thinking === "object" ? options.thinking.budgetTokens : DEFAULT_THINKING_BUDGET,
2168
- type: "enabled"
2169
- } : undefined;
2170
2304
  const stream = options.provider.stream({
2171
2305
  messages,
2172
2306
  model: options.model,
2307
+ reasoning: options.reasoning,
2173
2308
  signal,
2174
2309
  systemPrompt: options.systemPrompt,
2175
- thinking: thinkingConfig,
2176
2310
  tools: toolDefs
2177
2311
  });
2178
2312
  const result = await consumeStream(stream, options, socket, messages, messageId, conversationId, signal);
@@ -2282,7 +2416,6 @@ var handleStreamError = async (socket, err, messageId, conversationId, signal, s
2282
2416
 
2283
2417
  // src/ai/streamAIToSSE.ts
2284
2418
  var DEFAULT_MAX_TURNS2 = 10;
2285
- var DEFAULT_THINKING_BUDGET2 = 1e4;
2286
2419
  var buildToolDefinitions2 = (tools) => Object.entries(tools).map(([name, def]) => ({
2287
2420
  description: def.description,
2288
2421
  input_schema: def.input,
@@ -2299,10 +2432,6 @@ var executeTool2 = async (options, toolName, toolInput) => {
2299
2432
  return `Error: ${err instanceof Error ? err.message : String(err)}`;
2300
2433
  }
2301
2434
  };
2302
- var buildThinkingConfig = (options) => options.thinking ? {
2303
- budget_tokens: typeof options.thinking === "object" ? options.thinking.budgetTokens : DEFAULT_THINKING_BUDGET2,
2304
- type: "enabled"
2305
- } : undefined;
2306
2435
  var serializeToolCall2 = (name, input) => `${name}:${JSON.stringify(input)}`;
2307
2436
  var streamAIToSSE = async function* (conversationId, messageId, options, renderers) {
2308
2437
  const signal = options.signal ?? new AbortController().signal;
@@ -2463,7 +2592,6 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2463
2592
  turn: 0
2464
2593
  };
2465
2594
  const toolDefs = options.tools ? buildToolDefinitions2(options.tools) : undefined;
2466
- const thinkingConfig = buildThinkingConfig(options);
2467
2595
  for (;turnState.turn <= maxTurns && !signal.aborted; turnState.turn++) {
2468
2596
  const chunkState = {
2469
2597
  contentBlocks: [],
@@ -2474,9 +2602,9 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2474
2602
  const stream = options.provider.stream({
2475
2603
  messages: turnState.currentMessages,
2476
2604
  model: options.model,
2605
+ reasoning: options.reasoning,
2477
2606
  signal,
2478
2607
  systemPrompt: options.systemPrompt,
2479
- thinking: thinkingConfig,
2480
2608
  tools: toolDefs
2481
2609
  });
2482
2610
  yield* consumeStream2(stream, chunkState, renderers, options, turnState, signal);
@@ -2632,7 +2760,7 @@ var resolveModel = (config, parsed) => {
2632
2760
  return parsed.providerName;
2633
2761
  };
2634
2762
  var resolveTools = (config, providerName, model) => typeof config.tools === "function" ? config.tools(providerName, model) : config.tools;
2635
- var resolveThinking = (config, providerName, model) => typeof config.thinking === "function" ? config.thinking(providerName, model) : config.thinking;
2763
+ var resolveReasoning = (config, providerName, model) => typeof config.reasoning === "function" ? config.reasoning(providerName, model) : config.reasoning;
2636
2764
  var aiChat = (config) => {
2637
2765
  const path = config.path ?? DEFAULT_PATH;
2638
2766
  const store = config.store ?? createMemoryStore();
@@ -2683,7 +2811,7 @@ var aiChat = (config) => {
2683
2811
  provider: config.provider(providerName),
2684
2812
  signal: controller.signal,
2685
2813
  systemPrompt: config.systemPrompt,
2686
- thinking: resolveThinking(config, providerName, model),
2814
+ reasoning: resolveReasoning(config, providerName, model),
2687
2815
  tools: resolveTools(config, providerName, model),
2688
2816
  onComplete: async (fullResponse, usage) => {
2689
2817
  const conv = await store.get(conversationId);
@@ -2757,7 +2885,7 @@ var aiChat = (config) => {
2757
2885
  provider: config.provider(providerName),
2758
2886
  signal: controller.signal,
2759
2887
  systemPrompt: config.systemPrompt,
2760
- thinking: resolveThinking(config, providerName, model),
2888
+ reasoning: resolveReasoning(config, providerName, model),
2761
2889
  tools: resolveTools(config, providerName, model)
2762
2890
  }, renderers);
2763
2891
  for await (const event of sseStream) {
@@ -2821,9 +2949,11 @@ var aiChat = (config) => {
2821
2949
  var DEFAULT_OBJECT_TOOL_NAME = "respond";
2822
2950
  var generateAI = async (options) => {
2823
2951
  const stream = options.provider.stream({
2952
+ cacheSystemPrompt: options.cacheSystemPrompt,
2824
2953
  maxTokens: options.maxTokens,
2825
2954
  messages: options.messages,
2826
2955
  model: options.model,
2956
+ reasoning: options.reasoning,
2827
2957
  responseFormat: options.responseFormat,
2828
2958
  signal: options.signal,
2829
2959
  stopSequences: options.stopSequences,
@@ -2855,10 +2985,12 @@ var generateObjectAI = async (options) => {
2855
2985
  name: toolName
2856
2986
  };
2857
2987
  const { toolCalls, usage } = await generateAI({
2988
+ cacheSystemPrompt: options.cacheSystemPrompt,
2858
2989
  maxTokens: options.maxTokens,
2859
2990
  messages: options.messages,
2860
2991
  model: options.model,
2861
2992
  provider: options.provider,
2993
+ reasoning: options.reasoning,
2862
2994
  signal: options.signal,
2863
2995
  systemPrompt: options.systemPrompt,
2864
2996
  temperature: options.temperature,
@@ -3725,5 +3857,5 @@ export {
3725
3857
  aiChat
3726
3858
  };
3727
3859
 
3728
- //# debugId=A6D6E7B52873D16664756E2164756E21
3860
+ //# debugId=F448AA17322C183164756E2164756E21
3729
3861
  //# sourceMappingURL=index.js.map