@swift-agents/react-native
v1.0.0
Published
React Native/Expo UI and typed client for the Swift Agents SDK API.
Readme
@swift-agents/react-native
React Native/Expo UI and typed client for the Swift Agents SDK API.
Configuration
The host supplies only the four values required to initialize a session:
import {
SwiftAgents,
SwiftAgentsProvider,
type SwiftAgentsConfig,
} from "@swift-agents/react-native";
const config: SwiftAgentsConfig = {
baseUrl: process.env.EXPO_PUBLIC_SWIFT_AGENTS_BASE_URL ?? "",
companyId: process.env.EXPO_PUBLIC_SWIFT_AGENTS_COMPANY_ID ?? "",
apiKey: process.env.EXPO_PUBLIC_SWIFT_AGENTS_API_KEY ?? "",
userEmail: process.env.EXPO_PUBLIC_SWIFT_AGENTS_USER_EMAIL ?? "",
};
export function Support() {
return (
<SwiftAgentsProvider config={config}>
<SwiftAgents onClose={() => {/* dismiss the host surface */}} />
</SwiftAgentsProvider>
);
}EXPO_PUBLIC_SWIFT_AGENTS_BASE_URL is the backend origin, for example
https://backend.example.com. The SDK appends /api/v1/sdk; do not add that
path to the configured value.
Initialization starts when SwiftAgents opens. Missing values render an in-app configuration error and do not trigger a retry loop.
Session-token lifecycle
The SDK calls POST /api/v1/sdk/{companyId}/init with:
X-API-Key: apiKeyContent-Type: application/json{ "email": userEmail }
The returned session_token is held in memory by the central client. It is never rendered, logged, exposed through the UI hooks, or persisted. Every later request uses Authorization: Bearer <session_token>.
The SDK clears the token when initialization fails or the session receives a 401/403. The host can retry the visible initialization error by remounting the SDK or pressing its retry action.
Company branding and prompts
company.name and company.logo_url from /init populate the header. The home screen displays company.suggested_ai_prompts only when enable_suggested_prompts is true.
Conversations
The client calls:
GET /api/v1/sdk/{companyId}/conversations?limit=20GET /api/v1/sdk/{companyId}/conversations?limit=20&cursor={next_cursor}GET /api/v1/sdk/{companyId}/conversations/{encodeURIComponent(conversationId)}
The sliding sidebar preserves API order, supports chats and tickets, deduplicates IDs, handles loading/empty/error/retry states, and shows No recent conversations yet for an empty response. Selecting a row loads its complete messages array; it never reconstructs history from last_message.
SSE chat
Chat uses a POST fetch request because the API requires a JSON body and bearer header:
POST /api/v1/sdk/{companyId}/chat
Accept: text/event-stream
Content-Type: application/json
Authorization: Bearer <session_token>Each new chat generates a client-side session_id before this first request.
Existing chat conversation IDs are reused, and the same ID is sent for later
messages in that chat.
The SDK buffers lines and frames before parsing. It supports LF/CRLF, split lines and JSON, multiple events per chunk, heartbeats, malformed individual events, unknown stages, final buffered data, cancellation, and stream cleanup. It does not use browser EventSource.
The documented stages map to the UI as follows:
chat_details: confirms the client-generated active session ID (or supplies a server-canonical ID) for subsequent sends.subject: updates the active conversation title.thinking: updates one searching indicator; it does not create bubbles.stream: progressively updates one assistant bubble.done: finalizes the bubble, clears streaming state, patches the active recent, and refreshes conversations.
Attachments
The SDK uses Expo DocumentPicker for multi-file selection. Local previews remain visible while sending. On send it:
- POSTs every local file under the repeated multipart key
files. - Receives remote attachment descriptors.
- Sends only those remote descriptors in the chat JSON body.
- Clears local selections only after the chat request completes successfully.
The SDK never sends a local device URI to /chat, never sets a multipart boundary manually, and prevents a text-only fallback when upload fails.
Consumers using Expo should provide expo-document-picker as a peer dependency. The example app already includes it.
Ticket reopening
Resolved ticket conversations expose the existing reopen action. It calls:
POST /api/v1/sdk/{companyId}/tickets/{encodeURIComponent(ticketId)}/reopen
Authorization: Bearer <session_token>Any successful 2xx response is accepted, including JSON, an empty body, and 204 No Content. The ticket is marked unresolved only after success, messages remain intact, and recents refresh. Failures preserve the current resolved state and display a safe message.
Error and request states
The provider and hooks expose initialization, conversation, upload, thinking, streaming, and reopen state. Requests use abort signals, stale conversation responses are ignored, and duplicate pagination/send operations are blocked. Backend message, detail, and error shapes are normalized without exposing request headers, tokens, keys, stack traces, or internal server details.
The caret continues to call the optional host-provided onClose callback. Opening the hamburger sidebar does not cancel an active stream; closing/unmounting the SDK does.
Environment setup
Copy apps/example/.env.example to apps/example/.env and supply local values. The Postman collection does not define a backend base URL, so use the actual URL provided by your backend environment. The example configuration reads only EXPO_PUBLIC_SWIFT_AGENTS_* variables.
Expo public variables are bundled into the application. EXPO_PUBLIC_SWIFT_AGENTS_API_KEY must therefore be a restricted client/publishable SDK key, never a privileged backend secret. Keep real values in ignored local environment files and never commit them.
Public API
The package exports SwiftAgents, SwiftAgentsProvider, the existing screen/components, useSwiftAgents, useSwiftAgentsChat, useSwiftAgentsRecents, createSwiftAgentsClient, SwiftAgentsApiError, SwiftAgentsSseParser, and the typed Postman contracts.
