Skip to content

Edit tool fails on find/replace requests when unused optional fields are present #276

Description

@mathiasloh

Problem

The hoisted AFT edit tool rejects find/replace requests when unused line-range fields are also present in the same edits[] item.

The request fails with:

edit: edits[0] mixes find/replace and line-range fields

This can happen when the model or host serializer emits optional fields from both edit modes, even though only find/replace was intended.

Reproduction

Send the following to the hoisted edit tool:

{
  "path": "example.ts",
  "edits": [
    {
      "oldString": "before",
      "newString": "after",
      "startLine": 1,
      "endLine": 1,
      "content": ""
    }
  ]
}

The intended operation is a find/replace. The line-range fields are unused serializer/model fields, but their presence makes AFT treat the item as both a find/replace edit and a line-range edit.

Expected behavior

AFT should expose mutually exclusive edit-item shapes so that a find/replace item can contain only find/replace fields:

{
  "path": "example.ts",
  "edits": [
    {
      "oldString": "before",
      "newString": "after"
    }
  ]
}

A line-range item should remain a separate shape:

{
  "path": "example.ts",
  "edits": [
    {
      "startLine": 10,
      "endLine": 12,
      "content": "replacement"
    }
  ]
}

Genuinely mixed edits should continue to be rejected.

Likely cause

The public BatchEditParams schema defines all of these as optional fields on one object:

  • Find/replace: oldString, newString, replaceAll, occurrence
  • Line range: startLine, endLine, content

The schema does not express that these are two mutually exclusive shapes. AFT later checks which keys are present and rejects the mixed object, so the request is allowed by the model-facing schema and then rejected during normalization.

The current runtime check is reasonable for a genuinely mixed edit, but it cannot distinguish an intentionally empty line-1 deletion from serializer-generated line-range defaults once both modes have been sent. The schema should prevent the ambiguity at the source.

Proposed fixes

  1. Define edits[] as a union of two closed object shapes: find/replace and line range.
  2. Ensure unused optional fields are omitted rather than serialized as empty strings, null, or default values.
  3. Keep runtime rejection for meaningful mixed edits as a safety check.
  4. Add regression tests for find/replace items carrying empty/default line-range fields, alongside the existing tests for the opposite direction and null-valued fields.

This is a follow-up to #217 and #272, which address related sentinel cases but not this reverse combination of non-empty find/replace fields with line-range fields.

Environment

  • @cortexkit/aft-pi: 0.54.0
  • Pi with AFT's hoisted edit tool

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions