extrait 0.5.6 → 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
@@ -1572,6 +1572,7 @@ function createOpenAICompatibleAdapter(options) {
1572
1572
  model: options.model,
1573
1573
  messages: buildMessages(request),
1574
1574
  temperature: request.temperature,
1575
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1575
1576
  max_tokens: request.maxTokens,
1576
1577
  stream: true
1577
1578
  })),
@@ -1583,6 +1584,7 @@ function createOpenAICompatibleAdapter(options) {
1583
1584
  }
1584
1585
  callbacks.onStart?.();
1585
1586
  let text = "";
1587
+ let reasoning = "";
1586
1588
  let usage;
1587
1589
  let finishReason;
1588
1590
  await consumeSSE(response, (data) => {
@@ -1594,6 +1596,7 @@ function createOpenAICompatibleAdapter(options) {
1594
1596
  return;
1595
1597
  }
1596
1598
  const delta = pickAssistantDelta(json);
1599
+ const reasoningDelta = pickAssistantReasoningDelta(json);
1597
1600
  const chunkUsage = pickUsage(json);
1598
1601
  const chunkFinishReason = pickFinishReason(json);
1599
1602
  usage = preferLatestUsage(usage, chunkUsage);
@@ -1604,9 +1607,13 @@ function createOpenAICompatibleAdapter(options) {
1604
1607
  text += delta;
1605
1608
  callbacks.onToken?.(delta);
1606
1609
  }
1607
- if (delta || chunkUsage || chunkFinishReason) {
1610
+ if (reasoningDelta) {
1611
+ reasoning += reasoningDelta;
1612
+ }
1613
+ if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
1608
1614
  const chunk = {
1609
1615
  textDelta: delta,
1616
+ reasoningDelta: reasoningDelta || undefined,
1610
1617
  raw: json,
1611
1618
  usage: chunkUsage,
1612
1619
  finishReason: chunkFinishReason
@@ -1614,7 +1621,12 @@ function createOpenAICompatibleAdapter(options) {
1614
1621
  callbacks.onChunk?.(chunk);
1615
1622
  }
1616
1623
  });
1617
- const out = { text, usage, finishReason };
1624
+ const out = {
1625
+ text,
1626
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1627
+ usage,
1628
+ finishReason
1629
+ };
1618
1630
  callbacks.onComplete?.(out);
1619
1631
  return out;
1620
1632
  },
@@ -1674,6 +1686,7 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1674
1686
  model: options.model,
1675
1687
  messages: buildMessages(request),
1676
1688
  temperature: request.temperature,
1689
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1677
1690
  max_tokens: request.maxTokens,
1678
1691
  stream: false
1679
1692
  })),
@@ -1689,8 +1702,10 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1689
1702
  throw new Error("No assistant message in OpenAI-compatible response.");
1690
1703
  }
1691
1704
  const toolCalls = pickChatToolCalls(payload);
1705
+ const reasoning = pickAssistantReasoning(payload);
1692
1706
  return {
1693
1707
  text: pickAssistantText(payload),
1708
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1694
1709
  raw: payload,
1695
1710
  usage: pickUsage(payload),
1696
1711
  finishReason: pickFinishReason(payload),
@@ -1717,6 +1732,7 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1717
1732
  model: options.model,
1718
1733
  messages,
1719
1734
  temperature: request.temperature,
1735
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1720
1736
  max_tokens: request.maxTokens,
1721
1737
  tools: transportTools,
1722
1738
  tool_choice: request.toolChoice,
@@ -1738,8 +1754,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1738
1754
  throw new Error("No assistant message in OpenAI-compatible response.");
1739
1755
  }
1740
1756
  if (calledTools.length === 0) {
1757
+ const reasoning = pickAssistantReasoning(payload);
1741
1758
  return {
1742
1759
  text: pickAssistantText(payload),
1760
+ reasoning: reasoning.length > 0 ? reasoning : undefined,
1743
1761
  raw: payload,
1744
1762
  usage: aggregatedUsage,
1745
1763
  finishReason,
@@ -1767,6 +1785,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1767
1785
  }
1768
1786
  return {
1769
1787
  text: pickAssistantText(lastPayload ?? {}),
1788
+ reasoning: (() => {
1789
+ const value = pickAssistantReasoning(lastPayload ?? {});
1790
+ return value.length > 0 ? value : undefined;
1791
+ })(),
1770
1792
  raw: lastPayload,
1771
1793
  usage: aggregatedUsage,
1772
1794
  finishReason,
@@ -1786,6 +1808,7 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
1786
1808
  input: buildResponsesInput(request),
1787
1809
  previous_response_id: pickString(body?.previous_response_id),
1788
1810
  temperature: request.temperature,
1811
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1789
1812
  max_output_tokens: request.maxTokens
1790
1813
  })),
1791
1814
  signal: request.signal
@@ -1826,6 +1849,7 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
1826
1849
  input,
1827
1850
  previous_response_id: previousResponseId,
1828
1851
  temperature: request.temperature,
1852
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1829
1853
  max_output_tokens: request.maxTokens,
1830
1854
  tools: transportTools,
1831
1855
  tool_choice: request.toolChoice,
@@ -1890,6 +1914,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1890
1914
  const executedToolCalls = [];
1891
1915
  const toolExecutions = [];
1892
1916
  callbacks.onStart?.();
1917
+ let lastRoundText = "";
1918
+ let lastRoundReasoning = "";
1893
1919
  for (let round = 1;round <= maxToolRounds + 1; round += 1) {
1894
1920
  const mcpToolset = await resolveMCPToolset(request.mcpClients);
1895
1921
  const transportTools = toProviderFunctionTools(mcpToolset);
@@ -1902,6 +1928,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1902
1928
  model: options.model,
1903
1929
  messages,
1904
1930
  temperature: request.temperature,
1931
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
1905
1932
  max_tokens: request.maxTokens,
1906
1933
  tools: transportTools,
1907
1934
  tool_choice: request.toolChoice,
@@ -1915,9 +1942,11 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1915
1942
  throw new Error(`HTTP ${response.status}: ${message}`);
1916
1943
  }
1917
1944
  let roundText = "";
1945
+ let roundReasoning = "";
1918
1946
  let roundUsage;
1919
1947
  let roundFinishReason;
1920
1948
  const streamedToolCalls = new Map;
1949
+ let reasoningFieldName;
1921
1950
  await consumeSSE(response, (data) => {
1922
1951
  if (data === "[DONE]") {
1923
1952
  return;
@@ -1928,6 +1957,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1928
1957
  }
1929
1958
  lastPayload = json;
1930
1959
  const delta = pickAssistantDelta(json);
1960
+ const reasoningDelta = pickAssistantReasoningDelta(json);
1931
1961
  const chunkUsage = pickUsage(json);
1932
1962
  const chunkFinishReason = pickFinishReason(json);
1933
1963
  collectOpenAIStreamToolCalls(json, streamedToolCalls);
@@ -1939,9 +1969,14 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1939
1969
  roundText += delta;
1940
1970
  callbacks.onToken?.(delta);
1941
1971
  }
1942
- if (delta || chunkUsage || chunkFinishReason) {
1972
+ if (reasoningDelta) {
1973
+ roundReasoning += reasoningDelta;
1974
+ reasoningFieldName ??= pickAssistantReasoningDeltaFieldName(json);
1975
+ }
1976
+ if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
1943
1977
  const chunk = {
1944
1978
  textDelta: delta,
1979
+ reasoningDelta: reasoningDelta || undefined,
1945
1980
  raw: json,
1946
1981
  usage: chunkUsage,
1947
1982
  finishReason: chunkFinishReason
@@ -1957,6 +1992,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1957
1992
  if (calledTools.length === 0) {
1958
1993
  const out2 = {
1959
1994
  text: roundText,
1995
+ reasoning: roundReasoning.length > 0 ? roundReasoning : undefined,
1960
1996
  raw: lastPayload,
1961
1997
  usage: aggregatedUsage,
1962
1998
  finishReason,
@@ -1977,7 +2013,12 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1977
2013
  });
1978
2014
  executedToolCalls.push(...outputs.map((entry) => entry.call));
1979
2015
  toolExecutions.push(...outputs.map((entry) => entry.execution));
1980
- const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools);
2016
+ lastRoundText = roundText;
2017
+ lastRoundReasoning = roundReasoning;
2018
+ const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools, {
2019
+ reasoning: roundReasoning,
2020
+ reasoningFieldName
2021
+ });
1981
2022
  const toolMessages = outputs.map((entry) => ({
1982
2023
  role: "tool",
1983
2024
  tool_call_id: entry.call.id,
@@ -1986,7 +2027,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1986
2027
  messages = [...messages, assistantMessage, ...toolMessages];
1987
2028
  }
1988
2029
  const out = {
1989
- text: "",
2030
+ text: lastRoundText,
2031
+ reasoning: lastRoundReasoning.length > 0 ? lastRoundReasoning : undefined,
1990
2032
  raw: lastPayload,
1991
2033
  usage: aggregatedUsage,
1992
2034
  finishReason,
@@ -2008,6 +2050,7 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
2008
2050
  input: buildResponsesInput(request),
2009
2051
  previous_response_id: pickString(body?.previous_response_id),
2010
2052
  temperature: request.temperature,
2053
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
2011
2054
  max_output_tokens: request.maxTokens,
2012
2055
  stream: true
2013
2056
  })),
@@ -2088,6 +2131,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
2088
2131
  input,
2089
2132
  previous_response_id: previousResponseId,
2090
2133
  temperature: request.temperature,
2134
+ reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
2091
2135
  max_output_tokens: request.maxTokens,
2092
2136
  tools: transportTools,
2093
2137
  tool_choice: request.toolChoice,
@@ -2254,6 +2298,12 @@ function toResponsesTools(tools) {
2254
2298
  return { ...tool };
2255
2299
  });
2256
2300
  }
2301
+ function toOpenAIReasoningEffort(value) {
2302
+ if (!value) {
2303
+ return;
2304
+ }
2305
+ return value === "max" ? "xhigh" : value;
2306
+ }
2257
2307
  function pickChatToolCalls(payload) {
2258
2308
  const message = pickAssistantMessage(payload);
2259
2309
  if (!message) {
@@ -2335,20 +2385,50 @@ function pickAssistantDelta(payload) {
2335
2385
  if (!isRecord2(delta)) {
2336
2386
  return "";
2337
2387
  }
2338
- const content = delta.content;
2339
- if (typeof content === "string") {
2340
- return content;
2388
+ return pickTextFromOpenAIContent(delta.content);
2389
+ }
2390
+ function pickAssistantReasoning(payload) {
2391
+ const message = pickAssistantMessage(payload);
2392
+ if (!message) {
2393
+ return "";
2341
2394
  }
2342
- if (Array.isArray(content)) {
2343
- return content.map((part) => {
2344
- if (!isRecord2(part)) {
2345
- return "";
2346
- }
2347
- const text = part.text;
2348
- return typeof text === "string" ? text : "";
2349
- }).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 "";
2350
2401
  }
2351
- 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;
2352
2432
  }
2353
2433
  function collectOpenAIStreamToolCalls(payload, state) {
2354
2434
  const choices = payload.choices;
@@ -2397,8 +2477,8 @@ function buildOpenAIStreamToolCalls(state) {
2397
2477
  arguments: entry.argumentsText.length > 0 ? entry.argumentsText : {}
2398
2478
  }));
2399
2479
  }
2400
- function buildOpenAIAssistantToolMessage(text, toolCalls) {
2401
- return {
2480
+ function buildOpenAIAssistantToolMessage(text, toolCalls, reasoning) {
2481
+ const message = {
2402
2482
  role: "assistant",
2403
2483
  content: text,
2404
2484
  tool_calls: toolCalls.map((call) => ({
@@ -2410,6 +2490,10 @@ function buildOpenAIAssistantToolMessage(text, toolCalls) {
2410
2490
  }
2411
2491
  }))
2412
2492
  };
2493
+ if (reasoning?.reasoning && reasoning.reasoning.length > 0) {
2494
+ message[reasoning.reasoningFieldName ?? "reasoning"] = reasoning.reasoning;
2495
+ }
2496
+ return message;
2413
2497
  }
2414
2498
  function pickResponsesStreamPayload(payload) {
2415
2499
  if (isRecord2(payload.response)) {
@@ -2571,21 +2655,9 @@ function pickResponsesText(payload) {
2571
2655
  function pickAssistantText(payload) {
2572
2656
  const message = pickAssistantMessage(payload);
2573
2657
  if (message) {
2574
- const content = message.content;
2575
- if (typeof content === "string") {
2576
- return content;
2577
- }
2578
- if (Array.isArray(content)) {
2579
- return content.map((part) => {
2580
- if (typeof part === "string") {
2581
- return part;
2582
- }
2583
- if (!isRecord2(part)) {
2584
- return "";
2585
- }
2586
- const text = part.text;
2587
- return typeof text === "string" ? text : "";
2588
- }).join("");
2658
+ const text = pickTextFromOpenAIContent(message.content);
2659
+ if (text.length > 0) {
2660
+ return text;
2589
2661
  }
2590
2662
  }
2591
2663
  const choices = payload.choices;
@@ -2597,6 +2669,36 @@ function pickAssistantText(payload) {
2597
2669
  }
2598
2670
  return "";
2599
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
+ }
2600
2702
  function pickUsage(payload) {
2601
2703
  const usage = payload.usage;
2602
2704
  if (!isRecord2(usage)) {
@@ -2650,14 +2752,13 @@ function createAnthropicCompatibleAdapter(options) {
2650
2752
  const response = await fetcher(buildURL(options.baseURL, path), {
2651
2753
  method: "POST",
2652
2754
  headers: buildHeaders2(options),
2653
- body: JSON.stringify(cleanUndefined({
2755
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2654
2756
  ...options.defaultBody,
2655
2757
  ...request.body,
2656
2758
  model: options.model,
2657
2759
  system: input.systemPrompt,
2658
2760
  messages: input.messages,
2659
2761
  temperature: request.temperature,
2660
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2661
2762
  stream: true
2662
2763
  })),
2663
2764
  signal: request.signal
@@ -2713,14 +2814,13 @@ async function completePassThrough(options, fetcher, path, request) {
2713
2814
  const response = await fetcher(buildURL(options.baseURL, path), {
2714
2815
  method: "POST",
2715
2816
  headers: buildHeaders2(options),
2716
- body: JSON.stringify(cleanUndefined({
2817
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2717
2818
  ...options.defaultBody,
2718
2819
  ...request.body,
2719
2820
  model: options.model,
2720
2821
  system: input.systemPrompt,
2721
2822
  messages: input.messages,
2722
2823
  temperature: request.temperature,
2723
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2724
2824
  stream: false
2725
2825
  })),
2726
2826
  signal: request.signal
@@ -2758,14 +2858,13 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2758
2858
  const response = await fetcher(buildURL(options.baseURL, path), {
2759
2859
  method: "POST",
2760
2860
  headers: buildHeaders2(options),
2761
- body: JSON.stringify(cleanUndefined({
2861
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2762
2862
  ...options.defaultBody,
2763
2863
  ...request.body,
2764
2864
  model: options.model,
2765
2865
  system: input.systemPrompt,
2766
2866
  messages,
2767
2867
  temperature: request.temperature,
2768
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2769
2868
  tools,
2770
2869
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2771
2870
  stream: false
@@ -2843,14 +2942,13 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
2843
2942
  const response = await fetcher(buildURL(options.baseURL, path), {
2844
2943
  method: "POST",
2845
2944
  headers: buildHeaders2(options),
2846
- body: JSON.stringify(cleanUndefined({
2945
+ body: JSON.stringify(buildAnthropicRequestBody(options, request, {
2847
2946
  ...options.defaultBody,
2848
2947
  ...request.body,
2849
2948
  model: options.model,
2850
2949
  system: input.systemPrompt,
2851
2950
  messages,
2852
2951
  temperature: request.temperature,
2853
- max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2854
2952
  tools,
2855
2953
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2856
2954
  stream: true
@@ -2958,6 +3056,21 @@ function buildHeaders2(options) {
2958
3056
  ...options.headers
2959
3057
  };
2960
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
+ }
2961
3074
  function resolveAnthropicInput(request) {
2962
3075
  if (Array.isArray(request.messages) && request.messages.length > 0) {
2963
3076
  return toAnthropicInput(request.messages);
@@ -3312,8 +3425,34 @@ function buildProviderOptions(config) {
3312
3425
  };
3313
3426
  }
3314
3427
 
3315
- // src/structured.ts
3316
- 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
+ }
3317
3456
 
3318
3457
  // src/outdent.ts
3319
3458
  var DEFAULT_OPTIONS = {
@@ -3452,44 +3591,603 @@ function createOutdent(options = {}) {
3452
3591
  return outdent;
3453
3592
  }
3454
3593
 
3455
- // src/parse.ts
3456
- import { jsonrepair as jsonrepair2 } from "jsonrepair";
3457
- function parseLLMOutput(output, schema, options = {}) {
3458
- const sanitized = sanitizeThink(output);
3459
- const parseOptions = {
3460
- repair: options.repair ?? true,
3461
- maxCandidates: options.maxCandidates ?? 5,
3462
- acceptArrays: options.acceptArrays ?? true,
3463
- extraction: options.extraction,
3464
- 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
3465
3627
  };
3466
- const candidates = extractJsonCandidates(sanitized.visibleText, {
3467
- maxCandidates: parseOptions.maxCandidates,
3468
- acceptArrays: parseOptions.acceptArrays,
3469
- allowRepairHints: parseOptions.repair,
3470
- heuristics: parseOptions.extraction
3471
- });
3472
- emitTrace(parseOptions.onTrace, {
3473
- stage: "extract",
3474
- level: "info",
3475
- message: `Extracted ${candidates.length} candidate(s).`,
3476
- details: {
3477
- maxCandidates: parseOptions.maxCandidates,
3478
- thinkBlocks: sanitized.thinkBlocks.length,
3479
- 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
+ }
3480
3713
  }
3481
- });
3482
- const errors = [];
3483
- const diagnostics = [];
3484
- let bestIssues = [];
3485
- let bestCandidate = candidates[0] ?? null;
3486
- let bestParsed = null;
3487
- let bestRepaired = null;
3488
- for (const candidate of candidates) {
3489
- const parseAttempt = parseAttemptFromHint(candidate.parseHint, parseOptions.repair) ?? tryParseJsonCandidate(candidate.content, parseOptions.repair);
3490
- if (!parseAttempt.success) {
3491
- const diagnostic = {
3492
- candidateId: candidate.id,
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;
4186
+ for (const candidate of candidates) {
4187
+ const parseAttempt = parseAttemptFromHint(candidate.parseHint, parseOptions.repair) ?? tryParseJsonCandidate(candidate.content, parseOptions.repair);
4188
+ if (!parseAttempt.success) {
4189
+ const diagnostic = {
4190
+ candidateId: candidate.id,
3493
4191
  source: candidate.source,
3494
4192
  usedRepair: parseAttempt.usedRepair,
3495
4193
  parseSuccess: false,
@@ -3751,48 +4449,19 @@ function formatZodIssues(issues) {
3751
4449
  `);
3752
4450
  }
3753
4451
 
3754
- // src/utils/debug-colors.ts
3755
- var ANSI = {
3756
- reset: "\x1B[0m",
3757
- bold: "\x1B[1m",
3758
- cyan: "\x1B[36m",
3759
- yellow: "\x1B[33m",
3760
- green: "\x1B[32m",
3761
- red: "\x1B[31m",
3762
- dim: "\x1B[2m"
3763
- };
3764
- function color(config, text, tone) {
3765
- if (!config.colors) {
3766
- return text;
3767
- }
3768
- return `${ANSI[tone]}${text}${ANSI.reset}`;
3769
- }
3770
- function dim(config, text) {
3771
- if (!config.colors) {
3772
- return text;
3773
- }
3774
- return `${ANSI.dim}${text}${ANSI.reset}`;
3775
- }
3776
- function title(config, text) {
3777
- if (!config.colors) {
3778
- return text;
3779
- }
3780
- return `${ANSI.bold}${text}${ANSI.reset}`;
3781
- }
3782
-
3783
4452
  // src/structured.ts
3784
4453
  class StructuredParseError extends Error {
3785
4454
  name = "StructuredParseError";
3786
- raw;
3787
- thinkBlocks;
4455
+ text;
4456
+ reasoning;
3788
4457
  candidates;
3789
4458
  zodIssues;
3790
4459
  repairLog;
3791
4460
  attempt;
3792
4461
  constructor(input) {
3793
4462
  super(input.message ?? `Structured parsing failed after ${input.attempt} attempt(s).`);
3794
- this.raw = input.raw;
3795
- this.thinkBlocks = input.thinkBlocks;
4463
+ this.text = input.text;
4464
+ this.reasoning = input.reasoning;
3796
4465
  this.candidates = input.candidates;
3797
4466
  this.zodIssues = input.zodIssues;
3798
4467
  this.repairLog = input.repairLog;
@@ -3823,12 +4492,6 @@ var RE_SIMPLE_IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
3823
4492
  var RE_ESCAPE_QUOTE = /"/g;
3824
4493
  var RE_WHITESPACE2 = /\s+/g;
3825
4494
  var DEFAULT_SELF_HEAL_MAX_DIAGNOSTICS = 8;
3826
- var structuredOutdent = createOutdent({
3827
- trimLeadingNewline: true,
3828
- trimTrailingNewline: true,
3829
- newline: `
3830
- `
3831
- });
3832
4495
  var DEFAULT_STRICT_PARSE_OPTIONS = {
3833
4496
  repair: false,
3834
4497
  maxCandidates: 3,
@@ -3958,7 +4621,7 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
3958
4621
  });
3959
4622
  const selfHealSource = resolveSelfHealSource(previous);
3960
4623
  const repairPrompt = buildSelfHealPrompt({
3961
- rawOutput: previous.raw,
4624
+ rawOutput: composeParseSource(previous.text, previous.reasoning),
3962
4625
  issues: previous.zodIssues,
3963
4626
  schema: normalized.schema,
3964
4627
  schemaInstruction: normalized.schemaInstruction,
@@ -4031,74 +4694,6 @@ function normalizeStructuredInput(schemaOrOptions, promptInput, callOptions) {
4031
4694
  function isStructuredOptions(value) {
4032
4695
  return typeof value === "object" && value !== null && "schema" in value && "prompt" in value;
4033
4696
  }
4034
- function resolvePrompt(prompt, context) {
4035
- const resolved = typeof prompt === "function" ? prompt(context) : prompt;
4036
- return normalizePromptValue(resolved, context);
4037
- }
4038
- function normalizePromptValue(value, context) {
4039
- if (typeof value === "string") {
4040
- return {
4041
- prompt: value
4042
- };
4043
- }
4044
- if (isPromptResolver(value)) {
4045
- return normalizePromptPayload(value.resolvePrompt(context));
4046
- }
4047
- return normalizePromptPayload(value);
4048
- }
4049
- function isPromptResolver(value) {
4050
- return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
4051
- }
4052
- function normalizePromptPayload(value) {
4053
- const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
4054
- const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
4055
- if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
4056
- throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
4057
- }
4058
- return {
4059
- prompt,
4060
- systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
4061
- messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
4062
- };
4063
- }
4064
- function applyPromptOutdent(payload, enabled) {
4065
- if (!enabled) {
4066
- return payload;
4067
- }
4068
- return {
4069
- prompt: typeof payload.prompt === "string" ? structuredOutdent.string(payload.prompt) : undefined,
4070
- systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
4071
- messages: payload.messages?.map((message) => ({
4072
- ...message,
4073
- content: typeof message.content === "string" ? structuredOutdent.string(message.content) : message.content
4074
- }))
4075
- };
4076
- }
4077
- function isLLMMessage(value) {
4078
- if (typeof value !== "object" || value === null) {
4079
- return false;
4080
- }
4081
- const candidate = value;
4082
- if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
4083
- return false;
4084
- }
4085
- return "content" in candidate;
4086
- }
4087
- function applyOutdentToOptionalPrompt(value, enabled) {
4088
- if (!enabled || typeof value !== "string") {
4089
- return value;
4090
- }
4091
- return structuredOutdent.string(value);
4092
- }
4093
- function mergeSystemPrompts(primary, secondary) {
4094
- const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
4095
- if (prompts.length === 0) {
4096
- return;
4097
- }
4098
- return prompts.join(`
4099
-
4100
- `);
4101
- }
4102
4697
  function prepareStructuredPromptPayload(payload, systemPrompt, schema, schemaInstruction) {
4103
4698
  if (Array.isArray(payload.messages) && payload.messages.length > 0) {
4104
4699
  const messages = payload.messages.map((message) => ({ ...message }));
@@ -4279,7 +4874,7 @@ function resolveSelfHealSource(attempt) {
4279
4874
  }
4280
4875
  return {
4281
4876
  kind: "raw",
4282
- text: attempt.raw
4877
+ text: composeParseSource(attempt.text, attempt.reasoning)
4283
4878
  };
4284
4879
  }
4285
4880
  function isSelfHealStalled(previous, current) {
@@ -4289,60 +4884,22 @@ function isSelfHealStalled(previous, current) {
4289
4884
  if (current.zodIssues.length < previous.zodIssues.length) {
4290
4885
  return false;
4291
4886
  }
4292
- if (current.parsed.errors.length < previous.parsed.errors.length) {
4293
- return false;
4294
- }
4295
- return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
4296
- }
4297
- function buildSelfHealFailureFingerprint(attempt) {
4298
- const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
4299
- const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
4300
- const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
4301
- return [issues, errors, source].join("::");
4302
- }
4303
- function normalizeWhitespace(value) {
4304
- return value.replace(RE_WHITESPACE2, " ").trim();
4305
- }
4306
- function normalizeStreamConfig(option) {
4307
- if (typeof option === "boolean") {
4308
- return {
4309
- enabled: option
4310
- };
4311
- }
4312
- if (!option) {
4313
- return {
4314
- enabled: false
4315
- };
4316
- }
4317
- return {
4318
- enabled: option.enabled ?? true,
4319
- onData: option.onData,
4320
- to: option.to
4321
- };
4322
- }
4323
- function normalizeDebugConfig(option) {
4324
- if (typeof option === "boolean") {
4325
- return {
4326
- enabled: option,
4327
- colors: true,
4328
- logger: (line) => console.log(line)
4329
- };
4330
- }
4331
- if (!option) {
4332
- return {
4333
- enabled: false,
4334
- colors: true,
4335
- logger: (line) => console.log(line)
4336
- };
4887
+ if (current.parsed.errors.length < previous.parsed.errors.length) {
4888
+ return false;
4337
4889
  }
4338
- return {
4339
- enabled: option.enabled ?? true,
4340
- colors: option.colors ?? true,
4341
- logger: option.logger ?? ((line) => console.log(line))
4342
- };
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();
4343
4900
  }
4344
4901
  async function executeAttempt(adapter, input) {
4345
- const response = await callModel(adapter, {
4902
+ const response = await callModel2(adapter, {
4346
4903
  prompt: input.prompt,
4347
4904
  messages: input.messages,
4348
4905
  systemPrompt: input.systemPrompt,
@@ -4355,7 +4912,7 @@ async function executeAttempt(adapter, input) {
4355
4912
  selfHealEnabled: input.selfHealEnabled,
4356
4913
  timeout: input.timeout
4357
4914
  });
4358
- const parsed = parseWithObserve(response.text, input.schema, input.parseOptions, {
4915
+ const parsed = parseWithObserve(response.parseSource, input.schema, input.parseOptions, {
4359
4916
  observe: input.observe,
4360
4917
  attempt: input.attemptNumber,
4361
4918
  selfHeal: input.selfHeal
@@ -4364,8 +4921,8 @@ async function executeAttempt(adapter, input) {
4364
4921
  attempt: input.attemptNumber,
4365
4922
  selfHeal: input.selfHeal,
4366
4923
  via: response.via,
4367
- raw: response.text,
4368
- thinkBlocks: parsed.thinkBlocks,
4924
+ text: response.text,
4925
+ reasoning: response.reasoning,
4369
4926
  json: parsed.parsed,
4370
4927
  candidates: parsed.candidates.map((candidate) => candidate.content),
4371
4928
  repairLog: collectRepairLog(parsed),
@@ -4380,199 +4937,26 @@ async function executeAttempt(adapter, input) {
4380
4937
  trace
4381
4938
  };
4382
4939
  }
4383
- function withToolTimeout(client, toolTimeoutMs) {
4384
- return {
4385
- id: client.id,
4386
- listTools: client.listTools.bind(client),
4387
- close: client.close?.bind(client),
4388
- async callTool(params) {
4389
- let timeoutId;
4390
- const timeoutPromise = new Promise((_, reject) => {
4391
- timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
4392
- });
4393
- try {
4394
- return await Promise.race([client.callTool(params), timeoutPromise]);
4395
- } finally {
4396
- clearTimeout(timeoutId);
4397
- }
4398
- }
4399
- };
4400
- }
4401
- function applyToolTimeout(clients, toolTimeoutMs) {
4402
- return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
4403
- }
4404
- async function callModel(adapter, options) {
4405
- const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
4406
- const requestPayload = {
4407
- prompt: options.prompt,
4408
- messages: options.messages,
4409
- systemPrompt: options.systemPrompt,
4410
- temperature: options.request?.temperature,
4411
- maxTokens: options.request?.maxTokens,
4412
- mcpClients: options.request?.mcpClients,
4413
- toolChoice: options.request?.toolChoice,
4414
- parallelToolCalls: options.request?.parallelToolCalls,
4415
- maxToolRounds: options.request?.maxToolRounds,
4416
- onToolExecution: options.request?.onToolExecution,
4417
- transformToolOutput: options.request?.transformToolOutput,
4418
- transformToolArguments: options.request?.transformToolArguments,
4419
- transformToolCallParams: options.request?.transformToolCallParams,
4420
- unknownToolError: options.request?.unknownToolError,
4421
- toolDebug: options.request?.toolDebug,
4422
- body: options.request?.body,
4423
- signal: requestSignal
4424
- };
4425
- emitDebugRequest(options.debug, {
4426
- provider: adapter.provider,
4427
- model: adapter.model,
4428
- attempt: options.attempt,
4429
- selfHealAttempt: options.selfHeal,
4430
- selfHealEnabled: options.selfHealEnabled,
4431
- stream: options.stream.enabled && !!adapter.stream,
4432
- requestPayload
4433
- });
4434
- emitObserve(options.observe, {
4435
- stage: "llm.request",
4436
- attempt: options.attempt,
4437
- selfHeal: options.selfHeal,
4438
- message: "Sending LLM request.",
4439
- details: {
4440
- provider: adapter.provider,
4441
- model: adapter.model,
4442
- stream: options.stream.enabled && !!adapter.stream
4443
- }
4444
- });
4445
- if (options.stream.enabled && adapter.stream) {
4446
- let latestUsage;
4447
- let latestFinishReason;
4448
- let streamedRaw = "";
4449
- let sawToken = false;
4450
- let lastDataFingerprint;
4451
- const emitStreamingData = (raw, done, usage2, finishReason2) => {
4452
- const data = parseStreamingStructuredData(raw);
4453
- if (data === null && !done) {
4454
- return;
4455
- }
4456
- const fingerprint = toStreamDataFingerprint(data ?? null);
4457
- if (!done && fingerprint === lastDataFingerprint) {
4458
- return;
4459
- }
4460
- lastDataFingerprint = fingerprint;
4461
- options.stream.onData?.({
4462
- data: data ?? null,
4463
- raw,
4464
- done,
4465
- usage: usage2,
4466
- finishReason: finishReason2
4467
- });
4468
- emitObserve(options.observe, {
4469
- stage: "llm.stream.data",
4470
- attempt: options.attempt,
4471
- selfHeal: options.selfHeal,
4472
- message: done ? "Streaming structured data completed." : "Streaming structured data updated.",
4473
- details: {
4474
- done,
4475
- finishReason: finishReason2
4476
- }
4477
- });
4478
- };
4479
- const handleTextDelta = (delta) => {
4480
- if (!delta) {
4481
- return;
4482
- }
4483
- streamedRaw += delta;
4484
- if (options.stream.to === "stdout") {
4485
- process.stdout.write(delta);
4486
- }
4487
- emitObserve(options.observe, {
4488
- stage: "llm.stream.delta",
4489
- attempt: options.attempt,
4490
- selfHeal: options.selfHeal,
4491
- message: "Received stream delta.",
4492
- details: {
4493
- chars: delta.length
4494
- }
4495
- });
4496
- emitStreamingData(streamedRaw, false);
4497
- };
4498
- const response2 = await adapter.stream(requestPayload, {
4499
- onToken: (token) => {
4500
- sawToken = true;
4501
- handleTextDelta(token);
4502
- },
4503
- onChunk: (chunk) => {
4504
- if (!sawToken && chunk.textDelta) {
4505
- handleTextDelta(chunk.textDelta);
4506
- }
4507
- if (chunk.usage) {
4508
- latestUsage = preferLatestUsage(latestUsage, chunk.usage);
4509
- }
4510
- if (chunk.finishReason) {
4511
- latestFinishReason = chunk.finishReason;
4512
- }
4513
- }
4514
- });
4515
- const finalText = typeof response2.text === "string" && response2.text.length > 0 ? response2.text : streamedRaw;
4516
- const usage = preferLatestUsage(latestUsage, response2.usage);
4517
- const finishReason = response2.finishReason ?? latestFinishReason;
4518
- emitStreamingData(finalText, true, usage, finishReason);
4519
- emitObserve(options.observe, {
4520
- stage: "llm.response",
4940
+ async function callModel2(adapter, options) {
4941
+ return callModel(adapter, {
4942
+ ...options,
4943
+ buildEvent: ({ stage, message, details }) => ({
4944
+ stage,
4521
4945
  attempt: options.attempt,
4522
4946
  selfHeal: options.selfHeal,
4523
- message: "Streaming response completed.",
4524
- details: {
4525
- via: "stream",
4526
- chars: finalText.length,
4527
- finishReason
4528
- }
4529
- });
4530
- emitDebugResponse(options.debug, {
4531
- attempt: options.attempt,
4532
- selfHealAttempt: options.selfHeal,
4533
- selfHealEnabled: options.selfHealEnabled,
4534
- via: "stream",
4535
- responseText: finalText,
4536
- usage,
4537
- finishReason
4538
- });
4539
- return {
4540
- text: finalText,
4541
- via: "stream",
4542
- usage,
4543
- finishReason
4544
- };
4545
- }
4546
- const response = await adapter.complete(requestPayload);
4547
- emitObserve(options.observe, {
4548
- stage: "llm.response",
4549
- attempt: options.attempt,
4550
- selfHeal: options.selfHeal,
4551
- message: "Completion response received.",
4552
- details: {
4553
- via: "complete",
4554
- chars: response.text.length,
4555
- finishReason: response.finishReason
4556
- }
4557
- });
4558
- emitDebugResponse(options.debug, {
4559
- attempt: options.attempt,
4560
- selfHealAttempt: options.selfHeal,
4561
- selfHealEnabled: options.selfHealEnabled,
4562
- via: "complete",
4563
- responseText: response.text,
4564
- usage: response.usage,
4565
- 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"
4566
4956
  });
4567
- return {
4568
- text: response.text,
4569
- via: "complete",
4570
- usage: response.usage,
4571
- finishReason: response.finishReason
4572
- };
4573
4957
  }
4574
- function parseStreamingStructuredData(raw) {
4575
- const sanitized = sanitizeThink(raw);
4958
+ function parseStreamingStructuredData(parseSource) {
4959
+ const sanitized = sanitizeThink(parseSource);
4576
4960
  const start = findFirstJsonRootStart(sanitized.visibleText);
4577
4961
  if (start < 0) {
4578
4962
  return null;
@@ -4632,13 +5016,6 @@ function findFirstJsonRootStart(input) {
4632
5016
  }
4633
5017
  return Math.min(objectStart, arrayStart);
4634
5018
  }
4635
- function toStreamDataFingerprint(value) {
4636
- try {
4637
- return JSON.stringify(value);
4638
- } catch {
4639
- return "__unserializable__";
4640
- }
4641
- }
4642
5019
  function parseWithObserve(output, schema, parseOptions, context) {
4643
5020
  const userParseTrace = parseOptions.onTrace;
4644
5021
  return parseLLMOutput(output, schema, {
@@ -4668,38 +5045,20 @@ function buildSuccessResult(data, attempts) {
4668
5045
  const final = attempts.at(-1);
4669
5046
  return {
4670
5047
  data,
4671
- raw: final?.raw ?? "",
4672
- thinkBlocks: final?.thinkBlocks ?? [],
5048
+ text: final?.text ?? "",
5049
+ reasoning: final?.reasoning ?? "",
4673
5050
  json: final?.json ?? null,
4674
5051
  attempts,
4675
5052
  usage: aggregateUsage(attempts),
4676
5053
  finishReason: final?.finishReason
4677
5054
  };
4678
5055
  }
4679
- function aggregateUsage(attempts) {
4680
- let usage;
4681
- for (const attempt of attempts) {
4682
- usage = mergeUsage2(usage, attempt.usage);
4683
- }
4684
- return usage;
4685
- }
4686
- function mergeUsage2(base, next) {
4687
- if (!base && !next) {
4688
- return;
4689
- }
4690
- return {
4691
- inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
4692
- outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
4693
- totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
4694
- cost: (base?.cost ?? 0) + (next?.cost ?? 0)
4695
- };
4696
- }
4697
5056
  function toStructuredError(attempt) {
4698
5057
  if (!attempt) {
4699
5058
  return new StructuredParseError({
4700
5059
  message: "Structured parsing failed before any model response.",
4701
- raw: "",
4702
- thinkBlocks: [],
5060
+ text: "",
5061
+ reasoning: "",
4703
5062
  candidates: [],
4704
5063
  zodIssues: [],
4705
5064
  repairLog: [],
@@ -4707,8 +5066,8 @@ function toStructuredError(attempt) {
4707
5066
  });
4708
5067
  }
4709
5068
  return new StructuredParseError({
4710
- raw: attempt.raw,
4711
- thinkBlocks: attempt.thinkBlocks,
5069
+ text: attempt.text,
5070
+ reasoning: attempt.reasoning,
4712
5071
  candidates: attempt.candidates,
4713
5072
  zodIssues: attempt.zodIssues,
4714
5073
  repairLog: attempt.repairLog,
@@ -4718,59 +5077,6 @@ function toStructuredError(attempt) {
4718
5077
  function emitObserve(observe, event) {
4719
5078
  observe?.(event);
4720
5079
  }
4721
- function emitDebugRequest(config, input) {
4722
- const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
4723
- const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
4724
- const lines = [
4725
- color(config, title(config, [
4726
- "[structured][request]",
4727
- `attempt=${input.attempt}`,
4728
- `selfHealEnabled=${input.selfHealEnabled}`,
4729
- `selfHealAttempt=${input.selfHealAttempt}`
4730
- ].join(" ")), "cyan"),
4731
- dim(config, [
4732
- `provider=${input.provider ?? "unknown"}`,
4733
- `model=${input.model ?? "unknown"}`,
4734
- `stream=${input.stream}`
4735
- ].join(" ")),
4736
- color(config, "prompt:", "yellow"),
4737
- input.requestPayload.prompt ?? "(none)",
4738
- color(config, "messages:", "yellow"),
4739
- requestMessages,
4740
- color(config, "systemPrompt:", "yellow"),
4741
- input.requestPayload.systemPrompt ?? "(none)",
4742
- color(config, "request.body:", "yellow"),
4743
- requestBody
4744
- ];
4745
- emitDebug(config, lines.join(`
4746
- `));
4747
- }
4748
- function emitDebugResponse(config, input) {
4749
- const lines = [
4750
- color(config, title(config, [
4751
- "[structured][response]",
4752
- `attempt=${input.attempt}`,
4753
- `selfHealEnabled=${input.selfHealEnabled}`,
4754
- `selfHealAttempt=${input.selfHealAttempt}`
4755
- ].join(" ")), "green"),
4756
- dim(config, [
4757
- `via=${input.via}`,
4758
- `chars=${input.responseText.length}`,
4759
- `finishReason=${input.finishReason ?? "unknown"}`,
4760
- `usage=${JSON.stringify(input.usage ?? {})}`
4761
- ].join(" ")),
4762
- color(config, "text:", "yellow"),
4763
- input.responseText
4764
- ];
4765
- emitDebug(config, lines.join(`
4766
- `));
4767
- }
4768
- function emitDebug(config, message) {
4769
- if (!config.enabled) {
4770
- return;
4771
- }
4772
- config.logger(message);
4773
- }
4774
5080
 
4775
5081
  // src/llm.ts
4776
5082
  function createLLM(config, registry = createDefaultProviderRegistry()) {
@@ -4784,6 +5090,17 @@ function createLLM(config, registry = createDefaultProviderRegistry()) {
4784
5090
  const merged = mergeStructuredOptions(defaults, options);
4785
5091
  return structured(adapter, schema, prompt, merged);
4786
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
+ },
4787
5104
  async embed(input, options = {}) {
4788
5105
  if (!adapter.embed) {
4789
5106
  throw new Error(`Provider "${adapter.provider ?? "unknown"}" does not support embeddings.`);
@@ -4813,6 +5130,26 @@ function mergeStructuredOptions(defaults, overrides) {
4813
5130
  timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
4814
5131
  };
4815
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
+ }
4816
5153
  function mergeObjectLike(defaults, overrides) {
4817
5154
  if (overrides === undefined) {
4818
5155
  return defaults;
@@ -5280,6 +5617,7 @@ export {
5280
5617
  inspectSchemaMetadata,
5281
5618
  inferSchemaExample,
5282
5619
  images,
5620
+ generate,
5283
5621
  formatZodIssues,
5284
5622
  formatPrompt,
5285
5623
  extractMarkdownCodeBlocks,