@zhongqian97-code/ecode 0.5.5 → 0.5.7
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/dist/index.js +50 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -116,6 +116,7 @@ import { Box as Box6, useInput as useInput2, useStdout, useStdin } from "ink";
|
|
|
116
116
|
// src/providers/openai.ts
|
|
117
117
|
import OpenAI from "openai";
|
|
118
118
|
function createOpenAIProvider(profile) {
|
|
119
|
+
const THINK_END = "</think>";
|
|
119
120
|
const openai = new OpenAI({
|
|
120
121
|
baseURL: profile.baseUrl,
|
|
121
122
|
apiKey: profile.apiKey
|
|
@@ -151,6 +152,17 @@ function createOpenAIProvider(profile) {
|
|
|
151
152
|
let thinkPhase = "pre";
|
|
152
153
|
let scanningForClose = false;
|
|
153
154
|
let closeSearchBuffer = "";
|
|
155
|
+
let visibleTextTail = "";
|
|
156
|
+
function rememberVisibleText(text) {
|
|
157
|
+
if (!text) return;
|
|
158
|
+
visibleTextTail = (visibleTextTail + text).slice(-256);
|
|
159
|
+
}
|
|
160
|
+
function hasNearbyVisibleOpenThink(maxDistance = 4) {
|
|
161
|
+
const openIdx = visibleTextTail.lastIndexOf("<think>");
|
|
162
|
+
const closeIdx = visibleTextTail.lastIndexOf(THINK_END);
|
|
163
|
+
if (openIdx === -1 || openIdx < closeIdx) return false;
|
|
164
|
+
return visibleTextTail.length - (openIdx + "<think>".length) <= maxDistance;
|
|
165
|
+
}
|
|
154
166
|
function processContent(raw) {
|
|
155
167
|
if (!raw) return { text: "", thinking: "" };
|
|
156
168
|
if (thinkPhase === "post") return { text: raw, thinking: "" };
|
|
@@ -163,11 +175,11 @@ function createOpenAIProvider(profile) {
|
|
|
163
175
|
return { text: raw, thinking: "" };
|
|
164
176
|
}
|
|
165
177
|
}
|
|
166
|
-
const endIdx = raw.indexOf(
|
|
178
|
+
const endIdx = raw.indexOf(THINK_END);
|
|
167
179
|
if (endIdx === -1) return { text: "", thinking: raw };
|
|
168
180
|
const thinking = raw.slice(0, endIdx);
|
|
169
181
|
thinkPhase = "post";
|
|
170
|
-
return { text: raw.slice(endIdx +
|
|
182
|
+
return { text: raw.slice(endIdx + THINK_END.length), thinking };
|
|
171
183
|
}
|
|
172
184
|
const requestParams = {
|
|
173
185
|
model: profile.model,
|
|
@@ -234,9 +246,12 @@ function createOpenAIProvider(profile) {
|
|
|
234
246
|
rawToProcess = "";
|
|
235
247
|
} else if (scanningForClose) {
|
|
236
248
|
closeSearchBuffer += delta.content ?? "";
|
|
237
|
-
const closeIdx = closeSearchBuffer.indexOf(
|
|
249
|
+
const closeIdx = closeSearchBuffer.indexOf(THINK_END);
|
|
238
250
|
if (closeIdx !== -1) {
|
|
239
|
-
|
|
251
|
+
const openIdx = closeSearchBuffer.lastIndexOf("<think>", closeIdx);
|
|
252
|
+
const hasNearbyLiteralPair = openIdx !== -1 && closeIdx - (openIdx + "<think>".length) <= 8;
|
|
253
|
+
const afterClose = closeSearchBuffer.slice(closeIdx + THINK_END.length);
|
|
254
|
+
rawToProcess = hasNearbyLiteralPair ? closeSearchBuffer : afterClose.length > 0 ? afterClose : closeSearchBuffer.slice(0, closeIdx);
|
|
240
255
|
scanningForClose = false;
|
|
241
256
|
closeSearchBuffer = "";
|
|
242
257
|
thinkPhase = "post";
|
|
@@ -251,7 +266,11 @@ function createOpenAIProvider(profile) {
|
|
|
251
266
|
} else {
|
|
252
267
|
rawToProcess = delta.content ?? "";
|
|
253
268
|
}
|
|
269
|
+
if (thinkPhase === "post" && rawToProcess.endsWith(THINK_END) && !rawToProcess.includes("<think>") && !hasNearbyVisibleOpenThink()) {
|
|
270
|
+
rawToProcess = rawToProcess.slice(0, -THINK_END.length);
|
|
271
|
+
}
|
|
254
272
|
const { text: filteredText, thinking: thinkContent } = processContent(rawToProcess);
|
|
273
|
+
rememberVisibleText(filteredText);
|
|
255
274
|
if (thinkContent) {
|
|
256
275
|
reasoningAccumulator += thinkContent;
|
|
257
276
|
}
|
|
@@ -2115,12 +2134,13 @@ function confirmSelection(inputText, selectedPath) {
|
|
|
2115
2134
|
|
|
2116
2135
|
// src/ui/mouseInput.ts
|
|
2117
2136
|
var SGR_MOUSE_RE = /^\x1b\[<(\d+);\d+;\d+[Mm]/;
|
|
2118
|
-
function
|
|
2137
|
+
function mouseEventLength(data) {
|
|
2119
2138
|
const s = typeof data === "string" ? data : data.toString("binary");
|
|
2120
|
-
if (!s) return
|
|
2121
|
-
|
|
2122
|
-
if (
|
|
2123
|
-
return
|
|
2139
|
+
if (!s) return 0;
|
|
2140
|
+
const sgrMatch = SGR_MOUSE_RE.exec(s);
|
|
2141
|
+
if (sgrMatch) return sgrMatch[0].length;
|
|
2142
|
+
if (s.length >= 6 && s.charCodeAt(0) === 27 && s[1] === "[" && s[2] === "M") return 6;
|
|
2143
|
+
return 0;
|
|
2124
2144
|
}
|
|
2125
2145
|
function parseMouseScroll(data) {
|
|
2126
2146
|
const s = typeof data === "string" ? data : data.toString("binary");
|
|
@@ -2965,8 +2985,11 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
2965
2985
|
if (event === "readable") {
|
|
2966
2986
|
const chunk = stdin.read();
|
|
2967
2987
|
if (chunk !== null) {
|
|
2968
|
-
|
|
2969
|
-
|
|
2988
|
+
const s = typeof chunk === "string" ? chunk : chunk.toString("binary");
|
|
2989
|
+
const mouseLen = mouseEventLength(s);
|
|
2990
|
+
if (mouseLen > 0) {
|
|
2991
|
+
const mouseStr = s.slice(0, mouseLen);
|
|
2992
|
+
const scrollEvent = parseMouseScroll(mouseStr);
|
|
2970
2993
|
if (scrollEvent) {
|
|
2971
2994
|
if (scrollEvent.direction === "up") {
|
|
2972
2995
|
setScrollOffset((prev) => Math.min(prev + 3, Math.max(0, totalLinesRef.current - 1)));
|
|
@@ -2974,9 +2997,15 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
2974
2997
|
setScrollOffset((prev) => Math.max(0, prev - 3));
|
|
2975
2998
|
}
|
|
2976
2999
|
}
|
|
2977
|
-
|
|
3000
|
+
const remainder = s.slice(mouseLen);
|
|
3001
|
+
if (remainder.length > 0) {
|
|
3002
|
+
stdin.unshift(
|
|
3003
|
+
typeof chunk === "string" ? remainder : Buffer.from(remainder, "binary")
|
|
3004
|
+
);
|
|
3005
|
+
}
|
|
3006
|
+
} else {
|
|
3007
|
+
stdin.unshift(chunk);
|
|
2978
3008
|
}
|
|
2979
|
-
stdin.unshift(chunk);
|
|
2980
3009
|
}
|
|
2981
3010
|
}
|
|
2982
3011
|
return origEmit.apply(stdin, [event, ...args]);
|
|
@@ -3539,7 +3568,7 @@ var SkillRegistry = class {
|
|
|
3539
3568
|
};
|
|
3540
3569
|
|
|
3541
3570
|
// src/pipe.ts
|
|
3542
|
-
var PIPE_SYSTEM_PROMPT = "You are a helpful assistant running in headless pipe mode. You have access to read-only file tools (read, glob, grep). Answer concisely and accurately.";
|
|
3571
|
+
var PIPE_SYSTEM_PROMPT = "You are a helpful assistant running in headless pipe mode. You have access to read-only file tools (read, glob, grep). Answer concisely and accurately. Follow the user's requested language, format, and length exactly. Do not reveal chain-of-thought or emit raw <think> / </think> tags in the final answer; if you must refer to them, describe them in plain language instead.";
|
|
3543
3572
|
var PIPE_TOOLS = [READ_TOOL, GLOB_TOOL, GREP_TOOL];
|
|
3544
3573
|
function emit(out, event) {
|
|
3545
3574
|
out.write(JSON.stringify(event) + "\n");
|
|
@@ -3559,20 +3588,21 @@ async function executeToolCall(name, args) {
|
|
|
3559
3588
|
}
|
|
3560
3589
|
return `Unknown tool: ${name}`;
|
|
3561
3590
|
}
|
|
3562
|
-
async function runPipe(prompt, llm, out = process.stdout) {
|
|
3591
|
+
async function runPipe(prompt, llm, out = process.stdout, systemPrompt) {
|
|
3563
3592
|
const messages = [
|
|
3564
|
-
{ role: "system", content: PIPE_SYSTEM_PROMPT },
|
|
3593
|
+
{ role: "system", content: systemPrompt ?? PIPE_SYSTEM_PROMPT },
|
|
3565
3594
|
{ role: "user", content: prompt }
|
|
3566
3595
|
];
|
|
3567
3596
|
while (true) {
|
|
3568
3597
|
let assistantText = "";
|
|
3598
|
+
const pendingTextChunks = [];
|
|
3569
3599
|
let lastUsage;
|
|
3570
3600
|
let lastReasoning;
|
|
3571
3601
|
let lastReasoningDetails;
|
|
3572
3602
|
const toolCalls = [];
|
|
3573
3603
|
for await (const chunk of llm.stream(messages, PIPE_TOOLS)) {
|
|
3574
3604
|
if (chunk.text) {
|
|
3575
|
-
|
|
3605
|
+
pendingTextChunks.push(chunk.text);
|
|
3576
3606
|
assistantText += chunk.text;
|
|
3577
3607
|
}
|
|
3578
3608
|
if (chunk.reasoning) {
|
|
@@ -3604,6 +3634,9 @@ async function runPipe(prompt, llm, out = process.stdout) {
|
|
|
3604
3634
|
messages.push({ role: "tool", tool_call_id: tc.id, content });
|
|
3605
3635
|
}
|
|
3606
3636
|
} else {
|
|
3637
|
+
for (const text of pendingTextChunks) {
|
|
3638
|
+
emit(out, { type: "chunk", text });
|
|
3639
|
+
}
|
|
3607
3640
|
const doneEvent = lastUsage ? { type: "done", usage: lastUsage } : { type: "done" };
|
|
3608
3641
|
emit(out, doneEvent);
|
|
3609
3642
|
break;
|