# rn-docyrus-agent URL: /docs/native/docyrus/docyrus-agent Mobile AI assistant chat for Docyrus agents — streamed markdown, reasoning, tool calls, adaptive cards, sources and attachments, a composer with feature toggles and voice input, plus threads, projects, memories, an action panel and an inline text assistant. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-docyrus-agent ``` **Dependencies:** - [ai](https://www.npmjs.com/package/ai) - [expo-document-picker (optional)](https://www.npmjs.com/package/expo-document-picker) - [expo-image-picker (optional)](https://www.npmjs.com/package/expo-image-picker) - [expo-clipboard (optional)](https://www.npmjs.com/package/expo-clipboard) - [expo-speech-recognition (optional, dev build)](https://www.npmjs.com/package/expo-speech-recognition) The React Native port of the web `DocyrusAgent` family. Every component, type and hook keeps its web name. Like web, the components are **headless about the AI backend**: they render the AI SDK `UIMessage[]` / `ChatStatus` you pass in and call `onSendMessage`. The runtime is either your own `useChat` or [`useDocyrusAgentChat`](/docs/native/hooks/use-docyrus-agent-chat), which bundles the Docyrus transport, threads, attachment uploads and client tools. - **Messages:** assistant text renders through the built-in markdown renderer. `reasoning` parts become a collapsible block that opens while it streams. `tool-*` / `dynamic-tool` parts become a collapsible card with the tool name, a state badge (Pending / Running / Awaiting approval / Completed / Error / Denied) and the JSON input and output. A tool output (or a `data-*` part) that is an Adaptive Card payload (`{ type: 'AdaptiveCard' }`, or `{ card }` / `{ adaptiveCard }`) renders through the native [rn-adaptive-card](/docs/native/docyrus/adaptive-card). `source-url` / `source-document` parts become source chips, and `file` parts become image thumbnails or file chips. - **List:** a `FlatList` that sticks to the bottom while the reply streams. Streamed updates are batched at ~50 ms. A scroll-to-bottom button appears when you scroll up, and a "Thinking…" row shows until the first chunk arrives. Long-press a message, or tap the copy button under a reply, to copy it. Copy uses `expo-clipboard` when installed and falls back to the share sheet. - **Composer:** an auto-growing input capped at ~6 lines. Attach opens a Files / Photos / Camera sheet with only the installed pickers (`expo-document-picker` / `expo-image-picker`). Attachments show as a thumbnail strip. The five feature toggles appear as one sheet of switches (`toolbarLayout="menu"`) or as separate buttons (`"expanded"`). The send button becomes Stop while streaming. The mic and memory menu are optional tools. - **Keyboard:** `DocyrusAgentChat` is a `KeyboardAvoidingView` (`padding` on iOS). Pass `keyboardVerticalOffset` when a navigation header sits above it. ### Streaming, polyfills and host singletons Expo SDK 57 needs **no polyfills**. Its WinterCG runtime already makes the global `fetch` the streaming `expo/fetch` and installs `TextDecoderStream`, `TextEncoderStream` and `structuredClone`. `ai` (and `@ai-sdk/react` for `useDocyrusAgentChat`) are regular dependencies, **not** host singletons: only plain `UIMessage` data crosses the component boundary, which is the same classification as on web. `ai` needs `zod` as a peer. ### Voice input `DocyrusAgentChatInputMic` (or `DocyrusAgentChatInputMicButton` + [`useSpeechRecognition`](/docs/native/hooks/use-speech-recognition) + `useDocyrusAgentMicTranscription`) streams interim text into the input. It needs `expo-speech-recognition` and a **development build** — see [Speech Recognition](/docs/native/expo/speech-recognition). In Expo Go the button hides itself. ## Usage ```tsx import { useDocyrusAuth } from '@docyrus/signin/react-native'; import { DocyrusAgent, DocyrusAgentChatInput, DocyrusAgentChatInputDefaultBody, DocyrusAgentChatInputMemoryMenu, DocyrusAgentChatInputMic, DocyrusAgentThreadsSidebar, DocyrusAgentToolbarButton } from '@/components/docyrus-native/docyrus-agent'; import { useDocyrusAgentChat } from '@/hooks/docyrus-native/use-docyrus-agent-chat'; import { useDocyrusAgentInfo } from '@/hooks/docyrus-native/use-docyrus-agent-info'; export function AssistantScreen() { const { client, user } = useDocyrusAuth(); const [threadsOpen, setThreadsOpen] = useState(false); const info = useDocyrusAgentInfo({ client, agentId: AGENT_ID }); const chat = useDocyrusAgentChat({ agentId: AGENT_ID, apiBaseUrl: 'https://api.docyrus.com/v1', getAccessToken: () => client?.getAccessToken() ?? null, client, userId: user?.id }); if (!info.agent) return null; return ( <> )} /> setThreadsOpen(false)} threads={chat.threads.threads} activeThreadId={chat.activeThreadId} onNewThread={chat.newThread} onSelectThread={thread => chat.selectThread(thread)} onRenameThread={(thread, subject) => chat.renameThread(thread, subject)} onDeleteThread={thread => chat.deleteThread(thread)} /> ); } ``` Compact trigger card that opens the chat in a full-height sheet: ```tsx ``` ## API Reference ### DocyrusAgent | Prop | Type | Default | Description | |------|------|---------|-------------| | `agent` | `AgentProfile` | - | Agent identity: `name`, `description`, `welcomeMessage` (markdown), `avatar { name, color, icon, image }`, `model` (required) | | `messages` | `UIMessage[]` | `[]` | AI SDK messages | | `chatStatus` | `ChatStatus` | - | `'ready' \| 'submitted' \| 'streaming' \| 'error'` | | `actions` | `AgentAction[]` | `[]` | Actions for the action panel | | `sources` | `AgentSource[]` | `[]` | Context sources (action panel badges) | | `onSendMessage` | `(payload: AgentMessagePayload) => void \| Promise` | - | Submit — `{ text, files?, featureFlags? }` | | `onStopGeneration` | `() => void` | - | Stop button | | `onExecuteAction` | `(payload: AgentActionPayload) => void \| Promise` | - | Action panel execute | | `allowAttachments` | `boolean` | `false` | Attach button + attachment strip | | `acceptFileTypes` | `string \| string[]` | - | Web `accept` string (`'image/*,.pdf'`, extensions mapped to MIME) or a MIME array | | `suggestions` | `string[]` | `[]` | Empty-state suggestion chips | | `emptyState` | `ReactNode` | - | Replaces the empty-state hero | | `showMessageActions` | `boolean` | `true` | Copy button under assistant replies | | `headerLeading` | `ReactNode` | - | Slot before the header avatar | | `headerTrailing` | `ReactNode` | - | Slot at the end of the header | | `chatInput` | `ReactNode` | - | Replaces the chat input | | `chatTrailing` | `ReactNode` | - | Slot below the chat input | | `capabilities` | `AgentCapabilities` | `{}` | `support*` flags that decide which feature toggles show | | `initialFeatureFlags` | `Partial` | - | Initial toggle state | | `featureFlags` | `AgentFeatureFlags` | - | Controlled toggle state (pair with `onFeatureFlagsChange`) | | `onFeatureFlagsChange` | `(flags: AgentFeatureFlags) => void` | - | Toggle change | | `onAdaptiveCardAction` | `(event: AdaptiveCardActionEvent) => void \| Promise` | - | Native only: action tapped inside an Adaptive Card tool output | | `className` | `string` | - | Root classes (`flex-1 bg-background`) | ### DocyrusAgentTrigger All `DocyrusAgent` props (forwarded to the chat), plus: | Prop | Type | Default | Description | |------|------|---------|-------------| | `open` | `boolean` | - | Controlled open state of the chat sheet | | `onOpenChange` | `(open: boolean) => void` | - | Open state change | | `dialogContainer` | `'modal' \| 'sheet' \| 'drawer'` | `'sheet'` | `AwesomeDialog` container | | `dialogSide` | `'left' \| 'right' \| 'top' \| 'bottom'` | `'bottom'` | Sheet edge (web default `'right'`) | | `dialogSize` | `'sm' \| 'default' \| 'lg' \| 'xl' \| 'full'` | `'full'` | Sheet size (web default `'lg'`) | ### DocyrusAgentChat | Prop | Type | Default | Description | |------|------|---------|-------------| | `headerLeading` / `headerTrailing` | `ReactNode` | - | Header slots | | `chatInput` | `ReactNode` | `` | Input area | | `chatTrailing` | `ReactNode` | - | Slot below the input | | `hideHeader` | `boolean` | `false` | Native only: hide the agent header | | `keyboardVerticalOffset` | `number` | `0` | Native only: `KeyboardAvoidingView` offset | | `className` | `string` | - | Root classes | ### DocyrusAgentChatMessages | Prop | Type | Default | Description | |------|------|---------|-------------| | `className` | `string` | - | Root classes | | `contentContainerClassName` | `string` | - | Native only: list content classes | ### DocyrusAgentHeader | Prop | Type | Default | Description | |------|------|---------|-------------| | `agent` | `AgentProfile` | - | Agent (required) | | `leading` / `trailing` | `ReactNode` | - | Slots | | `className` | `string` | - | Classes | ### DocyrusAgentChatInput | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `ReactNode` | `` | Custom body. The draft provider (submit → `onSendMessage`) is always mounted | | `className` | `string` | - | Outer classes | `DocyrusAgentChatInputDefaultBody` takes `toolbarLayout?: 'menu' \| 'expanded'` (default `'menu'`) and native-only `extraTools?: ReactNode` (appended to the toolbar). `DocyrusAgentChatInputFooter` (native; web `PromptInputFooter`) takes `children` (tools), `submit?` (default ``) and `className`. ### Chat input parts | Component | Props | Notes | |-----------|-------|-------| | `DocyrusAgentChatInputTextarea` | `TextInputProps` except `value` / `onChangeText` / `multiline` / `style`, `placeholder?`, `maxHeight?: number` (default `140`), `className?` | Auto-growing, bound to the draft | | `DocyrusAgentChatInputSubmit` | `status?: ChatStatus`, `onStop?: () => void`, `disabled?: boolean`, `className?` | Send, or Stop while submitted / streaming | | `DocyrusAgentChatInputAttachButton` | `children?: ReactNode` (icon), `label?: string`, `className?` | Hidden when no picker is installed | | `DocyrusAgentChatInputAttachments` | `renderChip?: (file, remove) => ReactNode`, `className?` | Horizontal chip strip | | `DocyrusAgentChatInputFeatureToggle` | `feature: keyof AgentFeatureFlags`, `icon: string \| ReactNode`, `tooltip: string`, `activeClassName?`, `className?` | Generic toggle | | `DocyrusAgentChatInputWebSearchToggle` / `…DocumentSearchToggle` / `…ThinkingToggle` / `…DeepResearchToggle` / `…WorkCanvasToggle` | `className?` | Preset toggles | | `DocyrusAgentToolbarButton` | `icon: string \| ReactNode`, `label: string`, `onPress?`, `onLongPress?`, `disabled?`, `active?`, `activeTone?: 'primary' \| 'destructive'`, `badge?: number`, `overlay?: ReactNode`, `activeClassName?`, `className?` | Native stand-in for web `PromptInputButton` | ### DocyrusAgentChatInputFeatureMenu | Prop | Type | Default | Description | |------|------|---------|-------------| | `rows` | `ReadonlyArray` | `DEFAULT_FEATURE_ROWS` filtered by capabilities | Replace the rows | | `extraRows` | `ReadonlyArray` | - | Rows appended after the defaults | | `hideFeatures` | `ReadonlyArray` | - | Hide default rows by key | | `renderRow` | `(row, { active, onChange }) => ReactNode` | - | Custom row | | `triggerIcon` | `string` | `'fal sliders'` | Trigger DocyrusIcon name (web: lucide component) | | `activeClassName` | `string` | - | Trigger active classes | | `tooltip` | `string` | `'Options'` | Sheet title / accessibility label | | `className` | `string` | - | Trigger classes | `FeatureMenuRow`: `{ key, icon?: string \| ReactNode, label?, labelKey?, labelFallback?, flag?, capability?, active?, onChange? }`. ### DocyrusAgentChatInputMicButton / DocyrusAgentChatInputMic | Prop | Type | Default | Description | |------|------|---------|-------------| | `isRecording` | `boolean` | - | Recording state (button only, required) | | `onToggle` | `() => void` | - | Toggle (button only, required) | | `isSupported` | `boolean` | `true` | Hide when `false` (button only) | | `disabled` | `boolean` | - | Disable | | `icon` | `string` | `'fal microphone'` | DocyrusIcon name | | `recordingBadge` | `ReactNode \| null` | pulsing dot | Badge while recording (`null` hides it) | | `recordingClassName` | `string` | - | Active classes | | `tooltipIdle` / `tooltipRecording` | `string` | `'Microphone'` / `'Stop recording'` | Accessibility labels | | `lang` | `string` | device locale | `DocyrusAgentChatInputMic` only | | `separator` / `merge` / `clearOnStart` | see `useDocyrusAgentMicTranscription` | | `DocyrusAgentChatInputMic` only | | `className` | `string` | - | Classes | `useDocyrusAgentMicTranscription({ separator = ' ', merge?, clearOnStart = false })` returns `{ speechHandlers, resetBaseline }`. Spread `speechHandlers` into `useSpeechRecognition`. It must run inside `DocyrusAgentChatInput`. ### DocyrusAgentChatInputMemoryMenu | Prop | Type | Default | Description | |------|------|---------|-------------| | `onExtract` | `() => void` | - | "Extract Memories from Session" | | `onManageMemories` | `() => void` | - | "Manage Memories" | | `canExtract` / `canManage` | `boolean` | `true` | Enable the items | | `icon` | `string` | `'fal brain-circuit'` | Trigger DocyrusIcon name | | `tooltip` | `string` | `'Extract memories'` | Sheet title / label | | `children` | `ReactNode` | - | Replaces the two items | | `extractLabel` / `manageLabel` | `string` | - | Item labels (web: `ReactNode`) | | `className` | `string` | - | Classes | ### Prompt input (native) `DocyrusAgentPromptInputProvider` (`onSubmit({ text, files })`, `accept?: string[]`, `multiple?` = `true`, `initialInput?`) is what `DocyrusAgentChatInput` mounts. `useDocyrusAgentPromptInput()` is the native counterpart of the web `usePromptInputController()` + `usePromptInputAttachments()`. It returns `{ textInput: { value, setInput, clear }, attachments: { files, add, remove, clear, openFileDialog, availableSources }, submit, inputRef }`, and `attachments.add` accepts `NativeFile`s or `FileUIPart`s. ### Sidebar & threads | Component | Key props | |-----------|-----------| | `DocyrusAgentThreadsSidebar` | `threads`, `activeThreadId`, `isLoading`, `onSelectThread`, `onNewThread`, `onRenameThread`, `onDeleteThread`, `agent`, `header`, `onClose`, `open` (`true`), `presentation: 'inline' \| 'drawer'` (native, default `'drawer'`), `width` (native, `288`), `navExtra`, `projects`, `activeProjectId`, `maxVisibleProjects` (`3`), `onSelectProject`, `onNewProject`, `onRenameProject`, `onDeleteProject`, `onShowMoreProjects`, `sessionsLabel`, `defaultCollapsed` (`false`), `emptyState`, `className` | | `DocyrusAgentSidebar` | `open` (`true`), `onClose`, `widthClassName` (`'w-72'`), `width` (native, `288`), `presentation` (native, `'inline'`), `children`, `className` | | `DocyrusAgentSidebarHeader` | `agent`, `title` (`'Threads'`), `onClose`, `closeIcon`, `trailing`, `className` | | `DocyrusAgentSidebarNewChatButton` | `onClick`, `onPress` (native alias), `icon`, `label` (`'New Chat'`), `className` | | `DocyrusAgentSidebarThreadsSection` | `threads`, `activeThreadId`, `isLoading`, `label` (`'Recent Sessions'`), `defaultCollapsed`, `onSelectThread`, `onRenameThread`, `onDeleteThread`, `emptyState`, `loadingState`, `renderItem`, `className` | | `DocyrusAgentSidebarProjectsSection` | `projects`, `activeProjectId`, `maxVisibleProjects` (`3`), `label`, `onSelectProject`, `onNewProject`, `onRenameProject`, `onDeleteProject`, `onShowMoreProjects`, `emptyState`, `renderItem`, `header`, `renderShowMore`, `className` | | `DocyrusAgentThreadItem` | `thread`, `isActive`, `onSelect`, `onRename`, `onDelete`, `hideActions`, `meta`, `className` | Rows: tap selects the row. Long-press or "⋯" opens an action sheet with Rename (inline edit) and Delete (confirm dialog). `presentation="drawer"` needs a `SafeAreaProvider` above it. ### Projects | Component | Key props | |-----------|-----------| | `DocyrusAgentProjectsView` | `projects`, `onBack`, `onNewProject`, `onSelectProject`, `onRenameProject`, `onDeleteProject`, `onEditClick`, `onDeleteClick`, `title` (`'Projects'`), `subtitle` (`'Manage projects'`), `compact`, `search` (`null` hides), `renderCard`, `headerLeading`, `className` | | `DocyrusAgentProjectCard` | `project`, `onSelect`, `onEdit`, `onDelete`, `header`, `description`, `body`, `actions`, `className` | | `DocyrusAgentProjectItem` | `project`, `isActive`, `onSelect`, `onRename`, `onDelete`, `hideActions`, `className` | | `DocyrusAgentCreateProjectView` | `onCancel`, `onCreate({ name, description })` (both required), `isCreating` (`false`), `title`, `nameLabel`, `descriptionLabel`, `namePlaceholder`, `descriptionPlaceholder`, `headerLeading`, `extraFields`, `actions`, `className` | | `DocyrusAgentProjectDetailView` | `project`, `agent`, `threads` (required), `onBack`, `allProjectsLabel`, `headerLeading`, `onSendMessage`, `onStopGeneration`, `chatStatus`, `allowAttachments`, `acceptFileTypes` (`string \| string[]`), `inputPlaceholder`, `isLoadingThreads`, `activeThreadId`, `onSelectThread`, `sessionsContent`, `worksContent`, `documentsContent`, `renderThreadRow`, `activeTab` (`'sessions'`), `onTabChange`, `footerText`, `className` | | `DocyrusAgentProjectHeader` | `project`, `onBack`, `allProjectsLabel` (`'All Projects'`), `leading`, `className` | | `DocyrusAgentProjectTabs` | `sessionsContent` (required), `worksContent`, `documentsContent`, `sessionsLabel`, `worksLabel`, `documentsLabel`, `value`, `onValueChange`, `className` | | `DocyrusAgentProjectThreadRow` | `thread`, `isActive`, `onSelect`, `className` | | `DocyrusAgentProjectPromptInput` | `agent` (required), `onSendMessage`, `onStopGeneration`, `chatStatus`, `allowAttachments`, `acceptFileTypes`, `placeholder` (`'Ask about this project...'`), `footerText` (`null` hides), `children`, `className` | ### Memories | Component | Key props | |-----------|-----------| | `DocyrusAgentMemoriesView` | `memories`, `loading`, `saving`, `deletingId`, `error`, `levels` (`DEFAULT_MEMORY_LEVELS`), `defaultMemoryFormValue` (`EMPTY_MEMORY_FORM`), `onBack`, `onCreate`, `onUpdate`, `onDelete`, `searchQuery`, `onSearchQueryChange`, `hideSearch`, `levelFilter` / `onLevelFilterChange` / `hideLevelFilter` (native), `hideCreateButton`, `hideBackButton`, `renderRow`, `title`, `emptyState`, `loadingState`, `errorState`, `beforeList`, `headerTrailing`, `className` | | `DocyrusAgentMemoryRow` | `memory`, `onClick`, `onDelete`, `isDeleting`, `children`, `trailingMeta`, `actions`, `confirmDelete` (native, `true`), `className` | | `DocyrusAgentMemoryForm` | `value`, `onChange`, `levels`, `disabled`, `header`, `footer`, `className` | | `DocyrusAgentMemoryFormDialog` | `open`, `onOpenChange`, `memory` (`null` = create), `levels`, `saving` (`false`), `onSubmit`, `defaultValue` (`EMPTY_MEMORY_FORM`), `title(editing)`, `footer(helpers)`, `className` | | `DocyrusAgentMemoryExtractionDialog` | `open`, `onOpenChange`, `candidates`, `loading`, `saving`, `error`, `levels`, `onSave`, `onSkip`, `onSaveAll`, `onSkipAll`, `onLevelChange`, `renderRow`, `emptyState`, `loadingState`, `errorState`, `title`, `banner`, `footer`, `className` | | `DocyrusAgentMemoryCandidateRow` | `candidate`, `levels`, `onSave`, `onSkip`, `onLevelChange`, `children`, `className` | The dialogs are bottom `AwesomeDialog` sheets. Candidate rows slide out on save or skip (Reanimated). Back them with [`useDocyrusAgentMemories`](/docs/native/hooks/use-docyrus-agent-memories) and [`useDocyrusAgentMemoryCandidates`](/docs/native/hooks/use-docyrus-agent-memory-candidates). ### Action panel & inline | Component | Props | Notes | |-----------|-------|-------| | `DocyrusAgentActionPanel` | `className` | Mount inside `DocyrusAgentProvider mode="action-panel"`. State machine: action list → params → executing (chat when `opensChat`). A single `isDefault` action is auto-selected | | `DocyrusAgentActionList` | `className`, `contentContainerClassName` (native) | FlatList of action cards | | `DocyrusAgentActionParams` | `className` | `text` → Input, `textarea` → Textarea, `number` → numeric Input, `boolean` → Switch, `select` → Select. Required fields are validated (native) | | `DocyrusAgentInline` | `DocyrusAgentInlineProps` — `agent`, `messages`, `chatStatus`, `onSendMessage`, `onStopGeneration`, `onResubmit`, `selectedText`, `documentText`, `selectionStart`, `selectionEnd`, `onDocumentTextChange`, `onSelectedTextChange`, `promptTemplates`, `open`, `onOpenChange`, `side` / `align` (ignored), `className`, `children` (trigger) | Bottom sheet. The host passes the selection from its own `TextInput`. Insert / Replace write back through `onDocumentTextChange` | ### DocyrusAgentProvider `mode: 'chat' \| 'action-panel' \| 'trigger'` (required), plus every `DocyrusAgent` data prop. `useDocyrusAgent()` reads the context (throws outside a provider); `useOptionalDocyrusAgent()` returns `null` instead. ## Components | Component | Description | |-----------|-------------| | `DocyrusAgent` | Chat root (provider + chat) | | `DocyrusAgentTrigger` | Compact card that opens the chat in a sheet | | `DocyrusAgentChat` / `DocyrusAgentChatMessages` / `DocyrusAgentHeader` | Chat layout pieces | | `DocyrusAgentMessageParts` | Assistant part renderer (native export) | | `DocyrusAgentAvatar` | Agent avatar (image / icon / initials on the agent colour, native export) | | `DocyrusAgentChatInput*` | Composer and its parts | | `DocyrusAgentToolbarButton`, `DocyrusAgentPromptInputProvider` | Native composer primitives | | `DocyrusAgent*Sidebar*`, `DocyrusAgentThreadItem` | Threads drawer | | `DocyrusAgentProject*`, `DocyrusAgentCreateProjectView`, `DocyrusAgentProjectsView` | Projects | | `DocyrusAgentMemor*` | Memories | | `DocyrusAgentActionPanel` / `…ActionList` / `…ActionParams` | Action panel | | `DocyrusAgentInline` | Inline text assistant | | `DocyrusAgentProvider` | Context provider | ## Type Exports | Type | Description | |------|-------------| | `AgentProfile`, `AgentAction`, `AgentActionParam`, `AgentActionPayload`, `AgentMessagePayload`, `AgentSource`, `AgentSourceType`, `AgentCapabilities`, `AgentFeatureFlags`, `AgentMode`, `ActionPanelView` | Data model (same as web) | | `DocyrusAgentProps`, `DocyrusAgentTriggerProps`, `DocyrusAgentInlineProps`, `DocyrusAgentInlinePromptTemplate`, `DocyrusAgentContextValue` | Props / context | | `FeatureMenuRow`, `DocyrusAgentChatInputToolbarLayout`, `DocyrusAgentMicSpeechHandlers`, `UseDocyrusAgentMicTranscriptionArgs` / `Result` | Composer | | `DocyrusAgentMemory`, `DocyrusAgentMemoryCandidate`, `DocyrusAgentMemoryLevel`, `DocyrusAgentMemoryFormState` | Memories | | `DocyrusAgentProjectDetailTab`, `DocyrusAgentSidebarPresentation` | Projects / sidebar | | `DocyrusAgentPromptInputController`, `DocyrusAgentPromptInputFile`, `DocyrusAgentPromptInputMessage` | Native prompt input | Constants: `DEFAULT_FEATURE_ROWS`, `DEFAULT_MEMORY_LEVELS`, `EMPTY_MEMORY_FORM`. Helpers: `extractAdaptiveCard`, `normalizeAcceptFileTypes`, `getAgentInitials`. ## Translation Keys The components use the web `ui.agent.*` keys, including `askPrompt`, `sendMessage`, `stopGenerating`, `attachFile`, `copyMessage`, `thinking`, `defaultWelcome`, `sources`, `tools.*`, `memories.*`, `memory.*` and every sidebar / project key. Native-only keys: | Key | Fallback | |-----|----------| | `ui.agent.attachSource.files` / `.photos` / `.camera` | Files / Photos / Camera | | `ui.agent.removeAttachment` | Remove attachment | | `ui.agent.copied` | Copied | | `ui.agent.scrollToBottom` | Scroll to bottom | | `ui.agent.reasoning.title` / `.thinking` | Reasoning / Thinking… | | `ui.agent.toolState.pending` / `.running` / `.awaitingApproval` / `.responded` / `.completed` / `.error` / `.denied` | Pending / Running / Awaiting approval / Responded / Completed / Error / Denied | | `ui.agent.tool.parameters` / `.result` / `.error` | Parameters / Result / Error | | `ui.agent.back` | Back | | `ui.agent.fieldRequired` | This field is required | | `ui.agent.inline.yourPrompt` / `.previousVersion` / `.nextVersion` / `.close` / `.optionsGenerated` / `.thinking` / `.insert` / `.replace` / `.prompts` | Your prompt... / Previous version / Next version / Close / options generated: / Thinking… / Insert / Replace / Prompts | | `ui.agent.memories.actions` / `.objectName` / `.allLevels` | Memory actions / memory / All | ## Differences from web - **Icons:** props that take a lucide component on web (`triggerIcon`, `icon` on the mic / memory menu, `FeatureMenuRow.icon`) take a DocyrusIcon name here (`'fal globe'`). - **Menus:** dropdowns and hover menus become bottom action sheets. Hover actions become long-press or an always-visible "⋯" button. - **`acceptFileTypes`** also accepts a MIME array. `FileUIPart.url` is a local file URI, and uploads send the RN FormData `{ uri, name, type }` shape. - **Trigger** defaults to a full-height bottom sheet (`dialogSide='bottom'`, `dialogSize='full'`) and forwards capabilities, feature flags and header / input slots. - **Sidebar** has a `presentation` prop: `DocyrusAgentThreadsSidebar` is a left drawer by default. - **Inline** is a bottom sheet. `side` / `align` are ignored, and the host supplies the selection. - **Message rendering** adds adaptive cards, sources and file parts, which the web chat does not render.