Docyrus

DocyrusAgent

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.

iOSAndroidExpo Go
Preview DocyrusAgent on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-docyrus-agent
Required Packages(5 packages)
pnpm add ai expo-document-picker (optional) expo-image-picker (optional) expo-clipboard (optional) expo-speech-recognition (optional, dev build)

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, 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 AdaptiveCard. 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 + useDocyrusAgentMicTranscription) streams interim text into the input. It needs expo-speech-recognition and a development build — see Speech Recognition. In Expo Go the button hides itself.

Usage

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 (
    <>
      <DocyrusAgent
        agent={info.agent}
        messages={chat.messages}
        chatStatus={chat.chatStatus}
        suggestions={info.suggestions}
        capabilities={info.capabilities}
        allowAttachments
        acceptFileTypes="image/*,.pdf,.docx"
        onSendMessage={chat.sendMessage}
        onStopGeneration={chat.stop}
        headerLeading={<DocyrusAgentToolbarButton icon="fal sidebar" label="Threads" onPress={() => setThreadsOpen(true)} />}
        chatInput={(
          <DocyrusAgentChatInput>
            <DocyrusAgentChatInputDefaultBody extraTools={<DocyrusAgentChatInputMic />} />
          </DocyrusAgentChatInput>
        )} />
      <DocyrusAgentThreadsSidebar
        agent={info.agent}
        open={threadsOpen}
        onClose={() => 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:

<DocyrusAgentTrigger agent={agent} messages={messages} chatStatus={status} onSendMessage={send} onStopGeneration={stop} />

API Reference

DocyrusAgent

PropTypeDefaultDescription
agentAgentProfile-Agent identity: name, description, welcomeMessage (markdown), avatar { name, color, icon, image }, model (required)
messagesUIMessage[][]AI SDK messages
chatStatusChatStatus-'ready' | 'submitted' | 'streaming' | 'error'
actionsAgentAction[][]Actions for the action panel
sourcesAgentSource[][]Context sources (action panel badges)
onSendMessage(payload: AgentMessagePayload) => void | Promise<void>-Submit — { text, files?, featureFlags? }
onStopGeneration() => void-Stop button
onExecuteAction(payload: AgentActionPayload) => void | Promise<void>-Action panel execute
allowAttachmentsbooleanfalseAttach button + attachment strip
acceptFileTypesstring | string[]-Web accept string ('image/*,.pdf', extensions mapped to MIME) or a MIME array
suggestionsstring[][]Empty-state suggestion chips
emptyStateReactNode-Replaces the empty-state hero
showMessageActionsbooleantrueCopy button under assistant replies
headerLeadingReactNode-Slot before the header avatar
headerTrailingReactNode-Slot at the end of the header
chatInputReactNode-Replaces the chat input
chatTrailingReactNode-Slot below the chat input
capabilitiesAgentCapabilities{}support* flags that decide which feature toggles show
initialFeatureFlagsPartial<AgentFeatureFlags>-Initial toggle state
featureFlagsAgentFeatureFlags-Controlled toggle state (pair with onFeatureFlagsChange)
onFeatureFlagsChange(flags: AgentFeatureFlags) => void-Toggle change
onAdaptiveCardAction(event: AdaptiveCardActionEvent) => void | Promise<void>-Native only: action tapped inside an Adaptive Card tool output
classNamestring-Root classes (flex-1 bg-background)

DocyrusAgentTrigger

All DocyrusAgent props (forwarded to the chat), plus:

PropTypeDefaultDescription
openboolean-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

PropTypeDefaultDescription
headerLeading / headerTrailingReactNode-Header slots
chatInputReactNode<DocyrusAgentChatInput />Input area
chatTrailingReactNode-Slot below the input
hideHeaderbooleanfalseNative only: hide the agent header
keyboardVerticalOffsetnumber0Native only: KeyboardAvoidingView offset
classNamestring-Root classes

DocyrusAgentChatMessages

PropTypeDefaultDescription
classNamestring-Root classes
contentContainerClassNamestring-Native only: list content classes

DocyrusAgentHeader

PropTypeDefaultDescription
agentAgentProfile-Agent (required)
leading / trailingReactNode-Slots
classNamestring-Classes

DocyrusAgentChatInput

PropTypeDefaultDescription
childrenReactNode<DocyrusAgentChatInputDefaultBody />Custom body. The draft provider (submit → onSendMessage) is always mounted
classNamestring-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 <DocyrusAgentChatInputSubmit />) and className.

Chat input parts

ComponentPropsNotes
DocyrusAgentChatInputTextareaTextInputProps except value / onChangeText / multiline / style, placeholder?, maxHeight?: number (default 140), className?Auto-growing, bound to the draft
DocyrusAgentChatInputSubmitstatus?: ChatStatus, onStop?: () => void, disabled?: boolean, className?Send, or Stop while submitted / streaming
DocyrusAgentChatInputAttachButtonchildren?: ReactNode (icon), label?: string, className?Hidden when no picker is installed
DocyrusAgentChatInputAttachmentsrenderChip?: (file, remove) => ReactNode, className?Horizontal chip strip
DocyrusAgentChatInputFeatureTogglefeature: keyof AgentFeatureFlags, icon: string | ReactNode, tooltip: string, activeClassName?, className?Generic toggle
DocyrusAgentChatInputWebSearchToggle / …DocumentSearchToggle / …ThinkingToggle / …DeepResearchToggle / …WorkCanvasToggleclassName?Preset toggles
DocyrusAgentToolbarButtonicon: string | ReactNode, label: string, onPress?, onLongPress?, disabled?, active?, activeTone?: 'primary' | 'destructive', badge?: number, overlay?: ReactNode, activeClassName?, className?Native stand-in for web PromptInputButton

DocyrusAgentChatInputFeatureMenu

PropTypeDefaultDescription
rowsReadonlyArray<FeatureMenuRow>DEFAULT_FEATURE_ROWS filtered by capabilitiesReplace the rows
extraRowsReadonlyArray<FeatureMenuRow>-Rows appended after the defaults
hideFeaturesReadonlyArray<string>-Hide default rows by key
renderRow(row, { active, onChange }) => ReactNode-Custom row
triggerIconstring'fal sliders'Trigger DocyrusIcon name (web: lucide component)
activeClassNamestring-Trigger active classes
tooltipstring'Options'Sheet title / accessibility label
classNamestring-Trigger classes

FeatureMenuRow: { key, icon?: string \| ReactNode, label?, labelKey?, labelFallback?, flag?, capability?, active?, onChange? }.

DocyrusAgentChatInputMicButton / DocyrusAgentChatInputMic

PropTypeDefaultDescription
isRecordingboolean-Recording state (button only, required)
onToggle() => void-Toggle (button only, required)
isSupportedbooleantrueHide when false (button only)
disabledboolean-Disable
iconstring'fal microphone'DocyrusIcon name
recordingBadgeReactNode | nullpulsing dotBadge while recording (null hides it)
recordingClassNamestring-Active classes
tooltipIdle / tooltipRecordingstring'Microphone' / 'Stop recording'Accessibility labels
langstringdevice localeDocyrusAgentChatInputMic only
separator / merge / clearOnStartsee useDocyrusAgentMicTranscriptionDocyrusAgentChatInputMic only
classNamestring-Classes

useDocyrusAgentMicTranscription({ separator = ' ', merge?, clearOnStart = false }) returns { speechHandlers, resetBaseline }. Spread speechHandlers into useSpeechRecognition. It must run inside DocyrusAgentChatInput.

DocyrusAgentChatInputMemoryMenu

PropTypeDefaultDescription
onExtract() => void-"Extract Memories from Session"
onManageMemories() => void-"Manage Memories"
canExtract / canManagebooleantrueEnable the items
iconstring'fal brain-circuit'Trigger DocyrusIcon name
tooltipstring'Extract memories'Sheet title / label
childrenReactNode-Replaces the two items
extractLabel / manageLabelstring-Item labels (web: ReactNode)
classNamestring-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 NativeFiles or FileUIParts.

ComponentKey props
DocyrusAgentThreadsSidebarthreads, 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
DocyrusAgentSidebaropen (true), onClose, widthClassName ('w-72'), width (native, 288), presentation (native, 'inline'), children, className
DocyrusAgentSidebarHeaderagent, title ('Threads'), onClose, closeIcon, trailing, className
DocyrusAgentSidebarNewChatButtononClick, onPress (native alias), icon, label ('New Chat'), className
DocyrusAgentSidebarThreadsSectionthreads, activeThreadId, isLoading, label ('Recent Sessions'), defaultCollapsed, onSelectThread, onRenameThread, onDeleteThread, emptyState, loadingState, renderItem, className
DocyrusAgentSidebarProjectsSectionprojects, activeProjectId, maxVisibleProjects (3), label, onSelectProject, onNewProject, onRenameProject, onDeleteProject, onShowMoreProjects, emptyState, renderItem, header, renderShowMore, className
DocyrusAgentThreadItemthread, 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

ComponentKey props
DocyrusAgentProjectsViewprojects, onBack, onNewProject, onSelectProject, onRenameProject, onDeleteProject, onEditClick, onDeleteClick, title ('Projects'), subtitle ('Manage projects'), compact, search (null hides), renderCard, headerLeading, className
DocyrusAgentProjectCardproject, onSelect, onEdit, onDelete, header, description, body, actions, className
DocyrusAgentProjectItemproject, isActive, onSelect, onRename, onDelete, hideActions, className
DocyrusAgentCreateProjectViewonCancel, onCreate({ name, description }) (both required), isCreating (false), title, nameLabel, descriptionLabel, namePlaceholder, descriptionPlaceholder, headerLeading, extraFields, actions, className
DocyrusAgentProjectDetailViewproject, 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
DocyrusAgentProjectHeaderproject, onBack, allProjectsLabel ('All Projects'), leading, className
DocyrusAgentProjectTabssessionsContent (required), worksContent, documentsContent, sessionsLabel, worksLabel, documentsLabel, value, onValueChange, className
DocyrusAgentProjectThreadRowthread, isActive, onSelect, className
DocyrusAgentProjectPromptInputagent (required), onSendMessage, onStopGeneration, chatStatus, allowAttachments, acceptFileTypes, placeholder ('Ask about this project...'), footerText (null hides), children, className

Memories

ComponentKey props
DocyrusAgentMemoriesViewmemories, 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
DocyrusAgentMemoryRowmemory, onClick, onDelete, isDeleting, children, trailingMeta, actions, confirmDelete (native, true), className
DocyrusAgentMemoryFormvalue, onChange, levels, disabled, header, footer, className
DocyrusAgentMemoryFormDialogopen, onOpenChange, memory (null = create), levels, saving (false), onSubmit, defaultValue (EMPTY_MEMORY_FORM), title(editing), footer(helpers), className
DocyrusAgentMemoryExtractionDialogopen, onOpenChange, candidates, loading, saving, error, levels, onSave, onSkip, onSaveAll, onSkipAll, onLevelChange, renderRow, emptyState, loadingState, errorState, title, banner, footer, className
DocyrusAgentMemoryCandidateRowcandidate, 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 and useDocyrusAgentMemoryCandidates.

Action panel & inline

ComponentPropsNotes
DocyrusAgentActionPanelclassNameMount inside DocyrusAgentProvider mode="action-panel". State machine: action list → params → executing (chat when opensChat). A single isDefault action is auto-selected
DocyrusAgentActionListclassName, contentContainerClassName (native)FlatList of action cards
DocyrusAgentActionParamsclassNametext → Input, textarea → Textarea, number → numeric Input, boolean → Switch, select → Select. Required fields are validated (native)
DocyrusAgentInlineDocyrusAgentInlineProps — 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

ComponentDescription
DocyrusAgentChat root (provider + chat)
DocyrusAgentTriggerCompact card that opens the chat in a sheet
DocyrusAgentChat / DocyrusAgentChatMessages / DocyrusAgentHeaderChat layout pieces
DocyrusAgentMessagePartsAssistant part renderer (native export)
DocyrusAgentAvatarAgent avatar (image / icon / initials on the agent colour, native export)
DocyrusAgentChatInput*Composer and its parts
DocyrusAgentToolbarButton, DocyrusAgentPromptInputProviderNative composer primitives
DocyrusAgent*Sidebar*, DocyrusAgentThreadItemThreads drawer
DocyrusAgentProject*, DocyrusAgentCreateProjectView, DocyrusAgentProjectsViewProjects
DocyrusAgentMemor*Memories
DocyrusAgentActionPanel / …ActionList / …ActionParamsAction panel
DocyrusAgentInlineInline text assistant
DocyrusAgentProviderContext provider

Type Exports

TypeDescription
AgentProfile, AgentAction, AgentActionParam, AgentActionPayload, AgentMessagePayload, AgentSource, AgentSourceType, AgentCapabilities, AgentFeatureFlags, AgentMode, ActionPanelViewData model (same as web)
DocyrusAgentProps, DocyrusAgentTriggerProps, DocyrusAgentInlineProps, DocyrusAgentInlinePromptTemplate, DocyrusAgentContextValueProps / context
FeatureMenuRow, DocyrusAgentChatInputToolbarLayout, DocyrusAgentMicSpeechHandlers, UseDocyrusAgentMicTranscriptionArgs / ResultComposer
DocyrusAgentMemory, DocyrusAgentMemoryCandidate, DocyrusAgentMemoryLevel, DocyrusAgentMemoryFormStateMemories
DocyrusAgentProjectDetailTab, DocyrusAgentSidebarPresentationProjects / sidebar
DocyrusAgentPromptInputController, DocyrusAgentPromptInputFile, DocyrusAgentPromptInputMessageNative 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:

KeyFallback
ui.agent.attachSource.files / .photos / .cameraFiles / Photos / Camera
ui.agent.removeAttachmentRemove attachment
ui.agent.copiedCopied
ui.agent.scrollToBottomScroll to bottom
ui.agent.reasoning.title / .thinkingReasoning / Thinking…
ui.agent.toolState.pending / .running / .awaitingApproval / .responded / .completed / .error / .deniedPending / Running / Awaiting approval / Responded / Completed / Error / Denied
ui.agent.tool.parameters / .result / .errorParameters / Result / Error
ui.agent.backBack
ui.agent.fieldRequiredThis field is required
ui.agent.inline.yourPrompt / .previousVersion / .nextVersion / .close / .optionsGenerated / .thinking / .insert / .replace / .promptsYour prompt... / Previous version / Next version / Close / options generated: / Thinking… / Insert / Replace / Prompts
ui.agent.memories.actions / .objectName / .allLevelsMemory 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.

On this page