extrait 0.5.5 → 0.6.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
@@ -1228,6 +1228,17 @@ async function executeMCPToolCalls(calls, toolset, context) {
1228
1228
  remoteName: tool.remoteName,
1229
1229
  clientId: tool.clientId
1230
1230
  }) : rawArgs;
1231
+ const toolParams = context.request.transformToolCallParams ? await context.request.transformToolCallParams({
1232
+ name: tool.remoteName,
1233
+ arguments: args
1234
+ }, {
1235
+ name: toolName,
1236
+ remoteName: tool.remoteName,
1237
+ clientId: tool.clientId
1238
+ }) : {
1239
+ name: tool.remoteName,
1240
+ arguments: args
1241
+ };
1231
1242
  const metadata = {
1232
1243
  id: callId,
1233
1244
  type: call.type ?? "function",
@@ -1237,10 +1248,7 @@ async function executeMCPToolCalls(calls, toolset, context) {
1237
1248
  const startedAt = new Date().toISOString();
1238
1249
  const startedAtMs = Date.now();
1239
1250
  try {
1240
- const output = await tool.client.callTool({
1241
- name: tool.remoteName,
1242
- arguments: args
1243
- });
1251
+ const output = await tool.client.callTool(toolParams);
1244
1252
  const executionContext = {
1245
1253
  callId,
1246
1254
  type: call.type ?? "function",
@@ -1564,6 +1572,7 @@ function createOpenAICompatibleAdapter(options) {
1564
1572
  model: options.model,
1565
1573
  messages: buildMessages(request),
1566
1574
  temperature: request.temperature,
1575
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1567
1576
  max_tokens: request.maxTokens,
1568
1577
  stream: true
1569
1578
  })),
@@ -1575,6 +1584,7 @@ function createOpenAICompatibleAdapter(options) {
1575
1584
  }
1576
1585
  callbacks.onStart?.();
1577
1586
  let text = "";
1587
+ let reasoning = "";
1578
1588
  let usage;
1579
1589
  let finishReason;
1580
1590
  await consumeSSE(response, (data) => {
@@ -1586,6 +1596,7 @@ function createOpenAICompatibleAdapter(options) {
1586
1596
  return;
1587
1597
  }
1588
1598
  const delta = pickAssistantDelta(json);
1599
+ const reasoningDelta = pickAssistantReasoningDelta(json);
1589
1600
  const chunkUsage = pickUsage(json);
1590
1601
  const chunkFinishReason = pickFinishReason(json);
1591
1602
  usage = preferLatestUsage(usage, chunkUsage);
@@ -1596,9 +1607,13 @@ function createOpenAICompatibleAdapter(options) {
1596
1607
  text += delta;
1597
1608
  callbacks.onToken?.(delta);
1598
1609
  }
1599
- if (delta || chunkUsage || chunkFinishReason) {
1610
+ if (reasoningDelta) {
1611
+ reasoning += reasoningDelta;
1612
+ }
1613
+ if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
1600
1614
  const chunk = {
1601
1615
  textDelta: delta,
1616
+ reasoningDelta: reasoningDelta || undefined,
1602
1617
  raw: json,
1603
1618
  usage: chunkUsage,
1604
1619
  finishReason: chunkFinishReason
@@ -1606,7 +1621,12 @@ function createOpenAICompatibleAdapter(options) {
1606
1621
  callbacks.onChunk?.(chunk);
1607
1622
  }
1608
1623
  });
1609
- const out = { text, usage, finishReason };
1624
+ const out = {
1625
+ text,
1626
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1627
+ usage,
1628
+ finishReason
1629
+ };
1610
1630
  callbacks.onComplete?.(out);
1611
1631
  return out;
1612
1632
  },
@@ -1666,6 +1686,7 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1666
1686
  model: options.model,
1667
1687
  messages: buildMessages(request),
1668
1688
  temperature: request.temperature,
1689
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1669
1690
  max_tokens: request.maxTokens,
1670
1691
  stream: false
1671
1692
  })),
@@ -1681,8 +1702,10 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1681
1702
  throw new Error("No assistant message in OpenAI-compatible response.");
1682
1703
  }
1683
1704
  const toolCalls = pickChatToolCalls(payload);
1705
+ const reasoning = pickAssistantReasoning(payload);
1684
1706
  return {
1685
1707
  text: pickAssistantText(payload),
1708
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1686
1709
  raw: payload,
1687
1710
  usage: pickUsage(payload),
1688
1711
  finishReason: pickFinishReason(payload),
@@ -1709,6 +1732,7 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1709
1732
  model: options.model,
1710
1733
  messages,
1711
1734
  temperature: request.temperature,
1735
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1712
1736
  max_tokens: request.maxTokens,
1713
1737
  tools: transportTools,
1714
1738
  tool_choice: request.toolChoice,
@@ -1730,8 +1754,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1730
1754
  throw new Error("No assistant message in OpenAI-compatible response.");
1731
1755
  }
1732
1756
  if (calledTools.length === 0) {
1757
+ const reasoning = pickAssistantReasoning(payload);
1733
1758
  return {
1734
1759
  text: pickAssistantText(payload),
1760
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1735
1761
  raw: payload,
1736
1762
  usage: aggregatedUsage,
1737
1763
  finishReason,
@@ -1759,6 +1785,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1759
1785
  }
1760
1786
  return {
1761
1787
  text: pickAssistantText(lastPayload ?? {}),
1788
+ reasoning: (() => {
1789
+ const value = pickAssistantReasoning(lastPayload ?? {});
1790
+ return value.length > 0 ? value : undefined;
1791
+ })(),
1762
1792
  raw: lastPayload,
1763
1793
  usage: aggregatedUsage,
1764
1794
  finishReason,
@@ -1778,6 +1808,7 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
1778
1808
  input: buildResponsesInput(request),
1779
1809
  previous_response_id: pickString(body?.previous_response_id),
1780
1810
  temperature: request.temperature,
1811
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1781
1812
  max_output_tokens: request.maxTokens
1782
1813
  })),
1783
1814
  signal: request.signal
@@ -1818,6 +1849,7 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
1818
1849
  input,
1819
1850
  previous_response_id: previousResponseId,
1820
1851
  temperature: request.temperature,
1852
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1821
1853
  max_output_tokens: request.maxTokens,
1822
1854
  tools: transportTools,
1823
1855
  tool_choice: request.toolChoice,
@@ -1882,6 +1914,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1882
1914
  const executedToolCalls = [];
1883
1915
  const toolExecutions = [];
1884
1916
  callbacks.onStart?.();
1917
+ let lastRoundText = "";
1918
+ let lastRoundReasoning = "";
1885
1919
  for (let round = 1;round <= maxToolRounds + 1; round += 1) {
1886
1920
  const mcpToolset = await resolveMCPToolset(request.mcpClients);
1887
1921
  const transportTools = toProviderFunctionTools(mcpToolset);
@@ -1894,6 +1928,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1894
1928
  model: options.model,
1895
1929
  messages,
1896
1930
  temperature: request.temperature,
1931
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1897
1932
  max_tokens: request.maxTokens,
1898
1933
  tools: transportTools,
1899
1934
  tool_choice: request.toolChoice,
@@ -1907,9 +1942,11 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1907
1942
  throw new Error(`HTTP ${response.status}: ${message}`);
1908
1943
  }
1909
1944
  let roundText = "";
1945
+ let roundReasoning = "";
1910
1946
  let roundUsage;
1911
1947
  let roundFinishReason;
1912
1948
  const streamedToolCalls = new Map;
1949
+ let reasoningFieldName;
1913
1950
  await consumeSSE(response, (data) => {
1914
1951
  if (data === "[DONE]") {
1915
1952
  return;
@@ -1920,6 +1957,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1920
1957
  }
1921
1958
  lastPayload = json;
1922
1959
  const delta = pickAssistantDelta(json);
1960
+ const reasoningDelta = pickAssistantReasoningDelta(json);
1923
1961
  const chunkUsage = pickUsage(json);
1924
1962
  const chunkFinishReason = pickFinishReason(json);
1925
1963
  collectOpenAIStreamToolCalls(json, streamedToolCalls);
@@ -1931,9 +1969,14 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1931
1969
  roundText += delta;
1932
1970
  callbacks.onToken?.(delta);
1933
1971
  }
1934
- if (delta || chunkUsage || chunkFinishReason) {
1972
+ if (reasoningDelta) {
1973
+ roundReasoning += reasoningDelta;
1974
+ reasoningFieldName ??= pickAssistantReasoningDeltaFieldName(json);
1975
+ }
1976
+ if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
1935
1977
  const chunk = {
1936
1978
  textDelta: delta,
1979
+ reasoningDelta: reasoningDelta || undefined,
1937
1980
  raw: json,
1938
1981
  usage: chunkUsage,
1939
1982
  finishReason: chunkFinishReason
@@ -1949,6 +1992,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1949
1992
  if (calledTools.length === 0) {
1950
1993
  const out2 = {
1951
1994
  text: roundText,
1995
+ reasoning: roundReasoning.length > 0 ? roundReasoning : undefined,
1952
1996
  raw: lastPayload,
1953
1997
  usage: aggregatedUsage,
1954
1998
  finishReason,
@@ -1969,7 +2013,12 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1969
2013
  });
1970
2014
  executedToolCalls.push(...outputs.map((entry) => entry.call));
1971
2015
  toolExecutions.push(...outputs.map((entry) => entry.execution));
1972
- const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools);
2016
+ lastRoundText = roundText;
2017
+ lastRoundReasoning = roundReasoning;
2018
+ const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools, {
2019
+ reasoning: roundReasoning,
2020
+ reasoningFieldName
2021
+ });
1973
2022
  const toolMessages = outputs.map((entry) => ({
1974
2023
  role: "tool",
1975
2024
  tool_call_id: entry.call.id,
@@ -1978,7 +2027,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1978
2027
  messages = [...messages, assistantMessage, ...toolMessages];
1979
2028
  }
1980
2029
  const out = {
1981
- text: "",
2030
+ text: lastRoundText,
2031
+ reasoning: lastRoundReasoning.length > 0 ? lastRoundReasoning : undefined,
1982
2032
  raw: lastPayload,
1983
2033
  usage: aggregatedUsage,
1984
2034
  finishReason,
@@ -2000,6 +2050,7 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
2000
2050
  input: buildResponsesInput(request),
2001
2051
  previous_response_id: pickString(body?.previous_response_id),
2002
2052
  temperature: request.temperature,
2053
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
2003
2054
  max_output_tokens: request.maxTokens,
2004
2055
  stream: true
2005
2056
  })),
@@ -2080,6 +2131,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
2080
2131
  input,
2081
2132
  previous_response_id: previousResponseId,
2082
2133
  temperature: request.temperature,
2134
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
2083
2135
  max_output_tokens: request.maxTokens,
2084
2136
  tools: transportTools,
2085
2137
  tool_choice: request.toolChoice,
@@ -2246,6 +2298,12 @@ function toResponsesTools(tools) {
2246
2298
  return { ...tool };
2247
2299
  });
2248
2300
  }
2301
+ function toOpenAIReasoningEffort(value) {
2302
+ if (!value) {
2303
+ return;
2304
+ }
2305
+ return value === "max" ? "xhigh" : value;
2306
+ }
2249
2307
  function pickChatToolCalls(payload) {
2250
2308
  const message = pickAssistantMessage(payload);
2251
2309
  if (!message) {
@@ -2327,20 +2385,50 @@ function pickAssistantDelta(payload) {
2327
2385
  if (!isRecord2(delta)) {
2328
2386
  return "";
2329
2387
  }
2330
- const content = delta.content;
2331
- if (typeof content === "string") {
2332
- return content;
2388
+ return pickTextFromOpenAIContent(delta.content);
2389
+ }
2390
+ function pickAssistantReasoning(payload) {
2391
+ const message = pickAssistantMessage(payload);
2392
+ if (!message) {
2393
+ return "";
2333
2394
  }
2334
- if (Array.isArray(content)) {
2335
- return content.map((part) => {
2336
- if (!isRecord2(part)) {
2337
- return "";
2338
- }
2339
- const text = part.text;
2340
- return typeof text === "string" ? text : "";
2341
- }).join("");
2395
+ return pickReasoningText(message);
2396
+ }
2397
+ function pickAssistantReasoningDelta(payload) {
2398
+ const choices = payload.choices;
2399
+ if (!Array.isArray(choices) || choices.length === 0) {
2400
+ return "";
2342
2401
  }
2343
- return "";
2402
+ const first = choices[0];
2403
+ if (!isRecord2(first)) {
2404
+ return "";
2405
+ }
2406
+ const delta = first.delta;
2407
+ if (!isRecord2(delta)) {
2408
+ return "";
2409
+ }
2410
+ return pickReasoningText(delta);
2411
+ }
2412
+ function pickAssistantReasoningDeltaFieldName(payload) {
2413
+ const choices = payload.choices;
2414
+ if (!Array.isArray(choices) || choices.length === 0) {
2415
+ return;
2416
+ }
2417
+ const first = choices[0];
2418
+ if (!isRecord2(first)) {
2419
+ return;
2420
+ }
2421
+ const delta = first.delta;
2422
+ if (!isRecord2(delta)) {
2423
+ return;
2424
+ }
2425
+ if (hasTextLikeValue(delta.reasoning)) {
2426
+ return "reasoning";
2427
+ }
2428
+ if (hasTextLikeValue(delta.reasoning_content)) {
2429
+ return "reasoning_content";
2430
+ }
2431
+ return;
2344
2432
  }
2345
2433
  function collectOpenAIStreamToolCalls(payload, state) {
2346
2434
  const choices = payload.choices;
@@ -2389,8 +2477,8 @@ function buildOpenAIStreamToolCalls(state) {
2389
2477
  arguments: entry.argumentsText.length > 0 ? entry.argumentsText : {}
2390
2478
  }));
2391
2479
  }
2392
- function buildOpenAIAssistantToolMessage(text, toolCalls) {
2393
- return {
2480
+ function buildOpenAIAssistantToolMessage(text, toolCalls, reasoning) {
2481
+ const message = {
2394
2482
  role: "assistant",
2395
2483
  content: text,
2396
2484
  tool_calls: toolCalls.map((call) => ({
@@ -2402,6 +2490,10 @@ function buildOpenAIAssistantToolMessage(text, toolCalls) {
2402
2490
  }
2403
2491
  }))
2404
2492
  };
2493
+ if (reasoning?.reasoning && reasoning.reasoning.length > 0) {
2494
+ message[reasoning.reasoningFieldName ?? "reasoning"] = reasoning.reasoning;
2495
+ }
2496
+ return message;
2405
2497
  }
2406
2498
  function pickResponsesStreamPayload(payload) {
2407
2499
  if (isRecord2(payload.response)) {
@@ -2563,21 +2655,9 @@ function pickResponsesText(payload) {
2563
2655
  function pickAssistantText(payload) {
2564
2656
  const message = pickAssistantMessage(payload);
2565
2657
  if (message) {
2566
- const content = message.content;
2567
- if (typeof content === "string") {
2568
- return content;
2569
- }
2570
- if (Array.isArray(content)) {
2571
- return content.map((part) => {
2572
- if (typeof part === "string") {
2573
- return part;
2574
- }
2575
- if (!isRecord2(part)) {
2576
- return "";
2577
- }
2578
- const text = part.text;
2579
- return typeof text === "string" ? text : "";
2580
- }).join("");
2658
+ const text = pickTextFromOpenAIContent(message.content);
2659
+ if (text.length > 0) {
2660
+ return text;
2581
2661
  }
2582
2662
  }
2583
2663
  const choices = payload.choices;
@@ -2589,6 +2669,36 @@ function pickAssistantText(payload) {
2589
2669
  }
2590
2670
  return "";
2591
2671
  }
2672
+ function pickReasoningText(value) {
2673
+ return pickTextLike(value.reasoning) || pickTextLike(value.reasoning_content);
2674
+ }
2675
+ function pickTextFromOpenAIContent(value) {
2676
+ return pickTextLike(value);
2677
+ }
2678
+ function pickTextLike(value) {
2679
+ if (typeof value === "string") {
2680
+ return value;
2681
+ }
2682
+ if (Array.isArray(value)) {
2683
+ return value.map((part) => pickTextLikePart(part)).join("");
2684
+ }
2685
+ if (!isRecord2(value)) {
2686
+ return "";
2687
+ }
2688
+ return pickTextLikePart(value);
2689
+ }
2690
+ function pickTextLikePart(value) {
2691
+ if (typeof value === "string") {
2692
+ return value;
2693
+ }
2694
+ if (!isRecord2(value)) {
2695
+ return "";
2696
+ }
2697
+ return pickString(value.text) ?? pickString(value.output_text) ?? pickString(value.reasoning) ?? pickString(value.reasoning_content) ?? (Array.isArray(value.content) ? value.content.map((part) => pickTextLikePart(part)).join("") : "");
2698
+ }
2699
+ function hasTextLikeValue(value) {
2700
+ return pickTextLike(value).length > 0;
2701
+ }
2592
2702
  function pickUsage(payload) {
2593
2703
  const usage = payload.usage;
2594
2704
  if (!isRecord2(usage)) {
@@ -2642,14 +2752,13 @@ function createAnthropicCompatibleAdapter(options) {
2642
2752
  const response = await fetcher(buildURL(options.baseURL, path), {
2643
2753
  method: "POST",
2644
2754
  headers: buildHeaders2(options),
2645
- body: JSON.stringify(cleanUndefined({
2755
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2646
2756
  ...options.defaultBody,
2647
2757
  ...request.body,
2648
2758
  model: options.model,
2649
2759
  system: input.systemPrompt,
2650
2760
  messages: input.messages,
2651
2761
  temperature: request.temperature,
2652
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2653
2762
  stream: true
2654
2763
  })),
2655
2764
  signal: request.signal
@@ -2705,14 +2814,13 @@ async function completePassThrough(options, fetcher, path, request) {
2705
2814
  const response = await fetcher(buildURL(options.baseURL, path), {
2706
2815
  method: "POST",
2707
2816
  headers: buildHeaders2(options),
2708
- body: JSON.stringify(cleanUndefined({
2817
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2709
2818
  ...options.defaultBody,
2710
2819
  ...request.body,
2711
2820
  model: options.model,
2712
2821
  system: input.systemPrompt,
2713
2822
  messages: input.messages,
2714
2823
  temperature: request.temperature,
2715
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2716
2824
  stream: false
2717
2825
  })),
2718
2826
  signal: request.signal
@@ -2750,14 +2858,13 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2750
2858
  const response = await fetcher(buildURL(options.baseURL, path), {
2751
2859
  method: "POST",
2752
2860
  headers: buildHeaders2(options),
2753
- body: JSON.stringify(cleanUndefined({
2861
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2754
2862
  ...options.defaultBody,
2755
2863
  ...request.body,
2756
2864
  model: options.model,
2757
2865
  system: input.systemPrompt,
2758
2866
  messages,
2759
2867
  temperature: request.temperature,
2760
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2761
2868
  tools,
2762
2869
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2763
2870
  stream: false
@@ -2835,14 +2942,13 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
2835
2942
  const response = await fetcher(buildURL(options.baseURL, path), {
2836
2943
  method: "POST",
2837
2944
  headers: buildHeaders2(options),
2838
- body: JSON.stringify(cleanUndefined({
2945
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2839
2946
  ...options.defaultBody,
2840
2947
  ...request.body,
2841
2948
  model: options.model,
2842
2949
  system: input.systemPrompt,
2843
2950
  messages,
2844
2951
  temperature: request.temperature,
2845
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2846
2952
  tools,
2847
2953
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2848
2954
  stream: true
@@ -2950,6 +3056,21 @@ function buildHeaders2(options) {
2950
3056
  ...options.headers
2951
3057
  };
2952
3058
  }
3059
+ function buildAnthropicRequestBody(options, request, body) {
3060
+ const bodyOutputConfig = isRecord2(body.output_config) ? body.output_config : undefined;
3061
+ const bodyThinking = body.thinking;
3062
+ const hasExplicitThinking = Object.prototype.hasOwnProperty.call(body, "thinking");
3063
+ const reasoningEffort = request.reasoningEffort;
3064
+ return cleanUndefined({
3065
+ ...body,
3066
+ max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
3067
+ output_config: reasoningEffort ? cleanUndefined({
3068
+ ...bodyOutputConfig,
3069
+ effort: reasoningEffort
3070
+ }) : bodyOutputConfig,
3071
+ thinking: reasoningEffort ? hasExplicitThinking ? bodyThinking : { type: "adaptive" } : bodyThinking
3072
+ });
3073
+ }
2953
3074
  function resolveAnthropicInput(request) {
2954
3075
  if (Array.isArray(request.messages) && request.messages.length > 0) {
2955
3076
  return toAnthropicInput(request.messages);
@@ -3304,8 +3425,34 @@ function buildProviderOptions(config) {
3304
3425
  };
3305
3426
  }
3306
3427
 
3307
- // src/structured.ts
3308
- import { jsonrepair as jsonrepair3 } from "jsonrepair";
3428
+ // src/utils/debug-colors.ts
3429
+ var ANSI = {
3430
+ reset: "\x1B[0m",
3431
+ bold: "\x1B[1m",
3432
+ cyan: "\x1B[36m",
3433
+ yellow: "\x1B[33m",
3434
+ green: "\x1B[32m",
3435
+ red: "\x1B[31m",
3436
+ dim: "\x1B[2m"
3437
+ };
3438
+ function color(config, text, tone) {
3439
+ if (!config.colors) {
3440
+ return text;
3441
+ }
3442
+ return `${ANSI[tone]}${text}${ANSI.reset}`;
3443
+ }
3444
+ function dim(config, text) {
3445
+ if (!config.colors) {
3446
+ return text;
3447
+ }
3448
+ return `${ANSI.dim}${text}${ANSI.reset}`;
3449
+ }
3450
+ function title(config, text) {
3451
+ if (!config.colors) {
3452
+ return text;
3453
+ }
3454
+ return `${ANSI.bold}${text}${ANSI.reset}`;
3455
+ }
3309
3456
 
3310
3457
  // src/outdent.ts
3311
3458
  var DEFAULT_OPTIONS = {
@@ -3444,39 +3591,598 @@ function createOutdent(options = {}) {
3444
3591
  return outdent;
3445
3592
  }
3446
3593
 
3447
- // src/parse.ts
3448
- import { jsonrepair as jsonrepair2 } from "jsonrepair";
3449
- function parseLLMOutput(output, schema, options = {}) {
3450
- const sanitized = sanitizeThink(output);
3451
- const parseOptions = {
3452
- repair: options.repair ?? true,
3453
- maxCandidates: options.maxCandidates ?? 5,
3454
- acceptArrays: options.acceptArrays ?? true,
3455
- extraction: options.extraction,
3456
- onTrace: options.onTrace
3594
+ // src/generate-shared.ts
3595
+ var sharedOutdent = createOutdent({
3596
+ trimLeadingNewline: true,
3597
+ trimTrailingNewline: true,
3598
+ newline: `
3599
+ `
3600
+ });
3601
+ var RE_THINK_TAGS = /<\/?think\s*>/gi;
3602
+ function resolvePrompt(prompt, context) {
3603
+ const resolved = typeof prompt === "function" ? prompt(context) : prompt;
3604
+ return normalizePromptValue(resolved, context);
3605
+ }
3606
+ function normalizePromptValue(value, _context) {
3607
+ if (typeof value === "string") {
3608
+ return {
3609
+ prompt: value
3610
+ };
3611
+ }
3612
+ if (isPromptResolver(value)) {
3613
+ return normalizePromptPayload(value.resolvePrompt(_context));
3614
+ }
3615
+ return normalizePromptPayload(value);
3616
+ }
3617
+ function normalizePromptPayload(value) {
3618
+ const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
3619
+ const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
3620
+ if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
3621
+ throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
3622
+ }
3623
+ return {
3624
+ prompt,
3625
+ systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
3626
+ messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
3457
3627
  };
3458
- const candidates = extractJsonCandidates(sanitized.visibleText, {
3459
- maxCandidates: parseOptions.maxCandidates,
3460
- acceptArrays: parseOptions.acceptArrays,
3461
- allowRepairHints: parseOptions.repair,
3462
- heuristics: parseOptions.extraction
3463
- });
3464
- emitTrace(parseOptions.onTrace, {
3465
- stage: "extract",
3466
- level: "info",
3467
- message: `Extracted ${candidates.length} candidate(s).`,
3468
- details: {
3469
- maxCandidates: parseOptions.maxCandidates,
3470
- thinkBlocks: sanitized.thinkBlocks.length,
3471
- thinkDiagnostics: sanitized.diagnostics
3628
+ }
3629
+ function applyPromptOutdent(payload, enabled) {
3630
+ if (!enabled) {
3631
+ return payload;
3632
+ }
3633
+ return {
3634
+ prompt: typeof payload.prompt === "string" ? sharedOutdent.string(payload.prompt) : undefined,
3635
+ systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
3636
+ messages: payload.messages?.map((message) => ({
3637
+ ...message,
3638
+ content: typeof message.content === "string" ? sharedOutdent.string(message.content) : message.content
3639
+ }))
3640
+ };
3641
+ }
3642
+ function applyOutdentToOptionalPrompt(value, enabled) {
3643
+ if (!enabled || typeof value !== "string") {
3644
+ return value;
3645
+ }
3646
+ return sharedOutdent.string(value);
3647
+ }
3648
+ function mergeSystemPrompts(primary, secondary) {
3649
+ const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
3650
+ if (prompts.length === 0) {
3651
+ return;
3652
+ }
3653
+ return prompts.join(`
3654
+
3655
+ `);
3656
+ }
3657
+ function normalizeStreamConfig(option) {
3658
+ if (typeof option === "boolean") {
3659
+ return {
3660
+ enabled: option
3661
+ };
3662
+ }
3663
+ if (!option) {
3664
+ return {
3665
+ enabled: false
3666
+ };
3667
+ }
3668
+ return {
3669
+ enabled: option.enabled ?? true,
3670
+ onData: option.onData,
3671
+ to: option.to
3672
+ };
3673
+ }
3674
+ function normalizeDebugConfig(option) {
3675
+ if (typeof option === "boolean") {
3676
+ return {
3677
+ enabled: option,
3678
+ colors: true,
3679
+ verbose: false,
3680
+ logger: (line) => console.log(line)
3681
+ };
3682
+ }
3683
+ if (!option) {
3684
+ return {
3685
+ enabled: false,
3686
+ colors: true,
3687
+ verbose: false,
3688
+ logger: (line) => console.log(line)
3689
+ };
3690
+ }
3691
+ return {
3692
+ enabled: option.enabled ?? true,
3693
+ colors: option.colors ?? true,
3694
+ verbose: option.verbose ?? false,
3695
+ logger: option.logger ?? ((line) => console.log(line))
3696
+ };
3697
+ }
3698
+ function withToolTimeout(client, toolTimeoutMs) {
3699
+ return {
3700
+ id: client.id,
3701
+ listTools: client.listTools.bind(client),
3702
+ close: client.close?.bind(client),
3703
+ async callTool(params) {
3704
+ let timeoutId;
3705
+ const timeoutPromise = new Promise((_, reject) => {
3706
+ timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
3707
+ });
3708
+ try {
3709
+ return await Promise.race([client.callTool(params), timeoutPromise]);
3710
+ } finally {
3711
+ clearTimeout(timeoutId);
3712
+ }
3472
3713
  }
3473
- });
3474
- const errors = [];
3475
- const diagnostics = [];
3476
- let bestIssues = [];
3477
- let bestCandidate = candidates[0] ?? null;
3478
- let bestParsed = null;
3479
- let bestRepaired = null;
3714
+ };
3715
+ }
3716
+ function applyToolTimeout(clients, toolTimeoutMs) {
3717
+ return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
3718
+ }
3719
+ async function callModel(adapter, options) {
3720
+ const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
3721
+ const requestPayload = {
3722
+ prompt: options.prompt,
3723
+ messages: options.messages,
3724
+ systemPrompt: options.systemPrompt,
3725
+ temperature: options.request?.temperature,
3726
+ reasoningEffort: options.request?.reasoningEffort,
3727
+ maxTokens: options.request?.maxTokens,
3728
+ mcpClients: options.request?.mcpClients,
3729
+ toolChoice: options.request?.toolChoice,
3730
+ parallelToolCalls: options.request?.parallelToolCalls,
3731
+ maxToolRounds: options.request?.maxToolRounds,
3732
+ onToolExecution: options.request?.onToolExecution,
3733
+ transformToolOutput: options.request?.transformToolOutput,
3734
+ transformToolArguments: options.request?.transformToolArguments,
3735
+ transformToolCallParams: options.request?.transformToolCallParams,
3736
+ unknownToolError: options.request?.unknownToolError,
3737
+ toolDebug: options.request?.toolDebug,
3738
+ body: options.request?.body,
3739
+ signal: requestSignal
3740
+ };
3741
+ emitDebugRequest(options.debug, {
3742
+ label: options.debugLabel,
3743
+ provider: adapter.provider,
3744
+ model: adapter.model,
3745
+ attempt: options.attempt,
3746
+ selfHealAttempt: options.selfHeal,
3747
+ selfHealEnabled: options.selfHealEnabled,
3748
+ stream: options.stream.enabled && !!adapter.stream,
3749
+ requestPayload
3750
+ });
3751
+ options.observe?.(options.buildEvent({
3752
+ stage: "llm.request",
3753
+ message: "Sending LLM request.",
3754
+ details: {
3755
+ provider: adapter.provider,
3756
+ model: adapter.model,
3757
+ stream: options.stream.enabled && !!adapter.stream
3758
+ }
3759
+ }));
3760
+ if (options.stream.enabled && adapter.stream) {
3761
+ let latestUsage;
3762
+ let latestFinishReason;
3763
+ let streamedProviderText = "";
3764
+ let streamedDedicatedReasoning = "";
3765
+ let lastSnapshotFingerprint;
3766
+ let previousSnapshotText = "";
3767
+ let previousSnapshotReasoning = "";
3768
+ const emitStreamingData = (done, usage2, finishReason2) => {
3769
+ const normalized2 = normalizeModelOutput(streamedProviderText, streamedDedicatedReasoning);
3770
+ const snapshot = options.buildSnapshot(normalized2);
3771
+ const fingerprint = toStreamDataFingerprint(snapshot);
3772
+ if (!done && fingerprint === lastSnapshotFingerprint) {
3773
+ return;
3774
+ }
3775
+ const delta = {
3776
+ text: normalized2.text.startsWith(previousSnapshotText) ? normalized2.text.slice(previousSnapshotText.length) : "",
3777
+ reasoning: normalized2.reasoning.startsWith(previousSnapshotReasoning) ? normalized2.reasoning.slice(previousSnapshotReasoning.length) : ""
3778
+ };
3779
+ lastSnapshotFingerprint = fingerprint;
3780
+ previousSnapshotText = normalized2.text;
3781
+ previousSnapshotReasoning = normalized2.reasoning;
3782
+ options.stream.onData?.({
3783
+ delta,
3784
+ snapshot,
3785
+ done,
3786
+ usage: usage2,
3787
+ finishReason: finishReason2
3788
+ });
3789
+ if (options.stream.to === "stdout" && delta.text) {
3790
+ process.stdout.write(delta.text);
3791
+ }
3792
+ options.observe?.(options.buildEvent({
3793
+ stage: "llm.stream.data",
3794
+ message: done ? "Streaming response completed." : "Streaming response updated.",
3795
+ details: {
3796
+ done,
3797
+ finishReason: finishReason2
3798
+ }
3799
+ }));
3800
+ };
3801
+ const handleTextDelta = (delta) => {
3802
+ if (!delta) {
3803
+ return;
3804
+ }
3805
+ streamedProviderText += delta;
3806
+ options.observe?.(options.buildEvent({
3807
+ stage: "llm.stream.delta",
3808
+ message: "Received stream delta.",
3809
+ details: {
3810
+ chars: delta.length
3811
+ }
3812
+ }));
3813
+ emitStreamingData(false);
3814
+ };
3815
+ const handleReasoningDelta = (delta) => {
3816
+ if (!delta) {
3817
+ return;
3818
+ }
3819
+ streamedDedicatedReasoning += delta;
3820
+ emitStreamingData(false);
3821
+ };
3822
+ const response2 = await adapter.stream(requestPayload, {
3823
+ onChunk: (chunk) => {
3824
+ if (chunk.textDelta) {
3825
+ handleTextDelta(chunk.textDelta);
3826
+ }
3827
+ if (chunk.reasoningDelta) {
3828
+ handleReasoningDelta(chunk.reasoningDelta);
3829
+ }
3830
+ if (chunk.usage) {
3831
+ latestUsage = preferLatestUsage(latestUsage, chunk.usage);
3832
+ }
3833
+ if (chunk.finishReason) {
3834
+ latestFinishReason = chunk.finishReason;
3835
+ }
3836
+ }
3837
+ });
3838
+ streamedProviderText = typeof response2.text === "string" ? response2.text : streamedProviderText;
3839
+ streamedDedicatedReasoning = typeof response2.reasoning === "string" ? response2.reasoning : streamedDedicatedReasoning;
3840
+ const finalNormalized = normalizeModelOutput(streamedProviderText, streamedDedicatedReasoning);
3841
+ const usage = preferLatestUsage(latestUsage, response2.usage);
3842
+ const finishReason = response2.finishReason ?? latestFinishReason;
3843
+ emitStreamingData(true, usage, finishReason);
3844
+ options.observe?.(options.buildEvent({
3845
+ stage: "llm.response",
3846
+ message: "Streaming response completed.",
3847
+ details: {
3848
+ via: "stream",
3849
+ chars: finalNormalized.parseSource.length,
3850
+ finishReason
3851
+ }
3852
+ }));
3853
+ emitDebugResponse(options.debug, {
3854
+ label: options.debugLabel,
3855
+ attempt: options.attempt,
3856
+ selfHealAttempt: options.selfHeal,
3857
+ selfHealEnabled: options.selfHealEnabled,
3858
+ via: "stream",
3859
+ text: finalNormalized.text,
3860
+ reasoning: finalNormalized.reasoning,
3861
+ parseSource: finalNormalized.parseSource,
3862
+ usage,
3863
+ finishReason
3864
+ });
3865
+ return {
3866
+ text: finalNormalized.text,
3867
+ reasoning: finalNormalized.reasoning,
3868
+ thinkBlocks: finalNormalized.thinkBlocks,
3869
+ parseSource: finalNormalized.parseSource,
3870
+ via: "stream",
3871
+ usage,
3872
+ finishReason
3873
+ };
3874
+ }
3875
+ const response = await adapter.complete(requestPayload);
3876
+ const normalized = normalizeModelOutput(response.text, response.reasoning);
3877
+ options.observe?.(options.buildEvent({
3878
+ stage: "llm.response",
3879
+ message: "Completion response received.",
3880
+ details: {
3881
+ via: "complete",
3882
+ chars: normalized.parseSource.length,
3883
+ finishReason: response.finishReason
3884
+ }
3885
+ }));
3886
+ emitDebugResponse(options.debug, {
3887
+ label: options.debugLabel,
3888
+ attempt: options.attempt,
3889
+ selfHealAttempt: options.selfHeal,
3890
+ selfHealEnabled: options.selfHealEnabled,
3891
+ via: "complete",
3892
+ text: normalized.text,
3893
+ reasoning: normalized.reasoning,
3894
+ parseSource: normalized.parseSource,
3895
+ usage: response.usage,
3896
+ finishReason: response.finishReason
3897
+ });
3898
+ return {
3899
+ text: normalized.text,
3900
+ reasoning: normalized.reasoning,
3901
+ thinkBlocks: normalized.thinkBlocks,
3902
+ parseSource: normalized.parseSource,
3903
+ via: "complete",
3904
+ usage: response.usage,
3905
+ finishReason: response.finishReason
3906
+ };
3907
+ }
3908
+ function normalizeModelOutput(text, dedicatedReasoning) {
3909
+ const sanitized = sanitizeThink(text);
3910
+ const visibleText = stripThinkBlocks(text, sanitized.thinkBlocks);
3911
+ const reasoning = joinReasoningSegments([
3912
+ dedicatedReasoning,
3913
+ ...sanitized.thinkBlocks.map((block) => block.content)
3914
+ ]);
3915
+ return {
3916
+ text: visibleText,
3917
+ reasoning,
3918
+ thinkBlocks: sanitized.thinkBlocks,
3919
+ parseSource: composeParseSource(visibleText, reasoning)
3920
+ };
3921
+ }
3922
+ function composeParseSource(text, reasoning) {
3923
+ if (typeof reasoning !== "string" || reasoning.length === 0) {
3924
+ return text;
3925
+ }
3926
+ const sanitized = reasoning.replace(RE_THINK_TAGS, "");
3927
+ if (sanitized.length === 0) {
3928
+ return text;
3929
+ }
3930
+ return `<think>${sanitized}</think>${text}`;
3931
+ }
3932
+ function aggregateUsage(attempts) {
3933
+ let usage;
3934
+ for (const attempt of attempts) {
3935
+ usage = mergeUsage2(usage, attempt.usage);
3936
+ }
3937
+ return usage;
3938
+ }
3939
+ function mergeUsage2(base, next) {
3940
+ if (!base && !next) {
3941
+ return;
3942
+ }
3943
+ return {
3944
+ inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
3945
+ outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
3946
+ totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
3947
+ cost: (base?.cost ?? 0) + (next?.cost ?? 0)
3948
+ };
3949
+ }
3950
+ function isPromptResolver(value) {
3951
+ return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
3952
+ }
3953
+ function isLLMMessage(value) {
3954
+ if (typeof value !== "object" || value === null) {
3955
+ return false;
3956
+ }
3957
+ const candidate = value;
3958
+ if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
3959
+ return false;
3960
+ }
3961
+ return "content" in candidate;
3962
+ }
3963
+ function joinReasoningSegments(parts) {
3964
+ return parts.map((value) => value?.trim()).filter((value) => Boolean(value)).join(`
3965
+
3966
+ `);
3967
+ }
3968
+ function stripThinkBlocks(text, thinkBlocks) {
3969
+ if (thinkBlocks.length === 0) {
3970
+ return text;
3971
+ }
3972
+ let output = "";
3973
+ let cursor = 0;
3974
+ for (const block of thinkBlocks) {
3975
+ output += text.slice(cursor, block.start);
3976
+ cursor = block.end;
3977
+ }
3978
+ output += text.slice(cursor);
3979
+ return output;
3980
+ }
3981
+ function toStreamDataFingerprint(value) {
3982
+ try {
3983
+ return JSON.stringify(value);
3984
+ } catch {
3985
+ return "__unserializable__";
3986
+ }
3987
+ }
3988
+ function emitDebugRequest(config, input) {
3989
+ const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
3990
+ const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
3991
+ const lines = [
3992
+ color(config, title(config, [
3993
+ `[${input.label}][request]`,
3994
+ `attempt=${input.attempt}`,
3995
+ `selfHealEnabled=${input.selfHealEnabled}`,
3996
+ `selfHealAttempt=${input.selfHealAttempt}`
3997
+ ].join(" ")), "cyan"),
3998
+ dim(config, [
3999
+ `provider=${input.provider ?? "unknown"}`,
4000
+ `model=${input.model ?? "unknown"}`,
4001
+ `stream=${input.stream}`
4002
+ ].join(" ")),
4003
+ color(config, "prompt:", "yellow"),
4004
+ input.requestPayload.prompt ?? "(none)",
4005
+ color(config, "messages:", "yellow"),
4006
+ requestMessages,
4007
+ color(config, "systemPrompt:", "yellow"),
4008
+ input.requestPayload.systemPrompt ?? "(none)",
4009
+ color(config, "request.body:", "yellow"),
4010
+ requestBody
4011
+ ];
4012
+ emitDebug(config, lines.join(`
4013
+ `));
4014
+ }
4015
+ function emitDebugResponse(config, input) {
4016
+ const text = input.text.length > 0 ? input.text : "(none)";
4017
+ const reasoning = input.reasoning.length > 0 ? input.reasoning : "(none)";
4018
+ const metadata = [
4019
+ `via=${input.via}`,
4020
+ `textChars=${input.text.length}`,
4021
+ `reasoningChars=${input.reasoning.length}`
4022
+ ];
4023
+ if (config.verbose) {
4024
+ metadata.push(`parseSourceChars=${input.parseSource.length}`);
4025
+ }
4026
+ metadata.push(`finishReason=${input.finishReason ?? "unknown"}`, `usage=${JSON.stringify(input.usage ?? {})}`);
4027
+ const lines = [
4028
+ color(config, title(config, [
4029
+ `[${input.label}][response]`,
4030
+ `attempt=${input.attempt}`,
4031
+ `selfHealEnabled=${input.selfHealEnabled}`,
4032
+ `selfHealAttempt=${input.selfHealAttempt}`
4033
+ ].join(" ")), "green"),
4034
+ dim(config, metadata.join(" ")),
4035
+ color(config, "text:", "yellow"),
4036
+ text,
4037
+ color(config, "reasoning:", "yellow"),
4038
+ reasoning
4039
+ ];
4040
+ if (config.verbose) {
4041
+ lines.push(color(config, "parseSource:", "yellow"), input.parseSource);
4042
+ }
4043
+ emitDebug(config, lines.join(`
4044
+ `));
4045
+ }
4046
+ function emitDebug(config, message) {
4047
+ if (!config.enabled) {
4048
+ return;
4049
+ }
4050
+ config.logger(message);
4051
+ }
4052
+
4053
+ // src/generate.ts
4054
+ async function generate(adapter, promptOrOptions, callOptions) {
4055
+ const normalized = normalizeGenerateInput(promptOrOptions, callOptions);
4056
+ const useOutdent = normalized.outdent ?? true;
4057
+ const streamConfig = normalizeStreamConfig(normalized.stream);
4058
+ const debugConfig = normalizeDebugConfig(normalized.debug);
4059
+ const resolvedPrompt = applyPromptOutdent(resolvePrompt(normalized.prompt, { mode: "loose" }), useOutdent);
4060
+ const resolvedSystemPrompt = applyOutdentToOptionalPrompt(normalized.systemPrompt, useOutdent);
4061
+ const preparedPrompt = prepareGeneratePromptPayload(resolvedPrompt, resolvedSystemPrompt);
4062
+ const resolvedRequest = normalized.timeout?.tool !== undefined && normalized.request?.mcpClients !== undefined ? {
4063
+ ...normalized.request,
4064
+ mcpClients: applyToolTimeout(normalized.request.mcpClients, normalized.timeout.tool)
4065
+ } : normalized.request;
4066
+ const response = await callModel(adapter, {
4067
+ prompt: preparedPrompt.prompt,
4068
+ messages: preparedPrompt.messages,
4069
+ systemPrompt: preparedPrompt.systemPrompt,
4070
+ request: resolvedRequest,
4071
+ stream: streamConfig,
4072
+ observe: normalized.observe,
4073
+ buildEvent: ({ stage, message, details }) => ({
4074
+ stage,
4075
+ attempt: 1,
4076
+ message,
4077
+ details
4078
+ }),
4079
+ buildSnapshot: (model) => ({
4080
+ text: model.text,
4081
+ reasoning: model.reasoning
4082
+ }),
4083
+ debug: debugConfig,
4084
+ debugLabel: "generate",
4085
+ attempt: 1,
4086
+ selfHeal: false,
4087
+ selfHealEnabled: false,
4088
+ timeout: normalized.timeout
4089
+ });
4090
+ const attempt = {
4091
+ attempt: 1,
4092
+ via: response.via,
4093
+ text: response.text,
4094
+ reasoning: response.reasoning,
4095
+ usage: response.usage,
4096
+ finishReason: response.finishReason
4097
+ };
4098
+ const attempts = [attempt];
4099
+ normalized.observe?.({
4100
+ stage: "result",
4101
+ attempt: 1,
4102
+ message: "Text generation completed.",
4103
+ details: {
4104
+ via: response.via,
4105
+ finishReason: response.finishReason
4106
+ }
4107
+ });
4108
+ return {
4109
+ text: attempt.text,
4110
+ reasoning: attempt.reasoning,
4111
+ attempts,
4112
+ usage: aggregateUsage(attempts),
4113
+ finishReason: attempt.finishReason
4114
+ };
4115
+ }
4116
+ function normalizeGenerateInput(promptOrOptions, callOptions) {
4117
+ if (isGenerateOptions(promptOrOptions)) {
4118
+ return promptOrOptions;
4119
+ }
4120
+ if (!promptOrOptions) {
4121
+ throw new Error("Missing prompt in generate(adapter, prompt, options?) call.");
4122
+ }
4123
+ return {
4124
+ ...callOptions ?? {},
4125
+ prompt: promptOrOptions
4126
+ };
4127
+ }
4128
+ function isGenerateOptions(value) {
4129
+ return typeof value === "object" && value !== null && "prompt" in value;
4130
+ }
4131
+ function prepareGeneratePromptPayload(payload, systemPrompt) {
4132
+ if (Array.isArray(payload.messages) && payload.messages.length > 0) {
4133
+ const messages = payload.messages.map((message) => ({ ...message }));
4134
+ const mergedSystemPrompt = mergeSystemPrompts(payload.systemPrompt, systemPrompt);
4135
+ const systemMessages = mergedSystemPrompt ? [{ role: "system", content: mergedSystemPrompt }] : [];
4136
+ return {
4137
+ messages: [...systemMessages, ...messages]
4138
+ };
4139
+ }
4140
+ const resolvedPrompt = payload.prompt?.trim();
4141
+ if (!resolvedPrompt) {
4142
+ throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
4143
+ }
4144
+ return {
4145
+ prompt: resolvedPrompt,
4146
+ systemPrompt: mergeSystemPrompts(payload.systemPrompt, systemPrompt)
4147
+ };
4148
+ }
4149
+
4150
+ // src/structured.ts
4151
+ import { jsonrepair as jsonrepair3 } from "jsonrepair";
4152
+
4153
+ // src/parse.ts
4154
+ import { jsonrepair as jsonrepair2 } from "jsonrepair";
4155
+ function parseLLMOutput(output, schema, options = {}) {
4156
+ const sanitized = sanitizeThink(output);
4157
+ const parseOptions = {
4158
+ repair: options.repair ?? true,
4159
+ maxCandidates: options.maxCandidates ?? 5,
4160
+ acceptArrays: options.acceptArrays ?? true,
4161
+ extraction: options.extraction,
4162
+ onTrace: options.onTrace
4163
+ };
4164
+ const candidates = extractJsonCandidates(sanitized.visibleText, {
4165
+ maxCandidates: parseOptions.maxCandidates,
4166
+ acceptArrays: parseOptions.acceptArrays,
4167
+ allowRepairHints: parseOptions.repair,
4168
+ heuristics: parseOptions.extraction
4169
+ });
4170
+ emitTrace(parseOptions.onTrace, {
4171
+ stage: "extract",
4172
+ level: "info",
4173
+ message: `Extracted ${candidates.length} candidate(s).`,
4174
+ details: {
4175
+ maxCandidates: parseOptions.maxCandidates,
4176
+ thinkBlocks: sanitized.thinkBlocks.length,
4177
+ thinkDiagnostics: sanitized.diagnostics
4178
+ }
4179
+ });
4180
+ const errors = [];
4181
+ const diagnostics = [];
4182
+ let bestIssues = [];
4183
+ let bestCandidate = candidates[0] ?? null;
4184
+ let bestParsed = null;
4185
+ let bestRepaired = null;
3480
4186
  for (const candidate of candidates) {
3481
4187
  const parseAttempt = parseAttemptFromHint(candidate.parseHint, parseOptions.repair) ?? tryParseJsonCandidate(candidate.content, parseOptions.repair);
3482
4188
  if (!parseAttempt.success) {
@@ -3743,48 +4449,19 @@ function formatZodIssues(issues) {
3743
4449
  `);
3744
4450
  }
3745
4451
 
3746
- // src/utils/debug-colors.ts
3747
- var ANSI = {
3748
- reset: "\x1B[0m",
3749
- bold: "\x1B[1m",
3750
- cyan: "\x1B[36m",
3751
- yellow: "\x1B[33m",
3752
- green: "\x1B[32m",
3753
- red: "\x1B[31m",
3754
- dim: "\x1B[2m"
3755
- };
3756
- function color(config, text, tone) {
3757
- if (!config.colors) {
3758
- return text;
3759
- }
3760
- return `${ANSI[tone]}${text}${ANSI.reset}`;
3761
- }
3762
- function dim(config, text) {
3763
- if (!config.colors) {
3764
- return text;
3765
- }
3766
- return `${ANSI.dim}${text}${ANSI.reset}`;
3767
- }
3768
- function title(config, text) {
3769
- if (!config.colors) {
3770
- return text;
3771
- }
3772
- return `${ANSI.bold}${text}${ANSI.reset}`;
3773
- }
3774
-
3775
4452
  // src/structured.ts
3776
4453
  class StructuredParseError extends Error {
3777
4454
  name = "StructuredParseError";
3778
- raw;
3779
- thinkBlocks;
4455
+ text;
4456
+ reasoning;
3780
4457
  candidates;
3781
4458
  zodIssues;
3782
4459
  repairLog;
3783
4460
  attempt;
3784
4461
  constructor(input) {
3785
4462
  super(input.message ?? `Structured parsing failed after ${input.attempt} attempt(s).`);
3786
- this.raw = input.raw;
3787
- this.thinkBlocks = input.thinkBlocks;
4463
+ this.text = input.text;
4464
+ this.reasoning = input.reasoning;
3788
4465
  this.candidates = input.candidates;
3789
4466
  this.zodIssues = input.zodIssues;
3790
4467
  this.repairLog = input.repairLog;
@@ -3815,12 +4492,6 @@ var RE_SIMPLE_IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
3815
4492
  var RE_ESCAPE_QUOTE = /"/g;
3816
4493
  var RE_WHITESPACE2 = /\s+/g;
3817
4494
  var DEFAULT_SELF_HEAL_MAX_DIAGNOSTICS = 8;
3818
- var structuredOutdent = createOutdent({
3819
- trimLeadingNewline: true,
3820
- trimTrailingNewline: true,
3821
- newline: `
3822
- `
3823
- });
3824
4495
  var DEFAULT_STRICT_PARSE_OPTIONS = {
3825
4496
  repair: false,
3826
4497
  maxCandidates: 3,
@@ -3950,7 +4621,7 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
3950
4621
  });
3951
4622
  const selfHealSource = resolveSelfHealSource(previous);
3952
4623
  const repairPrompt = buildSelfHealPrompt({
3953
- rawOutput: previous.raw,
4624
+ rawOutput: composeParseSource(previous.text, previous.reasoning),
3954
4625
  issues: previous.zodIssues,
3955
4626
  schema: normalized.schema,
3956
4627
  schemaInstruction: normalized.schemaInstruction,
@@ -4023,74 +4694,6 @@ function normalizeStructuredInput(schemaOrOptions, promptInput, callOptions) {
4023
4694
  function isStructuredOptions(value) {
4024
4695
  return typeof value === "object" && value !== null && "schema" in value && "prompt" in value;
4025
4696
  }
4026
- function resolvePrompt(prompt, context) {
4027
- const resolved = typeof prompt === "function" ? prompt(context) : prompt;
4028
- return normalizePromptValue(resolved, context);
4029
- }
4030
- function normalizePromptValue(value, context) {
4031
- if (typeof value === "string") {
4032
- return {
4033
- prompt: value
4034
- };
4035
- }
4036
- if (isPromptResolver(value)) {
4037
- return normalizePromptPayload(value.resolvePrompt(context));
4038
- }
4039
- return normalizePromptPayload(value);
4040
- }
4041
- function isPromptResolver(value) {
4042
- return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
4043
- }
4044
- function normalizePromptPayload(value) {
4045
- const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
4046
- const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
4047
- if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
4048
- throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
4049
- }
4050
- return {
4051
- prompt,
4052
- systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
4053
- messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
4054
- };
4055
- }
4056
- function applyPromptOutdent(payload, enabled) {
4057
- if (!enabled) {
4058
- return payload;
4059
- }
4060
- return {
4061
- prompt: typeof payload.prompt === "string" ? structuredOutdent.string(payload.prompt) : undefined,
4062
- systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
4063
- messages: payload.messages?.map((message) => ({
4064
- ...message,
4065
- content: typeof message.content === "string" ? structuredOutdent.string(message.content) : message.content
4066
- }))
4067
- };
4068
- }
4069
- function isLLMMessage(value) {
4070
- if (typeof value !== "object" || value === null) {
4071
- return false;
4072
- }
4073
- const candidate = value;
4074
- if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
4075
- return false;
4076
- }
4077
- return "content" in candidate;
4078
- }
4079
- function applyOutdentToOptionalPrompt(value, enabled) {
4080
- if (!enabled || typeof value !== "string") {
4081
- return value;
4082
- }
4083
- return structuredOutdent.string(value);
4084
- }
4085
- function mergeSystemPrompts(primary, secondary) {
4086
- const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
4087
- if (prompts.length === 0) {
4088
- return;
4089
- }
4090
- return prompts.join(`
4091
-
4092
- `);
4093
- }
4094
4697
  function prepareStructuredPromptPayload(payload, systemPrompt, schema, schemaInstruction) {
4095
4698
  if (Array.isArray(payload.messages) && payload.messages.length > 0) {
4096
4699
  const messages = payload.messages.map((message) => ({ ...message }));
@@ -4271,70 +4874,32 @@ function resolveSelfHealSource(attempt) {
4271
4874
  }
4272
4875
  return {
4273
4876
  kind: "raw",
4274
- text: attempt.raw
4275
- };
4276
- }
4277
- function isSelfHealStalled(previous, current) {
4278
- if (current.success) {
4279
- return false;
4280
- }
4281
- if (current.zodIssues.length < previous.zodIssues.length) {
4282
- return false;
4283
- }
4284
- if (current.parsed.errors.length < previous.parsed.errors.length) {
4285
- return false;
4286
- }
4287
- return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
4288
- }
4289
- function buildSelfHealFailureFingerprint(attempt) {
4290
- const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
4291
- const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
4292
- const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
4293
- return [issues, errors, source].join("::");
4294
- }
4295
- function normalizeWhitespace(value) {
4296
- return value.replace(RE_WHITESPACE2, " ").trim();
4297
- }
4298
- function normalizeStreamConfig(option) {
4299
- if (typeof option === "boolean") {
4300
- return {
4301
- enabled: option
4302
- };
4303
- }
4304
- if (!option) {
4305
- return {
4306
- enabled: false
4307
- };
4308
- }
4309
- return {
4310
- enabled: option.enabled ?? true,
4311
- onData: option.onData,
4312
- to: option.to
4313
- };
4314
- }
4315
- function normalizeDebugConfig(option) {
4316
- if (typeof option === "boolean") {
4317
- return {
4318
- enabled: option,
4319
- colors: true,
4320
- logger: (line) => console.log(line)
4321
- };
4322
- }
4323
- if (!option) {
4324
- return {
4325
- enabled: false,
4326
- colors: true,
4327
- logger: (line) => console.log(line)
4328
- };
4329
- }
4330
- return {
4331
- enabled: option.enabled ?? true,
4332
- colors: option.colors ?? true,
4333
- logger: option.logger ?? ((line) => console.log(line))
4877
+ text: composeParseSource(attempt.text, attempt.reasoning)
4334
4878
  };
4335
4879
  }
4880
+ function isSelfHealStalled(previous, current) {
4881
+ if (current.success) {
4882
+ return false;
4883
+ }
4884
+ if (current.zodIssues.length < previous.zodIssues.length) {
4885
+ return false;
4886
+ }
4887
+ if (current.parsed.errors.length < previous.parsed.errors.length) {
4888
+ return false;
4889
+ }
4890
+ return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
4891
+ }
4892
+ function buildSelfHealFailureFingerprint(attempt) {
4893
+ const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
4894
+ const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
4895
+ const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
4896
+ return [issues, errors, source].join("::");
4897
+ }
4898
+ function normalizeWhitespace(value) {
4899
+ return value.replace(RE_WHITESPACE2, " ").trim();
4900
+ }
4336
4901
  async function executeAttempt(adapter, input) {
4337
- const response = await callModel(adapter, {
4902
+ const response = await callModel2(adapter, {
4338
4903
  prompt: input.prompt,
4339
4904
  messages: input.messages,
4340
4905
  systemPrompt: input.systemPrompt,
@@ -4347,7 +4912,7 @@ async function executeAttempt(adapter, input) {
4347
4912
  selfHealEnabled: input.selfHealEnabled,
4348
4913
  timeout: input.timeout
4349
4914
  });
4350
- const parsed = parseWithObserve(response.text, input.schema, input.parseOptions, {
4915
+ const parsed = parseWithObserve(response.parseSource, input.schema, input.parseOptions, {
4351
4916
  observe: input.observe,
4352
4917
  attempt: input.attemptNumber,
4353
4918
  selfHeal: input.selfHeal
@@ -4356,8 +4921,8 @@ async function executeAttempt(adapter, input) {
4356
4921
  attempt: input.attemptNumber,
4357
4922
  selfHeal: input.selfHeal,
4358
4923
  via: response.via,
4359
- raw: response.text,
4360
- thinkBlocks: parsed.thinkBlocks,
4924
+ text: response.text,
4925
+ reasoning: response.reasoning,
4361
4926
  json: parsed.parsed,
4362
4927
  candidates: parsed.candidates.map((candidate) => candidate.content),
4363
4928
  repairLog: collectRepairLog(parsed),
@@ -4372,195 +4937,26 @@ async function executeAttempt(adapter, input) {
4372
4937
  trace
4373
4938
  };
4374
4939
  }
4375
- function withToolTimeout(client, toolTimeoutMs) {
4376
- return {
4377
- id: client.id,
4378
- listTools: client.listTools.bind(client),
4379
- close: client.close?.bind(client),
4380
- async callTool(params) {
4381
- let timeoutId;
4382
- const timeoutPromise = new Promise((_, reject) => {
4383
- timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
4384
- });
4385
- try {
4386
- return await Promise.race([client.callTool(params), timeoutPromise]);
4387
- } finally {
4388
- clearTimeout(timeoutId);
4389
- }
4390
- }
4391
- };
4392
- }
4393
- function applyToolTimeout(clients, toolTimeoutMs) {
4394
- return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
4395
- }
4396
- async function callModel(adapter, options) {
4397
- const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
4398
- const requestPayload = {
4399
- prompt: options.prompt,
4400
- messages: options.messages,
4401
- systemPrompt: options.systemPrompt,
4402
- temperature: options.request?.temperature,
4403
- maxTokens: options.request?.maxTokens,
4404
- mcpClients: options.request?.mcpClients,
4405
- toolChoice: options.request?.toolChoice,
4406
- parallelToolCalls: options.request?.parallelToolCalls,
4407
- maxToolRounds: options.request?.maxToolRounds,
4408
- onToolExecution: options.request?.onToolExecution,
4409
- toolDebug: options.request?.toolDebug,
4410
- body: options.request?.body,
4411
- signal: requestSignal
4412
- };
4413
- emitDebugRequest(options.debug, {
4414
- provider: adapter.provider,
4415
- model: adapter.model,
4416
- attempt: options.attempt,
4417
- selfHealAttempt: options.selfHeal,
4418
- selfHealEnabled: options.selfHealEnabled,
4419
- stream: options.stream.enabled && !!adapter.stream,
4420
- requestPayload
4421
- });
4422
- emitObserve(options.observe, {
4423
- stage: "llm.request",
4424
- attempt: options.attempt,
4425
- selfHeal: options.selfHeal,
4426
- message: "Sending LLM request.",
4427
- details: {
4428
- provider: adapter.provider,
4429
- model: adapter.model,
4430
- stream: options.stream.enabled && !!adapter.stream
4431
- }
4432
- });
4433
- if (options.stream.enabled && adapter.stream) {
4434
- let latestUsage;
4435
- let latestFinishReason;
4436
- let streamedRaw = "";
4437
- let sawToken = false;
4438
- let lastDataFingerprint;
4439
- const emitStreamingData = (raw, done, usage2, finishReason2) => {
4440
- const data = parseStreamingStructuredData(raw);
4441
- if (data === null && !done) {
4442
- return;
4443
- }
4444
- const fingerprint = toStreamDataFingerprint(data ?? null);
4445
- if (!done && fingerprint === lastDataFingerprint) {
4446
- return;
4447
- }
4448
- lastDataFingerprint = fingerprint;
4449
- options.stream.onData?.({
4450
- data: data ?? null,
4451
- raw,
4452
- done,
4453
- usage: usage2,
4454
- finishReason: finishReason2
4455
- });
4456
- emitObserve(options.observe, {
4457
- stage: "llm.stream.data",
4458
- attempt: options.attempt,
4459
- selfHeal: options.selfHeal,
4460
- message: done ? "Streaming structured data completed." : "Streaming structured data updated.",
4461
- details: {
4462
- done,
4463
- finishReason: finishReason2
4464
- }
4465
- });
4466
- };
4467
- const handleTextDelta = (delta) => {
4468
- if (!delta) {
4469
- return;
4470
- }
4471
- streamedRaw += delta;
4472
- if (options.stream.to === "stdout") {
4473
- process.stdout.write(delta);
4474
- }
4475
- emitObserve(options.observe, {
4476
- stage: "llm.stream.delta",
4477
- attempt: options.attempt,
4478
- selfHeal: options.selfHeal,
4479
- message: "Received stream delta.",
4480
- details: {
4481
- chars: delta.length
4482
- }
4483
- });
4484
- emitStreamingData(streamedRaw, false);
4485
- };
4486
- const response2 = await adapter.stream(requestPayload, {
4487
- onToken: (token) => {
4488
- sawToken = true;
4489
- handleTextDelta(token);
4490
- },
4491
- onChunk: (chunk) => {
4492
- if (!sawToken && chunk.textDelta) {
4493
- handleTextDelta(chunk.textDelta);
4494
- }
4495
- if (chunk.usage) {
4496
- latestUsage = preferLatestUsage(latestUsage, chunk.usage);
4497
- }
4498
- if (chunk.finishReason) {
4499
- latestFinishReason = chunk.finishReason;
4500
- }
4501
- }
4502
- });
4503
- const finalText = typeof response2.text === "string" && response2.text.length > 0 ? response2.text : streamedRaw;
4504
- const usage = preferLatestUsage(latestUsage, response2.usage);
4505
- const finishReason = response2.finishReason ?? latestFinishReason;
4506
- emitStreamingData(finalText, true, usage, finishReason);
4507
- emitObserve(options.observe, {
4508
- stage: "llm.response",
4940
+ async function callModel2(adapter, options) {
4941
+ return callModel(adapter, {
4942
+ ...options,
4943
+ buildEvent: ({ stage, message, details }) => ({
4944
+ stage,
4509
4945
  attempt: options.attempt,
4510
4946
  selfHeal: options.selfHeal,
4511
- message: "Streaming response completed.",
4512
- details: {
4513
- via: "stream",
4514
- chars: finalText.length,
4515
- finishReason
4516
- }
4517
- });
4518
- emitDebugResponse(options.debug, {
4519
- attempt: options.attempt,
4520
- selfHealAttempt: options.selfHeal,
4521
- selfHealEnabled: options.selfHealEnabled,
4522
- via: "stream",
4523
- responseText: finalText,
4524
- usage,
4525
- finishReason
4526
- });
4527
- return {
4528
- text: finalText,
4529
- via: "stream",
4530
- usage,
4531
- finishReason
4532
- };
4533
- }
4534
- const response = await adapter.complete(requestPayload);
4535
- emitObserve(options.observe, {
4536
- stage: "llm.response",
4537
- attempt: options.attempt,
4538
- selfHeal: options.selfHeal,
4539
- message: "Completion response received.",
4540
- details: {
4541
- via: "complete",
4542
- chars: response.text.length,
4543
- finishReason: response.finishReason
4544
- }
4545
- });
4546
- emitDebugResponse(options.debug, {
4547
- attempt: options.attempt,
4548
- selfHealAttempt: options.selfHeal,
4549
- selfHealEnabled: options.selfHealEnabled,
4550
- via: "complete",
4551
- responseText: response.text,
4552
- usage: response.usage,
4553
- finishReason: response.finishReason
4947
+ message,
4948
+ details
4949
+ }),
4950
+ buildSnapshot: (normalized) => ({
4951
+ text: normalized.text,
4952
+ reasoning: normalized.reasoning,
4953
+ data: parseStreamingStructuredData(normalized.parseSource) ?? null
4954
+ }),
4955
+ debugLabel: "structured"
4554
4956
  });
4555
- return {
4556
- text: response.text,
4557
- via: "complete",
4558
- usage: response.usage,
4559
- finishReason: response.finishReason
4560
- };
4561
4957
  }
4562
- function parseStreamingStructuredData(raw) {
4563
- const sanitized = sanitizeThink(raw);
4958
+ function parseStreamingStructuredData(parseSource) {
4959
+ const sanitized = sanitizeThink(parseSource);
4564
4960
  const start = findFirstJsonRootStart(sanitized.visibleText);
4565
4961
  if (start < 0) {
4566
4962
  return null;
@@ -4620,13 +5016,6 @@ function findFirstJsonRootStart(input) {
4620
5016
  }
4621
5017
  return Math.min(objectStart, arrayStart);
4622
5018
  }
4623
- function toStreamDataFingerprint(value) {
4624
- try {
4625
- return JSON.stringify(value);
4626
- } catch {
4627
- return "__unserializable__";
4628
- }
4629
- }
4630
5019
  function parseWithObserve(output, schema, parseOptions, context) {
4631
5020
  const userParseTrace = parseOptions.onTrace;
4632
5021
  return parseLLMOutput(output, schema, {
@@ -4656,38 +5045,20 @@ function buildSuccessResult(data, attempts) {
4656
5045
  const final = attempts.at(-1);
4657
5046
  return {
4658
5047
  data,
4659
- raw: final?.raw ?? "",
4660
- thinkBlocks: final?.thinkBlocks ?? [],
5048
+ text: final?.text ?? "",
5049
+ reasoning: final?.reasoning ?? "",
4661
5050
  json: final?.json ?? null,
4662
5051
  attempts,
4663
5052
  usage: aggregateUsage(attempts),
4664
5053
  finishReason: final?.finishReason
4665
5054
  };
4666
5055
  }
4667
- function aggregateUsage(attempts) {
4668
- let usage;
4669
- for (const attempt of attempts) {
4670
- usage = mergeUsage2(usage, attempt.usage);
4671
- }
4672
- return usage;
4673
- }
4674
- function mergeUsage2(base, next) {
4675
- if (!base && !next) {
4676
- return;
4677
- }
4678
- return {
4679
- inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
4680
- outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
4681
- totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
4682
- cost: (base?.cost ?? 0) + (next?.cost ?? 0)
4683
- };
4684
- }
4685
5056
  function toStructuredError(attempt) {
4686
5057
  if (!attempt) {
4687
5058
  return new StructuredParseError({
4688
5059
  message: "Structured parsing failed before any model response.",
4689
- raw: "",
4690
- thinkBlocks: [],
5060
+ text: "",
5061
+ reasoning: "",
4691
5062
  candidates: [],
4692
5063
  zodIssues: [],
4693
5064
  repairLog: [],
@@ -4695,8 +5066,8 @@ function toStructuredError(attempt) {
4695
5066
  });
4696
5067
  }
4697
5068
  return new StructuredParseError({
4698
- raw: attempt.raw,
4699
- thinkBlocks: attempt.thinkBlocks,
5069
+ text: attempt.text,
5070
+ reasoning: attempt.reasoning,
4700
5071
  candidates: attempt.candidates,
4701
5072
  zodIssues: attempt.zodIssues,
4702
5073
  repairLog: attempt.repairLog,
@@ -4706,59 +5077,6 @@ function toStructuredError(attempt) {
4706
5077
  function emitObserve(observe, event) {
4707
5078
  observe?.(event);
4708
5079
  }
4709
- function emitDebugRequest(config, input) {
4710
- const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
4711
- const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
4712
- const lines = [
4713
- color(config, title(config, [
4714
- "[structured][request]",
4715
- `attempt=${input.attempt}`,
4716
- `selfHealEnabled=${input.selfHealEnabled}`,
4717
- `selfHealAttempt=${input.selfHealAttempt}`
4718
- ].join(" ")), "cyan"),
4719
- dim(config, [
4720
- `provider=${input.provider ?? "unknown"}`,
4721
- `model=${input.model ?? "unknown"}`,
4722
- `stream=${input.stream}`
4723
- ].join(" ")),
4724
- color(config, "prompt:", "yellow"),
4725
- input.requestPayload.prompt ?? "(none)",
4726
- color(config, "messages:", "yellow"),
4727
- requestMessages,
4728
- color(config, "systemPrompt:", "yellow"),
4729
- input.requestPayload.systemPrompt ?? "(none)",
4730
- color(config, "request.body:", "yellow"),
4731
- requestBody
4732
- ];
4733
- emitDebug(config, lines.join(`
4734
- `));
4735
- }
4736
- function emitDebugResponse(config, input) {
4737
- const lines = [
4738
- color(config, title(config, [
4739
- "[structured][response]",
4740
- `attempt=${input.attempt}`,
4741
- `selfHealEnabled=${input.selfHealEnabled}`,
4742
- `selfHealAttempt=${input.selfHealAttempt}`
4743
- ].join(" ")), "green"),
4744
- dim(config, [
4745
- `via=${input.via}`,
4746
- `chars=${input.responseText.length}`,
4747
- `finishReason=${input.finishReason ?? "unknown"}`,
4748
- `usage=${JSON.stringify(input.usage ?? {})}`
4749
- ].join(" ")),
4750
- color(config, "text:", "yellow"),
4751
- input.responseText
4752
- ];
4753
- emitDebug(config, lines.join(`
4754
- `));
4755
- }
4756
- function emitDebug(config, message) {
4757
- if (!config.enabled) {
4758
- return;
4759
- }
4760
- config.logger(message);
4761
- }
4762
5080
 
4763
5081
  // src/llm.ts
4764
5082
  function createLLM(config, registry = createDefaultProviderRegistry()) {
@@ -4772,6 +5090,17 @@ function createLLM(config, registry = createDefaultProviderRegistry()) {
4772
5090
  const merged = mergeStructuredOptions(defaults, options);
4773
5091
  return structured(adapter, schema, prompt, merged);
4774
5092
  },
5093
+ async generate(promptOrOptions, options) {
5094
+ if (isGenerateOptions2(promptOrOptions)) {
5095
+ const merged2 = {
5096
+ ...mergeGenerateOptions(defaults, promptOrOptions),
5097
+ prompt: promptOrOptions.prompt
5098
+ };
5099
+ return generate(adapter, merged2);
5100
+ }
5101
+ const merged = mergeGenerateOptions(defaults, options);
5102
+ return generate(adapter, promptOrOptions, merged);
5103
+ },
4775
5104
  async embed(input, options = {}) {
4776
5105
  if (!adapter.embed) {
4777
5106
  throw new Error(`Provider "${adapter.provider ?? "unknown"}" does not support embeddings.`);
@@ -4801,6 +5130,26 @@ function mergeStructuredOptions(defaults, overrides) {
4801
5130
  timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
4802
5131
  };
4803
5132
  }
5133
+ function mergeGenerateOptions(defaults, overrides) {
5134
+ if (!defaults && !overrides) {
5135
+ return {};
5136
+ }
5137
+ return {
5138
+ outdent: overrides?.outdent ?? defaults?.outdent,
5139
+ systemPrompt: overrides?.systemPrompt ?? defaults?.systemPrompt,
5140
+ request: {
5141
+ ...defaults?.request ?? {},
5142
+ ...overrides?.request ?? {}
5143
+ },
5144
+ stream: mergeObjectLike(defaults?.stream, overrides?.stream),
5145
+ debug: mergeObjectLike(defaults?.debug, overrides?.debug),
5146
+ timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout),
5147
+ observe: overrides?.observe ?? defaults?.observe
5148
+ };
5149
+ }
5150
+ function isGenerateOptions2(value) {
5151
+ return typeof value === "object" && value !== null && "prompt" in value;
5152
+ }
4804
5153
  function mergeObjectLike(defaults, overrides) {
4805
5154
  if (overrides === undefined) {
4806
5155
  return defaults;
@@ -5268,6 +5617,7 @@ export {
5268
5617
  inspectSchemaMetadata,
5269
5618
  inferSchemaExample,
5270
5619
  images,
5620
+ generate,
5271
5621
  formatZodIssues,
5272
5622
  formatPrompt,
5273
5623
  extractMarkdownCodeBlocks,