codicent-app-sdk
v0.4.26
Published
SDK for building AI-powered applications with Codicent
Readme
codicent-app-sdk
React SDK for building AI-powered, multi-tenant white-label applications on top of the Codicent platform.
Current version: 0.4.16 · License: MIT · Peer deps: React ≥16.8, Fluent UI v9, react-router-dom v6
What it provides
CodicentService— data CRUD, chat, file upload, token management- React components —
Page,Content,Chat,ListView,Markdown,UploadFile, and ~25 more - Pages —
AppFrame,Chat,Compose,Sales,Search,Snap,Login,Logout, and more - Hooks —
useCodicentApp,useLocalization,useChat,useRealtimeVoiceAI,useAuthState, and more - Global config —
initCodicentApp()initializer consumed by all SDK components - Full TypeScript types
This SDK is the primary dependency of codicentapp/ (the modern white-label Vite app) in the monorepo. See codicentapp/ for a complete real-world usage reference.
Installation
From npm
npm install codicent-app-sdkMonorepo local dependency (recommended during development)
In your app's package.json:
"dependencies": {
"codicent-app-sdk": "file:../codicent-app-sdk"
}Then npm install in your app.
Peer dependencies
Install these alongside the SDK:
npm install react react-dom react-router-dom @fluentui/react-components mermaidUsage
1. Initialize the SDK (once, at app startup)
Call initCodicentApp() before rendering your React tree. It stores config globally so all SDK components and hooks can read it.
// main.tsx
import { initCodicentApp } from 'codicent-app-sdk';
import { translations } from './services/translationService';
import { getAppConfig } from './appconfig';
initCodicentApp({
API_BASE_URL: 'https://codicent.com/',
APP_NAME: 'my-crm',
APP_PREFIX: 'mycrm',
USER_PREFIX: 'users',
APP_CONFIG: getAppConfig(), // buttons, listDefinitions, chatInstructions
TRANSLATIONS: translations, // { sv: {...}, en: {...}, ... }
USE_REALTIME_SESSION_ENDPOINT: true,
});2. Wrap with Auth0 and FluentProvider
The SDK components depend on these providers being present in the React tree:
// main.tsx (continued)
import { Auth0Provider } from '@auth0/auth0-react';
import { FluentProvider, webLightTheme } from '@fluentui/react-components';
import { createRoot } from 'react-dom/client';
createRoot(document.getElementById('root')!).render(
<Auth0Provider domain={AUTH0_DOMAIN} clientId={AUTH0_CLIENT_ID} authorizationParams={{ redirect_uri: window.location.origin }}>
<FluentProvider theme={webLightTheme}>
<App />
</FluentProvider>
</Auth0Provider>
);3. Use useCodicentApp() in your root App component
// App.tsx
import { useCodicentApp } from 'codicent-app-sdk';
import { useAuth0 } from '@auth0/auth0-react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import { Chat } from 'codicent-app-sdk';
import { ListPage } from './pages/ListPage';
export default function App() {
const auth0 = useAuth0();
const state = useCodicentApp({ auth0 });
if (!auth0.isAuthenticated) {
auth0.loginWithRedirect();
return null;
}
return (
<HashRouter>
<Routes>
<Route path="/chat" element={<Chat state={state} title="Chat" />} />
<Route path="/list" element={<ListPage state={state} />} />
</Routes>
</HashRouter>
);
}4. Build pages using SDK components
// pages/ListPage.tsx
import { Page, Content, ListView, useLocalization, CodicentAppState, DataMessage } from 'codicent-app-sdk';
import { useEffect, useState } from 'react';
import { APP_CONFIG } from '../appconfig';
import { APP_BUTTONS } from '../constants';
export const ListPage: React.FC<{ state: CodicentAppState }> = ({ state }) => {
const { service } = state;
const { t } = useLocalization();
const [data, setData] = useState<DataMessage[]>([]);
useEffect(() => {
service.readDataMessages('customer2').then(setData);
}, [service]);
const columns = APP_CONFIG.apps[APP_BUTTONS].listDefinitions['customer2'];
return (
<Page title={t('Kunder')}>
<Content>
<ListView data={data} columns={columns} />
</Content>
</Page>
);
};initCodicentApp() configuration options
Required:
| Key | Type | Description |
|-----|------|-------------|
| API_BASE_URL | string | Codicent backend URL, e.g. "https://codicent.com/" |
| APP_NAME | string | Application identifier |
Common optional:
| Key | Type | Description |
|-----|------|-------------|
| APP_PREFIX | string | URL/namespace prefix for this app |
| USER_PREFIX | string | User namespace prefix (default: "users") |
| APP_CONFIG | AppConfig | Per-app config: buttons, listDefinitions, chatInstructions |
| TRANSLATIONS | object | i18n map { sv: {...}, en: {...} }. Swedish strings are used as keys. |
| DEFAULT_LANGUAGE | string | Default language code (e.g. "sv", "en") |
| USE_REALTIME_SESSION_ENDPOINT | boolean | Use secure backend session token for voice AI (default: true) |
| REALTIME_VOICE_MODEL | string | Voice model: "alloy", "shimmer", or "echo" (default: "alloy") |
| SUBSCRIPTION_NEEDED | boolean | Redirect to purchase page if no active subscription |
| BUTTON_BORDER_RADIUS | string | CSS border-radius for nav buttons |
| BUTTON_BACKGROUND_COLOR | string | Background color for nav buttons |
Compose page GPS options:
| Key | Value | Behaviour |
|-----|-------|-----------|
| COMPOSE_HIDE_LOCATION | "true" | Hides GPS toggle button entirely |
| COMPOSE_HIDE_LOCATION | "false" (default) | Shows GPS toggle; users opt-in per post |
| COMPOSE_AUTO_LOCATION | "true" | Captures GPS automatically on page open |
When a location is attached, #gps(lat,lon) is appended to message content — queryable via tag search and readable by AI.
API Reference
CodicentService
The main service class for all data and chat operations. Access it via state.service from useCodicentApp().
Data message CRUD:
createDataMessage(tag: string, data: object, codicent?: string): Promise<string>
readDataMessages(
tag: string,
search?: string,
codicent?: string,
start?: number,
length?: number,
afterTimestamp?: string,
beforeTimestamp?: string,
dataFilters?: Record<string, string>
): Promise<DataMessage[]>
readOneDataMessage(id: string): Promise<DataMessage | null>
updateDataMessage(id: string, data: object, codicent?: string): Promise<string>
deleteDataMessage(id: string, codicent?: string): Promise<string>
getSchema(tag: string, codicent?: string): Promise<object | null>Chat and messages:
sendMessage(message: string, parentId?: string, codicent?: string): Promise<Message>
chat(message: string, messageId?: string, codicent?: string): Promise<Message>
getMessages(tags: string[], codicent?: string, length?: number): Promise<Message[]>
getMessagesFast(tags: string[], search?: string, length?: number, publicCodicent?: string, codicent?: string, start?: number): Promise<Message[]>Files:
uploadFile(filename: string, formData: FormData): Promise<string>
getFileInfo(fileId: string): Promise<FileInfo>
static getImageUrl(fileId: string, width: number): string
static getFileUrl(fileId: string, extension?: string): stringAuth and tokens:
getToken(): string
generateApiToken(expires?: Date, forUserNickname?: string): Promise<string>useCodicentApp(options)
Core hook that bootstraps app state, authentication, and the CodicentService instance.
const state = useCodicentApp({
auth0: useAuth0(), // Required: Auth0 hook result
toolsConfig?: object, // Optional: custom AI tool handlers
authOptions?: object, // Optional: override auth behaviour
});Returns CodicentAppState:
{
service: CodicentService; // Use for all data/chat operations
context: StateContext; // Project nickname, user info
auth: UseAuthState;
voice?: RealtimeVoice; // Voice AI connection (when active)
audio: AudioRecorderState;
stateMachine: AppStateMachine;
state: string; // Current state machine state
nickname: string; // Active project nickname
error: string;
isBusy: () => boolean;
html: string; // AI-generated HTML output
setHtml: (html: string) => void;
}5. Use DataMessagePicker for tagged record lookup
import { DataMessagePicker } from 'codicent-app-sdk';
<DataMessagePicker
service={state.service}
tag="customer2"
placeholder="Search customers"
primaryKey="Company Name"
displayKeys={["Company Name", "City"]}
secondaryKeys={["Customer Number", "City"]}
searchKeys={["Company Name", "Customer Number", "City"]}
onSelect={(selection) => {
console.log('Selected customer', selection.id, selection.data);
}}
/>The picker debounces lookups through readDataMessages(...), shows compact autosuggest results, and returns the raw DataMessage plus a normalized selection payload.
useLocalization()
const { t, tAsync, getLanguageInfo } = useLocalization();
t('Kunder') // → "Customers" (in English)
await tAsync('Kunder') // → API-backed translation with fallback
getLanguageInfo() // → { code: 'en', name: 'English', ... }Swedish strings are used as keys. Pass your translation maps via TRANSLATIONS in initCodicentApp().
Components
Page
Full-screen layout wrapper with optional header and footer.
<Page title="Customers" hideFooter={false} audio={state.audio} voice={state.voice}>
<Content>...</Content>
</Page>Content
Flex content container — use inside Page.
<Content>
<ListView data={data} columns={columns} />
</Content>Chat (page)
Full chat UI with message history, input, typing indicators, file uploads.
<Chat
state={state}
title="AI Assistant"
codicent="my-project" // Optional: override which project to chat with
welcomeMessage="Hi!" // Optional: shown when no messages exist
hideFooter={false}
/>ListView
Tabular data view with sorting, filtering, and column actions.
import { ListView } from 'codicent-app-sdk';
<ListView
data={dataMessages}
columns={[
{ key: 'name', title: 'Name', filterable: true },
{ key: ['offer_number', 'offerNumber'], title: 'Quote #', filterable: true },
{ key: 'grand_total', title: 'Total', format: formatNumber },
{ key: 'pdf', title: 'PDF', type: 'file' },
]}
onSelect={(item) => navigate(`/chat?id=${item.originalMessageId}`)}
/>Column definition options:
key: string | string[]— JSON field name; array = fallback chainformat: (value) => string— display transformerfilterable: true— per-column text filtertype: "file"— renders download linktype: "checkbox"— renders checkboxaction— icon button with click handler
AppFrame
Embeds an external URL in an iframe within the page layout.
<AppFrame src="https://example.com/embed" title="External view" showFooter={true} />Markdown
Renders markdown content including GFM and Mermaid diagrams.
<Markdown content={message.content} />UploadFile
File upload UI with progress.
<UploadFile service={state.service} codicent="my-project" />Hooks summary
| Hook | Purpose |
|------|---------|
| useCodicentApp() | Core app state, service, auth |
| useLocalization() | i18n translation |
| useChat(service) | Chat message state and send |
| useRealtimeVoiceAI(options) | Real-time voice AI connection |
| useAuthState(auth0) | Auth lifecycle and token |
| useTheme() | App theme/branding |
| useToaster() | Toast notification helpers |
| useStateWithLocalStorage() | Persistent local state |
| useAudioRecorder() | Microphone recording |
| useTemplateVariables() | Template string utilities |
| useTools() | AI tool handler registration |
| useEmbeddings() | Vector embedding operations |
TypeScript types
import type {
CodicentAppState,
ButtonConfig,
ColumnDefinition,
ListDefinitions,
DataMessage,
Message,
} from 'codicent-app-sdk';ButtonConfig — navigation button with optional RBAC claims:
{
title: string;
url: string; // "#/list?tag=customer2", "voice:...", "mailto:...", etc.
claim?: string; // Show only if user has this claim
notClaim?: string; // Hide if user has this claim
subtitle?: string;
options?: ButtonConfig[];
}DataMessage — result from readDataMessages():
{
id: string;
originalMessageId: string; // Stable ID across updates — use this for references/tags
content: string; // Raw: "@project #data #tag\n{json}"
data: Record<string, unknown>; // Parsed JSON payload
tags: string[];
createdAt: string;
}Alternative: createCodicentApp() factory
For standalone deployments where you do not control the React entry point, createCodicentApp() wraps the full initialization (including Auth0Provider, FluentProvider, HashRouter) and renders to a DOM element:
import { createCodicentApp } from 'codicent-app-sdk';
const app = createCodicentApp({
name: 'My CRM',
apiBaseUrl: 'https://codicent.com/',
auth0: { domain: '...', clientId: '...' },
buttons: [
{ title: 'Customers', url: './#/list?tag=customer2' },
{ title: 'Chat', url: './#/chat' },
],
listDefinitions: {
customer2: [
{ key: 'name', title: 'Name', filterable: true },
{ key: 'email', title: 'Email' },
],
},
chatInstructions: 'You are a helpful CRM assistant.',
modules: { sales: true, voice: true },
});
app.render('#root');
// app.unmount();
// app.getConfig();The codicentapp/ reference implementation uses initCodicentApp() + manual React tree setup, which gives more control over routing and layout. createCodicentApp() is appropriate for simpler or standalone deployments.
Local development workflow
Build the SDK
cd codicent-app-sdk
npm install
npm run build # Output: dist/cjs/, dist/esm/, dist/index.d.ts
npm run dev # Watch modeTest in codicentapp (file: reference)
In codicentapp/package.json:
"codicent-app-sdk": "file:../codicent-app-sdk"Then:
cd codicentapp
npm install
npm run buildTest with npm link
# In SDK directory
npm link
# In your app directory
npm link codicent-app-sdkTo restore npm version:
npm uninstall codicent-app-sdk
npm install codicent-app-sdkBuild output layout
dist/
cjs/ CommonJS modules
esm/ ES modules
index.d.ts TypeScript definitionsRelease
npm version patch # or minor / major
npm run build
npm publish --access publicDebugging
The SDK emits codicent-log custom events on window:
window.addEventListener('codicent-log', (event: CustomEvent) => {
console.log(event.detail); // { level, message, context }
});Related
codicentapp/— primary consumer; complete reference implementationcodicent-api-client/— framework-agnostic fetch-based API client (shared with web components)codicent-components/— zero-build Web Components library using the same Codicent API- Voice Upgrade Guide — real-time voice AI setup and security
License
MIT © Codicent Inside AB
