mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-08 01:48:26 -10:00
fix(ui): tool-summary suffix-match bridges MCP-prefixed names
LiveRows.tsx already used `name === s || name.endsWith("_" + s)` so MCP
tools like `filesystem_read_file` picked up the same per-tool argument
summary as the bare local `read_file`. tool-summary.ts used exact-name
match only, so bridged tools fell through to the generic "first line +
size hint" path in the compact scrollback row. Switch to the same
suffix predicate; add a write_file branch while there. +3 tests
covering the bridged path + a non-underscore-prefix non-match.
This commit is contained in:
1 parent
98f19d1d47
commit
1de2349350
2 files changed
+37
-4
No files matched your search
@@ -123,9 +123,14 @@ function summarizeStructured(content: string): ToolSummary | null {
|
||||
* Per-tool-name overrides for cases where a smarter summary is cheap
|
||||
* to compute. Returning null means "fall through to the generic
|
||||
* summary path."
|
||||
*
|
||||
* Suffix-match is on purpose: MCP-bridged tools come in prefixed
|
||||
* (`filesystem_read_file`, `git_search_files`) and we want them to
|
||||
* pick up the same specialized summary as the bare local name.
|
||||
*/
|
||||
function summarizeKnownTool(toolName: string, content: string): ToolSummary | null {
|
||||
if (toolName === "read_file") {
|
||||
const hasSuffix = (s: string) => toolName === s || toolName.endsWith(`_${s}`);
|
||||
if (hasSuffix("read_file")) {
|
||||
const lines = formatLineCount(content);
|
||||
const bytes = formatBytes(content.length);
|
||||
const head = clip(
|
||||
@@ -137,11 +142,11 @@ function summarizeKnownTool(toolName: string, content: string): ToolSummary | nu
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
if (toolName === "list_directory" || toolName === "directory_tree") {
|
||||
if (hasSuffix("list_directory") || hasSuffix("directory_tree")) {
|
||||
const entries = content.split(/\r?\n/).filter((l) => l.trim()).length;
|
||||
return { summary: `${entries} entr${entries === 1 ? "y" : "ies"}`, isError: false };
|
||||
}
|
||||
if (toolName === "search_files" || toolName === "search_content") {
|
||||
if (hasSuffix("search_files") || hasSuffix("search_content")) {
|
||||
const matches = content.split(/\r?\n/).filter((l) => l.trim()).length;
|
||||
if (matches === 0) return { summary: "no matches", isError: false };
|
||||
const first = firstNonEmptyLine(content);
|
||||
@@ -150,7 +155,12 @@ function summarizeKnownTool(toolName: string, content: string): ToolSummary | nu
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
if (toolName === "run_command" || toolName === "run_background") {
|
||||
if (hasSuffix("write_file")) {
|
||||
const lines = formatLineCount(content);
|
||||
const bytes = formatBytes(content.length);
|
||||
return { summary: `wrote ${lines} · ${bytes}`, isError: false };
|
||||
}
|
||||
if (hasSuffix("run_command") || hasSuffix("run_background")) {
|
||||
// Native shell tools prepend "exit 0:" / "exit N:" or the result
|
||||
// already mentions exit code. Try to surface it.
|
||||
const exitMatch = content.match(/exit (?:code )?(-?\d+)/i);
|
||||
|
||||
@@ -99,6 +99,29 @@ describe("summarizeToolResult — known tools", () => {
|
||||
expect(out.isError).toBe(true);
|
||||
expect(out.summary).toMatch(/exit 1/);
|
||||
});
|
||||
|
||||
it("write_file: shows wrote line count + size", () => {
|
||||
const out = summarizeToolResult("write_file", "alpha\nbeta\ngamma\n");
|
||||
expect(out.isError).toBe(false);
|
||||
expect(out.summary).toMatch(/wrote/);
|
||||
expect(out.summary).toMatch(/4 lines/);
|
||||
});
|
||||
|
||||
it("MCP-bridged tools pick up the same summary via suffix match", () => {
|
||||
// `filesystem_read_file` should hit the read_file branch.
|
||||
const out = summarizeToolResult(
|
||||
"filesystem_read_file",
|
||||
"import { foo } from 'bar';\nexport function baz() {}\n",
|
||||
);
|
||||
expect(out.summary).toMatch(/lines/);
|
||||
expect(out.summary).toMatch(/import.*foo/);
|
||||
});
|
||||
|
||||
it("suffix match doesn't false-trigger on non-underscore prefixes", () => {
|
||||
// `myread_file` (no underscore separator) should NOT match read_file.
|
||||
const out = summarizeToolResult("myread_file", "anything");
|
||||
expect(out.summary).not.toMatch(/lines/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatDuration", () => {
|
||||
|
||||
Reference in new issue
Block a user