fix(pi): reject null tool arguments before pi-schema coercion
Refs #843 (kept draft until the issue carries design-approved).
Harness coverage (required)
- OpenCode 1: not applicable — surface exists, but its zod schema rejects
nullbefore the handler; no change needed. - OpenCode 2: not applicable — same zod path as OpenCode 1.
- Pi: covered —
prepareArgumentsadded toctx_noteandctx_memory; tests added for both. - OMP: covered — shares the same
pi-plugintool definitions and hook. - Rust module: not applicable — no tool-argument schema there.
What
pi 1.5.0 validates tool arguments with @earendil-works/pi-schema, which coerces loosely typed arguments before validation. For required properties, null is not dropped: a string schema receives "null" and an array schema receives [null], whose number items become 0. As a result:
ctx_notewithcontent: nullwrites the literal text"null"as the note body.ctx_memorywithcontent: nullwrites the literal text"null"as the memory body.ctx_memorywithids: nullbecomes[0];getreturns nothing instead of rejecting, andupdate/archivelook up id 0.
This change adds ToolDefinition.prepareArguments to both tools. The hook runs before schema validation and before execute(), so it still sees the raw argument:
- reject
content === nullin both tools; - reject
idswhen it is present and not an array; - accept the literal string
"null"unchanged.
It also tightens ctx_memory.ids from Type.Array(Type.Number()) to Type.Array(Type.Integer({ minimum: 1 })), matching ctx_note.note_ids; memory ids start at 1.
Testing
bun test packages/pi-plugin/src/tools/ctx-memory.test.ts packages/pi-plugin/src/tools/ctx-note.test.ts
50 pass / 0 fail
bun test packages/pi-plugin/src/tools/
162 pass / 0 fail
bun run --cwd packages/pi-plugin typecheck
exit 0
biome check (from packages/pi-plugin, repo-local 2.5.1)
Checked 4 files, no fixes applied
The new tests were also run without the source change: exactly the nine new cases fail, so they cover the regression rather than merely passing.
Summary by cubic
Fixes pi 1.5.0's @earendil-works/pi-schema coercion mangling tool arguments in ctx_note and ctx_memory. content: null was written as the literal text "null", ids: null became [0] so get/update/archive targeted id 0, and fractional ids like 1.5 could be truncated into the integer that modified the wrong record.
- Adds
prepareArgumentsto both tools, which runs before schema validation andexecute()and rejects any non-stringcontentand non-arrayids; the literal string"null"remains accepted. - Rejects fractional ids in execution so they can't modify existing records, and adds
minimum: 1toctx_memory.ids, matching memory ids starting at 1.