@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,491 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { D as partialSuffixOverlapAny, E as FencedThinkingScanner, T as createInbandScanner } from "./utils-Cp76gCyk.mjs";
|
|
4
|
+
import { h as isDeepseekModelIdOrName } from "./models-SGASygJ3.mjs";
|
|
5
|
+
import "./identity-Da1GPU9a.mjs";
|
|
6
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/dialect/thinking.ts
|
|
7
|
+
/**
|
|
8
|
+
* Every dialect's in-band thinking section in its canonical `renderThinking`
|
|
9
|
+
* form (see the sibling `./*.ts` scanners). {@link ThinkingInbandScanner} heals
|
|
10
|
+
* reasoning a model leaked into its visible text channel back into thinking
|
|
11
|
+
* events, whichever dialect idiom the leak used.
|
|
12
|
+
*
|
|
13
|
+
* Plain (attribute-free) delimiters only — matching what `renderThinking`
|
|
14
|
+
* emits and what models leak in practice. Attributed or namespaced XML thinking
|
|
15
|
+
* tags (`<thinking signature="…">`, `antml:thinking`) are recovered by the owned
|
|
16
|
+
* anthropic-dialect parser, not this text-channel healing fallback.
|
|
17
|
+
*/
|
|
18
|
+
const TAGS = [
|
|
19
|
+
{
|
|
20
|
+
open: "<think>",
|
|
21
|
+
close: "</think>"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
open: "<thinking>",
|
|
25
|
+
close: "</thinking>"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
open: "<scratchpad>",
|
|
29
|
+
close: "</scratchpad>"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
open: "```thinking\n",
|
|
33
|
+
close: "```",
|
|
34
|
+
fenced: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
open: "<|channel>thought\n",
|
|
38
|
+
close: "<channel|>"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
open: "<|start|>assistant<|channel|>analysis<|message|>",
|
|
42
|
+
close: "<|end|>"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
open: "<|channel|>analysis<|message|>",
|
|
46
|
+
close: "<|end|>"
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
const OPENS = TAGS.map((tag) => tag.open);
|
|
50
|
+
var ThinkingInbandScanner = class {
|
|
51
|
+
#buffer = "";
|
|
52
|
+
#closeTag = "";
|
|
53
|
+
#thinking = "";
|
|
54
|
+
/** Fence-aware close-matcher while inside a ` ```thinking ` block; undefined otherwise. */
|
|
55
|
+
#fenced;
|
|
56
|
+
/** Backtick count that opened the Markdown code span/fence we are inside; 0 when not in code. */
|
|
57
|
+
#codeTicks = 0;
|
|
58
|
+
/** True when {@link #codeTicks} opened a fenced block (closes on a fence line), not an inline span. */
|
|
59
|
+
#codeFenced = false;
|
|
60
|
+
/**
|
|
61
|
+
* Leading-space count on the current output line, or -1 once a non-space
|
|
62
|
+
* character has appeared. Starts at 0 (line start) so a fence opening the
|
|
63
|
+
* stream — or one indented ≤3 spaces, as CommonMark allows — is recognized.
|
|
64
|
+
*/
|
|
65
|
+
#lineIndent = 0;
|
|
66
|
+
feed(text) {
|
|
67
|
+
if (text.length === 0) return [];
|
|
68
|
+
this.#buffer += text;
|
|
69
|
+
return this.#consume(false);
|
|
70
|
+
}
|
|
71
|
+
flush() {
|
|
72
|
+
const events = this.#consume(true);
|
|
73
|
+
if (this.#buffer.length === 0) return events;
|
|
74
|
+
if (this.#closeTag) {
|
|
75
|
+
this.#emitThinking(this.#buffer, events);
|
|
76
|
+
events.push({
|
|
77
|
+
type: "thinkingEnd",
|
|
78
|
+
thinking: this.#thinking
|
|
79
|
+
});
|
|
80
|
+
} else events.push({
|
|
81
|
+
type: "text",
|
|
82
|
+
text: this.#buffer
|
|
83
|
+
});
|
|
84
|
+
this.#buffer = "";
|
|
85
|
+
this.#closeTag = "";
|
|
86
|
+
return events;
|
|
87
|
+
}
|
|
88
|
+
#consume(final) {
|
|
89
|
+
const events = [];
|
|
90
|
+
for (;;) {
|
|
91
|
+
if (this.#fenced) {
|
|
92
|
+
const result = this.#fenced.feed(this.#buffer, final);
|
|
93
|
+
this.#buffer = result.closed ? result.rest : "";
|
|
94
|
+
this.#emitThinking(result.thinking, events);
|
|
95
|
+
if (result.closed || final) {
|
|
96
|
+
events.push({
|
|
97
|
+
type: "thinkingEnd",
|
|
98
|
+
thinking: this.#thinking
|
|
99
|
+
});
|
|
100
|
+
this.#thinking = "";
|
|
101
|
+
this.#closeTag = "";
|
|
102
|
+
this.#fenced = void 0;
|
|
103
|
+
}
|
|
104
|
+
if (this.#fenced) break;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (this.#buffer.length === 0) break;
|
|
108
|
+
if (this.#closeTag) {
|
|
109
|
+
const close = this.#buffer.indexOf(this.#closeTag);
|
|
110
|
+
if (close === -1) {
|
|
111
|
+
const hold = final ? 0 : partialSuffixOverlapAny(this.#buffer, [this.#closeTag]);
|
|
112
|
+
this.#emitThinking(this.#buffer.slice(0, this.#buffer.length - hold), events);
|
|
113
|
+
this.#buffer = this.#buffer.slice(this.#buffer.length - hold);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
this.#emitThinking(this.#buffer.slice(0, close), events);
|
|
117
|
+
this.#buffer = this.#buffer.slice(close + this.#closeTag.length);
|
|
118
|
+
events.push({
|
|
119
|
+
type: "thinkingEnd",
|
|
120
|
+
thinking: this.#thinking
|
|
121
|
+
});
|
|
122
|
+
this.#thinking = "";
|
|
123
|
+
this.#closeTag = "";
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (this.#codeTicks > 0) {
|
|
127
|
+
if (this.#emitCode(final, events)) continue;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
const hit = scanVisible(this.#buffer, final);
|
|
131
|
+
if (hit.kind === "none") {
|
|
132
|
+
this.#emitText(this.#buffer, events);
|
|
133
|
+
this.#buffer = "";
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
if (hit.index > 0) this.#emitText(this.#buffer.slice(0, hit.index), events);
|
|
137
|
+
if (hit.kind === "hold") {
|
|
138
|
+
this.#buffer = this.#buffer.slice(hit.index);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
if (hit.kind === "code") {
|
|
142
|
+
const fenced = hit.ticks >= 3 && this.#lineIndent >= 0 && this.#lineIndent <= 3;
|
|
143
|
+
this.#emitText(this.#buffer.slice(hit.index, hit.index + hit.ticks), events);
|
|
144
|
+
this.#buffer = this.#buffer.slice(hit.index + hit.ticks);
|
|
145
|
+
this.#codeTicks = hit.ticks;
|
|
146
|
+
this.#codeFenced = fenced;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
this.#buffer = this.#buffer.slice(hit.index + hit.tag.open.length);
|
|
150
|
+
this.#closeTag = hit.tag.close;
|
|
151
|
+
this.#thinking = "";
|
|
152
|
+
if (hit.tag.fenced) this.#fenced = new FencedThinkingScanner();
|
|
153
|
+
events.push({ type: "thinkingStart" });
|
|
154
|
+
}
|
|
155
|
+
return events;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Emit buffered content while inside a Markdown code region, suppressing
|
|
159
|
+
* reasoning-tag detection. A fenced block closes only on a fence line (a line
|
|
160
|
+
* of backticks ≥ the opener); an inline span closes on the first backtick run
|
|
161
|
+
* of exactly the opener length. Returns true when the region closed and the
|
|
162
|
+
* loop should continue, false when it held back and should break.
|
|
163
|
+
*/
|
|
164
|
+
#emitCode(final, events) {
|
|
165
|
+
if (this.#codeFenced) {
|
|
166
|
+
const end = findFenceCloseEnd(this.#buffer, this.#codeTicks, final);
|
|
167
|
+
if (end !== -1) {
|
|
168
|
+
this.#emitText(this.#buffer.slice(0, end), events);
|
|
169
|
+
this.#buffer = this.#buffer.slice(end);
|
|
170
|
+
this.#codeTicks = 0;
|
|
171
|
+
this.#codeFenced = false;
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
if (final) {
|
|
175
|
+
this.#emitText(this.#buffer, events);
|
|
176
|
+
this.#buffer = "";
|
|
177
|
+
this.#codeTicks = 0;
|
|
178
|
+
this.#codeFenced = false;
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
const lastNl = this.#buffer.lastIndexOf("\n");
|
|
182
|
+
if (lastNl !== -1) {
|
|
183
|
+
this.#emitText(this.#buffer.slice(0, lastNl + 1), events);
|
|
184
|
+
this.#buffer = this.#buffer.slice(lastNl + 1);
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const close = findBacktickRun(this.#buffer, 0, this.#codeTicks);
|
|
189
|
+
if (close !== -1 && (final || close + this.#codeTicks < this.#buffer.length)) {
|
|
190
|
+
this.#emitText(this.#buffer.slice(0, close + this.#codeTicks), events);
|
|
191
|
+
this.#buffer = this.#buffer.slice(close + this.#codeTicks);
|
|
192
|
+
this.#codeTicks = 0;
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
const hold = final ? 0 : trailingBacktickRun(this.#buffer);
|
|
196
|
+
this.#emitText(this.#buffer.slice(0, this.#buffer.length - hold), events);
|
|
197
|
+
this.#buffer = this.#buffer.slice(this.#buffer.length - hold);
|
|
198
|
+
if (final) this.#codeTicks = 0;
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
#emitText(text, events) {
|
|
202
|
+
if (text.length === 0) return;
|
|
203
|
+
events.push({
|
|
204
|
+
type: "text",
|
|
205
|
+
text
|
|
206
|
+
});
|
|
207
|
+
this.#lineIndent = trailingLineIndent(text, this.#lineIndent);
|
|
208
|
+
}
|
|
209
|
+
#emitThinking(delta, events) {
|
|
210
|
+
if (delta.length === 0) return;
|
|
211
|
+
this.#thinking += delta;
|
|
212
|
+
events.push({
|
|
213
|
+
type: "thinkingDelta",
|
|
214
|
+
delta
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Walk idle visible text for the earliest boundary: a leaked reasoning-tag open,
|
|
220
|
+
* a Markdown code-span/fence opener (a backtick run), or — when more chunks may
|
|
221
|
+
* follow — a held partial delimiter at the buffer tail.
|
|
222
|
+
*
|
|
223
|
+
* Reasoning tags win at any position so the gemini ` ```thinking ` fence is
|
|
224
|
+
* healed instead of being read as a code fence. Backtick runs enter code mode so
|
|
225
|
+
* a literal `<think>` inside inline code or a fenced block stays visible text.
|
|
226
|
+
*/
|
|
227
|
+
function scanVisible(buffer, final) {
|
|
228
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
229
|
+
const tag = TAGS.find((candidate) => buffer.startsWith(candidate.open, i));
|
|
230
|
+
if (tag) return {
|
|
231
|
+
kind: "tag",
|
|
232
|
+
index: i,
|
|
233
|
+
tag
|
|
234
|
+
};
|
|
235
|
+
if (!final) {
|
|
236
|
+
const rest = buffer.slice(i);
|
|
237
|
+
if (OPENS.some((open) => open.length > rest.length && open.startsWith(rest))) return {
|
|
238
|
+
kind: "hold",
|
|
239
|
+
index: i
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (buffer[i] === "`") {
|
|
243
|
+
const ticks = backtickRun(buffer, i);
|
|
244
|
+
if (!final && i + ticks === buffer.length) return {
|
|
245
|
+
kind: "hold",
|
|
246
|
+
index: i
|
|
247
|
+
};
|
|
248
|
+
return {
|
|
249
|
+
kind: "code",
|
|
250
|
+
index: i,
|
|
251
|
+
ticks
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return { kind: "none" };
|
|
256
|
+
}
|
|
257
|
+
/** Length of the maximal backtick run beginning at `from`. */
|
|
258
|
+
function backtickRun(buffer, from) {
|
|
259
|
+
let end = from;
|
|
260
|
+
while (end < buffer.length && buffer[end] === "`") end++;
|
|
261
|
+
return end - from;
|
|
262
|
+
}
|
|
263
|
+
/** Index of the first maximal backtick run of exactly `ticks` at/after `from`, else -1. */
|
|
264
|
+
function findBacktickRun(buffer, from, ticks) {
|
|
265
|
+
for (let i = buffer.indexOf("`", from); i !== -1; i = buffer.indexOf("`", i)) {
|
|
266
|
+
const run = backtickRun(buffer, i);
|
|
267
|
+
if (run === ticks) return i;
|
|
268
|
+
i += run;
|
|
269
|
+
}
|
|
270
|
+
return -1;
|
|
271
|
+
}
|
|
272
|
+
/** Length of a backtick run that ends at the buffer tail; 0 when the tail is not a backtick. */
|
|
273
|
+
function trailingBacktickRun(buffer) {
|
|
274
|
+
let start = buffer.length;
|
|
275
|
+
while (start > 0 && buffer[start - 1] === "`") start--;
|
|
276
|
+
return buffer.length - start;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Leading-space count of the line at the tail of `text`, continuing from the
|
|
280
|
+
* prior line's `indent` state (see {@link ThinkingInbandScanner.#lineIndent}).
|
|
281
|
+
* Returns -1 once any non-space character has appeared on the current line.
|
|
282
|
+
*/
|
|
283
|
+
function trailingLineIndent(text, prior) {
|
|
284
|
+
const lastNl = text.lastIndexOf("\n");
|
|
285
|
+
let indent = lastNl === -1 ? prior : 0;
|
|
286
|
+
for (let i = lastNl + 1; i < text.length; i++) {
|
|
287
|
+
if (indent === -1) break;
|
|
288
|
+
indent = text[i] === " " ? indent + 1 : -1;
|
|
289
|
+
}
|
|
290
|
+
return indent;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Index just past the first closing fence line for a fenced block opened with
|
|
294
|
+
* `ticks` backticks, or -1 when none is committed yet. A closing fence is a whole
|
|
295
|
+
* line whose trimmed content is only backticks, at least `ticks` of them. A line
|
|
296
|
+
* without a terminating newline is committed only when `final` (no more input can
|
|
297
|
+
* extend it into a non-fence line).
|
|
298
|
+
*/
|
|
299
|
+
function findFenceCloseEnd(buffer, ticks, final) {
|
|
300
|
+
for (let start = 0; start <= buffer.length;) {
|
|
301
|
+
const nl = buffer.indexOf("\n", start);
|
|
302
|
+
const terminated = nl !== -1;
|
|
303
|
+
const line = buffer.slice(start, terminated ? nl : buffer.length).trim();
|
|
304
|
+
if (line.length >= ticks && isAllBackticks(line) && (terminated || final)) return terminated ? nl + 1 : buffer.length;
|
|
305
|
+
if (!terminated) break;
|
|
306
|
+
start = nl + 1;
|
|
307
|
+
}
|
|
308
|
+
return -1;
|
|
309
|
+
}
|
|
310
|
+
/** True when `text` is non-empty and every character is a backtick. */
|
|
311
|
+
function isAllBackticks(text) {
|
|
312
|
+
for (let i = 0; i < text.length; i++) if (text[i] !== "`") return false;
|
|
313
|
+
return text.length > 0;
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/utils/stream-markup-healing.ts
|
|
317
|
+
/**
|
|
318
|
+
* Streaming-safe filters for leaked chat-template tool-call and thinking markup.
|
|
319
|
+
*
|
|
320
|
+
* Hosted models sometimes leak raw template markup into visible `content` instead
|
|
321
|
+
* of returning structured events. Tool-call healing delegates to the same
|
|
322
|
+
* dialect scanners used by owned in-band tool calling; this file keeps the
|
|
323
|
+
* provider-facing compatibility wrapper and model/provider gating.
|
|
324
|
+
*/
|
|
325
|
+
const KIMI_SECTION_END = "<|tool_calls_section_end|>";
|
|
326
|
+
const DSML_TOOL_CALLS_CLOSE_FULLWIDTH = "</|DSML|tool_calls>";
|
|
327
|
+
const DSML_TOOL_CALLS_CLOSE_ASCII = "</|DSML|tool_calls>";
|
|
328
|
+
/**
|
|
329
|
+
* State machine that consumes streamed visible text and emits cleaned text,
|
|
330
|
+
* thinking deltas, and reconstructed tool calls.
|
|
331
|
+
*
|
|
332
|
+
* A {@link ThinkingInbandScanner} always heals leaked reasoning idioms
|
|
333
|
+
* (`<think>`, `<thinking>`, ` ```thinking `, Gemma/Harmony channels, …) out of
|
|
334
|
+
* the visible channel. For Kimi / DeepSeek-DSML the provider tool-call grammar
|
|
335
|
+
* runs first and its cleaned text is piped through that thinking healer, so a
|
|
336
|
+
* model can leak tool-call markup and reasoning in the same stream.
|
|
337
|
+
*
|
|
338
|
+
* Feed only one stream channel (usually `delta.content` / `message.content`).
|
|
339
|
+
* Mixing reasoning and visible text into the same instance can corrupt held-back
|
|
340
|
+
* partial tag buffers.
|
|
341
|
+
*/
|
|
342
|
+
var StreamMarkupHealing = class {
|
|
343
|
+
#pattern;
|
|
344
|
+
/** Provider tool-call grammar (Kimi tokens / DSML envelope); absent for plain text streams. */
|
|
345
|
+
#toolScanner;
|
|
346
|
+
/** Always-on healer for leaked reasoning idioms in the visible text channel. */
|
|
347
|
+
#thinkingScanner = new ThinkingInbandScanner();
|
|
348
|
+
#sectionTerminated = false;
|
|
349
|
+
#completed = [];
|
|
350
|
+
constructor(options) {
|
|
351
|
+
this.#pattern = options.pattern;
|
|
352
|
+
this.#toolScanner = options.pattern === "kimi" ? createInbandScanner("kimi") : options.pattern === "dsml" ? createInbandScanner("xml", { xmlTagset: "dsml" }) : void 0;
|
|
353
|
+
}
|
|
354
|
+
get pattern() {
|
|
355
|
+
return this.#pattern;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Feed a chunk and return visible text only. Reconstructed tool calls are
|
|
359
|
+
* stored for {@link drainCompleted}; thinking blocks are intentionally not
|
|
360
|
+
* returned by this compatibility helper. Use {@link feedEvents} when the caller
|
|
361
|
+
* needs ordered text/thinking/tool-call events.
|
|
362
|
+
*/
|
|
363
|
+
feed(text) {
|
|
364
|
+
let clean = "";
|
|
365
|
+
for (const event of this.feedEvents(text)) if (event.type === "text") clean += event.text;
|
|
366
|
+
else if (event.type === "toolCall") this.#completed.push(event.call);
|
|
367
|
+
return clean;
|
|
368
|
+
}
|
|
369
|
+
/** Feed a chunk and return cleaned text/thinking/tool-call events in stream order. */
|
|
370
|
+
feedEvents(text) {
|
|
371
|
+
if (text.length === 0) return [];
|
|
372
|
+
this.#markSectionClosed(text);
|
|
373
|
+
if (!this.#toolScanner) return this.#convertScannerEvents(this.#thinkingScanner.feed(text));
|
|
374
|
+
return this.#convertScannerEvents(this.#healThinking(this.#toolScanner.feed(text)));
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Feed a chunk and return cleaned events, excluding synthesized tool calls.
|
|
378
|
+
* Used when the upstream chunk also carries structured `tool_calls`, keeping
|
|
379
|
+
* that structured payload as the single source of truth while preserving
|
|
380
|
+
* adjacent text and thinking events.
|
|
381
|
+
*/
|
|
382
|
+
feedEventsWithoutCalls(text) {
|
|
383
|
+
const events = this.feedEvents(text);
|
|
384
|
+
let out;
|
|
385
|
+
for (let i = 0; i < events.length; i++) {
|
|
386
|
+
const event = events[i];
|
|
387
|
+
if (event.type === "toolCall") out ??= events.slice(0, i);
|
|
388
|
+
else if (out) out.push(event);
|
|
389
|
+
}
|
|
390
|
+
return out ?? events;
|
|
391
|
+
}
|
|
392
|
+
/** Drain accumulated tool calls from calls to {@link feed}. */
|
|
393
|
+
drainCompleted() {
|
|
394
|
+
if (this.#completed.length === 0) return [];
|
|
395
|
+
return this.#completed.splice(0, this.#completed.length);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Flush held-back stream-end fragments as ordered events. Partial tool-call
|
|
399
|
+
* sections/envelopes are dropped by the delegated scanners; unterminated
|
|
400
|
+
* thinking blocks are emitted as thinking, matching the previous MiniMax parser
|
|
401
|
+
* behavior.
|
|
402
|
+
*/
|
|
403
|
+
flushEvents() {
|
|
404
|
+
const tail = this.#toolScanner ? this.#healThinking(this.#toolScanner.flush()) : [];
|
|
405
|
+
tail.push(...this.#thinkingScanner.flush());
|
|
406
|
+
return this.#convertScannerEvents(tail);
|
|
407
|
+
}
|
|
408
|
+
/** Flush held-back text only. Reconstructed calls are retained for {@link drainCompleted}. */
|
|
409
|
+
flushPending() {
|
|
410
|
+
let clean = "";
|
|
411
|
+
for (const event of this.flushEvents()) if (event.type === "text") clean += event.text;
|
|
412
|
+
else if (event.type === "toolCall") this.#completed.push(event.call);
|
|
413
|
+
return clean;
|
|
414
|
+
}
|
|
415
|
+
/** True once any configured tool-call section/envelope has fully closed. */
|
|
416
|
+
get sectionClosed() {
|
|
417
|
+
return this.#sectionTerminated;
|
|
418
|
+
}
|
|
419
|
+
#markSectionClosed(text) {
|
|
420
|
+
if (this.#sectionTerminated || !this.#toolScanner) return;
|
|
421
|
+
if (this.#pattern === "kimi") {
|
|
422
|
+
this.#sectionTerminated = text.includes(KIMI_SECTION_END);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
this.#sectionTerminated = text.includes(DSML_TOOL_CALLS_CLOSE_FULLWIDTH) || text.includes(DSML_TOOL_CALLS_CLOSE_ASCII);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Re-scan the tool scanner's visible text through the always-on thinking
|
|
429
|
+
* healer: `text` events are healed for leaked reasoning idioms, while the tool
|
|
430
|
+
* scanner's own thinking / tool-call events pass through in stream order.
|
|
431
|
+
*/
|
|
432
|
+
#healThinking(toolEvents) {
|
|
433
|
+
const out = [];
|
|
434
|
+
for (const event of toolEvents) if (event.type === "text") out.push(...this.#thinkingScanner.feed(event.text));
|
|
435
|
+
else out.push(event);
|
|
436
|
+
return out;
|
|
437
|
+
}
|
|
438
|
+
#convertScannerEvents(events) {
|
|
439
|
+
const out = [];
|
|
440
|
+
for (const event of events) switch (event.type) {
|
|
441
|
+
case "text":
|
|
442
|
+
out.push({
|
|
443
|
+
type: "text",
|
|
444
|
+
text: event.text
|
|
445
|
+
});
|
|
446
|
+
break;
|
|
447
|
+
case "thinkingDelta":
|
|
448
|
+
if (event.delta.length > 0) out.push({
|
|
449
|
+
type: "thinking",
|
|
450
|
+
thinking: event.delta
|
|
451
|
+
});
|
|
452
|
+
break;
|
|
453
|
+
case "toolEnd": out.push({
|
|
454
|
+
type: "toolCall",
|
|
455
|
+
call: {
|
|
456
|
+
id: generateHealedToolCallId(),
|
|
457
|
+
name: event.name,
|
|
458
|
+
arguments: JSON.stringify(event.arguments)
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
function generateHealedToolCallId() {
|
|
466
|
+
return `call_${crypto.randomUUID().replace(/-/g, "").slice(0, 24)}`;
|
|
467
|
+
}
|
|
468
|
+
/** Cheap model/provider gate for Kimi-K2 chat-template token leaks. */
|
|
469
|
+
function modelMayLeakKimiToolCalls(provider, modelId) {
|
|
470
|
+
if (provider === "kimi-code" || provider === "moonshot") return true;
|
|
471
|
+
return /kimi[-/_.]?k2/i.test(modelId);
|
|
472
|
+
}
|
|
473
|
+
/** Cheap model/provider gate for DeepSeek DSML envelope leaks. */
|
|
474
|
+
function modelMayLeakDsmlToolCalls(provider, modelId) {
|
|
475
|
+
if (!isDeepseekModelIdOrName(modelId)) return false;
|
|
476
|
+
return provider === "ollama" || provider === "ollama-cloud" || provider === "nvidia" || provider === "deepseek" || provider === "fireworks" || provider === "nanogpt" || provider === "opencode-go" || provider === "openrouter";
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Pick the leaked-markup healer for an OpenAI-compatible / Ollama visible-text
|
|
480
|
+
* stream. Kimi chat-template tokens and DeepSeek DSML envelopes need their
|
|
481
|
+
* dedicated tool-call grammars; every other model uses `"thinking"`. All three
|
|
482
|
+
* patterns run the generic {@link ThinkingInbandScanner}, so leaked reasoning
|
|
483
|
+
* idioms (e.g. a Gemini ` ```thinking ` fence on OpenRouter) are always healed.
|
|
484
|
+
*/
|
|
485
|
+
function getStreamMarkupHealingPattern(provider, modelId) {
|
|
486
|
+
if (modelMayLeakKimiToolCalls(provider, modelId)) return "kimi";
|
|
487
|
+
if (modelMayLeakDsmlToolCalls(provider, modelId)) return "dsml";
|
|
488
|
+
return "thinking";
|
|
489
|
+
}
|
|
490
|
+
//#endregion
|
|
491
|
+
export { getStreamMarkupHealingPattern as n, StreamMarkupHealing as t };
|