Skip to content

fix(tools): coerce stringified array params in tool calls#49

Merged
electron-rare merged 1 commit into
masterfrom
fix/cli-tool-array-coercion
Jun 1, 2026
Merged

fix(tools): coerce stringified array params in tool calls#49
electron-rare merged 1 commit into
masterfrom
fix/cli-tool-array-coercion

Conversation

@electron-rare
Copy link
Copy Markdown

Problem

ISAAC's native function-calling uses batch/plural array paramsread_file/list_files take paths, execute_command takes commands, and the symbol/skeleton/search/diagnostics tools take paths/symbols. Intermittently the worker/relay delivers an array argument as its JSON-stringified form (the literal string '["README.md"]' instead of the array ["README.md"]).

The handlers' old logic Array.isArray(x) ? x : (x ? [x] : []) then wrapped the whole bracketed string as a single path/command:

⏺ Error: read_file ["README.md"] → ENOENT
⏺ Error: Dirac tried to use read_file without providing a value for 'paths'. Retrying...

→ ENOENT on a bracketed path, no-op/failing shell commands, and an agent retry loop that never advances.

Fix

New helper src/core/task/tools/utils/coerceArray.ts:

  • coerceToStringArray(value) — real arrays pass through (members String()-ified); a string that trims to [...] is JSON.parsed back into an array (falling back to single-value wrap on parse failure / non-array); other non-empty strings wrap to [value]; nullish/empty → [].
  • coerceFirstStringArray(...candidates) — returns the first non-empty coercion, preserving the singular path/symbol fallback where handlers support it.

Routed 9 handlers through the helpers: ReadFile, ListFiles, ExecuteCommand, GetFunction, GetFileSkeleton, DiagnosticsScan, RenameSymbol, FindSymbolReferences, SearchFiles. The ExecuteCommand array-handling was simplified to a uniform for…of (rawCommands is now always string[]).

Object-array params (replace_symbol replacements, edit_file files) are intentionally left untouched — they are not string arrays.

Verification

  • check-types ✅, biome lint ✅ (1563 files)
  • mocha full suite ✅ 1366 passing / 0 failing (12 new helper tests)
  • End-to-end via isaac: list_filespaths:["."] and read_filepaths:["README.md"] now receive real arrays, task completes with no retry loop.

🤖 Generated with Claude Code

Native tool calls deliver batch params (read_file/list_files `paths`,
execute_command `commands`, get_function/get_file_skeleton/search_files/
diagnostics_scan/rename_symbol/find_symbol_references `paths`/`symbols`)
as real arrays. Intermittently an array argument arrives as its
JSON-stringified form, e.g. the string '["README.md"]'. Handlers then
fell into the "not an array -> wrap as [value]" branch and treated the
literal bracketed text as a single path/command, causing ENOENT on a
bracketed path and no-op or failing shell commands, which spun the agent
into a retry loop.

Add coerceToStringArray() / coerceFirstStringArray() and route every
string-array batch param through them: JSON-stringified arrays are parsed
back into real arrays, plain strings are wrapped, nullish/empty values
yield []. coerceFirstStringArray preserves the singular fallback
(path/symbol) where handlers support it. Object-array params
(replace_symbol `replacements`, edit_file `files`) are intentionally left
untouched.

Covers 9 handlers. 12 unit tests for the helpers; verified end-to-end
via isaac (list_files + read_file now receive real arrays, no retry loop).
Copilot AI review requested due to automatic review settings June 1, 2026 17:47
@electron-rare electron-rare merged commit fa42ef0 into master Jun 1, 2026
2 of 3 checks passed
@electron-rare electron-rare deleted the fix/cli-tool-array-coercion branch June 1, 2026 17:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants