dskcode 0.1.31 → 0.1.33
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 +116 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1175,7 +1175,7 @@ function formatArgsSummary(args) {
|
|
|
1175
1175
|
return ` ${truncated}`;
|
|
1176
1176
|
}
|
|
1177
1177
|
}
|
|
1178
|
-
function ToolCallBlock({ call
|
|
1178
|
+
function ToolCallBlock({ call }) {
|
|
1179
1179
|
const argsDisplay = formatArgsSummary(call.arguments);
|
|
1180
1180
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: [
|
|
1181
1181
|
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
@@ -1188,8 +1188,7 @@ function ToolCallBlock({ call, showPendingHint = true }) {
|
|
|
1188
1188
|
"\u2500".repeat(Math.max(1, 30 - call.name.length))
|
|
1189
1189
|
] })
|
|
1190
1190
|
] }),
|
|
1191
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay }) })
|
|
1192
|
-
showPendingHint && /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: "\u23F3 \u7B49\u5F85\u6267\u884C" }) })
|
|
1191
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay }) })
|
|
1193
1192
|
] });
|
|
1194
1193
|
}
|
|
1195
1194
|
|
|
@@ -2658,7 +2657,7 @@ var Reflector = class {
|
|
|
2658
2657
|
const reflections = [];
|
|
2659
2658
|
for (const item of items) {
|
|
2660
2659
|
if (item.result.success) continue;
|
|
2661
|
-
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
|
|
2660
|
+
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#ruleTextNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
|
|
2662
2661
|
if (r) reflections.push(r);
|
|
2663
2662
|
if (reflections.length >= this.#maxReflections) break;
|
|
2664
2663
|
}
|
|
@@ -2734,6 +2733,26 @@ var Reflector = class {
|
|
|
2734
2733
|
hint: `\`${item.name}\` \u5931\u8D25\uFF1A\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u7528 \`ls\` / \`glob\` \u770B\u4E00\u4E0B\u76EE\u5F55\u7ED3\u6784\uFF0C\u6216\u786E\u8BA4\u8DEF\u5F84\u62FC\u5199\uFF08\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u89C1 system prompt\uFF09\u3002`
|
|
2735
2734
|
};
|
|
2736
2735
|
}
|
|
2736
|
+
/**
|
|
2737
|
+
* R2.5 文本未找到:edit_file / multi_edit 报 TEXT_NOT_FOUND 或 TEXT_MULTIPLE_MATCHES。
|
|
2738
|
+
*
|
|
2739
|
+
* 这是编辑工具最高频的失败。工具内部已对 CRLF 做归一化,仍报此错通常是
|
|
2740
|
+
* old_text 与当前文件内容不一致(缩进 / 已被改过 / 多次出现)。给一条明确
|
|
2741
|
+
* 的「重新读文件、逐字复制」指引,避免模型用同一份旧 old_text 反复重试。
|
|
2742
|
+
*
|
|
2743
|
+
* @pure 仅读入参
|
|
2744
|
+
*/
|
|
2745
|
+
#ruleTextNotFound(item) {
|
|
2746
|
+
const isTextErr = item.result.error === "TEXT_NOT_FOUND" || item.result.error === "TEXT_MULTIPLE_MATCHES";
|
|
2747
|
+
if (!isTextErr) return null;
|
|
2748
|
+
const multiple = item.result.error === "TEXT_MULTIPLE_MATCHES";
|
|
2749
|
+
const hint = multiple ? `\`${item.name}\`\uFF1Aold_text \u5728\u6587\u4EF6\u4E2D\u51FA\u73B0\u591A\u6B21\u3002\u8BF7\u8865\u5145\u4E0A\u4E0B\u6587\u8BA9 old_text \u552F\u4E00\uFF0C\u6216\u6539\u7528 multi_edit \u7684 replaceAll\u3002` : `\`${item.name}\`\uFF1A\u672A\u627E\u5230 old_text\u3002\u8BF7\u91CD\u65B0 \`read_file\` \u770B\u5F53\u524D\u5185\u5BB9\uFF0C\u9010\u5B57\u590D\u5236\u8981\u66FF\u6362\u7684\u7247\u6BB5\uFF08\u6CE8\u610F\u7F29\u8FDB\u4E0E\u7A7A\u683C\uFF09\uFF1B\u884C\u5C3E\u5DF2\u505A CRLF \u5F52\u4E00\u5316\uFF0C\u65E0\u9700\u624B\u5199 \\r\\n\u3002`;
|
|
2750
|
+
return {
|
|
2751
|
+
category: "text_not_found",
|
|
2752
|
+
toolName: item.name,
|
|
2753
|
+
hint
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2737
2756
|
/**
|
|
2738
2757
|
* R3 权限拒绝:GATE_DENIED 错误码 或 data 含 EACCES / permission / denied(不区分大小写)。
|
|
2739
2758
|
*
|
|
@@ -2751,13 +2770,19 @@ var Reflector = class {
|
|
|
2751
2770
|
};
|
|
2752
2771
|
}
|
|
2753
2772
|
/**
|
|
2754
|
-
* R4 写根外:kind ∈ Edit/Delete/Move
|
|
2773
|
+
* R4 写根外:kind ∈ Edit/Delete/Move 且错误码为 OUTSIDE_WRITE_ROOTS。
|
|
2774
|
+
*
|
|
2775
|
+
* 仅在工具本身明确报「路径超出写根」时才命中。旧实现只要写类工具失败就
|
|
2776
|
+
* 触发,会把 TEXT_NOT_FOUND / EXECUTION_ERROR 等误报为「写根外」,注入
|
|
2777
|
+
* 误导性提示(见会话日志 e65f0205 round 13:edit_file 因 CRLF 失配返回
|
|
2778
|
+
* TEXT_NOT_FOUND,却被反射为 out_of_write_root)。
|
|
2755
2779
|
*
|
|
2756
2780
|
* @pure 仅读入参
|
|
2757
2781
|
*/
|
|
2758
2782
|
#ruleOutOfWriteRoot(item, writeRoots) {
|
|
2759
2783
|
const isWriteKind = item.kind === "edit" /* Edit */ || item.kind === "delete" /* Delete */ || item.kind === "move" /* Move */;
|
|
2760
2784
|
if (!isWriteKind) return null;
|
|
2785
|
+
if (item.result.error !== "OUTSIDE_WRITE_ROOTS") return null;
|
|
2761
2786
|
const primary = writeRoots[0] ?? "<\u672A\u914D\u7F6E>";
|
|
2762
2787
|
return {
|
|
2763
2788
|
category: "out_of_write_root",
|
|
@@ -4335,8 +4360,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
|
|
|
4335
4360
|
var DEFAULT_MAX_OUTPUT_LENGTH = 5e4;
|
|
4336
4361
|
var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
4337
4362
|
var isWindows = process2.platform === "win32";
|
|
4363
|
+
function stripMentionPrefix(inputPath) {
|
|
4364
|
+
if (inputPath.startsWith("@")) return inputPath.slice(1);
|
|
4365
|
+
return inputPath;
|
|
4366
|
+
}
|
|
4338
4367
|
function resolvePath(inputPath, cwd) {
|
|
4339
|
-
const
|
|
4368
|
+
const stripped = stripMentionPrefix(inputPath);
|
|
4369
|
+
const resolved = isAbsolute(stripped) ? stripped : resolve(cwd, stripped);
|
|
4340
4370
|
return resolve(resolved);
|
|
4341
4371
|
}
|
|
4342
4372
|
async function realPath(target) {
|
|
@@ -4732,6 +4762,10 @@ function detectEol(text) {
|
|
|
4732
4762
|
function hasTrailingNewline(text) {
|
|
4733
4763
|
return text.endsWith("\n") || text.endsWith("\r\n");
|
|
4734
4764
|
}
|
|
4765
|
+
function toLf(text) {
|
|
4766
|
+
if (!text.includes("\r")) return text;
|
|
4767
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
4768
|
+
}
|
|
4735
4769
|
function normalizeEol(originalContent, newContent) {
|
|
4736
4770
|
const targetEol = detectEol(originalContent);
|
|
4737
4771
|
const lines = newContent.replace(/\r\n/g, "\n").split("\n");
|
|
@@ -4823,7 +4857,7 @@ var readFileTool = {
|
|
|
4823
4857
|
}
|
|
4824
4858
|
}
|
|
4825
4859
|
const content = await readFile5(filePath, "utf-8");
|
|
4826
|
-
const lines = content.split("\n");
|
|
4860
|
+
const lines = toLf(content).split("\n");
|
|
4827
4861
|
if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
|
|
4828
4862
|
lines.pop();
|
|
4829
4863
|
}
|
|
@@ -4931,6 +4965,7 @@ var writeFileTool = {
|
|
|
4931
4965
|
|
|
4932
4966
|
// src/tool/builtins/edit-file.ts
|
|
4933
4967
|
import { readFile as readFile7 } from "fs/promises";
|
|
4968
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
4934
4969
|
import { basename as basename3 } from "path";
|
|
4935
4970
|
var editFileTool = {
|
|
4936
4971
|
name: "edit_file",
|
|
@@ -4974,7 +5009,9 @@ var editFileTool = {
|
|
|
4974
5009
|
}
|
|
4975
5010
|
try {
|
|
4976
5011
|
const content = await readFile7(filePath, "utf-8");
|
|
4977
|
-
const
|
|
5012
|
+
const contentN = toLf(content);
|
|
5013
|
+
const oldTextN = toLf(args.old_text);
|
|
5014
|
+
const firstIndex = contentN.indexOf(oldTextN);
|
|
4978
5015
|
if (firstIndex === -1) {
|
|
4979
5016
|
return {
|
|
4980
5017
|
success: false,
|
|
@@ -4982,7 +5019,7 @@ var editFileTool = {
|
|
|
4982
5019
|
error: "TEXT_NOT_FOUND"
|
|
4983
5020
|
};
|
|
4984
5021
|
}
|
|
4985
|
-
const secondIndex =
|
|
5022
|
+
const secondIndex = contentN.indexOf(oldTextN, firstIndex + 1);
|
|
4986
5023
|
if (secondIndex !== -1) {
|
|
4987
5024
|
return {
|
|
4988
5025
|
success: false,
|
|
@@ -4990,14 +5027,15 @@ var editFileTool = {
|
|
|
4990
5027
|
error: "TEXT_MULTIPLE_MATCHES"
|
|
4991
5028
|
};
|
|
4992
5029
|
}
|
|
4993
|
-
const
|
|
4994
|
-
|
|
4995
|
-
|
|
5030
|
+
const newContentN = contentN.slice(0, firstIndex) + toLf(args.new_text) + contentN.slice(firstIndex + oldTextN.length);
|
|
5031
|
+
const writtenContent = normalizeEol(content, newContentN);
|
|
5032
|
+
await writeFile5(filePath, writtenContent, "utf-8");
|
|
5033
|
+
const diff = computeFileDiff(content, writtenContent, filePath);
|
|
4996
5034
|
diff.existedBefore = true;
|
|
4997
|
-
const beforeText =
|
|
5035
|
+
const beforeText = contentN.slice(0, firstIndex);
|
|
4998
5036
|
const startLine = beforeText.split("\n").length;
|
|
4999
|
-
const oldLines =
|
|
5000
|
-
const newLines = args.new_text.split("\n").length;
|
|
5037
|
+
const oldLines = oldTextN.split("\n").length;
|
|
5038
|
+
const newLines = toLf(args.new_text).split("\n").length;
|
|
5001
5039
|
const diffSummary = `+${diff.additions} -${diff.deletions}`;
|
|
5002
5040
|
const summary = `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (+${diff.additions} -${diff.deletions})`;
|
|
5003
5041
|
return {
|
|
@@ -5022,6 +5060,7 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
|
|
|
5022
5060
|
|
|
5023
5061
|
// src/tool/builtins/multi-edit.ts
|
|
5024
5062
|
import { readFile as readFile8 } from "fs/promises";
|
|
5063
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
5025
5064
|
import { basename as basename4 } from "path";
|
|
5026
5065
|
var multiEditTool = {
|
|
5027
5066
|
name: "multi_edit",
|
|
@@ -5068,7 +5107,7 @@ var multiEditTool = {
|
|
|
5068
5107
|
}
|
|
5069
5108
|
try {
|
|
5070
5109
|
const originalContent = await readFile8(filePath, "utf-8");
|
|
5071
|
-
let currentContent = originalContent;
|
|
5110
|
+
let currentContent = toLf(originalContent);
|
|
5072
5111
|
for (let idx = 0; idx < args.edits.length; idx++) {
|
|
5073
5112
|
const step = args.edits[idx];
|
|
5074
5113
|
if (typeof step.oldText !== "string") {
|
|
@@ -5078,10 +5117,19 @@ var multiEditTool = {
|
|
|
5078
5117
|
error: "INVALID_STEP_ARGS"
|
|
5079
5118
|
};
|
|
5080
5119
|
}
|
|
5120
|
+
if (typeof step.newText !== "string") {
|
|
5121
|
+
return {
|
|
5122
|
+
success: false,
|
|
5123
|
+
data: `\u7B2C ${idx + 1} \u6B65\uFF1A\u7F3A\u5C11\u6709\u6548\u7684 newText`,
|
|
5124
|
+
error: "INVALID_STEP_ARGS"
|
|
5125
|
+
};
|
|
5126
|
+
}
|
|
5127
|
+
const oldTextN = toLf(step.oldText);
|
|
5128
|
+
const newTextN = toLf(step.newText);
|
|
5081
5129
|
if (step.replaceAll) {
|
|
5082
5130
|
let count = 0;
|
|
5083
5131
|
let pos = -1;
|
|
5084
|
-
while ((pos = currentContent.indexOf(
|
|
5132
|
+
while ((pos = currentContent.indexOf(oldTextN, pos + 1)) !== -1) {
|
|
5085
5133
|
count++;
|
|
5086
5134
|
}
|
|
5087
5135
|
if (count === 0) {
|
|
@@ -5091,9 +5139,9 @@ var multiEditTool = {
|
|
|
5091
5139
|
error: "TEXT_NOT_FOUND"
|
|
5092
5140
|
};
|
|
5093
5141
|
}
|
|
5094
|
-
currentContent = currentContent.split(
|
|
5142
|
+
currentContent = currentContent.split(oldTextN).join(newTextN);
|
|
5095
5143
|
} else {
|
|
5096
|
-
const firstIdx = currentContent.indexOf(
|
|
5144
|
+
const firstIdx = currentContent.indexOf(oldTextN);
|
|
5097
5145
|
if (firstIdx === -1) {
|
|
5098
5146
|
return {
|
|
5099
5147
|
success: false,
|
|
@@ -5101,7 +5149,7 @@ var multiEditTool = {
|
|
|
5101
5149
|
error: "TEXT_NOT_FOUND"
|
|
5102
5150
|
};
|
|
5103
5151
|
}
|
|
5104
|
-
const secondIdx = currentContent.indexOf(
|
|
5152
|
+
const secondIdx = currentContent.indexOf(oldTextN, firstIdx + 1);
|
|
5105
5153
|
if (secondIdx !== -1) {
|
|
5106
5154
|
return {
|
|
5107
5155
|
success: false,
|
|
@@ -5109,11 +5157,12 @@ var multiEditTool = {
|
|
|
5109
5157
|
error: "TEXT_MULTIPLE_MATCHES"
|
|
5110
5158
|
};
|
|
5111
5159
|
}
|
|
5112
|
-
currentContent = currentContent.
|
|
5160
|
+
currentContent = currentContent.slice(0, firstIdx) + newTextN + currentContent.slice(firstIdx + oldTextN.length);
|
|
5113
5161
|
}
|
|
5114
5162
|
}
|
|
5115
|
-
|
|
5116
|
-
|
|
5163
|
+
const writtenContent = normalizeEol(originalContent, currentContent);
|
|
5164
|
+
await writeFile6(filePath, writtenContent, "utf-8");
|
|
5165
|
+
const diff = computeFileDiff(originalContent, writtenContent, filePath);
|
|
5117
5166
|
diff.existedBefore = true;
|
|
5118
5167
|
return {
|
|
5119
5168
|
success: true,
|
|
@@ -5136,11 +5185,13 @@ var multiEditTool = {
|
|
|
5136
5185
|
|
|
5137
5186
|
// src/tool/builtins/delete-range.ts
|
|
5138
5187
|
import { readFile as readFile9 } from "fs/promises";
|
|
5188
|
+
import { writeFile as writeFile7 } from "fs/promises";
|
|
5139
5189
|
import { basename as basename5 } from "path";
|
|
5140
5190
|
function findUniqueLine(lines, anchor, label) {
|
|
5191
|
+
const anchorN = toLf(anchor);
|
|
5141
5192
|
const matches = [];
|
|
5142
5193
|
for (let i = 0; i < lines.length; i++) {
|
|
5143
|
-
if (lines[i] ===
|
|
5194
|
+
if (toLf(lines[i]) === anchorN) {
|
|
5144
5195
|
matches.push(i);
|
|
5145
5196
|
}
|
|
5146
5197
|
}
|
|
@@ -5199,7 +5250,7 @@ var deleteRangeTool = {
|
|
|
5199
5250
|
}
|
|
5200
5251
|
try {
|
|
5201
5252
|
const content = await readFile9(filePath, "utf-8");
|
|
5202
|
-
const lines = content.split("\n");
|
|
5253
|
+
const lines = toLf(content).split("\n");
|
|
5203
5254
|
const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
|
|
5204
5255
|
if ("error" in startResult) {
|
|
5205
5256
|
return { success: false, data: startResult.error, error: "ANCHOR_NOT_FOUND" };
|
|
@@ -5227,9 +5278,10 @@ var deleteRangeTool = {
|
|
|
5227
5278
|
};
|
|
5228
5279
|
}
|
|
5229
5280
|
const newLines = [...lines.slice(0, rangeStart), ...lines.slice(rangeEnd + 1)];
|
|
5230
|
-
const
|
|
5231
|
-
|
|
5232
|
-
|
|
5281
|
+
const newContentN = newLines.join("\n");
|
|
5282
|
+
const writtenContent = normalizeEol(content, newContentN);
|
|
5283
|
+
await writeFile7(filePath, writtenContent, "utf-8");
|
|
5284
|
+
const diff = computeFileDiff(content, writtenContent, filePath);
|
|
5233
5285
|
diff.existedBefore = true;
|
|
5234
5286
|
const deletedLines = rangeEnd - rangeStart + 1;
|
|
5235
5287
|
const summary = `\u{1F4DD} \u4FEE\u6539: ${basename5(filePath)} (\u5220 ${deletedLines} \u884C, +${diff.additions} -${diff.deletions})`;
|
|
@@ -5425,7 +5477,8 @@ var globTool = {
|
|
|
5425
5477
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
5426
5478
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
5427
5479
|
}
|
|
5428
|
-
const
|
|
5480
|
+
const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
|
|
5481
|
+
const searchDir = dir ? isAbsolute2(dir) ? dir : join7(ctx.cwd, dir) : ctx.cwd;
|
|
5429
5482
|
const regex = globToRegex(args.pattern);
|
|
5430
5483
|
try {
|
|
5431
5484
|
const dirStat = await stat2(searchDir);
|
|
@@ -5526,7 +5579,8 @@ var grepTool = {
|
|
|
5526
5579
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
5527
5580
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
5528
5581
|
}
|
|
5529
|
-
const
|
|
5582
|
+
const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
|
|
5583
|
+
const searchDir = dir ? isAbsolute3(dir) ? dir : join8(ctx.cwd, dir) : ctx.cwd;
|
|
5530
5584
|
const maxFiles = args.max_files ?? 200;
|
|
5531
5585
|
try {
|
|
5532
5586
|
const flags = args.case_sensitive ? "g" : "gi";
|
|
@@ -5836,6 +5890,11 @@ var PHASE_CONFIG = {
|
|
|
5836
5890
|
function isFileMutatingTool(name) {
|
|
5837
5891
|
return name === "edit_file" || name === "write_file" || name === "multi_edit" || name === "delete_range";
|
|
5838
5892
|
}
|
|
5893
|
+
function filterTodoToolCalls(calls) {
|
|
5894
|
+
if (!calls) return void 0;
|
|
5895
|
+
const filtered = calls.filter((tc) => !tc.name.startsWith("todo_"));
|
|
5896
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
5897
|
+
}
|
|
5839
5898
|
var commandRegistry = /* @__PURE__ */ new Map();
|
|
5840
5899
|
function registerCommand(name, cmd) {
|
|
5841
5900
|
commandRegistry.set(name, cmd);
|
|
@@ -5957,6 +6016,8 @@ function ChatSession({
|
|
|
5957
6016
|
const [_streamingModel, setStreamingModel] = useState4(void 0);
|
|
5958
6017
|
const [streamError, setStreamError] = useState4(void 0);
|
|
5959
6018
|
const [todoSnapshot, setTodoSnapshot] = useState4([]);
|
|
6019
|
+
const [todoPanelVisible, setTodoPanelVisible] = useState4(true);
|
|
6020
|
+
const todoHideTimerRef = useRef3(null);
|
|
5960
6021
|
const [sessionMode, setSessionMode] = useState4("code");
|
|
5961
6022
|
const [thinkingEnabled, setThinkingEnabled] = useState4(true);
|
|
5962
6023
|
const [thinkingEffort, setThinkingEffort] = useState4("high");
|
|
@@ -6014,6 +6075,20 @@ function ChatSession({
|
|
|
6014
6075
|
}
|
|
6015
6076
|
};
|
|
6016
6077
|
}, []);
|
|
6078
|
+
useEffect4(() => {
|
|
6079
|
+
if (todoHideTimerRef.current) {
|
|
6080
|
+
clearTimeout(todoHideTimerRef.current);
|
|
6081
|
+
todoHideTimerRef.current = null;
|
|
6082
|
+
}
|
|
6083
|
+
if (todoSnapshot.length === 0) {
|
|
6084
|
+
setTodoPanelVisible(false);
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
const hasUnfinished = todoSnapshot.some(
|
|
6088
|
+
(it) => it.status === "pending" || it.status === "running" || it.status === "failed"
|
|
6089
|
+
);
|
|
6090
|
+
setTodoPanelVisible(hasUnfinished);
|
|
6091
|
+
}, [todoSnapshot]);
|
|
6017
6092
|
const getFilteredSkills = useCallback2(
|
|
6018
6093
|
(value) => {
|
|
6019
6094
|
const match = value.match(/(?:^|\s)\/([^/]*)$/);
|
|
@@ -6055,7 +6130,7 @@ function ChatSession({
|
|
|
6055
6130
|
content: m.content,
|
|
6056
6131
|
assistantDetail: {
|
|
6057
6132
|
content: m.content,
|
|
6058
|
-
toolCalls: m.toolCalls
|
|
6133
|
+
toolCalls: filterTodoToolCalls(m.toolCalls)
|
|
6059
6134
|
}
|
|
6060
6135
|
});
|
|
6061
6136
|
} else if (m.role === "tool") {
|
|
@@ -6721,7 +6796,14 @@ function ChatSession({
|
|
|
6721
6796
|
currentToolCallsRef.current = [];
|
|
6722
6797
|
const r = event.result;
|
|
6723
6798
|
if (event.name.startsWith("todo_") && event.todoSnapshot) {
|
|
6724
|
-
|
|
6799
|
+
const allTerminated = event.todoSnapshot.length > 0 && event.todoSnapshot.every(
|
|
6800
|
+
(it) => it.status === "done" || it.status === "failed" || it.status === "skipped"
|
|
6801
|
+
);
|
|
6802
|
+
if (allTerminated) {
|
|
6803
|
+
setTodoSnapshot([]);
|
|
6804
|
+
} else {
|
|
6805
|
+
setTodoSnapshot(event.todoSnapshot);
|
|
6806
|
+
}
|
|
6725
6807
|
} else {
|
|
6726
6808
|
const line = r.success ? r.summary ?? `\u2705 ${event.name}: ${r.data.slice(0, 500)}${r.data.length > 500 ? "..." : ""}` : `\u274C ${event.name}: ${r.error ?? "\u6267\u884C\u5931\u8D25"}`;
|
|
6727
6809
|
setDisplayMessages((prev) => [
|
|
@@ -6769,7 +6851,7 @@ function ChatSession({
|
|
|
6769
6851
|
abortRef.current = null;
|
|
6770
6852
|
const finContent = currentContentRef.current;
|
|
6771
6853
|
const finReasoning = currentReasoningRef.current.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6772
|
-
const finToolCalls = currentToolCallsRef.current
|
|
6854
|
+
const finToolCalls = filterTodoToolCalls(currentToolCallsRef.current);
|
|
6773
6855
|
const finStreamError = streamErrorRef.current;
|
|
6774
6856
|
if (finContent || finToolCalls || finStreamError) {
|
|
6775
6857
|
const completed = {
|
|
@@ -6944,7 +7026,7 @@ function ChatSession({
|
|
|
6944
7026
|
streamError
|
|
6945
7027
|
] }) })
|
|
6946
7028
|
] }),
|
|
6947
|
-
todoSnapshot.length > 0 && /* @__PURE__ */ jsx10(TodoListPanel, { items: todoSnapshot }),
|
|
7029
|
+
todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx10(TodoListPanel, { items: todoSnapshot }),
|
|
6948
7030
|
selectingModel ? /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
6949
7031
|
/* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
6950
7032
|
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|