@assistant-ui/mcp-docs-server 0.2.1 → 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 +1 -1
- package/.docs/organized/code-examples/with-a2a.md +2 -2
- package/.docs/organized/code-examples/with-ag-ui.md +3 -3
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +5 -5
- package/.docs/organized/code-examples/with-artifacts.md +5 -5
- package/.docs/organized/code-examples/with-assistant-transport.md +3 -3
- package/.docs/organized/code-examples/with-browser-extension.md +4 -4
- package/.docs/organized/code-examples/with-chain-of-thought.md +5 -5
- package/.docs/organized/code-examples/with-cloud-standalone.md +5 -5
- package/.docs/organized/code-examples/with-cloud.md +5 -5
- package/.docs/organized/code-examples/with-custom-thread-list.md +6 -6
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +7 -7
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +8 -8
- package/.docs/organized/code-examples/with-eve.md +3 -3
- package/.docs/organized/code-examples/with-expo.md +13 -19
- package/.docs/organized/code-examples/with-external-store.md +3 -3
- package/.docs/organized/code-examples/with-ffmpeg.md +5 -5
- package/.docs/organized/code-examples/with-generative-ui.md +259 -23
- package/.docs/organized/code-examples/with-google-adk.md +2 -2
- package/.docs/organized/code-examples/with-heat-graph.md +1 -1
- package/.docs/organized/code-examples/with-image-generation.md +4 -4
- package/.docs/organized/code-examples/with-interactables.md +5 -5
- package/.docs/organized/code-examples/with-langchain.md +7 -7
- package/.docs/organized/code-examples/with-langgraph.md +4 -4
- package/.docs/organized/code-examples/with-livekit.md +7 -7
- package/.docs/organized/code-examples/with-mcp.md +6 -6
- package/.docs/organized/code-examples/with-nuxt.md +500 -564
- package/.docs/organized/code-examples/with-opencode.md +2 -2
- package/.docs/organized/code-examples/with-openui.md +449 -0
- package/.docs/organized/code-examples/with-pi.md +2 -2
- package/.docs/organized/code-examples/with-react-hook-form.md +7 -7
- package/.docs/organized/code-examples/with-react-ink-web.md +4 -4
- package/.docs/organized/code-examples/with-react-ink.md +2 -2
- package/.docs/organized/code-examples/with-react-router.md +4 -4
- package/.docs/organized/code-examples/with-resumable-stream.md +7 -7
- package/.docs/organized/code-examples/with-store.md +1 -1
- 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 +5 -5
- package/.docs/organized/code-examples/with-tap-runtime.md +2 -2
- package/.docs/organized/code-examples/with-virtualized-thread.md +2 -2
- package/.docs/organized/code-examples/with-vue.md +1 -1
- package/.docs/raw/docs/(docs)/cli.mdx +6 -1
- package/.docs/raw/docs/(docs)/installation.mdx +2 -2
- 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 +39 -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 +29 -1
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk.mdx +2 -2
- package/.docs/raw/docs/cloud/index.mdx +1 -1
- package/.docs/raw/docs/guides/attachments.mdx +2 -2
- package/.docs/raw/docs/guides/context-api.mdx +15 -17
- package/.docs/raw/docs/guides/dictation.mdx +1 -1
- package/.docs/raw/docs/guides/mentions.mdx +2 -0
- package/.docs/raw/docs/guides/suggestions.mdx +6 -3
- package/.docs/raw/docs/ink/primitives.mdx +1 -1
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +146 -128
- package/.docs/raw/docs/migrations/v0-15.mdx +34 -0
- package/.docs/raw/docs/primitives/suggestion.mdx +3 -1
- package/.docs/raw/docs/primitives/thread.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +35 -5
- 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 +68 -28
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +6 -2
- package/.docs/raw/docs/runtimes/langchain.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +4 -0
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +8 -1
- package/.docs/raw/docs/tools/defining-tools.mdx +19 -0
- 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 +5 -4
- package/.docs/raw/docs/tools/openui.mdx +175 -0
- package/.docs/raw/docs/tools/tool-ui.mdx +1 -2
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +5 -1
- package/.docs/raw/docs/ui/attachment.mdx +27 -0
- package/.docs/raw/docs/ui/file.mdx +1 -1
- package/.docs/raw/docs/ui/image.mdx +1 -1
- package/package.json +4 -4
- package/.docs/raw/docs/tools/interactables-legacy.mdx +0 -423
|
@@ -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.
|
|
@@ -224,6 +224,40 @@ return (
|
|
|
224
224
|
);
|
|
225
225
|
```
|
|
226
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.
|
|
260
|
+
|
|
227
261
|
## Still Deprecated (not removed)
|
|
228
262
|
|
|
229
263
|
- Primitive `If` components (`ThreadPrimitive.If`, `MessagePrimitive.If`, `ThreadPrimitive.Empty`) — replaced by `AuiIf`. The codemod migrates these.
|
|
@@ -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
|
|
|
@@ -16,7 +16,7 @@ Reference for the runtime's API surface. Start with [quickstart](/docs/runtimes/
|
|
|
16
16
|
| `showThinking` | `boolean` | Whether to render `THINKING_*` and `REASONING_*` events as visible reasoning. Defaults to `true`. |
|
|
17
17
|
| `autoCancelPendingToolCalls` | `boolean` | Cancel unresolved client-side tool calls automatically when the user sends, edits, or reloads a message. Defaults to `true`. See [below](#auto-cancelling-pending-tool-calls). |
|
|
18
18
|
| `onError` | `(e: Error) => void` | Error callback fired on `RUN_ERROR` events and protocol errors. |
|
|
19
|
-
| `onCancel` | `() => void` | Cancellation callback fired when
|
|
19
|
+
| `onCancel` | `() => void` | Cancellation callback fired when a run is cancelled, including user cancel and runtime teardown. |
|
|
20
20
|
| `adapters` | `UseAgUiRuntimeAdapters` | Standard adapter slots (see below). |
|
|
21
21
|
|
|
22
22
|
## Adapter slots
|
|
@@ -64,8 +64,20 @@ messages are gone on the next page load.
|
|
|
64
64
|
|
|
65
65
|
`fromAgUiMessages` accepts an optional second argument: pass
|
|
66
66
|
`{ showThinking: false }` to match a runtime configured with
|
|
67
|
-
`showThinking: false`, so
|
|
68
|
-
time, the same way a live run never stores
|
|
67
|
+
`showThinking: false`, so the readable text of an imported reasoning message is
|
|
68
|
+
dropped at conversion time, the same way a live run never stores it. An
|
|
69
|
+
`encryptedValue` on that message is kept, because it is opaque state the agent
|
|
70
|
+
needs back rather than something the option hides.
|
|
71
|
+
|
|
72
|
+
Reasoning makes the round trip in the shape it arrived in. `fromAgUiMessages` imports a `reasoning` record as an assistant message holding a reasoning part, and the run input converts that part back into a standalone `reasoning` record instead of dropping it, so a reloaded thread keeps its reasoning history on the next run. A reasoning part on an assistant message that also has text or tool calls leaves as its own `reasoning` record placed ahead of that assistant record; the AG-UI message body carries no run identity, so the original position of reasoning within a run is not recoverable.
|
|
73
|
+
|
|
74
|
+
The encrypted value survives with it. AG-UI describes it as an opaque chain-of-thought blob the client stores and forwards for state continuity, not as a signature computed over the text. An imported `ReasoningMessage` carrying `encryptedValue` keeps it at `providerMetadata.agui.encryptedValue` on the part, and a live run picks the same value up from the `REASONING_ENCRYPTED_VALUE` event (`subtype: "message"`, keyed by `entityId`), so reasoning from either source is re-emitted with the value intact and an agent that needs it back can replay it. A record whose readable `content` is empty and whose payload lives entirely in `encryptedValue`, the zero-data-retention shape AG-UI describes when an agent advertises `capabilities.reasoning.encrypted`, is preserved on the import path only. It has nothing to render by construction, so it never becomes a message or a part; it rides on `metadata.custom.agui.opaqueReasoning` of the message it sat next to on the wire and is replayed into the run input adjacent to that message. `showThinking` does not discard it. That option hides reasoning from the UI, and the encrypted value is opaque state the agent needs back rather than something rendered, so a hidden record keeps it and loses only the readable text. This is an import-path guarantee: a live run with `showThinking: false` opens no reasoning block, so a `REASONING_ENCRYPTED_VALUE` arriving during it resolves no slot and is not retained. The same thread therefore carries the value after a reload but not within the live session that produced it. A consumer calling `fromAgUiMessages` directly sees the metadata rather than a part.
|
|
75
|
+
|
|
76
|
+
Three limits apply to that record. A live stream that emits no readable content produces no reasoning part, so the runtime has nothing to attach the value to; only `fromAgUiMessages` preserves it, whether you call it yourself or the runtime calls it for you while importing a `MESSAGES_SNAPSHOT`. A record that sat between an assistant message and its own tool result is replayed after that tool result rather than between the two, because the import folds the result into the assistant message and the boundary is gone by export. A record in a snapshot that contains no other message has nothing to anchor to and is dropped.
|
|
77
|
+
|
|
78
|
+
Sending reasoning back is what the protocol asks for, and the inbound side has to handle it. `ag-ui-langgraph` is worth pinning for that reason: below 0.0.36 it raises `ValueError: Unsupported message role: reasoning` on the second turn of any thread that produced reasoning, because its converter recognised only the user, assistant, system, and tool roles. 0.0.36 skips inbound `reasoning` and `developer` records instead of raising, so the turn succeeds but the reasoning is discarded. 0.0.42 re-attaches an inbound `reasoning` record as a content block on the assistant message that follows it, encrypted content included, so the replay actually reaches the model; a record that no assistant message follows is still discarded there, which is what becomes of one replayed after the last message of a thread. Keep it at 0.0.36 or newer to avoid the error, and at 0.0.42 or newer for the replay to be worth anything.
|
|
79
|
+
|
|
80
|
+
What a server does with a replayed record remains its own choice, so treat continuity as best effort rather than guaranteed. `ag-ui-langgraph` covers all three behaviours across those three versions, and another integration may pick any of them; an `encryptedValue` reaches the provider only where the server forwards it.
|
|
69
81
|
|
|
70
82
|
`fromAgUiMessages` reconstructs the text, reasoning, and tool calls of each message. Multimodal user input (`image`, `audio`, `video`, and `document` parts, as well as legacy `binary` parts) is restored as attachments on the user message, so a backend that persists multimodal messages shows them again on reload and re-sends them on the next run. Legacy `binary` parts that only reference a file id are not restored.
|
|
71
83
|
|
|
@@ -183,8 +195,25 @@ The runtime parses the AG-UI event stream and maps each event type to assistant-
|
|
|
183
195
|
| `STATE_SNAPSHOT` | Replaces the agent's external state. |
|
|
184
196
|
| `STATE_DELTA` | Applies a JSON-patch-style delta to the agent's state. |
|
|
185
197
|
| `MESSAGES_SNAPSHOT` | Replaces the full message list (used for thread restore). |
|
|
186
|
-
| `CUSTOM` |
|
|
187
|
-
| `RAW` |
|
|
198
|
+
| `CUSTOM` | Appended to the in-flight assistant message as a `data` part. |
|
|
199
|
+
| `RAW` | Parsed and ignored; unrecognized wire event types are normalized into `RAW`. |
|
|
200
|
+
|
|
201
|
+
### Custom events
|
|
202
|
+
|
|
203
|
+
`CUSTOM` events are the protocol's extension mechanism for application-defined data. Each event is appended to the in-flight assistant message as a canonical `data` part in arrival order: `CUSTOM { name: "sources", value: {...} }` becomes `{ type: "data", name: "sources", data: {...} }`. Repeated names append separate parts, the `value` is passed through verbatim, and data parts reset with each run. Tool calls that carry a `parentMessageId` are anchored under that message rather than at their wire position, so a data part can render after a tool call that arrived later. A run that delivers its assistant message only through `MESSAGES_SNAPSHOT`, with no streamed text or tool calls, drops that run's data parts when the snapshot supersedes the in-flight message.
|
|
204
|
+
|
|
205
|
+
Render them by registering a per-name renderer; parts without a registered renderer are not displayed, unless a `Data` fallback component is registered, in which case the fallback receives every custom event name, including the framework plumbing listed below.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { useAssistantDataUI } from "@assistant-ui/react";
|
|
209
|
+
|
|
210
|
+
useAssistantDataUI({
|
|
211
|
+
name: "sources",
|
|
212
|
+
render: ({ data }) => <SourceList sources={data.sources} />,
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Data parts stay in the assistant-ui message but are not sent back to the agent, since the AG-UI assistant record has no field for them. History adapters, including the assistant-cloud one, persist them as part of the message JSON. Framework integrations emit their own plumbing over this channel (`on_interrupt`, `PredictState`, `Exit`, `hook_error`, `state_update_error`, `system:*`, `MultiAgentHandoff`), and those names surface as data parts like any other, so only register renderers for names your backend owns.
|
|
188
217
|
|
|
189
218
|
## Feature support
|
|
190
219
|
|
|
@@ -195,6 +224,7 @@ The runtime parses the AG-UI event stream and maps each event type to assistant-
|
|
|
195
224
|
| Tool calls and results | Yes |
|
|
196
225
|
| Tool result handoff (client-side execution) | Yes |
|
|
197
226
|
| State snapshots and deltas | Yes |
|
|
227
|
+
| Custom events (as `data` parts) | Yes |
|
|
198
228
|
| Cancellation | Yes |
|
|
199
229
|
| Message editing | Yes |
|
|
200
230
|
| Message reload | Yes |
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Claude Managed Agents
|
|
3
|
+
description: Connect Anthropic's Managed Agents sessions to assistant-ui with the external store runtime, folding the session event log into messages, rendering approval gates, and using sessions as the thread list.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) is Anthropic's hosted agent platform: Anthropic runs the agent loop and provisions a sandboxed container per session, and your client drives the session over an event stream. A session holds the entire conversation server-side as a durable event log, streams every step (text, tool calls, approval stops, status) as typed events, and accepts user messages and tool confirmations back.
|
|
7
|
+
|
|
8
|
+
That shape maps directly onto two assistant-ui primitives, with no adapter package in between:
|
|
9
|
+
|
|
10
|
+
- [`useExternalStoreRuntime`](/docs/runtimes/custom/external-store) renders messages you derive from the session's event log. The log is the single source of truth, so replaying a stored session and tailing a live one run through the same pure function and can never disagree.
|
|
11
|
+
- [`useRemoteThreadListRuntime`](/docs/api-reference/hooks/runtimes#useremotethreadlistruntime) turns the session list into the thread sidebar. A thread is a session; there is no conversations table anywhere in the app.
|
|
12
|
+
|
|
13
|
+
Anthropic ships an official reference implementation of this integration: the [Claude Managed Agents quickstart](https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/assistant-ui) is a complete Next.js app (composer, thread, sidebar, tool cards, approval gate) built exactly this way. This page teaches the pattern; the quickstart is the runnable proof.
|
|
14
|
+
|
|
15
|
+
<Callout type="info">
|
|
16
|
+
Managed Agents is a beta API (`managed-agents-2026-04-01`; the SDK sets the header automatically). The quickstart declares `@anthropic-ai/sdk` `^0.113.0` (the session event helpers and token previews need 0.109.0 or later), and `@assistant-ui/react` 0.14.27 or later for the toolkit API and the approval gate on the external store runtime.
|
|
17
|
+
</Callout>
|
|
18
|
+
|
|
19
|
+
## The event-to-message mapping
|
|
20
|
+
|
|
21
|
+
Everything the session emits arrives as a typed event. The integration is one pure fold from the event array to assistant-ui's message model:
|
|
22
|
+
|
|
23
|
+
| Managed Agents event | assistant-ui |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `user.message` | A user message |
|
|
26
|
+
| `agent.message` | Assistant text (buffered, authoritative) |
|
|
27
|
+
| `event_start` / `event_delta` | The same text, streamed early as token previews |
|
|
28
|
+
| `agent.thinking` | A reasoning part (progress signal only; the API sends no reasoning text) |
|
|
29
|
+
| `agent.tool_use` / `agent.mcp_tool_use` / `agent.custom_tool_use` | A tool-call part; the `toolCallId` is the event id |
|
|
30
|
+
| `agent.tool_result` (and mcp / custom variants) | That part's result |
|
|
31
|
+
| `session.status_idle` with `stop_reason: requires_action` | `requires-action` message status, plus an approval on each blocked tool part |
|
|
32
|
+
| `user.tool_confirmation` | The approval, settled (allowed or denied) |
|
|
33
|
+
| `session.status_running` / `status_idle` | Whether the turn is live (`isRunning`) |
|
|
34
|
+
| `session.error` | An error status on the message, or a retry banner |
|
|
35
|
+
|
|
36
|
+
Because the fold is pure, opening an old chat replays `sessions.events.list()` through it, and a live chat feeds the SSE tail through it, and the two paths cannot render differently. Approvals, denials, and charts all come back after a reload because they are in the log, not in browser state.
|
|
37
|
+
|
|
38
|
+
The runtime wiring is a structural subset of `ThreadMessageLike`, handed to the external store as-is:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const runtime = useExternalStoreRuntime<ThreadMessageLike>({
|
|
42
|
+
messages: snapshot.messages,
|
|
43
|
+
convertMessage: (m) => m,
|
|
44
|
+
isRunning: isBusy(snapshot),
|
|
45
|
+
|
|
46
|
+
onNew: async (message) => {
|
|
47
|
+
const id = await ensureSession();
|
|
48
|
+
await sendMessage(id, textOf(message));
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// The Stop button becomes a real server-side interrupt.
|
|
52
|
+
onCancel: async () => controller.interrupt(),
|
|
53
|
+
|
|
54
|
+
// The Allow / Deny click on a gated tool call. approvalId is the
|
|
55
|
+
// tool_use event id from session.status_idle { requires_action }.
|
|
56
|
+
onRespondToToolApproval: async ({ approvalId, approved, reason }) => {
|
|
57
|
+
controller.respondToApproval(approvalId, approved, reason);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Sessions are the thread list
|
|
63
|
+
|
|
64
|
+
The sidebar is a `RemoteThreadListAdapter` over the Managed Agents session API. Thread id and session id are the same string, so nothing maps between the two worlds:
|
|
65
|
+
|
|
66
|
+
| Adapter method | Managed Agents call |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `list` | `sessions.list()`, filtered to the sessions this app created (a `metadata` tag) |
|
|
69
|
+
| `initialize` | `sessions.create()`, invoked by assistant-ui on the first message of a new chat |
|
|
70
|
+
| `rename` | `sessions.update({ title })` |
|
|
71
|
+
| `archive` | `sessions.archive()` |
|
|
72
|
+
| `unarchive` | Throws. Managed Agents sessions cannot be unarchived, and switching to an archived thread auto-unarchives by default, so do not render archived sessions as switchable (the quickstart's ownership gate rejects archived ids outright) |
|
|
73
|
+
| `delete` | `sessions.delete()` |
|
|
74
|
+
| `fetch` | `sessions.retrieve()` |
|
|
75
|
+
| `generateTitle` | Reads the title back after the server retitles the session from the first message, so the sidebar row updates without a second model call |
|
|
76
|
+
|
|
77
|
+
A brand-new chat has no session until the first send: the composer works immediately, and `initialize()` creates the session lazily when the first message (or first attachment upload) needs one. Kill the server, restart, reload, and every conversation comes back, because none of it ever lived in the app.
|
|
78
|
+
|
|
79
|
+
## The approval gate
|
|
80
|
+
|
|
81
|
+
Managed Agents supports per-tool [permission policies](https://platform.claude.com/docs/en/managed-agents/permission-policies). A tool configured as `always_ask` (the quickstart gates `bash` this way) does not run when the agent reaches for it. The session emits the `agent.tool_use` event, then parks:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{ "type": "session.status_idle", "stop_reason": { "type": "requires_action", "event_ids": ["sevt_..."] } }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The fold stamps an approval onto that tool part and sets the message status to `requires-action`, which is everything assistant-ui needs to render Allow and Deny on the tool card. The click flows back through `onRespondToToolApproval` as a `user.tool_confirmation` event:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{ "type": "user.tool_confirmation", "tool_use_id": "sevt_...", "result": "deny", "deny_message": "Not on this box." }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Two wire details matter. The `tool_use_id` is the tool-use event id, not an Anthropic `toolu_` id. And a denial reaches the agent as the tool's result, so it adjusts course instead of retrying the same command.
|
|
94
|
+
|
|
95
|
+
Custom client-executed tools ride the same `requires_action` stop but take a `user.custom_tool_result` instead of a confirmation; sending a confirmation for one is a 400. The quickstart's inline chart tool is the worked example: the session parks, the card renders the chart from the tool's input, and the client answers so the agent continues.
|
|
96
|
+
|
|
97
|
+
## Token streaming
|
|
98
|
+
|
|
99
|
+
By default assistant text arrives as whole `agent.message` events when a model request finishes. Opting the stream into `event_deltas: ["agent.message", "agent.thinking"]` adds token previews: an `event_start` announces the upcoming event, `event_delta` fragments stream the text, and the buffered event lands last as the authoritative record. Concatenating a preview's deltas in arrival order yields a prefix of the final text, but under load the server may shed the remaining deltas for an event, so the prefix is not necessarily the whole message. The fold therefore appends fragments for display and discards the accumulated preview when the buffered event arrives; never treat a preview as final. When a turn errors or is interrupted, the buffered event may never arrive at all, but `span.model_request_end` still does, so close any unreconciled preview when you see it.
|
|
100
|
+
|
|
101
|
+
Previews are best-effort and gated per organization. Build against the buffered events and treat deltas as an enhancement: an org without the streaming gate runs the identical code path with replies arriving whole.
|
|
102
|
+
|
|
103
|
+
## Security boundary
|
|
104
|
+
|
|
105
|
+
The Anthropic API key stays server-side; the browser talks only to your own route handlers, which relay to Managed Agents. Because a session id arrives from the browser and becomes an API path parameter, validate ownership on every route: the id must resolve, belong to your agent, and carry your app's metadata tag before any read or write. The API key can see the whole workspace; that gate is what keeps a guessed id from reading it. The quickstart's [`ownedSession()`](https://github.com/anthropics/claude-quickstarts/blob/main/managed-agents/assistant-ui/lib/owned-session.ts) is the reference shape.
|
|
106
|
+
|
|
107
|
+
## Run the reference
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
git clone https://github.com/anthropics/claude-quickstarts
|
|
111
|
+
cd claude-quickstarts/managed-agents/assistant-ui
|
|
112
|
+
npm install
|
|
113
|
+
cp .env.example .env # add ANTHROPIC_API_KEY, or `ant auth login` once
|
|
114
|
+
npm run setup # one-time: creates the agent + environment, paste the IDs into .env
|
|
115
|
+
npm run dev # drop sample_data/sales.csv into the chat
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The quickstart's [README](https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/assistant-ui#readme) walks through every file: the reducer, the session controller, the thread list adapter, the tool cards, and the attachment adapter that uploads composer files into the session sandbox. For the platform itself, start with Anthropic's [Managed Agents overview](https://platform.claude.com/docs/en/managed-agents/overview) and [events reference](https://platform.claude.com/docs/en/managed-agents/events-and-streaming).
|
|
@@ -33,7 +33,8 @@ A non-exhaustive list of `unstable_` exports surfaced in the runtime docs.
|
|
|
33
33
|
| `unstable_humanToolNames` | `@assistant-ui/react` | Tool names that pause the run until a result is added via `addResult`. Only available on LocalRuntime; not supported in DataStream. |
|
|
34
34
|
| `unstable_threadListAdapter` | `@assistant-ui/react-langgraph` | LangGraph thread-list adapter slot on `useLangGraphRuntime`. |
|
|
35
35
|
| `unstable_createLangGraphStream` | `@assistant-ui/react-langgraph` | End-to-end cancellation primitive. |
|
|
36
|
-
| `unstable_Provider` | Various adapters |
|
|
36
|
+
| `unstable_Provider` | Various adapters | React-component face on `RemoteThreadListAdapter`. Must render children synchronously. `useRemoteThreadListRuntime` renders it when present; the `RemoteThreadList` store entry ignores it. |
|
|
37
|
+
| `unstable_useAdapters` | Various adapters | Hook face on `RemoteThreadListAdapter`. The `RemoteThreadList` store entry calls it. `useRemoteThreadListRuntime` synthesizes a `RuntimeAdapterProvider` from it when `unstable_Provider` is omitted. |
|
|
37
38
|
| `unstable_capabilities` | `ExternalStoreRuntime` | Toggle copy and other thread capabilities. |
|
|
38
39
|
| `unstable_state`, `unstable_annotations`, `unstable_data` | Message metadata | Runtime-internal fields exposed for advanced use cases. |
|
|
39
40
|
| `unstable_assistantMessageId`, `unstable_threadId`, `unstable_parentId`, `unstable_getMessage` | `ChatModelRunOptions` | Identifiers and accessors passed to your `ChatModelAdapter.run`. |
|