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/README.md +159 -9
- package/dist/generate-shared.d.ts +79 -0
- package/dist/generate.d.ts +3 -0
- package/dist/index.cjs +854 -516
- package/dist/index.d.ts +2 -1
- package/dist/index.js +854 -516
- package/dist/llm.d.ts +18 -2
- package/dist/structured.d.ts +4 -4
- package/dist/types.d.ts +75 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,6 +52,7 @@ __export(exports_src, {
|
|
|
52
52
|
inspectSchemaMetadata: () => inspectSchemaMetadata,
|
|
53
53
|
inferSchemaExample: () => inferSchemaExample,
|
|
54
54
|
images: () => images,
|
|
55
|
+
generate: () => generate,
|
|
55
56
|
formatZodIssues: () => formatZodIssues,
|
|
56
57
|
formatPrompt: () => formatPrompt,
|
|
57
58
|
extractMarkdownCodeBlocks: () => extractMarkdownCodeBlocks,
|
|
@@ -1661,6 +1662,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1661
1662
|
model: options.model,
|
|
1662
1663
|
messages: buildMessages(request),
|
|
1663
1664
|
temperature: request.temperature,
|
|
1665
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1664
1666
|
max_tokens: request.maxTokens,
|
|
1665
1667
|
stream: true
|
|
1666
1668
|
})),
|
|
@@ -1672,6 +1674,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1672
1674
|
}
|
|
1673
1675
|
callbacks.onStart?.();
|
|
1674
1676
|
let text = "";
|
|
1677
|
+
let reasoning = "";
|
|
1675
1678
|
let usage;
|
|
1676
1679
|
let finishReason;
|
|
1677
1680
|
await consumeSSE(response, (data) => {
|
|
@@ -1683,6 +1686,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1683
1686
|
return;
|
|
1684
1687
|
}
|
|
1685
1688
|
const delta = pickAssistantDelta(json);
|
|
1689
|
+
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
1686
1690
|
const chunkUsage = pickUsage(json);
|
|
1687
1691
|
const chunkFinishReason = pickFinishReason(json);
|
|
1688
1692
|
usage = preferLatestUsage(usage, chunkUsage);
|
|
@@ -1693,9 +1697,13 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1693
1697
|
text += delta;
|
|
1694
1698
|
callbacks.onToken?.(delta);
|
|
1695
1699
|
}
|
|
1696
|
-
if (
|
|
1700
|
+
if (reasoningDelta) {
|
|
1701
|
+
reasoning += reasoningDelta;
|
|
1702
|
+
}
|
|
1703
|
+
if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
|
|
1697
1704
|
const chunk = {
|
|
1698
1705
|
textDelta: delta,
|
|
1706
|
+
reasoningDelta: reasoningDelta || undefined,
|
|
1699
1707
|
raw: json,
|
|
1700
1708
|
usage: chunkUsage,
|
|
1701
1709
|
finishReason: chunkFinishReason
|
|
@@ -1703,7 +1711,12 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1703
1711
|
callbacks.onChunk?.(chunk);
|
|
1704
1712
|
}
|
|
1705
1713
|
});
|
|
1706
|
-
const out = {
|
|
1714
|
+
const out = {
|
|
1715
|
+
text,
|
|
1716
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1717
|
+
usage,
|
|
1718
|
+
finishReason
|
|
1719
|
+
};
|
|
1707
1720
|
callbacks.onComplete?.(out);
|
|
1708
1721
|
return out;
|
|
1709
1722
|
},
|
|
@@ -1763,6 +1776,7 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
|
|
|
1763
1776
|
model: options.model,
|
|
1764
1777
|
messages: buildMessages(request),
|
|
1765
1778
|
temperature: request.temperature,
|
|
1779
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1766
1780
|
max_tokens: request.maxTokens,
|
|
1767
1781
|
stream: false
|
|
1768
1782
|
})),
|
|
@@ -1778,8 +1792,10 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
|
|
|
1778
1792
|
throw new Error("No assistant message in OpenAI-compatible response.");
|
|
1779
1793
|
}
|
|
1780
1794
|
const toolCalls = pickChatToolCalls(payload);
|
|
1795
|
+
const reasoning = pickAssistantReasoning(payload);
|
|
1781
1796
|
return {
|
|
1782
1797
|
text: pickAssistantText(payload),
|
|
1798
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1783
1799
|
raw: payload,
|
|
1784
1800
|
usage: pickUsage(payload),
|
|
1785
1801
|
finishReason: pickFinishReason(payload),
|
|
@@ -1806,6 +1822,7 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1806
1822
|
model: options.model,
|
|
1807
1823
|
messages,
|
|
1808
1824
|
temperature: request.temperature,
|
|
1825
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1809
1826
|
max_tokens: request.maxTokens,
|
|
1810
1827
|
tools: transportTools,
|
|
1811
1828
|
tool_choice: request.toolChoice,
|
|
@@ -1827,8 +1844,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1827
1844
|
throw new Error("No assistant message in OpenAI-compatible response.");
|
|
1828
1845
|
}
|
|
1829
1846
|
if (calledTools.length === 0) {
|
|
1847
|
+
const reasoning = pickAssistantReasoning(payload);
|
|
1830
1848
|
return {
|
|
1831
1849
|
text: pickAssistantText(payload),
|
|
1850
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1832
1851
|
raw: payload,
|
|
1833
1852
|
usage: aggregatedUsage,
|
|
1834
1853
|
finishReason,
|
|
@@ -1856,6 +1875,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1856
1875
|
}
|
|
1857
1876
|
return {
|
|
1858
1877
|
text: pickAssistantText(lastPayload ?? {}),
|
|
1878
|
+
reasoning: (() => {
|
|
1879
|
+
const value = pickAssistantReasoning(lastPayload ?? {});
|
|
1880
|
+
return value.length > 0 ? value : undefined;
|
|
1881
|
+
})(),
|
|
1859
1882
|
raw: lastPayload,
|
|
1860
1883
|
usage: aggregatedUsage,
|
|
1861
1884
|
finishReason,
|
|
@@ -1875,6 +1898,7 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
|
|
|
1875
1898
|
input: buildResponsesInput(request),
|
|
1876
1899
|
previous_response_id: pickString(body?.previous_response_id),
|
|
1877
1900
|
temperature: request.temperature,
|
|
1901
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1878
1902
|
max_output_tokens: request.maxTokens
|
|
1879
1903
|
})),
|
|
1880
1904
|
signal: request.signal
|
|
@@ -1915,6 +1939,7 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
|
|
|
1915
1939
|
input,
|
|
1916
1940
|
previous_response_id: previousResponseId,
|
|
1917
1941
|
temperature: request.temperature,
|
|
1942
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1918
1943
|
max_output_tokens: request.maxTokens,
|
|
1919
1944
|
tools: transportTools,
|
|
1920
1945
|
tool_choice: request.toolChoice,
|
|
@@ -1979,6 +2004,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
1979
2004
|
const executedToolCalls = [];
|
|
1980
2005
|
const toolExecutions = [];
|
|
1981
2006
|
callbacks.onStart?.();
|
|
2007
|
+
let lastRoundText = "";
|
|
2008
|
+
let lastRoundReasoning = "";
|
|
1982
2009
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
1983
2010
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
1984
2011
|
const transportTools = toProviderFunctionTools(mcpToolset);
|
|
@@ -1991,6 +2018,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
1991
2018
|
model: options.model,
|
|
1992
2019
|
messages,
|
|
1993
2020
|
temperature: request.temperature,
|
|
2021
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1994
2022
|
max_tokens: request.maxTokens,
|
|
1995
2023
|
tools: transportTools,
|
|
1996
2024
|
tool_choice: request.toolChoice,
|
|
@@ -2004,9 +2032,11 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2004
2032
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
2005
2033
|
}
|
|
2006
2034
|
let roundText = "";
|
|
2035
|
+
let roundReasoning = "";
|
|
2007
2036
|
let roundUsage;
|
|
2008
2037
|
let roundFinishReason;
|
|
2009
2038
|
const streamedToolCalls = new Map;
|
|
2039
|
+
let reasoningFieldName;
|
|
2010
2040
|
await consumeSSE(response, (data) => {
|
|
2011
2041
|
if (data === "[DONE]") {
|
|
2012
2042
|
return;
|
|
@@ -2017,6 +2047,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2017
2047
|
}
|
|
2018
2048
|
lastPayload = json;
|
|
2019
2049
|
const delta = pickAssistantDelta(json);
|
|
2050
|
+
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
2020
2051
|
const chunkUsage = pickUsage(json);
|
|
2021
2052
|
const chunkFinishReason = pickFinishReason(json);
|
|
2022
2053
|
collectOpenAIStreamToolCalls(json, streamedToolCalls);
|
|
@@ -2028,9 +2059,14 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2028
2059
|
roundText += delta;
|
|
2029
2060
|
callbacks.onToken?.(delta);
|
|
2030
2061
|
}
|
|
2031
|
-
if (
|
|
2062
|
+
if (reasoningDelta) {
|
|
2063
|
+
roundReasoning += reasoningDelta;
|
|
2064
|
+
reasoningFieldName ??= pickAssistantReasoningDeltaFieldName(json);
|
|
2065
|
+
}
|
|
2066
|
+
if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
|
|
2032
2067
|
const chunk = {
|
|
2033
2068
|
textDelta: delta,
|
|
2069
|
+
reasoningDelta: reasoningDelta || undefined,
|
|
2034
2070
|
raw: json,
|
|
2035
2071
|
usage: chunkUsage,
|
|
2036
2072
|
finishReason: chunkFinishReason
|
|
@@ -2046,6 +2082,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2046
2082
|
if (calledTools.length === 0) {
|
|
2047
2083
|
const out2 = {
|
|
2048
2084
|
text: roundText,
|
|
2085
|
+
reasoning: roundReasoning.length > 0 ? roundReasoning : undefined,
|
|
2049
2086
|
raw: lastPayload,
|
|
2050
2087
|
usage: aggregatedUsage,
|
|
2051
2088
|
finishReason,
|
|
@@ -2066,7 +2103,12 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2066
2103
|
});
|
|
2067
2104
|
executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2068
2105
|
toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2069
|
-
|
|
2106
|
+
lastRoundText = roundText;
|
|
2107
|
+
lastRoundReasoning = roundReasoning;
|
|
2108
|
+
const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools, {
|
|
2109
|
+
reasoning: roundReasoning,
|
|
2110
|
+
reasoningFieldName
|
|
2111
|
+
});
|
|
2070
2112
|
const toolMessages = outputs.map((entry) => ({
|
|
2071
2113
|
role: "tool",
|
|
2072
2114
|
tool_call_id: entry.call.id,
|
|
@@ -2075,7 +2117,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2075
2117
|
messages = [...messages, assistantMessage, ...toolMessages];
|
|
2076
2118
|
}
|
|
2077
2119
|
const out = {
|
|
2078
|
-
text:
|
|
2120
|
+
text: lastRoundText,
|
|
2121
|
+
reasoning: lastRoundReasoning.length > 0 ? lastRoundReasoning : undefined,
|
|
2079
2122
|
raw: lastPayload,
|
|
2080
2123
|
usage: aggregatedUsage,
|
|
2081
2124
|
finishReason,
|
|
@@ -2097,6 +2140,7 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
|
|
|
2097
2140
|
input: buildResponsesInput(request),
|
|
2098
2141
|
previous_response_id: pickString(body?.previous_response_id),
|
|
2099
2142
|
temperature: request.temperature,
|
|
2143
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2100
2144
|
max_output_tokens: request.maxTokens,
|
|
2101
2145
|
stream: true
|
|
2102
2146
|
})),
|
|
@@ -2177,6 +2221,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2177
2221
|
input,
|
|
2178
2222
|
previous_response_id: previousResponseId,
|
|
2179
2223
|
temperature: request.temperature,
|
|
2224
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2180
2225
|
max_output_tokens: request.maxTokens,
|
|
2181
2226
|
tools: transportTools,
|
|
2182
2227
|
tool_choice: request.toolChoice,
|
|
@@ -2343,6 +2388,12 @@ function toResponsesTools(tools) {
|
|
|
2343
2388
|
return { ...tool };
|
|
2344
2389
|
});
|
|
2345
2390
|
}
|
|
2391
|
+
function toOpenAIReasoningEffort(value) {
|
|
2392
|
+
if (!value) {
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
return value === "max" ? "xhigh" : value;
|
|
2396
|
+
}
|
|
2346
2397
|
function pickChatToolCalls(payload) {
|
|
2347
2398
|
const message = pickAssistantMessage(payload);
|
|
2348
2399
|
if (!message) {
|
|
@@ -2424,20 +2475,50 @@ function pickAssistantDelta(payload) {
|
|
|
2424
2475
|
if (!isRecord2(delta)) {
|
|
2425
2476
|
return "";
|
|
2426
2477
|
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2478
|
+
return pickTextFromOpenAIContent(delta.content);
|
|
2479
|
+
}
|
|
2480
|
+
function pickAssistantReasoning(payload) {
|
|
2481
|
+
const message = pickAssistantMessage(payload);
|
|
2482
|
+
if (!message) {
|
|
2483
|
+
return "";
|
|
2430
2484
|
}
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
return typeof text === "string" ? text : "";
|
|
2438
|
-
}).join("");
|
|
2485
|
+
return pickReasoningText(message);
|
|
2486
|
+
}
|
|
2487
|
+
function pickAssistantReasoningDelta(payload) {
|
|
2488
|
+
const choices = payload.choices;
|
|
2489
|
+
if (!Array.isArray(choices) || choices.length === 0) {
|
|
2490
|
+
return "";
|
|
2439
2491
|
}
|
|
2440
|
-
|
|
2492
|
+
const first = choices[0];
|
|
2493
|
+
if (!isRecord2(first)) {
|
|
2494
|
+
return "";
|
|
2495
|
+
}
|
|
2496
|
+
const delta = first.delta;
|
|
2497
|
+
if (!isRecord2(delta)) {
|
|
2498
|
+
return "";
|
|
2499
|
+
}
|
|
2500
|
+
return pickReasoningText(delta);
|
|
2501
|
+
}
|
|
2502
|
+
function pickAssistantReasoningDeltaFieldName(payload) {
|
|
2503
|
+
const choices = payload.choices;
|
|
2504
|
+
if (!Array.isArray(choices) || choices.length === 0) {
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
const first = choices[0];
|
|
2508
|
+
if (!isRecord2(first)) {
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2511
|
+
const delta = first.delta;
|
|
2512
|
+
if (!isRecord2(delta)) {
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
if (hasTextLikeValue(delta.reasoning)) {
|
|
2516
|
+
return "reasoning";
|
|
2517
|
+
}
|
|
2518
|
+
if (hasTextLikeValue(delta.reasoning_content)) {
|
|
2519
|
+
return "reasoning_content";
|
|
2520
|
+
}
|
|
2521
|
+
return;
|
|
2441
2522
|
}
|
|
2442
2523
|
function collectOpenAIStreamToolCalls(payload, state) {
|
|
2443
2524
|
const choices = payload.choices;
|
|
@@ -2486,8 +2567,8 @@ function buildOpenAIStreamToolCalls(state) {
|
|
|
2486
2567
|
arguments: entry.argumentsText.length > 0 ? entry.argumentsText : {}
|
|
2487
2568
|
}));
|
|
2488
2569
|
}
|
|
2489
|
-
function buildOpenAIAssistantToolMessage(text, toolCalls) {
|
|
2490
|
-
|
|
2570
|
+
function buildOpenAIAssistantToolMessage(text, toolCalls, reasoning) {
|
|
2571
|
+
const message = {
|
|
2491
2572
|
role: "assistant",
|
|
2492
2573
|
content: text,
|
|
2493
2574
|
tool_calls: toolCalls.map((call) => ({
|
|
@@ -2499,6 +2580,10 @@ function buildOpenAIAssistantToolMessage(text, toolCalls) {
|
|
|
2499
2580
|
}
|
|
2500
2581
|
}))
|
|
2501
2582
|
};
|
|
2583
|
+
if (reasoning?.reasoning && reasoning.reasoning.length > 0) {
|
|
2584
|
+
message[reasoning.reasoningFieldName ?? "reasoning"] = reasoning.reasoning;
|
|
2585
|
+
}
|
|
2586
|
+
return message;
|
|
2502
2587
|
}
|
|
2503
2588
|
function pickResponsesStreamPayload(payload) {
|
|
2504
2589
|
if (isRecord2(payload.response)) {
|
|
@@ -2660,21 +2745,9 @@ function pickResponsesText(payload) {
|
|
|
2660
2745
|
function pickAssistantText(payload) {
|
|
2661
2746
|
const message = pickAssistantMessage(payload);
|
|
2662
2747
|
if (message) {
|
|
2663
|
-
const
|
|
2664
|
-
if (
|
|
2665
|
-
return
|
|
2666
|
-
}
|
|
2667
|
-
if (Array.isArray(content)) {
|
|
2668
|
-
return content.map((part) => {
|
|
2669
|
-
if (typeof part === "string") {
|
|
2670
|
-
return part;
|
|
2671
|
-
}
|
|
2672
|
-
if (!isRecord2(part)) {
|
|
2673
|
-
return "";
|
|
2674
|
-
}
|
|
2675
|
-
const text = part.text;
|
|
2676
|
-
return typeof text === "string" ? text : "";
|
|
2677
|
-
}).join("");
|
|
2748
|
+
const text = pickTextFromOpenAIContent(message.content);
|
|
2749
|
+
if (text.length > 0) {
|
|
2750
|
+
return text;
|
|
2678
2751
|
}
|
|
2679
2752
|
}
|
|
2680
2753
|
const choices = payload.choices;
|
|
@@ -2686,6 +2759,36 @@ function pickAssistantText(payload) {
|
|
|
2686
2759
|
}
|
|
2687
2760
|
return "";
|
|
2688
2761
|
}
|
|
2762
|
+
function pickReasoningText(value) {
|
|
2763
|
+
return pickTextLike(value.reasoning) || pickTextLike(value.reasoning_content);
|
|
2764
|
+
}
|
|
2765
|
+
function pickTextFromOpenAIContent(value) {
|
|
2766
|
+
return pickTextLike(value);
|
|
2767
|
+
}
|
|
2768
|
+
function pickTextLike(value) {
|
|
2769
|
+
if (typeof value === "string") {
|
|
2770
|
+
return value;
|
|
2771
|
+
}
|
|
2772
|
+
if (Array.isArray(value)) {
|
|
2773
|
+
return value.map((part) => pickTextLikePart(part)).join("");
|
|
2774
|
+
}
|
|
2775
|
+
if (!isRecord2(value)) {
|
|
2776
|
+
return "";
|
|
2777
|
+
}
|
|
2778
|
+
return pickTextLikePart(value);
|
|
2779
|
+
}
|
|
2780
|
+
function pickTextLikePart(value) {
|
|
2781
|
+
if (typeof value === "string") {
|
|
2782
|
+
return value;
|
|
2783
|
+
}
|
|
2784
|
+
if (!isRecord2(value)) {
|
|
2785
|
+
return "";
|
|
2786
|
+
}
|
|
2787
|
+
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("") : "");
|
|
2788
|
+
}
|
|
2789
|
+
function hasTextLikeValue(value) {
|
|
2790
|
+
return pickTextLike(value).length > 0;
|
|
2791
|
+
}
|
|
2689
2792
|
function pickUsage(payload) {
|
|
2690
2793
|
const usage = payload.usage;
|
|
2691
2794
|
if (!isRecord2(usage)) {
|
|
@@ -2739,14 +2842,13 @@ function createAnthropicCompatibleAdapter(options) {
|
|
|
2739
2842
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2740
2843
|
method: "POST",
|
|
2741
2844
|
headers: buildHeaders2(options),
|
|
2742
|
-
body: JSON.stringify(
|
|
2845
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2743
2846
|
...options.defaultBody,
|
|
2744
2847
|
...request.body,
|
|
2745
2848
|
model: options.model,
|
|
2746
2849
|
system: input.systemPrompt,
|
|
2747
2850
|
messages: input.messages,
|
|
2748
2851
|
temperature: request.temperature,
|
|
2749
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2750
2852
|
stream: true
|
|
2751
2853
|
})),
|
|
2752
2854
|
signal: request.signal
|
|
@@ -2802,14 +2904,13 @@ async function completePassThrough(options, fetcher, path, request) {
|
|
|
2802
2904
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2803
2905
|
method: "POST",
|
|
2804
2906
|
headers: buildHeaders2(options),
|
|
2805
|
-
body: JSON.stringify(
|
|
2907
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2806
2908
|
...options.defaultBody,
|
|
2807
2909
|
...request.body,
|
|
2808
2910
|
model: options.model,
|
|
2809
2911
|
system: input.systemPrompt,
|
|
2810
2912
|
messages: input.messages,
|
|
2811
2913
|
temperature: request.temperature,
|
|
2812
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2813
2914
|
stream: false
|
|
2814
2915
|
})),
|
|
2815
2916
|
signal: request.signal
|
|
@@ -2847,14 +2948,13 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
|
|
|
2847
2948
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2848
2949
|
method: "POST",
|
|
2849
2950
|
headers: buildHeaders2(options),
|
|
2850
|
-
body: JSON.stringify(
|
|
2951
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2851
2952
|
...options.defaultBody,
|
|
2852
2953
|
...request.body,
|
|
2853
2954
|
model: options.model,
|
|
2854
2955
|
system: input.systemPrompt,
|
|
2855
2956
|
messages,
|
|
2856
2957
|
temperature: request.temperature,
|
|
2857
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2858
2958
|
tools,
|
|
2859
2959
|
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
2860
2960
|
stream: false
|
|
@@ -2932,14 +3032,13 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
|
|
|
2932
3032
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2933
3033
|
method: "POST",
|
|
2934
3034
|
headers: buildHeaders2(options),
|
|
2935
|
-
body: JSON.stringify(
|
|
3035
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2936
3036
|
...options.defaultBody,
|
|
2937
3037
|
...request.body,
|
|
2938
3038
|
model: options.model,
|
|
2939
3039
|
system: input.systemPrompt,
|
|
2940
3040
|
messages,
|
|
2941
3041
|
temperature: request.temperature,
|
|
2942
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2943
3042
|
tools,
|
|
2944
3043
|
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
2945
3044
|
stream: true
|
|
@@ -3047,6 +3146,21 @@ function buildHeaders2(options) {
|
|
|
3047
3146
|
...options.headers
|
|
3048
3147
|
};
|
|
3049
3148
|
}
|
|
3149
|
+
function buildAnthropicRequestBody(options, request, body) {
|
|
3150
|
+
const bodyOutputConfig = isRecord2(body.output_config) ? body.output_config : undefined;
|
|
3151
|
+
const bodyThinking = body.thinking;
|
|
3152
|
+
const hasExplicitThinking = Object.prototype.hasOwnProperty.call(body, "thinking");
|
|
3153
|
+
const reasoningEffort = request.reasoningEffort;
|
|
3154
|
+
return cleanUndefined({
|
|
3155
|
+
...body,
|
|
3156
|
+
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
3157
|
+
output_config: reasoningEffort ? cleanUndefined({
|
|
3158
|
+
...bodyOutputConfig,
|
|
3159
|
+
effort: reasoningEffort
|
|
3160
|
+
}) : bodyOutputConfig,
|
|
3161
|
+
thinking: reasoningEffort ? hasExplicitThinking ? bodyThinking : { type: "adaptive" } : bodyThinking
|
|
3162
|
+
});
|
|
3163
|
+
}
|
|
3050
3164
|
function resolveAnthropicInput(request) {
|
|
3051
3165
|
if (Array.isArray(request.messages) && request.messages.length > 0) {
|
|
3052
3166
|
return toAnthropicInput(request.messages);
|
|
@@ -3401,8 +3515,34 @@ function buildProviderOptions(config) {
|
|
|
3401
3515
|
};
|
|
3402
3516
|
}
|
|
3403
3517
|
|
|
3404
|
-
// src/
|
|
3405
|
-
var
|
|
3518
|
+
// src/utils/debug-colors.ts
|
|
3519
|
+
var ANSI = {
|
|
3520
|
+
reset: "\x1B[0m",
|
|
3521
|
+
bold: "\x1B[1m",
|
|
3522
|
+
cyan: "\x1B[36m",
|
|
3523
|
+
yellow: "\x1B[33m",
|
|
3524
|
+
green: "\x1B[32m",
|
|
3525
|
+
red: "\x1B[31m",
|
|
3526
|
+
dim: "\x1B[2m"
|
|
3527
|
+
};
|
|
3528
|
+
function color(config, text, tone) {
|
|
3529
|
+
if (!config.colors) {
|
|
3530
|
+
return text;
|
|
3531
|
+
}
|
|
3532
|
+
return `${ANSI[tone]}${text}${ANSI.reset}`;
|
|
3533
|
+
}
|
|
3534
|
+
function dim(config, text) {
|
|
3535
|
+
if (!config.colors) {
|
|
3536
|
+
return text;
|
|
3537
|
+
}
|
|
3538
|
+
return `${ANSI.dim}${text}${ANSI.reset}`;
|
|
3539
|
+
}
|
|
3540
|
+
function title(config, text) {
|
|
3541
|
+
if (!config.colors) {
|
|
3542
|
+
return text;
|
|
3543
|
+
}
|
|
3544
|
+
return `${ANSI.bold}${text}${ANSI.reset}`;
|
|
3545
|
+
}
|
|
3406
3546
|
|
|
3407
3547
|
// src/outdent.ts
|
|
3408
3548
|
var DEFAULT_OPTIONS = {
|
|
@@ -3541,44 +3681,603 @@ function createOutdent(options = {}) {
|
|
|
3541
3681
|
return outdent;
|
|
3542
3682
|
}
|
|
3543
3683
|
|
|
3544
|
-
// src/
|
|
3545
|
-
var
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3684
|
+
// src/generate-shared.ts
|
|
3685
|
+
var sharedOutdent = createOutdent({
|
|
3686
|
+
trimLeadingNewline: true,
|
|
3687
|
+
trimTrailingNewline: true,
|
|
3688
|
+
newline: `
|
|
3689
|
+
`
|
|
3690
|
+
});
|
|
3691
|
+
var RE_THINK_TAGS = /<\/?think\s*>/gi;
|
|
3692
|
+
function resolvePrompt(prompt, context) {
|
|
3693
|
+
const resolved = typeof prompt === "function" ? prompt(context) : prompt;
|
|
3694
|
+
return normalizePromptValue(resolved, context);
|
|
3695
|
+
}
|
|
3696
|
+
function normalizePromptValue(value, _context) {
|
|
3697
|
+
if (typeof value === "string") {
|
|
3698
|
+
return {
|
|
3699
|
+
prompt: value
|
|
3700
|
+
};
|
|
3701
|
+
}
|
|
3702
|
+
if (isPromptResolver(value)) {
|
|
3703
|
+
return normalizePromptPayload(value.resolvePrompt(_context));
|
|
3704
|
+
}
|
|
3705
|
+
return normalizePromptPayload(value);
|
|
3706
|
+
}
|
|
3707
|
+
function normalizePromptPayload(value) {
|
|
3708
|
+
const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
|
|
3709
|
+
const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
|
|
3710
|
+
if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
|
|
3711
|
+
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
3712
|
+
}
|
|
3713
|
+
return {
|
|
3714
|
+
prompt,
|
|
3715
|
+
systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
|
|
3716
|
+
messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
|
|
3554
3717
|
};
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3718
|
+
}
|
|
3719
|
+
function applyPromptOutdent(payload, enabled) {
|
|
3720
|
+
if (!enabled) {
|
|
3721
|
+
return payload;
|
|
3722
|
+
}
|
|
3723
|
+
return {
|
|
3724
|
+
prompt: typeof payload.prompt === "string" ? sharedOutdent.string(payload.prompt) : undefined,
|
|
3725
|
+
systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
|
|
3726
|
+
messages: payload.messages?.map((message) => ({
|
|
3727
|
+
...message,
|
|
3728
|
+
content: typeof message.content === "string" ? sharedOutdent.string(message.content) : message.content
|
|
3729
|
+
}))
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
function applyOutdentToOptionalPrompt(value, enabled) {
|
|
3733
|
+
if (!enabled || typeof value !== "string") {
|
|
3734
|
+
return value;
|
|
3735
|
+
}
|
|
3736
|
+
return sharedOutdent.string(value);
|
|
3737
|
+
}
|
|
3738
|
+
function mergeSystemPrompts(primary, secondary) {
|
|
3739
|
+
const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
|
|
3740
|
+
if (prompts.length === 0) {
|
|
3741
|
+
return;
|
|
3742
|
+
}
|
|
3743
|
+
return prompts.join(`
|
|
3744
|
+
|
|
3745
|
+
`);
|
|
3746
|
+
}
|
|
3747
|
+
function normalizeStreamConfig(option) {
|
|
3748
|
+
if (typeof option === "boolean") {
|
|
3749
|
+
return {
|
|
3750
|
+
enabled: option
|
|
3751
|
+
};
|
|
3752
|
+
}
|
|
3753
|
+
if (!option) {
|
|
3754
|
+
return {
|
|
3755
|
+
enabled: false
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3758
|
+
return {
|
|
3759
|
+
enabled: option.enabled ?? true,
|
|
3760
|
+
onData: option.onData,
|
|
3761
|
+
to: option.to
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3764
|
+
function normalizeDebugConfig(option) {
|
|
3765
|
+
if (typeof option === "boolean") {
|
|
3766
|
+
return {
|
|
3767
|
+
enabled: option,
|
|
3768
|
+
colors: true,
|
|
3769
|
+
verbose: false,
|
|
3770
|
+
logger: (line) => console.log(line)
|
|
3771
|
+
};
|
|
3772
|
+
}
|
|
3773
|
+
if (!option) {
|
|
3774
|
+
return {
|
|
3775
|
+
enabled: false,
|
|
3776
|
+
colors: true,
|
|
3777
|
+
verbose: false,
|
|
3778
|
+
logger: (line) => console.log(line)
|
|
3779
|
+
};
|
|
3780
|
+
}
|
|
3781
|
+
return {
|
|
3782
|
+
enabled: option.enabled ?? true,
|
|
3783
|
+
colors: option.colors ?? true,
|
|
3784
|
+
verbose: option.verbose ?? false,
|
|
3785
|
+
logger: option.logger ?? ((line) => console.log(line))
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
function withToolTimeout(client, toolTimeoutMs) {
|
|
3789
|
+
return {
|
|
3790
|
+
id: client.id,
|
|
3791
|
+
listTools: client.listTools.bind(client),
|
|
3792
|
+
close: client.close?.bind(client),
|
|
3793
|
+
async callTool(params) {
|
|
3794
|
+
let timeoutId;
|
|
3795
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
3796
|
+
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
3797
|
+
});
|
|
3798
|
+
try {
|
|
3799
|
+
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
3800
|
+
} finally {
|
|
3801
|
+
clearTimeout(timeoutId);
|
|
3802
|
+
}
|
|
3569
3803
|
}
|
|
3570
|
-
}
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3804
|
+
};
|
|
3805
|
+
}
|
|
3806
|
+
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
3807
|
+
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
3808
|
+
}
|
|
3809
|
+
async function callModel(adapter, options) {
|
|
3810
|
+
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
3811
|
+
const requestPayload = {
|
|
3812
|
+
prompt: options.prompt,
|
|
3813
|
+
messages: options.messages,
|
|
3814
|
+
systemPrompt: options.systemPrompt,
|
|
3815
|
+
temperature: options.request?.temperature,
|
|
3816
|
+
reasoningEffort: options.request?.reasoningEffort,
|
|
3817
|
+
maxTokens: options.request?.maxTokens,
|
|
3818
|
+
mcpClients: options.request?.mcpClients,
|
|
3819
|
+
toolChoice: options.request?.toolChoice,
|
|
3820
|
+
parallelToolCalls: options.request?.parallelToolCalls,
|
|
3821
|
+
maxToolRounds: options.request?.maxToolRounds,
|
|
3822
|
+
onToolExecution: options.request?.onToolExecution,
|
|
3823
|
+
transformToolOutput: options.request?.transformToolOutput,
|
|
3824
|
+
transformToolArguments: options.request?.transformToolArguments,
|
|
3825
|
+
transformToolCallParams: options.request?.transformToolCallParams,
|
|
3826
|
+
unknownToolError: options.request?.unknownToolError,
|
|
3827
|
+
toolDebug: options.request?.toolDebug,
|
|
3828
|
+
body: options.request?.body,
|
|
3829
|
+
signal: requestSignal
|
|
3830
|
+
};
|
|
3831
|
+
emitDebugRequest(options.debug, {
|
|
3832
|
+
label: options.debugLabel,
|
|
3833
|
+
provider: adapter.provider,
|
|
3834
|
+
model: adapter.model,
|
|
3835
|
+
attempt: options.attempt,
|
|
3836
|
+
selfHealAttempt: options.selfHeal,
|
|
3837
|
+
selfHealEnabled: options.selfHealEnabled,
|
|
3838
|
+
stream: options.stream.enabled && !!adapter.stream,
|
|
3839
|
+
requestPayload
|
|
3840
|
+
});
|
|
3841
|
+
options.observe?.(options.buildEvent({
|
|
3842
|
+
stage: "llm.request",
|
|
3843
|
+
message: "Sending LLM request.",
|
|
3844
|
+
details: {
|
|
3845
|
+
provider: adapter.provider,
|
|
3846
|
+
model: adapter.model,
|
|
3847
|
+
stream: options.stream.enabled && !!adapter.stream
|
|
3848
|
+
}
|
|
3849
|
+
}));
|
|
3850
|
+
if (options.stream.enabled && adapter.stream) {
|
|
3851
|
+
let latestUsage;
|
|
3852
|
+
let latestFinishReason;
|
|
3853
|
+
let streamedProviderText = "";
|
|
3854
|
+
let streamedDedicatedReasoning = "";
|
|
3855
|
+
let lastSnapshotFingerprint;
|
|
3856
|
+
let previousSnapshotText = "";
|
|
3857
|
+
let previousSnapshotReasoning = "";
|
|
3858
|
+
const emitStreamingData = (done, usage2, finishReason2) => {
|
|
3859
|
+
const normalized2 = normalizeModelOutput(streamedProviderText, streamedDedicatedReasoning);
|
|
3860
|
+
const snapshot = options.buildSnapshot(normalized2);
|
|
3861
|
+
const fingerprint = toStreamDataFingerprint(snapshot);
|
|
3862
|
+
if (!done && fingerprint === lastSnapshotFingerprint) {
|
|
3863
|
+
return;
|
|
3864
|
+
}
|
|
3865
|
+
const delta = {
|
|
3866
|
+
text: normalized2.text.startsWith(previousSnapshotText) ? normalized2.text.slice(previousSnapshotText.length) : "",
|
|
3867
|
+
reasoning: normalized2.reasoning.startsWith(previousSnapshotReasoning) ? normalized2.reasoning.slice(previousSnapshotReasoning.length) : ""
|
|
3868
|
+
};
|
|
3869
|
+
lastSnapshotFingerprint = fingerprint;
|
|
3870
|
+
previousSnapshotText = normalized2.text;
|
|
3871
|
+
previousSnapshotReasoning = normalized2.reasoning;
|
|
3872
|
+
options.stream.onData?.({
|
|
3873
|
+
delta,
|
|
3874
|
+
snapshot,
|
|
3875
|
+
done,
|
|
3876
|
+
usage: usage2,
|
|
3877
|
+
finishReason: finishReason2
|
|
3878
|
+
});
|
|
3879
|
+
if (options.stream.to === "stdout" && delta.text) {
|
|
3880
|
+
process.stdout.write(delta.text);
|
|
3881
|
+
}
|
|
3882
|
+
options.observe?.(options.buildEvent({
|
|
3883
|
+
stage: "llm.stream.data",
|
|
3884
|
+
message: done ? "Streaming response completed." : "Streaming response updated.",
|
|
3885
|
+
details: {
|
|
3886
|
+
done,
|
|
3887
|
+
finishReason: finishReason2
|
|
3888
|
+
}
|
|
3889
|
+
}));
|
|
3890
|
+
};
|
|
3891
|
+
const handleTextDelta = (delta) => {
|
|
3892
|
+
if (!delta) {
|
|
3893
|
+
return;
|
|
3894
|
+
}
|
|
3895
|
+
streamedProviderText += delta;
|
|
3896
|
+
options.observe?.(options.buildEvent({
|
|
3897
|
+
stage: "llm.stream.delta",
|
|
3898
|
+
message: "Received stream delta.",
|
|
3899
|
+
details: {
|
|
3900
|
+
chars: delta.length
|
|
3901
|
+
}
|
|
3902
|
+
}));
|
|
3903
|
+
emitStreamingData(false);
|
|
3904
|
+
};
|
|
3905
|
+
const handleReasoningDelta = (delta) => {
|
|
3906
|
+
if (!delta) {
|
|
3907
|
+
return;
|
|
3908
|
+
}
|
|
3909
|
+
streamedDedicatedReasoning += delta;
|
|
3910
|
+
emitStreamingData(false);
|
|
3911
|
+
};
|
|
3912
|
+
const response2 = await adapter.stream(requestPayload, {
|
|
3913
|
+
onChunk: (chunk) => {
|
|
3914
|
+
if (chunk.textDelta) {
|
|
3915
|
+
handleTextDelta(chunk.textDelta);
|
|
3916
|
+
}
|
|
3917
|
+
if (chunk.reasoningDelta) {
|
|
3918
|
+
handleReasoningDelta(chunk.reasoningDelta);
|
|
3919
|
+
}
|
|
3920
|
+
if (chunk.usage) {
|
|
3921
|
+
latestUsage = preferLatestUsage(latestUsage, chunk.usage);
|
|
3922
|
+
}
|
|
3923
|
+
if (chunk.finishReason) {
|
|
3924
|
+
latestFinishReason = chunk.finishReason;
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
});
|
|
3928
|
+
streamedProviderText = typeof response2.text === "string" ? response2.text : streamedProviderText;
|
|
3929
|
+
streamedDedicatedReasoning = typeof response2.reasoning === "string" ? response2.reasoning : streamedDedicatedReasoning;
|
|
3930
|
+
const finalNormalized = normalizeModelOutput(streamedProviderText, streamedDedicatedReasoning);
|
|
3931
|
+
const usage = preferLatestUsage(latestUsage, response2.usage);
|
|
3932
|
+
const finishReason = response2.finishReason ?? latestFinishReason;
|
|
3933
|
+
emitStreamingData(true, usage, finishReason);
|
|
3934
|
+
options.observe?.(options.buildEvent({
|
|
3935
|
+
stage: "llm.response",
|
|
3936
|
+
message: "Streaming response completed.",
|
|
3937
|
+
details: {
|
|
3938
|
+
via: "stream",
|
|
3939
|
+
chars: finalNormalized.parseSource.length,
|
|
3940
|
+
finishReason
|
|
3941
|
+
}
|
|
3942
|
+
}));
|
|
3943
|
+
emitDebugResponse(options.debug, {
|
|
3944
|
+
label: options.debugLabel,
|
|
3945
|
+
attempt: options.attempt,
|
|
3946
|
+
selfHealAttempt: options.selfHeal,
|
|
3947
|
+
selfHealEnabled: options.selfHealEnabled,
|
|
3948
|
+
via: "stream",
|
|
3949
|
+
text: finalNormalized.text,
|
|
3950
|
+
reasoning: finalNormalized.reasoning,
|
|
3951
|
+
parseSource: finalNormalized.parseSource,
|
|
3952
|
+
usage,
|
|
3953
|
+
finishReason
|
|
3954
|
+
});
|
|
3955
|
+
return {
|
|
3956
|
+
text: finalNormalized.text,
|
|
3957
|
+
reasoning: finalNormalized.reasoning,
|
|
3958
|
+
thinkBlocks: finalNormalized.thinkBlocks,
|
|
3959
|
+
parseSource: finalNormalized.parseSource,
|
|
3960
|
+
via: "stream",
|
|
3961
|
+
usage,
|
|
3962
|
+
finishReason
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
const response = await adapter.complete(requestPayload);
|
|
3966
|
+
const normalized = normalizeModelOutput(response.text, response.reasoning);
|
|
3967
|
+
options.observe?.(options.buildEvent({
|
|
3968
|
+
stage: "llm.response",
|
|
3969
|
+
message: "Completion response received.",
|
|
3970
|
+
details: {
|
|
3971
|
+
via: "complete",
|
|
3972
|
+
chars: normalized.parseSource.length,
|
|
3973
|
+
finishReason: response.finishReason
|
|
3974
|
+
}
|
|
3975
|
+
}));
|
|
3976
|
+
emitDebugResponse(options.debug, {
|
|
3977
|
+
label: options.debugLabel,
|
|
3978
|
+
attempt: options.attempt,
|
|
3979
|
+
selfHealAttempt: options.selfHeal,
|
|
3980
|
+
selfHealEnabled: options.selfHealEnabled,
|
|
3981
|
+
via: "complete",
|
|
3982
|
+
text: normalized.text,
|
|
3983
|
+
reasoning: normalized.reasoning,
|
|
3984
|
+
parseSource: normalized.parseSource,
|
|
3985
|
+
usage: response.usage,
|
|
3986
|
+
finishReason: response.finishReason
|
|
3987
|
+
});
|
|
3988
|
+
return {
|
|
3989
|
+
text: normalized.text,
|
|
3990
|
+
reasoning: normalized.reasoning,
|
|
3991
|
+
thinkBlocks: normalized.thinkBlocks,
|
|
3992
|
+
parseSource: normalized.parseSource,
|
|
3993
|
+
via: "complete",
|
|
3994
|
+
usage: response.usage,
|
|
3995
|
+
finishReason: response.finishReason
|
|
3996
|
+
};
|
|
3997
|
+
}
|
|
3998
|
+
function normalizeModelOutput(text, dedicatedReasoning) {
|
|
3999
|
+
const sanitized = sanitizeThink(text);
|
|
4000
|
+
const visibleText = stripThinkBlocks(text, sanitized.thinkBlocks);
|
|
4001
|
+
const reasoning = joinReasoningSegments([
|
|
4002
|
+
dedicatedReasoning,
|
|
4003
|
+
...sanitized.thinkBlocks.map((block) => block.content)
|
|
4004
|
+
]);
|
|
4005
|
+
return {
|
|
4006
|
+
text: visibleText,
|
|
4007
|
+
reasoning,
|
|
4008
|
+
thinkBlocks: sanitized.thinkBlocks,
|
|
4009
|
+
parseSource: composeParseSource(visibleText, reasoning)
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
function composeParseSource(text, reasoning) {
|
|
4013
|
+
if (typeof reasoning !== "string" || reasoning.length === 0) {
|
|
4014
|
+
return text;
|
|
4015
|
+
}
|
|
4016
|
+
const sanitized = reasoning.replace(RE_THINK_TAGS, "");
|
|
4017
|
+
if (sanitized.length === 0) {
|
|
4018
|
+
return text;
|
|
4019
|
+
}
|
|
4020
|
+
return `<think>${sanitized}</think>${text}`;
|
|
4021
|
+
}
|
|
4022
|
+
function aggregateUsage(attempts) {
|
|
4023
|
+
let usage;
|
|
4024
|
+
for (const attempt of attempts) {
|
|
4025
|
+
usage = mergeUsage2(usage, attempt.usage);
|
|
4026
|
+
}
|
|
4027
|
+
return usage;
|
|
4028
|
+
}
|
|
4029
|
+
function mergeUsage2(base, next) {
|
|
4030
|
+
if (!base && !next) {
|
|
4031
|
+
return;
|
|
4032
|
+
}
|
|
4033
|
+
return {
|
|
4034
|
+
inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
|
|
4035
|
+
outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
|
|
4036
|
+
totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
|
|
4037
|
+
cost: (base?.cost ?? 0) + (next?.cost ?? 0)
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
function isPromptResolver(value) {
|
|
4041
|
+
return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
|
|
4042
|
+
}
|
|
4043
|
+
function isLLMMessage(value) {
|
|
4044
|
+
if (typeof value !== "object" || value === null) {
|
|
4045
|
+
return false;
|
|
4046
|
+
}
|
|
4047
|
+
const candidate = value;
|
|
4048
|
+
if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
|
|
4049
|
+
return false;
|
|
4050
|
+
}
|
|
4051
|
+
return "content" in candidate;
|
|
4052
|
+
}
|
|
4053
|
+
function joinReasoningSegments(parts) {
|
|
4054
|
+
return parts.map((value) => value?.trim()).filter((value) => Boolean(value)).join(`
|
|
4055
|
+
|
|
4056
|
+
`);
|
|
4057
|
+
}
|
|
4058
|
+
function stripThinkBlocks(text, thinkBlocks) {
|
|
4059
|
+
if (thinkBlocks.length === 0) {
|
|
4060
|
+
return text;
|
|
4061
|
+
}
|
|
4062
|
+
let output = "";
|
|
4063
|
+
let cursor = 0;
|
|
4064
|
+
for (const block of thinkBlocks) {
|
|
4065
|
+
output += text.slice(cursor, block.start);
|
|
4066
|
+
cursor = block.end;
|
|
4067
|
+
}
|
|
4068
|
+
output += text.slice(cursor);
|
|
4069
|
+
return output;
|
|
4070
|
+
}
|
|
4071
|
+
function toStreamDataFingerprint(value) {
|
|
4072
|
+
try {
|
|
4073
|
+
return JSON.stringify(value);
|
|
4074
|
+
} catch {
|
|
4075
|
+
return "__unserializable__";
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
function emitDebugRequest(config, input) {
|
|
4079
|
+
const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
|
|
4080
|
+
const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
|
|
4081
|
+
const lines = [
|
|
4082
|
+
color(config, title(config, [
|
|
4083
|
+
`[${input.label}][request]`,
|
|
4084
|
+
`attempt=${input.attempt}`,
|
|
4085
|
+
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4086
|
+
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4087
|
+
].join(" ")), "cyan"),
|
|
4088
|
+
dim(config, [
|
|
4089
|
+
`provider=${input.provider ?? "unknown"}`,
|
|
4090
|
+
`model=${input.model ?? "unknown"}`,
|
|
4091
|
+
`stream=${input.stream}`
|
|
4092
|
+
].join(" ")),
|
|
4093
|
+
color(config, "prompt:", "yellow"),
|
|
4094
|
+
input.requestPayload.prompt ?? "(none)",
|
|
4095
|
+
color(config, "messages:", "yellow"),
|
|
4096
|
+
requestMessages,
|
|
4097
|
+
color(config, "systemPrompt:", "yellow"),
|
|
4098
|
+
input.requestPayload.systemPrompt ?? "(none)",
|
|
4099
|
+
color(config, "request.body:", "yellow"),
|
|
4100
|
+
requestBody
|
|
4101
|
+
];
|
|
4102
|
+
emitDebug(config, lines.join(`
|
|
4103
|
+
`));
|
|
4104
|
+
}
|
|
4105
|
+
function emitDebugResponse(config, input) {
|
|
4106
|
+
const text = input.text.length > 0 ? input.text : "(none)";
|
|
4107
|
+
const reasoning = input.reasoning.length > 0 ? input.reasoning : "(none)";
|
|
4108
|
+
const metadata = [
|
|
4109
|
+
`via=${input.via}`,
|
|
4110
|
+
`textChars=${input.text.length}`,
|
|
4111
|
+
`reasoningChars=${input.reasoning.length}`
|
|
4112
|
+
];
|
|
4113
|
+
if (config.verbose) {
|
|
4114
|
+
metadata.push(`parseSourceChars=${input.parseSource.length}`);
|
|
4115
|
+
}
|
|
4116
|
+
metadata.push(`finishReason=${input.finishReason ?? "unknown"}`, `usage=${JSON.stringify(input.usage ?? {})}`);
|
|
4117
|
+
const lines = [
|
|
4118
|
+
color(config, title(config, [
|
|
4119
|
+
`[${input.label}][response]`,
|
|
4120
|
+
`attempt=${input.attempt}`,
|
|
4121
|
+
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4122
|
+
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4123
|
+
].join(" ")), "green"),
|
|
4124
|
+
dim(config, metadata.join(" ")),
|
|
4125
|
+
color(config, "text:", "yellow"),
|
|
4126
|
+
text,
|
|
4127
|
+
color(config, "reasoning:", "yellow"),
|
|
4128
|
+
reasoning
|
|
4129
|
+
];
|
|
4130
|
+
if (config.verbose) {
|
|
4131
|
+
lines.push(color(config, "parseSource:", "yellow"), input.parseSource);
|
|
4132
|
+
}
|
|
4133
|
+
emitDebug(config, lines.join(`
|
|
4134
|
+
`));
|
|
4135
|
+
}
|
|
4136
|
+
function emitDebug(config, message) {
|
|
4137
|
+
if (!config.enabled) {
|
|
4138
|
+
return;
|
|
4139
|
+
}
|
|
4140
|
+
config.logger(message);
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
// src/generate.ts
|
|
4144
|
+
async function generate(adapter, promptOrOptions, callOptions) {
|
|
4145
|
+
const normalized = normalizeGenerateInput(promptOrOptions, callOptions);
|
|
4146
|
+
const useOutdent = normalized.outdent ?? true;
|
|
4147
|
+
const streamConfig = normalizeStreamConfig(normalized.stream);
|
|
4148
|
+
const debugConfig = normalizeDebugConfig(normalized.debug);
|
|
4149
|
+
const resolvedPrompt = applyPromptOutdent(resolvePrompt(normalized.prompt, { mode: "loose" }), useOutdent);
|
|
4150
|
+
const resolvedSystemPrompt = applyOutdentToOptionalPrompt(normalized.systemPrompt, useOutdent);
|
|
4151
|
+
const preparedPrompt = prepareGeneratePromptPayload(resolvedPrompt, resolvedSystemPrompt);
|
|
4152
|
+
const resolvedRequest = normalized.timeout?.tool !== undefined && normalized.request?.mcpClients !== undefined ? {
|
|
4153
|
+
...normalized.request,
|
|
4154
|
+
mcpClients: applyToolTimeout(normalized.request.mcpClients, normalized.timeout.tool)
|
|
4155
|
+
} : normalized.request;
|
|
4156
|
+
const response = await callModel(adapter, {
|
|
4157
|
+
prompt: preparedPrompt.prompt,
|
|
4158
|
+
messages: preparedPrompt.messages,
|
|
4159
|
+
systemPrompt: preparedPrompt.systemPrompt,
|
|
4160
|
+
request: resolvedRequest,
|
|
4161
|
+
stream: streamConfig,
|
|
4162
|
+
observe: normalized.observe,
|
|
4163
|
+
buildEvent: ({ stage, message, details }) => ({
|
|
4164
|
+
stage,
|
|
4165
|
+
attempt: 1,
|
|
4166
|
+
message,
|
|
4167
|
+
details
|
|
4168
|
+
}),
|
|
4169
|
+
buildSnapshot: (model) => ({
|
|
4170
|
+
text: model.text,
|
|
4171
|
+
reasoning: model.reasoning
|
|
4172
|
+
}),
|
|
4173
|
+
debug: debugConfig,
|
|
4174
|
+
debugLabel: "generate",
|
|
4175
|
+
attempt: 1,
|
|
4176
|
+
selfHeal: false,
|
|
4177
|
+
selfHealEnabled: false,
|
|
4178
|
+
timeout: normalized.timeout
|
|
4179
|
+
});
|
|
4180
|
+
const attempt = {
|
|
4181
|
+
attempt: 1,
|
|
4182
|
+
via: response.via,
|
|
4183
|
+
text: response.text,
|
|
4184
|
+
reasoning: response.reasoning,
|
|
4185
|
+
usage: response.usage,
|
|
4186
|
+
finishReason: response.finishReason
|
|
4187
|
+
};
|
|
4188
|
+
const attempts = [attempt];
|
|
4189
|
+
normalized.observe?.({
|
|
4190
|
+
stage: "result",
|
|
4191
|
+
attempt: 1,
|
|
4192
|
+
message: "Text generation completed.",
|
|
4193
|
+
details: {
|
|
4194
|
+
via: response.via,
|
|
4195
|
+
finishReason: response.finishReason
|
|
4196
|
+
}
|
|
4197
|
+
});
|
|
4198
|
+
return {
|
|
4199
|
+
text: attempt.text,
|
|
4200
|
+
reasoning: attempt.reasoning,
|
|
4201
|
+
attempts,
|
|
4202
|
+
usage: aggregateUsage(attempts),
|
|
4203
|
+
finishReason: attempt.finishReason
|
|
4204
|
+
};
|
|
4205
|
+
}
|
|
4206
|
+
function normalizeGenerateInput(promptOrOptions, callOptions) {
|
|
4207
|
+
if (isGenerateOptions(promptOrOptions)) {
|
|
4208
|
+
return promptOrOptions;
|
|
4209
|
+
}
|
|
4210
|
+
if (!promptOrOptions) {
|
|
4211
|
+
throw new Error("Missing prompt in generate(adapter, prompt, options?) call.");
|
|
4212
|
+
}
|
|
4213
|
+
return {
|
|
4214
|
+
...callOptions ?? {},
|
|
4215
|
+
prompt: promptOrOptions
|
|
4216
|
+
};
|
|
4217
|
+
}
|
|
4218
|
+
function isGenerateOptions(value) {
|
|
4219
|
+
return typeof value === "object" && value !== null && "prompt" in value;
|
|
4220
|
+
}
|
|
4221
|
+
function prepareGeneratePromptPayload(payload, systemPrompt) {
|
|
4222
|
+
if (Array.isArray(payload.messages) && payload.messages.length > 0) {
|
|
4223
|
+
const messages = payload.messages.map((message) => ({ ...message }));
|
|
4224
|
+
const mergedSystemPrompt = mergeSystemPrompts(payload.systemPrompt, systemPrompt);
|
|
4225
|
+
const systemMessages = mergedSystemPrompt ? [{ role: "system", content: mergedSystemPrompt }] : [];
|
|
4226
|
+
return {
|
|
4227
|
+
messages: [...systemMessages, ...messages]
|
|
4228
|
+
};
|
|
4229
|
+
}
|
|
4230
|
+
const resolvedPrompt = payload.prompt?.trim();
|
|
4231
|
+
if (!resolvedPrompt) {
|
|
4232
|
+
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
4233
|
+
}
|
|
4234
|
+
return {
|
|
4235
|
+
prompt: resolvedPrompt,
|
|
4236
|
+
systemPrompt: mergeSystemPrompts(payload.systemPrompt, systemPrompt)
|
|
4237
|
+
};
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
// src/structured.ts
|
|
4241
|
+
var import_jsonrepair3 = require("jsonrepair");
|
|
4242
|
+
|
|
4243
|
+
// src/parse.ts
|
|
4244
|
+
var import_jsonrepair2 = require("jsonrepair");
|
|
4245
|
+
function parseLLMOutput(output, schema, options = {}) {
|
|
4246
|
+
const sanitized = sanitizeThink(output);
|
|
4247
|
+
const parseOptions = {
|
|
4248
|
+
repair: options.repair ?? true,
|
|
4249
|
+
maxCandidates: options.maxCandidates ?? 5,
|
|
4250
|
+
acceptArrays: options.acceptArrays ?? true,
|
|
4251
|
+
extraction: options.extraction,
|
|
4252
|
+
onTrace: options.onTrace
|
|
4253
|
+
};
|
|
4254
|
+
const candidates = extractJsonCandidates(sanitized.visibleText, {
|
|
4255
|
+
maxCandidates: parseOptions.maxCandidates,
|
|
4256
|
+
acceptArrays: parseOptions.acceptArrays,
|
|
4257
|
+
allowRepairHints: parseOptions.repair,
|
|
4258
|
+
heuristics: parseOptions.extraction
|
|
4259
|
+
});
|
|
4260
|
+
emitTrace(parseOptions.onTrace, {
|
|
4261
|
+
stage: "extract",
|
|
4262
|
+
level: "info",
|
|
4263
|
+
message: `Extracted ${candidates.length} candidate(s).`,
|
|
4264
|
+
details: {
|
|
4265
|
+
maxCandidates: parseOptions.maxCandidates,
|
|
4266
|
+
thinkBlocks: sanitized.thinkBlocks.length,
|
|
4267
|
+
thinkDiagnostics: sanitized.diagnostics
|
|
4268
|
+
}
|
|
4269
|
+
});
|
|
4270
|
+
const errors = [];
|
|
4271
|
+
const diagnostics = [];
|
|
4272
|
+
let bestIssues = [];
|
|
4273
|
+
let bestCandidate = candidates[0] ?? null;
|
|
4274
|
+
let bestParsed = null;
|
|
4275
|
+
let bestRepaired = null;
|
|
4276
|
+
for (const candidate of candidates) {
|
|
4277
|
+
const parseAttempt = parseAttemptFromHint(candidate.parseHint, parseOptions.repair) ?? tryParseJsonCandidate(candidate.content, parseOptions.repair);
|
|
4278
|
+
if (!parseAttempt.success) {
|
|
4279
|
+
const diagnostic = {
|
|
4280
|
+
candidateId: candidate.id,
|
|
3582
4281
|
source: candidate.source,
|
|
3583
4282
|
usedRepair: parseAttempt.usedRepair,
|
|
3584
4283
|
parseSuccess: false,
|
|
@@ -3840,48 +4539,19 @@ function formatZodIssues(issues) {
|
|
|
3840
4539
|
`);
|
|
3841
4540
|
}
|
|
3842
4541
|
|
|
3843
|
-
// src/utils/debug-colors.ts
|
|
3844
|
-
var ANSI = {
|
|
3845
|
-
reset: "\x1B[0m",
|
|
3846
|
-
bold: "\x1B[1m",
|
|
3847
|
-
cyan: "\x1B[36m",
|
|
3848
|
-
yellow: "\x1B[33m",
|
|
3849
|
-
green: "\x1B[32m",
|
|
3850
|
-
red: "\x1B[31m",
|
|
3851
|
-
dim: "\x1B[2m"
|
|
3852
|
-
};
|
|
3853
|
-
function color(config, text, tone) {
|
|
3854
|
-
if (!config.colors) {
|
|
3855
|
-
return text;
|
|
3856
|
-
}
|
|
3857
|
-
return `${ANSI[tone]}${text}${ANSI.reset}`;
|
|
3858
|
-
}
|
|
3859
|
-
function dim(config, text) {
|
|
3860
|
-
if (!config.colors) {
|
|
3861
|
-
return text;
|
|
3862
|
-
}
|
|
3863
|
-
return `${ANSI.dim}${text}${ANSI.reset}`;
|
|
3864
|
-
}
|
|
3865
|
-
function title(config, text) {
|
|
3866
|
-
if (!config.colors) {
|
|
3867
|
-
return text;
|
|
3868
|
-
}
|
|
3869
|
-
return `${ANSI.bold}${text}${ANSI.reset}`;
|
|
3870
|
-
}
|
|
3871
|
-
|
|
3872
4542
|
// src/structured.ts
|
|
3873
4543
|
class StructuredParseError extends Error {
|
|
3874
4544
|
name = "StructuredParseError";
|
|
3875
|
-
|
|
3876
|
-
|
|
4545
|
+
text;
|
|
4546
|
+
reasoning;
|
|
3877
4547
|
candidates;
|
|
3878
4548
|
zodIssues;
|
|
3879
4549
|
repairLog;
|
|
3880
4550
|
attempt;
|
|
3881
4551
|
constructor(input) {
|
|
3882
4552
|
super(input.message ?? `Structured parsing failed after ${input.attempt} attempt(s).`);
|
|
3883
|
-
this.
|
|
3884
|
-
this.
|
|
4553
|
+
this.text = input.text;
|
|
4554
|
+
this.reasoning = input.reasoning;
|
|
3885
4555
|
this.candidates = input.candidates;
|
|
3886
4556
|
this.zodIssues = input.zodIssues;
|
|
3887
4557
|
this.repairLog = input.repairLog;
|
|
@@ -3912,12 +4582,6 @@ var RE_SIMPLE_IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
|
3912
4582
|
var RE_ESCAPE_QUOTE = /"/g;
|
|
3913
4583
|
var RE_WHITESPACE2 = /\s+/g;
|
|
3914
4584
|
var DEFAULT_SELF_HEAL_MAX_DIAGNOSTICS = 8;
|
|
3915
|
-
var structuredOutdent = createOutdent({
|
|
3916
|
-
trimLeadingNewline: true,
|
|
3917
|
-
trimTrailingNewline: true,
|
|
3918
|
-
newline: `
|
|
3919
|
-
`
|
|
3920
|
-
});
|
|
3921
4585
|
var DEFAULT_STRICT_PARSE_OPTIONS = {
|
|
3922
4586
|
repair: false,
|
|
3923
4587
|
maxCandidates: 3,
|
|
@@ -4047,7 +4711,7 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
4047
4711
|
});
|
|
4048
4712
|
const selfHealSource = resolveSelfHealSource(previous);
|
|
4049
4713
|
const repairPrompt = buildSelfHealPrompt({
|
|
4050
|
-
rawOutput: previous.
|
|
4714
|
+
rawOutput: composeParseSource(previous.text, previous.reasoning),
|
|
4051
4715
|
issues: previous.zodIssues,
|
|
4052
4716
|
schema: normalized.schema,
|
|
4053
4717
|
schemaInstruction: normalized.schemaInstruction,
|
|
@@ -4120,74 +4784,6 @@ function normalizeStructuredInput(schemaOrOptions, promptInput, callOptions) {
|
|
|
4120
4784
|
function isStructuredOptions(value) {
|
|
4121
4785
|
return typeof value === "object" && value !== null && "schema" in value && "prompt" in value;
|
|
4122
4786
|
}
|
|
4123
|
-
function resolvePrompt(prompt, context) {
|
|
4124
|
-
const resolved = typeof prompt === "function" ? prompt(context) : prompt;
|
|
4125
|
-
return normalizePromptValue(resolved, context);
|
|
4126
|
-
}
|
|
4127
|
-
function normalizePromptValue(value, context) {
|
|
4128
|
-
if (typeof value === "string") {
|
|
4129
|
-
return {
|
|
4130
|
-
prompt: value
|
|
4131
|
-
};
|
|
4132
|
-
}
|
|
4133
|
-
if (isPromptResolver(value)) {
|
|
4134
|
-
return normalizePromptPayload(value.resolvePrompt(context));
|
|
4135
|
-
}
|
|
4136
|
-
return normalizePromptPayload(value);
|
|
4137
|
-
}
|
|
4138
|
-
function isPromptResolver(value) {
|
|
4139
|
-
return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
|
|
4140
|
-
}
|
|
4141
|
-
function normalizePromptPayload(value) {
|
|
4142
|
-
const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
|
|
4143
|
-
const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
|
|
4144
|
-
if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
|
|
4145
|
-
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
4146
|
-
}
|
|
4147
|
-
return {
|
|
4148
|
-
prompt,
|
|
4149
|
-
systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
|
|
4150
|
-
messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
|
|
4151
|
-
};
|
|
4152
|
-
}
|
|
4153
|
-
function applyPromptOutdent(payload, enabled) {
|
|
4154
|
-
if (!enabled) {
|
|
4155
|
-
return payload;
|
|
4156
|
-
}
|
|
4157
|
-
return {
|
|
4158
|
-
prompt: typeof payload.prompt === "string" ? structuredOutdent.string(payload.prompt) : undefined,
|
|
4159
|
-
systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
|
|
4160
|
-
messages: payload.messages?.map((message) => ({
|
|
4161
|
-
...message,
|
|
4162
|
-
content: typeof message.content === "string" ? structuredOutdent.string(message.content) : message.content
|
|
4163
|
-
}))
|
|
4164
|
-
};
|
|
4165
|
-
}
|
|
4166
|
-
function isLLMMessage(value) {
|
|
4167
|
-
if (typeof value !== "object" || value === null) {
|
|
4168
|
-
return false;
|
|
4169
|
-
}
|
|
4170
|
-
const candidate = value;
|
|
4171
|
-
if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
|
|
4172
|
-
return false;
|
|
4173
|
-
}
|
|
4174
|
-
return "content" in candidate;
|
|
4175
|
-
}
|
|
4176
|
-
function applyOutdentToOptionalPrompt(value, enabled) {
|
|
4177
|
-
if (!enabled || typeof value !== "string") {
|
|
4178
|
-
return value;
|
|
4179
|
-
}
|
|
4180
|
-
return structuredOutdent.string(value);
|
|
4181
|
-
}
|
|
4182
|
-
function mergeSystemPrompts(primary, secondary) {
|
|
4183
|
-
const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
|
|
4184
|
-
if (prompts.length === 0) {
|
|
4185
|
-
return;
|
|
4186
|
-
}
|
|
4187
|
-
return prompts.join(`
|
|
4188
|
-
|
|
4189
|
-
`);
|
|
4190
|
-
}
|
|
4191
4787
|
function prepareStructuredPromptPayload(payload, systemPrompt, schema, schemaInstruction) {
|
|
4192
4788
|
if (Array.isArray(payload.messages) && payload.messages.length > 0) {
|
|
4193
4789
|
const messages = payload.messages.map((message) => ({ ...message }));
|
|
@@ -4368,7 +4964,7 @@ function resolveSelfHealSource(attempt) {
|
|
|
4368
4964
|
}
|
|
4369
4965
|
return {
|
|
4370
4966
|
kind: "raw",
|
|
4371
|
-
text: attempt.
|
|
4967
|
+
text: composeParseSource(attempt.text, attempt.reasoning)
|
|
4372
4968
|
};
|
|
4373
4969
|
}
|
|
4374
4970
|
function isSelfHealStalled(previous, current) {
|
|
@@ -4378,60 +4974,22 @@ function isSelfHealStalled(previous, current) {
|
|
|
4378
4974
|
if (current.zodIssues.length < previous.zodIssues.length) {
|
|
4379
4975
|
return false;
|
|
4380
4976
|
}
|
|
4381
|
-
if (current.parsed.errors.length < previous.parsed.errors.length) {
|
|
4382
|
-
return false;
|
|
4383
|
-
}
|
|
4384
|
-
return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
|
|
4385
|
-
}
|
|
4386
|
-
function buildSelfHealFailureFingerprint(attempt) {
|
|
4387
|
-
const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
|
|
4388
|
-
const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
|
|
4389
|
-
const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
|
|
4390
|
-
return [issues, errors, source].join("::");
|
|
4391
|
-
}
|
|
4392
|
-
function normalizeWhitespace(value) {
|
|
4393
|
-
return value.replace(RE_WHITESPACE2, " ").trim();
|
|
4394
|
-
}
|
|
4395
|
-
function normalizeStreamConfig(option) {
|
|
4396
|
-
if (typeof option === "boolean") {
|
|
4397
|
-
return {
|
|
4398
|
-
enabled: option
|
|
4399
|
-
};
|
|
4400
|
-
}
|
|
4401
|
-
if (!option) {
|
|
4402
|
-
return {
|
|
4403
|
-
enabled: false
|
|
4404
|
-
};
|
|
4405
|
-
}
|
|
4406
|
-
return {
|
|
4407
|
-
enabled: option.enabled ?? true,
|
|
4408
|
-
onData: option.onData,
|
|
4409
|
-
to: option.to
|
|
4410
|
-
};
|
|
4411
|
-
}
|
|
4412
|
-
function normalizeDebugConfig(option) {
|
|
4413
|
-
if (typeof option === "boolean") {
|
|
4414
|
-
return {
|
|
4415
|
-
enabled: option,
|
|
4416
|
-
colors: true,
|
|
4417
|
-
logger: (line) => console.log(line)
|
|
4418
|
-
};
|
|
4419
|
-
}
|
|
4420
|
-
if (!option) {
|
|
4421
|
-
return {
|
|
4422
|
-
enabled: false,
|
|
4423
|
-
colors: true,
|
|
4424
|
-
logger: (line) => console.log(line)
|
|
4425
|
-
};
|
|
4977
|
+
if (current.parsed.errors.length < previous.parsed.errors.length) {
|
|
4978
|
+
return false;
|
|
4426
4979
|
}
|
|
4427
|
-
return
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
};
|
|
4980
|
+
return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
|
|
4981
|
+
}
|
|
4982
|
+
function buildSelfHealFailureFingerprint(attempt) {
|
|
4983
|
+
const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
|
|
4984
|
+
const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
|
|
4985
|
+
const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
|
|
4986
|
+
return [issues, errors, source].join("::");
|
|
4987
|
+
}
|
|
4988
|
+
function normalizeWhitespace(value) {
|
|
4989
|
+
return value.replace(RE_WHITESPACE2, " ").trim();
|
|
4432
4990
|
}
|
|
4433
4991
|
async function executeAttempt(adapter, input) {
|
|
4434
|
-
const response = await
|
|
4992
|
+
const response = await callModel2(adapter, {
|
|
4435
4993
|
prompt: input.prompt,
|
|
4436
4994
|
messages: input.messages,
|
|
4437
4995
|
systemPrompt: input.systemPrompt,
|
|
@@ -4444,7 +5002,7 @@ async function executeAttempt(adapter, input) {
|
|
|
4444
5002
|
selfHealEnabled: input.selfHealEnabled,
|
|
4445
5003
|
timeout: input.timeout
|
|
4446
5004
|
});
|
|
4447
|
-
const parsed = parseWithObserve(response.
|
|
5005
|
+
const parsed = parseWithObserve(response.parseSource, input.schema, input.parseOptions, {
|
|
4448
5006
|
observe: input.observe,
|
|
4449
5007
|
attempt: input.attemptNumber,
|
|
4450
5008
|
selfHeal: input.selfHeal
|
|
@@ -4453,8 +5011,8 @@ async function executeAttempt(adapter, input) {
|
|
|
4453
5011
|
attempt: input.attemptNumber,
|
|
4454
5012
|
selfHeal: input.selfHeal,
|
|
4455
5013
|
via: response.via,
|
|
4456
|
-
|
|
4457
|
-
|
|
5014
|
+
text: response.text,
|
|
5015
|
+
reasoning: response.reasoning,
|
|
4458
5016
|
json: parsed.parsed,
|
|
4459
5017
|
candidates: parsed.candidates.map((candidate) => candidate.content),
|
|
4460
5018
|
repairLog: collectRepairLog(parsed),
|
|
@@ -4469,199 +5027,26 @@ async function executeAttempt(adapter, input) {
|
|
|
4469
5027
|
trace
|
|
4470
5028
|
};
|
|
4471
5029
|
}
|
|
4472
|
-
function
|
|
4473
|
-
return {
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
async callTool(params) {
|
|
4478
|
-
let timeoutId;
|
|
4479
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
4480
|
-
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
4481
|
-
});
|
|
4482
|
-
try {
|
|
4483
|
-
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
4484
|
-
} finally {
|
|
4485
|
-
clearTimeout(timeoutId);
|
|
4486
|
-
}
|
|
4487
|
-
}
|
|
4488
|
-
};
|
|
4489
|
-
}
|
|
4490
|
-
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
4491
|
-
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
4492
|
-
}
|
|
4493
|
-
async function callModel(adapter, options) {
|
|
4494
|
-
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
4495
|
-
const requestPayload = {
|
|
4496
|
-
prompt: options.prompt,
|
|
4497
|
-
messages: options.messages,
|
|
4498
|
-
systemPrompt: options.systemPrompt,
|
|
4499
|
-
temperature: options.request?.temperature,
|
|
4500
|
-
maxTokens: options.request?.maxTokens,
|
|
4501
|
-
mcpClients: options.request?.mcpClients,
|
|
4502
|
-
toolChoice: options.request?.toolChoice,
|
|
4503
|
-
parallelToolCalls: options.request?.parallelToolCalls,
|
|
4504
|
-
maxToolRounds: options.request?.maxToolRounds,
|
|
4505
|
-
onToolExecution: options.request?.onToolExecution,
|
|
4506
|
-
transformToolOutput: options.request?.transformToolOutput,
|
|
4507
|
-
transformToolArguments: options.request?.transformToolArguments,
|
|
4508
|
-
transformToolCallParams: options.request?.transformToolCallParams,
|
|
4509
|
-
unknownToolError: options.request?.unknownToolError,
|
|
4510
|
-
toolDebug: options.request?.toolDebug,
|
|
4511
|
-
body: options.request?.body,
|
|
4512
|
-
signal: requestSignal
|
|
4513
|
-
};
|
|
4514
|
-
emitDebugRequest(options.debug, {
|
|
4515
|
-
provider: adapter.provider,
|
|
4516
|
-
model: adapter.model,
|
|
4517
|
-
attempt: options.attempt,
|
|
4518
|
-
selfHealAttempt: options.selfHeal,
|
|
4519
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4520
|
-
stream: options.stream.enabled && !!adapter.stream,
|
|
4521
|
-
requestPayload
|
|
4522
|
-
});
|
|
4523
|
-
emitObserve(options.observe, {
|
|
4524
|
-
stage: "llm.request",
|
|
4525
|
-
attempt: options.attempt,
|
|
4526
|
-
selfHeal: options.selfHeal,
|
|
4527
|
-
message: "Sending LLM request.",
|
|
4528
|
-
details: {
|
|
4529
|
-
provider: adapter.provider,
|
|
4530
|
-
model: adapter.model,
|
|
4531
|
-
stream: options.stream.enabled && !!adapter.stream
|
|
4532
|
-
}
|
|
4533
|
-
});
|
|
4534
|
-
if (options.stream.enabled && adapter.stream) {
|
|
4535
|
-
let latestUsage;
|
|
4536
|
-
let latestFinishReason;
|
|
4537
|
-
let streamedRaw = "";
|
|
4538
|
-
let sawToken = false;
|
|
4539
|
-
let lastDataFingerprint;
|
|
4540
|
-
const emitStreamingData = (raw, done, usage2, finishReason2) => {
|
|
4541
|
-
const data = parseStreamingStructuredData(raw);
|
|
4542
|
-
if (data === null && !done) {
|
|
4543
|
-
return;
|
|
4544
|
-
}
|
|
4545
|
-
const fingerprint = toStreamDataFingerprint(data ?? null);
|
|
4546
|
-
if (!done && fingerprint === lastDataFingerprint) {
|
|
4547
|
-
return;
|
|
4548
|
-
}
|
|
4549
|
-
lastDataFingerprint = fingerprint;
|
|
4550
|
-
options.stream.onData?.({
|
|
4551
|
-
data: data ?? null,
|
|
4552
|
-
raw,
|
|
4553
|
-
done,
|
|
4554
|
-
usage: usage2,
|
|
4555
|
-
finishReason: finishReason2
|
|
4556
|
-
});
|
|
4557
|
-
emitObserve(options.observe, {
|
|
4558
|
-
stage: "llm.stream.data",
|
|
4559
|
-
attempt: options.attempt,
|
|
4560
|
-
selfHeal: options.selfHeal,
|
|
4561
|
-
message: done ? "Streaming structured data completed." : "Streaming structured data updated.",
|
|
4562
|
-
details: {
|
|
4563
|
-
done,
|
|
4564
|
-
finishReason: finishReason2
|
|
4565
|
-
}
|
|
4566
|
-
});
|
|
4567
|
-
};
|
|
4568
|
-
const handleTextDelta = (delta) => {
|
|
4569
|
-
if (!delta) {
|
|
4570
|
-
return;
|
|
4571
|
-
}
|
|
4572
|
-
streamedRaw += delta;
|
|
4573
|
-
if (options.stream.to === "stdout") {
|
|
4574
|
-
process.stdout.write(delta);
|
|
4575
|
-
}
|
|
4576
|
-
emitObserve(options.observe, {
|
|
4577
|
-
stage: "llm.stream.delta",
|
|
4578
|
-
attempt: options.attempt,
|
|
4579
|
-
selfHeal: options.selfHeal,
|
|
4580
|
-
message: "Received stream delta.",
|
|
4581
|
-
details: {
|
|
4582
|
-
chars: delta.length
|
|
4583
|
-
}
|
|
4584
|
-
});
|
|
4585
|
-
emitStreamingData(streamedRaw, false);
|
|
4586
|
-
};
|
|
4587
|
-
const response2 = await adapter.stream(requestPayload, {
|
|
4588
|
-
onToken: (token) => {
|
|
4589
|
-
sawToken = true;
|
|
4590
|
-
handleTextDelta(token);
|
|
4591
|
-
},
|
|
4592
|
-
onChunk: (chunk) => {
|
|
4593
|
-
if (!sawToken && chunk.textDelta) {
|
|
4594
|
-
handleTextDelta(chunk.textDelta);
|
|
4595
|
-
}
|
|
4596
|
-
if (chunk.usage) {
|
|
4597
|
-
latestUsage = preferLatestUsage(latestUsage, chunk.usage);
|
|
4598
|
-
}
|
|
4599
|
-
if (chunk.finishReason) {
|
|
4600
|
-
latestFinishReason = chunk.finishReason;
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
4603
|
-
});
|
|
4604
|
-
const finalText = typeof response2.text === "string" && response2.text.length > 0 ? response2.text : streamedRaw;
|
|
4605
|
-
const usage = preferLatestUsage(latestUsage, response2.usage);
|
|
4606
|
-
const finishReason = response2.finishReason ?? latestFinishReason;
|
|
4607
|
-
emitStreamingData(finalText, true, usage, finishReason);
|
|
4608
|
-
emitObserve(options.observe, {
|
|
4609
|
-
stage: "llm.response",
|
|
5030
|
+
async function callModel2(adapter, options) {
|
|
5031
|
+
return callModel(adapter, {
|
|
5032
|
+
...options,
|
|
5033
|
+
buildEvent: ({ stage, message, details }) => ({
|
|
5034
|
+
stage,
|
|
4610
5035
|
attempt: options.attempt,
|
|
4611
5036
|
selfHeal: options.selfHeal,
|
|
4612
|
-
message
|
|
4613
|
-
details
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
selfHealAttempt: options.selfHeal,
|
|
4622
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4623
|
-
via: "stream",
|
|
4624
|
-
responseText: finalText,
|
|
4625
|
-
usage,
|
|
4626
|
-
finishReason
|
|
4627
|
-
});
|
|
4628
|
-
return {
|
|
4629
|
-
text: finalText,
|
|
4630
|
-
via: "stream",
|
|
4631
|
-
usage,
|
|
4632
|
-
finishReason
|
|
4633
|
-
};
|
|
4634
|
-
}
|
|
4635
|
-
const response = await adapter.complete(requestPayload);
|
|
4636
|
-
emitObserve(options.observe, {
|
|
4637
|
-
stage: "llm.response",
|
|
4638
|
-
attempt: options.attempt,
|
|
4639
|
-
selfHeal: options.selfHeal,
|
|
4640
|
-
message: "Completion response received.",
|
|
4641
|
-
details: {
|
|
4642
|
-
via: "complete",
|
|
4643
|
-
chars: response.text.length,
|
|
4644
|
-
finishReason: response.finishReason
|
|
4645
|
-
}
|
|
4646
|
-
});
|
|
4647
|
-
emitDebugResponse(options.debug, {
|
|
4648
|
-
attempt: options.attempt,
|
|
4649
|
-
selfHealAttempt: options.selfHeal,
|
|
4650
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4651
|
-
via: "complete",
|
|
4652
|
-
responseText: response.text,
|
|
4653
|
-
usage: response.usage,
|
|
4654
|
-
finishReason: response.finishReason
|
|
5037
|
+
message,
|
|
5038
|
+
details
|
|
5039
|
+
}),
|
|
5040
|
+
buildSnapshot: (normalized) => ({
|
|
5041
|
+
text: normalized.text,
|
|
5042
|
+
reasoning: normalized.reasoning,
|
|
5043
|
+
data: parseStreamingStructuredData(normalized.parseSource) ?? null
|
|
5044
|
+
}),
|
|
5045
|
+
debugLabel: "structured"
|
|
4655
5046
|
});
|
|
4656
|
-
return {
|
|
4657
|
-
text: response.text,
|
|
4658
|
-
via: "complete",
|
|
4659
|
-
usage: response.usage,
|
|
4660
|
-
finishReason: response.finishReason
|
|
4661
|
-
};
|
|
4662
5047
|
}
|
|
4663
|
-
function parseStreamingStructuredData(
|
|
4664
|
-
const sanitized = sanitizeThink(
|
|
5048
|
+
function parseStreamingStructuredData(parseSource) {
|
|
5049
|
+
const sanitized = sanitizeThink(parseSource);
|
|
4665
5050
|
const start = findFirstJsonRootStart(sanitized.visibleText);
|
|
4666
5051
|
if (start < 0) {
|
|
4667
5052
|
return null;
|
|
@@ -4721,13 +5106,6 @@ function findFirstJsonRootStart(input) {
|
|
|
4721
5106
|
}
|
|
4722
5107
|
return Math.min(objectStart, arrayStart);
|
|
4723
5108
|
}
|
|
4724
|
-
function toStreamDataFingerprint(value) {
|
|
4725
|
-
try {
|
|
4726
|
-
return JSON.stringify(value);
|
|
4727
|
-
} catch {
|
|
4728
|
-
return "__unserializable__";
|
|
4729
|
-
}
|
|
4730
|
-
}
|
|
4731
5109
|
function parseWithObserve(output, schema, parseOptions, context) {
|
|
4732
5110
|
const userParseTrace = parseOptions.onTrace;
|
|
4733
5111
|
return parseLLMOutput(output, schema, {
|
|
@@ -4757,38 +5135,20 @@ function buildSuccessResult(data, attempts) {
|
|
|
4757
5135
|
const final = attempts.at(-1);
|
|
4758
5136
|
return {
|
|
4759
5137
|
data,
|
|
4760
|
-
|
|
4761
|
-
|
|
5138
|
+
text: final?.text ?? "",
|
|
5139
|
+
reasoning: final?.reasoning ?? "",
|
|
4762
5140
|
json: final?.json ?? null,
|
|
4763
5141
|
attempts,
|
|
4764
5142
|
usage: aggregateUsage(attempts),
|
|
4765
5143
|
finishReason: final?.finishReason
|
|
4766
5144
|
};
|
|
4767
5145
|
}
|
|
4768
|
-
function aggregateUsage(attempts) {
|
|
4769
|
-
let usage;
|
|
4770
|
-
for (const attempt of attempts) {
|
|
4771
|
-
usage = mergeUsage2(usage, attempt.usage);
|
|
4772
|
-
}
|
|
4773
|
-
return usage;
|
|
4774
|
-
}
|
|
4775
|
-
function mergeUsage2(base, next) {
|
|
4776
|
-
if (!base && !next) {
|
|
4777
|
-
return;
|
|
4778
|
-
}
|
|
4779
|
-
return {
|
|
4780
|
-
inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
|
|
4781
|
-
outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
|
|
4782
|
-
totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
|
|
4783
|
-
cost: (base?.cost ?? 0) + (next?.cost ?? 0)
|
|
4784
|
-
};
|
|
4785
|
-
}
|
|
4786
5146
|
function toStructuredError(attempt) {
|
|
4787
5147
|
if (!attempt) {
|
|
4788
5148
|
return new StructuredParseError({
|
|
4789
5149
|
message: "Structured parsing failed before any model response.",
|
|
4790
|
-
|
|
4791
|
-
|
|
5150
|
+
text: "",
|
|
5151
|
+
reasoning: "",
|
|
4792
5152
|
candidates: [],
|
|
4793
5153
|
zodIssues: [],
|
|
4794
5154
|
repairLog: [],
|
|
@@ -4796,8 +5156,8 @@ function toStructuredError(attempt) {
|
|
|
4796
5156
|
});
|
|
4797
5157
|
}
|
|
4798
5158
|
return new StructuredParseError({
|
|
4799
|
-
|
|
4800
|
-
|
|
5159
|
+
text: attempt.text,
|
|
5160
|
+
reasoning: attempt.reasoning,
|
|
4801
5161
|
candidates: attempt.candidates,
|
|
4802
5162
|
zodIssues: attempt.zodIssues,
|
|
4803
5163
|
repairLog: attempt.repairLog,
|
|
@@ -4807,59 +5167,6 @@ function toStructuredError(attempt) {
|
|
|
4807
5167
|
function emitObserve(observe, event) {
|
|
4808
5168
|
observe?.(event);
|
|
4809
5169
|
}
|
|
4810
|
-
function emitDebugRequest(config, input) {
|
|
4811
|
-
const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
|
|
4812
|
-
const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
|
|
4813
|
-
const lines = [
|
|
4814
|
-
color(config, title(config, [
|
|
4815
|
-
"[structured][request]",
|
|
4816
|
-
`attempt=${input.attempt}`,
|
|
4817
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4818
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4819
|
-
].join(" ")), "cyan"),
|
|
4820
|
-
dim(config, [
|
|
4821
|
-
`provider=${input.provider ?? "unknown"}`,
|
|
4822
|
-
`model=${input.model ?? "unknown"}`,
|
|
4823
|
-
`stream=${input.stream}`
|
|
4824
|
-
].join(" ")),
|
|
4825
|
-
color(config, "prompt:", "yellow"),
|
|
4826
|
-
input.requestPayload.prompt ?? "(none)",
|
|
4827
|
-
color(config, "messages:", "yellow"),
|
|
4828
|
-
requestMessages,
|
|
4829
|
-
color(config, "systemPrompt:", "yellow"),
|
|
4830
|
-
input.requestPayload.systemPrompt ?? "(none)",
|
|
4831
|
-
color(config, "request.body:", "yellow"),
|
|
4832
|
-
requestBody
|
|
4833
|
-
];
|
|
4834
|
-
emitDebug(config, lines.join(`
|
|
4835
|
-
`));
|
|
4836
|
-
}
|
|
4837
|
-
function emitDebugResponse(config, input) {
|
|
4838
|
-
const lines = [
|
|
4839
|
-
color(config, title(config, [
|
|
4840
|
-
"[structured][response]",
|
|
4841
|
-
`attempt=${input.attempt}`,
|
|
4842
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4843
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4844
|
-
].join(" ")), "green"),
|
|
4845
|
-
dim(config, [
|
|
4846
|
-
`via=${input.via}`,
|
|
4847
|
-
`chars=${input.responseText.length}`,
|
|
4848
|
-
`finishReason=${input.finishReason ?? "unknown"}`,
|
|
4849
|
-
`usage=${JSON.stringify(input.usage ?? {})}`
|
|
4850
|
-
].join(" ")),
|
|
4851
|
-
color(config, "text:", "yellow"),
|
|
4852
|
-
input.responseText
|
|
4853
|
-
];
|
|
4854
|
-
emitDebug(config, lines.join(`
|
|
4855
|
-
`));
|
|
4856
|
-
}
|
|
4857
|
-
function emitDebug(config, message) {
|
|
4858
|
-
if (!config.enabled) {
|
|
4859
|
-
return;
|
|
4860
|
-
}
|
|
4861
|
-
config.logger(message);
|
|
4862
|
-
}
|
|
4863
5170
|
|
|
4864
5171
|
// src/llm.ts
|
|
4865
5172
|
function createLLM(config, registry = createDefaultProviderRegistry()) {
|
|
@@ -4873,6 +5180,17 @@ function createLLM(config, registry = createDefaultProviderRegistry()) {
|
|
|
4873
5180
|
const merged = mergeStructuredOptions(defaults, options);
|
|
4874
5181
|
return structured(adapter, schema, prompt, merged);
|
|
4875
5182
|
},
|
|
5183
|
+
async generate(promptOrOptions, options) {
|
|
5184
|
+
if (isGenerateOptions2(promptOrOptions)) {
|
|
5185
|
+
const merged2 = {
|
|
5186
|
+
...mergeGenerateOptions(defaults, promptOrOptions),
|
|
5187
|
+
prompt: promptOrOptions.prompt
|
|
5188
|
+
};
|
|
5189
|
+
return generate(adapter, merged2);
|
|
5190
|
+
}
|
|
5191
|
+
const merged = mergeGenerateOptions(defaults, options);
|
|
5192
|
+
return generate(adapter, promptOrOptions, merged);
|
|
5193
|
+
},
|
|
4876
5194
|
async embed(input, options = {}) {
|
|
4877
5195
|
if (!adapter.embed) {
|
|
4878
5196
|
throw new Error(`Provider "${adapter.provider ?? "unknown"}" does not support embeddings.`);
|
|
@@ -4902,6 +5220,26 @@ function mergeStructuredOptions(defaults, overrides) {
|
|
|
4902
5220
|
timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
|
|
4903
5221
|
};
|
|
4904
5222
|
}
|
|
5223
|
+
function mergeGenerateOptions(defaults, overrides) {
|
|
5224
|
+
if (!defaults && !overrides) {
|
|
5225
|
+
return {};
|
|
5226
|
+
}
|
|
5227
|
+
return {
|
|
5228
|
+
outdent: overrides?.outdent ?? defaults?.outdent,
|
|
5229
|
+
systemPrompt: overrides?.systemPrompt ?? defaults?.systemPrompt,
|
|
5230
|
+
request: {
|
|
5231
|
+
...defaults?.request ?? {},
|
|
5232
|
+
...overrides?.request ?? {}
|
|
5233
|
+
},
|
|
5234
|
+
stream: mergeObjectLike(defaults?.stream, overrides?.stream),
|
|
5235
|
+
debug: mergeObjectLike(defaults?.debug, overrides?.debug),
|
|
5236
|
+
timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout),
|
|
5237
|
+
observe: overrides?.observe ?? defaults?.observe
|
|
5238
|
+
};
|
|
5239
|
+
}
|
|
5240
|
+
function isGenerateOptions2(value) {
|
|
5241
|
+
return typeof value === "object" && value !== null && "prompt" in value;
|
|
5242
|
+
}
|
|
4905
5243
|
function mergeObjectLike(defaults, overrides) {
|
|
4906
5244
|
if (overrides === undefined) {
|
|
4907
5245
|
return defaults;
|