Architecture
Cranberrry provides a comprehensive React-based architecture for building AI agent applications. This guide explains the core components, hooks, and providers that make up the Cranberrry package and how to use them effectively in your projects.
Overview
The Cranberrry package is built around a centralized state management system with specialized hooks for managing AI agents, tasks, and real-time message processing. The architecture consists of:
- State Management: Centralized store with agents and tasks
- Hooks: React hooks for accessing and managing state
- Providers: Context providers for dependency injection
- Supervisors: Task processing and message block handling
- Renderers: Real-time message rendering components
Core Components
CranberrryProvider
The CranberrryProvider
is the foundation of the Cranberrry architecture. It provides the centralized store to all child components.
import { CranberrryProvider } from '@cranberrry/package';
import { createCBStore, CBAgentReducer } from '@cranberrry/package/core';
const store = createCBStore(CBAgentReducer, {
agents: [],
tasks: []
});
function App() {
return (
<CranberrryProvider store={store}>
<YourApp />
</CranberrryProvider>
);
}
Purpose: Provides the centralized state store to all components in your application. This is required for all other Cranberrry components to work properly.
CranberrryRenderer
The CranberrryRenderer
component displays real-time AI agent messages as they are processed.
import { CranberrryRenderer } from '@cranberrry/package';
function ChatInterface({ taskId }) {
return (
<div className="chat-container">
<CranberrryRenderer taskId={taskId} />
</div>
);
}
Purpose: Renders AI agent responses in real-time as message blocks are processed. It automatically updates when new message blocks are added to the specified task.
State Management Hooks
useCBDispatch
Provides access to the store's dispatch function for updating state.
- Name
dispatch
- Description
Function to dispatch actions to the store.
Usage Example
import { useCBDispatch } from '@cranberrry/package';
import { addAgent, updateAgent } from '@cranberrry/package/core';
function AgentManager() {
const dispatch = useCBDispatch();
const createAgent = (agentData) => {
dispatch(addAgent(agentData));
};
const updateAgentStatus = (id, updates) => {
dispatch(updateAgent({ id, ...updates }));
};
return (
<div>
<button onClick={() => createAgent({ id: 'agent1', name: 'Assistant' })}>
Create Agent
</button>
</div>
);
}
Purpose: Gives you direct access to dispatch actions to the store. Use this when you need to manually update agents or tasks.
useCBSelector
A React hook for subscribing to specific parts of the store state.
- Name
selector
- Description
Function to select specific data from the store state.
- Name
selected
- Description
The selected data that will trigger re-renders when changed.
Usage Example
import { useCBSelector } from '@cranberrry/package';
function AgentList() {
const agents = useCBSelector(state => state.agents);
const busyAgents = useCBSelector(state =>
state.agents.filter(agent => agent.isBusy)
);
return (
<div>
<h3>All Agents ({agents.length})</h3>
<h3>Busy Agents ({busyAgents.length})</h3>
</div>
);
}
Purpose: Efficiently subscribe to specific parts of the store state. The component will only re-render when the selected data changes.
Agent Management Hooks
useCBAgent
Provides utilities for working with AI agents in the store.
- Name
agents
- Description
Array of all agents in the store.
- Name
getAgentById
- Description
Function to get a specific agent by ID.
Usage Example
import { useCBAgent } from '@cranberrry/package';
function AgentDetails({ agentId }) {
const { agents, getAgentById } = useCBAgent();
const agent = getAgentById(agentId);
if (!agent) {
return <div>Agent not found</div>;
}
return (
<div>
<h2>{agent.name}</h2>
<p>Status: {agent.isBusy ? 'Busy' : 'Available'}</p>
<p>Description: {agent.description}</p>
</div>
);
}
Purpose: Provides convenient methods for accessing and working with agents in the store. Use this when you need to display agent information or check agent status.
Task Management Hooks
useCBTaskManager
Comprehensive task management with CRUD operations for tasks.
- Name
tasks
- Description
Array of all tasks in the store.
- Name
createTask
- Description
Function to create a new task with agentId, input, and metadata.
- Name
updateTask
- Description
Function to update an existing task with partial data.
- Name
removeTask
- Description
Function to remove a task by ID.
- Name
getTask
- Description
Function to get a specific task by ID.
- Name
setTaskStatus
- Description
Function to update task status (idle, ongoing, completed, failed).
- Name
addMessageBlockToTask
- Description
Function to add a message block to a specific task.
Usage Example
import { useCBTaskManager } from '@cranberrry/package';
function TaskManager({ agentId }) {
const {
tasks,
createTask,
updateTask,
removeTask,
getTask,
setTaskStatus,
addMessageBlockToTask
} = useCBTaskManager();
const startNewTask = (input) => {
const taskId = createTask(agentId, input, { priority: 'high' });
return taskId;
};
const completeTask = (taskId) => {
setTaskStatus(taskId, 'completed');
};
const agentTasks = tasks.filter(task => task.agentId === agentId);
return (
<div>
<button onClick={() => startNewTask('Help me with coding')}>
Start New Task
</button>
{agentTasks.map(task => (
<div key={task.id}>
<span>{task.input}</span>
<span>{task.status}</span>
<button onClick={() => completeTask(task.id)}>
Complete
</button>
</div>
))}
</div>
);
}
Purpose: Provides complete task lifecycle management including creation, updates, status changes, and message block handling. This is the primary hook for managing AI agent tasks.
Agent Controller Hook
useCBController
The most comprehensive hook that combines task management with real-time processing capabilities.
- Name
prompt
- Description
Current prompt text being processed.
- Name
setPrompt
- Description
Function to update the prompt text.
- Name
isRunning
- Description
Boolean indicating if a task is currently running.
- Name
error
- Description
Current error message if any.
- Name
startAgentTask
- Description
Function to start a new agent task with input and metadata.
- Name
startExistingAgentTask
- Description
Function to resume an existing task by ID.
- Name
parseChunk
- Description
Function to process incoming data chunks in real-time.
- Name
complete
- Description
Function to mark the current task as completed.
- Name
reset
- Description
Function to reset the controller state.
- Name
status
- Description
Current status of the task processing.
- Name
tasks
- Description
Array of all tasks for the current agent.
- Name
messageBlocks
- Description
Array of processed message blocks for the current task.
- Name
emitter
- Description
Event emitter for real-time communication.
Usage Example
import { useCBController } from '@cranberrry/package';
function AIAgentInterface({ agentId, tagConfigs }) {
const {
prompt,
setPrompt,
isRunning,
error,
startAgentTask,
parseChunk,
complete
} = useCBController({
agentId,
tagConfigs,
callbacks: {
onComplete: () => console.log('Task completed'),
onError: (err) => console.error('Task failed:', err),
onBlockProcessed: (block) => console.log('Block processed:', block)
}
});
const handleSubmit = async (input) => {
const taskId = startAgentTask(input);
// Process streaming response
const response = await fetch('/api/ai', {
method: 'POST',
body: JSON.stringify({ prompt: input })
});
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
parseChunk(chunk);
}
complete();
};
return (
<div>
<textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Ask your AI agent..."
/>
<button
onClick={() => handleSubmit(prompt)}
disabled={isRunning}
>
{isRunning ? 'Processing...' : 'Send'}
</button>
{error && <div className="error">{error}</div>}
</div>
);
}
Purpose: The main hook for building AI agent interfaces. It provides:
- Task creation and management
- Real-time message processing
- Status tracking
- Error handling
- Message block rendering
- Event emission for real-time updates
Task Status Types
- Name
idle
- Description
Task is not yet started or has been reset.
- Name
ongoing
- Description
Task is currently being processed.
- Name
completed
- Description
Task has finished successfully.
- Name
failed
- Description
Task encountered an error and stopped.
Status Management Example
const { setTaskStatus, getTask } = useAgentTaskManager();
// Check task status
const task = getTask(taskId);
console.log(`Task ${taskId} is ${task.status}`);
// Update task status
setTaskStatus(taskId, 'completed');
// Monitor status changes
const taskStatus = useAgentSelector(state =>
state.tasks.find(t => t.id === taskId)?.status
);
Message Block Processing
Cranberrry uses a tag-based system for processing different types of AI responses:
const tagConfigs = [
{
tag: 'text',
processor: 'TEXT',
component: ({ ai }) => <p>{ai}</p>
},
{
tag: 'code',
processor: 'TEXT',
component: ({ ai }) => <pre><code>{ai}</code></pre>
},
{
tag: 'chart',
processor: 'JSON',
component: ({ ai }) => <Chart data={ai} />
}
];
Processor Types:
TEXT
: Treats content as plain textJSON
: Parses content as JSON object
Event System
The package uses a global event emitter for real-time communication:
// Listen for message events
useEffect(() => {
const handleMessage = ({ taskId, block }) => {
if (taskId === currentTaskId) {
// Handle new message block
console.log('New block:', block);
}
};
emitter.on('message', handleMessage);
return () => emitter.off('message', handleMessage);
}, [currentTaskId, emitter]);
Best Practices
- Provider Setup: Always wrap your app with
CranberrryProvider
- Hook Selection: Use specific hooks for specific needs:
useCBController
for complete AI interfacesuseCBTaskManager
for task managementuseCBSelector
for state subscriptions
- Error Handling: Implement proper error callbacks in your controllers
- Real-time Updates: Use the event system for live updates across components
- Status Management: Monitor task status for proper UI state management
This architecture provides a robust foundation for building AI agent applications with real-time processing, state management, and component reusability.