Chat SDK

Overview

Build applications with multiple specialized agents working together. Each agent can have its own purpose, UI, and event handlers - all running simultaneously without interference.

Why Multiple Agents?

Instead of one general-purpose agent, use specialized agents for different tasks:

  • Code Agent - Writes and reviews code
  • Design Agent - Creates UI designs and components
  • Documentation Agent - Writes technical docs
  • Testing Agent - Generates and runs tests
  • DevOps Agent - Handles deployments and infrastructure

Each agent focuses on what it does best, creating a powerful development environment.

Basic Multi-Instance Setup

Unique Agent IDs

Always provide unique agentId to each ChatProvider:

function MultiAgentApp() {
  return (
    <div className="agent-workspace">
      {/* Code Writing Agent */}
      <ChatProvider agentId="code-agent" authConfig={codeAgentAuth}>
        <CodePanel />
      </ChatProvider>

      {/* Design Agent */}
      <ChatProvider agentId="design-agent" authConfig={designAgentAuth}>
        <DesignPanel />
      </ChatProvider>

      {/* Testing Agent */}
      <ChatProvider agentId="test-agent" authConfig={testAgentAuth}>
        <TestPanel />
      </ChatProvider>
    </div>
  );
}

Event Isolation

Each agent's events are automatically isolated:

function CodePanel() {
  // Only receives events from code-agent
  useForwarding('write_code', (code) => {
    updateCodeEditor(code);
  });

  useStatusSubscription('tool_call', (status) => {
    updateCodeToolStatus(status);
  });

  return <CodeEditor />;
}

function DesignPanel() {
  // Only receives events from design-agent
  useForwarding('generate_design', (design) => {
    updateDesignCanvas(design);
  });

  useStatusSubscription('tool_call', (status) => {
    updateDesignToolStatus(status);
  });

  return <DesignCanvas />;
}

Real-World Applications

Full-Stack Development IDE

Build entire applications with specialized agents:

function DevIDE() {
  const [codeAuth, setCodeAuth] = useState(null);
  const [designAuth, setDesignAuth] = useState(null);
  const [testAuth, setTestAuth] = useState(null);

  useEffect(() => {
    // Create sessions for each agent
    Promise.all([
      createSession({ agentId: 'code-writer' }),
      createSession({ agentId: 'ui-designer' }),
      createSession({ agentId: 'test-generator' })
    ]).then(([code, design, test]) => {
      setCodeAuth(code);
      setDesignAuth(design);
      setTestAuth(test);
    });
  }, []);

  if (!codeAuth || !designAuth || !testAuth) {
    return <Loading />;
  }

  return (
    <div className="grid grid-cols-3 h-screen">
      {/* Backend Code Agent */}
      <ChatProvider agentId="backend" authConfig={codeAuth}>
        <BackendPanel />
      </ChatProvider>

      {/* Frontend Design Agent */}
      <ChatProvider agentId="frontend" authConfig={designAuth}>
        <FrontendPanel />
      </ChatProvider>

      {/* Testing Agent */}
      <ChatProvider agentId="testing" authConfig={testAuth}>
        <TestingPanel />
      </ChatProvider>
    </div>
  );
}

Content Creation Platform

Multiple agents for different content types:

function ContentPlatform() {
  return (
    <div className="content-workspace">
      {/* Article Writer */}
      <ChatProvider agentId="writer" authConfig={writerAuth}>
        <ArticleEditor />
      </ChatProvider>

      {/* SEO Optimizer */}
      <ChatProvider agentId="seo" authConfig={seoAuth}>
        <SEOPanel />
      </ChatProvider>

      {/* Image Generator */}
      <ChatProvider agentId="images" authConfig={imageAuth}>
        <ImageGallery />
      </ChatProvider>

      {/* Social Media */}
      <ChatProvider agentId="social" authConfig={socialAuth}>
        <SocialPosts />
      </ChatProvider>
    </div>
  );
}

Data Analysis Dashboard

Agents for different analysis tasks:

function AnalyticsDashboard() {
  return (
    <div className="dashboard">
      {/* Data Query Agent */}
      <ChatProvider agentId="query" authConfig={queryAuth}>
        <QueryBuilder />
      </ChatProvider>

      {/* Visualization Agent */}
      <ChatProvider agentId="viz" authConfig={vizAuth}>
        <ChartGenerator />
      </ChatProvider>

      {/* Insights Agent */}
      <ChatProvider agentId="insights" authConfig={insightsAuth}>
        <InsightsPanel />
      </ChatProvider>

      {/* Report Agent */}
      <ChatProvider agentId="reports" authConfig={reportAuth}>
        <ReportGenerator />
      </ChatProvider>
    </div>
  );
}

Agent Communication

Agents can work together through your application state:

function CollaborativeAgents() {
  const [sharedState, setSharedState] = useState({
    code: '',
    design: '',
    tests: ''
  });

  return (
    <>
      {/* Code Agent writes code */}
      <ChatProvider agentId="coder" authConfig={coderAuth}>
        <CodeAgent
          onCodeChange={(code) => setSharedState(s => ({ ...s, code }))}
        />
      </ChatProvider>

      {/* Design Agent uses the code to generate UI */}
      <ChatProvider agentId="designer" authConfig={designAuth}>
        <DesignAgent
          codeContext={sharedState.code}
          onDesignChange={(design) => setSharedState(s => ({ ...s, design }))}
        />
      </ChatProvider>

      {/* Test Agent generates tests for the code */}
      <ChatProvider agentId="tester" authConfig={testAuth}>
        <TestAgent
          codeContext={sharedState.code}
          onTestsChange={(tests) => setSharedState(s => ({ ...s, tests }))}
        />
      </ChatProvider>
    </>
  );
}

Dynamic Agent Loading

Load agents on demand:

function DynamicAgentWorkspace() {
  const [activeAgents, setActiveAgents] = useState(new Map());

  const addAgent = async (type) => {
    const session = await createSession({ agentId: type });
    setActiveAgents(prev => new Map(prev).set(type, {
      auth: session,
      instanceId: `agent-${type}-${Date.now()}`
    }));
  };

  const removeAgent = (type) => {
    setActiveAgents(prev => {
      const next = new Map(prev);
      next.delete(type);
      return next;
    });
  };

  return (
    <div>
      <div className="agent-controls">
        <button onClick={() => addAgent('code')}>Add Code Agent</button>
        <button onClick={() => addAgent('design')}>Add Design Agent</button>
        <button onClick={() => addAgent('docs')}>Add Docs Agent</button>
      </div>

      <div className="agent-panels">
        {Array.from(activeAgents.entries()).map(([type, agent]) => (
          <ChatProvider
            key={agent.instanceId}
            agentId={agent.instanceId}
            authConfig={agent.auth}
          >
            <AgentPanel
              type={type}
              onClose={() => removeAgent(type)}
            />
          </ChatProvider>
        ))}
      </div>
    </div>
  );
}

Per-Agent Configuration

Different settings for each agent:

function CustomizedAgents() {
  return (
    <>
      {/* Fast, minimal agent */}
      <ChatProvider
        agentId="quick-helper"
        authConfig={quickAuth}
        typingAnimation={{ mode: 'instant' }}
        enableHistory={false}
      >
        <QuickHelp />
      </ChatProvider>

      {/* Detailed, animated agent */}
      <ChatProvider
        agentId="detailed-writer"
        authConfig={writerAuth}
        typingAnimation={{ mode: 'char', speed: 50 }}
        enableHistory={true}
      >
        <DetailedWriter />
      </ChatProvider>

      {/* Code agent with custom components */}
      <ChatProvider
        agentId="code-agent"
        authConfig={codeAuth}
        statusComponents={{
          tool_call: CodeToolStatus,
          edit_file: FileEditStatus
        }}
      >
        <CodeWorkspace />
      </ChatProvider>
    </>
  );
}

Layout Patterns

Side-by-Side

<div className="flex gap-4">
  <ChatProvider agentId="agent-1" authConfig={auth1}>
    <div className="w-1/2"><ChatPanel /></div>
  </ChatProvider>
  <ChatProvider agentId="agent-2" authConfig={auth2}>
    <div className="w-1/2"><ChatPanel /></div>
  </ChatProvider>
</div>

Tabbed Interface

function TabbedAgents() {
  const [activeTab, setActiveTab] = useState('code');

  return (
    <div>
      <Tabs value={activeTab} onValueChange={setActiveTab}>
        <TabsList>
          <TabsTrigger value="code">Code Agent</TabsTrigger>
          <TabsTrigger value="design">Design Agent</TabsTrigger>
          <TabsTrigger value="test">Test Agent</TabsTrigger>
        </TabsList>

        <TabsContent value="code">
          <ChatProvider agentId="code" authConfig={codeAuth}>
            <ChatPanel />
          </ChatProvider>
        </TabsContent>

        <TabsContent value="design">
          <ChatProvider agentId="design" authConfig={designAuth}>
            <ChatPanel />
          </ChatProvider>
        </TabsContent>

        <TabsContent value="test">
          <ChatProvider agentId="test" authConfig={testAuth}>
            <ChatPanel />
          </ChatProvider>
        </TabsContent>
      </Tabs>
    </div>
  );
}

Modal/Overlay

function ModalAgent() {
  const [showAgent, setShowAgent] = useState(false);

  return (
    <>
      <button onClick={() => setShowAgent(true)}>
        Ask Code Agent
      </button>

      {showAgent && (
        <Modal onClose={() => setShowAgent(false)}>
          <ChatProvider agentId="modal-agent" authConfig={agentAuth}>
            <ChatPanel />
          </ChatProvider>
        </Modal>
      )}
    </>
  );
}

Grid Layout

<div className="grid grid-cols-2 grid-rows-2 gap-4 h-screen">
  <ChatProvider agentId="agent-1" authConfig={auth1}>
    <ChatPanel />
  </ChatProvider>
  <ChatProvider agentId="agent-2" authConfig={auth2}>
    <ChatPanel />
  </ChatProvider>
  <ChatProvider agentId="agent-3" authConfig={auth3}>
    <ChatPanel />
  </ChatProvider>
  <ChatProvider agentId="agent-4" authConfig={auth4}>
    <ChatPanel />
  </ChatProvider>
</div>

Performance Considerations

Lazy Loading

function LazyAgents() {
  return (
    <Suspense fallback={<Loading />}>
      <LazyCodeAgent />
      <LazyDesignAgent />
      <LazyTestAgent />
    </Suspense>
  );
}

const LazyCodeAgent = lazy(() => import('./agents/CodeAgent'));
const LazyDesignAgent = lazy(() => import('./agents/DesignAgent'));
const LazyTestAgent = lazy(() => import('./agents/TestAgent'));

Memory Management

function ManagedAgents() {
  const [agents, setAgents] = useState(new Map());

  // Clean up inactive agents
  useEffect(() => {
    const interval = setInterval(() => {
      const now = Date.now();
      setAgents(prev => {
        const active = new Map();
        prev.forEach((agent, id) => {
          if (now - agent.lastActivity < 300000) { // 5 min
            active.set(id, agent);
          }
        });
        return active;
      });
    }, 60000); // Check every minute

    return () => clearInterval(interval);
  }, []);

  return <div>{/* Render active agents */}</div>;
}

Error Handling

Handle errors per agent:

<ChatProvider
  agentId="code-agent"
  authConfig={codeAuth}
  onError={(error) => {
    console.error('Code agent error:', error);
    notifyUser('Code agent encountered an issue');
  }}
>
  <CodePanel />
</ChatProvider>

<ChatProvider
  agentId="design-agent"
  authConfig={designAuth}
  onError={(error) => {
    console.error('Design agent error:', error);
    notifyUser('Design agent encountered an issue');
  }}
>
  <DesignPanel />
</ChatProvider>

Best Practices

Agent Naming

// ✅ Descriptive, unique IDs
agentId="code-writer-typescript"
agentId="ui-designer-react"
agentId="api-tester-backend"

// ❌ Generic IDs
agentId="agent1"
agentId="agent2"

State Management

// ✅ Centralized state for agent communication
const [appState, setAppState] = useState({
  code: '',
  design: '',
  tests: ''
});

// Pass to agents as needed
<CodeAgent state={appState} onUpdate={setAppState} />

Resource Limits

// ✅ Limit concurrent agents
const MAX_AGENTS = 5;

function addAgent(type) {
  if (activeAgents.size >= MAX_AGENTS) {
    alert('Maximum agents reached');
    return;
  }
  // Add agent...
}

TypeScript Support

interface AgentConfig {
  id: string;
  type: 'code' | 'design' | 'test';
  auth: AuthConfig;
}

const agents: AgentConfig[] = [
  { id: 'coder', type: 'code', auth: codeAuth },
  { id: 'designer', type: 'design', auth: designAuth },
  { id: 'tester', type: 'test', auth: testAuth }
];

Next Steps