When the in-app AI chat issued a parallel batch of tool calls, the model
sometimes dropped a required parameter (typically a repeated `pageId`). zod
rejected it and the AI SDK surfaced the raw zod text
("Invalid input: expected string, received undefined") to the model, which is
not actionable — so it could not reliably retry.
Add a centralized `modelFriendlyInput(shape)` wrapper for in-app tool input
schemas:
- the model-facing JSON schema is derived from the SAME zod shape via
`z.toJSONSchema(z.object(shape), { target: 'draft-7' })`, so `required`,
`description` and field constraints are unchanged (contract preserved);
- on a validation failure `validate` returns a human-readable Error naming the
offending parameter(s) plus a fixed retry hint ("Include every REQUIRED
parameter ... do not drop ids like pageId"), which the SDK relays to the model
via InvalidToolInputError;
- on success it returns the parsed (unknown-key-stripped) data, preserving the
existing strip guardrails (deletePage never forwards permanentlyDelete/
forceDelete; transformPage never forwards deleteComments).
Applied in ai-chat-tools.service.ts (the sharedTool builder + every inline
tool inputSchema) and in public-share-chat-tools.service.ts. Values are never
guessed and the required/optional contract is untouched.
Tests: new model-friendly-input.spec.ts (friendly message names the param +
hint; unknown keys stripped; JSON schema keeps required/description); the two
.parse()-based guardrail tests reworked to assert via the new validate path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>