@assistant-ui/mcp-docs-server 0.2.0 → 0.2.2
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/.docs/organized/code-examples/waterfall.md +12 -13
- package/.docs/organized/code-examples/with-a2a.md +16 -11
- package/.docs/organized/code-examples/with-ag-ui.md +15 -13
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +14 -13
- package/.docs/organized/code-examples/with-artifacts.md +14 -13
- package/.docs/organized/code-examples/with-assistant-transport.md +20 -28
- package/.docs/organized/code-examples/with-browser-extension.md +18 -11
- package/.docs/organized/code-examples/with-chain-of-thought.md +17 -15
- package/.docs/organized/code-examples/with-cloud-standalone.md +10 -11
- package/.docs/organized/code-examples/with-cloud.md +19 -14
- package/.docs/organized/code-examples/with-custom-thread-list.md +15 -14
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +14 -14
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +19 -17
- package/.docs/organized/code-examples/with-eve.md +66 -12
- package/.docs/organized/code-examples/with-expo.md +26 -31
- package/.docs/organized/code-examples/with-external-store.md +17 -12
- package/.docs/organized/code-examples/with-ffmpeg.md +21 -15
- package/.docs/organized/code-examples/with-generative-ui.md +271 -36
- package/.docs/organized/code-examples/with-google-adk.md +17 -12
- package/.docs/organized/code-examples/with-heat-graph.md +6 -7
- package/.docs/organized/code-examples/with-image-generation.md +9 -10
- package/.docs/organized/code-examples/with-interactables.md +14 -13
- package/.docs/organized/code-examples/with-langchain.md +12 -13
- package/.docs/organized/code-examples/with-langgraph.md +19 -13
- package/.docs/organized/code-examples/with-livekit.md +13 -13
- package/.docs/organized/code-examples/with-mcp.md +14 -15
- package/.docs/organized/code-examples/with-nuxt.md +2428 -0
- package/.docs/organized/code-examples/with-opencode.md +23 -14
- package/.docs/organized/code-examples/with-openui.md +449 -0
- package/.docs/organized/code-examples/with-pi.md +59 -57
- package/.docs/organized/code-examples/with-react-hook-form.md +16 -15
- package/.docs/organized/code-examples/with-react-ink-web.md +7 -8
- package/.docs/organized/code-examples/with-react-ink.md +6 -6
- package/.docs/organized/code-examples/with-react-router.md +17 -11
- package/.docs/organized/code-examples/with-resumable-stream.md +12 -13
- package/.docs/organized/code-examples/with-store.md +27 -16
- package/.docs/organized/code-examples/with-svelte.md +415 -0
- package/.docs/organized/code-examples/with-sveltekit.md +1061 -0
- package/.docs/organized/code-examples/with-tanstack.md +19 -13
- package/.docs/organized/code-examples/with-tap-runtime.md +15 -15
- package/.docs/organized/code-examples/with-virtualized-thread.md +8 -9
- package/.docs/organized/code-examples/with-vue.md +408 -0
- package/.docs/raw/docs/(docs)/cli.mdx +7 -2
- package/.docs/raw/docs/(docs)/index.mdx +9 -76
- package/.docs/raw/docs/(docs)/installation.mdx +6 -20
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +24 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +5 -1
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +9 -2
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +2 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +47 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +29 -4
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +52 -1
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +2 -2
- package/.docs/raw/docs/cloud/ai-sdk.mdx +4 -4
- package/.docs/raw/docs/cloud/index.mdx +1 -1
- package/.docs/raw/docs/copilots/model-context.mdx +4 -3
- package/.docs/raw/docs/copilots/motivation.mdx +4 -4
- package/.docs/raw/docs/guides/attachments.mdx +2 -2
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/context-api.mdx +15 -17
- package/.docs/raw/docs/guides/dictation.mdx +1 -1
- package/.docs/raw/docs/guides/electron.mdx +1 -1
- package/.docs/raw/docs/guides/mentions.mdx +2 -0
- package/.docs/raw/docs/guides/resumable-streams.mdx +74 -3
- package/.docs/raw/docs/guides/suggestions.mdx +15 -12
- package/.docs/raw/docs/ink/hooks.mdx +9 -4
- package/.docs/raw/docs/ink/primitives.mdx +5 -4
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +16 -0
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/clerk.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +2 -2
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
- package/.docs/raw/docs/integrations/gateways/index.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/helicone.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +2 -2
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +146 -128
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +15 -13
- package/.docs/raw/docs/migrations/v0-15.mdx +118 -4
- package/.docs/raw/docs/primitives/attachment.mdx +2 -2
- package/.docs/raw/docs/primitives/composer.mdx +2 -2
- package/.docs/raw/docs/primitives/message.mdx +33 -1
- package/.docs/raw/docs/primitives/suggestion.mdx +4 -2
- package/.docs/raw/docs/primitives/thread.mdx +1 -1
- package/.docs/raw/docs/react-native/hooks.mdx +14 -4
- package/.docs/raw/docs/react-native/index.mdx +1 -1
- package/.docs/raw/docs/react-native/primitives.mdx +2 -2
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +35 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +9 -10
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +9 -10
- package/.docs/raw/docs/runtimes/claude-managed-agents.mdx +118 -0
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +2 -1
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +106 -27
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +19 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +34 -1
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +36 -9
- package/.docs/raw/docs/runtimes/eve/overview.mdx +51 -0
- package/.docs/raw/docs/runtimes/eve/quickstart.mdx +51 -2
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +9 -12
- package/.docs/raw/docs/runtimes/langchain.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +5 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +7 -7
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +4 -4
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +1 -0
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +10 -0
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +8 -1
- package/.docs/raw/docs/tools/backend.mdx +2 -2
- package/.docs/raw/docs/tools/defining-tools.mdx +28 -7
- package/.docs/raw/docs/tools/dynamic-tools.mdx +6 -4
- package/.docs/raw/docs/tools/generative-ui-primitive.mdx +180 -0
- package/.docs/raw/docs/tools/generative-ui-slack.mdx +167 -0
- package/.docs/raw/docs/tools/generative-ui-teams.mdx +160 -0
- package/.docs/raw/docs/tools/generative-ui.mdx +224 -211
- package/.docs/raw/docs/tools/index.mdx +2 -1
- package/.docs/raw/docs/tools/interactables.mdx +29 -17
- package/.docs/raw/docs/tools/mcp-apps.mdx +35 -6
- package/.docs/raw/docs/tools/mcp.mdx +9 -7
- package/.docs/raw/docs/tools/openui.mdx +175 -0
- package/.docs/raw/docs/tools/tool-ui.mdx +27 -24
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +17 -8
- package/.docs/raw/docs/ui/attachment.mdx +27 -0
- package/.docs/raw/docs/ui/file.mdx +7 -2
- package/.docs/raw/docs/ui/image.mdx +1 -1
- package/.docs/raw/docs/ui/mcp-config.mdx +8 -3
- package/.docs/raw/docs/ui/model-selector.mdx +8 -8
- package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
- package/.docs/raw/docs/ui/thread.mdx +24 -5
- package/.docs/raw/docs/utilities/react-o11y.mdx +7 -9
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/tools/docs.js +4 -2
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.js +2 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.js +2 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/tests/test-setup.js +2 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.js +4 -2
- package/dist/tools/xulux-templates.js.map +1 -1
- package/dist/utils/mdx.js +2 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/xulux/catalog-client.js +1 -1
- package/dist/xulux/catalog-client.js.map +1 -1
- package/package.json +4 -4
- package/src/tools/tests/docs.test.ts +2 -2
- package/.docs/raw/docs/tools/interactables-legacy.mdx +0 -410
|
@@ -227,7 +227,7 @@ export async function POST(
|
|
|
227
227
|
|
|
228
228
|
### Implement `RemoteThreadListAdapter`
|
|
229
229
|
|
|
230
|
-
The adapter calls your endpoints. `
|
|
230
|
+
The adapter calls your endpoints. `unstable_useAdapters` injects the per-thread history adapter on the `RemoteThreadList` store entry and on `useRemoteThreadListRuntime` when `unstable_Provider` is omitted. `unstable_Provider` is an optional React face for that runtime. On the `RemoteThreadList` store entry, key the thread factory with `withKey(id, …)` so history reloads when the visible thread changes.
|
|
231
231
|
|
|
232
232
|
<PlatformTabs>
|
|
233
233
|
<Tab value="React">
|
|
@@ -244,6 +244,51 @@ import {
|
|
|
244
244
|
import { createAssistantStream } from "assistant-stream";
|
|
245
245
|
import { useMemo } from "react";
|
|
246
246
|
|
|
247
|
+
function useThreadListAdapters() {
|
|
248
|
+
const aui = useAui();
|
|
249
|
+
const history = useMemo<ThreadHistoryAdapter>(
|
|
250
|
+
() => ({
|
|
251
|
+
async load() {
|
|
252
|
+
return { messages: [] };
|
|
253
|
+
},
|
|
254
|
+
async append() {},
|
|
255
|
+
withFormat: (fmt) => ({
|
|
256
|
+
async load() {
|
|
257
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
258
|
+
if (!remoteId) return { messages: [] };
|
|
259
|
+
const rows = await fetch(
|
|
260
|
+
`/api/threads/${remoteId}/messages`,
|
|
261
|
+
).then((r) => r.json());
|
|
262
|
+
return {
|
|
263
|
+
messages: rows.map((row: any) =>
|
|
264
|
+
fmt.decode({
|
|
265
|
+
id: row.id,
|
|
266
|
+
parent_id: row.parent_id,
|
|
267
|
+
format: row.format,
|
|
268
|
+
content: row.content,
|
|
269
|
+
}),
|
|
270
|
+
),
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
async append(item) {
|
|
274
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
275
|
+
await fetch(`/api/threads/${remoteId}/messages`, {
|
|
276
|
+
method: "POST",
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
id: fmt.getId(item.message),
|
|
279
|
+
parent_id: item.parentId,
|
|
280
|
+
format: fmt.format,
|
|
281
|
+
content: fmt.encode(item),
|
|
282
|
+
}),
|
|
283
|
+
});
|
|
284
|
+
},
|
|
285
|
+
}),
|
|
286
|
+
}),
|
|
287
|
+
[aui],
|
|
288
|
+
);
|
|
289
|
+
return useMemo(() => ({ history }), [history]);
|
|
290
|
+
}
|
|
291
|
+
|
|
247
292
|
export const threadListAdapter: RemoteThreadListAdapter = {
|
|
248
293
|
async list() {
|
|
249
294
|
const rows = await fetch("/api/threads").then((r) => r.json());
|
|
@@ -295,50 +340,11 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
295
340
|
controller.appendText(title);
|
|
296
341
|
});
|
|
297
342
|
},
|
|
343
|
+
unstable_useAdapters: useThreadListAdapters,
|
|
298
344
|
unstable_Provider({ children }) {
|
|
299
|
-
const
|
|
300
|
-
const history = useMemo<ThreadHistoryAdapter>(
|
|
301
|
-
() => ({
|
|
302
|
-
async load() {
|
|
303
|
-
return { messages: [] };
|
|
304
|
-
},
|
|
305
|
-
async append() {},
|
|
306
|
-
withFormat: (fmt) => ({
|
|
307
|
-
async load() {
|
|
308
|
-
const { remoteId } = aui.threadListItem.getState();
|
|
309
|
-
if (!remoteId) return { messages: [] };
|
|
310
|
-
const rows = await fetch(
|
|
311
|
-
`/api/threads/${remoteId}/messages`,
|
|
312
|
-
).then((r) => r.json());
|
|
313
|
-
return {
|
|
314
|
-
messages: rows.map((row: any) =>
|
|
315
|
-
fmt.decode({
|
|
316
|
-
id: row.id,
|
|
317
|
-
parent_id: row.parent_id,
|
|
318
|
-
format: row.format,
|
|
319
|
-
content: row.content,
|
|
320
|
-
}),
|
|
321
|
-
),
|
|
322
|
-
};
|
|
323
|
-
},
|
|
324
|
-
async append(item) {
|
|
325
|
-
const { remoteId } = await aui.threadListItem.initialize();
|
|
326
|
-
await fetch(`/api/threads/${remoteId}/messages`, {
|
|
327
|
-
method: "POST",
|
|
328
|
-
body: JSON.stringify({
|
|
329
|
-
id: fmt.getId(item.message),
|
|
330
|
-
parent_id: item.parentId,
|
|
331
|
-
format: fmt.format,
|
|
332
|
-
content: fmt.encode(item),
|
|
333
|
-
}),
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
}),
|
|
337
|
-
}),
|
|
338
|
-
[aui],
|
|
339
|
-
);
|
|
345
|
+
const adapters = useThreadListAdapters();
|
|
340
346
|
return (
|
|
341
|
-
<RuntimeAdapterProvider adapters={
|
|
347
|
+
<RuntimeAdapterProvider adapters={adapters}>
|
|
342
348
|
{children}
|
|
343
349
|
</RuntimeAdapterProvider>
|
|
344
350
|
);
|
|
@@ -359,6 +365,51 @@ import {
|
|
|
359
365
|
import { createAssistantStream } from "assistant-stream";
|
|
360
366
|
import { useMemo } from "react";
|
|
361
367
|
|
|
368
|
+
function useThreadListAdapters() {
|
|
369
|
+
const aui = useAui();
|
|
370
|
+
const history = useMemo<ThreadHistoryAdapter>(
|
|
371
|
+
() => ({
|
|
372
|
+
async load() {
|
|
373
|
+
return { messages: [] };
|
|
374
|
+
},
|
|
375
|
+
async append() {},
|
|
376
|
+
withFormat: (fmt) => ({
|
|
377
|
+
async load() {
|
|
378
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
379
|
+
if (!remoteId) return { messages: [] };
|
|
380
|
+
const rows = await fetch(
|
|
381
|
+
`${API_URL}/threads/${remoteId}/messages`,
|
|
382
|
+
).then((r) => r.json());
|
|
383
|
+
return {
|
|
384
|
+
messages: rows.map((row: any) =>
|
|
385
|
+
fmt.decode({
|
|
386
|
+
id: row.id,
|
|
387
|
+
parent_id: row.parent_id,
|
|
388
|
+
format: row.format,
|
|
389
|
+
content: row.content,
|
|
390
|
+
}),
|
|
391
|
+
),
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
async append(item) {
|
|
395
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
396
|
+
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
397
|
+
method: "POST",
|
|
398
|
+
body: JSON.stringify({
|
|
399
|
+
id: fmt.getId(item.message),
|
|
400
|
+
parent_id: item.parentId,
|
|
401
|
+
format: fmt.format,
|
|
402
|
+
content: fmt.encode(item),
|
|
403
|
+
}),
|
|
404
|
+
});
|
|
405
|
+
},
|
|
406
|
+
}),
|
|
407
|
+
}),
|
|
408
|
+
[aui],
|
|
409
|
+
);
|
|
410
|
+
return useMemo(() => ({ history }), [history]);
|
|
411
|
+
}
|
|
412
|
+
|
|
362
413
|
export const threadListAdapter: RemoteThreadListAdapter = {
|
|
363
414
|
async list() {
|
|
364
415
|
const rows = await fetch(`${API_URL}/threads`).then((r) => r.json());
|
|
@@ -412,50 +463,11 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
412
463
|
controller.appendText(title);
|
|
413
464
|
});
|
|
414
465
|
},
|
|
466
|
+
unstable_useAdapters: useThreadListAdapters,
|
|
415
467
|
unstable_Provider({ children }) {
|
|
416
|
-
const
|
|
417
|
-
const history = useMemo<ThreadHistoryAdapter>(
|
|
418
|
-
() => ({
|
|
419
|
-
async load() {
|
|
420
|
-
return { messages: [] };
|
|
421
|
-
},
|
|
422
|
-
async append() {},
|
|
423
|
-
withFormat: (fmt) => ({
|
|
424
|
-
async load() {
|
|
425
|
-
const { remoteId } = aui.threadListItem.getState();
|
|
426
|
-
if (!remoteId) return { messages: [] };
|
|
427
|
-
const rows = await fetch(
|
|
428
|
-
`${API_URL}/threads/${remoteId}/messages`,
|
|
429
|
-
).then((r) => r.json());
|
|
430
|
-
return {
|
|
431
|
-
messages: rows.map((row: any) =>
|
|
432
|
-
fmt.decode({
|
|
433
|
-
id: row.id,
|
|
434
|
-
parent_id: row.parent_id,
|
|
435
|
-
format: row.format,
|
|
436
|
-
content: row.content,
|
|
437
|
-
}),
|
|
438
|
-
),
|
|
439
|
-
};
|
|
440
|
-
},
|
|
441
|
-
async append(item) {
|
|
442
|
-
const { remoteId } = await aui.threadListItem.initialize();
|
|
443
|
-
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
444
|
-
method: "POST",
|
|
445
|
-
body: JSON.stringify({
|
|
446
|
-
id: fmt.getId(item.message),
|
|
447
|
-
parent_id: item.parentId,
|
|
448
|
-
format: fmt.format,
|
|
449
|
-
content: fmt.encode(item),
|
|
450
|
-
}),
|
|
451
|
-
});
|
|
452
|
-
},
|
|
453
|
-
}),
|
|
454
|
-
}),
|
|
455
|
-
[aui],
|
|
456
|
-
);
|
|
468
|
+
const adapters = useThreadListAdapters();
|
|
457
469
|
return (
|
|
458
|
-
<RuntimeAdapterProvider adapters={
|
|
470
|
+
<RuntimeAdapterProvider adapters={adapters}>
|
|
459
471
|
{children}
|
|
460
472
|
</RuntimeAdapterProvider>
|
|
461
473
|
);
|
|
@@ -478,6 +490,51 @@ import {
|
|
|
478
490
|
import { createAssistantStream } from "assistant-stream";
|
|
479
491
|
import { useMemo } from "react";
|
|
480
492
|
|
|
493
|
+
function useThreadListAdapters() {
|
|
494
|
+
const aui = useAui();
|
|
495
|
+
const history = useMemo<ThreadHistoryAdapter>(
|
|
496
|
+
() => ({
|
|
497
|
+
async load() {
|
|
498
|
+
return { messages: [] };
|
|
499
|
+
},
|
|
500
|
+
async append() {},
|
|
501
|
+
withFormat: (fmt) => ({
|
|
502
|
+
async load() {
|
|
503
|
+
const { remoteId } = aui.threadListItem.getState();
|
|
504
|
+
if (!remoteId) return { messages: [] };
|
|
505
|
+
const rows = await fetch(
|
|
506
|
+
`${API_URL}/threads/${remoteId}/messages`,
|
|
507
|
+
).then((r) => r.json());
|
|
508
|
+
return {
|
|
509
|
+
messages: rows.map((row: any) =>
|
|
510
|
+
fmt.decode({
|
|
511
|
+
id: row.id,
|
|
512
|
+
parent_id: row.parent_id,
|
|
513
|
+
format: row.format,
|
|
514
|
+
content: row.content,
|
|
515
|
+
}),
|
|
516
|
+
),
|
|
517
|
+
};
|
|
518
|
+
},
|
|
519
|
+
async append(item) {
|
|
520
|
+
const { remoteId } = await aui.threadListItem.initialize();
|
|
521
|
+
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
522
|
+
method: "POST",
|
|
523
|
+
body: JSON.stringify({
|
|
524
|
+
id: fmt.getId(item.message),
|
|
525
|
+
parent_id: item.parentId,
|
|
526
|
+
format: fmt.format,
|
|
527
|
+
content: fmt.encode(item),
|
|
528
|
+
}),
|
|
529
|
+
});
|
|
530
|
+
},
|
|
531
|
+
}),
|
|
532
|
+
}),
|
|
533
|
+
[aui],
|
|
534
|
+
);
|
|
535
|
+
return useMemo(() => ({ history }), [history]);
|
|
536
|
+
}
|
|
537
|
+
|
|
481
538
|
export const threadListAdapter: RemoteThreadListAdapter = {
|
|
482
539
|
async list() {
|
|
483
540
|
const rows = await fetch(`${API_URL}/threads`).then((r) => r.json());
|
|
@@ -531,50 +588,11 @@ export const threadListAdapter: RemoteThreadListAdapter = {
|
|
|
531
588
|
controller.appendText(title);
|
|
532
589
|
});
|
|
533
590
|
},
|
|
591
|
+
unstable_useAdapters: useThreadListAdapters,
|
|
534
592
|
unstable_Provider({ children }) {
|
|
535
|
-
const
|
|
536
|
-
const history = useMemo<ThreadHistoryAdapter>(
|
|
537
|
-
() => ({
|
|
538
|
-
async load() {
|
|
539
|
-
return { messages: [] };
|
|
540
|
-
},
|
|
541
|
-
async append() {},
|
|
542
|
-
withFormat: (fmt) => ({
|
|
543
|
-
async load() {
|
|
544
|
-
const { remoteId } = aui.threadListItem.getState();
|
|
545
|
-
if (!remoteId) return { messages: [] };
|
|
546
|
-
const rows = await fetch(
|
|
547
|
-
`${API_URL}/threads/${remoteId}/messages`,
|
|
548
|
-
).then((r) => r.json());
|
|
549
|
-
return {
|
|
550
|
-
messages: rows.map((row: any) =>
|
|
551
|
-
fmt.decode({
|
|
552
|
-
id: row.id,
|
|
553
|
-
parent_id: row.parent_id,
|
|
554
|
-
format: row.format,
|
|
555
|
-
content: row.content,
|
|
556
|
-
}),
|
|
557
|
-
),
|
|
558
|
-
};
|
|
559
|
-
},
|
|
560
|
-
async append(item) {
|
|
561
|
-
const { remoteId } = await aui.threadListItem.initialize();
|
|
562
|
-
await fetch(`${API_URL}/threads/${remoteId}/messages`, {
|
|
563
|
-
method: "POST",
|
|
564
|
-
body: JSON.stringify({
|
|
565
|
-
id: fmt.getId(item.message),
|
|
566
|
-
parent_id: item.parentId,
|
|
567
|
-
format: fmt.format,
|
|
568
|
-
content: fmt.encode(item),
|
|
569
|
-
}),
|
|
570
|
-
});
|
|
571
|
-
},
|
|
572
|
-
}),
|
|
573
|
-
}),
|
|
574
|
-
[aui],
|
|
575
|
-
);
|
|
593
|
+
const adapters = useThreadListAdapters();
|
|
576
594
|
return (
|
|
577
|
-
<RuntimeAdapterProvider adapters={
|
|
595
|
+
<RuntimeAdapterProvider adapters={adapters}>
|
|
578
596
|
{children}
|
|
579
597
|
</RuntimeAdapterProvider>
|
|
580
598
|
);
|
|
@@ -728,7 +746,7 @@ Send a message in a fresh thread. Check the database:
|
|
|
728
746
|
|
|
729
747
|
## Notes
|
|
730
748
|
|
|
731
|
-
- **First-message race.** `append` may fire before the thread row exists. The
|
|
749
|
+
- **First-message race.** `append` may fire before the thread row exists. The example above always awaits `aui.threadListItem.initialize()` before writing; do the same in any custom implementation.
|
|
732
750
|
- **Reload after async auth.** If `auth()` resolves after the initial `list()` call, threads won't appear until the user refreshes. Call `aui.threads.reload()` from a `useEffect` watching the session. Pattern is documented in [threads](/docs/runtimes/concepts/threads#reloading-after-async-authentication).
|
|
733
751
|
- **Format string.** The `format` column is *not* a free-text label; it identifies the on-disk shape so multiple runtimes can coexist. Don't strip it. Don't make assumptions about its value (`useChatRuntime` is responsible for setting and decoding it).
|
|
734
752
|
- **Pending approvals need `update`.** Tool call approvals persist across reloads only when the formatted adapter implements `update`; omitting it keeps the pre-approval snapshot out of storage by design.
|
|
@@ -73,20 +73,18 @@ export default defineToolkit({
|
|
|
73
73
|
|
|
74
74
|
import {
|
|
75
75
|
AssistantRuntimeProvider,
|
|
76
|
+
AuiConfig,
|
|
76
77
|
Tools,
|
|
77
|
-
useAui,
|
|
78
78
|
} from "@assistant-ui/react";
|
|
79
79
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
80
80
|
import toolkit from "./toolkit";
|
|
81
81
|
|
|
82
82
|
export function App() {
|
|
83
83
|
const runtime = useChatRuntime();
|
|
84
|
-
const
|
|
85
|
-
tools: Tools({ toolkit }),
|
|
86
|
-
});
|
|
84
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
87
85
|
|
|
88
86
|
return (
|
|
89
|
-
<AssistantRuntimeProvider
|
|
87
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
90
88
|
<Thread />
|
|
91
89
|
</AssistantRuntimeProvider>
|
|
92
90
|
);
|
|
@@ -100,7 +98,7 @@ export function App() {
|
|
|
100
98
|
1. Create a `Toolkit` object.
|
|
101
99
|
2. Move each `toolName` into the toolkit key.
|
|
102
100
|
3. Move `description`, `parameters`, `execute`, `providerOptions`, `render`, `renderText`, and `display` onto the toolkit entry.
|
|
103
|
-
4. Register the toolkit once with `
|
|
101
|
+
4. Register the toolkit once with `config={config}` on your runtime provider, where `const config = AuiConfig({ tools: Tools({ toolkit }) })`.
|
|
104
102
|
5. Remove `<Tool />`, `<ToolUI />`, `useAssistantTool(...)`, and `useAssistantToolUI(...)` registrations.
|
|
105
103
|
|
|
106
104
|
## UI-Only Tool Renderers
|
|
@@ -126,7 +124,7 @@ export default defineToolkit({
|
|
|
126
124
|
});
|
|
127
125
|
```
|
|
128
126
|
|
|
129
|
-
Register it like any toolkit: `
|
|
127
|
+
Register it like any toolkit: `config={config}` where `const config = AuiConfig({ tools: Tools({ toolkit }) })`.
|
|
130
128
|
Render-only entries upload no schema and run no browser code — they only attach
|
|
131
129
|
UI for matching tool-call message parts. For MCP server catalogs, spread
|
|
132
130
|
`defineMcpToolkit({ ... })` in the same generative toolkit.
|
|
@@ -163,20 +161,24 @@ export default defineToolkit({
|
|
|
163
161
|
```
|
|
164
162
|
|
|
165
163
|
```tsx title="TaskBoard.tsx"
|
|
166
|
-
import {
|
|
164
|
+
import {
|
|
165
|
+
AuiConfig,
|
|
166
|
+
AuiProvider,
|
|
167
|
+
Tools,
|
|
168
|
+
useAui,
|
|
169
|
+
useAuiToolOverrides,
|
|
170
|
+
} from "@assistant-ui/react";
|
|
167
171
|
import { useState, type Dispatch, type SetStateAction } from "react";
|
|
168
172
|
import type { Task } from "./task-board-toolkit";
|
|
169
173
|
import toolkit from "./task-board-toolkit";
|
|
170
174
|
|
|
171
175
|
function TaskBoard() {
|
|
172
176
|
const [tasks, setTasks] = useState<Task[]>([]);
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
tools: Tools({ toolkit }),
|
|
176
|
-
});
|
|
177
|
+
const aui = useAui();
|
|
178
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
177
179
|
|
|
178
180
|
return (
|
|
179
|
-
<AuiProvider
|
|
181
|
+
<AuiProvider extends={aui} config={config}>
|
|
180
182
|
<TaskBoardToolOverrides setTasks={setTasks} />
|
|
181
183
|
<TaskList tasks={tasks} />
|
|
182
184
|
</AuiProvider>
|
|
@@ -133,16 +133,130 @@ const aui = useAui(scopes, { parent });
|
|
|
133
133
|
|
|
134
134
|
// After
|
|
135
135
|
const Scoped = ({ children }) => {
|
|
136
|
-
const aui = useAui(
|
|
137
|
-
|
|
136
|
+
const aui = useAui();
|
|
137
|
+
const config = AuiConfig(scopes);
|
|
138
|
+
return (
|
|
139
|
+
<AuiProvider extends={aui} config={config}>
|
|
140
|
+
{children}
|
|
141
|
+
</AuiProvider>
|
|
142
|
+
);
|
|
138
143
|
};
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
const rootConfig = AuiConfig({});
|
|
146
|
+
|
|
147
|
+
<AuiProvider extends={parent} config={rootConfig}>
|
|
141
148
|
<Scoped />
|
|
142
149
|
</AuiProvider>;
|
|
143
150
|
```
|
|
144
151
|
|
|
145
|
-
Where `{ parent: null }` was used to detach from context, `<AuiProvider
|
|
152
|
+
Where `{ parent: null }` was used to detach from context, `<AuiProvider extends={null} config={config}>` where `const config = AuiConfig({})` now provides an isolated empty root.
|
|
153
|
+
|
|
154
|
+
## `AuiProvider` Grammar
|
|
155
|
+
|
|
156
|
+
`AuiProvider` takes a `config` built with `AuiConfig(...)` — raw object literals are a type error. At the top level, `config` alone creates the subtree's client. Nested under a parent provider, `extends` is mandatory: `extends={aui}` extends the parent, `extends={null}` isolates (dev-enforced). `ref` receives the resulting client after mount.
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
const aui = useAui();
|
|
160
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
161
|
+
|
|
162
|
+
// Top-level root
|
|
163
|
+
<AuiProvider config={config}>
|
|
164
|
+
|
|
165
|
+
// Nested: extend the parent
|
|
166
|
+
<AuiProvider extends={aui} config={config}>
|
|
167
|
+
|
|
168
|
+
// Nested: isolate from the parent
|
|
169
|
+
<AuiProvider extends={null} config={config}>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`AuiConfig` is exported from `@assistant-ui/store` and re-exported from `@assistant-ui/react`, `@assistant-ui/react-native`, and `@assistant-ui/react-ink`.
|
|
173
|
+
|
|
174
|
+
### `value` Prop Deprecated
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
// Before
|
|
178
|
+
<AuiProvider value={client}>
|
|
179
|
+
<AuiProvider value={null}>
|
|
180
|
+
|
|
181
|
+
// After
|
|
182
|
+
const config = AuiConfig({});
|
|
183
|
+
|
|
184
|
+
<AuiProvider extends={client} config={config}>
|
|
185
|
+
<AuiProvider extends={null} config={config}>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The replacement exposes a client extending the given one, not the same instance — `useAui()` beneath it returns the new client, with scope access delegating to `client`. The deprecated `value={client}` form behaves the same way: it also exposes a derived client rather than the exact instance, and the given client must implement `subscribe`.
|
|
189
|
+
|
|
190
|
+
### `useAui({ ... })` Extension Overload Deprecated
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
// Before
|
|
194
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
195
|
+
return <AuiProvider value={aui}>{children}</AuiProvider>;
|
|
196
|
+
|
|
197
|
+
// After
|
|
198
|
+
const aui = useAui();
|
|
199
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
200
|
+
return (
|
|
201
|
+
<AuiProvider extends={aui} config={config}>
|
|
202
|
+
{children}
|
|
203
|
+
</AuiProvider>
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Where the extended client was passed to `<AssistantRuntimeProvider aui={aui}>`, use the new `config` prop instead — the scopes are provided alongside the runtime's threads scope:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
// Before
|
|
211
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
212
|
+
return (
|
|
213
|
+
<AssistantRuntimeProvider aui={aui} runtime={runtime}>
|
|
214
|
+
{children}
|
|
215
|
+
</AssistantRuntimeProvider>
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// After
|
|
219
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
220
|
+
return (
|
|
221
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
222
|
+
{children}
|
|
223
|
+
</AssistantRuntimeProvider>
|
|
224
|
+
);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Thread Switch Events: `threads.selectionChanged`
|
|
228
|
+
|
|
229
|
+
The per-item thread switch events are deprecated in favor of a single event on the thread list. `threads.selectionChanged` fires once per switch and carries both sides of the transition:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// Before
|
|
233
|
+
useAuiEvent("threadListItem.switchedTo", ({ threadId }) => {
|
|
234
|
+
// threadId: the newly selected thread
|
|
235
|
+
});
|
|
236
|
+
useAuiEvent("threadListItem.switchedAway", ({ threadId }) => {
|
|
237
|
+
// threadId: the thread that was switched away from
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// After
|
|
241
|
+
useAuiEvent("threads.selectionChanged", ({ threadId, previousThreadId }) => {
|
|
242
|
+
// threadId: the newly selected thread
|
|
243
|
+
// previousThreadId: the thread that was switched away from
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Like its predecessors, it does not fire for the initially selected thread on mount. The deprecated events still fire and will keep working until the next major.
|
|
248
|
+
|
|
249
|
+
The deprecated pair was scope-filtered: inside a per-item `threadListItem` scope (such as `ThreadListPrimitive.Items`), `threadListItem.switchedTo` only fired for that item. `threads.selectionChanged` resolves against the shared `threads` scope, so every listener fires on every switch. Filter by id to reproduce the per-item behavior:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const id = useAuiState((s) => s.threadListItem.id);
|
|
253
|
+
useAuiEvent("threads.selectionChanged", ({ threadId }) => {
|
|
254
|
+
if (threadId !== id) return;
|
|
255
|
+
// this item became selected
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The new event also fires in situations where the deprecated pair did not: `InMemoryThreadList` emits on selection changes (it previously emitted no switch events), and `switchToNewThread()` emits for the newly created thread. Selection-driven defaults such as `scrollToBottomOnThreadSwitch` and `unstable_focusOnThreadSwitched` now engage in both situations. Runtimes that resolve a deep-linked `threadId`/`initialThreadId` after mount (such as `useRemoteThreadListRuntime`) start on a placeholder new thread, so the deep link's resolution also fires the event — `previousThreadId` is the placeholder in that case.
|
|
146
260
|
|
|
147
261
|
## Still Deprecated (not removed)
|
|
148
262
|
|
|
@@ -53,7 +53,7 @@ import { AttachmentPrimitive, ComposerPrimitive } from "@assistant-ui/react";
|
|
|
53
53
|
</ComposerPrimitive.Root>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
`Root` renders a `<div>`, `unstable_Thumb` renders a `<div>` showing the file extension with a leading dot (e.g., `.pdf`), `Name` renders plain text, and `Remove` renders a `<button>`.
|
|
56
|
+
`Root` renders a `<div>`, `unstable_Thumb` renders a `<div>` showing the file extension with a leading dot (e.g., `.pdf`), or the attachment type (e.g., `image`) when the filename has no extension (including leading-dot names like `.env`), `Name` renders plain text, and `Remove` renders a `<button>`. If you pass `children` to `unstable_Thumb`, they override that text.
|
|
57
57
|
|
|
58
58
|
<Callout type="info">
|
|
59
59
|
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
|
|
@@ -124,7 +124,7 @@ Container for a single attachment item. Renders a `<div>` element unless `asChil
|
|
|
124
124
|
|
|
125
125
|
### unstable_Thumb
|
|
126
126
|
|
|
127
|
-
Thumbnail slot for attachment previews. Renders a `<div>` element unless `asChild` is set.
|
|
127
|
+
Thumbnail slot for attachment previews. Renders a `<div>` element unless `asChild` is set. By default it shows the file extension with a leading dot (e.g., `.pdf`); if you pass `children`, they override the automatic text.
|
|
128
128
|
|
|
129
129
|
```tsx
|
|
130
130
|
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs" />
|
|
@@ -258,7 +258,7 @@ Renders a single attachment at a specific index.
|
|
|
258
258
|
|
|
259
259
|
### AttachmentDropzone
|
|
260
260
|
|
|
261
|
-
Drag-and-drop zone for file attachments. Sets `data-dragging` when a file is being dragged over it. Renders a `<div>` element unless `asChild` is set.
|
|
261
|
+
Drag-and-drop zone for file attachments. Sets `data-dragging` when a file is being dragged over it and the runtime supports attachments; without the attachments capability the dropzone accepts no files and shows no highlight. Non-file drags (text, links) are ignored. Renders a `<div>` element unless `asChild` is set.
|
|
262
262
|
|
|
263
263
|
```tsx
|
|
264
264
|
<ComposerPrimitive.AttachmentDropzone className="rounded-xl border-2 border-dashed data-[dragging]:border-primary data-[dragging]:bg-primary/5">
|
|
@@ -507,7 +507,7 @@ Wrap your composer with `AttachmentDropzone` to support dragging files directly
|
|
|
507
507
|
</ComposerPrimitive.AttachmentDropzone>
|
|
508
508
|
```
|
|
509
509
|
|
|
510
|
-
The dropzone sets `data-dragging` when a file is being dragged over it, so you can style the active state with CSS.
|
|
510
|
+
The dropzone sets `data-dragging` when a file is being dragged over it, so you can style the active state with CSS. It requires the runtime's attachments capability (an attachment adapter); without it the dropzone stays inert.
|
|
511
511
|
|
|
512
512
|
### With Voice Input
|
|
513
513
|
|
|
@@ -112,6 +112,37 @@ Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRun
|
|
|
112
112
|
For most new code, prefer `MessagePrimitive.Parts` with a `children` render function. When you need adjacent grouping, use `MessagePrimitive.GroupedParts`.
|
|
113
113
|
</Callout>
|
|
114
114
|
|
|
115
|
+
### Part Types
|
|
116
|
+
|
|
117
|
+
A message part is one of three kinds, and which kind a new capability belongs to is decided by the list below rather than case by case.
|
|
118
|
+
|
|
119
|
+
| Kind | Parts | Grows by |
|
|
120
|
+
|------|-------|----------|
|
|
121
|
+
| Modality | `text`, `image`, `file` | Never. `file` carries every non-image binary modality through its `mimeType`. |
|
|
122
|
+
| Provider channel | `reasoning`, `source`, `tool-call`, `generative-ui` | Never. These mirror channels a model already emits. |
|
|
123
|
+
| Extensibility | `data` | Freely, through `name`. This is the growth path for anything app-level. |
|
|
124
|
+
|
|
125
|
+
`file` is the media carrier. Audio, video, PDFs and everything else are `{ type: "file", mimeType: "audio/mpeg" }` rather than part types of their own, so one renderer and one converter branch handle them all. The payload can be inline base64 or a URL; `sourceType` additionally allows an opaque storage id, which the LangChain-family runtimes honor and other adapters ignore.
|
|
126
|
+
|
|
127
|
+
Anything that is not a modality the model consumes or a channel it emits is a `data` part, routed by `name`:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<MessagePrimitive.Parts
|
|
131
|
+
components={{
|
|
132
|
+
data: {
|
|
133
|
+
by_name: { citation: MyCitation },
|
|
134
|
+
Fallback: MyDataFallback,
|
|
135
|
+
},
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
<Callout type="warn">
|
|
141
|
+
`Unstable_AudioMessagePart` and the `Unstable_Audio` slot are deprecated. The audio part cannot carry a filename, has no way to declare how its payload goes on the wire (no `sourceType`, so no storage id), and exists only on user messages, so a model that returns audio has no way to express it. Send audio as a `file` part with an `audio/*` mime type instead, and give it a filename.
|
|
142
|
+
|
|
143
|
+
Adapter coverage for the file path is still uneven, so check your adapter's converter before relying on file parts. Known so far: `react-pi` and the assistant-transport runtime have no file part on their user-content surface at all, so one is dropped; `react-data-stream` carries the payload but not the filename. Existing audio parts keep working; they will not gain fields.
|
|
144
|
+
</Callout>
|
|
145
|
+
|
|
115
146
|
### Tool Resolution
|
|
116
147
|
|
|
117
148
|
Tool call parts resolve in this order:
|
|
@@ -149,7 +180,8 @@ Returning `null` still allows registered tool UIs and data renderer UIs to rende
|
|
|
149
180
|
- `components.ChainOfThought` takes over all reasoning and tool-call rendering (mutually exclusive with `ToolGroup`, `ReasoningGroup`, `tools`, and `Reasoning`). This legacy path is deprecated; use `MessagePrimitive.GroupedParts` for grouped Chain of Thought in new code.
|
|
150
181
|
- `data.by_name` and `data.Fallback` let you route custom data part types
|
|
151
182
|
- `Quote` renders quoted message references from metadata
|
|
152
|
-
- `Empty`
|
|
183
|
+
- `Empty` is available for edge rendering paths
|
|
184
|
+
- `Unstable_Audio` is deprecated; render `audio/*` from the `File` slot instead
|
|
153
185
|
|
|
154
186
|
```tsx
|
|
155
187
|
<MessagePrimitive.Parts
|
|
@@ -106,7 +106,7 @@ Both render a `<span>` and accept `children` to override the value from state:
|
|
|
106
106
|
|
|
107
107
|
`Trigger`'s `send` prop controls what happens on click:
|
|
108
108
|
|
|
109
|
-
- **`send={true}`**: immediately sends the suggestion as a new message.
|
|
109
|
+
- **`send={true}`**: immediately sends the suggestion as a new message. While a run is in progress, the suggestion is queued on runtimes that support queueing (leaving the composer draft untouched); otherwise the trigger is disabled.
|
|
110
110
|
- **`send={false}`** (default): populates the composer text so the user can edit before sending
|
|
111
111
|
|
|
112
112
|
```tsx
|
|
@@ -130,11 +130,13 @@ When `send={false}`, the `clearComposer` prop controls whether the suggestion re
|
|
|
130
130
|
|
|
131
131
|
### Static configuration vs. runtime suggestions
|
|
132
132
|
|
|
133
|
-
There are two
|
|
133
|
+
There are two data flows for suggestions:
|
|
134
134
|
|
|
135
135
|
- **Static configuration** flows through the `suggestions` scope. Pass an array to `Suggestions(...)` in your runtime provider; render it with `ThreadPrimitive.Suggestions`. Best for welcome screen prompts.
|
|
136
136
|
- **Runtime / dynamic suggestions** flow through `thread.suggestions`. Populate it via `SuggestionAdapter` (local runtime) or the `suggestions` field on `useExternalStoreRuntime`; render it with the shadcn `ThreadFollowupSuggestions` component or your own component reading `useAuiState((s) => s.thread.suggestions)`. Best for follow up prompts after a turn.
|
|
137
137
|
|
|
138
|
+
When no static configuration is provided, the `suggestions` scope derives from `thread.suggestions`, so runtime suggestions also render through `ThreadPrimitive.Suggestions`. A static `Suggestions(...)` configuration takes precedence over the derived values.
|
|
139
|
+
|
|
138
140
|
See [Suggested Prompts](/docs/guides/suggestions) for end to end examples.
|
|
139
141
|
|
|
140
142
|
### ThreadPrimitive.Suggestion (Legacy)
|
|
@@ -143,7 +143,7 @@ Use `topAnchorMessageClamp` to control how much of a long user message remains v
|
|
|
143
143
|
|
|
144
144
|
- `scrollToBottomOnRunStart` (default `true`): scrolls when `thread.runStart` fires
|
|
145
145
|
- `scrollToBottomOnInitialize` (default `true`): scrolls when `thread.initialize` fires
|
|
146
|
-
- `scrollToBottomOnThreadSwitch` (default `true`): scrolls when `
|
|
146
|
+
- `scrollToBottomOnThreadSwitch` (default `true`): scrolls when `threads.selectionChanged` fires
|
|
147
147
|
|
|
148
148
|
These work alongside `autoScroll`. If `autoScroll` is omitted, it defaults to `true` for `turnAnchor="bottom"` and `false` for `turnAnchor="top"`.
|
|
149
149
|
|