fix(DIS-102): sanitize response before DB storage to break path feedback loop
The root cause was twofold: 1. Raw (unsanitized) agent responses were stored in the conversation history DB. On subsequent calls, these paths were fed back to the agent as context, causing it to reproduce full paths regardless of Discord-side sanitization. 2. repoRoot (workspace_path) was not passed to sanitizeForDiscord, so workspace-specific paths were only partially masked via the home directory fallback. Fix: sanitize the full response once before both sending to Discord and storing in the DB. Pass workspace_path as repoRoot for precise path replacement. Add Windows path tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5869c15f9d
commit
714e0c01e5
2 changed files with 38 additions and 5 deletions
|
|
@ -107,30 +107,43 @@ export async function routeMessage(
|
||||||
message.author.username
|
message.author.username
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Sanitize the full response once, then use the sanitized version
|
||||||
|
// for both Discord output and conversation history storage.
|
||||||
|
// This prevents a feedback loop where raw paths in stored history
|
||||||
|
// get fed back to the agent as context, causing it to reproduce them.
|
||||||
|
const sanitizeOpts = {
|
||||||
|
repoRoot: workspace.workspace_path,
|
||||||
|
home: os.homedir(),
|
||||||
|
};
|
||||||
|
const sanitizedResponse = sanitizeForDiscord(response, sanitizeOpts);
|
||||||
|
|
||||||
// Split and send response
|
// Split and send response
|
||||||
const chunks = splitMessage(response);
|
const chunks = splitMessage(sanitizedResponse);
|
||||||
let firstMsgId: string | null = null;
|
let firstMsgId: string | null = null;
|
||||||
|
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
const sent = await channel.send(sanitizeForDiscord(chunk, { home: os.homedir() }));
|
const sent = await channel.send(chunk);
|
||||||
if (!firstMsgId) {
|
if (!firstMsgId) {
|
||||||
firstMsgId = sent.id;
|
firstMsgId = sent.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store assistant response (use first message id for dedup)
|
// Store sanitized assistant response (use first message id for dedup)
|
||||||
if (firstMsgId) {
|
if (firstMsgId) {
|
||||||
db.addConversation(
|
db.addConversation(
|
||||||
workspace.id,
|
workspace.id,
|
||||||
firstMsgId,
|
firstMsgId,
|
||||||
"assistant",
|
"assistant",
|
||||||
response,
|
sanitizedResponse,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = error instanceof Error ? error.message : "Unbekannter Fehler";
|
const msg = error instanceof Error ? error.message : "Unbekannter Fehler";
|
||||||
const safeMsg = sanitizeForDiscord(`Fehler bei der Verarbeitung: ${msg}`, { home: os.homedir() });
|
const safeMsg = sanitizeForDiscord(`Fehler bei der Verarbeitung: ${msg}`, {
|
||||||
|
repoRoot: workspace.workspace_path,
|
||||||
|
home: os.homedir(),
|
||||||
|
});
|
||||||
await channel.send(safeMsg).catch(() => {});
|
await channel.send(safeMsg).catch(() => {});
|
||||||
} finally {
|
} finally {
|
||||||
clearInterval(typingInterval);
|
clearInterval(typingInterval);
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,24 @@ describe("sanitizeForDiscord", () => {
|
||||||
});
|
});
|
||||||
expect(result).toBe("<disclaw>/src/index.ts and ~/other.ts");
|
expect(result).toBe("<disclaw>/src/index.ts and ~/other.ts");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Windows-style backslash paths are sanitized
|
||||||
|
it("replaces Windows backslash paths", () => {
|
||||||
|
const text = "File at C:\\Users\\dev\\.disclaw\\workspaces\\agent-x\\src\\main.ts";
|
||||||
|
const result = sanitizeForDiscord(text, {
|
||||||
|
repoRoot: "C:\\Users\\dev\\.disclaw\\workspaces\\agent-x",
|
||||||
|
home: "C:\\Users\\dev",
|
||||||
|
});
|
||||||
|
expect(result).toBe("File at <disclaw>\\src\\main.ts");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mixed slash styles (common on Windows when tools output forward slashes)
|
||||||
|
it("replaces forward-slash variants of Windows paths", () => {
|
||||||
|
const text = "File at C:/Users/dev/.disclaw/workspaces/agent-x/src/main.ts";
|
||||||
|
const result = sanitizeForDiscord(text, {
|
||||||
|
repoRoot: "C:\\Users\\dev\\.disclaw\\workspaces\\agent-x",
|
||||||
|
home: "C:\\Users\\dev",
|
||||||
|
});
|
||||||
|
expect(result).toBe("File at <disclaw>/src/main.ts");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue