Stop falsely labeling log-reading tools as failed when they read stack traces
This commit is contained in:
@@ -628,6 +628,30 @@ function extractPreviewUrl(messages: ChatMessage[]): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
function summarizeForUI(raw: string): string {
|
||||
try {
|
||||
const p = JSON.parse(raw);
|
||||
if (p && typeof p === "object") {
|
||||
const clone = { ...p };
|
||||
// Strip massive payload fields so the UI gets intact JSON
|
||||
if (clone.result && typeof clone.result === 'object') {
|
||||
if (clone.result.log) clone.result.log = "...";
|
||||
if (clone.result.content) clone.result.content = "...";
|
||||
if (clone.result.listing) clone.result.listing = "...";
|
||||
}
|
||||
if (typeof clone.stdout === 'string' && clone.stdout.length > 200) {
|
||||
clone.stdout = clone.stdout.slice(0, 200) + "...";
|
||||
}
|
||||
if (typeof clone.stderr === 'string' && clone.stderr.length > 200) {
|
||||
clone.stderr = clone.stderr.slice(0, 200) + "...";
|
||||
}
|
||||
return JSON.stringify(clone);
|
||||
}
|
||||
} catch {}
|
||||
return raw.slice(0, 500);
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
await ensureChatTables();
|
||||
|
||||
@@ -1109,7 +1133,7 @@ export async function POST(request: Request) {
|
||||
emit({
|
||||
type: "tool_result",
|
||||
name: tc.name,
|
||||
result: result.slice(0, 500),
|
||||
result: summarizeForUI(result),
|
||||
});
|
||||
messages.push({
|
||||
role: "tool",
|
||||
@@ -1322,7 +1346,7 @@ export async function POST(request: Request) {
|
||||
emit({
|
||||
type: "tool_result",
|
||||
name: tc.name,
|
||||
result: result.slice(0, 500),
|
||||
result: summarizeForUI(result),
|
||||
});
|
||||
|
||||
messages.push({
|
||||
|
||||
@@ -284,11 +284,14 @@ function summarizeToolResult(result?: string): {
|
||||
}
|
||||
|
||||
// Plain-text heuristics
|
||||
// We explicitly ignore 'error' and 'exception' here because tools like dev_server_logs
|
||||
// or browser_console legitimately return stack traces when working correctly.
|
||||
// A raw string with 'error' inside it shouldn't auto-fail the tool execution pill.
|
||||
const lower = raw.toLowerCase();
|
||||
if (
|
||||
/(econnrefused|enoent|error|failed|traceback|exception|not found|permission denied|cannot)/.test(
|
||||
/(econnrefused|enoent|permission denied|command not found)/.test(
|
||||
lower,
|
||||
)
|
||||
) && !raw.includes("dev_server_logs") && !raw.includes("browser_console")
|
||||
) {
|
||||
return { ok: false, label: `Failed — ${firstLine(raw)}` };
|
||||
}
|
||||
@@ -1548,12 +1551,15 @@ export function ChatPanel({
|
||||
}
|
||||
} catch {
|
||||
// 2. If it's a raw string (like a bash crash), scan for fatal keywords
|
||||
// We skip this check for log-reading tools since they legitimately contain errors.
|
||||
const lower = ev.result.toLowerCase();
|
||||
if (
|
||||
lower.includes("error") ||
|
||||
lower.includes("failed") ||
|
||||
lower.includes("unexpected") ||
|
||||
lower.includes("not found")
|
||||
!ev.name?.includes("logs") &&
|
||||
!ev.name?.includes("console") &&
|
||||
(lower.includes("econnrefused") ||
|
||||
lower.includes("enoent") ||
|
||||
lower.includes("permission denied") ||
|
||||
lower.includes("command not found"))
|
||||
) {
|
||||
isToolErr = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user