You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
Commit 3a43a15
Browse filesBrowse the repository at this point in the historyBrowse files
feat(types,app-shell): carry the tool approval envelope through hydration (#9229)
* feat(types,app-shell): carry the tool approval envelope through hydration
Three of `ChatToolInvocation`'s ten declared `state` values —
`approval-requested`, `approval-responded`, `output-denied` — are states the AI
SDK's own tool-part union cannot express without an
`{ id, approved?, reason?, isAutomatic?, signature? }` envelope. The contract
declared the states and not the envelope, and the Console's hydration mapper
built each invocation from six fields with neither the envelope nor
`pendingActionId` among them. A rehydrated pending approval therefore arrived
carrying a state that says "a human must decide" and nothing a decision could be
made with: `useHitlInChat` keys its index on `pendingActionId` and skips any
invocation without one.
Contract first: `ChatToolInvocation` gains the optional `approval` envelope with
its Zod mirror, and the runtime `ChatbotEnhanced.ChatToolInvocation` mirrors it.
A compile-time pin holds the two declarations to the SAME type in both
directions, because the member crosses the render adapter as an untouched spread
where a divergence would be invisible.
`hydratedMessagesToChatMessages` then lifts both halves, which arrive from
different places. The SDK envelope is persisted ON THE PART and is narrowed to
its declared shape rather than cast — an `approval` with no usable `id` is
refused, not passed through. `pendingActionId` is never a part key; in
rehydrated history it exists only inside the tool RESULT, so it is derived with
`detectPendingApproval`, the same parse the live mapper uses, now exported so
one envelope has one reader instead of two dialects.
Nothing is narrowed. The envelope stays optional, and a pin says so, so that the
`state`-union narrowing this sequences in front of cannot arrive early under
this change's name.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
* docs(changeset): declare the approval envelope as `minor`, per the repo's written precedent
PM ruling on the bump the seat flagged rather than assumed. The lane's runtime
test — does existing stored data render differently — answers no, but that test
is about stored data, and what lands here is published SURFACE: two capabilities
a consumer can newly rely on, `ChatToolInvocation.approval` and the
`detectPendingApproval` export. `.changeset/8214-chatbot-anypart-state-widen.md`
settles that case in this repo in those words.
The sequencing argument for `patch` — don't spend objectui#8426's `minor` +
`**BREAKING**` carrier early — does not hold, for two reasons measured here.
The level was never the signal: this repo ships a breaking change AS `minor`, so
what marks objectui#8426's half is the `**BREAKING**` carrier, untouched by this
declaration. And `.changeset/config.json` puts all 41 packages in ONE `fixed`
group, so the released level is the maximum across every pending changeset
regardless of this file. `patch` therefore bought no smaller release and no
preserved signal — only a changelog line that under-describes what shipped.
Prose and frontmatter only; no source file is touched.
Ref: objectui#8442
Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments