extrait 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -9
- package/dist/generate-shared.d.ts +79 -0
- package/dist/generate.d.ts +3 -0
- package/dist/index.cjs +870 -520
- package/dist/index.d.ts +2 -1
- package/dist/index.js +870 -520
- package/dist/llm.d.ts +18 -2
- package/dist/structured.d.ts +4 -4
- package/dist/types.d.ts +82 -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,
|
|
@@ -1317,6 +1318,17 @@ async function executeMCPToolCalls(calls, toolset, context) {
|
|
|
1317
1318
|
remoteName: tool.remoteName,
|
|
1318
1319
|
clientId: tool.clientId
|
|
1319
1320
|
}) : rawArgs;
|
|
1321
|
+
const toolParams = context.request.transformToolCallParams ? await context.request.transformToolCallParams({
|
|
1322
|
+
name: tool.remoteName,
|
|
1323
|
+
arguments: args
|
|
1324
|
+
}, {
|
|
1325
|
+
name: toolName,
|
|
1326
|
+
remoteName: tool.remoteName,
|
|
1327
|
+
clientId: tool.clientId
|
|
1328
|
+
}) : {
|
|
1329
|
+
name: tool.remoteName,
|
|
1330
|
+
arguments: args
|
|
1331
|
+
};
|
|
1320
1332
|
const metadata = {
|
|
1321
1333
|
id: callId,
|
|
1322
1334
|
type: call.type ?? "function",
|
|
@@ -1326,10 +1338,7 @@ async function executeMCPToolCalls(calls, toolset, context) {
|
|
|
1326
1338
|
const startedAt = new Date().toISOString();
|
|
1327
1339
|
const startedAtMs = Date.now();
|
|
1328
1340
|
try {
|
|
1329
|
-
const output = await tool.client.callTool(
|
|
1330
|
-
name: tool.remoteName,
|
|
1331
|
-
arguments: args
|
|
1332
|
-
});
|
|
1341
|
+
const output = await tool.client.callTool(toolParams);
|
|
1333
1342
|
const executionContext = {
|
|
1334
1343
|
callId,
|
|
1335
1344
|
type: call.type ?? "function",
|
|
@@ -1653,6 +1662,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1653
1662
|
model: options.model,
|
|
1654
1663
|
messages: buildMessages(request),
|
|
1655
1664
|
temperature: request.temperature,
|
|
1665
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1656
1666
|
max_tokens: request.maxTokens,
|
|
1657
1667
|
stream: true
|
|
1658
1668
|
})),
|
|
@@ -1664,6 +1674,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1664
1674
|
}
|
|
1665
1675
|
callbacks.onStart?.();
|
|
1666
1676
|
let text = "";
|
|
1677
|
+
let reasoning = "";
|
|
1667
1678
|
let usage;
|
|
1668
1679
|
let finishReason;
|
|
1669
1680
|
await consumeSSE(response, (data) => {
|
|
@@ -1675,6 +1686,7 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1675
1686
|
return;
|
|
1676
1687
|
}
|
|
1677
1688
|
const delta = pickAssistantDelta(json);
|
|
1689
|
+
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
1678
1690
|
const chunkUsage = pickUsage(json);
|
|
1679
1691
|
const chunkFinishReason = pickFinishReason(json);
|
|
1680
1692
|
usage = preferLatestUsage(usage, chunkUsage);
|
|
@@ -1685,9 +1697,13 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1685
1697
|
text += delta;
|
|
1686
1698
|
callbacks.onToken?.(delta);
|
|
1687
1699
|
}
|
|
1688
|
-
if (
|
|
1700
|
+
if (reasoningDelta) {
|
|
1701
|
+
reasoning += reasoningDelta;
|
|
1702
|
+
}
|
|
1703
|
+
if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
|
|
1689
1704
|
const chunk = {
|
|
1690
1705
|
textDelta: delta,
|
|
1706
|
+
reasoningDelta: reasoningDelta || undefined,
|
|
1691
1707
|
raw: json,
|
|
1692
1708
|
usage: chunkUsage,
|
|
1693
1709
|
finishReason: chunkFinishReason
|
|
@@ -1695,7 +1711,12 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1695
1711
|
callbacks.onChunk?.(chunk);
|
|
1696
1712
|
}
|
|
1697
1713
|
});
|
|
1698
|
-
const out = {
|
|
1714
|
+
const out = {
|
|
1715
|
+
text,
|
|
1716
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1717
|
+
usage,
|
|
1718
|
+
finishReason
|
|
1719
|
+
};
|
|
1699
1720
|
callbacks.onComplete?.(out);
|
|
1700
1721
|
return out;
|
|
1701
1722
|
},
|
|
@@ -1755,6 +1776,7 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
|
|
|
1755
1776
|
model: options.model,
|
|
1756
1777
|
messages: buildMessages(request),
|
|
1757
1778
|
temperature: request.temperature,
|
|
1779
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1758
1780
|
max_tokens: request.maxTokens,
|
|
1759
1781
|
stream: false
|
|
1760
1782
|
})),
|
|
@@ -1770,8 +1792,10 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
|
|
|
1770
1792
|
throw new Error("No assistant message in OpenAI-compatible response.");
|
|
1771
1793
|
}
|
|
1772
1794
|
const toolCalls = pickChatToolCalls(payload);
|
|
1795
|
+
const reasoning = pickAssistantReasoning(payload);
|
|
1773
1796
|
return {
|
|
1774
1797
|
text: pickAssistantText(payload),
|
|
1798
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1775
1799
|
raw: payload,
|
|
1776
1800
|
usage: pickUsage(payload),
|
|
1777
1801
|
finishReason: pickFinishReason(payload),
|
|
@@ -1798,6 +1822,7 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1798
1822
|
model: options.model,
|
|
1799
1823
|
messages,
|
|
1800
1824
|
temperature: request.temperature,
|
|
1825
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1801
1826
|
max_tokens: request.maxTokens,
|
|
1802
1827
|
tools: transportTools,
|
|
1803
1828
|
tool_choice: request.toolChoice,
|
|
@@ -1819,8 +1844,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1819
1844
|
throw new Error("No assistant message in OpenAI-compatible response.");
|
|
1820
1845
|
}
|
|
1821
1846
|
if (calledTools.length === 0) {
|
|
1847
|
+
const reasoning = pickAssistantReasoning(payload);
|
|
1822
1848
|
return {
|
|
1823
1849
|
text: pickAssistantText(payload),
|
|
1850
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1824
1851
|
raw: payload,
|
|
1825
1852
|
usage: aggregatedUsage,
|
|
1826
1853
|
finishReason,
|
|
@@ -1848,6 +1875,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1848
1875
|
}
|
|
1849
1876
|
return {
|
|
1850
1877
|
text: pickAssistantText(lastPayload ?? {}),
|
|
1878
|
+
reasoning: (() => {
|
|
1879
|
+
const value = pickAssistantReasoning(lastPayload ?? {});
|
|
1880
|
+
return value.length > 0 ? value : undefined;
|
|
1881
|
+
})(),
|
|
1851
1882
|
raw: lastPayload,
|
|
1852
1883
|
usage: aggregatedUsage,
|
|
1853
1884
|
finishReason,
|
|
@@ -1867,6 +1898,7 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
|
|
|
1867
1898
|
input: buildResponsesInput(request),
|
|
1868
1899
|
previous_response_id: pickString(body?.previous_response_id),
|
|
1869
1900
|
temperature: request.temperature,
|
|
1901
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1870
1902
|
max_output_tokens: request.maxTokens
|
|
1871
1903
|
})),
|
|
1872
1904
|
signal: request.signal
|
|
@@ -1907,6 +1939,7 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
|
|
|
1907
1939
|
input,
|
|
1908
1940
|
previous_response_id: previousResponseId,
|
|
1909
1941
|
temperature: request.temperature,
|
|
1942
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1910
1943
|
max_output_tokens: request.maxTokens,
|
|
1911
1944
|
tools: transportTools,
|
|
1912
1945
|
tool_choice: request.toolChoice,
|
|
@@ -1971,6 +2004,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
1971
2004
|
const executedToolCalls = [];
|
|
1972
2005
|
const toolExecutions = [];
|
|
1973
2006
|
callbacks.onStart?.();
|
|
2007
|
+
let lastRoundText = "";
|
|
2008
|
+
let lastRoundReasoning = "";
|
|
1974
2009
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
1975
2010
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
1976
2011
|
const transportTools = toProviderFunctionTools(mcpToolset);
|
|
@@ -1983,6 +2018,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
1983
2018
|
model: options.model,
|
|
1984
2019
|
messages,
|
|
1985
2020
|
temperature: request.temperature,
|
|
2021
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1986
2022
|
max_tokens: request.maxTokens,
|
|
1987
2023
|
tools: transportTools,
|
|
1988
2024
|
tool_choice: request.toolChoice,
|
|
@@ -1996,9 +2032,11 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
1996
2032
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1997
2033
|
}
|
|
1998
2034
|
let roundText = "";
|
|
2035
|
+
let roundReasoning = "";
|
|
1999
2036
|
let roundUsage;
|
|
2000
2037
|
let roundFinishReason;
|
|
2001
2038
|
const streamedToolCalls = new Map;
|
|
2039
|
+
let reasoningFieldName;
|
|
2002
2040
|
await consumeSSE(response, (data) => {
|
|
2003
2041
|
if (data === "[DONE]") {
|
|
2004
2042
|
return;
|
|
@@ -2009,6 +2047,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2009
2047
|
}
|
|
2010
2048
|
lastPayload = json;
|
|
2011
2049
|
const delta = pickAssistantDelta(json);
|
|
2050
|
+
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
2012
2051
|
const chunkUsage = pickUsage(json);
|
|
2013
2052
|
const chunkFinishReason = pickFinishReason(json);
|
|
2014
2053
|
collectOpenAIStreamToolCalls(json, streamedToolCalls);
|
|
@@ -2020,9 +2059,14 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2020
2059
|
roundText += delta;
|
|
2021
2060
|
callbacks.onToken?.(delta);
|
|
2022
2061
|
}
|
|
2023
|
-
if (
|
|
2062
|
+
if (reasoningDelta) {
|
|
2063
|
+
roundReasoning += reasoningDelta;
|
|
2064
|
+
reasoningFieldName ??= pickAssistantReasoningDeltaFieldName(json);
|
|
2065
|
+
}
|
|
2066
|
+
if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
|
|
2024
2067
|
const chunk = {
|
|
2025
2068
|
textDelta: delta,
|
|
2069
|
+
reasoningDelta: reasoningDelta || undefined,
|
|
2026
2070
|
raw: json,
|
|
2027
2071
|
usage: chunkUsage,
|
|
2028
2072
|
finishReason: chunkFinishReason
|
|
@@ -2038,6 +2082,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2038
2082
|
if (calledTools.length === 0) {
|
|
2039
2083
|
const out2 = {
|
|
2040
2084
|
text: roundText,
|
|
2085
|
+
reasoning: roundReasoning.length > 0 ? roundReasoning : undefined,
|
|
2041
2086
|
raw: lastPayload,
|
|
2042
2087
|
usage: aggregatedUsage,
|
|
2043
2088
|
finishReason,
|
|
@@ -2058,7 +2103,12 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2058
2103
|
});
|
|
2059
2104
|
executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2060
2105
|
toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2061
|
-
|
|
2106
|
+
lastRoundText = roundText;
|
|
2107
|
+
lastRoundReasoning = roundReasoning;
|
|
2108
|
+
const assistantMessage = buildOpenAIAssistantToolMessage(roundText, calledTools, {
|
|
2109
|
+
reasoning: roundReasoning,
|
|
2110
|
+
reasoningFieldName
|
|
2111
|
+
});
|
|
2062
2112
|
const toolMessages = outputs.map((entry) => ({
|
|
2063
2113
|
role: "tool",
|
|
2064
2114
|
tool_call_id: entry.call.id,
|
|
@@ -2067,7 +2117,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2067
2117
|
messages = [...messages, assistantMessage, ...toolMessages];
|
|
2068
2118
|
}
|
|
2069
2119
|
const out = {
|
|
2070
|
-
text:
|
|
2120
|
+
text: lastRoundText,
|
|
2121
|
+
reasoning: lastRoundReasoning.length > 0 ? lastRoundReasoning : undefined,
|
|
2071
2122
|
raw: lastPayload,
|
|
2072
2123
|
usage: aggregatedUsage,
|
|
2073
2124
|
finishReason,
|
|
@@ -2089,6 +2140,7 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
|
|
|
2089
2140
|
input: buildResponsesInput(request),
|
|
2090
2141
|
previous_response_id: pickString(body?.previous_response_id),
|
|
2091
2142
|
temperature: request.temperature,
|
|
2143
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2092
2144
|
max_output_tokens: request.maxTokens,
|
|
2093
2145
|
stream: true
|
|
2094
2146
|
})),
|
|
@@ -2169,6 +2221,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2169
2221
|
input,
|
|
2170
2222
|
previous_response_id: previousResponseId,
|
|
2171
2223
|
temperature: request.temperature,
|
|
2224
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2172
2225
|
max_output_tokens: request.maxTokens,
|
|
2173
2226
|
tools: transportTools,
|
|
2174
2227
|
tool_choice: request.toolChoice,
|
|
@@ -2335,6 +2388,12 @@ function toResponsesTools(tools) {
|
|
|
2335
2388
|
return { ...tool };
|
|
2336
2389
|
});
|
|
2337
2390
|
}
|
|
2391
|
+
function toOpenAIReasoningEffort(value) {
|
|
2392
|
+
if (!value) {
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
return value === "max" ? "xhigh" : value;
|
|
2396
|
+
}
|
|
2338
2397
|
function pickChatToolCalls(payload) {
|
|
2339
2398
|
const message = pickAssistantMessage(payload);
|
|
2340
2399
|
if (!message) {
|
|
@@ -2416,20 +2475,50 @@ function pickAssistantDelta(payload) {
|
|
|
2416
2475
|
if (!isRecord2(delta)) {
|
|
2417
2476
|
return "";
|
|
2418
2477
|
}
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2478
|
+
return pickTextFromOpenAIContent(delta.content);
|
|
2479
|
+
}
|
|
2480
|
+
function pickAssistantReasoning(payload) {
|
|
2481
|
+
const message = pickAssistantMessage(payload);
|
|
2482
|
+
if (!message) {
|
|
2483
|
+
return "";
|
|
2422
2484
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
return typeof text === "string" ? text : "";
|
|
2430
|
-
}).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 "";
|
|
2431
2491
|
}
|
|
2432
|
-
|
|
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;
|
|
2433
2522
|
}
|
|
2434
2523
|
function collectOpenAIStreamToolCalls(payload, state) {
|
|
2435
2524
|
const choices = payload.choices;
|
|
@@ -2478,8 +2567,8 @@ function buildOpenAIStreamToolCalls(state) {
|
|
|
2478
2567
|
arguments: entry.argumentsText.length > 0 ? entry.argumentsText : {}
|
|
2479
2568
|
}));
|
|
2480
2569
|
}
|
|
2481
|
-
function buildOpenAIAssistantToolMessage(text, toolCalls) {
|
|
2482
|
-
|
|
2570
|
+
function buildOpenAIAssistantToolMessage(text, toolCalls, reasoning) {
|
|
2571
|
+
const message = {
|
|
2483
2572
|
role: "assistant",
|
|
2484
2573
|
content: text,
|
|
2485
2574
|
tool_calls: toolCalls.map((call) => ({
|
|
@@ -2491,6 +2580,10 @@ function buildOpenAIAssistantToolMessage(text, toolCalls) {
|
|
|
2491
2580
|
}
|
|
2492
2581
|
}))
|
|
2493
2582
|
};
|
|
2583
|
+
if (reasoning?.reasoning && reasoning.reasoning.length > 0) {
|
|
2584
|
+
message[reasoning.reasoningFieldName ?? "reasoning"] = reasoning.reasoning;
|
|
2585
|
+
}
|
|
2586
|
+
return message;
|
|
2494
2587
|
}
|
|
2495
2588
|
function pickResponsesStreamPayload(payload) {
|
|
2496
2589
|
if (isRecord2(payload.response)) {
|
|
@@ -2652,21 +2745,9 @@ function pickResponsesText(payload) {
|
|
|
2652
2745
|
function pickAssistantText(payload) {
|
|
2653
2746
|
const message = pickAssistantMessage(payload);
|
|
2654
2747
|
if (message) {
|
|
2655
|
-
const
|
|
2656
|
-
if (
|
|
2657
|
-
return
|
|
2658
|
-
}
|
|
2659
|
-
if (Array.isArray(content)) {
|
|
2660
|
-
return content.map((part) => {
|
|
2661
|
-
if (typeof part === "string") {
|
|
2662
|
-
return part;
|
|
2663
|
-
}
|
|
2664
|
-
if (!isRecord2(part)) {
|
|
2665
|
-
return "";
|
|
2666
|
-
}
|
|
2667
|
-
const text = part.text;
|
|
2668
|
-
return typeof text === "string" ? text : "";
|
|
2669
|
-
}).join("");
|
|
2748
|
+
const text = pickTextFromOpenAIContent(message.content);
|
|
2749
|
+
if (text.length > 0) {
|
|
2750
|
+
return text;
|
|
2670
2751
|
}
|
|
2671
2752
|
}
|
|
2672
2753
|
const choices = payload.choices;
|
|
@@ -2678,6 +2759,36 @@ function pickAssistantText(payload) {
|
|
|
2678
2759
|
}
|
|
2679
2760
|
return "";
|
|
2680
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
|
+
}
|
|
2681
2792
|
function pickUsage(payload) {
|
|
2682
2793
|
const usage = payload.usage;
|
|
2683
2794
|
if (!isRecord2(usage)) {
|
|
@@ -2731,14 +2842,13 @@ function createAnthropicCompatibleAdapter(options) {
|
|
|
2731
2842
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2732
2843
|
method: "POST",
|
|
2733
2844
|
headers: buildHeaders2(options),
|
|
2734
|
-
body: JSON.stringify(
|
|
2845
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2735
2846
|
...options.defaultBody,
|
|
2736
2847
|
...request.body,
|
|
2737
2848
|
model: options.model,
|
|
2738
2849
|
system: input.systemPrompt,
|
|
2739
2850
|
messages: input.messages,
|
|
2740
2851
|
temperature: request.temperature,
|
|
2741
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2742
2852
|
stream: true
|
|
2743
2853
|
})),
|
|
2744
2854
|
signal: request.signal
|
|
@@ -2794,14 +2904,13 @@ async function completePassThrough(options, fetcher, path, request) {
|
|
|
2794
2904
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2795
2905
|
method: "POST",
|
|
2796
2906
|
headers: buildHeaders2(options),
|
|
2797
|
-
body: JSON.stringify(
|
|
2907
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2798
2908
|
...options.defaultBody,
|
|
2799
2909
|
...request.body,
|
|
2800
2910
|
model: options.model,
|
|
2801
2911
|
system: input.systemPrompt,
|
|
2802
2912
|
messages: input.messages,
|
|
2803
2913
|
temperature: request.temperature,
|
|
2804
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2805
2914
|
stream: false
|
|
2806
2915
|
})),
|
|
2807
2916
|
signal: request.signal
|
|
@@ -2839,14 +2948,13 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
|
|
|
2839
2948
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2840
2949
|
method: "POST",
|
|
2841
2950
|
headers: buildHeaders2(options),
|
|
2842
|
-
body: JSON.stringify(
|
|
2951
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2843
2952
|
...options.defaultBody,
|
|
2844
2953
|
...request.body,
|
|
2845
2954
|
model: options.model,
|
|
2846
2955
|
system: input.systemPrompt,
|
|
2847
2956
|
messages,
|
|
2848
2957
|
temperature: request.temperature,
|
|
2849
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2850
2958
|
tools,
|
|
2851
2959
|
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
2852
2960
|
stream: false
|
|
@@ -2924,14 +3032,13 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
|
|
|
2924
3032
|
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
2925
3033
|
method: "POST",
|
|
2926
3034
|
headers: buildHeaders2(options),
|
|
2927
|
-
body: JSON.stringify(
|
|
3035
|
+
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
2928
3036
|
...options.defaultBody,
|
|
2929
3037
|
...request.body,
|
|
2930
3038
|
model: options.model,
|
|
2931
3039
|
system: input.systemPrompt,
|
|
2932
3040
|
messages,
|
|
2933
3041
|
temperature: request.temperature,
|
|
2934
|
-
max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
|
|
2935
3042
|
tools,
|
|
2936
3043
|
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
2937
3044
|
stream: true
|
|
@@ -3039,6 +3146,21 @@ function buildHeaders2(options) {
|
|
|
3039
3146
|
...options.headers
|
|
3040
3147
|
};
|
|
3041
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
|
+
}
|
|
3042
3164
|
function resolveAnthropicInput(request) {
|
|
3043
3165
|
if (Array.isArray(request.messages) && request.messages.length > 0) {
|
|
3044
3166
|
return toAnthropicInput(request.messages);
|
|
@@ -3393,8 +3515,34 @@ function buildProviderOptions(config) {
|
|
|
3393
3515
|
};
|
|
3394
3516
|
}
|
|
3395
3517
|
|
|
3396
|
-
// src/
|
|
3397
|
-
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
|
+
}
|
|
3398
3546
|
|
|
3399
3547
|
// src/outdent.ts
|
|
3400
3548
|
var DEFAULT_OPTIONS = {
|
|
@@ -3533,39 +3681,598 @@ function createOutdent(options = {}) {
|
|
|
3533
3681
|
return outdent;
|
|
3534
3682
|
}
|
|
3535
3683
|
|
|
3536
|
-
// src/
|
|
3537
|
-
var
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
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
|
|
3546
3717
|
};
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
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
|
+
}
|
|
3561
3803
|
}
|
|
3562
|
-
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
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;
|
|
3569
4276
|
for (const candidate of candidates) {
|
|
3570
4277
|
const parseAttempt = parseAttemptFromHint(candidate.parseHint, parseOptions.repair) ?? tryParseJsonCandidate(candidate.content, parseOptions.repair);
|
|
3571
4278
|
if (!parseAttempt.success) {
|
|
@@ -3832,48 +4539,19 @@ function formatZodIssues(issues) {
|
|
|
3832
4539
|
`);
|
|
3833
4540
|
}
|
|
3834
4541
|
|
|
3835
|
-
// src/utils/debug-colors.ts
|
|
3836
|
-
var ANSI = {
|
|
3837
|
-
reset: "\x1B[0m",
|
|
3838
|
-
bold: "\x1B[1m",
|
|
3839
|
-
cyan: "\x1B[36m",
|
|
3840
|
-
yellow: "\x1B[33m",
|
|
3841
|
-
green: "\x1B[32m",
|
|
3842
|
-
red: "\x1B[31m",
|
|
3843
|
-
dim: "\x1B[2m"
|
|
3844
|
-
};
|
|
3845
|
-
function color(config, text, tone) {
|
|
3846
|
-
if (!config.colors) {
|
|
3847
|
-
return text;
|
|
3848
|
-
}
|
|
3849
|
-
return `${ANSI[tone]}${text}${ANSI.reset}`;
|
|
3850
|
-
}
|
|
3851
|
-
function dim(config, text) {
|
|
3852
|
-
if (!config.colors) {
|
|
3853
|
-
return text;
|
|
3854
|
-
}
|
|
3855
|
-
return `${ANSI.dim}${text}${ANSI.reset}`;
|
|
3856
|
-
}
|
|
3857
|
-
function title(config, text) {
|
|
3858
|
-
if (!config.colors) {
|
|
3859
|
-
return text;
|
|
3860
|
-
}
|
|
3861
|
-
return `${ANSI.bold}${text}${ANSI.reset}`;
|
|
3862
|
-
}
|
|
3863
|
-
|
|
3864
4542
|
// src/structured.ts
|
|
3865
4543
|
class StructuredParseError extends Error {
|
|
3866
4544
|
name = "StructuredParseError";
|
|
3867
|
-
|
|
3868
|
-
|
|
4545
|
+
text;
|
|
4546
|
+
reasoning;
|
|
3869
4547
|
candidates;
|
|
3870
4548
|
zodIssues;
|
|
3871
4549
|
repairLog;
|
|
3872
4550
|
attempt;
|
|
3873
4551
|
constructor(input) {
|
|
3874
4552
|
super(input.message ?? `Structured parsing failed after ${input.attempt} attempt(s).`);
|
|
3875
|
-
this.
|
|
3876
|
-
this.
|
|
4553
|
+
this.text = input.text;
|
|
4554
|
+
this.reasoning = input.reasoning;
|
|
3877
4555
|
this.candidates = input.candidates;
|
|
3878
4556
|
this.zodIssues = input.zodIssues;
|
|
3879
4557
|
this.repairLog = input.repairLog;
|
|
@@ -3904,12 +4582,6 @@ var RE_SIMPLE_IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
|
3904
4582
|
var RE_ESCAPE_QUOTE = /"/g;
|
|
3905
4583
|
var RE_WHITESPACE2 = /\s+/g;
|
|
3906
4584
|
var DEFAULT_SELF_HEAL_MAX_DIAGNOSTICS = 8;
|
|
3907
|
-
var structuredOutdent = createOutdent({
|
|
3908
|
-
trimLeadingNewline: true,
|
|
3909
|
-
trimTrailingNewline: true,
|
|
3910
|
-
newline: `
|
|
3911
|
-
`
|
|
3912
|
-
});
|
|
3913
4585
|
var DEFAULT_STRICT_PARSE_OPTIONS = {
|
|
3914
4586
|
repair: false,
|
|
3915
4587
|
maxCandidates: 3,
|
|
@@ -4039,7 +4711,7 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
4039
4711
|
});
|
|
4040
4712
|
const selfHealSource = resolveSelfHealSource(previous);
|
|
4041
4713
|
const repairPrompt = buildSelfHealPrompt({
|
|
4042
|
-
rawOutput: previous.
|
|
4714
|
+
rawOutput: composeParseSource(previous.text, previous.reasoning),
|
|
4043
4715
|
issues: previous.zodIssues,
|
|
4044
4716
|
schema: normalized.schema,
|
|
4045
4717
|
schemaInstruction: normalized.schemaInstruction,
|
|
@@ -4112,74 +4784,6 @@ function normalizeStructuredInput(schemaOrOptions, promptInput, callOptions) {
|
|
|
4112
4784
|
function isStructuredOptions(value) {
|
|
4113
4785
|
return typeof value === "object" && value !== null && "schema" in value && "prompt" in value;
|
|
4114
4786
|
}
|
|
4115
|
-
function resolvePrompt(prompt, context) {
|
|
4116
|
-
const resolved = typeof prompt === "function" ? prompt(context) : prompt;
|
|
4117
|
-
return normalizePromptValue(resolved, context);
|
|
4118
|
-
}
|
|
4119
|
-
function normalizePromptValue(value, context) {
|
|
4120
|
-
if (typeof value === "string") {
|
|
4121
|
-
return {
|
|
4122
|
-
prompt: value
|
|
4123
|
-
};
|
|
4124
|
-
}
|
|
4125
|
-
if (isPromptResolver(value)) {
|
|
4126
|
-
return normalizePromptPayload(value.resolvePrompt(context));
|
|
4127
|
-
}
|
|
4128
|
-
return normalizePromptPayload(value);
|
|
4129
|
-
}
|
|
4130
|
-
function isPromptResolver(value) {
|
|
4131
|
-
return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
|
|
4132
|
-
}
|
|
4133
|
-
function normalizePromptPayload(value) {
|
|
4134
|
-
const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
|
|
4135
|
-
const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
|
|
4136
|
-
if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
|
|
4137
|
-
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
4138
|
-
}
|
|
4139
|
-
return {
|
|
4140
|
-
prompt,
|
|
4141
|
-
systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
|
|
4142
|
-
messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
|
|
4143
|
-
};
|
|
4144
|
-
}
|
|
4145
|
-
function applyPromptOutdent(payload, enabled) {
|
|
4146
|
-
if (!enabled) {
|
|
4147
|
-
return payload;
|
|
4148
|
-
}
|
|
4149
|
-
return {
|
|
4150
|
-
prompt: typeof payload.prompt === "string" ? structuredOutdent.string(payload.prompt) : undefined,
|
|
4151
|
-
systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
|
|
4152
|
-
messages: payload.messages?.map((message) => ({
|
|
4153
|
-
...message,
|
|
4154
|
-
content: typeof message.content === "string" ? structuredOutdent.string(message.content) : message.content
|
|
4155
|
-
}))
|
|
4156
|
-
};
|
|
4157
|
-
}
|
|
4158
|
-
function isLLMMessage(value) {
|
|
4159
|
-
if (typeof value !== "object" || value === null) {
|
|
4160
|
-
return false;
|
|
4161
|
-
}
|
|
4162
|
-
const candidate = value;
|
|
4163
|
-
if (candidate.role !== "system" && candidate.role !== "user" && candidate.role !== "assistant" && candidate.role !== "tool") {
|
|
4164
|
-
return false;
|
|
4165
|
-
}
|
|
4166
|
-
return "content" in candidate;
|
|
4167
|
-
}
|
|
4168
|
-
function applyOutdentToOptionalPrompt(value, enabled) {
|
|
4169
|
-
if (!enabled || typeof value !== "string") {
|
|
4170
|
-
return value;
|
|
4171
|
-
}
|
|
4172
|
-
return structuredOutdent.string(value);
|
|
4173
|
-
}
|
|
4174
|
-
function mergeSystemPrompts(primary, secondary) {
|
|
4175
|
-
const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
|
|
4176
|
-
if (prompts.length === 0) {
|
|
4177
|
-
return;
|
|
4178
|
-
}
|
|
4179
|
-
return prompts.join(`
|
|
4180
|
-
|
|
4181
|
-
`);
|
|
4182
|
-
}
|
|
4183
4787
|
function prepareStructuredPromptPayload(payload, systemPrompt, schema, schemaInstruction) {
|
|
4184
4788
|
if (Array.isArray(payload.messages) && payload.messages.length > 0) {
|
|
4185
4789
|
const messages = payload.messages.map((message) => ({ ...message }));
|
|
@@ -4360,70 +4964,32 @@ function resolveSelfHealSource(attempt) {
|
|
|
4360
4964
|
}
|
|
4361
4965
|
return {
|
|
4362
4966
|
kind: "raw",
|
|
4363
|
-
text: attempt.
|
|
4364
|
-
};
|
|
4365
|
-
}
|
|
4366
|
-
function isSelfHealStalled(previous, current) {
|
|
4367
|
-
if (current.success) {
|
|
4368
|
-
return false;
|
|
4369
|
-
}
|
|
4370
|
-
if (current.zodIssues.length < previous.zodIssues.length) {
|
|
4371
|
-
return false;
|
|
4372
|
-
}
|
|
4373
|
-
if (current.parsed.errors.length < previous.parsed.errors.length) {
|
|
4374
|
-
return false;
|
|
4375
|
-
}
|
|
4376
|
-
return buildSelfHealFailureFingerprint(previous) === buildSelfHealFailureFingerprint(current);
|
|
4377
|
-
}
|
|
4378
|
-
function buildSelfHealFailureFingerprint(attempt) {
|
|
4379
|
-
const issues = attempt.zodIssues.map((issue) => `${formatIssuePath(issue.path)}:${issue.code}:${normalizeWhitespace(issue.message)}`).sort().join("|");
|
|
4380
|
-
const errors = attempt.parsed.errors.map((error) => `${error.stage}:${error.candidateId ?? "-"}:${normalizeWhitespace(error.message)}`).sort().join("|");
|
|
4381
|
-
const source = normalizeWhitespace(resolveSelfHealSource(attempt).text).slice(0, 512);
|
|
4382
|
-
return [issues, errors, source].join("::");
|
|
4383
|
-
}
|
|
4384
|
-
function normalizeWhitespace(value) {
|
|
4385
|
-
return value.replace(RE_WHITESPACE2, " ").trim();
|
|
4386
|
-
}
|
|
4387
|
-
function normalizeStreamConfig(option) {
|
|
4388
|
-
if (typeof option === "boolean") {
|
|
4389
|
-
return {
|
|
4390
|
-
enabled: option
|
|
4391
|
-
};
|
|
4392
|
-
}
|
|
4393
|
-
if (!option) {
|
|
4394
|
-
return {
|
|
4395
|
-
enabled: false
|
|
4396
|
-
};
|
|
4397
|
-
}
|
|
4398
|
-
return {
|
|
4399
|
-
enabled: option.enabled ?? true,
|
|
4400
|
-
onData: option.onData,
|
|
4401
|
-
to: option.to
|
|
4402
|
-
};
|
|
4403
|
-
}
|
|
4404
|
-
function normalizeDebugConfig(option) {
|
|
4405
|
-
if (typeof option === "boolean") {
|
|
4406
|
-
return {
|
|
4407
|
-
enabled: option,
|
|
4408
|
-
colors: true,
|
|
4409
|
-
logger: (line) => console.log(line)
|
|
4410
|
-
};
|
|
4411
|
-
}
|
|
4412
|
-
if (!option) {
|
|
4413
|
-
return {
|
|
4414
|
-
enabled: false,
|
|
4415
|
-
colors: true,
|
|
4416
|
-
logger: (line) => console.log(line)
|
|
4417
|
-
};
|
|
4418
|
-
}
|
|
4419
|
-
return {
|
|
4420
|
-
enabled: option.enabled ?? true,
|
|
4421
|
-
colors: option.colors ?? true,
|
|
4422
|
-
logger: option.logger ?? ((line) => console.log(line))
|
|
4967
|
+
text: composeParseSource(attempt.text, attempt.reasoning)
|
|
4423
4968
|
};
|
|
4424
4969
|
}
|
|
4970
|
+
function isSelfHealStalled(previous, current) {
|
|
4971
|
+
if (current.success) {
|
|
4972
|
+
return false;
|
|
4973
|
+
}
|
|
4974
|
+
if (current.zodIssues.length < previous.zodIssues.length) {
|
|
4975
|
+
return false;
|
|
4976
|
+
}
|
|
4977
|
+
if (current.parsed.errors.length < previous.parsed.errors.length) {
|
|
4978
|
+
return false;
|
|
4979
|
+
}
|
|
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();
|
|
4990
|
+
}
|
|
4425
4991
|
async function executeAttempt(adapter, input) {
|
|
4426
|
-
const response = await
|
|
4992
|
+
const response = await callModel2(adapter, {
|
|
4427
4993
|
prompt: input.prompt,
|
|
4428
4994
|
messages: input.messages,
|
|
4429
4995
|
systemPrompt: input.systemPrompt,
|
|
@@ -4436,7 +5002,7 @@ async function executeAttempt(adapter, input) {
|
|
|
4436
5002
|
selfHealEnabled: input.selfHealEnabled,
|
|
4437
5003
|
timeout: input.timeout
|
|
4438
5004
|
});
|
|
4439
|
-
const parsed = parseWithObserve(response.
|
|
5005
|
+
const parsed = parseWithObserve(response.parseSource, input.schema, input.parseOptions, {
|
|
4440
5006
|
observe: input.observe,
|
|
4441
5007
|
attempt: input.attemptNumber,
|
|
4442
5008
|
selfHeal: input.selfHeal
|
|
@@ -4445,8 +5011,8 @@ async function executeAttempt(adapter, input) {
|
|
|
4445
5011
|
attempt: input.attemptNumber,
|
|
4446
5012
|
selfHeal: input.selfHeal,
|
|
4447
5013
|
via: response.via,
|
|
4448
|
-
|
|
4449
|
-
|
|
5014
|
+
text: response.text,
|
|
5015
|
+
reasoning: response.reasoning,
|
|
4450
5016
|
json: parsed.parsed,
|
|
4451
5017
|
candidates: parsed.candidates.map((candidate) => candidate.content),
|
|
4452
5018
|
repairLog: collectRepairLog(parsed),
|
|
@@ -4461,195 +5027,26 @@ async function executeAttempt(adapter, input) {
|
|
|
4461
5027
|
trace
|
|
4462
5028
|
};
|
|
4463
5029
|
}
|
|
4464
|
-
function
|
|
4465
|
-
return {
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
async callTool(params) {
|
|
4470
|
-
let timeoutId;
|
|
4471
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
4472
|
-
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
4473
|
-
});
|
|
4474
|
-
try {
|
|
4475
|
-
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
4476
|
-
} finally {
|
|
4477
|
-
clearTimeout(timeoutId);
|
|
4478
|
-
}
|
|
4479
|
-
}
|
|
4480
|
-
};
|
|
4481
|
-
}
|
|
4482
|
-
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
4483
|
-
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
4484
|
-
}
|
|
4485
|
-
async function callModel(adapter, options) {
|
|
4486
|
-
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
4487
|
-
const requestPayload = {
|
|
4488
|
-
prompt: options.prompt,
|
|
4489
|
-
messages: options.messages,
|
|
4490
|
-
systemPrompt: options.systemPrompt,
|
|
4491
|
-
temperature: options.request?.temperature,
|
|
4492
|
-
maxTokens: options.request?.maxTokens,
|
|
4493
|
-
mcpClients: options.request?.mcpClients,
|
|
4494
|
-
toolChoice: options.request?.toolChoice,
|
|
4495
|
-
parallelToolCalls: options.request?.parallelToolCalls,
|
|
4496
|
-
maxToolRounds: options.request?.maxToolRounds,
|
|
4497
|
-
onToolExecution: options.request?.onToolExecution,
|
|
4498
|
-
toolDebug: options.request?.toolDebug,
|
|
4499
|
-
body: options.request?.body,
|
|
4500
|
-
signal: requestSignal
|
|
4501
|
-
};
|
|
4502
|
-
emitDebugRequest(options.debug, {
|
|
4503
|
-
provider: adapter.provider,
|
|
4504
|
-
model: adapter.model,
|
|
4505
|
-
attempt: options.attempt,
|
|
4506
|
-
selfHealAttempt: options.selfHeal,
|
|
4507
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4508
|
-
stream: options.stream.enabled && !!adapter.stream,
|
|
4509
|
-
requestPayload
|
|
4510
|
-
});
|
|
4511
|
-
emitObserve(options.observe, {
|
|
4512
|
-
stage: "llm.request",
|
|
4513
|
-
attempt: options.attempt,
|
|
4514
|
-
selfHeal: options.selfHeal,
|
|
4515
|
-
message: "Sending LLM request.",
|
|
4516
|
-
details: {
|
|
4517
|
-
provider: adapter.provider,
|
|
4518
|
-
model: adapter.model,
|
|
4519
|
-
stream: options.stream.enabled && !!adapter.stream
|
|
4520
|
-
}
|
|
4521
|
-
});
|
|
4522
|
-
if (options.stream.enabled && adapter.stream) {
|
|
4523
|
-
let latestUsage;
|
|
4524
|
-
let latestFinishReason;
|
|
4525
|
-
let streamedRaw = "";
|
|
4526
|
-
let sawToken = false;
|
|
4527
|
-
let lastDataFingerprint;
|
|
4528
|
-
const emitStreamingData = (raw, done, usage2, finishReason2) => {
|
|
4529
|
-
const data = parseStreamingStructuredData(raw);
|
|
4530
|
-
if (data === null && !done) {
|
|
4531
|
-
return;
|
|
4532
|
-
}
|
|
4533
|
-
const fingerprint = toStreamDataFingerprint(data ?? null);
|
|
4534
|
-
if (!done && fingerprint === lastDataFingerprint) {
|
|
4535
|
-
return;
|
|
4536
|
-
}
|
|
4537
|
-
lastDataFingerprint = fingerprint;
|
|
4538
|
-
options.stream.onData?.({
|
|
4539
|
-
data: data ?? null,
|
|
4540
|
-
raw,
|
|
4541
|
-
done,
|
|
4542
|
-
usage: usage2,
|
|
4543
|
-
finishReason: finishReason2
|
|
4544
|
-
});
|
|
4545
|
-
emitObserve(options.observe, {
|
|
4546
|
-
stage: "llm.stream.data",
|
|
4547
|
-
attempt: options.attempt,
|
|
4548
|
-
selfHeal: options.selfHeal,
|
|
4549
|
-
message: done ? "Streaming structured data completed." : "Streaming structured data updated.",
|
|
4550
|
-
details: {
|
|
4551
|
-
done,
|
|
4552
|
-
finishReason: finishReason2
|
|
4553
|
-
}
|
|
4554
|
-
});
|
|
4555
|
-
};
|
|
4556
|
-
const handleTextDelta = (delta) => {
|
|
4557
|
-
if (!delta) {
|
|
4558
|
-
return;
|
|
4559
|
-
}
|
|
4560
|
-
streamedRaw += delta;
|
|
4561
|
-
if (options.stream.to === "stdout") {
|
|
4562
|
-
process.stdout.write(delta);
|
|
4563
|
-
}
|
|
4564
|
-
emitObserve(options.observe, {
|
|
4565
|
-
stage: "llm.stream.delta",
|
|
4566
|
-
attempt: options.attempt,
|
|
4567
|
-
selfHeal: options.selfHeal,
|
|
4568
|
-
message: "Received stream delta.",
|
|
4569
|
-
details: {
|
|
4570
|
-
chars: delta.length
|
|
4571
|
-
}
|
|
4572
|
-
});
|
|
4573
|
-
emitStreamingData(streamedRaw, false);
|
|
4574
|
-
};
|
|
4575
|
-
const response2 = await adapter.stream(requestPayload, {
|
|
4576
|
-
onToken: (token) => {
|
|
4577
|
-
sawToken = true;
|
|
4578
|
-
handleTextDelta(token);
|
|
4579
|
-
},
|
|
4580
|
-
onChunk: (chunk) => {
|
|
4581
|
-
if (!sawToken && chunk.textDelta) {
|
|
4582
|
-
handleTextDelta(chunk.textDelta);
|
|
4583
|
-
}
|
|
4584
|
-
if (chunk.usage) {
|
|
4585
|
-
latestUsage = preferLatestUsage(latestUsage, chunk.usage);
|
|
4586
|
-
}
|
|
4587
|
-
if (chunk.finishReason) {
|
|
4588
|
-
latestFinishReason = chunk.finishReason;
|
|
4589
|
-
}
|
|
4590
|
-
}
|
|
4591
|
-
});
|
|
4592
|
-
const finalText = typeof response2.text === "string" && response2.text.length > 0 ? response2.text : streamedRaw;
|
|
4593
|
-
const usage = preferLatestUsage(latestUsage, response2.usage);
|
|
4594
|
-
const finishReason = response2.finishReason ?? latestFinishReason;
|
|
4595
|
-
emitStreamingData(finalText, true, usage, finishReason);
|
|
4596
|
-
emitObserve(options.observe, {
|
|
4597
|
-
stage: "llm.response",
|
|
5030
|
+
async function callModel2(adapter, options) {
|
|
5031
|
+
return callModel(adapter, {
|
|
5032
|
+
...options,
|
|
5033
|
+
buildEvent: ({ stage, message, details }) => ({
|
|
5034
|
+
stage,
|
|
4598
5035
|
attempt: options.attempt,
|
|
4599
5036
|
selfHeal: options.selfHeal,
|
|
4600
|
-
message
|
|
4601
|
-
details
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
selfHealAttempt: options.selfHeal,
|
|
4610
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4611
|
-
via: "stream",
|
|
4612
|
-
responseText: finalText,
|
|
4613
|
-
usage,
|
|
4614
|
-
finishReason
|
|
4615
|
-
});
|
|
4616
|
-
return {
|
|
4617
|
-
text: finalText,
|
|
4618
|
-
via: "stream",
|
|
4619
|
-
usage,
|
|
4620
|
-
finishReason
|
|
4621
|
-
};
|
|
4622
|
-
}
|
|
4623
|
-
const response = await adapter.complete(requestPayload);
|
|
4624
|
-
emitObserve(options.observe, {
|
|
4625
|
-
stage: "llm.response",
|
|
4626
|
-
attempt: options.attempt,
|
|
4627
|
-
selfHeal: options.selfHeal,
|
|
4628
|
-
message: "Completion response received.",
|
|
4629
|
-
details: {
|
|
4630
|
-
via: "complete",
|
|
4631
|
-
chars: response.text.length,
|
|
4632
|
-
finishReason: response.finishReason
|
|
4633
|
-
}
|
|
4634
|
-
});
|
|
4635
|
-
emitDebugResponse(options.debug, {
|
|
4636
|
-
attempt: options.attempt,
|
|
4637
|
-
selfHealAttempt: options.selfHeal,
|
|
4638
|
-
selfHealEnabled: options.selfHealEnabled,
|
|
4639
|
-
via: "complete",
|
|
4640
|
-
responseText: response.text,
|
|
4641
|
-
usage: response.usage,
|
|
4642
|
-
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"
|
|
4643
5046
|
});
|
|
4644
|
-
return {
|
|
4645
|
-
text: response.text,
|
|
4646
|
-
via: "complete",
|
|
4647
|
-
usage: response.usage,
|
|
4648
|
-
finishReason: response.finishReason
|
|
4649
|
-
};
|
|
4650
5047
|
}
|
|
4651
|
-
function parseStreamingStructuredData(
|
|
4652
|
-
const sanitized = sanitizeThink(
|
|
5048
|
+
function parseStreamingStructuredData(parseSource) {
|
|
5049
|
+
const sanitized = sanitizeThink(parseSource);
|
|
4653
5050
|
const start = findFirstJsonRootStart(sanitized.visibleText);
|
|
4654
5051
|
if (start < 0) {
|
|
4655
5052
|
return null;
|
|
@@ -4709,13 +5106,6 @@ function findFirstJsonRootStart(input) {
|
|
|
4709
5106
|
}
|
|
4710
5107
|
return Math.min(objectStart, arrayStart);
|
|
4711
5108
|
}
|
|
4712
|
-
function toStreamDataFingerprint(value) {
|
|
4713
|
-
try {
|
|
4714
|
-
return JSON.stringify(value);
|
|
4715
|
-
} catch {
|
|
4716
|
-
return "__unserializable__";
|
|
4717
|
-
}
|
|
4718
|
-
}
|
|
4719
5109
|
function parseWithObserve(output, schema, parseOptions, context) {
|
|
4720
5110
|
const userParseTrace = parseOptions.onTrace;
|
|
4721
5111
|
return parseLLMOutput(output, schema, {
|
|
@@ -4745,38 +5135,20 @@ function buildSuccessResult(data, attempts) {
|
|
|
4745
5135
|
const final = attempts.at(-1);
|
|
4746
5136
|
return {
|
|
4747
5137
|
data,
|
|
4748
|
-
|
|
4749
|
-
|
|
5138
|
+
text: final?.text ?? "",
|
|
5139
|
+
reasoning: final?.reasoning ?? "",
|
|
4750
5140
|
json: final?.json ?? null,
|
|
4751
5141
|
attempts,
|
|
4752
5142
|
usage: aggregateUsage(attempts),
|
|
4753
5143
|
finishReason: final?.finishReason
|
|
4754
5144
|
};
|
|
4755
5145
|
}
|
|
4756
|
-
function aggregateUsage(attempts) {
|
|
4757
|
-
let usage;
|
|
4758
|
-
for (const attempt of attempts) {
|
|
4759
|
-
usage = mergeUsage2(usage, attempt.usage);
|
|
4760
|
-
}
|
|
4761
|
-
return usage;
|
|
4762
|
-
}
|
|
4763
|
-
function mergeUsage2(base, next) {
|
|
4764
|
-
if (!base && !next) {
|
|
4765
|
-
return;
|
|
4766
|
-
}
|
|
4767
|
-
return {
|
|
4768
|
-
inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
|
|
4769
|
-
outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
|
|
4770
|
-
totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
|
|
4771
|
-
cost: (base?.cost ?? 0) + (next?.cost ?? 0)
|
|
4772
|
-
};
|
|
4773
|
-
}
|
|
4774
5146
|
function toStructuredError(attempt) {
|
|
4775
5147
|
if (!attempt) {
|
|
4776
5148
|
return new StructuredParseError({
|
|
4777
5149
|
message: "Structured parsing failed before any model response.",
|
|
4778
|
-
|
|
4779
|
-
|
|
5150
|
+
text: "",
|
|
5151
|
+
reasoning: "",
|
|
4780
5152
|
candidates: [],
|
|
4781
5153
|
zodIssues: [],
|
|
4782
5154
|
repairLog: [],
|
|
@@ -4784,8 +5156,8 @@ function toStructuredError(attempt) {
|
|
|
4784
5156
|
});
|
|
4785
5157
|
}
|
|
4786
5158
|
return new StructuredParseError({
|
|
4787
|
-
|
|
4788
|
-
|
|
5159
|
+
text: attempt.text,
|
|
5160
|
+
reasoning: attempt.reasoning,
|
|
4789
5161
|
candidates: attempt.candidates,
|
|
4790
5162
|
zodIssues: attempt.zodIssues,
|
|
4791
5163
|
repairLog: attempt.repairLog,
|
|
@@ -4795,59 +5167,6 @@ function toStructuredError(attempt) {
|
|
|
4795
5167
|
function emitObserve(observe, event) {
|
|
4796
5168
|
observe?.(event);
|
|
4797
5169
|
}
|
|
4798
|
-
function emitDebugRequest(config, input) {
|
|
4799
|
-
const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
|
|
4800
|
-
const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
|
|
4801
|
-
const lines = [
|
|
4802
|
-
color(config, title(config, [
|
|
4803
|
-
"[structured][request]",
|
|
4804
|
-
`attempt=${input.attempt}`,
|
|
4805
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4806
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4807
|
-
].join(" ")), "cyan"),
|
|
4808
|
-
dim(config, [
|
|
4809
|
-
`provider=${input.provider ?? "unknown"}`,
|
|
4810
|
-
`model=${input.model ?? "unknown"}`,
|
|
4811
|
-
`stream=${input.stream}`
|
|
4812
|
-
].join(" ")),
|
|
4813
|
-
color(config, "prompt:", "yellow"),
|
|
4814
|
-
input.requestPayload.prompt ?? "(none)",
|
|
4815
|
-
color(config, "messages:", "yellow"),
|
|
4816
|
-
requestMessages,
|
|
4817
|
-
color(config, "systemPrompt:", "yellow"),
|
|
4818
|
-
input.requestPayload.systemPrompt ?? "(none)",
|
|
4819
|
-
color(config, "request.body:", "yellow"),
|
|
4820
|
-
requestBody
|
|
4821
|
-
];
|
|
4822
|
-
emitDebug(config, lines.join(`
|
|
4823
|
-
`));
|
|
4824
|
-
}
|
|
4825
|
-
function emitDebugResponse(config, input) {
|
|
4826
|
-
const lines = [
|
|
4827
|
-
color(config, title(config, [
|
|
4828
|
-
"[structured][response]",
|
|
4829
|
-
`attempt=${input.attempt}`,
|
|
4830
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4831
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4832
|
-
].join(" ")), "green"),
|
|
4833
|
-
dim(config, [
|
|
4834
|
-
`via=${input.via}`,
|
|
4835
|
-
`chars=${input.responseText.length}`,
|
|
4836
|
-
`finishReason=${input.finishReason ?? "unknown"}`,
|
|
4837
|
-
`usage=${JSON.stringify(input.usage ?? {})}`
|
|
4838
|
-
].join(" ")),
|
|
4839
|
-
color(config, "text:", "yellow"),
|
|
4840
|
-
input.responseText
|
|
4841
|
-
];
|
|
4842
|
-
emitDebug(config, lines.join(`
|
|
4843
|
-
`));
|
|
4844
|
-
}
|
|
4845
|
-
function emitDebug(config, message) {
|
|
4846
|
-
if (!config.enabled) {
|
|
4847
|
-
return;
|
|
4848
|
-
}
|
|
4849
|
-
config.logger(message);
|
|
4850
|
-
}
|
|
4851
5170
|
|
|
4852
5171
|
// src/llm.ts
|
|
4853
5172
|
function createLLM(config, registry = createDefaultProviderRegistry()) {
|
|
@@ -4861,6 +5180,17 @@ function createLLM(config, registry = createDefaultProviderRegistry()) {
|
|
|
4861
5180
|
const merged = mergeStructuredOptions(defaults, options);
|
|
4862
5181
|
return structured(adapter, schema, prompt, merged);
|
|
4863
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
|
+
},
|
|
4864
5194
|
async embed(input, options = {}) {
|
|
4865
5195
|
if (!adapter.embed) {
|
|
4866
5196
|
throw new Error(`Provider "${adapter.provider ?? "unknown"}" does not support embeddings.`);
|
|
@@ -4890,6 +5220,26 @@ function mergeStructuredOptions(defaults, overrides) {
|
|
|
4890
5220
|
timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
|
|
4891
5221
|
};
|
|
4892
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
|
+
}
|
|
4893
5243
|
function mergeObjectLike(defaults, overrides) {
|
|
4894
5244
|
if (overrides === undefined) {
|
|
4895
5245
|
return defaults;
|