fix(web): stop tool card crashes from taking down the session view #54

Merged
lucas merged 2 commits from 53-ask-tool-card-crashes-the-session-view-on-options-without-a-label into main 2026-10-21 16:58:18 +02:00
Collaborator

An ask call whose arguments were still streaming, or arrived with options that weren't { label: string } objects, crashed AskTool on label.endsWith. With no error boundary around tool renderers, that one card replaced the whole session route with the router's error page. This PR makes the ask card tolerate malformed arguments and wraps every tool card body in its own error boundary.

Decisions

  • Rebased onto origin/main after the branch was first cut from a stale local main; upstream touched none of the changed files (comment).
  • The boundary's resetKey is stream ?? args. Both are replaced on every streaming update, so a crashed card retries as soon as more data arrives (comment).

Verification

  • Throwaway bun test that ran renderToString(<AskTool>) with options [{}, "Plain", { label: "A (Recommended)" }], a null question and a selection containing undefined rendered without throwing: it showed Plain (selected) and A (Recommended), and dropped {}. The test was removed afterwards.
  • bun run typecheck in apps/web passed, both before and after the rebase.
  • Not exercised: the boundary's fallback in a live browser. Server-side rendering does not run error boundaries, so a throwing renderer was not tested.

Closes #53

An `ask` call whose arguments were still streaming, or arrived with options that weren't `{ label: string }` objects, crashed `AskTool` on `label.endsWith`. With no error boundary around tool renderers, that one card replaced the whole session route with the router's error page. This PR makes the ask card tolerate malformed arguments and wraps every tool card body in its own error boundary. ## Decisions - Rebased onto `origin/main` after the branch was first cut from a stale local `main`; upstream touched none of the changed files ([comment](https://git.sclu1034.dev/lucas/omp-deck/issues/53#issuecomment-16525)). - The boundary's `resetKey` is `stream ?? args`. Both are replaced on every streaming update, so a crashed card retries as soon as more data arrives ([comment](https://git.sclu1034.dev/lucas/omp-deck/issues/53#issuecomment-16525)). ## Verification - Throwaway `bun test` that ran `renderToString(<AskTool>)` with options `[{}, "Plain", { label: "A (Recommended)" }]`, a `null` question and a selection containing `undefined` rendered without throwing: it showed `Plain` (selected) and `A (Recommended)`, and dropped `{}`. The test was removed afterwards. - `bun run typecheck` in `apps/web` passed, both before and after the rebase. - Not exercised: the boundary's fallback in a live browser. Server-side rendering does not run error boundaries, so a throwing renderer was not tested. Closes #53
While an ask call streams, its arguments are partial JSON, so an option
can arrive as `{}` or as a plain string. The card assumed every option
had a string label and threw on `endsWith`, taking the session route
down. Options without a label are now skipped, plain-string options are
accepted, and non-string selections in the result are ignored.

Co-Authored-By: Claude Opus 5.5 via omp-deck
A throwing tool renderer used to unmount the whole session route into
the router's error page. Each card body now has its own error boundary
that shows the error inline and retries once the call's args or stream
change.

Co-Authored-By: Claude Opus 5.5 via omp-deck
lucas merged commit 0f1efd79d9 into main 2026-10-21 16:58:18 +02:00
lucas deleted branch 53-ask-tool-card-crashes-the-session-view-on-options-without-a-label 2026-10-21 16:58:19 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/omp-deck!54
No description provided.