@assistant-ui/mcp-docs-server 0.1.30 → 0.1.31
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-v6.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-chain-of-thought.md +79 -50
- package/.docs/organized/code-examples/with-cloud-standalone.md +4 -4
- package/.docs/organized/code-examples/with-cloud.md +4 -4
- package/.docs/organized/code-examples/with-custom-thread-list.md +56 -11
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +7 -7
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +7 -7
- package/.docs/organized/code-examples/with-expo.md +16 -16
- package/.docs/organized/code-examples/with-external-store.md +2 -2
- package/.docs/organized/code-examples/with-ffmpeg.md +5 -5
- package/.docs/organized/code-examples/with-generative-ui.md +5 -5
- package/.docs/organized/code-examples/with-google-adk.md +4 -4
- package/.docs/organized/code-examples/with-heat-graph.md +1 -1
- package/.docs/organized/code-examples/with-interactables.md +5 -5
- package/.docs/organized/code-examples/with-langchain.md +3 -3
- package/.docs/organized/code-examples/with-langgraph.md +3 -3
- package/.docs/organized/code-examples/with-livekit.md +8 -8
- package/.docs/organized/code-examples/with-opencode.md +99 -54
- package/.docs/organized/code-examples/with-parent-id-grouping.md +4 -4
- package/.docs/organized/code-examples/with-react-hook-form.md +5 -5
- package/.docs/organized/code-examples/with-react-ink.md +1 -1
- package/.docs/organized/code-examples/with-react-router.md +8 -8
- package/.docs/organized/code-examples/with-store.md +1 -1
- package/.docs/organized/code-examples/with-tanstack.md +5 -5
- package/.docs/organized/code-examples/with-tap-runtime.md +2 -2
- package/.docs/raw/docs/(docs)/cli.mdx +2 -1
- package/.docs/raw/docs/(docs)/copilots/assistant-frame.mdx +1 -0
- package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +10 -3
- package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +8 -3
- package/.docs/raw/docs/(docs)/copilots/make-assistant-visible.mdx +1 -0
- package/.docs/raw/docs/(docs)/copilots/model-context.mdx +1 -0
- package/.docs/raw/docs/(docs)/copilots/motivation.mdx +1 -0
- package/.docs/raw/docs/(docs)/copilots/use-assistant-instructions.mdx +1 -0
- package/.docs/raw/docs/(docs)/devtools.mdx +1 -0
- package/.docs/raw/docs/(docs)/index.mdx +1 -0
- package/.docs/raw/docs/(docs)/installation.mdx +1 -0
- package/.docs/raw/docs/(docs)/rtl.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +34 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/feedback-speech.mdx +41 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +26 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +34 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +31 -0
- package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +20 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +26 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +72 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +41 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +48 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +30 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +23 -0
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +21 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +7 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +65 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +50 -6
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +15 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +36 -1
- package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +38 -0
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +5 -0
- package/.docs/raw/docs/(reference)/migrations/v0-14.mdx +144 -6
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +230 -2
- package/.docs/raw/docs/cloud/ai-sdk.mdx +221 -3
- package/.docs/raw/docs/cloud/langgraph.mdx +274 -2
- package/.docs/raw/docs/{(docs)/guides → guides}/attachments.mdx +41 -36
- package/.docs/raw/docs/guides/branching.mdx +76 -0
- package/.docs/raw/docs/guides/chain-of-thought.mdx +166 -0
- package/.docs/raw/docs/{(docs)/guides → guides}/context-api.mdx +50 -22
- package/.docs/raw/docs/{(docs)/guides → guides}/dictation.mdx +2 -0
- package/.docs/raw/docs/guides/editing.mdx +102 -0
- package/.docs/raw/docs/guides/index.mdx +103 -0
- package/.docs/raw/docs/{(docs)/guides → guides}/interactables.mdx +49 -0
- package/.docs/raw/docs/{(docs)/guides → guides}/latex.mdx +51 -8
- package/.docs/raw/docs/{(docs)/guides → guides}/mentions.mdx +61 -86
- package/.docs/raw/docs/{(docs)/guides → guides}/message-timing.mdx +8 -2
- package/.docs/raw/docs/{(docs)/guides → guides}/multi-agent.mdx +64 -4
- package/.docs/raw/docs/{(docs)/guides → guides}/quoting.mdx +10 -17
- package/.docs/raw/docs/{(docs)/guides → guides}/slash-commands.mdx +103 -37
- package/.docs/raw/docs/guides/speech.mdx +156 -0
- package/.docs/raw/docs/{(docs)/guides → guides}/suggestions.mdx +21 -83
- package/.docs/raw/docs/{(docs)/guides → guides}/tool-ui.mdx +108 -36
- package/.docs/raw/docs/{(docs)/guides → guides}/tools.mdx +131 -35
- package/.docs/raw/docs/{(docs)/guides → guides}/voice.mdx +39 -0
- package/.docs/raw/docs/ink/index.mdx +1 -3
- package/.docs/raw/docs/ink/migration.mdx +1 -3
- package/.docs/raw/docs/ink/primitives.mdx +37 -1
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +520 -0
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +191 -0
- package/.docs/raw/docs/integrations/auth/clerk.mdx +172 -0
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +196 -0
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +79 -0
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +188 -0
- package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +57 -0
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +201 -0
- package/.docs/raw/docs/integrations/gateways/index.mdx +157 -0
- package/.docs/raw/docs/integrations/index.mdx +173 -0
- package/.docs/raw/docs/integrations/observability/helicone.mdx +130 -0
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +156 -0
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +146 -0
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +712 -0
- package/.docs/raw/docs/integrations/tools/mcp.mdx +267 -0
- package/.docs/raw/docs/primitives/action-bar.mdx +1 -0
- package/.docs/raw/docs/primitives/assistant-modal.mdx +1 -0
- package/.docs/raw/docs/primitives/attachment.mdx +1 -0
- package/.docs/raw/docs/primitives/branch-picker.mdx +1 -0
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +90 -85
- package/.docs/raw/docs/primitives/composer.mdx +2 -1
- package/.docs/raw/docs/primitives/error.mdx +1 -0
- package/.docs/raw/docs/primitives/index.mdx +2 -1
- package/.docs/raw/docs/primitives/message.mdx +68 -5
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +1 -0
- package/.docs/raw/docs/primitives/suggestion.mdx +1 -0
- package/.docs/raw/docs/primitives/thread-list.mdx +39 -0
- package/.docs/raw/docs/primitives/thread.mdx +16 -13
- package/.docs/raw/docs/react-native/index.mdx +1 -3
- package/.docs/raw/docs/react-native/migration.mdx +1 -3
- package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +396 -0
- package/.docs/raw/docs/runtimes/a2a/overview.mdx +60 -0
- package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +216 -0
- package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +70 -0
- package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +243 -0
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +123 -0
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +52 -0
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +71 -131
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +69 -63
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +330 -123
- package/.docs/raw/docs/runtimes/concepts/adapters.mdx +265 -0
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +125 -0
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +67 -0
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +428 -0
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +703 -0
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +323 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +253 -1236
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +746 -0
- package/.docs/raw/docs/runtimes/custom/overview.mdx +71 -0
- package/.docs/raw/docs/runtimes/google-adk/api.mdx +256 -0
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +717 -0
- package/.docs/raw/docs/runtimes/google-adk/overview.mdx +69 -0
- package/.docs/raw/docs/runtimes/google-adk/quickstart.mdx +229 -0
- package/.docs/raw/docs/runtimes/langchain.mdx +533 -0
- package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +305 -0
- package/.docs/raw/docs/runtimes/langgraph/interrupts.mdx +104 -0
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +84 -0
- package/.docs/raw/docs/runtimes/langgraph/quickstart.mdx +496 -0
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +127 -0
- package/.docs/raw/docs/runtimes/langgraph/threads.mdx +113 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +3 -3
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +0 -23
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +191 -0
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +48 -0
- package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +119 -0
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +71 -203
- package/.docs/raw/docs/ui/accordion.mdx +1 -0
- package/.docs/raw/docs/ui/assistant-modal.mdx +1 -0
- package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -0
- package/.docs/raw/docs/ui/attachment.mdx +1 -0
- package/.docs/raw/docs/ui/badge.mdx +1 -0
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +1 -0
- package/.docs/raw/docs/ui/context-display.mdx +1 -0
- package/.docs/raw/docs/ui/diff-viewer.mdx +1 -0
- package/.docs/raw/docs/ui/directive-text.mdx +1 -0
- package/.docs/raw/docs/ui/file.mdx +1 -0
- package/.docs/raw/docs/ui/image.mdx +1 -0
- package/.docs/raw/docs/ui/markdown.mdx +2 -14
- package/.docs/raw/docs/ui/mermaid.mdx +1 -0
- package/.docs/raw/docs/ui/message-timing.mdx +3 -2
- package/.docs/raw/docs/ui/model-selector.mdx +1 -0
- package/.docs/raw/docs/ui/part-grouping.mdx +325 -313
- package/.docs/raw/docs/ui/quote.mdx +1 -0
- package/.docs/raw/docs/ui/reasoning.mdx +66 -33
- package/.docs/raw/docs/ui/scrollbar.mdx +1 -0
- package/.docs/raw/docs/ui/select.mdx +1 -0
- package/.docs/raw/docs/ui/sources.mdx +1 -0
- package/.docs/raw/docs/ui/streamdown.mdx +1 -0
- package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -0
- package/.docs/raw/docs/ui/tabs.mdx +1 -0
- package/.docs/raw/docs/ui/thread-list.mdx +17 -0
- package/.docs/raw/docs/ui/thread.mdx +56 -1
- package/.docs/raw/docs/ui/tool-fallback.mdx +1 -0
- package/.docs/raw/docs/ui/tool-group.mdx +39 -11
- package/.docs/raw/docs/ui/voice.mdx +1 -0
- package/.docs/raw/docs/utilities/heat-graph.mdx +1 -0
- package/.docs/raw/docs/utilities/react-o11y.mdx +278 -0
- package/.docs/raw/docs/utilities/tw-shimmer.mdx +1 -0
- package/package.json +3 -3
- package/src/tools/tests/path-traversal.test.ts +1 -1
- package/.docs/raw/docs/(docs)/guides/branching.mdx +0 -65
- package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +0 -164
- package/.docs/raw/docs/(docs)/guides/editing.mdx +0 -66
- package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -38
- package/.docs/raw/docs/runtimes/a2a/index.mdx +0 -298
- package/.docs/raw/docs/runtimes/assistant-transport.mdx +0 -1033
- package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +0 -314
- package/.docs/raw/docs/runtimes/custom/local.mdx +0 -1464
- package/.docs/raw/docs/runtimes/data-stream.mdx +0 -422
- package/.docs/raw/docs/runtimes/google-adk/index.mdx +0 -686
- package/.docs/raw/docs/runtimes/helicone.mdx +0 -61
- package/.docs/raw/docs/runtimes/langchain/comparison.mdx +0 -60
- package/.docs/raw/docs/runtimes/langchain/index.mdx +0 -210
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +0 -699
- package/.docs/raw/docs/runtimes/langgraph/tutorial/index.mdx +0 -12
- package/.docs/raw/docs/runtimes/langserve.mdx +0 -116
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -218
- package/.docs/raw/docs/runtimes/mastra/overview.mdx +0 -18
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -217
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Context API
|
|
3
3
|
description: Read and update assistant state to build custom components.
|
|
4
|
+
platforms: ["react"]
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
The Context API provides direct access to assistant-ui's state management system, enabling you to build custom components that integrate seamlessly with the assistant runtime.
|
|
@@ -211,6 +212,8 @@ aui.attachment().getState();
|
|
|
211
212
|
// ThreadList actions
|
|
212
213
|
aui.threads().switchToNewThread();
|
|
213
214
|
aui.threads().switchToThread(threadId);
|
|
215
|
+
aui.threads().reload();
|
|
216
|
+
await aui.threads().getLoadThreadsPromise();
|
|
214
217
|
aui.threads().getState();
|
|
215
218
|
|
|
216
219
|
// ThreadListItem actions
|
|
@@ -233,9 +236,9 @@ aui.chainOfThought().getState();
|
|
|
233
236
|
aui.chainOfThought().setCollapsed(collapsed);
|
|
234
237
|
aui.chainOfThought().part({ index: 0 });
|
|
235
238
|
|
|
236
|
-
// ModelContext actions
|
|
237
|
-
aui.modelContext().getState();
|
|
239
|
+
// ModelContext actions — see /docs/copilots/model-context for full usage
|
|
238
240
|
aui.modelContext().register(provider);
|
|
241
|
+
aui.modelContext().getState();
|
|
239
242
|
|
|
240
243
|
// Tools actions
|
|
241
244
|
aui.tools().setToolUI(toolName, render);
|
|
@@ -355,9 +358,14 @@ const partByToolCall = aui.message().part({ toolCallId: "call_123" });
|
|
|
355
358
|
// Access attachment by index
|
|
356
359
|
const attachment = aui.composer().attachment({ index: 0 }).getState();
|
|
357
360
|
|
|
358
|
-
// Access thread list item by ID or
|
|
361
|
+
// Access thread list item by ID, index, or the "main" selector
|
|
359
362
|
const threadItem = aui.threads().item({ id: "thread_123" });
|
|
360
363
|
const threadByIndex = aui.threads().item({ index: 0 });
|
|
364
|
+
const archivedThread = aui.threads().item({ index: 0, archived: true });
|
|
365
|
+
|
|
366
|
+
// Traverse to the main thread directly
|
|
367
|
+
const mainThread = aui.threads().thread("main");
|
|
368
|
+
const message = aui.threads().thread("main").message({ id: "msg_123" });
|
|
361
369
|
```
|
|
362
370
|
|
|
363
371
|
## Common Patterns
|
|
@@ -490,9 +498,9 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
|
|
|
490
498
|
|
|
491
499
|
| Scope | Key State Properties | Description |
|
|
492
500
|
| -------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
|
|
493
|
-
| ThreadList | `mainThreadId`, `newThreadId`, `threadIds`, `archivedThreadIds`, `isLoading`, `threadItems`
|
|
494
|
-
| ThreadListItem | `id`, `title`, `status`, `remoteId`, `externalId`
|
|
495
|
-
| Thread | `isRunning
|
|
501
|
+
| ThreadList | `mainThreadId`, `newThreadId`, `threadIds`, `archivedThreadIds`, `isLoading`, `threadItems` (`readonly ThreadListItemState[]`) | Manages all available conversation threads |
|
|
502
|
+
| ThreadListItem | `id`, `title`, `status`, `remoteId`, `externalId`, `custom?: Record<string, unknown>` | Individual thread metadata and status; `custom` carries arbitrary per-thread metadata set by remote runtimes |
|
|
503
|
+
| Thread | `isRunning` (may be explicitly set by the runtime rather than derived from last-message status), `isLoading`, `isDisabled`, `isEmpty`, `messages`, `capabilities`, `suggestions` | Active conversation state and message history |
|
|
496
504
|
| Message | `role`, `content`, `status`, `attachments`, `parts`, `parentId`, `branchNumber`, `branchCount`, `isLast`, `index` | Individual message content and metadata |
|
|
497
505
|
| Part | `type`, `status`, `text`, `toolCallId`, `toolName` | Content parts within messages (text, tool calls) |
|
|
498
506
|
| ChainOfThought | `parts`, `collapsed`, `status` | Reasoning steps grouped within a message |
|
|
@@ -500,13 +508,15 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
|
|
|
500
508
|
| Attachment | `id`, `type`, `name`, `contentType`, `status` | File attachments metadata and content |
|
|
501
509
|
| Suggestions | `suggestions` | Collection of follow-up message suggestions |
|
|
502
510
|
| Suggestion | `title`, `label`, `prompt` | Individual suggestion with title, label, and prompt |
|
|
503
|
-
| ModelContext | *(empty — use `register()` / `getToolCallParams()` methods)*
|
|
511
|
+
| ModelContext | *(empty — use `register()` / `getToolCallParams()` methods; see [Model Context](/docs/copilots/model-context))* | System instructions, tools, and context providers |
|
|
504
512
|
|
|
505
513
|
### Available Actions by Scope
|
|
506
514
|
|
|
515
|
+
The table below covers the most commonly used actions. For the full catalog, see the [API Reference](/docs/api-reference/overview).
|
|
516
|
+
|
|
507
517
|
| Scope | Actions | Use Cases |
|
|
508
518
|
| -------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
509
|
-
| ThreadList | `switchToNewThread()`, `switchToThread(id)`, `item(selector)`, `thread("main")`, `getState()`
|
|
519
|
+
| ThreadList | `switchToNewThread()`, `switchToThread(id)`, `reload()`, `getLoadThreadsPromise()`, `item(selector)`, `thread("main")`, `getState()` | Thread navigation, creation, and sync |
|
|
510
520
|
| ThreadListItem | `switchTo()`, `rename(title)`, `archive()`, `unarchive()`, `delete()`, `getState()` | Thread management operations |
|
|
511
521
|
| Thread | `append(message)`, `startRun(config)`, `resumeRun(config)`, `cancelRun()`, `reset()`, `export()`, `import(repository)`, `message(selector)`, `composer()`, `getState()` | Message handling and conversation control |
|
|
512
522
|
| Message | `reload()`, `speak()`, `stopSpeaking()`, `submitFeedback(feedback)`, `switchToBranch(options)`, `getCopyText()`, `part(selector)`, `attachment(selector)`, `composer()`, `setIsCopied(value)`, `setIsHovering(value)`, `getState()` | Message interactions and regeneration |
|
|
@@ -516,20 +526,38 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
|
|
|
516
526
|
| Attachment | `remove()`, `getState()` | File management |
|
|
517
527
|
| Suggestions | `suggestion({ index })`, `getState()` | Access follow-up suggestions |
|
|
518
528
|
| Suggestion | `getState()` | Read individual suggestion data |
|
|
519
|
-
| ModelContext | `register(provider)`, `getState()` | Register model
|
|
520
|
-
|
|
521
|
-
###
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
529
|
+
| ModelContext | `register(provider)`, `getState()` | Register providers; full details in [Model Context](/docs/copilots/model-context) |
|
|
530
|
+
|
|
531
|
+
### Events vs State Observation
|
|
532
|
+
|
|
533
|
+
`useAuiEvent` is the escape hatch for **transient occurrences that are not derivable from state**. State-derivable transitions (attachment list changing, run progress, thread switching) should be observed with `useAuiState`, not subscribed via events.
|
|
534
|
+
|
|
535
|
+
The rule of thumb:
|
|
536
|
+
|
|
537
|
+
1. Can you read the new value from state right now? → use `useAuiState`.
|
|
538
|
+
2. Are you the caller and want immediate feedback? → catch the rejection / read the return value.
|
|
539
|
+
3. Did something happen that has no representation in state at all? → use `useAuiEvent`.
|
|
540
|
+
|
|
541
|
+
Most existing events are kept for backward compatibility but duplicate state. They are marked `@deprecated` in the type definitions; new code should follow the rule above.
|
|
542
|
+
|
|
543
|
+
#### Currently Recommended (Truly Transient)
|
|
544
|
+
|
|
545
|
+
| Event | When It Fires |
|
|
546
|
+
| ----------------------------- | ---------------------------------------------------------------------------- |
|
|
547
|
+
| `composer.attachmentAddError` | An `addAttachment()` call failed. Payload `reason` discriminates `no-adapter` / `not-accepted` / `adapter-error`. `no-adapter` and `not-accepted` are non-state-derivable. `adapter-error` is partially state-derivable: if the adapter produced any attachment before failing, the errored attachment also appears in `composer.attachments` with `status.reason === "error"`. The event additionally surfaces a human-readable `message` (and the underlying `Error` instance via the low-level `runtime.unstable_on("attachmentAddError")` API; `useAuiEvent` payloads omit it because raw `Error` objects are not store-serializable). |
|
|
548
|
+
| `thread.modelContextUpdate` | The model context provider notified a change. The model context lives in a provider, not in thread state, so this event has no state-derivable equivalent. |
|
|
549
|
+
|
|
550
|
+
#### Legacy (State-Derivable, Prefer `useAuiState`)
|
|
551
|
+
|
|
552
|
+
These events fire at the same transition you can observe via state. They are kept for backward compatibility but new code should observe state instead.
|
|
553
|
+
|
|
554
|
+
| Legacy Event | Observe Instead |
|
|
555
|
+
| -------------------------------------------- | -------------------------------------------------------------- |
|
|
556
|
+
| `composer.send` | composer `text` clearing |
|
|
557
|
+
| `composer.attachmentAdd` | composer `attachments` |
|
|
558
|
+
| `thread.runStart` / `runEnd` | thread `isRunning` flipping to `true` / `false` |
|
|
559
|
+
| `thread.initialize` | thread `messages` becoming non-empty (or `isEmpty` flipping) |
|
|
560
|
+
| `threadListItem.switchedTo` / `switchedAway` | compare `s.threads.mainThreadId` against `s.threadListItem.id` |
|
|
533
561
|
|
|
534
562
|
## Troubleshooting
|
|
535
563
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Message Editing
|
|
3
|
+
description: Allow users to edit their messages with custom editor interfaces.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Mental Model
|
|
8
|
+
|
|
9
|
+
Editing re-submits a message from a past point in the conversation and creates a new branch. The messages after the edited one are discarded, and the assistant generates a fresh response from that point forward. Each user message has an independent edit composer; only one can be active at a time.
|
|
10
|
+
|
|
11
|
+
The recommended way to wire this up is via the `children` render prop on `ThreadPrimitive.Messages`, branching on `message.role` and on `message.composer.isEditing` to swap in an edit composer when needed.
|
|
12
|
+
|
|
13
|
+
## Enabling Edit Support
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import {
|
|
17
|
+
ActionBarPrimitive,
|
|
18
|
+
ComposerPrimitive,
|
|
19
|
+
MessagePrimitive,
|
|
20
|
+
ThreadPrimitive,
|
|
21
|
+
} from "@assistant-ui/react";
|
|
22
|
+
|
|
23
|
+
const Thread = () => {
|
|
24
|
+
return (
|
|
25
|
+
<ThreadPrimitive.Root>
|
|
26
|
+
<ThreadPrimitive.Viewport>
|
|
27
|
+
<ThreadPrimitive.Messages>
|
|
28
|
+
{({ message }) => {
|
|
29
|
+
if (message.role === "user") {
|
|
30
|
+
if (message.composer.isEditing) return <UserEditComposer />;
|
|
31
|
+
return <UserMessage />;
|
|
32
|
+
}
|
|
33
|
+
return <AssistantMessage />;
|
|
34
|
+
}}
|
|
35
|
+
</ThreadPrimitive.Messages>
|
|
36
|
+
</ThreadPrimitive.Viewport>
|
|
37
|
+
</ThreadPrimitive.Root>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const UserMessage = () => {
|
|
42
|
+
return (
|
|
43
|
+
<MessagePrimitive.Root>
|
|
44
|
+
{/* message content */}
|
|
45
|
+
<ActionBarPrimitive.Root>
|
|
46
|
+
<ActionBarPrimitive.Edit />
|
|
47
|
+
</ActionBarPrimitive.Root>
|
|
48
|
+
</MessagePrimitive.Root>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const UserEditComposer = () => {
|
|
53
|
+
return (
|
|
54
|
+
<MessagePrimitive.Root>
|
|
55
|
+
<ComposerPrimitive.Root>
|
|
56
|
+
<ComposerPrimitive.Input />
|
|
57
|
+
<ComposerPrimitive.Cancel />
|
|
58
|
+
<ComposerPrimitive.Send />
|
|
59
|
+
</ComposerPrimitive.Root>
|
|
60
|
+
</MessagePrimitive.Root>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const AssistantMessage = () => {
|
|
65
|
+
return <MessagePrimitive.Root>{/* message content */}</MessagePrimitive.Root>;
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`ActionBarPrimitive.Edit` calls `aui.composer().beginEdit()` under the hood and is disabled when the composer is already in edit mode.
|
|
70
|
+
|
|
71
|
+
`ComposerPrimitive.Cancel` calls `aui.composer().cancel()`, which exits edit mode and restores the original message content. See [Composer primitives](/docs/primitives/composer) for the full composer API.
|
|
72
|
+
|
|
73
|
+
## Detecting Edit Mode
|
|
74
|
+
|
|
75
|
+
The `isEditing` flag is available on both `ThreadComposerState` and `EditComposerState`, so `useAuiState((s) => s.composer.isEditing)` works inside any composer context. The more idiomatic path is to rely on the `UserEditComposer` slot in the render function (shown above), which scopes the component tree automatically and avoids manual state checks.
|
|
76
|
+
|
|
77
|
+
## Imperative API
|
|
78
|
+
|
|
79
|
+
`aui.composer().beginEdit()` is the programmatic entry point for entering edit mode on a message. Use it for headless or keyboard-shortcut-driven flows where `ActionBarPrimitive.Edit` is not rendered:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { useAui } from "@assistant-ui/react";
|
|
83
|
+
|
|
84
|
+
const EditButton = () => {
|
|
85
|
+
const aui = useAui();
|
|
86
|
+
return (
|
|
87
|
+
<button onClick={() => aui.composer().beginEdit()}>Edit</button>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`aui.composer().cancel()` exits edit mode without re-submitting.
|
|
93
|
+
|
|
94
|
+
## Editing While Streaming
|
|
95
|
+
|
|
96
|
+
If a user triggers edit mode while the assistant is still generating a response, the in-progress run is cancelled and a new branch is started from the edited message. The hook does not block this. If your UI should prevent editing during streaming, gate the edit button on the thread run state before rendering `ActionBarPrimitive.Edit` or calling `beginEdit()`.
|
|
97
|
+
|
|
98
|
+
## References
|
|
99
|
+
|
|
100
|
+
- [ActionBar primitives](/docs/primitives/action-bar) — `ActionBarPrimitive.Edit` and related actions
|
|
101
|
+
- [Composer primitives](/docs/primitives/composer) — full composer anatomy including `Cancel`, `Send`, and `Input`
|
|
102
|
+
- [Message primitives](/docs/primitives/message) — `MessagePrimitive.Root` and content parts
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overview
|
|
3
|
+
description: Practical patterns for building features with assistant-ui.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Guides are task-oriented walkthroughs for building specific features on top of assistant-ui. They sit between the [Primitives](/docs/primitives) (low-level building blocks) and [Components](/docs/ui/thread) (pre-styled installs) — pick a guide when you know what you want to build and need the recommended pattern.
|
|
8
|
+
|
|
9
|
+
## Composer
|
|
10
|
+
|
|
11
|
+
Extend the message input with file attachments, mentions, slash commands, voice, and quoting.
|
|
12
|
+
|
|
13
|
+
<Cards>
|
|
14
|
+
<Card title="Attachments" href="/docs/guides/attachments">
|
|
15
|
+
Let users attach files, images, and documents to messages. Covers upload adapters, validation, and the typed `attachmentAddError` event.
|
|
16
|
+
</Card>
|
|
17
|
+
<Card title="Mentions" href="/docs/guides/mentions">
|
|
18
|
+
`@`-style triggers that insert directives into the composer. Sync and async search patterns.
|
|
19
|
+
</Card>
|
|
20
|
+
<Card title="Slash Commands" href="/docs/guides/slash-commands">
|
|
21
|
+
`/`-style commands with arguments, async loading, and combining with mentions.
|
|
22
|
+
</Card>
|
|
23
|
+
<Card title="Quoting" href="/docs/guides/quoting">
|
|
24
|
+
Selection toolbar, programmatic `setQuote`, and forwarding quote context to the LLM.
|
|
25
|
+
</Card>
|
|
26
|
+
<Card title="Dictation" href="/docs/guides/dictation">
|
|
27
|
+
Speech-to-text into the composer using `DictationAdapter` and `ComposerPrimitive.Dictate`.
|
|
28
|
+
</Card>
|
|
29
|
+
</Cards>
|
|
30
|
+
|
|
31
|
+
## Messages
|
|
32
|
+
|
|
33
|
+
Customize how messages render, are edited, branched, and suggested.
|
|
34
|
+
|
|
35
|
+
<Cards>
|
|
36
|
+
<Card title="Suggestions" href="/docs/guides/suggestions">
|
|
37
|
+
Welcome-screen prompts, dynamic suggestions, and the `AuiIf` empty-thread pattern.
|
|
38
|
+
</Card>
|
|
39
|
+
<Card title="Editing" href="/docs/guides/editing">
|
|
40
|
+
Edit user messages with `UserEditComposer`, `beginEdit()`, and edit-during-streaming behavior.
|
|
41
|
+
</Card>
|
|
42
|
+
<Card title="Branching" href="/docs/guides/branching">
|
|
43
|
+
Navigate alternative message versions with `BranchPickerPrimitive`, reload, and direct branch-id navigation.
|
|
44
|
+
</Card>
|
|
45
|
+
<Card title="Message Timing" href="/docs/guides/message-timing">
|
|
46
|
+
Display response duration and stream timing with `useMessageTiming` (experimental).
|
|
47
|
+
</Card>
|
|
48
|
+
</Cards>
|
|
49
|
+
|
|
50
|
+
## Tools & Generative UI
|
|
51
|
+
|
|
52
|
+
Connect tools to the LLM and render their outputs as interactive UI.
|
|
53
|
+
|
|
54
|
+
<Cards>
|
|
55
|
+
<Card title="Tools" href="/docs/guides/tools">
|
|
56
|
+
Define tools with the Toolkit API, stream args, handle cancellation, and integrate with AI SDK / LangGraph / LangChain.
|
|
57
|
+
</Card>
|
|
58
|
+
<Card title="Tool UI" href="/docs/guides/tool-ui">
|
|
59
|
+
Render tool calls and `DataMessagePart` into custom components, with fallback handling.
|
|
60
|
+
</Card>
|
|
61
|
+
<Card title="Interactables" href="/docs/guides/interactables">
|
|
62
|
+
Persisted, schema-validated interactive UI driven by AI state.
|
|
63
|
+
</Card>
|
|
64
|
+
<Card title="Multi-Agent" href="/docs/guides/multi-agent">
|
|
65
|
+
Sub-agent message attribution via `ToolCallMessagePart.messages` and LangGraph subgraph events.
|
|
66
|
+
</Card>
|
|
67
|
+
</Cards>
|
|
68
|
+
|
|
69
|
+
## Display
|
|
70
|
+
|
|
71
|
+
Render specialized message content.
|
|
72
|
+
|
|
73
|
+
<Cards>
|
|
74
|
+
<Card title="Chain of Thought" href="/docs/guides/chain-of-thought">
|
|
75
|
+
Display the assistant's reasoning steps in a collapsible accordion.
|
|
76
|
+
</Card>
|
|
77
|
+
<Card title="LaTeX" href="/docs/guides/latex">
|
|
78
|
+
Render math via React Markdown or Streamdown, with streaming-safe escape rules.
|
|
79
|
+
</Card>
|
|
80
|
+
</Cards>
|
|
81
|
+
|
|
82
|
+
## Audio
|
|
83
|
+
|
|
84
|
+
Voice input and output.
|
|
85
|
+
|
|
86
|
+
<Cards>
|
|
87
|
+
<Card title="Voice" href="/docs/guides/voice">
|
|
88
|
+
Realtime bidirectional audio with `RealtimeVoiceAdapter` and `createVoiceSession`.
|
|
89
|
+
</Card>
|
|
90
|
+
<Card title="Speech" href="/docs/guides/speech">
|
|
91
|
+
Text-to-speech for assistant messages via `SpeechSynthesisAdapter`.
|
|
92
|
+
</Card>
|
|
93
|
+
</Cards>
|
|
94
|
+
|
|
95
|
+
## Programmatic
|
|
96
|
+
|
|
97
|
+
Read and drive runtime state from your own code.
|
|
98
|
+
|
|
99
|
+
<Cards>
|
|
100
|
+
<Card title="Context API" href="/docs/guides/context-api">
|
|
101
|
+
Access threads, messages, composer, and tool state via `useAui` and the runtime scope tree.
|
|
102
|
+
</Card>
|
|
103
|
+
</Cards>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Interactables
|
|
3
3
|
description: Persistent UI whose state can be read and updated by the AI assistant.
|
|
4
|
+
platforms: ["react"]
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
import { InteractableSample } from "@/components/docs/samples/interactable";
|
|
@@ -344,6 +345,49 @@ const aui = useAui({
|
|
|
344
345
|
});
|
|
345
346
|
```
|
|
346
347
|
|
|
348
|
+
## Streaming Updates
|
|
349
|
+
|
|
350
|
+
While the AI is generating tool arguments, `useInteractableState` reflects the partial state in real time as fields stream in. You can use the partial state itself plus the thread's running status to show a skeleton UI while the AI is mid-stream:
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { useAuiState } from "@assistant-ui/react";
|
|
354
|
+
|
|
355
|
+
function TaskBoard() {
|
|
356
|
+
const id = useAssistantInteractable("taskBoard", config);
|
|
357
|
+
const [state] = useInteractableState(id, taskBoardInitialState);
|
|
358
|
+
const isRunning = useAuiState((s) => s.thread.isRunning);
|
|
359
|
+
|
|
360
|
+
const isLoading = isRunning && state.tasks.length === 0;
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
<div>
|
|
364
|
+
<h2>Tasks</h2>
|
|
365
|
+
{isLoading ? (
|
|
366
|
+
<div className="animate-pulse h-8 rounded bg-muted" />
|
|
367
|
+
) : (
|
|
368
|
+
<ul>
|
|
369
|
+
{state.tasks.map((task) => (
|
|
370
|
+
<li key={task.id}>{task.title}</li>
|
|
371
|
+
))}
|
|
372
|
+
</ul>
|
|
373
|
+
)}
|
|
374
|
+
</div>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
The state object updates progressively as the AI streams in each field, so partial renders work without any extra wiring. Use the runtime's `isRunning` to distinguish "still streaming, no fields yet" from "model returned an empty result".
|
|
380
|
+
|
|
381
|
+
## Schema Evolution
|
|
382
|
+
|
|
383
|
+
<Callout type="warn">
|
|
384
|
+
If you change a Zod schema after state has been persisted, the imported snapshot may silently mis-match the new shape. The adapter does a shallow merge, so extra fields are preserved and missing fields keep their initial values, but type mismatches are not caught at runtime. To avoid silent corruption, version your schema key (e.g. `"taskBoard_v2"`) or namespace it by schema hash whenever you make breaking changes. Alternatively, add a migration step in your `importState` call.
|
|
385
|
+
</Callout>
|
|
386
|
+
|
|
387
|
+
## Unmount Behavior
|
|
388
|
+
|
|
389
|
+
When a component that called `useAssistantInteractable` unmounts, the interactable is unregistered from the AI's tool list and system prompt. However, its state is preserved in the `Interactables` scope. When the component mounts again with the same name and id, the scope re-merges the preserved state rather than resetting to `initialState`. This means transient unmounts (such as React Strict Mode double-mounts or tab switches) do not lose state.
|
|
390
|
+
|
|
347
391
|
## Full Example
|
|
348
392
|
|
|
349
393
|
See the complete [with-interactables example](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-interactables) for a working implementation featuring:
|
|
@@ -352,3 +396,8 @@ See the complete [with-interactables example](https://github.com/assistant-ui/as
|
|
|
352
396
|
- **Sticky Notes** — multi-instance interactables with selection and partial updates
|
|
353
397
|
- **localStorage persistence** — state survives page refresh via `setPersistenceAdapter`
|
|
354
398
|
- **Sync indicator** — spinning icon while a save is in-flight (`isPending`)
|
|
399
|
+
|
|
400
|
+
## Related
|
|
401
|
+
|
|
402
|
+
- [Generative UI](/docs/guides/tool-ui) — Inline tool call UIs rendered inside messages
|
|
403
|
+
- [LangGraph Generative UI](/docs/runtimes/langgraph/generative-ui) — Structured UI components emitted by a LangGraph graph alongside messages
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: LaTeX
|
|
3
3
|
description: Render mathematical expressions in chat messages using KaTeX.
|
|
4
|
+
platforms: ["react"]
|
|
4
5
|
---
|
|
5
6
|
|
|
7
|
+
import { PackageManagerTabs } from "@/components/docs/fumadocs/install/package-manager-tabs";
|
|
6
8
|
|
|
7
9
|
Render LaTeX mathematical expressions in chat messages using KaTeX.
|
|
8
10
|
|
|
9
|
-
<Callout type="warn">LaTeX rendering is not enabled
|
|
11
|
+
<Callout type="warn">LaTeX rendering is not enabled by default.</Callout>
|
|
12
|
+
|
|
13
|
+
<Tabs items={["react-markdown", "Streamdown"]}>
|
|
14
|
+
<Tab value="react-markdown">
|
|
10
15
|
|
|
11
16
|
<Steps>
|
|
12
17
|
<Step>
|
|
13
18
|
|
|
14
19
|
### Install dependencies
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
npm i katex rehype-katex remark-math
|
|
18
|
-
```
|
|
21
|
+
<PackageManagerTabs packages={["katex", "rehype-katex", "remark-math"]} />
|
|
19
22
|
|
|
20
23
|
</Step>
|
|
21
24
|
<Step>
|
|
@@ -53,9 +56,50 @@ export const MarkdownText = memo(MarkdownTextImpl);
|
|
|
53
56
|
</Step>
|
|
54
57
|
</Steps>
|
|
55
58
|
|
|
59
|
+
</Tab>
|
|
60
|
+
<Tab value="Streamdown">
|
|
61
|
+
|
|
62
|
+
<Callout type="info">
|
|
63
|
+
Using [Streamdown](/docs/ui/streamdown) as your renderer? Math support is a first-party plugin — no remark or rehype packages needed.
|
|
64
|
+
</Callout>
|
|
65
|
+
|
|
66
|
+
<Steps>
|
|
67
|
+
<Step>
|
|
68
|
+
|
|
69
|
+
### Install dependencies
|
|
70
|
+
|
|
71
|
+
<PackageManagerTabs packages={["@streamdown/math", "katex"]} />
|
|
72
|
+
|
|
73
|
+
</Step>
|
|
74
|
+
<Step>
|
|
75
|
+
|
|
76
|
+
### Add KaTeX CSS to your layout
|
|
77
|
+
|
|
78
|
+
```tsx title="/app/layout.tsx"
|
|
79
|
+
import "katex/dist/katex.min.css"; // [!code ++]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
</Step>
|
|
83
|
+
<Step>
|
|
84
|
+
|
|
85
|
+
### Pass the `math` plugin to `StreamdownTextPrimitive`
|
|
86
|
+
|
|
87
|
+
```tsx title="/components/assistant-ui/streamdown-text.tsx"
|
|
88
|
+
import { math } from "@streamdown/math"; // [!code ++]
|
|
89
|
+
import "katex/dist/katex.min.css"; // [!code ++]
|
|
90
|
+
|
|
91
|
+
<StreamdownTextPrimitive plugins={{ math }} /> // [!code ++]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
</Step>
|
|
95
|
+
</Steps>
|
|
96
|
+
|
|
97
|
+
</Tab>
|
|
98
|
+
</Tabs>
|
|
99
|
+
|
|
56
100
|
## Supported Formats
|
|
57
101
|
|
|
58
|
-
By default, remark-math supports:
|
|
102
|
+
By default, remark-math (react-markdown path) supports:
|
|
59
103
|
- `$...$` for inline math
|
|
60
104
|
- `$$...$$` for display math
|
|
61
105
|
- Fenced code blocks with the `math` language identifier
|
|
@@ -67,7 +111,7 @@ Many language models generate LaTeX using different delimiter formats:
|
|
|
67
111
|
- `\[...\]` for display math
|
|
68
112
|
- Custom formats like `[/math]...[/math]`
|
|
69
113
|
|
|
70
|
-
You can use the `preprocess` prop to normalize these formats:
|
|
114
|
+
You can use the `preprocess` prop on `MarkdownTextPrimitive` to normalize these formats before parsing:
|
|
71
115
|
|
|
72
116
|
```tsx title="/components/assistant-ui/markdown-text.tsx"
|
|
73
117
|
import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";
|
|
@@ -104,6 +148,5 @@ function normalizeCustomMathTags(input: string): string {
|
|
|
104
148
|
```
|
|
105
149
|
|
|
106
150
|
<Callout type="tip">
|
|
107
|
-
|
|
151
|
+
Inside `MarkdownTextPrimitive`, the streamed text first passes through `preprocess` (delimiter normalization) and then through `useSmooth` (character-by-character accumulation), and only then reaches the markdown parser. Both run before remark-math sees the text, so delimiter replacement and the streaming smoothing are streaming-safe — partially-received delimiters are accumulated in the smoothing buffer rather than parsed mid-fragment.
|
|
108
152
|
</Callout>
|
|
109
|
-
|