@zhongqian97-code/ecode 0.5.5 → 0.5.6
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 +31 -8
- 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
|
}
|
|
@@ -3539,7 +3558,7 @@ var SkillRegistry = class {
|
|
|
3539
3558
|
};
|
|
3540
3559
|
|
|
3541
3560
|
// 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.";
|
|
3561
|
+
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
3562
|
var PIPE_TOOLS = [READ_TOOL, GLOB_TOOL, GREP_TOOL];
|
|
3544
3563
|
function emit(out, event) {
|
|
3545
3564
|
out.write(JSON.stringify(event) + "\n");
|
|
@@ -3559,20 +3578,21 @@ async function executeToolCall(name, args) {
|
|
|
3559
3578
|
}
|
|
3560
3579
|
return `Unknown tool: ${name}`;
|
|
3561
3580
|
}
|
|
3562
|
-
async function runPipe(prompt, llm, out = process.stdout) {
|
|
3581
|
+
async function runPipe(prompt, llm, out = process.stdout, systemPrompt) {
|
|
3563
3582
|
const messages = [
|
|
3564
|
-
{ role: "system", content: PIPE_SYSTEM_PROMPT },
|
|
3583
|
+
{ role: "system", content: systemPrompt ?? PIPE_SYSTEM_PROMPT },
|
|
3565
3584
|
{ role: "user", content: prompt }
|
|
3566
3585
|
];
|
|
3567
3586
|
while (true) {
|
|
3568
3587
|
let assistantText = "";
|
|
3588
|
+
const pendingTextChunks = [];
|
|
3569
3589
|
let lastUsage;
|
|
3570
3590
|
let lastReasoning;
|
|
3571
3591
|
let lastReasoningDetails;
|
|
3572
3592
|
const toolCalls = [];
|
|
3573
3593
|
for await (const chunk of llm.stream(messages, PIPE_TOOLS)) {
|
|
3574
3594
|
if (chunk.text) {
|
|
3575
|
-
|
|
3595
|
+
pendingTextChunks.push(chunk.text);
|
|
3576
3596
|
assistantText += chunk.text;
|
|
3577
3597
|
}
|
|
3578
3598
|
if (chunk.reasoning) {
|
|
@@ -3604,6 +3624,9 @@ async function runPipe(prompt, llm, out = process.stdout) {
|
|
|
3604
3624
|
messages.push({ role: "tool", tool_call_id: tc.id, content });
|
|
3605
3625
|
}
|
|
3606
3626
|
} else {
|
|
3627
|
+
for (const text of pendingTextChunks) {
|
|
3628
|
+
emit(out, { type: "chunk", text });
|
|
3629
|
+
}
|
|
3607
3630
|
const doneEvent = lastUsage ? { type: "done", usage: lastUsage } : { type: "done" };
|
|
3608
3631
|
emit(out, doneEvent);
|
|
3609
3632
|
break;
|