@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.4
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.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/abort-D1_Z5Ut5.mjs +51 -0
- package/lib/abort-dIkZBV7Q.mjs +51 -0
- package/lib/amazon-bedrock-B0nxT06F.mjs +917 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/amazon-bedrock-WQhvjHYu.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CJCauvYz.mjs +3115 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/anthropic-CZghe_9U.mjs +3115 -0
- package/lib/anthropic-sCMH7JID.mjs +262 -0
- package/lib/anthropic-tTntD8BD.mjs +262 -0
- package/lib/api-key-login-BzqNdM2y.mjs +157 -0
- package/lib/api-key-login-CWVwvHT1.mjs +157 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/aws-credentials-CXryMobh.mjs +867 -0
- package/lib/aws-credentials-ChG79ey-.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/azure-openai-responses-Cgmc-rbL.mjs +274 -0
- package/lib/azure-openai-responses-DuukbD0F.mjs +274 -0
- package/lib/bun-shim.mjs +252 -12
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/bundled-references-Cavaffah.mjs +55 -0
- package/lib/bundled-references-sLN0YdXU.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/callback-server-CQ5Jo8F-.mjs +398 -0
- package/lib/callback-server-DDSrZ6l_.mjs +398 -0
- package/lib/client.js +111 -41
- package/lib/cursor-B3zg7EHj.mjs +273 -0
- package/lib/cursor-B6TUEmgP.mjs +135 -0
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-D8gvtTL3.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-DkSX2h3H.mjs +5441 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/cursor-aJrXeYCb.mjs +273 -0
- package/lib/cursor-mJQwUKXK.mjs +5441 -0
- package/lib/device-code-DBo3B5nh.mjs +51 -0
- package/lib/device-code-DIb0FU-H.mjs +51 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-BHZZyMhO.mjs +95 -0
- package/lib/devin-BK7DHeca.mjs +114 -0
- package/lib/devin-CfMp3cXS.mjs +95 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-D9zR5B_R.mjs +542 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/devin-Q1yem3lp.mjs +114 -0
- package/lib/devin-vNZTNUON.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/error-Dd8DIqs-.mjs +1449 -0
- package/lib/error-yCSG0mGC.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/event-stream-BbFZJy-z.mjs +151 -0
- package/lib/event-stream-loUa0s1T.mjs +151 -0
- package/lib/fs-promises-shim-Bx0fpxuk.mjs +57 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B1yiyVRh.mjs +104 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/github-copilot-BWT3eAOF.mjs +208 -0
- package/lib/github-copilot-CYkjeTi3.mjs +208 -0
- package/lib/github-copilot-jscUZ8Hf.mjs +104 -0
- package/lib/gitlab-duo-CM7Ref1H.mjs +155 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-gubO4FNw.mjs +155 -0
- package/lib/gitlab-duo-workflow-BGAF6JDw.mjs +91 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/gitlab-duo-workflow-D78tdn8E.mjs +91 -0
- package/lib/google-BS4T25Pn.mjs +30 -0
- package/lib/google-TFe-7-of.mjs +30 -0
- package/lib/google-antigravity-DGmwC2KV.mjs +198 -0
- package/lib/google-antigravity-DNYhgTpA.mjs +198 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-B6gjsZvg.mjs +232 -0
- package/lib/google-auth-De7_s3eo.mjs +232 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-CWu8HvXW.mjs +211 -0
- package/lib/google-gemini-cli-Cb97bzQc.mjs +850 -0
- package/lib/google-gemini-cli-Cqds_Q5T.mjs +850 -0
- package/lib/google-gemini-cli-Dsztq0N5.mjs +211 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CuEHaDDj.mjs +147 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-oauth-shared-yqlyqPPC.mjs +147 -0
- package/lib/google-shared-CgKmmdO3.mjs +760 -0
- package/lib/google-shared-Dr-VG-ap.mjs +760 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-BDN2tLaD.mjs +99 -0
- package/lib/google-vertex-DopVOQOG.mjs +99 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-Da1GPU9a.mjs +219 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/identity-xRP7_eSR.mjs +219 -0
- package/lib/idle-iterator-Baoyn3Hp.mjs +366 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/idle-iterator-DUjKQEGT.mjs +366 -0
- package/lib/index.mjs +4608 -3935
- package/lib/kimi--wUOWER5.mjs +236 -0
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/kimi-Dh0pv3WZ.mjs +236 -0
- package/lib/markit-BL3cH47U.mjs +1417 -0
- package/lib/markit-BNiNY6SE.mjs +1417 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/minimax-code-DCbuA6Yk.mjs +53 -0
- package/lib/minimax-code-Uq8Qu9LW.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/models-D_XnT6ay.mjs +104660 -0
- package/lib/models-SGASygJ3.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/ollama-DPzBmq89.mjs +589 -0
- package/lib/ollama-DoBz5SFm.mjs +589 -0
- package/lib/openai-codex-Bi-4S4PX.mjs +255 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-Ch8CkT3p.mjs +255 -0
- package/lib/openai-codex-responses-CvxL_FMF.mjs +3144 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-codex-responses-pejZgdZo.mjs +3144 -0
- package/lib/openai-completions-CF8IyNtP.mjs +1360 -0
- package/lib/openai-completions-DIf361kF.mjs +1360 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-reasoning-fallback-Nj6yB2rY.mjs +286 -0
- package/lib/openai-reasoning-fallback-OdJREP1o.mjs +286 -0
- package/lib/openai-responses-BqXJInHX.mjs +867 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/openai-responses-Db_a-U4-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/opencode-DhMolSoB.mjs +38 -0
- package/lib/opencode-Rq_Q2vAO.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/perplexity-C4iLVMUj.mjs +194 -0
- package/lib/perplexity-Uu7Jzg5b.mjs +194 -0
- package/lib/proxy-DDqrmjjC.mjs +190 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/proxy-pM_NIv-H.mjs +190 -0
- package/lib/request-debug-HJMoJncL.mjs +183 -0
- package/lib/sanitize-text-CfcXzw5X.mjs +33 -0
- package/lib/scrapers-BkFfcPHj.mjs +9198 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CVptboMs.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/scrapers-nhQAvc8d.mjs +9198 -0
- package/lib/shell-snapshot-fn-env.sh +67 -43
- package/lib/src-BgpusnsB.mjs +5076 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/src-lDmkSRbm.mjs +5006 -0
- package/lib/stream-BlldLkVq.mjs +10236 -0
- package/lib/stream-CRtexYLe.mjs +10236 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/stream-markup-healing-DMsxBx1L.mjs +491 -0
- package/lib/stream-markup-healing-KMkiAA00.mjs +491 -0
- package/lib/turndown-DN7ByzEI.mjs +667 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +25 -3
- package/lib/types/config/truncate.d.ts +9 -5
- package/lib/types/tools/bash/background.d.ts +1 -1
- package/lib/types/tools/bash/bash-executor.d.ts +4 -0
- package/lib/types/tools/bash/bash-interceptor.d.ts +10 -8
- package/lib/types/tools/bash/cd-workdir.d.ts +35 -0
- package/lib/types/tools/bash/non-interactive-env.d.ts +2 -0
- package/lib/types/tools/bash/render.d.ts +4 -3
- package/lib/types/tools/bash/sanitize-text.d.ts +5 -0
- package/lib/types/tools/bash/shell-snapshot.d.ts +4 -1
- package/lib/types/tools/bash/shell-tokenize.d.ts +60 -0
- package/lib/types/tools/bash/streaming-output.d.ts +12 -212
- package/lib/types/tools/bash/which.d.ts +20 -0
- package/lib/types/tools/bash/windows-shell.d.ts +31 -0
- package/lib/types/tools/edit/adapter/index.d.ts +25 -3
- package/lib/types/tools/edit/adapter/tools/auto-generated-guard.d.ts +7 -17
- package/lib/types/tools/glob/adapter/index.d.ts +27 -1
- package/lib/types/tools/grep/adapter/index.d.ts +29 -1
- package/lib/types/tools/omp/edit/dispatch.d.ts +43 -0
- package/lib/types/tools/omp/edit/hashline/noop-loop-guard.d.ts +3 -1
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/auto-generated-guard.d.ts +20 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/tools/write.d.ts +4 -4
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/auto-generated-guard.dsh.d.ts +16 -4
- package/lib/types/tools/shared/bun-shim.d.ts +39 -3
- package/lib/types/tools/shared/fs-promises-shim.d.ts +3 -1
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +17 -9
- package/lib/types/tools/shared/session-state.d.ts +9 -3
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-Bw139LTz.mjs +8119 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-CZw4tVZQ.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-CiGN7OHR.mjs +12315 -0
- package/lib/utils-Cp76gCyk.mjs +8119 -0
- package/lib/utils-D0GRDgAr.mjs +12315 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-D2YknRk4.mjs +51 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-DzXZDfYc.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-01qSwFpf.mjs +92 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/vision-guard-DzZGaOga.mjs +92 -0
- package/lib/wafer-CgtPHerf.mjs +17 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/wafer-cBtrn6q9.mjs +17 -0
- package/lib/xai-oauth-Buk8XVvM.mjs +446 -0
- package/lib/xai-oauth-CMal8l1O.mjs +446 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-CZgwvX2G.mjs +157 -0
- package/lib/xiaomi-D2qT5cAC.mjs +157 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-7DWMkEqM.mjs +203 -0
- package/lib/zai-C59YnomG.mjs +203 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-Cg9ANN_U.mjs +1316 -0
- package/lib/zip-D36ZKsP8.mjs +1316 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { r as __exportAll } from "./fs-promises-shim-B-9cMxz5.mjs";
|
|
4
|
+
import { g as parseStreamingJson, i as readJsonl } from "./src-lDmkSRbm.mjs";
|
|
5
|
+
import { G as fetchWithRetry, b as LLAMA_CPP_TOOL_CALL_PARSE_PATTERN, g as MissingApiKeyError, l as finalize, z as OllamaApiError } from "./error-yCSG0mGC.mjs";
|
|
6
|
+
import { C as kStreamingPartialJson, I as sanitizeSchemaForOllama, a as normalizeSystemPrompts, h as clearStreamingPartialJson, k as toolWireSchema, m as transformMessages } from "./utils-Bw139LTz.mjs";
|
|
7
|
+
import { Ct as withEmptyCompletionRetry, n as getEnvApiKey } from "./stream-BlldLkVq.mjs";
|
|
8
|
+
import { i as partitionVisionContent, r as joinTextWithImagePlaceholder } from "./vision-guard-DzZGaOga.mjs";
|
|
9
|
+
import { t as AssistantMessageEventStream } from "./event-stream-loUa0s1T.mjs";
|
|
10
|
+
import { n as getOpenAIStreamFirstEventTimeoutMs, r as getOpenAIStreamIdleTimeoutMs, t as armPreResponseTimeout } from "./idle-iterator-Baoyn3Hp.mjs";
|
|
11
|
+
import { n as getStreamMarkupHealingPattern, t as StreamMarkupHealing } from "./stream-markup-healing-DMsxBx1L.mjs";
|
|
12
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/ollama.ts
|
|
13
|
+
var ollama_exports = /* @__PURE__ */ __exportAll({ streamOllama: () => streamOllama });
|
|
14
|
+
function normalizeBaseUrl(baseUrl) {
|
|
15
|
+
const value = baseUrl?.trim();
|
|
16
|
+
if (!value) return "https://ollama.com";
|
|
17
|
+
const trimmed = value.endsWith("/") ? value.slice(0, -1) : value;
|
|
18
|
+
return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed;
|
|
19
|
+
}
|
|
20
|
+
function mapReasoning(model, reasoning, disableReasoning) {
|
|
21
|
+
const modelReasoning = model.reasoning;
|
|
22
|
+
if (disableReasoning && modelReasoning) return false;
|
|
23
|
+
switch (model.provider === "ollama-cloud" && reasoning ? model.thinking?.effortMap?.[reasoning] ?? reasoning : reasoning) {
|
|
24
|
+
case "minimal":
|
|
25
|
+
case "low": return "low";
|
|
26
|
+
case "medium": return "medium";
|
|
27
|
+
case "high": return "high";
|
|
28
|
+
case "max": return "max";
|
|
29
|
+
case "xhigh": return "high";
|
|
30
|
+
default: return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function mapToolChoice(toolChoice) {
|
|
34
|
+
if (!toolChoice || toolChoice === "auto") return;
|
|
35
|
+
if (toolChoice === "none") return "none";
|
|
36
|
+
if (toolChoice === "required" || toolChoice === "any") return "required";
|
|
37
|
+
if (typeof toolChoice === "object" && toolChoice.type === "computer") return void 0;
|
|
38
|
+
if (typeof toolChoice === "object") return "required";
|
|
39
|
+
}
|
|
40
|
+
function getNamedToolChoiceName(toolChoice) {
|
|
41
|
+
if (!toolChoice || typeof toolChoice === "string") return;
|
|
42
|
+
if (toolChoice.type === "computer") return void 0;
|
|
43
|
+
if ("function" in toolChoice) return toolChoice.function.name;
|
|
44
|
+
return toolChoice.name;
|
|
45
|
+
}
|
|
46
|
+
function selectToolsForToolChoice(tools, toolChoice) {
|
|
47
|
+
const toolName = getNamedToolChoiceName(toolChoice);
|
|
48
|
+
if (!toolName || !tools) return tools;
|
|
49
|
+
for (const tool of tools) if (tool.name === toolName) return [tool];
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
function toPlainContent(content, supportsImages) {
|
|
53
|
+
if (typeof content === "string") return { content };
|
|
54
|
+
const { textBlocks, imageBlocks, omittedImages } = partitionVisionContent(content, supportsImages);
|
|
55
|
+
const text = textBlocks.map((block) => block.text).join("\n");
|
|
56
|
+
return {
|
|
57
|
+
content: joinTextWithImagePlaceholder(text, omittedImages),
|
|
58
|
+
...imageBlocks.length > 0 ? { images: imageBlocks.map((block) => block.data) } : {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function convertMessage(message, supportsImages, developerRole = "user") {
|
|
62
|
+
if (message.role === "user") return {
|
|
63
|
+
role: "user",
|
|
64
|
+
...toPlainContent(message.content, supportsImages)
|
|
65
|
+
};
|
|
66
|
+
if (message.role === "developer") return {
|
|
67
|
+
role: developerRole,
|
|
68
|
+
...toPlainContent(message.content, supportsImages)
|
|
69
|
+
};
|
|
70
|
+
if (message.role === "toolResult") {
|
|
71
|
+
const converted = toPlainContent(message.content, supportsImages);
|
|
72
|
+
return {
|
|
73
|
+
role: "tool",
|
|
74
|
+
tool_name: message.toolName,
|
|
75
|
+
...converted
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const text = [];
|
|
79
|
+
const thinking = [];
|
|
80
|
+
const toolCalls = [];
|
|
81
|
+
for (const block of message.content) {
|
|
82
|
+
if (block.type === "text") {
|
|
83
|
+
text.push(block.text);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (block.type === "thinking") {
|
|
87
|
+
thinking.push(block.thinking);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (block.type === "toolCall") toolCalls.push({
|
|
91
|
+
type: "function",
|
|
92
|
+
function: {
|
|
93
|
+
name: block.name,
|
|
94
|
+
arguments: block.arguments
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
role: "assistant",
|
|
100
|
+
content: text.join("\n"),
|
|
101
|
+
...thinking.length > 0 ? { thinking: thinking.join("\n") } : {},
|
|
102
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function convertMessages(model, context) {
|
|
106
|
+
const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
|
|
107
|
+
const messages = [...systemPrompts.map((systemPrompt) => ({
|
|
108
|
+
role: "developer",
|
|
109
|
+
content: systemPrompt,
|
|
110
|
+
timestamp: Date.now()
|
|
111
|
+
})), ...context.messages];
|
|
112
|
+
const isCloud = model.provider === "ollama-cloud";
|
|
113
|
+
const supportsImages = model.input.includes("image");
|
|
114
|
+
const converted = transformMessages(messages, model).map((msg, index) => {
|
|
115
|
+
const developerRole = msg.role === "developer" && (index < systemPrompts.length || msg.attribution !== "user") ? "system" : "user";
|
|
116
|
+
const converted = convertMessage(msg, supportsImages, developerRole);
|
|
117
|
+
if (isCloud && converted.role === "assistant" && converted.thinking) {
|
|
118
|
+
const { thinking: _t, ...rest } = converted;
|
|
119
|
+
return rest;
|
|
120
|
+
}
|
|
121
|
+
return converted;
|
|
122
|
+
});
|
|
123
|
+
if (!converted.some((m) => m.role === "user")) {
|
|
124
|
+
for (let i = converted.length - 1; i >= systemPrompts.length; i--) if (converted[i].role === "system") {
|
|
125
|
+
converted[i].role = "user";
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return converted;
|
|
130
|
+
}
|
|
131
|
+
function convertTools(tools) {
|
|
132
|
+
if (!tools || tools.length === 0) return;
|
|
133
|
+
return tools.map((tool) => ({
|
|
134
|
+
type: "function",
|
|
135
|
+
function: {
|
|
136
|
+
name: tool.name,
|
|
137
|
+
description: tool.description,
|
|
138
|
+
parameters: sanitizeSchemaForOllama(toolWireSchema(tool))
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Ollama Cloud rejects `num_predict` above this value with HTTP 400
|
|
144
|
+
* (`max_tokens (...) exceeds model's maximum output tokens (65536)`).
|
|
145
|
+
* The cap currently applies uniformly to cloud-served models; the cloud-side
|
|
146
|
+
* limit was confirmed empirically against `deepseek-v4-pro`/`-flash` and is
|
|
147
|
+
* the same cap surfaced for every other Ollama Cloud model we've probed.
|
|
148
|
+
*
|
|
149
|
+
* Acts as a wire-level safety net so stale `models.db` rows (or custom
|
|
150
|
+
* `modelOverrides` re-enabling `num_predict`) cannot 400 the request — even
|
|
151
|
+
* when `model.omitMaxOutputTokens` was never applied. See #3392.
|
|
152
|
+
*/
|
|
153
|
+
const OLLAMA_CLOUD_NUM_PREDICT_CAP = 65536;
|
|
154
|
+
function resolveNumPredict(model, requested) {
|
|
155
|
+
if (model.provider === "ollama-cloud") return Math.min(requested, OLLAMA_CLOUD_NUM_PREDICT_CAP);
|
|
156
|
+
return requested;
|
|
157
|
+
}
|
|
158
|
+
function createChatBody(model, context, options) {
|
|
159
|
+
const think = mapReasoning(model, options?.reasoning, options?.disableReasoning);
|
|
160
|
+
const toolChoice = mapToolChoice(options?.toolChoice);
|
|
161
|
+
const tools = convertTools(selectToolsForToolChoice(context.tools, options?.toolChoice));
|
|
162
|
+
const runtimeOptions = {};
|
|
163
|
+
let hasRuntimeOptions = false;
|
|
164
|
+
if (options?.maxTokens !== void 0 && !model.omitMaxOutputTokens) {
|
|
165
|
+
runtimeOptions.num_predict = resolveNumPredict(model, options.maxTokens);
|
|
166
|
+
hasRuntimeOptions = true;
|
|
167
|
+
}
|
|
168
|
+
if (options?.temperature !== void 0) {
|
|
169
|
+
runtimeOptions.temperature = options.temperature;
|
|
170
|
+
hasRuntimeOptions = true;
|
|
171
|
+
}
|
|
172
|
+
if (options?.topP !== void 0) {
|
|
173
|
+
runtimeOptions.top_p = options.topP;
|
|
174
|
+
hasRuntimeOptions = true;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
model: model.id,
|
|
178
|
+
messages: convertMessages(model, context),
|
|
179
|
+
...tools ? { tools } : {},
|
|
180
|
+
...think !== void 0 ? { think } : {},
|
|
181
|
+
...toolChoice !== void 0 ? { tool_choice: toolChoice } : {},
|
|
182
|
+
...hasRuntimeOptions ? { options: runtimeOptions } : {},
|
|
183
|
+
stream: true
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function shouldRetryOllamaResponse(response, bodyText) {
|
|
187
|
+
return response.status < 500 || !LLAMA_CPP_TOOL_CALL_PARSE_PATTERN.test(bodyText);
|
|
188
|
+
}
|
|
189
|
+
async function captureHttpErrorResponse(response) {
|
|
190
|
+
let bodyText;
|
|
191
|
+
let bodyJson;
|
|
192
|
+
try {
|
|
193
|
+
bodyText = await response.text();
|
|
194
|
+
if (bodyText.trim()) try {
|
|
195
|
+
bodyJson = JSON.parse(bodyText);
|
|
196
|
+
} catch {}
|
|
197
|
+
} catch {}
|
|
198
|
+
return {
|
|
199
|
+
status: response.status,
|
|
200
|
+
headers: response.headers,
|
|
201
|
+
bodyText,
|
|
202
|
+
bodyJson
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function createEmptyOutput(model) {
|
|
206
|
+
return {
|
|
207
|
+
role: "assistant",
|
|
208
|
+
content: [],
|
|
209
|
+
api: "ollama-chat",
|
|
210
|
+
provider: model.provider,
|
|
211
|
+
model: model.id,
|
|
212
|
+
usage: {
|
|
213
|
+
input: 0,
|
|
214
|
+
output: 0,
|
|
215
|
+
cacheRead: 0,
|
|
216
|
+
cacheWrite: 0,
|
|
217
|
+
totalTokens: 0,
|
|
218
|
+
cost: {
|
|
219
|
+
input: 0,
|
|
220
|
+
output: 0,
|
|
221
|
+
cacheRead: 0,
|
|
222
|
+
cacheWrite: 0,
|
|
223
|
+
total: 0
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
stopReason: "stop",
|
|
227
|
+
timestamp: Date.now()
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function endThinkingBlock(stream, output, index) {
|
|
231
|
+
const block = output.content[index];
|
|
232
|
+
if (block?.type === "thinking") stream.push({
|
|
233
|
+
type: "thinking_end",
|
|
234
|
+
contentIndex: index,
|
|
235
|
+
content: block.thinking,
|
|
236
|
+
partial: output
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function endTextBlock(stream, output, index) {
|
|
240
|
+
const block = output.content[index];
|
|
241
|
+
if (block?.type === "text") stream.push({
|
|
242
|
+
type: "text_end",
|
|
243
|
+
contentIndex: index,
|
|
244
|
+
content: block.text,
|
|
245
|
+
partial: output
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function endToolCallBlock(stream, output, index) {
|
|
249
|
+
const block = output.content[index];
|
|
250
|
+
if (block?.type !== "toolCall") return;
|
|
251
|
+
const toolCall = block;
|
|
252
|
+
if (toolCall[kStreamingPartialJson]) {
|
|
253
|
+
toolCall.arguments = parseStreamingJson(toolCall[kStreamingPartialJson]);
|
|
254
|
+
clearStreamingPartialJson(toolCall);
|
|
255
|
+
}
|
|
256
|
+
stream.push({
|
|
257
|
+
type: "toolcall_end",
|
|
258
|
+
contentIndex: index,
|
|
259
|
+
toolCall,
|
|
260
|
+
partial: output
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function mapDoneReason(doneReason, output) {
|
|
264
|
+
if (doneReason === "length") return "length";
|
|
265
|
+
if (doneReason === "tool_calls") return "toolUse";
|
|
266
|
+
if (doneReason === "load") return "error";
|
|
267
|
+
if (doneReason === void 0 && output.content.some((block) => block.type === "toolCall")) return "toolUse";
|
|
268
|
+
return "stop";
|
|
269
|
+
}
|
|
270
|
+
const EMPTY_OLLAMA_LENGTH_COMPLETION_MESSAGE = "Model returned no content: prompt filled the context window; raise Ollama num_ctx or shorten the prompt.";
|
|
271
|
+
const EMPTY_OLLAMA_LOAD_COMPLETION_MESSAGE = "Ollama loaded the model but generated nothing (done_reason: load): the request contained no user-role message.";
|
|
272
|
+
function hasVisibleAssistantContent(output) {
|
|
273
|
+
return output.content.some((block) => {
|
|
274
|
+
if (block.type === "text") return block.text.trim().length > 0;
|
|
275
|
+
if (block.type === "thinking") return block.thinking.trim().length > 0;
|
|
276
|
+
return block.type === "toolCall";
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const OLLAMA_RETRY_DELAYS_MS = [
|
|
280
|
+
2e3,
|
|
281
|
+
5e3,
|
|
282
|
+
1e4
|
|
283
|
+
];
|
|
284
|
+
const streamOllamaOnce = (model, context, options = {}) => {
|
|
285
|
+
const stream = new AssistantMessageEventStream();
|
|
286
|
+
(async () => {
|
|
287
|
+
const startTime = performance.now();
|
|
288
|
+
let firstTokenTime;
|
|
289
|
+
const output = createEmptyOutput(model);
|
|
290
|
+
let rawRequestDump;
|
|
291
|
+
let capturedErrorResponse;
|
|
292
|
+
let activeThinkingIndex;
|
|
293
|
+
let activeTextIndex;
|
|
294
|
+
const activeToolIndices = /* @__PURE__ */ new Set();
|
|
295
|
+
const streamMarkupHealingPattern = getStreamMarkupHealingPattern(model.provider, model.id);
|
|
296
|
+
const streamMarkupHealing = streamMarkupHealingPattern ? new StreamMarkupHealing({ pattern: streamMarkupHealingPattern }) : void 0;
|
|
297
|
+
let healedToolCallEmitted = false;
|
|
298
|
+
let suppressHealedThinking = false;
|
|
299
|
+
const endActiveTextBlock = () => {
|
|
300
|
+
if (activeTextIndex === void 0) return;
|
|
301
|
+
endTextBlock(stream, output, activeTextIndex);
|
|
302
|
+
activeTextIndex = void 0;
|
|
303
|
+
};
|
|
304
|
+
const endActiveThinkingBlock = () => {
|
|
305
|
+
if (activeThinkingIndex === void 0) return;
|
|
306
|
+
endThinkingBlock(stream, output, activeThinkingIndex);
|
|
307
|
+
activeThinkingIndex = void 0;
|
|
308
|
+
};
|
|
309
|
+
const appendVisibleText = (text) => {
|
|
310
|
+
if (text.length === 0) return;
|
|
311
|
+
endActiveThinkingBlock();
|
|
312
|
+
if (activeTextIndex === void 0) {
|
|
313
|
+
output.content.push({
|
|
314
|
+
type: "text",
|
|
315
|
+
text: ""
|
|
316
|
+
});
|
|
317
|
+
activeTextIndex = output.content.length - 1;
|
|
318
|
+
stream.push({
|
|
319
|
+
type: "text_start",
|
|
320
|
+
contentIndex: activeTextIndex,
|
|
321
|
+
partial: output
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const block = output.content[activeTextIndex];
|
|
325
|
+
if (block?.type === "text") {
|
|
326
|
+
block.text += text;
|
|
327
|
+
stream.push({
|
|
328
|
+
type: "text_delta",
|
|
329
|
+
contentIndex: activeTextIndex,
|
|
330
|
+
delta: text,
|
|
331
|
+
partial: output
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
335
|
+
};
|
|
336
|
+
const appendVisibleThinking = (thinking) => {
|
|
337
|
+
if (thinking.length === 0) return;
|
|
338
|
+
endActiveTextBlock();
|
|
339
|
+
if (activeThinkingIndex === void 0) {
|
|
340
|
+
output.content.push({
|
|
341
|
+
type: "thinking",
|
|
342
|
+
thinking: ""
|
|
343
|
+
});
|
|
344
|
+
activeThinkingIndex = output.content.length - 1;
|
|
345
|
+
stream.push({
|
|
346
|
+
type: "thinking_start",
|
|
347
|
+
contentIndex: activeThinkingIndex,
|
|
348
|
+
partial: output
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const block = output.content[activeThinkingIndex];
|
|
352
|
+
if (block?.type === "thinking") {
|
|
353
|
+
block.thinking += thinking;
|
|
354
|
+
stream.push({
|
|
355
|
+
type: "thinking_delta",
|
|
356
|
+
contentIndex: activeThinkingIndex,
|
|
357
|
+
delta: thinking,
|
|
358
|
+
partial: output
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
362
|
+
};
|
|
363
|
+
const emitHealedToolCall = (call) => {
|
|
364
|
+
endActiveThinkingBlock();
|
|
365
|
+
endActiveTextBlock();
|
|
366
|
+
const toolCall = {
|
|
367
|
+
type: "toolCall",
|
|
368
|
+
id: call.id,
|
|
369
|
+
name: call.name,
|
|
370
|
+
arguments: parseStreamingJson(call.arguments),
|
|
371
|
+
[kStreamingPartialJson]: call.arguments
|
|
372
|
+
};
|
|
373
|
+
output.content.push(toolCall);
|
|
374
|
+
const index = output.content.length - 1;
|
|
375
|
+
stream.push({
|
|
376
|
+
type: "toolcall_start",
|
|
377
|
+
contentIndex: index,
|
|
378
|
+
partial: output
|
|
379
|
+
});
|
|
380
|
+
stream.push({
|
|
381
|
+
type: "toolcall_delta",
|
|
382
|
+
contentIndex: index,
|
|
383
|
+
delta: call.arguments,
|
|
384
|
+
partial: output
|
|
385
|
+
});
|
|
386
|
+
endToolCallBlock(stream, output, index);
|
|
387
|
+
healedToolCallEmitted = true;
|
|
388
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
389
|
+
};
|
|
390
|
+
const emitHealingEvent = (event) => {
|
|
391
|
+
if (event.type === "text") appendVisibleText(event.text);
|
|
392
|
+
else if (event.type === "thinking") {
|
|
393
|
+
if (!suppressHealedThinking) appendVisibleThinking(event.thinking);
|
|
394
|
+
} else emitHealedToolCall(event.call);
|
|
395
|
+
};
|
|
396
|
+
const drainHealedToolCalls = () => {
|
|
397
|
+
if (!streamMarkupHealing) return;
|
|
398
|
+
for (const call of streamMarkupHealing.drainCompleted()) emitHealedToolCall(call);
|
|
399
|
+
};
|
|
400
|
+
try {
|
|
401
|
+
const apiKey = options.apiKey || getEnvApiKey(model.provider);
|
|
402
|
+
if (!apiKey) throw new MissingApiKeyError(model.provider);
|
|
403
|
+
const baseUrl = normalizeBaseUrl(model.baseUrl);
|
|
404
|
+
let body = createChatBody(model, context, options);
|
|
405
|
+
const replacementPayload = await options.onPayload?.(body, model);
|
|
406
|
+
if (replacementPayload !== void 0) body = replacementPayload;
|
|
407
|
+
rawRequestDump = {
|
|
408
|
+
provider: model.provider,
|
|
409
|
+
api: model.api,
|
|
410
|
+
model: model.id,
|
|
411
|
+
method: "POST",
|
|
412
|
+
url: `${baseUrl}/api/chat`,
|
|
413
|
+
body
|
|
414
|
+
};
|
|
415
|
+
const idleTimeoutMs = options.streamIdleTimeoutMs ?? getOpenAIStreamIdleTimeoutMs();
|
|
416
|
+
const firstEventTimeoutMs = options.streamFirstEventTimeoutMs ?? getOpenAIStreamFirstEventTimeoutMs(idleTimeoutMs);
|
|
417
|
+
const watchdog = armPreResponseTimeout(options.signal, firstEventTimeoutMs);
|
|
418
|
+
let response;
|
|
419
|
+
try {
|
|
420
|
+
response = await fetchWithRetry(`${baseUrl}/api/chat`, {
|
|
421
|
+
method: "POST",
|
|
422
|
+
headers: {
|
|
423
|
+
...model.headers,
|
|
424
|
+
...options.headers,
|
|
425
|
+
Authorization: `Bearer ${apiKey}`,
|
|
426
|
+
"Content-Type": "application/json"
|
|
427
|
+
},
|
|
428
|
+
body: JSON.stringify(body),
|
|
429
|
+
signal: watchdog.signal,
|
|
430
|
+
defaultDelayMs: OLLAMA_RETRY_DELAYS_MS,
|
|
431
|
+
shouldRetryResponse: shouldRetryOllamaResponse,
|
|
432
|
+
fetch: options.fetch,
|
|
433
|
+
timeout: false
|
|
434
|
+
});
|
|
435
|
+
} finally {
|
|
436
|
+
watchdog.clear();
|
|
437
|
+
}
|
|
438
|
+
if (!response.ok) {
|
|
439
|
+
capturedErrorResponse = await captureHttpErrorResponse(response);
|
|
440
|
+
throw new OllamaApiError(`HTTP ${response.status} from ${baseUrl}/api/chat`, response.status, { headers: response.headers });
|
|
441
|
+
}
|
|
442
|
+
if (!response.body) throw new OllamaApiError("Ollama returned an empty response body", response.status, { headers: response.headers });
|
|
443
|
+
stream.push({
|
|
444
|
+
type: "start",
|
|
445
|
+
partial: output
|
|
446
|
+
});
|
|
447
|
+
for await (const chunk of readJsonl(response.body)) {
|
|
448
|
+
if (chunk.message?.thinking) {
|
|
449
|
+
suppressHealedThinking = true;
|
|
450
|
+
endActiveTextBlock();
|
|
451
|
+
if (activeThinkingIndex === void 0) {
|
|
452
|
+
output.content.push({
|
|
453
|
+
type: "thinking",
|
|
454
|
+
thinking: ""
|
|
455
|
+
});
|
|
456
|
+
activeThinkingIndex = output.content.length - 1;
|
|
457
|
+
stream.push({
|
|
458
|
+
type: "thinking_start",
|
|
459
|
+
contentIndex: activeThinkingIndex,
|
|
460
|
+
partial: output
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
const block = output.content[activeThinkingIndex];
|
|
464
|
+
if (block?.type === "thinking") {
|
|
465
|
+
block.thinking += chunk.message.thinking;
|
|
466
|
+
stream.push({
|
|
467
|
+
type: "thinking_delta",
|
|
468
|
+
contentIndex: activeThinkingIndex,
|
|
469
|
+
delta: chunk.message.thinking,
|
|
470
|
+
partial: output
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
474
|
+
}
|
|
475
|
+
const chunkContent = chunk.message?.content;
|
|
476
|
+
const structuredCalls = chunk.message?.tool_calls?.length ? chunk.message.tool_calls : void 0;
|
|
477
|
+
if (chunkContent) {
|
|
478
|
+
if (streamMarkupHealing) {
|
|
479
|
+
const healingEvents = structuredCalls ? streamMarkupHealing.feedEventsWithoutCalls(chunkContent) : streamMarkupHealing.feedEvents(chunkContent);
|
|
480
|
+
for (const event of healingEvents) emitHealingEvent(event);
|
|
481
|
+
} else appendVisibleText(chunkContent);
|
|
482
|
+
}
|
|
483
|
+
if (structuredCalls) {
|
|
484
|
+
endActiveThinkingBlock();
|
|
485
|
+
endActiveTextBlock();
|
|
486
|
+
for (const call of structuredCalls) {
|
|
487
|
+
const name = call.function?.name ?? "unknown_tool";
|
|
488
|
+
const rawArgs = call.function?.arguments;
|
|
489
|
+
const partialJson = typeof rawArgs === "string" ? rawArgs : JSON.stringify(rawArgs ?? {});
|
|
490
|
+
const toolCall = {
|
|
491
|
+
type: "toolCall",
|
|
492
|
+
id: `ollama:${output.content.length}:${name}`,
|
|
493
|
+
name,
|
|
494
|
+
arguments: parseStreamingJson(partialJson),
|
|
495
|
+
[kStreamingPartialJson]: partialJson
|
|
496
|
+
};
|
|
497
|
+
output.content.push(toolCall);
|
|
498
|
+
const index = output.content.length - 1;
|
|
499
|
+
activeToolIndices.add(index);
|
|
500
|
+
stream.push({
|
|
501
|
+
type: "toolcall_start",
|
|
502
|
+
contentIndex: index,
|
|
503
|
+
partial: output
|
|
504
|
+
});
|
|
505
|
+
stream.push({
|
|
506
|
+
type: "toolcall_delta",
|
|
507
|
+
contentIndex: index,
|
|
508
|
+
delta: partialJson,
|
|
509
|
+
partial: output
|
|
510
|
+
});
|
|
511
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (chunk.done) {
|
|
515
|
+
if (streamMarkupHealing) {
|
|
516
|
+
for (const event of streamMarkupHealing.flushEvents()) emitHealingEvent(event);
|
|
517
|
+
drainHealedToolCalls();
|
|
518
|
+
}
|
|
519
|
+
endActiveThinkingBlock();
|
|
520
|
+
endActiveTextBlock();
|
|
521
|
+
for (const index of activeToolIndices) endToolCallBlock(stream, output, index);
|
|
522
|
+
activeToolIndices.clear();
|
|
523
|
+
output.stopReason = mapDoneReason(chunk.done_reason, output);
|
|
524
|
+
if (healedToolCallEmitted && output.stopReason === "stop") output.stopReason = "toolUse";
|
|
525
|
+
output.usage.input = chunk.prompt_eval_count ?? 0;
|
|
526
|
+
output.usage.output = chunk.eval_count ?? 0;
|
|
527
|
+
output.usage.totalTokens = output.usage.input + output.usage.output;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (streamMarkupHealing) {
|
|
531
|
+
for (const event of streamMarkupHealing.flushEvents()) emitHealingEvent(event);
|
|
532
|
+
drainHealedToolCalls();
|
|
533
|
+
if (healedToolCallEmitted && output.stopReason === "stop") output.stopReason = "toolUse";
|
|
534
|
+
}
|
|
535
|
+
endActiveThinkingBlock();
|
|
536
|
+
endActiveTextBlock();
|
|
537
|
+
if (output.stopReason === "length" && !hasVisibleAssistantContent(output)) {
|
|
538
|
+
output.stopReason = "error";
|
|
539
|
+
output.errorMessage = EMPTY_OLLAMA_LENGTH_COMPLETION_MESSAGE;
|
|
540
|
+
}
|
|
541
|
+
if (output.stopReason === "error" && !output.errorMessage) output.errorMessage = EMPTY_OLLAMA_LOAD_COMPLETION_MESSAGE;
|
|
542
|
+
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
543
|
+
output.duration = performance.now() - startTime;
|
|
544
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
545
|
+
if (output.stopReason === "error") {
|
|
546
|
+
stream.push({
|
|
547
|
+
type: "error",
|
|
548
|
+
reason: "error",
|
|
549
|
+
error: output
|
|
550
|
+
});
|
|
551
|
+
stream.end();
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const doneReason = output.stopReason === "length" ? "length" : output.stopReason === "toolUse" ? "toolUse" : "stop";
|
|
555
|
+
stream.push({
|
|
556
|
+
type: "done",
|
|
557
|
+
reason: doneReason,
|
|
558
|
+
message: output
|
|
559
|
+
});
|
|
560
|
+
stream.end();
|
|
561
|
+
} catch (error) {
|
|
562
|
+
for (const block of output.content) if (block.type === "toolCall") clearStreamingPartialJson(block);
|
|
563
|
+
const result = await finalize(error, {
|
|
564
|
+
api: model.api,
|
|
565
|
+
provider: model.provider,
|
|
566
|
+
signal: options.signal,
|
|
567
|
+
rawRequestDump,
|
|
568
|
+
capturedErrorResponse
|
|
569
|
+
});
|
|
570
|
+
output.stopReason = result.stopReason;
|
|
571
|
+
output.errorStatus = result.status;
|
|
572
|
+
output.errorId = result.id;
|
|
573
|
+
output.errorMessage = result.message;
|
|
574
|
+
output.duration = performance.now() - startTime;
|
|
575
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
576
|
+
stream.push({
|
|
577
|
+
type: "error",
|
|
578
|
+
reason: output.stopReason,
|
|
579
|
+
error: output
|
|
580
|
+
});
|
|
581
|
+
stream.end();
|
|
582
|
+
}
|
|
583
|
+
})();
|
|
584
|
+
return stream;
|
|
585
|
+
};
|
|
586
|
+
/** Retry EOS-only Ollama completions before the agent loop sees an empty stop. */
|
|
587
|
+
const streamOllama = (model, context, options) => withEmptyCompletionRetry(model, context, options, streamOllamaOnce);
|
|
588
|
+
//#endregion
|
|
589
|
+
export { ollama_exports as t };
|