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 text
  • JSON: 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

  1. Provider Setup: Always wrap your app with CranberrryProvider
  2. Hook Selection: Use specific hooks for specific needs:
    • useCBController for complete AI interfaces
    • useCBTaskManager for task management
    • useCBSelector for state subscriptions
  3. Error Handling: Implement proper error callbacks in your controllers
  4. Real-time Updates: Use the event system for live updates across components
  5. 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.

Was this page helpful?