@object-ui/plugin-chatbot 17.2.0 → 17.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,324 @@
1
1
  # @object-ui/plugin-chatbot
2
2
 
3
+ ## 17.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3256b14: `@object-ui/plugin-chatbot`'s `ChatMessage` is now one type instead of two
8
+
9
+ The barrel exported two different `ChatMessage` types: a minimal one it declared itself (`id` / `role` / `content` / `timestamp` / `avatar` / `avatarFallback`) and the shape `<ChatbotEnhanced>` actually renders, re-exported under the alias `ChatbotEnhancedMessage`. The natural name resolved to the narrow one, so an importer reaching for `ChatMessage` silently got the wrong contract — and the compiler could not object, because both shapes existed on purpose and every construction site spreads the extra keys conditionally, which defeats excess-property checking. That is how app-shell's `AiChatPage` ended up unable to read `toolInvocations` off its own function's return value (objectui#4040; re-pointed in PR #4379, but the collision itself was left standing). objectui#4383.
10
+
11
+ **Breaking semantics** (declared `minor` per AGENTS.md §版本号策略 — objectui never declares `major` outside an `@objectstack` major sync): `ChatMessage` exported from `@object-ui/plugin-chatbot` now denotes the enhanced shape. In practice this is a widening rather than a removal — every field of the retired shape survives with the same type, and the enhanced shape adds only optional keys (`streaming`, `toolInvocations`, `reasoning`, `sources`, `traceId`, `buildProgress`, `blueprintProgress`, `charts`), so anything that was a valid `ChatMessage` still is, and `<Chatbot messages={…} />` keeps accepting the same values. Code that relied on the name meaning _exactly_ the six-key shape (exhaustive `keyof` maps, `Equal`-style assertions) is the case that changes.
12
+
13
+ `ChatbotEnhancedMessage` is kept as a `@deprecated` alias of the same type, so importers that spelled the disambiguating name keep compiling; new code should import `ChatMessage`. Pinned at compile time by `packages/plugin-chatbot/src/__tests__/chat-message-contract.test.ts`.
14
+
15
+ - eec2e4f: `useObjectChat` declares the message shape it actually hands back
16
+
17
+ The hook typed `messages` — and the `onSend(content, messages)` callback fed from it — as `@object-ui/types`' authoring `ChatMessage`. That was true in local mode only. In API mode the values came out of the runtime mapper and were asserted into place with `as OuiChatMessage[]`, and the authoring contract declares none of what they carry: `buildProgress`, `blueprintProgress`, `charts`, and `pendingActionId` / `draftReview` / `proposedPlan` / `proposedChanges` / `builderHandoff` on every tool invocation. Those keys are the HITL approval card, the "Review N changes" affordance, the proposed-plan card, the build panel and the inline charts. They survived only because nothing on the path ever rebuilt a message; anyone writing the obvious thing — reconstruct a message field-by-field from its declared type — deleted all of them, with the compiler agreeing, because the declared type genuinely did not have them.
18
+
19
+ The declaration is now the truth, published as `ObjectChatMessage`. The survey behind it found the honest type to be neither of the two `ChatMessage` types on either side, because neither is true of both modes: it stays **wide** where local mode is wide (an authored `'tool'` role and the legacy `'partial-call'` / `'call'` / `'result'` tool states reach this surface unchanged and are folded only at the render seam), **narrow** where both modes are narrow (`timestamp` is `string`, never `Date` — API mode never produces one and local mode absorbs it before emitting), and adds the render-only keys API mode really carries. The `as OuiChatMessage[]` assertion is deleted rather than moved: the mapper's output satisfies the declared type, so the compiler checks that assignment instead of being told to stop looking.
20
+
21
+ Nothing about the values changed, and nothing correct breaks. `ObjectChatMessage` is a **subtype** of the authoring `ChatMessage` it replaces, so every consumer that accepted the old declaration still accepts these values — including a host `onSend` callback that types its parameter as `ChatMessage[]`, which keeps type-checking by contravariance. Naming `ObjectChatMessage` is what lets a host _read_ the keys above. The one observable narrowing is deliberate: code that branched on `timestamp instanceof Date` was handling a value this hook cannot emit, and now says so at compile time.
22
+
23
+ The seam below it (`chatMessageAdapter.ts`, from objectui#4399) is still necessary and unchanged in behaviour — `'tool'` and the legacy tool states still have to be narrowed for the renderers. What changed is that its pass-through is no longer an act of faith: its input type (`SeamChatMessage`, also exported, alongside `SeamToolInvocation`) names the render-only keys, so the spread preserves them as declared properties the compiler can see, and the pass-through tests type their API-mode fixture directly instead of casting it past the compiler. A cast returning to the hook is now caught by a test rather than by a future outage.
24
+
25
+ App-shell carries a comment-only correction on the same family: `AiChatPage` still described `@object-ui/plugin-chatbot` as exporting a second, minimal legacy `ChatMessage` alongside the enhanced one. That collision was retired in objectui#4383 — the barrel publishes one contract and `ChatbotEnhancedMessage` is a deprecated alias of it — so the paragraph was sending readers to look for a hazard that no longer exists.
26
+
27
+ ### Patch Changes
28
+
29
+ - dde7283: `chatbot` and `chatbot-enhanced` now pass only whitelisted DOM props to their host element (objectui#4431)
30
+
31
+ Both registrations destructured `schema` and `className` and forwarded everything else. `SchemaRenderer` hands a registered component the authored node's own keys, the contents of its `props` container, the ARIA it resolved and the host's trailing props — so all of it became attributes on the chat root `div`, because React passes unknown lowercase attributes through in silence and stringifies object values. Measured through the real SDUI path with a data-source adapter attached: **14 non-DOM attributes on each widget**, including `datasource="[object Object]"` (the injected adapter, which only appears on a deployment that really loads data) and a camelCase `arialabel` sitting next to the resolved `aria-label`, so the element carried each ARIA value twice under two spellings — one of them meaningless to assistive technology.
32
+
33
+ Both are now consume-or-whitelist: configuration is read off `schema` as before, the evaluated `disabled` verdict is consumed by name, and only `toDomProps`' output reaches the element. The resolved `aria-label` / `aria-describedby`, `role`, `id`, `tabIndex` and the `data-*` family still arrive — dropping them would have been an accessibility regression dressed as a leak fix, so the pin asserts the delivered set exactly, not just the absent one. `chatbot-floating` is untouched: its content mounts through a portal and its root never spread.
34
+
35
+ `@object-ui/core` gains the shared executor this migration needs (`utils/dom-props.ts`): `toDomProps` for the SDUI widget contract, plus `pickDomProps` — the mechanism — for a package whose own contract declares a different key set. That is the objectui#4409 dependency direction: plugin packages declare `@object-ui/core` and must not grow a dependency on `@object-ui/fields` to reach a whitelist.
36
+
37
+ `@object-ui/fields` keeps its own key list and its compile-time bindings, and now executes them through core's mechanism. Its behaviour is unchanged and its exported `DomProps<P>` is the same structural type. The two lists differ for measured reasons and no longer can drift silently: `name` and `disabled` are legal only on form controls, which is what every field widget renders and what `FieldWidgetComponentProps` declares, while `role` is resolved by `SchemaRenderer` for every SDUI node and is not part of the field contract. A new assertion binds every shared key in both directions, with `role` named as the single deliberate exception.
38
+
39
+ - 37bbc42: Replace the three `messages as any` casts at the `@object-ui/types` ↔
40
+ `@object-ui/plugin-chatbot` `ChatMessage` boundary with one explicit typed
41
+ adapter (`toRuntimeMessages` / `authoredToRuntimeMessage`, now exported).
42
+
43
+ The authoring contract (`ChatbotSchema['messages']`) and the runtime contract
44
+ `<ChatbotEnhanced>` renders are both deliberate and deliberately different; the
45
+ casts erased ALL of that drift rather than the intentional parts, so a future
46
+ vocabulary move would have surfaced as rendering behaviour instead of a type
47
+ error. Each narrowing is now named, documented and tested: an authored
48
+ `role: 'tool'` message is an assistant message (unchanged rendering — the
49
+ implicit fallthrough is now the recorded decision), a `Date` timestamp becomes
50
+ its ISO string (one expression, consumed by both the seam and the hook's
51
+ `normalizeMessages`), and the legacy tool-invocation states
52
+ `'partial-call'`/`'call'`/`'result'` map to their AI SDK v6 equivalents as the
53
+ authoring type's own documentation declares — previously they reached the tool
54
+ chip unrecognised and rendered a status badge with no label.
55
+
56
+ - Updated dependencies [0e67b53]
57
+ - Updated dependencies [ceccdcf]
58
+ - Updated dependencies [d6e5124]
59
+ - Updated dependencies [debad27]
60
+ - Updated dependencies [dc2aa3e]
61
+ - Updated dependencies [ee66e2e]
62
+ - Updated dependencies [ee26e65]
63
+ - Updated dependencies [5900ac5]
64
+ - Updated dependencies [932cbcd]
65
+ - Updated dependencies [734d186]
66
+ - Updated dependencies [f650253]
67
+ - Updated dependencies [3d9769a]
68
+ - Updated dependencies [8f85f8b]
69
+ - Updated dependencies [d0c3b26]
70
+ - Updated dependencies [3fc2971]
71
+ - Updated dependencies [aca27fa]
72
+ - Updated dependencies [dde7283]
73
+ - Updated dependencies [f7c6430]
74
+ - Updated dependencies [4dadf0d]
75
+ - Updated dependencies [ae10a01]
76
+ - Updated dependencies [92876f0]
77
+ - Updated dependencies [f279deb]
78
+ - Updated dependencies [4b70d28]
79
+ - Updated dependencies [eb7f586]
80
+ - Updated dependencies [e901131]
81
+ - Updated dependencies [d9d3463]
82
+ - Updated dependencies [2a40f69]
83
+ - Updated dependencies [bec3e14]
84
+ - Updated dependencies [613b167]
85
+ - Updated dependencies [b4d3c22]
86
+ - Updated dependencies [1f9b905]
87
+ - Updated dependencies [cb13400]
88
+ - Updated dependencies [828549a]
89
+ - Updated dependencies [e1ade8f]
90
+ - Updated dependencies [bc64bfe]
91
+ - Updated dependencies [abb0f81]
92
+ - Updated dependencies [38ab505]
93
+ - Updated dependencies [3e19fe7]
94
+ - Updated dependencies [bb58d1d]
95
+ - Updated dependencies [5cc847c]
96
+ - Updated dependencies [fa21254]
97
+ - Updated dependencies [33c32bf]
98
+ - Updated dependencies [66fb4fa]
99
+ - Updated dependencies [b953a97]
100
+ - Updated dependencies [d7f3e30]
101
+ - Updated dependencies [6d641c9]
102
+ - Updated dependencies [7e4f0e5]
103
+ - Updated dependencies [a84385b]
104
+ - Updated dependencies [45e1949]
105
+ - Updated dependencies [92250d6]
106
+ - Updated dependencies [c1d939f]
107
+ - Updated dependencies [58bebf6]
108
+ - Updated dependencies [405e808]
109
+ - Updated dependencies [49ae9f4]
110
+ - Updated dependencies [a3ae404]
111
+ - Updated dependencies [bfdf3d4]
112
+ - Updated dependencies [bb68488]
113
+ - Updated dependencies [c0f9a4b]
114
+ - Updated dependencies [b1e42d0]
115
+ - Updated dependencies [2459a3e]
116
+ - Updated dependencies [ac853ce]
117
+ - Updated dependencies [fa51109]
118
+ - Updated dependencies [d6aa172]
119
+ - Updated dependencies [fe52a04]
120
+ - Updated dependencies [d46f9b8]
121
+ - Updated dependencies [3f5f87c]
122
+ - Updated dependencies [2fea4d2]
123
+ - Updated dependencies [f5e1143]
124
+ - Updated dependencies [7f1cb33]
125
+ - Updated dependencies [f148a64]
126
+ - Updated dependencies [bb68488]
127
+ - Updated dependencies [2e3b0c0]
128
+ - Updated dependencies [9461dd3]
129
+ - Updated dependencies [78fa331]
130
+ - Updated dependencies [47f551b]
131
+ - Updated dependencies [31ab1ac]
132
+ - Updated dependencies [0082db8]
133
+ - Updated dependencies [ab04728]
134
+ - Updated dependencies [5bf09fd]
135
+ - Updated dependencies [06915b0]
136
+ - Updated dependencies [ff84b05]
137
+ - @object-ui/i18n@17.5.0
138
+ - @object-ui/react@17.5.0
139
+ - @object-ui/components@17.5.0
140
+ - @object-ui/core@17.5.0
141
+ - @object-ui/types@17.5.0
142
+
143
+ ## 17.4.0
144
+
145
+ ### Minor Changes
146
+
147
+ - d9ce385: `ApproveOutcome` / `RejectOutcome` are now derived from `@objectstack/spec`
148
+ instead of hand-transcribed (objectui#3783). Same failure class #3220 cleared
149
+ from the same file for `PendingActionRow` / `PendingActionStatus` — but this pair
150
+ wore local names rather than spec names, so `check-spec-symbol-derivation.mjs`,
151
+ which fires on a spec export name being occupied, had no handle on it. A renamed
152
+ hand copy is invisible to a name-based guard by construction.
153
+
154
+ Both types now re-export the spec's decision responses
155
+ (`ApproveAiPendingActionResponse` / `RejectAiPendingActionResponse` from
156
+ `@objectstack/spec/api` — the same schemas `@objectstack/client`'s
157
+ `ai.pendingActions.approve()` / `.reject()` type their returns with). The public
158
+ export names do not change. The shapes do, in three ways:
159
+
160
+ - **`ApproveOutcome` no longer declares `id`.** The approve response has never
161
+ carried one — `id` is on the _reject_ response. This was the one drift that
162
+ was not dormant: `useHitlInChat`'s public `onDecided` callback promised
163
+ consumers `id: string` and handed them `undefined` at runtime, with nothing
164
+ in the compiler to say so. **If you read `outcome.id` after an approve, that
165
+ read was already `undefined` and now fails to compile** — take the id from
166
+ `ContinueContext.pendingActionId` or from the row you decided on.
167
+ - **`status` is closed.** `'executed' | 'failed' | string` and
168
+ `'rejected' | string` were both just `string`: a union with `string` absorbs
169
+ the literals, so neither annotation carried any information. They are now
170
+ `'executed' | 'failed'` and `'rejected'`.
171
+ - **The `[k: string]: unknown` index signature on `ApproveOutcome` is gone.** The
172
+ objectstack#4075 mechanism: with it, any structural comparison against the
173
+ spec answers "identical" however far the copy has drifted, so a parity test
174
+ bolted onto the old type would have been green from its first day.
175
+
176
+ **Breaking at the type level for importers of `@object-ui/plugin-chatbot`** —
177
+ narrowing a published type is a break even when the old type was lying, which is
178
+ why it is spelled out here. Shipped as `minor` per AGENTS.md §版本号策略: the
179
+ family's `major` tracks `@objectstack`'s, and objectui's own breaking changes go
180
+ out as `minor` with the break named in the changeset.
181
+
182
+ Runtime behaviour is unchanged — including the hook's decision handling for a
183
+ status outside the spec vocabulary, and the locally synthesized failure envelope
184
+ on a non-2xx, both now pinned by tests. The consumer-side tolerances that remain
185
+ in `useHitlInChat` are recorded in objectui#3790 for a maintainer decision.
186
+
187
+ ### Patch Changes
188
+
189
+ - 2a54e86: `parseAiQuotaError` now reads the AI quota refusal code from all three shapes the
190
+ cloud 429 producers use, instead of only the flat `error`-holds-the-code dialect.
191
+
192
+ The two live producers fill the same `error` key in opposite ways — the token
193
+ guardrail puts the **code** there, `service-ai` puts the **message** there and the
194
+ code in a `code` sibling — while ADR-0112 declares a third shape both are
195
+ converging on: `{ success: false, error: { code, message } }`. The consumer had to
196
+ learn the declared shape **first**, or the producers' convergence would silently
197
+ turn every quota refusal back into a generic "Response failed" banner (the same
198
+ consumer-first sequencing as objectui#2992).
199
+
200
+ - Code lookup order is a total order — declared envelope, then the flat guardrail
201
+ code, then the `code` sibling — so a transitional producer that double-emits the
202
+ new envelope alongside the legacy top-level keys has one defined outcome.
203
+ - Only the code's **location** widens. The recognized code set is unchanged, and
204
+ any unrecognized shape still degrades to today's behavior (`null`), so no
205
+ non-quota error is newly captured by the quota CTA.
206
+ - Companion fields (`upgrade`, `topUp`, `messageEn`) keep their established
207
+ top-level read; their position inside the declared envelope is deliberately not
208
+ presumed, and is aligned once the producer PR fixes the real shape.
209
+
210
+ - Updated dependencies [794c497]
211
+ - Updated dependencies [993336f]
212
+ - Updated dependencies [f0a625a]
213
+ - Updated dependencies [b5980f4]
214
+ - Updated dependencies [8aad9fd]
215
+ - Updated dependencies [6719877]
216
+ - Updated dependencies [56ff091]
217
+ - Updated dependencies [7864f03]
218
+ - Updated dependencies [0cbdca8]
219
+ - Updated dependencies [d229dfa]
220
+ - Updated dependencies [ecae400]
221
+ - Updated dependencies [4bc6c23]
222
+ - Updated dependencies [d3e738a]
223
+ - Updated dependencies [c3b01a7]
224
+ - Updated dependencies [f5f8744]
225
+ - Updated dependencies [7ed3360]
226
+ - Updated dependencies [69becd2]
227
+ - Updated dependencies [5e52495]
228
+ - Updated dependencies [0fa5e4d]
229
+ - Updated dependencies [b750823]
230
+ - Updated dependencies [5bfaabd]
231
+ - Updated dependencies [e06810e]
232
+ - Updated dependencies [ab3ad4f]
233
+ - Updated dependencies [c2fd122]
234
+ - Updated dependencies [ac2139c]
235
+ - Updated dependencies [b14ab3a]
236
+ - Updated dependencies [e24d767]
237
+ - Updated dependencies [8c60819]
238
+ - Updated dependencies [aca561a]
239
+ - Updated dependencies [e64a52e]
240
+ - Updated dependencies [844d17f]
241
+ - Updated dependencies [48132f7]
242
+ - Updated dependencies [4dcd52a]
243
+ - Updated dependencies [42ae5c6]
244
+ - Updated dependencies [0ef9dfd]
245
+ - Updated dependencies [1d723e3]
246
+ - Updated dependencies [0109f54]
247
+ - Updated dependencies [7e5bb5d]
248
+ - Updated dependencies [fbc23e0]
249
+ - Updated dependencies [6d762da]
250
+ - Updated dependencies [e6fdbdc]
251
+ - Updated dependencies [54233b1]
252
+ - Updated dependencies [f9faa7d]
253
+ - Updated dependencies [97b63d7]
254
+ - Updated dependencies [6bb454a]
255
+ - Updated dependencies [523be48]
256
+ - Updated dependencies [7e2b7e9]
257
+ - Updated dependencies [33526fd]
258
+ - Updated dependencies [32413ec]
259
+ - Updated dependencies [c1e1e6b]
260
+ - @object-ui/components@17.4.0
261
+ - @object-ui/react@17.4.0
262
+ - @object-ui/core@17.4.0
263
+ - @object-ui/i18n@17.4.0
264
+ - @object-ui/types@17.4.0
265
+
266
+ ## 17.3.0
267
+
268
+ ### Patch Changes
269
+
270
+ - Updated dependencies [18cd432]
271
+ - Updated dependencies [532cf8b]
272
+ - Updated dependencies [680080a]
273
+ - Updated dependencies [a7651e6]
274
+ - Updated dependencies [d915c47]
275
+ - Updated dependencies [b71fc92]
276
+ - Updated dependencies [65516ba]
277
+ - Updated dependencies [94c5b7c]
278
+ - Updated dependencies [ca0fa8f]
279
+ - Updated dependencies [34595eb]
280
+ - Updated dependencies [3889ffb]
281
+ - Updated dependencies [5781fb1]
282
+ - Updated dependencies [7e2406a]
283
+ - Updated dependencies [9e9e9a9]
284
+ - Updated dependencies [56409c2]
285
+ - Updated dependencies [042e09d]
286
+ - Updated dependencies [9cbcbf4]
287
+ - Updated dependencies [85c4c9c]
288
+ - Updated dependencies [fd54c3e]
289
+ - Updated dependencies [4eeb932]
290
+ - Updated dependencies [5c856ec]
291
+ - Updated dependencies [23018cc]
292
+ - Updated dependencies [53811d1]
293
+ - Updated dependencies [68b6a28]
294
+ - Updated dependencies [0554e88]
295
+ - Updated dependencies [d915c47]
296
+ - Updated dependencies [f44d872]
297
+ - Updated dependencies [28b2e65]
298
+ - Updated dependencies [509104a]
299
+ - Updated dependencies [825bbe3]
300
+ - Updated dependencies [6195841]
301
+ - Updated dependencies [5dd0127]
302
+ - Updated dependencies [06632e9]
303
+ - Updated dependencies [a415684]
304
+ - Updated dependencies [a4cff5b]
305
+ - Updated dependencies [175bd79]
306
+ - Updated dependencies [5af2852]
307
+ - Updated dependencies [f833d3a]
308
+ - Updated dependencies [a6ec93d]
309
+ - Updated dependencies [2a9513d]
310
+ - Updated dependencies [71be406]
311
+ - Updated dependencies [d22ae31]
312
+ - Updated dependencies [c7ed4c3]
313
+ - Updated dependencies [2409e1d]
314
+ - Updated dependencies [789fe3e]
315
+ - Updated dependencies [8d8094a]
316
+ - @object-ui/core@17.3.0
317
+ - @object-ui/components@17.3.0
318
+ - @object-ui/types@17.3.0
319
+ - @object-ui/i18n@17.3.0
320
+ - @object-ui/react@17.3.0
321
+
3
322
  ## 17.2.0
4
323
 
5
324
  ### Minor Changes
@@ -944,6 +1263,7 @@ type:'chart', … }}/>` (decoupled — no hard dep on `plugin-charts`), giving t
944
1263
  - 0335ec4: Polish the AI chat surface based on real-world dogfooding feedback.
945
1264
 
946
1265
  **`@object-ui/plugin-chatbot`** — new display helpers shared by `ChatbotEnhanced`:
1266
+
947
1267
  - `unwrapToolResult(value)` peels the MCP-style `{ type: 'text', value: '<json>' }`
948
1268
  envelope that backend tools emit (`@objectstack/service-ai`'s data/metadata
949
1269
  tools, in particular), and JSON-parses the inner payload. The result panel
@@ -964,6 +1284,7 @@ type:'chart', … }}/>` (decoupled — no hard dep on `plugin-charts`), giving t
964
1284
  so wrappers can compose richer titles.
965
1285
 
966
1286
  **`@object-ui/app-shell`** — `AiChatPage`:
1287
+
967
1288
  - Removes the fake "Hello! I'm X" assistant welcome bubble so the empty-state
968
1289
  suggestion chips can actually render.
969
1290
  - Adds per-agent default suggestion sets (`data_chat`, `metadata_assistant`)
@@ -1416,6 +1737,7 @@ Assistant… (try "系统里有多少个用户?")`).
1416
1737
  ### Patch Changes
1417
1738
 
1418
1739
  - 1b6dc64: fix: complete Tailwind v3→v4 migration cleanup
1740
+
1419
1741
  - Rename deprecated `flex-shrink-0` → `shrink-0` and `flex-grow-N` →
1420
1742
  `grow-N` (Tailwind v4 dropped the long-form aliases). Affects
1421
1743
  data-table, fields/index, FileField, ChatbotEnhanced,
@@ -1476,6 +1798,7 @@ Assistant… (try "系统里有多少个用户?")`).
1476
1798
  Library builds (vite lib mode) now externalize every non-relative import instead of bundling third-party CJS dependencies into the published dist. This avoids inlined `require("react")` / `require("react-dom")` calls that cause `Calling \`require\` for "react" in an environment that doesn't expose the \`require\` function` runtime errors when consumer apps re-bundle the published dist.
1477
1799
 
1478
1800
  Specifically fixes:
1801
+
1479
1802
  - `@object-ui/plugin-dashboard` no longer inlines `react-grid-layout` (and its transitive `react-draggable` / `react-resizable` CJS bundles). `react-grid-layout` is now declared as a peer dependency so consumers install a single ESM-friendly copy.
1480
1803
  - `@object-ui/components`, `@object-ui/plugin-calendar`, `@object-ui/plugin-charts`, `@object-ui/plugin-designer` no longer inline `react-i18next` / `i18next` / `use-sync-external-store` CJS shims.
1481
1804
  - All plugin packages now use a unified `external: (id) => !/^[./]/.test(id) && !id.startsWith(__dirname)` rule, ensuring future additions of CJS deps are automatically externalized.
package/README.md CHANGED
@@ -55,7 +55,7 @@ function App() {
55
55
  ### AI Streaming Mode (service-ai)
56
56
 
57
57
  When `api` is set in the schema, the chatbot connects to a backend SSE endpoint
58
- using `@ai-sdk/react` v3 (Vercel UI Message Stream protocol) for streaming,
58
+ using `@ai-sdk/react` v4 (Vercel UI Message Stream protocol) for streaming,
59
59
  tool-calling, and production-grade chat:
60
60
 
61
61
  ```tsx
@@ -110,6 +110,30 @@ function MyChat() {
110
110
  }
111
111
  ```
112
112
 
113
+ #### What `messages` actually contains
114
+
115
+ `messages` — and the `onSend(content, messages)` callback fed from it — is
116
+ typed `ObjectChatMessage[]`, exported from this package. It is deliberately
117
+ neither of the two `ChatMessage` types nearby, because neither is true of both
118
+ modes (objectui#4424):
119
+
120
+ - **Not `@object-ui/types`' authoring `ChatMessage`.** In API mode the values
121
+ come from the runtime mapper and carry `buildProgress`, `blueprintProgress`,
122
+ `charts`, and `pendingActionId` / `draftReview` / `proposedPlan` /
123
+ `proposedChanges` / `builderHandoff` on each tool invocation — the approval
124
+ card, the "Review N changes" affordance, the plan card, the build panel and
125
+ the inline charts. The authoring contract declares none of them, so rebuilding
126
+ a message field-by-field from it deletes all of them, and the compiler agrees.
127
+ - **Not this package's runtime `ChatMessage` either.** In local mode an authored
128
+ `'tool'` role and the legacy `'partial-call'` / `'call'` / `'result'` tool
129
+ states pass through untouched; they are folded only at the render seam
130
+ (`toRuntimeMessages`, `chatMessageAdapter.ts`).
131
+
132
+ `ObjectChatMessage` is a subtype of the authoring `ChatMessage`, so anything
133
+ already typed against that keeps compiling — naming `ObjectChatMessage` is what
134
+ lets you *read* the keys above. `timestamp` is always a `string` here: both
135
+ modes absorb an authored `Date` before emitting.
136
+
113
137
  ## Schema-Driven Usage
114
138
 
115
139
  ### Discovering Backend Agents
@@ -211,17 +235,6 @@ const aiSchema = {
211
235
  | Stop/Reload | Stop cancels timer | Stop interrupts stream |
212
236
  | Backend | None required | service-ai (IAIService) |
213
237
 
214
- <!-- release-metadata:v3.3.0 -->
215
-
216
- ## Compatibility
217
-
218
- - **React:** 18.x or 19.x
219
- - **Node.js:** ≥ 18
220
- - **TypeScript:** ≥ 5.0 (strict mode)
221
- - **`@objectstack/spec`:** ^3.3.0
222
- - **`@objectstack/client`:** ^3.3.0
223
- - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
224
-
225
238
  ## Links
226
239
 
227
240
  - 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-chatbot)
@@ -267,6 +280,62 @@ import { AIElements } from '@object-ui/plugin-chatbot';
267
280
  </AIElements.Conversation>;
268
281
  ```
269
282
 
283
+ ### The `ChatMessage` type
284
+
285
+ `ChatMessage` is this package's one message contract — the shape
286
+ `<ChatbotEnhanced>` renders and the mappers below produce. On top of the core
287
+ `id` / `role` / `content` / `timestamp` / `avatar` / `avatarFallback` fields it
288
+ carries the streaming and agent-process keys (`streaming`, `toolInvocations`,
289
+ `reasoning`, `sources`, `traceId`, `buildProgress`, `blueprintProgress`,
290
+ `charts`), all optional.
291
+
292
+ ```tsx
293
+ import type { ChatMessage } from '@object-ui/plugin-chatbot';
294
+ ```
295
+
296
+ > This barrel used to export **two** different `ChatMessage` types: a minimal
297
+ > one declared here, plus the enhanced shape aliased as
298
+ > `ChatbotEnhancedMessage`. Reaching for the natural name got you the narrow
299
+ > contract with no compiler complaint (objectui#4383). The minimal shape is
300
+ > retired; `ChatbotEnhancedMessage` is now a **deprecated alias of the same
301
+ > type**, kept only so existing importers keep compiling.
302
+
303
+ Note that `@object-ui/types` also exports a `ChatMessage`. That one is the
304
+ **JSON/SDUI schema** type (`ChatbotSchema['messages']`, `role` includes
305
+ `'tool'`, `timestamp` may be a `Date`) — the authoring contract, not the React
306
+ runtime one. Import the schema type from `@object-ui/types` and the runtime
307
+ type from this package.
308
+
309
+ ### Authoring → runtime: `toRuntimeMessages`
310
+
311
+ The two contracts are both deliberate, so they drift — and the conversion
312
+ between them is a real decision, not a formality. If you hold **authored**
313
+ messages (`@object-ui/types`) and want to render them with the components in
314
+ this package, convert them; do not cast:
315
+
316
+ ```tsx
317
+ import type { ChatMessage as AuthoredChatMessage } from '@object-ui/types';
318
+ import { ChatbotEnhanced, toRuntimeMessages } from '@object-ui/plugin-chatbot';
319
+
320
+ function MyAuthoredChat({ messages }: { messages: AuthoredChatMessage[] }) {
321
+ return <ChatbotEnhanced messages={toRuntimeMessages(messages)} />;
322
+ }
323
+ ```
324
+
325
+ | key | authoring (`@object-ui/types`) | runtime (this package) | what the adapter decides |
326
+ |---|---|---|---|
327
+ | `role` | `'user' \| 'assistant' \| 'system' \| 'tool'` | `'user' \| 'assistant' \| 'system'` | a `'tool'` message **is an assistant message**: it renders as an assistant bubble with its content shown. `'system'` keeps its own role (`<Chatbot>` renders it as a centred pill). |
328
+ | `timestamp` | `string \| Date` | `string` | a `Date` becomes its ISO 8601 string. The runtime renders the timestamp straight into a React child, where an object throws. |
329
+ | `toolInvocations[].state` | AI SDK v6 states **+ legacy** `'partial-call' \| 'call' \| 'result'` | v6 states only | the legacy spellings map to `'input-streaming'` / `'input-available'` / `'output-available'` — the mapping the authoring type's own docs declare. |
330
+ | everything else | — | — | passed through untouched, including keys the runtime contract does not declare. |
331
+
332
+ The three registered SDUI renderers (`chatbot`, `chatbot-enhanced`,
333
+ `chatbot-floating`) use this adapter; they used to use `messages as any`, which
334
+ compiled away the intentional drift and any accidental drift with it
335
+ (objectui#4399). `authoredToRuntimeMessage` is the single-message variant, and
336
+ `toRuntimeRole` / `toRuntimeTimestamp` / `toRuntimeToolState` are the individual
337
+ decisions if you need one on its own.
338
+
270
339
  ### Message mapping helpers
271
340
 
272
341
  If you wire `@ai-sdk/react`'s `useChat()` directly and want to render its
@@ -0,0 +1,134 @@
1
+ import { ChatMessage as AuthoredChatMessage, ChatToolInvocation as AuthoredToolInvocation } from '@object-ui/types';
2
+ import { ChatMessage as RuntimeChatMessage, ChatToolInvocation as RuntimeToolInvocation } from './ChatbotEnhanced';
3
+ /**
4
+ * The render-only MESSAGE keys — declared by the runtime contract, never by the
5
+ * authoring one. Named here (rather than spelled out at each use) so that
6
+ * adding a render-only key to `ChatbotEnhanced.ChatMessage` and forgetting this
7
+ * list is a one-line fix in one place. objectui#4424.
8
+ */
9
+ type RuntimeOnlyMessageKeys = Pick<RuntimeChatMessage, 'buildProgress' | 'blueprintProgress' | 'charts'>;
10
+ /**
11
+ * The render-only TOOL-INVOCATION keys — the HITL approval id, the ADR-0033
12
+ * draft review, the proposed plan / changes cards and the ADR-0057 P4 builder
13
+ * handoff. `mapMessages.ts` lifts every one of them out of a tool result; the
14
+ * authoring contract declares none of them. objectui#4424.
15
+ */
16
+ type RuntimeOnlyToolInvocationKeys = Pick<RuntimeToolInvocation, 'pendingActionId' | 'draftReview' | 'proposedPlan' | 'proposedChanges' | 'builderHandoff'>;
17
+ /**
18
+ * One tool invocation as it actually crosses this seam: the authoring contract,
19
+ * plus the render-only extensions it may ALREADY be carrying when it arrives
20
+ * from API mode.
21
+ *
22
+ * `AuthoredToolInvocation` stays assignable to this (every added key is
23
+ * optional), so a host holding plain authored invocations is unaffected.
24
+ */
25
+ export type SeamToolInvocation = AuthoredToolInvocation & Partial<RuntimeOnlyToolInvocationKeys>;
26
+ /**
27
+ * One message as it actually crosses this seam — the seam's INPUT contract.
28
+ *
29
+ * The authoring shape (`role: 'tool'`, `timestamp: Date`, legacy tool states —
30
+ * all still narrowed below) widened by the render-only keys an API-mode value
31
+ * already carries. This is what lets the pass-through spread preserve those
32
+ * keys as declared properties rather than as invisible runtime baggage
33
+ * (objectui#4424); see "Pass-through" in the module doc.
34
+ *
35
+ * `AuthoredChatMessage` is assignable to it, and so is the hook's
36
+ * `ObjectChatMessage` — the two callers this seam serves.
37
+ */
38
+ export type SeamChatMessage = Omit<AuthoredChatMessage, 'toolInvocations'> & {
39
+ toolInvocations?: SeamToolInvocation[];
40
+ } & Partial<RuntimeOnlyMessageKeys>;
41
+ /**
42
+ * `timestamp: string | Date` -> `string | undefined`.
43
+ *
44
+ * The authoring schema declares `z.union([z.string(), z.date()])`, and the
45
+ * runtime renders `{message.timestamp}` straight into a React child — a `Date`
46
+ * there is the classic "Objects are not valid as a React child" throw.
47
+ *
48
+ * This is the SINGLE expression of that absorption in the package: it was
49
+ * inlined in `useObjectChat`'s `normalizeMessages`, which now calls this
50
+ * function instead (objectui#4399). `normalizeMessages` keeps applying it
51
+ * because the hook's own `messages` output — and the `onSend(content,
52
+ * messages)` callback it feeds — has always handed hosts an ISO string, not a
53
+ * `Date`; the absorption is expressed once here and consumed at both points.
54
+ *
55
+ * The `instanceof` check (rather than an unconditional `.toISOString()`) is
56
+ * deliberate: authored JSON is not type-checked at runtime, so a value that is
57
+ * neither `string` nor `Date` must be dropped rather than thrown on. That is
58
+ * the behaviour the inlined version had.
59
+ */
60
+ export declare function toRuntimeTimestamp(timestamp: AuthoredChatMessage['timestamp']): string | undefined;
61
+ /**
62
+ * `role: 'user' | 'assistant' | 'system' | 'tool'` -> the runtime's three roles.
63
+ *
64
+ * **The named decision (objectui#4399): an authored `'tool'` message renders as
65
+ * an assistant bubble, with its content shown.** That was already the outcome
66
+ * before this module existed — the cast let `'tool'` reach `<ChatbotEnhanced>`,
67
+ * whose `formatMessageProps` maps everything that is not `'user'` to the
68
+ * assistant bubble — but it was an implicit fallthrough that nothing recorded
69
+ * and nothing tested. It is now a decision this seam makes, by name.
70
+ *
71
+ * Note this is NOT the same decision as `formatMessageProps`: that one maps a
72
+ * runtime role to one of the vendored `<Message>` element's two BUBBLE styles
73
+ * (and folds `'system'` in as well). This one answers a different question —
74
+ * which runtime role an authored `'tool'` message IS. `'system'` keeps its own
75
+ * runtime role here and still renders as the centred system pill in
76
+ * `<Chatbot>`.
77
+ *
78
+ * Changing the rendering of tool messages (a transcript-style tool block, say)
79
+ * is a UX card, not this one; it would start here.
80
+ */
81
+ export declare function toRuntimeRole(role: AuthoredChatMessage['role']): RuntimeChatMessage['role'];
82
+ /**
83
+ * Tool-invocation `state` -> the runtime's AI SDK v6 lifecycle states.
84
+ *
85
+ * The authoring type accepts three extra legacy values and its own doc comment
86
+ * already declares the mapping: "the legacy `partial-call`/`call`/`result`
87
+ * values are kept for back-compat; the AI SDK v6 lifecycle states map cleanly
88
+ * to `input-streaming`/`input-available`/`output-available`". This implements
89
+ * exactly that sentence — the fourth drift the `as any` was hiding, which the
90
+ * issue's table did not list.
91
+ *
92
+ * Rendered-output note: an authored legacy state used to reach `getToolState`
93
+ * unrecognised, which fell through to `'running'` and rendered a status badge
94
+ * with no label. Only schema-authored `toolInvocations` can carry the legacy
95
+ * spelling (API-mode messages come from `mapMessages`, which emits v6 states
96
+ * already), so this is the one place where the seam's honesty changes a
97
+ * rendered result — from a blank badge to the state the author declared.
98
+ */
99
+ export declare function toRuntimeToolState(state: AuthoredToolInvocation['state']): RuntimeToolInvocation['state'];
100
+ /**
101
+ * One authored tool invocation -> one runtime tool invocation.
102
+ *
103
+ * Only `state` drifts; everything else is spread through, which is what keeps
104
+ * the runtime-only extensions (`pendingActionId`, `draftReview`,
105
+ * `proposedPlan`, `proposedChanges`, `builderHandoff`) alive on the API-mode
106
+ * path. Since objectui#4424 the parameter names them ({@link
107
+ * SeamToolInvocation}), so `passthrough` carries them as declared properties
108
+ * instead of as keys the compiler cannot see — see the module doc.
109
+ */
110
+ export declare function toRuntimeToolInvocation(tool: SeamToolInvocation): RuntimeToolInvocation;
111
+ /**
112
+ * One chat message -> the message shape the chat components render.
113
+ *
114
+ * This is the seam. The three `messages as any` casts in `renderer.tsx` are
115
+ * this function now.
116
+ *
117
+ * The parameter is {@link SeamChatMessage} rather than the bare authoring type
118
+ * (objectui#4424): both are accepted — `AuthoredChatMessage` is assignable to
119
+ * it — but naming the render-only keys is what makes the pass-through
120
+ * compiler-visible instead of a documented act of faith.
121
+ */
122
+ export declare function authoredToRuntimeMessage(message: SeamChatMessage): RuntimeChatMessage;
123
+ /**
124
+ * Array form of {@link authoredToRuntimeMessage} — what the three registered
125
+ * renderers call.
126
+ *
127
+ * Call sites memoize on the input array (`useMemo(..., [messages])`) so the
128
+ * runtime array's identity stays exactly as stable as the hook's own output:
129
+ * local mode holds its messages in state, and the chat components key effects
130
+ * and memos off the `messages` prop.
131
+ */
132
+ export declare function toRuntimeMessages(messages: readonly SeamChatMessage[] | undefined): RuntimeChatMessage[];
133
+ export {};
134
+ //# sourceMappingURL=chatMessageAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatMessageAdapter.d.ts","sourceRoot":"","sources":["../src/chatMessageAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,KAAK,EACV,WAAW,IAAI,mBAAmB,EAClC,kBAAkB,IAAI,sBAAsB,EAC7C,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,WAAW,IAAI,kBAAkB,EACjC,kBAAkB,IAAI,qBAAqB,EAC5C,MAAM,mBAAmB,CAAC;AAE3B;;;;;GAKG;AACH,KAAK,sBAAsB,GAAG,IAAI,CAChC,kBAAkB,EAClB,eAAe,GAAG,mBAAmB,GAAG,QAAQ,CACjD,CAAC;AAEF;;;;;GAKG;AACH,KAAK,6BAA6B,GAAG,IAAI,CACvC,qBAAqB,EACrB,iBAAiB,GAAG,aAAa,GAAG,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,CAC1F,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GACrD,OAAO,CAAC,6BAA6B,CAAC,CAAC;AAEzC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,GAAG;IAC3E,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACxC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,mBAAmB,CAAC,WAAW,CAAC,GAC1C,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,GAChC,kBAAkB,CAAC,MAAM,CAAC,CAE5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,GACrC,qBAAqB,CAAC,OAAO,CAAC,CAahC;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,kBAAkB,GACvB,qBAAqB,CAGvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,eAAe,GACvB,kBAAkB,CAQpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,GAC/C,kBAAkB,EAAE,CAEtB"}