### Chat Setup
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of setting up a floating chat interface with Cedar-OS.
```tsx
import { FloatingCedarChat } from 'cedar-os';
function ChatApp() {
return (
{/* This automatically works */}
);
}
```
--------------------------------
### Using CLI flags
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of using the `--yes` flag to skip prompts during installation.
```bash
npx cedar-os-cli plant-seed --project-name my-cedar-tree --yes
```
--------------------------------
### Add your API key
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of setting up the `.env.local` file with OpenAI API keys for client-side and server-side access.
```bash
# For client-side access (Cedar-OS components in browser)
NEXT_PUBLIC_OPENAI_API_KEY=your-openai-api-key
# For server-side access (API routes, server components)
OPENAI_API_KEY=your-openai-api-key
```
--------------------------------
### Install cedar-os package using npm, yarn, pnpm, or bun
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Commands to install the cedar-os package using different package managers.
```bash
npm install cedar-os
```
```bash
yarn add cedar-os
```
```bash
pnpm add cedar-os
```
```bash
bun add cedar-os
```
--------------------------------
### Install runtime dependencies for Cedar-OS components
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Commands to install the necessary runtime dependencies for Cedar-OS components using npm, yarn, pnpm, or bun.
```bash
npm install lucide-react motion motion-plus-react uuid react-markdown framer-motion @radix-ui/react-slot class-variance-authority
```
```bash
yarn add lucide-react motion motion-plus-react uuid react-markdown framer-motion @radix-ui/react-slot class-variance-authority
```
```bash
pnpm add lucide-react motion motion-plus-react uuid react-markdown framer-motion @radix-ui/react-slot class-variance-authority
```
```bash
bun add lucide-react motion motion-plus-react uuid react-markdown framer-motion @radix-ui/react-slot class-variance-authority
```
--------------------------------
### Development Commands
Source: https://github.com/cedarcopilot/cedar-os/blob/main/src/app/examples/product-roadmap/README.md
Commands to install dependencies, run the development server, and access the product roadmap example.
```bash
# Install dependencies
npm install
# Run development server
npm run dev
# Navigate to
http://localhost:3000/examples/product-roadmap
```
--------------------------------
### Initialize CedarCopilot with OpenAI provider
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of configuring CedarCopilot with the OpenAI LLM provider.
```tsx
"use client";
import { CedarCopilot } from 'cedar-os';
function App() {
return (
);
}
```
--------------------------------
### Basic Setup Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/docs/THREAD_SYSTEM_SUMMARY.md
Example of how to set up Cedar Copilot with FloatingCedarChat, specifying LLM provider and message storage.
```tsx
import { FloatingCedarChat } from 'cedar-os-components';
```
--------------------------------
### LLM Provider Configuration
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of configuring a custom LLM provider with CedarCopilot.
```tsx
function App() {
return (
);
}
```
--------------------------------
### State Access
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of registering and managing application state with `useRegisterState` for AI interaction.
```tsx
import { useRegisterState } from 'cedar-os';
import { useState } from 'react';
import { z } from 'zod';
function TodoApp() {
const [todos, setTodos] = useState([]);
useRegisterState({
key: 'todos',
value: todos,
setValue: setTodos,
description: 'User todo list manageable by AI',
stateSetters: {
addTodo: {
name: 'addTodo',
description: 'Add a new todo item',
argsSchema: z.object({
text: z.string().describe('Todo text')
}),
execute: (currentTodos, args) => {
const { text } = args;
setTodos([...currentTodos, {
id: Date.now(),
text,
completed: false
}]);
}
},
toggleTodo: {
name: 'toggleTodo',
description: 'Toggle todo completion status',
argsSchema: z.object({
id: z.number().describe('Todo ID')
}),
execute: (currentTodos, args) => {
const { id } = args;
setTodos(currentTodos.map(t =>
t.id === id ? { ...t, completed: !t.completed } : t
));
}
}
}
});
return (
);
}
```
--------------------------------
### Initialize CedarCopilot with Mastra provider
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of wrapping your app with CedarCopilot and configuring the Mastra LLM provider.
```tsx
"use client";
import { CedarCopilot } from 'cedar-os';
function App() {
return (
);
}
```
--------------------------------
### Initialize CedarCopilot with AI SDK provider
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of configuring CedarCopilot with the AI SDK provider, supporting multiple LLM services.
```tsx
"use client";
import { CedarCopilot } from 'cedar-os';
function App() {
return (
// You don't need to put every model,
// but if you try to use a model without a key it will fail
);
}
```
--------------------------------
### Install Dependencies
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/hackathon-starter.mdx
Navigate to your project and install dependencies.
```bash
cd your-project-name
npm install && cd src/backend && npm install && cd ../..
```
--------------------------------
### Manual Installation Fails
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/cli.mdx
If automatic installation fails, the CLI will show manual installation steps.
```bash
# Manual Next.js creation
npx create-next-app@latest my-project
cd my-project
npx cedar-os-cli add-sapling
# Or follow the manual installation guide
```
--------------------------------
### Add Cedar components to an existing project
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Use this command if `plant-seed` fails to add Cedar components and dependencies.
```bash
# Add Cedar components and install dependencies only
npx cedar-os-cli add-sapling
```
--------------------------------
### Initialize CedarCopilot with Custom Backend
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Placeholder for configuring CedarCopilot with a custom backend provider.
```tsx
"use client";
import { CedarCopilot } from 'cedar-os';
```
--------------------------------
### Initialize CedarCopilot with Anthropic provider
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of configuring CedarCopilot with the Anthropic LLM provider.
```tsx
"use client";
import { CedarCopilot } from 'cedar-os';
function App() {
return (
);
}
```
--------------------------------
### Installation
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/README.md
Provides commands for installing Cedar-OS, recommending the CLI for automatic setup and offering a manual npm installation option.
```bash
# Recommended: Use our CLI for automatic setup (new and existing projects)
npx cedar-os-cli plant-seed
# Or install manually
npm install cedar-os
```
--------------------------------
### Example Implementation
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/chat/message-storage-configuration.mdx
An example implementation of a custom storage adapter for CedarCopilot.
```typescript
import { CedarCopilot } from 'cedar-os';
// Your custom storage implementation
const myCustomAdapter = {
async listThreads(userId) {
return await myDatabase.getThreads(userId);
},
async loadMessages(userId, threadId) {
return await myDatabase.getMessages(userId, threadId);
},
await persistMessage(userId, threadId, message) {
await myDatabase.appendMessage(userId, threadId, message);
},
};
function App() {
return (
);
}
```
--------------------------------
### Install Mintlify CLI
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/README.md
Command to install the Mintlify CLI globally.
```bash
npm i -g mint
```
--------------------------------
### Storage Abstraction API
Source: https://github.com/cedarcopilot/cedar-os/blob/main/src/app/examples/product-roadmap/README.md
Example functions demonstrating the consistent API for interacting with storage backends (Supabase or localStorage).
```typescript
// These functions work with both storage backends
await getNodes(); // Fetch all nodes
await saveNodes(nodes); // Save nodes
await getEdges(); // Fetch all edges
await saveEdges(edges); // Save edges
await deleteNode(id); // Soft delete a node
```
--------------------------------
### File Selection Collapse Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Real-world example of collapse configuration for file selection.
```tsx
const [selectedFiles, setSelectedFiles] = useState([]);
useSubscribeStateToAgentContext(
'selectedFiles',
(files) => ({ selectedFiles: files }),
{
labelField: 'filename',
icon: ,
color: '#EF4444',
// Boolean with default behavior
collapse: true, // Uses default threshold of 5
}
);
```
--------------------------------
### Installation
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os-components/README.md
Install the cedar-os-components package using npm.
```bash
npm install cedar-os-components
```
--------------------------------
### Installation
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os-backend/README.md
Install the @cedar-os/backend package using npm, yarn, or pnpm.
```bash
npm install @cedar-os/backend
# or
yarn add @cedar-os/backend
# or
pnpm add @cedar-os/backend
```
--------------------------------
### Multiple Context Keys Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Example demonstrating returning multiple keys from `mapFn` with different data structures.
```tsx
useSubscribeStateToAgentContext('appState', (state) => ({
currentUser: state.user, // Single object → single entry
act iveTasks: state.tasks, // Array → array of entries
selectedItems: [state.selected], // Single-item array → array
preferences: state.prefs, // Single object → single entry
}));
// Agent receives all four keys with appropriate structures
```
--------------------------------
### Basic Usage Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
A simple example demonstrating how to use `useSubscribeStateToAgentContext` with a todo list.
```tsx
import { useCedarState, useSubscribeStateToAgentContext } from 'cedar-os';
import { CheckCircle } from 'lucide-react';
function TodoApp() {
// 1) Register the state in Cedar
const [todos, setTodos] = useCedarState(
'todos',
[
{ id: 1, text: 'Buy groceries', completed: false },
{ id: 2, text: 'Walk the dog', completed: true },
],
'Todo items'
);
// 2) Subscribe that state to input context
useSubscribeStateToAgentContext(
'todos',
(todoList) => ({
todos: todoList, // Key 'todos' will be available to the agent
}),
{
icon: ,
color: '#10B981', // Green color
labelField: 'text', // Use the 'text' field as label for each todo
}
);
return (
{/* Agent can now see todos in context */}
);
}
```
--------------------------------
### Label Template Examples
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Examples demonstrating different label templates for the collapsed badge.
```tsx
// Examples of label templates
collapse: {
threshold: 3,
label: '{count} Items',
}
collapse: {
threshold: 8,
label: 'Multiple Selections ({count})',
}
collapse: {
threshold: 5,
label: 'Batch Selection',
}
```
--------------------------------
### Task Management Collapse Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Real-world example of collapse configuration for task management.
```tsx
const [selectedTasks, setSelectedTasks] = useState([]);
useSubscribeStateToAgentContext(
'selectedTasks',
(tasks) => ({ selectedTasks: tasks }),
{
labelField: 'title',
icon: ,
color: '#6366F1',
// Simple numeric threshold
collapse: 7, // Collapse when more than 7 tasks selected
}
);
```
--------------------------------
### Shopping Cart Collapse Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Real-world example of collapse configuration for a shopping cart.
```tsx
const [cartItems, setCartItems] = useState([
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Mouse', price: 29 },
{ id: 3, name: 'Keyboard', price: 79 },
// ... more items
]);
useSubscribeStateToAgentContext(
'cart',
(items) => ({ cartItems: items }),
{
labelField: 'name',
icon: ,
color: '#10B981',
// Collapse when cart has more than 3 items
collapse: {
threshold: 3,
label: '{count} Items in Cart',
icon: ,
},
}
);
```
--------------------------------
### Auto-Thread Creation Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/chat/thread-management.mdx
Example demonstrating how to automatically create a new thread if none exist when using storage adapters.
```typescript
// In messageStorage.ts - automatically creates a thread if none exist
const loadAndSelectThreads = async (
userId: string,
autoCreateThread: boolean = true
) => {
if (threads.length === 0 && autoCreateThread) {
const newThreadId = `thread-${Date.now()}-${Math.random()
.toString(36)
.substring(2, 9)}`;
await adapter.createThread(userId, newThreadId, {
id: newThreadId,
title: 'New Chat',
updatedAt: new Date().toISOString(),
});
}
};
```
--------------------------------
### Report Retrieval Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-backend-connection/agent-backend-connection.mdx
Example demonstrating how to retrieve a report from the backend with custom headers and how to access its typed properties.
```javascript
import { CedarClient } from "@cedarcopilot/cedar-client";
const cedarClient = new CedarClient({
// You can pass in custom headers here.
headers: {
'X-Custom-Auth': 'bearer-token',
'X-Report-Format': 'structured',
},
});
// reportResponse.object is fully typed as Report
console.log(reportResponse.object.summary); // string
console.log(reportResponse.object.metrics.conversionRate); // number (0-1)
console.log(reportResponse.object.insights[0].impact); // 'positive' | 'negative' | 'neutral'
console.log(reportResponse.object.recommendations); // string[]
```
--------------------------------
### Component-Level Styling Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/customising/styling.mdx
Example showing how a component like FloatingCedarChat uses global styling and how to set custom colors before rendering.
```tsx
import { FloatingCedarChat } from '@/chatComponents/FloatingCedarChat';
import { useCedarStore } from 'cedar-os';
function StyledChat() {
const { setStyling } = useCedarStore();
// Set custom colors before rendering
useEffect(() => {
setStyling({
color: '#8B5CF6', // Purple
secondaryColor: '#7C3AED',
accentColor: '#F97316', // Orange
});
}, []);
return ;
}
```
--------------------------------
### Programmatic Control Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/docs/THREAD_SYSTEM_SUMMARY.md
Example demonstrating how to use the `useThreadController` hook for programmatic control of threads.
```typescript
import { useThreadController } from 'cedar-os';
const { createThread, switchThread, deleteThread } = useThreadController();
// Create and switch to new thread
const newId = createThread();
switchThread(newId);
```
--------------------------------
### Streaming Response Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/voice/agentic-backend.mdx
An example of how to implement streaming audio responses for voice interactions, sending audio data in chunks to the client.
```typescript
// Example streaming response
app.post('/api/chat/voice-stream', async (req, res) => {
res.writeHead(200, {
'Content-Type': 'audio/mpeg',
'Transfer-Encoding': 'chunked',
});
const audioStream = await generateAudioStream(transcription);
audioStream.on('data', (chunk) => {
res.write(chunk);
});
audioStream.on('end', () => {
res.end();
});
});
```
--------------------------------
### Spells Integration
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/getting-started.mdx
Example of registering a spell with `useSpells` for custom actions.
```tsx
import { useSpells } from 'cedar-os';
import { useEffect } from 'react';
function SpellsApp() {
const { registerSpell } = useSpells();
useEffect(() => {
registerSpell({
id: 'quick-action',
name: 'Quick Action',
icon: '⚡',
action: () => console.log('Spell activated!'),
trigger: 'cmd+k'
});
}, []);
return (
Press Cmd+K to activate spells
);
}
```
--------------------------------
### Start Development Server
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/hackathon-starter.mdx
Make sure you're in the main project directory and run the development server.
```bash
cd path-to-root-project # if not already there
npm run dev
```
--------------------------------
### Supabase Environment Variables
Source: https://github.com/cedarcopilot/cedar-os/blob/main/src/app/examples/product-roadmap/README.md
Environment variables required to configure Supabase as the primary storage backend for the product roadmap.
```bash
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_KEY=your-supabase-anon-key
```
--------------------------------
### Quick Start CLI Command
Source: https://github.com/cedarcopilot/cedar-os/blob/main/README.md
Command to initialize a new Cedar OS project.
```bash
npx cedar-os-cli plant-seed
```
--------------------------------
### Quick Start Commands
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cli/README.md
Commands to quickly scaffold a new Cedar-OS project or add Cedar to an existing project.
```bash
npx cedar-os-cli
npx cedar-os-cli plant-seed
npx cedar-os-cli add-sapling
```
--------------------------------
### Using `useTypedAgentConnection` for Specific Providers
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/docs/agent-connection-examples.md
Example of using the `useTypedAgentConnection` hook to get type-safe `callLLM` and `streamLLM` functions for a known provider (e.g., 'openai' or 'mastra').
```typescript
import { useTypedAgentConnection } from 'cedar-os';
function MyOpenAIComponent() {
const { callLLM, streamLLM } = useTypedAgentConnection('openai');
const handleClick = async () => {
// TypeScript knows this needs model, not route
const response = await callLLM({
model: 'gpt-4', // ✅ Required and type-checked
prompt: 'Hello, world!',
});
// streamLLM is also properly typed
const stream = streamLLM(
{
model: 'gpt-4', // ✅ Required
prompt: 'Tell me a story',
},
(event) => {
if (event.type === 'chunk') {
console.log(event.content);
}
}
);
};
}
function MyMastraComponent() {
const { callLLM } = useTypedAgentConnection('mastra');
const handleClick = async () => {
// TypeScript knows this needs route, not model
const response = await callLLM({
route: '/chat/completions', // ✅ Required and type-checked
prompt: 'Hello, world!',
});
};
}
```
--------------------------------
### cedar pluck-component Usage
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/cli.mdx
Downloads specific Cedar components locally from an existing npm installation. Use this when you've installed `cedar-os-components` via npm but want to customize specific components.
```bash
npx cedar-os-cli pluck-component
```
--------------------------------
### Quick Start
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/spells/spells.mdx
Example of how to use the useSpell hook to create a custom spell with activation conditions and lifecycle callbacks.
```tsx
import { useSpell, Hotkey, ActivationMode } from 'cedar-os';
function MyComponent() {
const { isActive, activate, deactivate, toggle } = useSpell({
id: 'my-spell',
activationConditions: {
events: [Hotkey.SPACE],
mode: ActivationMode.HOLD,
},
onActivate: () => console.log('Spell activated!'),
onDeactivate: () => console.log('Spell deactivated!'),
});
// You can also trigger spells programmatically
const handleButtonClick = () => {
toggle(); // or activate() / deactivate()
};
return (
<>
{isActive ?
✨ Magic is happening!
: null}
>
);
}
```
--------------------------------
### Advanced Dynamic Configuration Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
A comprehensive example showing dynamic icons based on node status, conditional display (`showInChat`), and collapsing of context badges when multiple nodes are selected.
```tsx
import { Box } from 'lucide-react';
interface FeatureNodeData {
title: string;
status: 'done' | 'in progress' | 'planned' | 'backlog';
priority: 'high' | 'medium' | 'low';
}
const [selectedNodes, setSelectedNodes] = useState[]>([]);
useSubscribeStateToAgentContext(
'selectedNodes',
(nodes) => ({ selectedNodes: nodes }),
{
// Dynamic icons based on node status
icon: (node) => {
const status = node?.data?.status;
switch (status) {
case 'done':
return '✅';
case 'in progress':
return '🔄';
case 'planned':
return '📋';
case 'backlog':
return '📝';
default:
return ;
}
},
color: '#8B5CF6',
labelField: (node) => node?.data?.title,
// Only show nodes that are not in backlog status in chat context
showInChat: (entry) => {
const node = entry.data;
return node?.data?.status !== 'backlog';
},
order: 2,
// Collapse into a single badge when more than 5 nodes are selected
collapse: {
threshold: 5,
label: '{count} Selected Nodes',
icon: ,
},
}
);
```
--------------------------------
### Getting Current User ID
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/chat/message-storage-configuration.mdx
Provides an example of how to retrieve the currently set user ID using the `getCedarState` function.
```typescript
import { getCedarState } from 'cedar-os';
function CurrentUserDisplay() {
const userId = getCedarState('userId');
return
Current user: {userId || 'Not logged in'}
;
}
```
--------------------------------
### Message Grouping Logic
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/components/chat-bubbles.mdx
Example demonstrating how consistent 'role' values in messages lead to grouping, while a change in 'role' starts a new group.
```tsx
// Messages need consistent role values
const messages = [
{ id: '1', role: 'user', content: 'Hello' },
{ id: '2', role: 'user', content: 'How are you?' }, // Same role = grouped
{ id: '3', role: 'assistant', content: 'I am well' }, // Different role = new group
];
```
--------------------------------
### Stringified Context Access
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/agent-context.mdx
Example demonstrating how to get stringified versions of the editor input, compiled additional context, and the combined input context using `useCedarStore`.
```tsx
import { useCedarStore } from 'cedar-os';
function ContextStringifier() {
const { stringifyEditor, compileAdditionalContext, stringifyInputContext } =
useCedarStore();
const inspectContext = () => {
// Get just the user's text input
const userText = stringifyEditor();
console.log('User text:', userText);
// Get additional context as object (includes state data, setters, and schemas)
const contextData = compileAdditionalContext();
console.log('Context data:', contextData);
// Get combined input and context (what gets sent to AI)
const fullContext = stringifyInputContext();
console.log('Full context:', fullContext);
};
return ;
}
```
--------------------------------
### cedar add-sapling Usage
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/cli.mdx
Installs the latest version of Cedar-OS and optionally downloads Cedar UI components. Use to refresh your environment after Cedar updaes.
```bash
npx cedar-os-cli add-sapling
```
--------------------------------
### Download specific components
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/cli.mdx
Pass one or more component names with -c to download them directly.
```bash
npx cedar-os-cli pluck-component -c FloatingCedarChat TooltipMenu
```
--------------------------------
### Mastra Backend Connection
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-backend-connection/agent-backend-connection.mdx
Demonstrates how to use `useTypedAgentConnection` to get a typed connection for the Mastra backend, including examples for basic `callLLM`, streaming, and structured responses.
```typescript
import { useTypedAgentConnection } from 'cedar-os';
import { z } from 'zod';
// Get a typed connection for Mastra
const { callLLM, streamLLM, callLLMStructured } =
useTypedAgentConnection('mastra');
interface MastraParams extends BaseParams {
route: string;
resourceId?: string; // User ID in Cedar
threadId?: string;
}
// Example usage
const response = await callLLM({
route: '/chat/completions', // Full route path
prompt: 'Hello, AI!',
});
// Response is fully typed as LLMResponse
console.log(response.content); // string
console.log(response.usage?.totalTokens); // number | undefined
console.log(response.object); // unknown (for structured responses)
// Example with additional Mastra features
// Note: When using sendMessage(), the default route is automatically constructed
// as `${chatPath}` (e.g., '/chat')
const advancedResponse = await callLLM({
route: '/chat', // This would be the default for sendMessage()
prompt: 'Remember my name is John',
// Additional Mastra-specific parameters can be added
sessionId: 'user-123',
tools: ['web_search', 'calculator'],
knowledgeBaseId: 'kb-456',
});
// Structured response example with Mastra
const TaskPlanSchema = z.object({
title: z.string(),
steps: z.array(
z.object({
id: z.number(),
description: z.string(),
estimatedTime: z.string(),
dependencies: z.array(z.number()).optional(),
toolsRequired: z.array(z.string()).optional(),
})
),
totalEstimatedTime: z.string(),
complexity: z.enum(['simple', 'moderate', 'complex']),
requiredTools: z.array(z.string()),
});
type TaskPlan = z.infer;
const taskPlanResponse: TaskPlan = await callLLMStructured({
route: '/chat/structured',
prompt: 'Create a plan to build a todo app with user authentication',
schema: TaskPlanSchema,
// Mastra-specific parameters
sessionId: 'user-123',
tools: ['web_search', 'code_generator'],
knowledgeBaseId: 'development-kb',
});
// taskPlanResponse.object is fully typed as TaskPlan
console.log(taskPlanResponse.object.title); // string
console.log(taskPlanResponse.object.steps[0].estimatedTime); // string
console.log(taskPlanResponse.object.complexity); // 'simple' | 'moderate' | 'complex'
console.log(taskPlanResponse.object.requiredTools); // string[]
```
--------------------------------
### Node.js WebSocket Server Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/voice/websockets.mdx
This code snippet demonstrates a basic Node.js WebSocket server setup for handling voice interactions, including text response streaming and audio generation.
```typescript
import WebSocket from 'ws';
import { VoiceSession } from './voice-session'; // Assuming VoiceSession is defined elsewhere
import OpenAI from 'openai';
const openai = new OpenAI();
const server = new WebSocket.Server({ noServer: true });
// In-memory store for active sessions (replace with a more robust solution for production)
const sessions = new Map();
// Handle WebSocket upgrade requests
server.on('upgrade', (request, socket, head) => {
// Authenticate and authorize the connection here if needed
// For simplicity, we'll accept all connections
server.handleUpgrade(request, socket, head, (ws) => {
server.emit('connection', ws, request);
});
});
server.on('connection', (ws) => {
console.log('Client connected');
// Initialize a new voice session for this client
const session: VoiceSession = {
ws: ws,
settings: {
voiceId: 'alloy', // Default voice
rate: 1.0, // Default rate
},
// Add other session-specific properties as needed
};
sessions.set(ws, session);
ws.on('message', async (message: string) => {
console.log('Received message:', message);
try {
const parsedMessage = JSON.parse(message);
switch (parsedMessage.type) {
case 'text_input':
await handleTextInput(session, parsedMessage.text);
break;
case 'set_voice':
session.settings.voiceId = parsedMessage.voiceId;
break;
case 'set_rate':
session.settings.rate = parsedMessage.rate;
break;
default:
console.warn('Unknown message type:', parsedMessage.type);
}
} catch (error) {
console.error('Failed to process message:', error);
ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
}
});
ws.on('close', () => {
console.log('Client disconnected');
sessions.delete(ws);
});
ws.on('error', (error) => {
console.error('WebSocket error:', error);
sessions.delete(ws);
});
});
async function handleTextInput(session: VoiceSession, text: string) {
try {
// Simulate response generation
let fullResponse = '';
const responseChunks = ['This is the first part of the response. ', 'And this is the second part. ', 'Finally, the end of the response.'];
for (const chunk of responseChunks) {
fullResponse += chunk;
// Send response chunk
session.ws.send(
JSON.stringify({
type: 'response_chunk',
text: chunk,
})
);
// Simulate delay for streaming effect
await new Promise((resolve) => setTimeout(resolve, 500));
}
// Send complete response
session.ws.send(
JSON.stringify({
type: 'response_complete',
text: fullResponse,
})
);
// Generate and stream audio response
await generateStreamingAudio(session, fullResponse);
} catch (error) {
console.error('Response generation error:', error);
session.ws.send(
JSON.stringify({
type: 'error',
message: 'Failed to generate response',
})
);
}
}
async function generateStreamingAudio(session: VoiceSession, text: string) {
try {
// Generate speech
const speech = await openai.audio.speech.create({
model: 'tts-1',
voice: session.settings.voiceId || 'alloy',
input: text,
response_format: 'mp3',
speed: session.settings.rate || 1.0,
});
const audioBuffer = Buffer.from(await speech.arrayBuffer());
// Stream audio in chunks
const chunkSize = 4096;
for (let i = 0; i < audioBuffer.length; i += chunkSize) {
const chunk = audioBuffer.slice(i, i + chunkSize);
const base64Chunk = chunk.toString('base64');
session.ws.send(
JSON.stringify({
type: 'audio_chunk',
data: base64Chunk,
isLast: i + chunkSize >= audioBuffer.length,
})
);
// Small delay to prevent overwhelming the client
await new Promise((resolve) => setTimeout(resolve, 30));
}
// Mark audio complete
session.ws.send(
JSON.stringify({
type: 'audio_complete',
})
);
} catch (error) {
console.error('TTS generation error:', error);
session.ws.send(
JSON.stringify({
type: 'error',
message: 'Failed to generate speech',
})
);
}
}
// Start server
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`WebSocket voice server running on port ${PORT}`);
});
```
--------------------------------
### Complete Custom Provider Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-backend-connection/custom.mdx
A full TypeScript example demonstrating the implementation of a custom LLM provider, including methods for calling the LLM, handling responses, and streaming.
```typescript
import type {
CustomParams,
ProviderImplementation,
InferProviderConfig,
StructuredParams,
LLMResponse,
StreamHandler,
StreamResponse,
StreamEvent,
} from '@cedar-os/core';
type CustomConfig = InferProviderConfig<'custom'>;
export const myCustomProvider: ProviderImplementation<
CustomParams,
CustomConfig
> = {
callLLM: async (params, config) => {
const { prompt, systemPrompt, temperature, maxTokens, ...rest } = params;
const response = await fetch(`${config.config.baseURL}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${config.config.apiKey}`,
},
body: JSON.stringify({
messages: [
...(systemPrompt ? [{ role: 'system', content: systemPrompt }] : []),
{ role: 'user', content: prompt },
],
temperature,
max_tokens: maxTokens,
...rest,
}),
});
return myCustomProvider.handleResponse(response);
},
callLLMStructured: async (params, config) => {
// Implementation similar to callLLM but with schema handling
// ... (see example above)
},
streamLLM: (params, config, handler) => {
// Implementation for streaming
// ... (see example above)
},
handleResponse: async (response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return {
content: data.response || data.text || '',
usage: data.usage,
metadata: { model: data.model, id: data.id },
};
},
};
```
--------------------------------
### Add API Key
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/hackathon-starter.mdx
Create a .env file in the project root and add your OpenAI API key.
```bash
echo "OPENAI_API_KEY=your-api-key-here" > .env
```
--------------------------------
### Multi-Step Workflow
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/docs/agent-connection-examples.md
An example of a multi-step workflow using `useCedarStore` to call an LLM for different stages of code review: structure analysis, security checks, and improvement suggestions.
```typescript
function useCodeReviewFlow() {
const store = useCedarStore();
const reviewCode = async (code: string) => {
// Step 1: Analyze code structure
const structureAnalysis = await store.callLLM({
model: 'gpt-3.5-turbo',
prompt: `Analyze the structure of this code: ${code}`,
});
// Step 2: Check for security issues (using a different model)
const securityCheck = await store.callLLM({
model: 'gpt-4', // Use GPT-4 for security analysis
prompt: `Check for security vulnerabilities: ${code}`,
systemPrompt: 'You are a security expert. Be thorough.',
});
// Step 3: Generate improvement suggestions
const improvements = await store.callLLM({
model: 'gpt-4',
prompt: `Suggest improvements based on:
Structure: ${structureAnalysis.content}
Security: ${securityCheck.content}
Code: ${code}`,
});
return {
structure: structureAnalysis,
security: securityCheck,
improvements: improvements,
};
};
return { reviewCode };
}
```
--------------------------------
### FrontendTool Response Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/state-access/agentic-actions.mdx
Example of a JSON response for a frontendTool type action.
```json
{
"type": "frontendTool",
"toolName": "showNotification",
"args": {
"message": "Feature added successfully!",
"type": "success"
}
}
```
--------------------------------
### setState Response Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/state-access/agentic-actions.mdx
Example of a JSON response for a setState type action.
```json
{
"type": "setState",
"stateKey": "nodes",
"setterKey": "addNode",
"args": {
/* node data */
}
}
```
--------------------------------
### Basic Order Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/subscribing-state.mdx
Demonstrates how to use the `order` option in `useSubscribeStateToAgentContext` to control the display priority of different types of context data.
```tsx
function PrioritizedContext() {
const [criticalAlerts, setCriticalAlerts] = useState([]);
const [normalTasks, setNormalTasks] = useState([]);
const [archivedItems, setArchivedItems] = useState([]);
// Critical alerts appear first (order: 1)
useSubscribeStateToAgentContext(
criticalAlerts,
(alerts) => ({ criticalAlerts: alerts }),
{
icon: ,
color: '#EF4444',
order: 1, // Highest priority - appears first
}
);
// Normal tasks appear second (order: 10)
useSubscribeStateToAgentContext(
normalTasks,
(tasks) => ({ activeTasks: tasks }),
{
icon: ,
color: '#3B82F6',
order: 10, // Medium priority
}
);
// Archived items appear last (order: 100)
useSubscribeStateToAgentContext(
archivedItems,
(items) => ({ archivedItems: items }),
{
icon: ,
color: '#6B7280',
order: 100, // Low priority - appears last
}
);
return ;
}
```
--------------------------------
### Streaming AI Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/components/markdown-renderer.mdx
Example of using MarkdownRenderer with streaming AI messages.
```tsx
import { MarkdownRenderer } from 'cedar-os-components/chatMessages/MarkdownRenderer';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages } = useChat();
return messages.map((message) => (
));
}
```
--------------------------------
### Recommended Configuration Pattern
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/getting-started/organizing-a-cedar-project.mdx
Example of defining message renderers and response handlers in separate files within the `cedar/` directory and importing them for `CedarCopilot` initialization.
```tsx
// cedar/messageRenderers.ts
export const messageRenderers = {
// Your custom message renderers
};
// cedar/responseHandlers.ts
export const responseHandlers = {
// Your response handling logic
};
// In your main component
import { messageRenderers } from '../cedar/messageRenderers';
import { responseHandlers } from '../cedar/responseHandlers';
;
```
--------------------------------
### Custom Debug Flow Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os/docs/agent-connection-examples.md
An example of a custom `useDebugFlow` hook that demonstrates how to build a specific prompt for debugging, make a streaming LLM call, and handle the response with custom logic.
```typescript
import { useCedarStore } from 'cedar-os';
function useDebugFlow() {
const store = useCedarStore();
const debugFlow = async () => {
// 1. Parse context from the current state
const context = store.getCedarState('debugContext');
const userCode = store.getCedarState('currentCode');
const errorMessage = store.getCedarState('lastError');
// 2. Build a specific prompt for debugging
const debugPrompt = `
Debug the following code:
Code:
${userCode}
Error:
${errorMessage}
Context:
${JSON.stringify(context, null, 2)}
Please provide:
1. The root cause of the error
2. A fix for the code
3. An explanation of what went wrong
`;
// 3. Make the LLM call with specific configuration
const response = await store.streamLLM(
{
prompt: debugPrompt,
model: 'gpt-4', // Use GPT-4 for complex debugging
temperature: 0.2, // Low temperature for precise debugging
systemPrompt: 'You are an expert debugger. Be concise and accurate.',
},
// 4. Handle the streaming response with custom logic
(event) => {
switch (event.type) {
case 'chunk':
// Parse the response and update UI in real-time
const lines = event.content.split('\n');
// Look for specific patterns in the response
if (event.content.includes('ROOT CAUSE:')) {
store.setCedarState('debugRootCause', event.content);
} else if (event.content.includes('FIX:')) {
store.setCedarState('suggestedFix', event.content);
}
// Update the debug output
store.setCedarState(
'debugOutput',
(prev: string) => prev + event.content
);
break;
case 'done':
// Execute post-processing
store.setCedarState('debugStatus', 'complete');
// Automatically apply the fix if confidence is high
const output = store.getCedarState('debugOutput');
if (output.includes('CONFIDENCE: HIGH')) {
applyDebugFix();
}
break;
case 'error':
console.error('Debug flow error:', event.error);
store.setCedarState('debugStatus', 'error');
break;
}
}
);
return response;
};
const applyDebugFix = () => {
const suggestedFix = store.getCedarState('suggestedFix');
// Apply the fix to the code editor
store.setCedarState('currentCode', suggestedFix);
};
return { debugFlow };
}
```
--------------------------------
### Container Styling Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/components/chat-bubbles.mdx
Examples of applying background and border styles to the ChatBubbles container.
```tsx
// Default flexible container
// Fixed height with custom styling
```
--------------------------------
### Advanced Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/components/typewriter-text.mdx
An advanced example combining multiple props for a complex typewriter effect.
```tsx
setShowNextSection(true)}
/>
```
--------------------------------
### Quick Start: Extracting Schemas
Source: https://github.com/cedarcopilot/cedar-os/blob/main/packages/cedar-os-backend/README.md
Demonstrates how to extract frontend tool and state setter schemas using the @cedar-os/backend package and how to use them directly with AI agent's experimental_output.
```typescript
import {
getFrontendToolSchemas,
getStateSetterSchemas,
getFrontendToolSchema,
getStateSetterSchema,
} from '@cedar-os/backend';
// Extract all frontend tool schemas (returns JSON Schemas directly)
const frontendSchemas = getFrontendToolSchemas(requestBody);
// Extract all state setter schemas (returns JSON Schemas directly)
const setterSchemas = getStateSetterSchemas(requestBody);
// Extract a specific frontend tool schema
const notificationSchema = getFrontendToolSchema(
requestBody,
'showNotification'
);
// Extract a specific state setter schema
const addNodeSchema = getStateSetterSchema({
requestBody,
setterKey: 'addNode',
stateKey: 'nodes',
});
// Use directly with experimental_output
const response = await agent.generate({
messages: [{ role: 'user', content: body.prompt }],
experimental_output: {
schema: notificationSchema, // JSON Schema works directly
},
});
```
--------------------------------
### Mentions System Example
Source: https://github.com/cedarcopilot/cedar-os/blob/main/docs/agent-context/agent-context.mdx
Example of creating a mention provider for documents using useStateBasedMentionProvider.
```tsx
import { useStateBasedMentionProvider } from 'cedar-os';
import { FileText } from 'lucide-react';
function DocumentChat() {
const [documents] = useCedarState('documents', [
{ id: 'doc1', title: 'Project Proposal', type: 'pdf' },
{ id: 'doc2', title: 'Meeting Notes', type: 'doc' },
]);
// Create a mention provider for documents
useStateBasedMentionProvider({
stateKey: 'documents',
trigger: '@',
labelField: 'title',
searchFields: ['title', 'type'],
description: 'Documents',
icon: ,
color: '#8b5cf6',
order: 5, // Control display order when mentioned
});
return ;
}
```