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