diff --git a/crates/pi-natives/src/ast.rs b/crates/pi-natives/src/ast.rs index 8e74dbc9f..1ecb55c76 100644 --- a/crates/pi-natives/src/ast.rs +++ b/crates/pi-natives/src/ast.rs @@ -517,20 +517,13 @@ fn normalize_rewrite_map( rewrites: Option>, ) -> Result> { let mut normalized = Vec::new(); - for (raw_pattern, raw_rewrite) in rewrites.unwrap_or_default() { - let pattern = raw_pattern.trim(); + for (pattern, rewrite) in rewrites.unwrap_or_default() { if pattern.is_empty() { return Err(Error::from_reason( "`rewrites` keys must be non-empty pattern strings".to_string(), )); } - let rewrite = raw_rewrite.trim(); - if rewrite.is_empty() { - return Err(Error::from_reason(format!( - "`rewrites[{pattern}]` must be a non-empty rewrite template" - ))); - } - normalized.push((pattern.to_string(), rewrite.to_string())); + normalized.push((pattern, rewrite)); } if normalized.is_empty() { return Err(Error::from_reason( diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 74649307c..1c3f120b4 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -20,6 +20,8 @@ ### Fixed +- `ast_replace` no longer rejects empty `out` values; an empty string now deletes matched nodes +- `ast_replace` no longer trims `pat` and `out` values, preserving intentional whitespace - `gemini_image` tool: corrected `responseModalities` values from `'Image'`/`'Text'` to uppercase `'IMAGE'`/`'TEXT'` matching the API enum ### Breaking Changes diff --git a/packages/coding-agent/src/tools/ast-replace.ts b/packages/coding-agent/src/tools/ast-replace.ts index 0e02f9f9a..1e93e4d1d 100644 --- a/packages/coding-agent/src/tools/ast-replace.ts +++ b/packages/coding-agent/src/tools/ast-replace.ts @@ -69,15 +69,10 @@ export class AstReplaceTool implements AgentTool> { return untilAborted(signal, async () => { const ops = params.ops.map((entry, index) => { - const pat = entry.pat.trim(); - const out = entry.out.trim(); - if (pat.length === 0) { + if (entry.pat.length === 0) { throw new ToolError(`\`ops[${index}].pat\` must be a non-empty pattern`); } - if (out.length === 0) { - throw new ToolError(`\`ops[${index}].out\` must be a non-empty replacement template`); - } - return [pat, out] as const; + return [entry.pat, entry.out] as const; }); if (ops.length === 0) { throw new ToolError("`ops` must include at least one op entry"); @@ -122,10 +117,7 @@ export class AstReplaceTool implements AgentTool { - const relative = path.relative(this.session.cwd, resolvedSearchPath).replace(/\\/g, "/"); - return relative.length === 0 ? "." : relative; - })(); + const scopePath = path.relative(this.session.cwd, resolvedSearchPath).replace(/\\/g, "/") || "."; let isDirectory: boolean; try { const stat = await Bun.file(resolvedSearchPath).stat();