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