fix(tools): map cursor-agent fileText arg to canonical content - #119
fix(tools): map cursor-agent fileText arg to canonical content#119Nomadcxx wants to merge 2 commits into
fileText arg to canonical content#119Conversation
cursor-agent 2026.07.17 carries full-file edit/write bodies under `fileText`, replacing the earlier `streamContent` field. ARG_KEY_ALIASES had no mapping for it, so the body was dropped and the write/edit reroute lost the content. Add `filetext -> content`; key normalization also covers `file_text`. Found by reading the cursor-agent client bundle directly.
|
Draft for refinement, not merge-ready. Verified by unit test (540/0), but still needs:
|
Nomadcxx
left a comment
There was a problem hiding this comment.
Review: fileText alias is correct, but it re-opens the edit→write reroute with the anti-clobber guard disabled
Verdict: Not merge-ready yet. The alias itself is right, but as written this PR re-enables edit→write reroutes for 2026.07.17+ agents while the suspicious-overwrite guard stays dark for exactly those payloads. Details below.
What checks out
- Correct, minimal fix.
resolveCanonicalArgKeylowercases + strips non-alphanumerics (tool-schema-compat.ts:263-266), so["filetext", "content"]coversfileText,file_text, andfiletextas described. - Schema-respect and collision handling are safe. A tool that legitimately declares
fileTextis skipped by normalization; an explicitcontentkey wins overfileTextwith the drop recorded incollisionKeys. - End-to-end path verified by tracing: edit
{path, fileText}→ alias →content→ edit repair setsnew_string→missing: [old_string]only → full-file hint →tryRerouteEditToWrite→ write carrying the content. Works forwrite/oc_write, snake_/camelCase schemas. - Correctly alias-only. Adding
fileTextto the local edit schema (defaults.ts:187) instead would trip the schema-respect skip and strand the body, sincehasEditBodydoesn't knowfileText. This is the right layer. streamContentback-compat retained (alias, reroute chain at lines 200-207,hasEditBodyat 738, local schema) — right call for agents ≤ 2026.07.09.- Tests reproduced locally: 540 pass / 0 fail.
Important — must fix before merge
1. detectSuspiciousStreamContentWrite never fires for fileText payloads.
hasStreamContentArg (runtime-interception.ts:877-879) only matches keys normalizing to streamcontent:
return Object.keys(args).some((key) => key.toLowerCase().replace(/[^a-z0-9]/g, "") === "streamcontent");Before this PR, fileText payloads never rerouted at all (body dropped, hint emitted — the bug being fixed), so the guard's blindness was moot. After this PR, fileText payloads reroute to write — but the guard that blocks a reroute when it would shrink an existing ≥5-line file to ≤10% lines and ≤10% bytes never fires for them. The hazard the guard models (suspicious/truncated full-file body clobbering a real file) is protocol-field-agnostic, and it's tested for streamContent (provider-runtime-interception.test.ts:649,687) but not fileText.
Fix:
function hasStreamContentArg(args: Record<string, unknown>): boolean {
return Object.keys(args).some((key) => {
const token = key.toLowerCase().replace(/[^a-z0-9]/g, "");
return token === "streamcontent" || token === "filetext";
});
}plus a regression test mirroring the existing suspicious-reroute tests with a fileText payload.
Minor
2. No reroute-path test for fileText. The new test covers only the direct write path, but the headline failure is the edit→write reroute. One test — edit call {path, fileText} with no old_string → tryRerouteEditToWrite → write carrying the content — would lock in the behavior.
3. Dead fileText fallback in the guard. runtime-interception.ts:823-824 reads args.fileText from the rerouted write args, but buildWriteArguments only ever emits {path|filePath, content} — fileText can never appear there. It reads as if the guard were already fileText-aware when it isn't; remove it when fixing #1.
Process notes
- The two open checklist items in the draft comment remain the right gates: live capture on 2026.07.17 confirming
fileTexton the wire (the premise is currently inferred from bundle reading), and keeping thestreamContentalias (yes, keep). - Worth documenting the
streamContent→fileTextdrift window (2026.07.09 → 2026.07.17) — this codebase now has three layers (ARG_KEY_ALIASES, the reroute chain, the guard) that each had to learn about protocol field renames independently.
The filetext alias re-enables edit-to-write reroutes for cursor-agent 2026.07.17+ full-file edit payloads, but hasStreamContentArg only matched the streamcontent token, so the anti-clobber guard (blocks reroutes that would shrink an existing file) never fired for those payloads. Match both tokens so the guard applies regardless of protocol field name. Also remove the dead fileText fallback when reading rerouted write args (buildWriteArguments only ever emits content), and add regression tests: fileText edit payloads reroute to write carrying the content, and suspicious fileText reroutes that would shrink an existing file are skipped. The guard test fails without the hasStreamContentArg change.
|
Follow-up to the review above: all three findings are now addressed on this branch in
Suite: 542 pass / 0 fail ( Still open before merge, per the draft checklist: a live capture on cursor-agent |
Summary
cursor-agent
2026.07.17carries full-file edit/write bodies underfileText(it replaced the earlierstreamContentfield).ARG_KEY_ALIASESinsrc/provider/tool-schema-compat.tshad no mapping for it, so the content was dropped and the write/edit reroute lost the body.Adds
["filetext", "content"]. Key normalization (lowercase + strip non-alphanumerics) means this one entry coversfileText,file_text, andfiletext.How it was found
Reading the cursor-agent client bundle directly (the binary is a shell launcher over readable Node.js). Its edit builder constructs full-file edits from
r.fileText, andstreamContentis absent from the2026.07.17build while present in2026.07.09— live protocol drift between builds.Test
normalizes fileText (cursor-agent full-file content) to contentbun run test:ci:unit: 540 pass / 0 fail