Summary
When actionFusion is enabled, calling the fused write (same presumably applies to edit) with invalid arguments produces a cryptic low-level TypeError instead of the host's clean schema-validation error. The fused tool path appears to bypass the host's argument-validation layer that native tools go through. Fail-safe behavior is intact; this is about error quality.
Environment
- SoL-Pi 0.1.0 (
2b79168), installed as a standalone extension (no Pi patches)
- Host: Pi-compatible agent v18.2.1 (same
@earendil-works/pi-coding-agent extension API)
- Node v25.2.1, Windows
Repro
Call write with only path (deliberately omit required content), once with actionFusion: false and once with actionFusion: true, and compare the error text.
Observed
- AF off (native tool): clean validation error —
Validation failed for tool "write": content must be file content (was missing) plus the received arguments.
- AF on (fused tool):
undefined is not an object (evaluating 't.split') followed by the (correct) [then_run:skipped] The file mutation did not complete successfully; the command was not run.
Analysis
createActionFusionExtension (src/sol-pi/extensions/action-fusion/index.ts) re-registers edit/write via pi.registerTool, spreading the base template's parameters and adding optional then_run. Its execute calls the base definition's execute directly through executeMutationThenRun (then-run.ts). I verified by reading the sources (neither file contains any .split call) and by experiment: calling the host's own createWriteToolDefinition(ctx.cwd).execute(...) directly with valid args succeeds, so the t.split TypeError comes from the implementation receiving unvalidated input (content === undefined) — input the native path would have rejected up front with a schema error.
To be explicit: valid fused calls work fine on this host (verified end-to-end with the real executeMutationThenRun: file created byte-exact, [then_run:succeeded] marker present). Only the invalid-input error path degrades.
Expected
Fused tools should surface the same argument-validation error a native tool would for invalid input — e.g. validate required fields before mutate(), or route through the host's validation — instead of leaking an implementation-internal TypeError to the model.
Summary
When
actionFusionis enabled, calling the fusedwrite(same presumably applies toedit) with invalid arguments produces a cryptic low-levelTypeErrorinstead of the host's clean schema-validation error. The fused tool path appears to bypass the host's argument-validation layer that native tools go through. Fail-safe behavior is intact; this is about error quality.Environment
2b79168), installed as a standalone extension (no Pi patches)@earendil-works/pi-coding-agentextension API)Repro
Call
writewith onlypath(deliberately omit requiredcontent), once withactionFusion: falseand once withactionFusion: true, and compare the error text.Observed
Validation failed for tool "write": content must be file content (was missing)plus the received arguments.undefined is not an object (evaluating 't.split')followed by the (correct)[then_run:skipped] The file mutation did not complete successfully; the command was not run.Analysis
createActionFusionExtension(src/sol-pi/extensions/action-fusion/index.ts) re-registersedit/writeviapi.registerTool, spreading the base template'sparametersand adding optionalthen_run. Itsexecutecalls the base definition'sexecutedirectly throughexecuteMutationThenRun(then-run.ts). I verified by reading the sources (neither file contains any.splitcall) and by experiment: calling the host's owncreateWriteToolDefinition(ctx.cwd).execute(...)directly with valid args succeeds, so thet.splitTypeError comes from the implementation receiving unvalidated input (content === undefined) — input the native path would have rejected up front with a schema error.To be explicit: valid fused calls work fine on this host (verified end-to-end with the real
executeMutationThenRun: file created byte-exact,[then_run:succeeded]marker present). Only the invalid-input error path degrades.Expected
Fused tools should surface the same argument-validation error a native tool would for invalid input — e.g. validate required fields before
mutate(), or route through the host's validation — instead of leaking an implementation-internalTypeErrorto the model.