@octavus/docs 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/content/01-getting-started/02-quickstart.md +4 -3
  2. package/content/02-server-sdk/01-overview.md +11 -5
  3. package/content/02-server-sdk/02-sessions.md +6 -3
  4. package/content/02-server-sdk/03-tools.md +4 -2
  5. package/content/02-server-sdk/04-streaming.md +12 -4
  6. package/content/03-client-sdk/01-overview.md +11 -5
  7. package/content/03-client-sdk/05-socket-transport.md +263 -153
  8. package/content/03-client-sdk/06-http-transport.md +280 -0
  9. package/content/04-protocol/03-triggers.md +10 -2
  10. package/content/05-api-reference/01-overview.md +3 -17
  11. package/content/06-examples/01-overview.md +27 -0
  12. package/content/06-examples/02-nextjs-chat.md +343 -0
  13. package/content/06-examples/03-socket-chat.md +392 -0
  14. package/content/06-examples/_meta.md +5 -0
  15. package/dist/chunk-5M7DS4DF.js +519 -0
  16. package/dist/chunk-5M7DS4DF.js.map +1 -0
  17. package/dist/chunk-H6JGSSAJ.js +519 -0
  18. package/dist/chunk-H6JGSSAJ.js.map +1 -0
  19. package/dist/chunk-JZRABTHU.js +519 -0
  20. package/dist/chunk-JZRABTHU.js.map +1 -0
  21. package/dist/chunk-OL5QDJ42.js +483 -0
  22. package/dist/chunk-OL5QDJ42.js.map +1 -0
  23. package/dist/chunk-PMOVVTHO.js +519 -0
  24. package/dist/chunk-PMOVVTHO.js.map +1 -0
  25. package/dist/chunk-R5MTVABN.js +439 -0
  26. package/dist/chunk-R5MTVABN.js.map +1 -0
  27. package/dist/chunk-RJ4H4YVA.js +519 -0
  28. package/dist/chunk-RJ4H4YVA.js.map +1 -0
  29. package/dist/chunk-S5U4IWCR.js +439 -0
  30. package/dist/chunk-S5U4IWCR.js.map +1 -0
  31. package/dist/chunk-UCJE36LL.js +519 -0
  32. package/dist/chunk-UCJE36LL.js.map +1 -0
  33. package/dist/chunk-WW7TRC7S.js +519 -0
  34. package/dist/chunk-WW7TRC7S.js.map +1 -0
  35. package/dist/content.js +1 -1
  36. package/dist/docs.json +46 -10
  37. package/dist/index.js +1 -1
  38. package/dist/search-index.json +1 -1
  39. package/dist/search.js +1 -1
  40. package/dist/search.js.map +1 -1
  41. package/dist/sections.json +54 -10
  42. package/package.json +1 -1
package/dist/content.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  getDocSlugs,
6
6
  getDocsData,
7
7
  getSectionBySlug
8
- } from "./chunk-232K4EME.js";
8
+ } from "./chunk-H6JGSSAJ.js";
9
9
  export {
10
10
  getAllDocs,
11
11
  getDocBySlug,
package/dist/docs.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "section": "getting-started",
14
14
  "title": "Quick Start",
15
15
  "description": "Get your first Octavus agent running in minutes.",
16
- "content": "\n# Quick Start\n\nThis guide will walk you through integrating Octavus into your application in under 10 minutes.\n\n## Prerequisites\n\n- Node.js 18+\n- An Octavus account with API key\n- A Next.js application (or any Node.js backend)\n\n## Installation\n\nInstall the Octavus SDKs in your project:\n\n```bash\n# Server SDK for backend\nnpm install @octavus/server-sdk\n\n# React bindings for frontend\nnpm install @octavus/react\n```\n\n## Backend Setup\n\n### 1. Initialize the Client\n\nCreate an Octavus client instance in your backend:\n\n```typescript\n// lib/octavus.ts\nimport { OctavusClient } from '@octavus/server-sdk';\n\nexport const octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n```\n\n### 2. Create a Session Endpoint\n\nCreate an API endpoint that creates sessions and returns the session ID:\n\n```typescript\n// app/api/chat/create/route.ts\nimport { NextResponse } from 'next/server';\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { agentSlug, input } = await request.json();\n\n // Look up agent by slug to get its ID\n const agent = await octavus.agents.getBySlug(agentSlug);\n if (!agent) {\n return NextResponse.json({ error: 'Agent not found' }, { status: 404 });\n }\n\n // Create a new session using the agent ID\n const sessionId = await octavus.agentSessions.create(agent.id, input);\n\n return NextResponse.json({ sessionId });\n}\n```\n\n### 3. Create a Trigger Endpoint\n\nCreate an endpoint that handles triggers and streams responses:\n\n```typescript\n// app/api/trigger/route.ts\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { sessionId, triggerName, input } = await request.json();\n\n // Attach to session with tool handlers\n const session = octavus.agentSessions.attach(sessionId, {\n tools: {\n // Define tool handlers that run on your server\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n // Fetch from your database\n return {\n name: 'Demo User',\n email: 'demo@example.com',\n plan: 'pro',\n };\n },\n 'create-support-ticket': async (args) => {\n // Create ticket in your system\n return {\n ticketId: 'TICKET-123',\n estimatedResponse: '24 hours',\n };\n },\n },\n });\n\n // Trigger the action and get the stream\n const { stream } = session.trigger(triggerName, input);\n\n // Return as streaming response\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n```\n\n## Frontend Setup\n\n### 1. Create a Chat Component\n\nUse the `useOctavusChat` hook with the HTTP transport:\n\n```tsx\n// components/chat.tsx\n'use client';\n\nimport { useState, useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';\n\ninterface ChatProps {\n sessionId: string;\n}\n\nexport function Chat({ sessionId }: ChatProps) {\n const [inputValue, setInputValue] = useState('');\n\n // Create a stable transport instance\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, error, send } = useOctavusChat({ transport });\n\n const isStreaming = status === 'streaming';\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || isStreaming) return;\n\n const message = inputValue.trim();\n setInputValue('');\n\n // Add user message and trigger in one call\n await send(\n 'user-message',\n { USER_MESSAGE: message },\n { userMessage: { content: message } },\n );\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n </div>\n\n {/* Input */}\n <form onSubmit={handleSubmit} className=\"p-4 border-t\">\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n placeholder=\"Type a message...\"\n className=\"flex-1 px-4 py-2 border rounded-lg\"\n disabled={isStreaming}\n />\n <button\n type=\"submit\"\n disabled={isStreaming}\n className=\"px-4 py-2 bg-blue-500 text-white rounded-lg disabled:opacity-50\"\n >\n Send\n </button>\n </div>\n </form>\n </div>\n );\n}\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n const isUser = message.role === 'user';\n\n return (\n <div className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}>\n <div\n className={`p-3 rounded-lg max-w-md ${\n isUser ? 'bg-blue-500 text-white' : 'bg-gray-100'\n }`}\n >\n {message.parts.map((part, i) => {\n if (part.type === 'text') {\n return <p key={i}>{part.text}</p>;\n }\n return null;\n })}\n\n {/* Streaming indicator */}\n {message.status === 'streaming' && (\n <span className=\"inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1\" />\n )}\n </div>\n </div>\n );\n}\n```\n\n### 2. Create Session and Render Chat\n\n```tsx\n// app/chat/page.tsx\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Chat } from '@/components/chat';\n\nexport default function ChatPage() {\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n useEffect(() => {\n async function createSession() {\n const response = await fetch('/api/chat/create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n agentSlug: 'support-chat',\n input: {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n },\n }),\n });\n const { sessionId } = await response.json();\n setSessionId(sessionId);\n }\n\n createSession();\n }, []);\n\n if (!sessionId) {\n return <div>Loading...</div>;\n }\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\n## Environment Variables\n\nAdd these to your `.env.local`:\n\n```bash\nOCTAVUS_API_URL=https://octavus.ai\nOCTAVUS_API_KEY=your-api-key-here\n```\n\n## What's Next?\n\nNow that you have a basic integration working:\n\n- [Learn about the protocol](/docs/protocol/overview) to define custom agent behavior\n- [Explore the Server SDK](/docs/server-sdk/overview) for advanced backend features\n- [Build rich UIs](/docs/client-sdk/overview) with the Client SDK\n",
16
+ "content": "\n# Quick Start\n\nThis guide will walk you through integrating Octavus into your application in under 10 minutes.\n\n## Prerequisites\n\n- Node.js 18+\n- An Octavus account with API key\n- A Next.js application (or any Node.js backend)\n\n## Installation\n\nInstall the Octavus SDKs in your project:\n\n```bash\n# Server SDK for backend\nnpm install @octavus/server-sdk\n\n# React bindings for frontend\nnpm install @octavus/react\n```\n\n## Backend Setup\n\n### 1. Initialize the Client\n\nCreate an Octavus client instance in your backend:\n\n```typescript\n// lib/octavus.ts\nimport { OctavusClient } from '@octavus/server-sdk';\n\nexport const octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n```\n\n### 2. Create a Session Endpoint\n\nCreate an API endpoint that creates sessions and returns the session ID:\n\n```typescript\n// app/api/chat/create/route.ts\nimport { NextResponse } from 'next/server';\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { agentSlug, input } = await request.json();\n\n // Look up agent by slug to get its ID\n const agent = await octavus.agents.getBySlug(agentSlug);\n if (!agent) {\n return NextResponse.json({ error: 'Agent not found' }, { status: 404 });\n }\n\n // Create a new session using the agent ID\n const sessionId = await octavus.agentSessions.create(agent.id, input);\n\n return NextResponse.json({ sessionId });\n}\n```\n\n### 3. Create a Trigger Endpoint\n\nCreate an endpoint that handles triggers and streams responses:\n\n```typescript\n// app/api/trigger/route.ts\nimport { toSSEStream } from '@octavus/server-sdk';\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { sessionId, triggerName, input } = await request.json();\n\n // Attach to session with tool handlers\n const session = octavus.agentSessions.attach(sessionId, {\n tools: {\n // Define tool handlers that run on your server\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n // Fetch from your database\n return {\n name: 'Demo User',\n email: 'demo@example.com',\n plan: 'pro',\n };\n },\n 'create-support-ticket': async (args) => {\n // Create ticket in your system\n return {\n ticketId: 'TICKET-123',\n estimatedResponse: '24 hours',\n };\n },\n },\n });\n\n // Trigger the action and convert to SSE stream\n const events = session.trigger(triggerName, input);\n\n // Return as streaming response\n return new Response(toSSEStream(events), {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n```\n\n## Frontend Setup\n\n### 1. Create a Chat Component\n\nUse the `useOctavusChat` hook with the HTTP transport:\n\n```tsx\n// components/chat.tsx\n'use client';\n\nimport { useState, useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';\n\ninterface ChatProps {\n sessionId: string;\n}\n\nexport function Chat({ sessionId }: ChatProps) {\n const [inputValue, setInputValue] = useState('');\n\n // Create a stable transport instance\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, error, send } = useOctavusChat({ transport });\n\n const isStreaming = status === 'streaming';\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || isStreaming) return;\n\n const message = inputValue.trim();\n setInputValue('');\n\n // Add user message and trigger in one call\n await send(\n 'user-message',\n { USER_MESSAGE: message },\n { userMessage: { content: message } },\n );\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n </div>\n\n {/* Input */}\n <form onSubmit={handleSubmit} className=\"p-4 border-t\">\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n placeholder=\"Type a message...\"\n className=\"flex-1 px-4 py-2 border rounded-lg\"\n disabled={isStreaming}\n />\n <button\n type=\"submit\"\n disabled={isStreaming}\n className=\"px-4 py-2 bg-blue-500 text-white rounded-lg disabled:opacity-50\"\n >\n Send\n </button>\n </div>\n </form>\n </div>\n );\n}\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n const isUser = message.role === 'user';\n\n return (\n <div className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}>\n <div\n className={`p-3 rounded-lg max-w-md ${\n isUser ? 'bg-blue-500 text-white' : 'bg-gray-100'\n }`}\n >\n {message.parts.map((part, i) => {\n if (part.type === 'text') {\n return <p key={i}>{part.text}</p>;\n }\n return null;\n })}\n\n {/* Streaming indicator */}\n {message.status === 'streaming' && (\n <span className=\"inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1\" />\n )}\n </div>\n </div>\n );\n}\n```\n\n### 2. Create Session and Render Chat\n\n```tsx\n// app/chat/page.tsx\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Chat } from '@/components/chat';\n\nexport default function ChatPage() {\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n useEffect(() => {\n async function createSession() {\n const response = await fetch('/api/chat/create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n agentSlug: 'support-chat',\n input: {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n },\n }),\n });\n const { sessionId } = await response.json();\n setSessionId(sessionId);\n }\n\n createSession();\n }, []);\n\n if (!sessionId) {\n return <div>Loading...</div>;\n }\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\n## Environment Variables\n\nAdd these to your `.env.local`:\n\n```bash\nOCTAVUS_API_URL=https://octavus.ai\nOCTAVUS_API_KEY=your-api-key-here\n```\n\n## What's Next?\n\nNow that you have a basic integration working:\n\n- [Learn about the protocol](/docs/protocol/overview) to define custom agent behavior\n- [Explore the Server SDK](/docs/server-sdk/overview) for advanced backend features\n- [Build rich UIs](/docs/client-sdk/overview) with the Client SDK\n",
17
17
  "excerpt": "Quick Start This guide will walk you through integrating Octavus into your application in under 10 minutes. Prerequisites - Node.js 18+ - An Octavus account with API key - A Next.js application (or...",
18
18
  "order": 2
19
19
  },
@@ -22,7 +22,7 @@
22
22
  "section": "server-sdk",
23
23
  "title": "Overview",
24
24
  "description": "Introduction to the Octavus Server SDK for backend integration.",
25
- "content": "\n# Server SDK Overview\n\nThe `@octavus/server-sdk` package provides a Node.js SDK for integrating Octavus agents into your backend application. It handles session management, streaming, and the tool execution continuation loop.\n\n**Current version:** `0.0.7`\n\n## Installation\n\n```bash\nnpm install @octavus/server-sdk\n```\n\n## Basic Usage\n\n```typescript\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: 'https://octavus.ai',\n apiKey: 'your-api-key',\n});\n```\n\n## Key Features\n\n### Session Management\n\nCreate and manage agent sessions:\n\n```typescript\n// Create a new session\nconst sessionId = await client.agentSessions.create('agent-id', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n});\n\n// Get UI-ready session messages (for session restore)\nconst session = await client.agentSessions.getMessages(sessionId);\n```\n\n### Tool Handlers\n\nTools run on your server with your data:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Access your database, APIs, etc.\n return await db.users.findById(args.userId);\n },\n },\n});\n```\n\n### Streaming\n\nAll responses stream in real-time:\n\n```typescript\nconst { stream } = session.trigger('user-message', {\n USER_MESSAGE: 'Hello!',\n});\n\n// Use as a streaming response\nreturn new Response(stream, {\n headers: { 'Content-Type': 'text/event-stream' },\n});\n```\n\n## API Reference\n\n### OctavusClient\n\nThe main entry point for interacting with Octavus.\n\n```typescript\ninterface OctavusClientConfig {\n baseUrl: string; // Octavus API URL\n apiKey?: string; // Your API key\n}\n\nclass OctavusClient {\n readonly agents: AgentsApi;\n readonly agentSessions: AgentSessionsApi;\n\n constructor(config: OctavusClientConfig);\n}\n```\n\n### AgentSessionsApi\n\nManages agent sessions.\n\n```typescript\nclass AgentSessionsApi {\n // Create a new session\n async create(agentId: string, input?: Record<string, unknown>): Promise<string>;\n\n // Get full session state (for debugging/internal use)\n async get(sessionId: string): Promise<SessionState>;\n\n // Get UI-ready messages (for client display)\n async getMessages(sessionId: string): Promise<UISessionState>;\n\n // Attach to a session for triggering\n attach(sessionId: string, options?: SessionAttachOptions): AgentSession;\n}\n\n// Full session state (internal format)\ninterface SessionState {\n id: string;\n agentId: string;\n input: Record<string, unknown>;\n variables: Record<string, unknown>;\n resources: Record<string, unknown>;\n messages: ChatMessage[]; // Internal message format\n createdAt: string;\n updatedAt: string;\n}\n\n// UI-ready session state\ninterface UISessionState {\n sessionId: string;\n agentId: string;\n messages: UIMessage[]; // UI-ready messages for frontend\n}\n```\n\n### AgentSession\n\nHandles triggering and streaming for a specific session.\n\n```typescript\nclass AgentSession {\n // Trigger an action and stream the response\n trigger(\n triggerName: string,\n input?: Record<string, unknown>\n ): { stream: ReadableStream<Uint8Array> };\n\n // Get the session ID\n getSessionId(): string;\n}\n```\n\n## Next Steps\n\n- [Sessions](/docs/server-sdk/sessions) — Deep dive into session management\n- [Tools](/docs/server-sdk/tools) — Implementing tool handlers\n- [Streaming](/docs/server-sdk/streaming) — Understanding stream events\n",
25
+ "content": "\n# Server SDK Overview\n\nThe `@octavus/server-sdk` package provides a Node.js SDK for integrating Octavus agents into your backend application. It handles session management, streaming, and the tool execution continuation loop.\n\n**Current version:** `0.0.8`\n\n## Installation\n\n```bash\nnpm install @octavus/server-sdk\n```\n\n## Basic Usage\n\n```typescript\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: 'https://octavus.ai',\n apiKey: 'your-api-key',\n});\n```\n\n## Key Features\n\n### Session Management\n\nCreate and manage agent sessions:\n\n```typescript\n// Create a new session\nconst sessionId = await client.agentSessions.create('agent-id', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n});\n\n// Get UI-ready session messages (for session restore)\nconst session = await client.agentSessions.getMessages(sessionId);\n```\n\n### Tool Handlers\n\nTools run on your server with your data:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Access your database, APIs, etc.\n return await db.users.findById(args.userId);\n },\n },\n});\n```\n\n### Streaming\n\nAll responses stream in real-time:\n\n```typescript\nimport { toSSEStream } from '@octavus/server-sdk';\n\n// trigger() returns an async generator of events\nconst events = session.trigger('user-message', {\n USER_MESSAGE: 'Hello!',\n});\n\n// Convert to SSE stream for HTTP responses\nreturn new Response(toSSEStream(events), {\n headers: { 'Content-Type': 'text/event-stream' },\n});\n```\n\n## API Reference\n\n### OctavusClient\n\nThe main entry point for interacting with Octavus.\n\n```typescript\ninterface OctavusClientConfig {\n baseUrl: string; // Octavus API URL\n apiKey?: string; // Your API key\n}\n\nclass OctavusClient {\n readonly agents: AgentsApi;\n readonly agentSessions: AgentSessionsApi;\n\n constructor(config: OctavusClientConfig);\n}\n```\n\n### AgentSessionsApi\n\nManages agent sessions.\n\n```typescript\nclass AgentSessionsApi {\n // Create a new session\n async create(agentId: string, input?: Record<string, unknown>): Promise<string>;\n\n // Get full session state (for debugging/internal use)\n async get(sessionId: string): Promise<SessionState>;\n\n // Get UI-ready messages (for client display)\n async getMessages(sessionId: string): Promise<UISessionState>;\n\n // Attach to a session for triggering\n attach(sessionId: string, options?: SessionAttachOptions): AgentSession;\n}\n\n// Full session state (internal format)\ninterface SessionState {\n id: string;\n agentId: string;\n input: Record<string, unknown>;\n variables: Record<string, unknown>;\n resources: Record<string, unknown>;\n messages: ChatMessage[]; // Internal message format\n createdAt: string;\n updatedAt: string;\n}\n\n// UI-ready session state\ninterface UISessionState {\n sessionId: string;\n agentId: string;\n messages: UIMessage[]; // UI-ready messages for frontend\n}\n```\n\n### AgentSession\n\nHandles triggering and streaming for a specific session.\n\n```typescript\nclass AgentSession {\n // Trigger an action and stream parsed events\n trigger(\n triggerName: string,\n input?: Record<string, unknown>\n ): AsyncGenerator<StreamEvent>;\n\n // Get the session ID\n getSessionId(): string;\n}\n\n// Helper to convert events to SSE stream\nfunction toSSEStream(events: AsyncIterable<StreamEvent>): ReadableStream<Uint8Array>;\n```\n\n## Next Steps\n\n- [Sessions](/docs/server-sdk/sessions) — Deep dive into session management\n- [Tools](/docs/server-sdk/tools) — Implementing tool handlers\n- [Streaming](/docs/server-sdk/streaming) — Understanding stream events\n",
26
26
  "excerpt": "Server SDK Overview The package provides a Node.js SDK for integrating Octavus agents into your backend application. It handles session management, streaming, and the tool execution continuation...",
27
27
  "order": 1
28
28
  },
@@ -31,7 +31,7 @@
31
31
  "section": "server-sdk",
32
32
  "title": "Sessions",
33
33
  "description": "Managing agent sessions with the Server SDK.",
34
- "content": "\n# Sessions\n\nSessions represent conversations with an agent. They store conversation history, track resources and variables, and enable stateful interactions.\n\n## Creating Sessions\n\nCreate a session by specifying the agent ID and initial input variables:\n\n```typescript\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\n// Create a session with the support-chat agent\nconst sessionId = await client.agentSessions.create('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n USER_ID: 'user-123', // Optional inputs\n});\n\nconsole.log('Session created:', sessionId);\n```\n\n## Getting Session Messages\n\nTo restore a conversation on page load, use `getMessages()` to retrieve UI-ready messages:\n\n```typescript\nconst session = await client.agentSessions.getMessages(sessionId);\n\nconsole.log({\n sessionId: session.sessionId,\n agentId: session.agentId,\n messages: session.messages.length, // UIMessage[] ready for frontend\n});\n```\n\nThe returned messages can be passed directly to the client SDK's `initialMessages` option.\n\n### UISessionState Interface\n\n```typescript\ninterface UISessionState {\n sessionId: string;\n agentId: string;\n messages: UIMessage[]; // UI-ready conversation history\n}\n```\n\n## Full Session State (Debug)\n\nFor debugging or internal use, you can retrieve the complete session state including all variables and internal message format:\n\n```typescript\nconst state = await client.agentSessions.get(sessionId);\n\nconsole.log({\n id: state.id,\n agentId: state.agentId,\n messages: state.messages.length, // ChatMessage[] (internal format)\n resources: state.resources,\n variables: state.variables,\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n});\n```\n\n> **Note**: Use `getMessages()` for client-facing code. The `get()` method returns internal message format that includes hidden content not intended for end users.\n\n## Attaching to Sessions\n\nTo trigger actions on a session, you need to attach to it first:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n // Tool handlers (see Tools documentation)\n },\n resources: [\n // Resource watchers (optional)\n ],\n});\n```\n\n## Triggering Actions\n\nOnce attached, trigger actions on the session:\n\n```typescript\nconst { stream } = session.trigger('user-message', {\n USER_MESSAGE: 'How do I reset my password?',\n});\n\n// Return the stream to your frontend\nreturn new Response(stream, {\n headers: { 'Content-Type': 'text/event-stream' },\n});\n```\n\n## Session Lifecycle\n\n```mermaid\nflowchart TD\n A[1. CREATE] --> B[2. ATTACH]\n B --> C[3. TRIGGER]\n C --> C\n C --> D[4. RETRIEVE]\n D --> C\n C --> E[5. EXPIRE]\n\n A -.- A1[\"`**client.agentSessions.create()**\n Returns sessionId\n Initializes state`\"]\n \n B -.- B1[\"`**client.agentSessions.attach()**\n Configure tool handlers\n Configure resource watchers`\"]\n \n C -.- C1[\"`**session.trigger()**\n Execute handler\n Stream events\n Update state`\"]\n \n D -.- D1[\"`**client.agentSessions.getMessages()**\n Get UI-ready messages\n Restore conversation`\"]\n \n E -.- E1[\"`Sessions expire after\n 24 hours (configurable)`\"]\n```\n\n## Restoring Sessions\n\nWhen a user returns to your app, restore their session:\n\n```typescript\n// On page load\nconst session = await client.agentSessions.getMessages(sessionId);\n\n// Pass messages to frontend - they're already UI-ready\nreturn {\n sessionId: session.sessionId,\n messages: session.messages, // UIMessage[] with parts\n};\n```\n\nThe `messages` array contains `UIMessage` objects with properly structured `parts`, enabling direct use with the client SDK's `initialMessages` option.\n\n## Error Handling\n\n```typescript\nimport { ApiError } from '@octavus/server-sdk';\n\ntry {\n const session = await client.agentSessions.getMessages(sessionId);\n} catch (error) {\n if (error instanceof ApiError) {\n if (error.status === 404) {\n // Session not found or expired\n console.log('Session expired, create a new one');\n } else {\n console.error('API Error:', error.message);\n }\n }\n throw error;\n}\n```\n",
34
+ "content": "\n# Sessions\n\nSessions represent conversations with an agent. They store conversation history, track resources and variables, and enable stateful interactions.\n\n## Creating Sessions\n\nCreate a session by specifying the agent ID and initial input variables:\n\n```typescript\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\n// Create a session with the support-chat agent\nconst sessionId = await client.agentSessions.create('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n USER_ID: 'user-123', // Optional inputs\n});\n\nconsole.log('Session created:', sessionId);\n```\n\n## Getting Session Messages\n\nTo restore a conversation on page load, use `getMessages()` to retrieve UI-ready messages:\n\n```typescript\nconst session = await client.agentSessions.getMessages(sessionId);\n\nconsole.log({\n sessionId: session.sessionId,\n agentId: session.agentId,\n messages: session.messages.length, // UIMessage[] ready for frontend\n});\n```\n\nThe returned messages can be passed directly to the client SDK's `initialMessages` option.\n\n### UISessionState Interface\n\n```typescript\ninterface UISessionState {\n sessionId: string;\n agentId: string;\n messages: UIMessage[]; // UI-ready conversation history\n}\n```\n\n## Full Session State (Debug)\n\nFor debugging or internal use, you can retrieve the complete session state including all variables and internal message format:\n\n```typescript\nconst state = await client.agentSessions.get(sessionId);\n\nconsole.log({\n id: state.id,\n agentId: state.agentId,\n messages: state.messages.length, // ChatMessage[] (internal format)\n resources: state.resources,\n variables: state.variables,\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n});\n```\n\n> **Note**: Use `getMessages()` for client-facing code. The `get()` method returns internal message format that includes hidden content not intended for end users.\n\n## Attaching to Sessions\n\nTo trigger actions on a session, you need to attach to it first:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n // Tool handlers (see Tools documentation)\n },\n resources: [\n // Resource watchers (optional)\n ],\n});\n```\n\n## Triggering Actions\n\nOnce attached, trigger actions on the session:\n\n```typescript\nimport { toSSEStream } from '@octavus/server-sdk';\n\n// trigger() returns an async generator of events\nconst events = session.trigger('user-message', {\n USER_MESSAGE: 'How do I reset my password?',\n});\n\n// Convert to SSE stream for HTTP responses\nreturn new Response(toSSEStream(events), {\n headers: { 'Content-Type': 'text/event-stream' },\n});\n```\n\n## Session Lifecycle\n\n```mermaid\nflowchart TD\n A[1. CREATE] --> B[2. ATTACH]\n B --> C[3. TRIGGER]\n C --> C\n C --> D[4. RETRIEVE]\n D --> C\n C --> E[5. EXPIRE]\n\n A -.- A1[\"`**client.agentSessions.create()**\n Returns sessionId\n Initializes state`\"]\n \n B -.- B1[\"`**client.agentSessions.attach()**\n Configure tool handlers\n Configure resource watchers`\"]\n \n C -.- C1[\"`**session.trigger()**\n Execute handler\n Stream events\n Update state`\"]\n \n D -.- D1[\"`**client.agentSessions.getMessages()**\n Get UI-ready messages\n Restore conversation`\"]\n \n E -.- E1[\"`Sessions expire after\n 24 hours (configurable)`\"]\n```\n\n## Restoring Sessions\n\nWhen a user returns to your app, restore their session:\n\n```typescript\n// On page load\nconst session = await client.agentSessions.getMessages(sessionId);\n\n// Pass messages to frontend - they're already UI-ready\nreturn {\n sessionId: session.sessionId,\n messages: session.messages, // UIMessage[] with parts\n};\n```\n\nThe `messages` array contains `UIMessage` objects with properly structured `parts`, enabling direct use with the client SDK's `initialMessages` option.\n\n## Error Handling\n\n```typescript\nimport { ApiError } from '@octavus/server-sdk';\n\ntry {\n const session = await client.agentSessions.getMessages(sessionId);\n} catch (error) {\n if (error instanceof ApiError) {\n if (error.status === 404) {\n // Session not found or expired\n console.log('Session expired, create a new one');\n } else {\n console.error('API Error:', error.message);\n }\n }\n throw error;\n}\n```\n",
35
35
  "excerpt": "Sessions Sessions represent conversations with an agent. They store conversation history, track resources and variables, and enable stateful interactions. Creating Sessions Create a session by...",
36
36
  "order": 2
37
37
  },
@@ -40,7 +40,7 @@
40
40
  "section": "server-sdk",
41
41
  "title": "Tools",
42
42
  "description": "Implementing tool handlers with the Server SDK.",
43
- "content": "\n# Tools\n\nTools extend what agents can do. In Octavus, tools execute on your server, giving you full control over data access and authentication.\n\n## Why Tools Run on Your Server\n\nUnlike traditional AI platforms where tools run in a sandbox, Octavus tools execute in your backend:\n\n- ✅ **Full data access** — Query your database directly\n- ✅ **Your authentication** — Use your existing auth context\n- ✅ **No data exposure** — Sensitive data never leaves your infrastructure\n- ✅ **Custom logic** — Any complexity you need\n\n## Defining Tool Handlers\n\nTool handlers are async functions that receive arguments and return results:\n\n```typescript\nimport type { ToolHandlers } from '@octavus/server-sdk';\n\nconst tools: ToolHandlers = {\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n \n // Query your database\n const user = await db.users.findById(userId);\n \n return {\n name: user.name,\n email: user.email,\n plan: user.subscription.plan,\n createdAt: user.createdAt.toISOString(),\n };\n },\n \n 'create-support-ticket': async (args) => {\n const summary = args.summary as string;\n const priority = args.priority as string;\n \n // Create ticket in your system\n const ticket = await ticketService.create({\n summary,\n priority,\n source: 'ai-chat',\n });\n \n return {\n ticketId: ticket.id,\n estimatedResponse: getEstimatedResponse(priority),\n };\n },\n};\n```\n\n## Using Tools in Sessions\n\nPass tool handlers when attaching to a session:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Implementation\n },\n 'create-support-ticket': async (args) => {\n // Implementation\n },\n },\n});\n```\n\n## Tool Handler Signature\n\n```typescript\ntype ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\ntype ToolHandlers = Record<string, ToolHandler>;\n```\n\n### Arguments\n\nArguments are passed as a `Record<string, unknown>`. Type-check as needed:\n\n```typescript\n'search-products': async (args) => {\n const query = args.query as string;\n const category = args.category as string | undefined;\n const maxPrice = args.maxPrice as number | undefined;\n \n return await productSearch({ query, category, maxPrice });\n}\n```\n\n### Return Values\n\nReturn any JSON-serializable value. The result is:\n1. Sent back to the LLM as context\n2. Stored in session state\n3. Optionally stored in a variable for protocol use\n\n```typescript\n// Return object\nreturn { id: '123', status: 'created' };\n\n// Return array\nreturn [{ id: '1' }, { id: '2' }];\n\n// Return primitive\nreturn 42;\n\n// Return null for \"no result\"\nreturn null;\n```\n\n## Error Handling\n\nThrow errors for failures. They're captured and sent to the LLM:\n\n```typescript\n'get-user-account': async (args) => {\n const userId = args.userId as string;\n \n const user = await db.users.findById(userId);\n \n if (!user) {\n throw new Error(`User not found: ${userId}`);\n }\n \n return user;\n}\n```\n\nThe LLM receives the error message and can respond appropriately (e.g., \"I couldn't find that account\").\n\n## Tool Execution Flow\n\nWhen the LLM calls a tool:\n\n```mermaid\nsequenceDiagram\n participant LLM\n participant Platform as Octavus Platform\n participant SDK as Server SDK\n participant UI as Your Frontend\n\n LLM->>Platform: 1. Decides to call tool\n Platform-->>UI: tool-input-start, tool-input-delta\n Platform-->>UI: tool-input-available\n Platform-->>SDK: 2. tool-request (stream pauses)\n \n Note over SDK: 3. Execute handler<br/>tools['get-user']()\n \n SDK-->>UI: 4. tool-output-available\n SDK->>Platform: 5. POST /trigger with results\n Platform->>LLM: 6. Continue with results\n LLM-->>Platform: Response\n Platform-->>UI: text-delta events\n \n Note over LLM,UI: 7. Repeat if more tools needed\n```\n\n## Accessing Request Context\n\nFor request-specific data (auth, headers), create handlers dynamically:\n\n```typescript\n// In your API route\nexport async function POST(request: Request) {\n const authToken = request.headers.get('Authorization');\n const user = await validateToken(authToken);\n \n const session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Use request context\n return await db.users.findById(user.id);\n },\n 'create-order': async (args) => {\n // Create with user context\n return await orderService.create({\n ...args,\n userId: user.id,\n createdBy: user.email,\n });\n },\n },\n });\n \n const { stream } = session.trigger(triggerName, input);\n return new Response(stream);\n}\n```\n\n## Best Practices\n\n### 1. Validate Arguments\n\n```typescript\n'create-ticket': async (args) => {\n const summary = args.summary;\n if (typeof summary !== 'string' || summary.length === 0) {\n throw new Error('Summary is required');\n }\n // ...\n}\n```\n\n### 2. Handle Timeouts\n\n```typescript\n'external-api-call': async (args) => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10000);\n \n try {\n const response = await fetch(url, { signal: controller.signal });\n return await response.json();\n } finally {\n clearTimeout(timeout);\n }\n}\n```\n\n### 3. Log Tool Calls\n\n```typescript\n'search-products': async (args) => {\n console.log('Tool call: search-products', { args });\n \n const result = await productSearch(args);\n \n console.log('Tool result: search-products', { \n resultCount: result.length \n });\n \n return result;\n}\n```\n\n",
43
+ "content": "\n# Tools\n\nTools extend what agents can do. In Octavus, tools execute on your server, giving you full control over data access and authentication.\n\n## Why Tools Run on Your Server\n\nUnlike traditional AI platforms where tools run in a sandbox, Octavus tools execute in your backend:\n\n- ✅ **Full data access** — Query your database directly\n- ✅ **Your authentication** — Use your existing auth context\n- ✅ **No data exposure** — Sensitive data never leaves your infrastructure\n- ✅ **Custom logic** — Any complexity you need\n\n## Defining Tool Handlers\n\nTool handlers are async functions that receive arguments and return results:\n\n```typescript\nimport type { ToolHandlers } from '@octavus/server-sdk';\n\nconst tools: ToolHandlers = {\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n \n // Query your database\n const user = await db.users.findById(userId);\n \n return {\n name: user.name,\n email: user.email,\n plan: user.subscription.plan,\n createdAt: user.createdAt.toISOString(),\n };\n },\n \n 'create-support-ticket': async (args) => {\n const summary = args.summary as string;\n const priority = args.priority as string;\n \n // Create ticket in your system\n const ticket = await ticketService.create({\n summary,\n priority,\n source: 'ai-chat',\n });\n \n return {\n ticketId: ticket.id,\n estimatedResponse: getEstimatedResponse(priority),\n };\n },\n};\n```\n\n## Using Tools in Sessions\n\nPass tool handlers when attaching to a session:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Implementation\n },\n 'create-support-ticket': async (args) => {\n // Implementation\n },\n },\n});\n```\n\n## Tool Handler Signature\n\n```typescript\ntype ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\ntype ToolHandlers = Record<string, ToolHandler>;\n```\n\n### Arguments\n\nArguments are passed as a `Record<string, unknown>`. Type-check as needed:\n\n```typescript\n'search-products': async (args) => {\n const query = args.query as string;\n const category = args.category as string | undefined;\n const maxPrice = args.maxPrice as number | undefined;\n \n return await productSearch({ query, category, maxPrice });\n}\n```\n\n### Return Values\n\nReturn any JSON-serializable value. The result is:\n1. Sent back to the LLM as context\n2. Stored in session state\n3. Optionally stored in a variable for protocol use\n\n```typescript\n// Return object\nreturn { id: '123', status: 'created' };\n\n// Return array\nreturn [{ id: '1' }, { id: '2' }];\n\n// Return primitive\nreturn 42;\n\n// Return null for \"no result\"\nreturn null;\n```\n\n## Error Handling\n\nThrow errors for failures. They're captured and sent to the LLM:\n\n```typescript\n'get-user-account': async (args) => {\n const userId = args.userId as string;\n \n const user = await db.users.findById(userId);\n \n if (!user) {\n throw new Error(`User not found: ${userId}`);\n }\n \n return user;\n}\n```\n\nThe LLM receives the error message and can respond appropriately (e.g., \"I couldn't find that account\").\n\n## Tool Execution Flow\n\nWhen the LLM calls a tool:\n\n```mermaid\nsequenceDiagram\n participant LLM\n participant Platform as Octavus Platform\n participant SDK as Server SDK\n participant UI as Your Frontend\n\n LLM->>Platform: 1. Decides to call tool\n Platform-->>UI: tool-input-start, tool-input-delta\n Platform-->>UI: tool-input-available\n Platform-->>SDK: 2. tool-request (stream pauses)\n \n Note over SDK: 3. Execute handler<br/>tools['get-user']()\n \n SDK-->>UI: 4. tool-output-available\n SDK->>Platform: 5. POST /trigger with results\n Platform->>LLM: 6. Continue with results\n LLM-->>Platform: Response\n Platform-->>UI: text-delta events\n \n Note over LLM,UI: 7. Repeat if more tools needed\n```\n\n## Accessing Request Context\n\nFor request-specific data (auth, headers), create handlers dynamically:\n\n```typescript\nimport { toSSEStream } from '@octavus/server-sdk';\n\n// In your API route\nexport async function POST(request: Request) {\n const authToken = request.headers.get('Authorization');\n const user = await validateToken(authToken);\n \n const session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n // Use request context\n return await db.users.findById(user.id);\n },\n 'create-order': async (args) => {\n // Create with user context\n return await orderService.create({\n ...args,\n userId: user.id,\n createdBy: user.email,\n });\n },\n },\n });\n \n const events = session.trigger(triggerName, input);\n return new Response(toSSEStream(events));\n}\n```\n\n## Best Practices\n\n### 1. Validate Arguments\n\n```typescript\n'create-ticket': async (args) => {\n const summary = args.summary;\n if (typeof summary !== 'string' || summary.length === 0) {\n throw new Error('Summary is required');\n }\n // ...\n}\n```\n\n### 2. Handle Timeouts\n\n```typescript\n'external-api-call': async (args) => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10000);\n \n try {\n const response = await fetch(url, { signal: controller.signal });\n return await response.json();\n } finally {\n clearTimeout(timeout);\n }\n}\n```\n\n### 3. Log Tool Calls\n\n```typescript\n'search-products': async (args) => {\n console.log('Tool call: search-products', { args });\n \n const result = await productSearch(args);\n \n console.log('Tool result: search-products', { \n resultCount: result.length \n });\n \n return result;\n}\n```\n\n",
44
44
  "excerpt": "Tools Tools extend what agents can do. In Octavus, tools execute on your server, giving you full control over data access and authentication. Why Tools Run on Your Server Unlike traditional AI...",
45
45
  "order": 3
46
46
  },
@@ -49,8 +49,8 @@
49
49
  "section": "server-sdk",
50
50
  "title": "Streaming",
51
51
  "description": "Understanding stream events from the Server SDK.",
52
- "content": "\n# Streaming\n\nAll Octavus responses stream in real-time using Server-Sent Events (SSE). This enables responsive UX with incremental updates.\n\n## Stream Response\n\nWhen you trigger an action, you get a readable stream:\n\n```typescript\nconst { stream } = session.trigger('user-message', { \n USER_MESSAGE: 'Hello!' \n});\n\n// Return to frontend as streaming response\nreturn new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n },\n});\n```\n\n## Event Types\n\nThe stream emits various event types. Octavus events align with the [Vercel AI SDK](https://sdk.vercel.ai/) naming conventions where applicable.\n\n### Lifecycle Events\n\n```typescript\n// Stream started\n{ type: 'start', messageId: '...' }\n\n// Stream completed\n{ type: 'finish', finishReason: 'stop' }\n\n// Possible finish reasons:\n// - 'stop': Normal completion\n// - 'tool-calls': Waiting for tool execution (handled by SDK)\n// - 'length': Max tokens reached\n// - 'content-filter': Content filtered\n// - 'error': Error occurred\n// - 'other': Other reason\n\n// Error event\n{ type: 'error', errorText: 'Something went wrong' }\n```\n\n### Block Events\n\nTrack execution progress:\n\n```typescript\n// Block started\n{ type: 'block-start', blockId: '...', blockName: 'Respond to user', blockType: 'next-message', display: 'stream', thread: 'main' }\n\n// Block completed\n{ type: 'block-end', blockId: '...', summary: 'Generated response' }\n```\n\n### Text Events\n\nStreaming text content:\n\n```typescript\n// Text generation started\n{ type: 'text-start', id: '...' }\n\n// Incremental text (most common event)\n{ type: 'text-delta', id: '...', delta: 'Hello' }\n{ type: 'text-delta', id: '...', delta: '!' }\n{ type: 'text-delta', id: '...', delta: ' How' }\n{ type: 'text-delta', id: '...', delta: ' can' }\n{ type: 'text-delta', id: '...', delta: ' I' }\n{ type: 'text-delta', id: '...', delta: ' help?' }\n\n// Text generation ended\n{ type: 'text-end', id: '...' }\n```\n\n### Reasoning Events\n\nExtended reasoning (for supported models like Claude):\n\n```typescript\n// Reasoning started\n{ type: 'reasoning-start', id: '...' }\n\n// Reasoning content\n{ type: 'reasoning-delta', id: '...', delta: 'Let me analyze this request...' }\n\n// Reasoning ended\n{ type: 'reasoning-end', id: '...' }\n```\n\n### Tool Events\n\nTool call lifecycle:\n\n```typescript\n// Tool input started\n{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user-account', title: 'Looking up account' }\n\n// Tool input/arguments streaming\n{ type: 'tool-input-delta', toolCallId: '...', inputTextDelta: '{\"userId\":\"user-123\"}' }\n\n// Tool input streaming ended\n{ type: 'tool-input-end', toolCallId: '...' }\n\n// Tool input is complete and available\n{ type: 'tool-input-available', toolCallId: '...', toolName: 'get-user-account', input: { userId: 'user-123' } }\n\n// Tool output available (success)\n{ type: 'tool-output-available', toolCallId: '...', output: { name: 'Demo User', email: '...' } }\n\n// Tool output error (failure)\n{ type: 'tool-output-error', toolCallId: '...', errorText: 'User not found' }\n```\n\n### Resource Events\n\nResource updates:\n\n```typescript\n{ type: 'resource-update', name: 'CONVERSATION_SUMMARY', value: 'User asked about...' }\n```\n\n## Display Modes\n\nEach block/tool specifies how it should appear to users:\n\n| Mode | Description |\n|------|-------------|\n| `hidden` | Not shown to user (background work) |\n| `name` | Shows block/tool name |\n| `description` | Shows description text |\n| `stream` | Streams content to chat |\n\n**Note**: Hidden events are filtered before reaching the client SDK. Your frontend only sees user-facing events.\n\n## Stream Event Type\n\n```typescript\ntype StreamEvent =\n // Lifecycle\n | StartEvent\n | FinishEvent\n | ErrorEvent\n // Text\n | TextStartEvent\n | TextDeltaEvent\n | TextEndEvent\n // Reasoning\n | ReasoningStartEvent\n | ReasoningDeltaEvent\n | ReasoningEndEvent\n // Tool Input/Output\n | ToolInputStartEvent\n | ToolInputDeltaEvent\n | ToolInputEndEvent\n | ToolInputAvailableEvent\n | ToolOutputAvailableEvent\n | ToolOutputErrorEvent\n // Octavus-Specific\n | BlockStartEvent\n | BlockEndEvent\n | ResourceUpdateEvent\n | ToolRequestEvent;\n```\n\n## Error Recovery\n\nThe SDK handles common error scenarios:\n\n```typescript\n// Network errors are caught and emitted\n{ type: 'error', errorText: 'Network request failed' }\n\n// Tool errors are captured per-tool\n{ type: 'tool-output-error', toolCallId: '...', errorText: 'Handler threw exception' }\n\n// The stream always ends with either 'finish' or 'error'\n```\n",
53
- "excerpt": "Streaming All Octavus responses stream in real-time using Server-Sent Events (SSE). This enables responsive UX with incremental updates. Stream Response When you trigger an action, you get a...",
52
+ "content": "\n# Streaming\n\nAll Octavus responses stream in real-time using Server-Sent Events (SSE). This enables responsive UX with incremental updates.\n\n## Stream Response\n\nWhen you trigger an action, you get an async generator of parsed events:\n\n```typescript\nimport { toSSEStream } from '@octavus/server-sdk';\n\n// trigger() returns an async generator of StreamEvent\nconst events = session.trigger('user-message', { \n USER_MESSAGE: 'Hello!' \n});\n\n// For HTTP endpoints, convert to SSE stream\nreturn new Response(toSSEStream(events), {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n },\n});\n\n// For sockets, iterate events directly\nfor await (const event of events) {\n conn.write(JSON.stringify(event));\n}\n```\n\n## Event Types\n\nThe stream emits various event types. Octavus events align with the [Vercel AI SDK](https://sdk.vercel.ai/) naming conventions where applicable.\n\n### Lifecycle Events\n\n```typescript\n// Stream started\n{ type: 'start', messageId: '...' }\n\n// Stream completed\n{ type: 'finish', finishReason: 'stop' }\n\n// Possible finish reasons:\n// - 'stop': Normal completion\n// - 'tool-calls': Waiting for tool execution (handled by SDK)\n// - 'length': Max tokens reached\n// - 'content-filter': Content filtered\n// - 'error': Error occurred\n// - 'other': Other reason\n\n// Error event\n{ type: 'error', errorText: 'Something went wrong' }\n```\n\n### Block Events\n\nTrack execution progress:\n\n```typescript\n// Block started\n{ type: 'block-start', blockId: '...', blockName: 'Respond to user', blockType: 'next-message', display: 'stream', thread: 'main' }\n\n// Block completed\n{ type: 'block-end', blockId: '...', summary: 'Generated response' }\n```\n\n### Text Events\n\nStreaming text content:\n\n```typescript\n// Text generation started\n{ type: 'text-start', id: '...' }\n\n// Incremental text (most common event)\n{ type: 'text-delta', id: '...', delta: 'Hello' }\n{ type: 'text-delta', id: '...', delta: '!' }\n{ type: 'text-delta', id: '...', delta: ' How' }\n{ type: 'text-delta', id: '...', delta: ' can' }\n{ type: 'text-delta', id: '...', delta: ' I' }\n{ type: 'text-delta', id: '...', delta: ' help?' }\n\n// Text generation ended\n{ type: 'text-end', id: '...' }\n```\n\n### Reasoning Events\n\nExtended reasoning (for supported models like Claude):\n\n```typescript\n// Reasoning started\n{ type: 'reasoning-start', id: '...' }\n\n// Reasoning content\n{ type: 'reasoning-delta', id: '...', delta: 'Let me analyze this request...' }\n\n// Reasoning ended\n{ type: 'reasoning-end', id: '...' }\n```\n\n### Tool Events\n\nTool call lifecycle:\n\n```typescript\n// Tool input started\n{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user-account', title: 'Looking up account' }\n\n// Tool input/arguments streaming\n{ type: 'tool-input-delta', toolCallId: '...', inputTextDelta: '{\"userId\":\"user-123\"}' }\n\n// Tool input streaming ended\n{ type: 'tool-input-end', toolCallId: '...' }\n\n// Tool input is complete and available\n{ type: 'tool-input-available', toolCallId: '...', toolName: 'get-user-account', input: { userId: 'user-123' } }\n\n// Tool output available (success)\n{ type: 'tool-output-available', toolCallId: '...', output: { name: 'Demo User', email: '...' } }\n\n// Tool output error (failure)\n{ type: 'tool-output-error', toolCallId: '...', errorText: 'User not found' }\n```\n\n### Resource Events\n\nResource updates:\n\n```typescript\n{ type: 'resource-update', name: 'CONVERSATION_SUMMARY', value: 'User asked about...' }\n```\n\n## Display Modes\n\nEach block/tool specifies how it should appear to users:\n\n| Mode | Description |\n|------|-------------|\n| `hidden` | Not shown to user (background work) |\n| `name` | Shows block/tool name |\n| `description` | Shows description text |\n| `stream` | Streams content to chat |\n\n**Note**: Hidden events are filtered before reaching the client SDK. Your frontend only sees user-facing events.\n\n## Stream Event Type\n\n```typescript\ntype StreamEvent =\n // Lifecycle\n | StartEvent\n | FinishEvent\n | ErrorEvent\n // Text\n | TextStartEvent\n | TextDeltaEvent\n | TextEndEvent\n // Reasoning\n | ReasoningStartEvent\n | ReasoningDeltaEvent\n | ReasoningEndEvent\n // Tool Input/Output\n | ToolInputStartEvent\n | ToolInputDeltaEvent\n | ToolInputEndEvent\n | ToolInputAvailableEvent\n | ToolOutputAvailableEvent\n | ToolOutputErrorEvent\n // Octavus-Specific\n | BlockStartEvent\n | BlockEndEvent\n | ResourceUpdateEvent\n | ToolRequestEvent;\n```\n\n## Error Recovery\n\nThe SDK handles common error scenarios:\n\n```typescript\n// Network errors are caught and emitted\n{ type: 'error', errorText: 'Network request failed' }\n\n// Tool errors are captured per-tool\n{ type: 'tool-output-error', toolCallId: '...', errorText: 'Handler threw exception' }\n\n// The stream always ends with either 'finish' or 'error'\n```\n",
53
+ "excerpt": "Streaming All Octavus responses stream in real-time using Server-Sent Events (SSE). This enables responsive UX with incremental updates. Stream Response When you trigger an action, you get an async...",
54
54
  "order": 4
55
55
  },
56
56
  {
@@ -58,7 +58,7 @@
58
58
  "section": "client-sdk",
59
59
  "title": "Overview",
60
60
  "description": "Introduction to the Octavus Client SDKs for building chat interfaces.",
61
- "content": "\n# Client SDK Overview\n\nOctavus provides two packages for frontend integration:\n\n| Package | Purpose | Use When |\n|---------|---------|----------|\n| `@octavus/react` | React hooks and bindings | Building React applications |\n| `@octavus/client-sdk` | Framework-agnostic core | Using Vue, Svelte, vanilla JS, or custom integrations |\n\n**Most users should install `@octavus/react`** — it includes everything from `@octavus/client-sdk` plus React-specific hooks.\n\n## Installation\n\n### React Applications\n\n```bash\nnpm install @octavus/react\n```\n\n**Current version:** `0.0.7`\n\n### Other Frameworks\n\n```bash\nnpm install @octavus/client-sdk\n```\n\n**Current version:** `0.0.7`\n\n## Transport Pattern\n\nThe Client SDK uses a **transport abstraction** to handle communication with your backend. This gives you flexibility in how events are delivered:\n\n| Transport | Use Case |\n|-----------|----------|\n| `createHttpTransport` | HTTP/SSE (Next.js, Express, etc.) |\n| `createSocketTransport` | WebSocket, SockJS, or other socket protocols |\n\n## React Usage\n\nThe `useOctavusChat` hook provides state management and streaming for React applications:\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n // Create a stable transport instance (memoized on sessionId)\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n\n const sendMessage = async (text: string) => {\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n };\n\n return (\n <div>\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n </div>\n );\n}\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n return (\n <div>\n {message.parts.map((part, i) => {\n if (part.type === 'text') {\n return <p key={i}>{part.text}</p>;\n }\n return null;\n })}\n </div>\n );\n}\n```\n\n## Framework-Agnostic Usage\n\nThe `OctavusChat` class can be used with any framework or vanilla JavaScript:\n\n```typescript\nimport { OctavusChat, createHttpTransport } from '@octavus/client-sdk';\n\nconst transport = createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n});\n\nconst chat = new OctavusChat({ transport });\n\n// Subscribe to state changes\nconst unsubscribe = chat.subscribe(() => {\n console.log('Messages:', chat.messages);\n console.log('Status:', chat.status);\n // Update your UI here\n});\n\n// Send a message\nawait chat.send(\n 'user-message',\n { USER_MESSAGE: 'Hello' },\n { userMessage: { content: 'Hello' } },\n);\n\n// Cleanup when done\nunsubscribe();\n```\n\n## Key Features\n\n### Unified Send Function\n\nThe `send` function handles both user message display and agent triggering in one call:\n\n```tsx\nconst { send } = useOctavusChat({ transport });\n\n// Add user message to UI and trigger agent\nawait send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n);\n\n// Trigger without adding a user message (e.g., button click)\nawait send('request-human');\n```\n\n### Message Parts\n\nMessages contain ordered `parts` for rich content:\n\n```tsx\nconst { messages } = useOctavusChat({ transport });\n\n// Each message has typed parts\nmessage.parts.map((part) => {\n switch (part.type) {\n case 'text': // Text content\n case 'reasoning': // Extended reasoning/thinking\n case 'tool-call': // Tool execution\n case 'operation': // Internal operations (set-resource, etc.)\n }\n});\n```\n\n### Status Tracking\n\n```tsx\nconst { status } = useOctavusChat({ transport });\n\n// status: 'idle' | 'streaming' | 'error'\n```\n\n### Stop Streaming\n\n```tsx\nconst { stop } = useOctavusChat({ transport });\n\n// Stop current stream and finalize message\nstop();\n```\n\n## Hook Reference (React)\n\n### useOctavusChat\n\n```typescript\nfunction useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn;\n\ninterface OctavusChatOptions {\n // Required: Transport for streaming events\n transport: Transport;\n\n // Optional: Pre-populate with existing messages (session restore)\n initialMessages?: UIMessage[];\n\n // Optional: Callbacks\n onError?: (error: Error) => void;\n onFinish?: () => void;\n onResourceUpdate?: (name: string, value: unknown) => void;\n}\n\ninterface UseOctavusChatReturn {\n // State\n messages: UIMessage[];\n status: ChatStatus; // 'idle' | 'streaming' | 'error'\n error: Error | null;\n\n // Actions\n send: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput }\n ) => Promise<void>;\n stop: () => void;\n}\n\ninterface UserMessageInput {\n content: string;\n}\n```\n\n## Transport Reference\n\n### createHttpTransport\n\nCreates an HTTP/SSE transport using native `fetch()`:\n\n```typescript\nimport { createHttpTransport } from '@octavus/react';\n\nconst transport = createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n});\n```\n\n### createSocketTransport\n\nCreates a WebSocket/SockJS transport for real-time connections:\n\n```typescript\nimport { createSocketTransport } from '@octavus/react';\n\nconst transport = createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const ws = new WebSocket(`wss://api.example.com/stream?sessionId=${sessionId}`);\n ws.onopen = () => resolve(ws);\n ws.onerror = () => reject(new Error('Connection failed'));\n }),\n});\n```\n\nFor detailed WebSocket/SockJS usage including custom events, reconnection patterns, and server-side implementation, see [Socket Transport](/docs/client-sdk/socket-transport).\n\n## Class Reference (Framework-Agnostic)\n\n### OctavusChat\n\n```typescript\nclass OctavusChat {\n constructor(options: OctavusChatOptions);\n\n // State (read-only)\n readonly messages: UIMessage[];\n readonly status: ChatStatus;\n readonly error: Error | null;\n\n // Actions\n send(\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput }\n ): Promise<void>;\n stop(): void;\n\n // Subscription\n subscribe(callback: () => void): () => void; // Returns unsubscribe function\n}\n```\n\n## Next Steps\n\n- [Messages](/docs/client-sdk/messages) — Working with message state\n- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs\n- [Operations](/docs/client-sdk/execution-blocks) — Showing agent progress\n- [Socket Transport](/docs/client-sdk/socket-transport) — WebSocket and SockJS integration\n",
61
+ "content": "\n# Client SDK Overview\n\nOctavus provides two packages for frontend integration:\n\n| Package | Purpose | Use When |\n|---------|---------|----------|\n| `@octavus/react` | React hooks and bindings | Building React applications |\n| `@octavus/client-sdk` | Framework-agnostic core | Using Vue, Svelte, vanilla JS, or custom integrations |\n\n**Most users should install `@octavus/react`** — it includes everything from `@octavus/client-sdk` plus React-specific hooks.\n\n## Installation\n\n### React Applications\n\n```bash\nnpm install @octavus/react\n```\n\n**Current version:** `0.0.8`\n\n### Other Frameworks\n\n```bash\nnpm install @octavus/client-sdk\n```\n\n**Current version:** `0.0.8`\n\n## Transport Pattern\n\nThe Client SDK uses a **transport abstraction** to handle communication with your backend. This gives you flexibility in how events are delivered:\n\n| Transport | Use Case | Docs |\n|-----------|----------|------|\n| `createHttpTransport` | HTTP/SSE (Next.js, Express, etc.) | [HTTP Transport](/docs/client-sdk/http-transport) |\n| `createSocketTransport` | WebSocket, SockJS, or other socket protocols | [Socket Transport](/docs/client-sdk/socket-transport) |\n\nWhen the transport changes (e.g., when `sessionId` changes), the `useOctavusChat` hook automatically reinitializes with the new transport.\n\n> **Recommendation**: Use HTTP transport unless you specifically need WebSocket features (custom real-time events, Meteor/Phoenix, etc.).\n\n## React Usage\n\nThe `useOctavusChat` hook provides state management and streaming for React applications:\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n // Create a stable transport instance (memoized on sessionId)\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n\n const sendMessage = async (text: string) => {\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n };\n\n return (\n <div>\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n </div>\n );\n}\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n return (\n <div>\n {message.parts.map((part, i) => {\n if (part.type === 'text') {\n return <p key={i}>{part.text}</p>;\n }\n return null;\n })}\n </div>\n );\n}\n```\n\n## Framework-Agnostic Usage\n\nThe `OctavusChat` class can be used with any framework or vanilla JavaScript:\n\n```typescript\nimport { OctavusChat, createHttpTransport } from '@octavus/client-sdk';\n\nconst transport = createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n});\n\nconst chat = new OctavusChat({ transport });\n\n// Subscribe to state changes\nconst unsubscribe = chat.subscribe(() => {\n console.log('Messages:', chat.messages);\n console.log('Status:', chat.status);\n // Update your UI here\n});\n\n// Send a message\nawait chat.send(\n 'user-message',\n { USER_MESSAGE: 'Hello' },\n { userMessage: { content: 'Hello' } },\n);\n\n// Cleanup when done\nunsubscribe();\n```\n\n## Key Features\n\n### Unified Send Function\n\nThe `send` function handles both user message display and agent triggering in one call:\n\n```tsx\nconst { send } = useOctavusChat({ transport });\n\n// Add user message to UI and trigger agent\nawait send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n);\n\n// Trigger without adding a user message (e.g., button click)\nawait send('request-human');\n```\n\n### Message Parts\n\nMessages contain ordered `parts` for rich content:\n\n```tsx\nconst { messages } = useOctavusChat({ transport });\n\n// Each message has typed parts\nmessage.parts.map((part) => {\n switch (part.type) {\n case 'text': // Text content\n case 'reasoning': // Extended reasoning/thinking\n case 'tool-call': // Tool execution\n case 'operation': // Internal operations (set-resource, etc.)\n }\n});\n```\n\n### Status Tracking\n\n```tsx\nconst { status } = useOctavusChat({ transport });\n\n// status: 'idle' | 'streaming' | 'error'\n```\n\n### Stop Streaming\n\n```tsx\nconst { stop } = useOctavusChat({ transport });\n\n// Stop current stream and finalize message\nstop();\n```\n\n## Hook Reference (React)\n\n### useOctavusChat\n\n```typescript\nfunction useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn;\n\ninterface OctavusChatOptions {\n // Required: Transport for streaming events\n transport: Transport;\n\n // Optional: Pre-populate with existing messages (session restore)\n initialMessages?: UIMessage[];\n\n // Optional: Callbacks\n onError?: (error: Error) => void;\n onFinish?: () => void;\n onResourceUpdate?: (name: string, value: unknown) => void;\n}\n\ninterface UseOctavusChatReturn {\n // State\n messages: UIMessage[];\n status: ChatStatus; // 'idle' | 'streaming' | 'error'\n error: Error | null;\n\n // Actions\n send: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput }\n ) => Promise<void>;\n stop: () => void;\n}\n\ninterface UserMessageInput {\n content: string;\n}\n```\n\n## Transport Reference\n\n### createHttpTransport\n\nCreates an HTTP/SSE transport using native `fetch()`:\n\n```typescript\nimport { createHttpTransport } from '@octavus/react';\n\nconst transport = createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n});\n```\n\n### createSocketTransport\n\nCreates a WebSocket/SockJS transport for real-time connections:\n\n```typescript\nimport { createSocketTransport } from '@octavus/react';\n\nconst transport = createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const ws = new WebSocket(`wss://api.example.com/stream?sessionId=${sessionId}`);\n ws.onopen = () => resolve(ws);\n ws.onerror = () => reject(new Error('Connection failed'));\n }),\n});\n```\n\nFor detailed WebSocket/SockJS usage including custom events, reconnection patterns, and server-side implementation, see [Socket Transport](/docs/client-sdk/socket-transport).\n\n## Class Reference (Framework-Agnostic)\n\n### OctavusChat\n\n```typescript\nclass OctavusChat {\n constructor(options: OctavusChatOptions);\n\n // State (read-only)\n readonly messages: UIMessage[];\n readonly status: ChatStatus;\n readonly error: Error | null;\n\n // Actions\n send(\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput }\n ): Promise<void>;\n stop(): void;\n\n // Subscription\n subscribe(callback: () => void): () => void; // Returns unsubscribe function\n}\n```\n\n## Next Steps\n\n- [HTTP Transport](/docs/client-sdk/http-transport) — HTTP/SSE integration (recommended)\n- [Socket Transport](/docs/client-sdk/socket-transport) — WebSocket and SockJS integration\n- [Messages](/docs/client-sdk/messages) — Working with message state\n- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs\n- [Operations](/docs/client-sdk/execution-blocks) — Showing agent progress\n- [Examples](/docs/examples/overview) — Complete working examples\n",
62
62
  "excerpt": "Client SDK Overview Octavus provides two packages for frontend integration: | Package | Purpose | Use When | |---------|---------|----------| | | React hooks and bindings | Building React...",
63
63
  "order": 1
64
64
  },
@@ -94,10 +94,19 @@
94
94
  "section": "client-sdk",
95
95
  "title": "Socket Transport",
96
96
  "description": "Using WebSocket or SockJS for real-time streaming with Octavus.",
97
- "content": "\n# Socket Transport\n\nThe socket transport enables real-time bidirectional communication using WebSocket or SockJS. Use this when you need persistent connections, custom server events, or when HTTP/SSE isn't suitable for your infrastructure.\n\n## When to Use Socket Transport\n\n| Use Case | Recommended Transport |\n|----------|----------------------|\n| Standard web apps (Next.js, etc.) | HTTP (`createHttpTransport`) |\n| Real-time apps with custom events | Socket (`createSocketTransport`) |\n| Apps behind proxies that don't support SSE | Socket |\n| Need for typing indicators, presence, etc. | Socket |\n| Meteor, Phoenix, or socket-based frameworks | Socket |\n\n## Basic Setup\n\n### Native WebSocket\n\n```typescript\nimport { useMemo } from 'react';\nimport { useOctavusChat, createSocketTransport } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const transport = useMemo(\n () =>\n createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const ws = new WebSocket(\n `wss://your-server.com/octavus?sessionId=${sessionId}`\n );\n ws.onopen = () => resolve(ws);\n ws.onerror = () => reject(new Error('WebSocket connection failed'));\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n\n // ... rest of your component\n}\n```\n\n### SockJS\n\nSockJS provides WebSocket-like functionality with fallbacks for older browsers:\n\n```typescript\nimport SockJS from 'sockjs-client';\nimport { createSocketTransport } from '@octavus/react';\n\nconst transport = createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const sock = new SockJS('/octavus-stream');\n sock.onopen = () => resolve(sock);\n sock.onerror = () => reject(new Error('SockJS connection failed'));\n }),\n});\n```\n\n## Custom Events\n\nThe socket transport can handle custom events alongside Octavus stream events. Use the `onMessage` callback to process any message your server sends:\n\n```typescript\nconst transport = createSocketTransport({\n connect: () => /* ... */,\n\n onMessage: (data) => {\n const msg = data as { type: string; [key: string]: unknown };\n\n switch (msg.type) {\n case 'typing-indicator':\n setAgentTyping(msg.isTyping as boolean);\n break;\n\n case 'presence-update':\n setOnlineUsers(msg.users as string[]);\n break;\n\n case 'notification':\n showToast(msg.message as string);\n break;\n\n // Octavus events (text-delta, finish, etc.) are handled automatically\n // No need to handle them here\n }\n },\n});\n```\n\n> **Note**: Octavus stream events (`text-delta`, `finish`, `tool-input-start`, etc.) are automatically processed by the transport. The `onMessage` callback is for your custom events only.\n\n## Connection Management\n\n### Handling Disconnections\n\nUse the `onClose` callback for cleanup or reconnection logic:\n\n```typescript\nconst transport = createSocketTransport({\n connect: () => /* ... */,\n\n onClose: () => {\n console.log('Socket disconnected');\n setConnectionStatus('disconnected');\n\n // Optional: trigger reconnection\n // reconnect();\n },\n});\n```\n\n### Reconnection Pattern\n\nFor production apps, implement reconnection with exponential backoff:\n\n```typescript\nimport { useRef, useCallback, useMemo } from 'react';\nimport { createSocketTransport, type SocketLike } from '@octavus/react';\n\nfunction useReconnectingTransport(sessionId: string) {\n const reconnectAttempts = useRef(0);\n const maxAttempts = 5;\n\n const connect = useCallback((): Promise<SocketLike> => {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(`wss://your-server.com/octavus?sessionId=${sessionId}`);\n\n ws.onopen = () => {\n reconnectAttempts.current = 0; // Reset on success\n resolve(ws);\n };\n\n ws.onerror = () => {\n if (reconnectAttempts.current < maxAttempts) {\n reconnectAttempts.current++;\n const delay = Math.min(1000 * 2 ** reconnectAttempts.current, 30000);\n console.log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempts.current})`);\n setTimeout(() => connect().then(resolve).catch(reject), delay);\n } else {\n reject(new Error('Max reconnection attempts reached'));\n }\n };\n });\n }, [sessionId]);\n\n return useMemo(\n () =>\n createSocketTransport({\n connect,\n onClose: () => {\n console.log('Connection closed');\n },\n }),\n [connect],\n );\n}\n```\n\n## Server-Side Implementation\n\nYour server needs to handle socket connections and forward events from the Octavus platform. Here's a basic pattern:\n\n### Express + ws (WebSocket)\n\n```typescript\nimport { WebSocketServer } from 'ws';\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nconst wss = new WebSocketServer({ server });\n\nwss.on('connection', (ws, req) => {\n const sessionId = new URL(req.url!, 'http://localhost').searchParams.get('sessionId');\n\n ws.on('message', async (data) => {\n const message = JSON.parse(data.toString());\n\n if (message.type === 'trigger') {\n const session = octavus.agentSessions.attach(sessionId!, {\n tools: {\n // Your tool handlers\n },\n });\n\n const { stream } = session.trigger(message.triggerName, message.input);\n\n // Forward SSE stream to WebSocket\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const text = decoder.decode(value);\n // Parse SSE format and send as JSON\n for (const line of text.split('\\n')) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n ws.send(line.slice(6)); // Send JSON directly\n }\n }\n }\n }\n\n if (message.type === 'stop') {\n // Handle stop request\n }\n });\n});\n```\n\n### Express + SockJS\n\n```typescript\nimport sockjs from 'sockjs';\nimport { OctavusClient } from '@octavus/server-sdk';\n\nconst octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nconst sockServer = sockjs.createServer();\n\nsockServer.on('connection', (conn) => {\n let sessionId: string | null = null;\n\n conn.on('data', async (data) => {\n const message = JSON.parse(data);\n\n if (message.type === 'init') {\n sessionId = message.sessionId;\n return;\n }\n\n if (message.type === 'trigger' && sessionId) {\n const session = octavus.agentSessions.attach(sessionId, {\n tools: {\n // Your tool handlers\n },\n });\n\n const { stream } = session.trigger(message.triggerName, message.input);\n\n // Forward stream events\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const text = decoder.decode(value);\n for (const line of text.split('\\n')) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n conn.write(line.slice(6));\n }\n }\n }\n }\n });\n});\n\nsockServer.installHandlers(server, { prefix: '/octavus-stream' });\n```\n\n## Protocol Reference\n\n### Client → Server Messages\n\n```typescript\n// Trigger an action\n{ type: 'trigger', triggerName: string, input?: Record<string, unknown> }\n\n// Stop current stream\n{ type: 'stop' }\n```\n\n### Server → Client Messages\n\nThe server sends Octavus `StreamEvent` objects as JSON. See [Streaming Events](/docs/server-sdk/streaming#event-types) for the full list.\n\n```typescript\n// Examples\n{ type: 'start', messageId: '...' }\n{ type: 'text-delta', id: '...', delta: 'Hello' }\n{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user' }\n{ type: 'finish', finishReason: 'stop' }\n```\n\n\n",
97
+ "content": "\n# Socket Transport\n\nThe socket transport enables real-time bidirectional communication using WebSocket or SockJS. Use this when you need persistent connections, custom server events, or when HTTP/SSE isn't suitable for your infrastructure.\n\n## When to Use Socket Transport\n\n| Use Case | Recommended Transport |\n|----------|----------------------|\n| Standard web apps (Next.js, etc.) | HTTP (`createHttpTransport`) |\n| Real-time apps with custom events | Socket (`createSocketTransport`) |\n| Apps behind proxies that don't support SSE | Socket |\n| Need for typing indicators, presence, etc. | Socket |\n| Meteor, Phoenix, or socket-based frameworks | Socket |\n\n## Patterns Overview\n\nThere are two main patterns for socket-based integrations:\n\n| Pattern | When to Use |\n|---------|-------------|\n| [Server-Managed Sessions](#server-managed-sessions-recommended) | **Recommended.** Server creates sessions lazily. Client doesn't need sessionId. |\n| [Client-Provided Session ID](#client-provided-session-id) | When client must control session creation or pass sessionId from URL. |\n\n## Server-Managed Sessions (Recommended)\n\nThe cleanest pattern is to have the server manage session lifecycle. The client never needs to know about `sessionId` — the server creates it lazily on first message.\n\n### Client Setup\n\n```typescript\nimport { useMemo } from 'react';\nimport SockJS from 'sockjs-client';\nimport { useOctavusChat, createSocketTransport, type SocketLike } from '@octavus/react';\n\nfunction connectSocket(): Promise<SocketLike> {\n return new Promise((resolve, reject) => {\n const sock = new SockJS('/octavus');\n sock.onopen = () => resolve(sock);\n sock.onerror = () => reject(new Error('Connection failed'));\n });\n}\n\nfunction Chat() {\n // Transport is stable — no dependencies on sessionId\n const transport = useMemo(\n () => createSocketTransport({ connect: connectSocket }),\n [],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n\n const sendMessage = async (text: string) => {\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n };\n\n // ... render messages\n}\n```\n\n### Server Setup (Express + SockJS)\n\nThe server creates a session on first trigger message:\n\n```typescript\nimport sockjs from 'sockjs';\nimport { OctavusClient, type AgentSession } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nfunction createSocketHandler() {\n return (conn: sockjs.Connection) => {\n let session: AgentSession | null = null;\n let abortController: AbortController | null = null;\n\n conn.on('data', (rawData: string) => {\n void handleMessage(rawData);\n });\n\n async function handleMessage(rawData: string) {\n const msg = JSON.parse(rawData);\n\n if (msg.type === 'stop') {\n abortController?.abort();\n return;\n }\n\n if (msg.type === 'trigger') {\n // Create session lazily on first trigger\n if (!session) {\n const sessionId = await client.agentSessions.create('your-agent-id', {\n // Initial input variables\n COMPANY_NAME: 'Acme Corp',\n });\n session = client.agentSessions.attach(sessionId, {\n tools: {\n // Your tool handlers\n },\n });\n }\n\n abortController = new AbortController();\n\n // Iterate events directly — no SSE parsing needed\n const events = session.trigger(msg.triggerName, msg.input);\n\n try {\n for await (const event of events) {\n if (abortController.signal.aborted) break;\n conn.write(JSON.stringify(event));\n }\n } catch {\n // Handle errors\n }\n }\n }\n\n conn.on('close', () => abortController?.abort());\n };\n}\n\nconst sockServer = sockjs.createServer({ prefix: '/octavus' });\nsockServer.on('connection', createSocketHandler());\nsockServer.installHandlers(httpServer);\n```\n\n**Benefits of this pattern:**\n- Client code is simple — no sessionId management\n- No transport caching issues\n- Session is created only when needed\n- Server controls session configuration\n\n## Client-Provided Session ID\n\nIf you need the client to control the session (e.g., resuming a specific session from URL), pass the sessionId in an init message after connecting:\n\n```typescript\nimport { useMemo } from 'react';\nimport SockJS from 'sockjs-client';\nimport { useOctavusChat, createSocketTransport, type SocketLike } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const transport = useMemo(\n () =>\n createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const sock = new SockJS('/octavus');\n sock.onopen = () => {\n // Send init message with sessionId\n sock.send(JSON.stringify({ type: 'init', sessionId }));\n resolve(sock);\n };\n sock.onerror = () => reject(new Error('Connection failed'));\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n // ... render chat\n}\n```\n\nWhen `sessionId` changes, the hook automatically reinitializes with the new transport.\n\n### Server Handler with Init Message\n\nWhen using client-provided sessionId, the server must handle an `init` message:\n\n```typescript\nsockServer.on('connection', (conn) => {\n let session: AgentSession | null = null;\n let abortController: AbortController | null = null;\n\n conn.on('data', (rawData: string) => {\n void handleMessage(rawData);\n });\n\n async function handleMessage(rawData: string) {\n const msg = JSON.parse(rawData);\n\n // Handle session initialization\n if (msg.type === 'init') {\n session = client.agentSessions.attach(msg.sessionId, {\n tools: { /* ... */ },\n });\n return;\n }\n\n if (msg.type === 'stop') {\n abortController?.abort();\n return;\n }\n\n // All other messages require initialized session\n if (!session) {\n conn.write(JSON.stringify({\n type: 'error',\n errorText: 'Session not initialized. Send init message first.',\n }));\n return;\n }\n\n if (msg.type === 'trigger') {\n // ... handle trigger (same as server-managed pattern)\n }\n }\n});\n```\n\n## Async Session ID\n\nWhen the session ID is fetched asynchronously (e.g., from an API), you have two options:\n\n### Option 1: Conditionally Render (Recommended)\n\nDon't render the chat component until `sessionId` is available:\n\n```tsx\nfunction ChatPage() {\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n useEffect(() => {\n api.createSession().then(res => setSessionId(res.sessionId));\n }, []);\n\n // Don't render until sessionId is ready\n if (!sessionId) {\n return <LoadingSpinner />;\n }\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\nThis is the cleanest approach — the `Chat` component always receives a valid `sessionId`.\n\n### Option 2: Server-Managed Sessions\n\nUse the [server-managed sessions pattern](#server-managed-sessions-recommended) where the server creates the session lazily. The client never needs to know about `sessionId`.\n\n## Native WebSocket\n\nIf you're using native WebSocket instead of SockJS, you can pass sessionId via URL:\n\n```typescript\nconst transport = useMemo(\n () =>\n createSocketTransport({\n connect: () =>\n new Promise((resolve, reject) => {\n const ws = new WebSocket(\n `wss://your-server.com/octavus?sessionId=${sessionId}`\n );\n ws.onopen = () => resolve(ws);\n ws.onerror = () => reject(new Error('WebSocket connection failed'));\n }),\n }),\n [sessionId],\n);\n```\n\nWhen `sessionId` changes, the hook automatically reinitializes with the new transport.\n\n## Custom Events\n\nHandle custom events alongside Octavus stream events:\n\n```typescript\nconst transport = createSocketTransport({\n connect: connectSocket,\n\n onMessage: (data) => {\n const msg = data as { type: string; [key: string]: unknown };\n\n switch (msg.type) {\n case 'typing-indicator':\n setAgentTyping(msg.isTyping as boolean);\n break;\n\n case 'presence-update':\n setOnlineUsers(msg.users as string[]);\n break;\n\n case 'notification':\n showToast(msg.message as string);\n break;\n\n // Octavus events (text-delta, finish, etc.) are handled automatically\n }\n },\n});\n```\n\n## Connection Management\n\n### Handling Disconnections\n\n```typescript\nconst transport = createSocketTransport({\n connect: connectSocket,\n\n onClose: () => {\n console.log('Socket disconnected');\n setConnectionStatus('disconnected');\n },\n});\n```\n\n### Reconnection with Exponential Backoff\n\n```typescript\nimport { useRef, useCallback, useMemo } from 'react';\nimport { createSocketTransport, type SocketLike } from '@octavus/react';\n\nfunction useReconnectingTransport() {\n const reconnectAttempts = useRef(0);\n const maxAttempts = 5;\n\n const connect = useCallback((): Promise<SocketLike> => {\n return new Promise((resolve, reject) => {\n const sock = new SockJS('/octavus');\n\n sock.onopen = () => {\n reconnectAttempts.current = 0;\n resolve(sock);\n };\n\n sock.onerror = () => {\n if (reconnectAttempts.current < maxAttempts) {\n reconnectAttempts.current++;\n const delay = Math.min(1000 * 2 ** reconnectAttempts.current, 30000);\n console.log(`Reconnecting in ${delay}ms...`);\n setTimeout(() => connect().then(resolve).catch(reject), delay);\n } else {\n reject(new Error('Max reconnection attempts reached'));\n }\n };\n });\n }, []);\n\n return useMemo(\n () => createSocketTransport({ connect }),\n [connect],\n );\n}\n```\n\n## Framework Notes\n\n### Meteor\n\nMeteor's bundler may have issues with ES6 imports of `sockjs-client`. Use `require()` instead:\n\n```typescript\n// ❌ May fail in Meteor\nimport SockJS from 'sockjs-client';\n\n// ✅ Works in Meteor\nconst SockJS: typeof import('sockjs-client') = require('sockjs-client');\n```\n\n### SockJS vs WebSocket\n\n| Feature | WebSocket | SockJS |\n|---------|-----------|--------|\n| Browser support | Modern browsers | All browsers (with fallbacks) |\n| Session ID | Via URL query params | Via init message |\n| Proxy compatibility | Varies | Excellent (polling fallback) |\n| Setup complexity | Lower | Higher (requires server library) |\n\n## Protocol Reference\n\n### Client → Server Messages\n\n```typescript\n// Initialize session (only for client-provided sessionId pattern)\n{ type: 'init', sessionId: string }\n\n// Trigger an action\n{ type: 'trigger', triggerName: string, input?: Record<string, unknown> }\n\n// Stop current stream\n{ type: 'stop' }\n```\n\n### Server → Client Messages\n\nThe server sends Octavus `StreamEvent` objects as JSON. See [Streaming Events](/docs/server-sdk/streaming#event-types) for the full list.\n\n```typescript\n// Examples\n{ type: 'start', messageId: '...' }\n{ type: 'text-delta', id: '...', delta: 'Hello' }\n{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user' }\n{ type: 'finish', finishReason: 'stop' }\n{ type: 'error', errorText: 'Something went wrong' }\n```\n\n## Full Example\n\nFor a complete walkthrough of building a chat interface with SockJS, see the [Socket Chat Example](/docs/examples/socket-chat).\n",
98
98
  "excerpt": "Socket Transport The socket transport enables real-time bidirectional communication using WebSocket or SockJS. Use this when you need persistent connections, custom server events, or when HTTP/SSE...",
99
99
  "order": 5
100
100
  },
101
+ {
102
+ "slug": "client-sdk/http-transport",
103
+ "section": "client-sdk",
104
+ "title": "HTTP Transport",
105
+ "description": "Using HTTP/SSE for streaming with Octavus in Next.js, Express, and other frameworks.",
106
+ "content": "\n# HTTP Transport\n\nThe HTTP transport uses standard HTTP requests with Server-Sent Events (SSE) for streaming. This is the simplest and most compatible transport option.\n\n## When to Use HTTP Transport\n\n| Use Case | Recommendation |\n|----------|----------------|\n| Next.js, Remix, or similar frameworks | ✅ Use HTTP |\n| Standard web apps without special requirements | ✅ Use HTTP |\n| Serverless deployments (Vercel, etc.) | ✅ Use HTTP |\n| Need custom real-time events | Consider [Socket Transport](/docs/client-sdk/socket-transport) |\n\n## Basic Setup\n\n### Client\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, error, send, stop } = useOctavusChat({ transport });\n\n const sendMessage = async (text: string) => {\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n };\n\n // ... render chat\n}\n```\n\n### Server (Next.js API Route)\n\n```typescript\n// app/api/trigger/route.ts\nimport { OctavusClient, toSSEStream } from '@octavus/server-sdk';\n\nconst client = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nexport async function POST(request: Request) {\n const { sessionId, triggerName, input } = await request.json();\n\n const session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n return { name: 'Demo User', plan: 'pro' };\n },\n },\n });\n\n // trigger() returns parsed events, toSSEStream() converts to SSE format\n const events = session.trigger(triggerName, input);\n\n return new Response(toSSEStream(events), {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n```\n\n## Session Creation\n\nSessions should be created server-side before rendering the chat. There are two patterns:\n\n### Pattern 1: Create Session on Page Load\n\n```tsx\n// app/chat/page.tsx\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Chat } from '@/components/Chat';\n\nexport default function ChatPage() {\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n useEffect(() => {\n fetch('/api/sessions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n agentId: 'your-agent-id',\n input: { COMPANY_NAME: 'Acme Corp' },\n }),\n })\n .then(res => res.json())\n .then(data => setSessionId(data.sessionId));\n }, []);\n\n if (!sessionId) {\n return <LoadingSpinner />;\n }\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\n### Pattern 2: Server-Side Session Creation (App Router)\n\n```tsx\n// app/chat/page.tsx\nimport { octavus } from '@/lib/octavus';\nimport { Chat } from '@/components/Chat';\n\nexport default async function ChatPage() {\n // Create session server-side\n const sessionId = await octavus.agentSessions.create('your-agent-id', {\n COMPANY_NAME: 'Acme Corp',\n });\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\nThis pattern is cleaner as the session is ready before the component renders.\n\n## Error Handling\n\nHandle errors in both the transport and the hook:\n\n```tsx\nconst { messages, status, error, send } = useOctavusChat({\n transport,\n onError: (err) => {\n console.error('Stream error:', err);\n // Show toast, update UI, etc.\n },\n});\n\n// Also check error state\nif (error) {\n return <ErrorMessage error={error} />;\n}\n```\n\n## Stop Streaming\n\nAllow users to cancel ongoing streams:\n\n```tsx\nconst { send, stop, status } = useOctavusChat({ transport });\n\nreturn (\n <button\n onClick={status === 'streaming' ? stop : () => sendMessage()}\n disabled={status === 'streaming' && !inputValue}\n >\n {status === 'streaming' ? 'Stop' : 'Send'}\n </button>\n);\n```\n\n## Express Server\n\nFor non-Next.js backends:\n\n```typescript\nimport express from 'express';\nimport { OctavusClient, toSSEStream } from '@octavus/server-sdk';\n\nconst app = express();\nconst client = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\napp.post('/api/trigger', async (req, res) => {\n const { sessionId, triggerName, input } = req.body;\n\n const session = client.agentSessions.attach(sessionId, {\n tools: {\n // Your tool handlers\n },\n });\n\n const events = session.trigger(triggerName, input);\n const stream = toSSEStream(events);\n\n // Set SSE headers\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n // Pipe the stream to the response\n const reader = stream.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n }\n } finally {\n reader.releaseLock();\n res.end();\n }\n});\n```\n\n## Transport Options\n\n```typescript\ninterface HttpTransportOptions {\n // Function that makes the HTTP request\n triggerRequest: (\n triggerName: string,\n input?: Record<string, unknown>\n ) => Promise<Response>;\n}\n```\n\n## Protocol\n\n### Request Format\n\nThe `triggerRequest` function should send a POST request with:\n\n```json\n{\n \"sessionId\": \"sess_abc123\",\n \"triggerName\": \"user-message\",\n \"input\": {\n \"USER_MESSAGE\": \"Hello\"\n }\n}\n```\n\n### Response Format\n\nThe server responds with an SSE stream:\n\n```\ndata: {\"type\":\"start\",\"messageId\":\"msg_xyz\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"msg_xyz\",\"delta\":\"Hello\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"msg_xyz\",\"delta\":\" there!\"}\n\ndata: {\"type\":\"finish\",\"finishReason\":\"stop\"}\n\ndata: [DONE]\n```\n\nSee [Streaming Events](/docs/server-sdk/streaming#event-types) for the full list of event types.\n\n## Next Steps\n\n- [Quick Start](/docs/getting-started/quickstart) — Complete Next.js integration guide\n- [Messages](/docs/client-sdk/messages) — Working with message state\n- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs\n\n",
107
+ "excerpt": "HTTP Transport The HTTP transport uses standard HTTP requests with Server-Sent Events (SSE) for streaming. This is the simplest and most compatible transport option. When to Use HTTP Transport | Use...",
108
+ "order": 6
109
+ },
101
110
  {
102
111
  "slug": "protocol/overview",
103
112
  "section": "protocol",
@@ -121,7 +130,7 @@
121
130
  "section": "protocol",
122
131
  "title": "Triggers",
123
132
  "description": "Defining how agents are invoked.",
124
- "content": "\n# Triggers\n\nTriggers define how an agent can be invoked. Each trigger has a name, optional inputs, and a corresponding handler.\n\n## Trigger Types\n\n### User Message\n\nThe most common trigger — when a user sends a chat message:\n\n```yaml\ntriggers:\n user-message:\n description: User sends a chat message\n input:\n USER_MESSAGE:\n type: string\n description: The user's message\n```\n\n### User Action\n\nFor UI interactions like button clicks:\n\n```yaml\ntriggers:\n request-human:\n description: User clicks \"Talk to Human\" button\n # No input needed - action is implicit\n\n submit-feedback:\n description: User submits feedback form\n input:\n RATING:\n type: number\n description: Rating from 1-5\n COMMENT:\n type: string\n description: Optional comment\n optional: true\n```\n\n### API Trigger\n\nDirect invocation through the SDK:\n\n```yaml\ntriggers:\n analyze-document:\n description: Analyze an uploaded document\n input:\n DOCUMENT_URL:\n type: string\n ANALYSIS_TYPE:\n type: string\n description: Type of analysis (summary, sentiment, extraction)\n```\n\n## Trigger Definition\n\n```yaml\ntriggers:\n trigger-name:\n description: Optional description\n input:\n VARIABLE_NAME:\n type: string | number | boolean | unknown\n description: What this input is for\n optional: true | false # defaults to false\n default: value # default if optional and not provided\n```\n\n## Invoking Triggers\n\n### From Client SDK\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { send } = useOctavusChat({ transport });\n\n // User message trigger with UI message\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n\n // User action trigger (no input, no UI message)\n await send('request-human');\n\n // Action with input\n await send('submit-feedback', { RATING: 5, COMMENT: 'Great help!' });\n}\n```\n\n### From Server SDK\n\n```typescript\nconst { stream } = session.trigger('user-message', {\n USER_MESSAGE: 'Help me with billing',\n});\n\nconst { stream } = session.trigger('request-human');\n```\n\n## Handlers\n\nEach trigger must have a corresponding handler:\n\n```yaml\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n\n request-human:\n description: Escalate to human support\n\nhandlers:\n user-message:\n # Blocks executed when user-message is triggered\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n\n Respond:\n type: next-message\n\n request-human:\n # Blocks executed when request-human is triggered\n Summarize:\n type: serialize-thread\n # ...\n```\n\n## Trigger Input Naming\n\nTrigger inputs use `UPPERCASE_SNAKE_CASE`:\n\n```yaml\ntriggers:\n search-products:\n input:\n SEARCH_QUERY: { type: string }\n MAX_RESULTS: { type: number, optional: true, default: 10 }\n FILTER_CATEGORY: { type: string, optional: true }\n```\n\n## Best Practices\n\n### 1. Use Descriptive Names\n\n```yaml\n# Good\ntriggers:\n user-message: # Clear - user sends chat message\n request-human: # Clear - wants human support\n cancel-subscription: # Clear - specific action\n\n# Avoid\ntriggers:\n trigger1: # Unclear\n msg: # Too abbreviated\n do-thing: # Vague\n```\n\n### 2. Document Triggers\n\n```yaml\ntriggers:\n escalate-to-tier2:\n description: >\n Escalate the conversation to tier 2 support.\n Should be called when the issue cannot be resolved\n at tier 1 level.\n input:\n REASON:\n type: string\n description: Why escalation is needed\n```\n\n### 3. Keep Triggers Focused\n\nEach trigger should do one thing:\n\n```yaml\n# Good - focused triggers\ntriggers:\n send-message:\n input: { MESSAGE: { type: string } }\n\n upload-file:\n input: { FILE_URL: { type: string } }\n\n request-callback:\n input: { PHONE: { type: string } }\n\n# Avoid - overloaded trigger\ntriggers:\n user-action:\n input:\n ACTION_TYPE: { type: string } # \"message\" | \"file\" | \"callback\"\n PAYLOAD: { type: unknown } # Different structure per type\n```\n",
133
+ "content": "\n# Triggers\n\nTriggers define how an agent can be invoked. Each trigger has a name, optional inputs, and a corresponding handler.\n\n## Trigger Types\n\n### User Message\n\nThe most common trigger — when a user sends a chat message:\n\n```yaml\ntriggers:\n user-message:\n description: User sends a chat message\n input:\n USER_MESSAGE:\n type: string\n description: The user's message\n```\n\n### User Action\n\nFor UI interactions like button clicks:\n\n```yaml\ntriggers:\n request-human:\n description: User clicks \"Talk to Human\" button\n # No input needed - action is implicit\n\n submit-feedback:\n description: User submits feedback form\n input:\n RATING:\n type: number\n description: Rating from 1-5\n COMMENT:\n type: string\n description: Optional comment\n optional: true\n```\n\n### API Trigger\n\nDirect invocation through the SDK:\n\n```yaml\ntriggers:\n analyze-document:\n description: Analyze an uploaded document\n input:\n DOCUMENT_URL:\n type: string\n ANALYSIS_TYPE:\n type: string\n description: Type of analysis (summary, sentiment, extraction)\n```\n\n## Trigger Definition\n\n```yaml\ntriggers:\n trigger-name:\n description: Optional description\n input:\n VARIABLE_NAME:\n type: string | number | boolean | unknown\n description: What this input is for\n optional: true | false # defaults to false\n default: value # default if optional and not provided\n```\n\n## Invoking Triggers\n\n### From Client SDK\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport } from '@octavus/react';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { send } = useOctavusChat({ transport });\n\n // User message trigger with UI message\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n\n // User action trigger (no input, no UI message)\n await send('request-human');\n\n // Action with input\n await send('submit-feedback', { RATING: 5, COMMENT: 'Great help!' });\n}\n```\n\n### From Server SDK\n\n```typescript\n// trigger() returns an async generator of events\nconst events = session.trigger('user-message', {\n USER_MESSAGE: 'Help me with billing',\n});\n\n// Iterate events directly\nfor await (const event of events) {\n console.log(event);\n}\n\n// Or convert to SSE for HTTP responses\nimport { toSSEStream } from '@octavus/server-sdk';\nreturn new Response(toSSEStream(events), { headers: { 'Content-Type': 'text/event-stream' } });\n```\n\n## Handlers\n\nEach trigger must have a corresponding handler:\n\n```yaml\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n\n request-human:\n description: Escalate to human support\n\nhandlers:\n user-message:\n # Blocks executed when user-message is triggered\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n\n Respond:\n type: next-message\n\n request-human:\n # Blocks executed when request-human is triggered\n Summarize:\n type: serialize-thread\n # ...\n```\n\n## Trigger Input Naming\n\nTrigger inputs use `UPPERCASE_SNAKE_CASE`:\n\n```yaml\ntriggers:\n search-products:\n input:\n SEARCH_QUERY: { type: string }\n MAX_RESULTS: { type: number, optional: true, default: 10 }\n FILTER_CATEGORY: { type: string, optional: true }\n```\n\n## Best Practices\n\n### 1. Use Descriptive Names\n\n```yaml\n# Good\ntriggers:\n user-message: # Clear - user sends chat message\n request-human: # Clear - wants human support\n cancel-subscription: # Clear - specific action\n\n# Avoid\ntriggers:\n trigger1: # Unclear\n msg: # Too abbreviated\n do-thing: # Vague\n```\n\n### 2. Document Triggers\n\n```yaml\ntriggers:\n escalate-to-tier2:\n description: >\n Escalate the conversation to tier 2 support.\n Should be called when the issue cannot be resolved\n at tier 1 level.\n input:\n REASON:\n type: string\n description: Why escalation is needed\n```\n\n### 3. Keep Triggers Focused\n\nEach trigger should do one thing:\n\n```yaml\n# Good - focused triggers\ntriggers:\n send-message:\n input: { MESSAGE: { type: string } }\n\n upload-file:\n input: { FILE_URL: { type: string } }\n\n request-callback:\n input: { PHONE: { type: string } }\n\n# Avoid - overloaded trigger\ntriggers:\n user-action:\n input:\n ACTION_TYPE: { type: string } # \"message\" | \"file\" | \"callback\"\n PAYLOAD: { type: unknown } # Different structure per type\n```\n",
125
134
  "excerpt": "Triggers Triggers define how an agent can be invoked. Each trigger has a name, optional inputs, and a corresponding handler. Trigger Types User Message The most common trigger — when a user sends a...",
126
135
  "order": 3
127
136
  },
@@ -157,7 +166,7 @@
157
166
  "section": "api-reference",
158
167
  "title": "Overview",
159
168
  "description": "REST API overview and authentication.",
160
- "content": "\n# API Reference\n\nThe Octavus API is a RESTful API that enables programmatic access to agent management and session execution.\n\n## Base URL\n\n```\nhttps://octavus.ai\n```\n\n## Authentication\n\nAll API requests require authentication using a Bearer token:\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n https://octavus.ai/api/agents\n```\n\nAPI keys can be created in the Octavus Platform under Project Settings API Keys.\n\n## Response Format\n\nAll responses are JSON. Success responses return the data directly (not wrapped in a `data` field).\n\n### Success Response\n\n```json\n{\n \"sessionId\": \"sess_abc123\"\n}\n```\n\n### Error Response\n\n```json\n{\n \"error\": {\n \"code\": \"NOT_FOUND\",\n \"message\": \"Agent not found\"\n }\n}\n```\n\n## HTTP Status Codes\n\n| Code | Description |\n|------|-------------|\n| 200 | Success |\n| 201 | Created |\n| 400 | Bad Request - Invalid parameters |\n| 401 | Unauthorized - Missing or invalid API key |\n| 403 | Forbidden - Insufficient permissions |\n| 404 | Not Found |\n| 429 | Too Many Requests - Rate limited |\n| 500 | Internal Server Error |\n\n## Rate Limits\n\n- **Standard tier**: 100 requests/minute\n- **Pro tier**: 1,000 requests/minute\n- **Enterprise**: Custom limits\n\nRate limit headers are included in responses:\n\n```\nX-RateLimit-Limit: 100\nX-RateLimit-Remaining: 95\nX-RateLimit-Reset: 1735312800\n```\n\n## Endpoints Overview\n\n### Agents\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/agents` | List all agents |\n| GET | `/api/agents/:id` | Get agent by ID |\n| POST | `/api/agents` | Create agent |\n| PATCH | `/api/agents/:id` | Update agent |\n\n### Sessions\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| POST | `/api/agent-sessions` | Create session |\n| GET | `/api/agent-sessions/:id` | Get session state |\n| POST | `/api/agent-sessions/:id/trigger` | Execute trigger (SSE) |\n\n## Streaming\n\nThe trigger endpoint returns Server-Sent Events (SSE):\n\n```bash\ncurl -N -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"triggerName\": \"user-message\", \"input\": {\"USER_MESSAGE\": \"Hello\"}}' \\\n https://octavus.ai/api/agent-sessions/SESSION_ID/trigger\n```\n\nResponse format:\n\n```\ndata: {\"type\":\"start\",\"messageId\":\"...\"}\n\ndata: {\"type\":\"block-start\",\"blockId\":\"...\",\"blockName\":\"Respond\",\"blockType\":\"next-message\",\"display\":\"stream\"}\n\ndata: {\"type\":\"text-start\",\"id\":\"...\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"Hello\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"!\"}\n\ndata: {\"type\":\"text-end\",\"id\":\"...\"}\n\ndata: {\"type\":\"block-end\",\"blockId\":\"...\"}\n\ndata: {\"type\":\"finish\",\"finishReason\":\"stop\"}\n\ndata: [DONE]\n```\n\n## SDKs\n\nWe recommend using our SDKs instead of calling the API directly:\n\n- **Server SDK**: `@octavus/server-sdk` - For Node.js backends\n- **Client SDK**: `@octavus/client-sdk` - For React frontends\n\nThe SDKs handle authentication, streaming, and tool execution automatically.\n\n",
169
+ "content": "\n# API Reference\n\nThe Octavus API is a RESTful API that enables programmatic access to agent management and session execution.\n\n## Base URL\n\n```\nhttps://octavus.ai\n```\n\n## Authentication\n\nAll API requests require authentication using a Bearer token:\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" \\\n https://octavus.ai/api/agents\n```\n\nAPI keys can be created in the Octavus Platform under your project's **API Keys** page.\n\n## Response Format\n\nAll responses are JSON. Success responses return the data directly (not wrapped in a `data` field).\n\n### Success Response\n\n```json\n{\n \"sessionId\": \"sess_abc123\"\n}\n```\n\n### Error Response\n\n```json\n{\n \"error\": {\n \"code\": \"NOT_FOUND\",\n \"message\": \"Agent not found\"\n }\n}\n```\n\n## HTTP Status Codes\n\n| Code | Description |\n|------|-------------|\n| 200 | Success |\n| 201 | Created |\n| 400 | Bad Request - Invalid parameters |\n| 401 | Unauthorized - Missing or invalid API key |\n| 403 | Forbidden - Insufficient permissions |\n| 404 | Not Found |\n| 500 | Internal Server Error |\n\n## Endpoints Overview\n\n### Agents\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/agents` | List all agents |\n| GET | `/api/agents/:id` | Get agent by ID |\n| POST | `/api/agents` | Create agent |\n| PATCH | `/api/agents/:id` | Update agent |\n\n### Sessions\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| POST | `/api/agent-sessions` | Create session |\n| GET | `/api/agent-sessions/:id` | Get session state |\n| POST | `/api/agent-sessions/:id/trigger` | Execute trigger (SSE) |\n\n## Streaming\n\nThe trigger endpoint returns Server-Sent Events (SSE):\n\n```bash\ncurl -N -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"triggerName\": \"user-message\", \"input\": {\"USER_MESSAGE\": \"Hello\"}}' \\\n https://octavus.ai/api/agent-sessions/SESSION_ID/trigger\n```\n\nResponse format:\n\n```\ndata: {\"type\":\"start\",\"messageId\":\"...\"}\n\ndata: {\"type\":\"block-start\",\"blockId\":\"...\",\"blockName\":\"Respond\",\"blockType\":\"next-message\",\"display\":\"stream\"}\n\ndata: {\"type\":\"text-start\",\"id\":\"...\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"Hello\"}\n\ndata: {\"type\":\"text-delta\",\"id\":\"...\",\"delta\":\"!\"}\n\ndata: {\"type\":\"text-end\",\"id\":\"...\"}\n\ndata: {\"type\":\"block-end\",\"blockId\":\"...\"}\n\ndata: {\"type\":\"finish\",\"finishReason\":\"stop\"}\n\ndata: [DONE]\n```\n\n## SDKs\n\nWe recommend using our SDKs instead of calling the API directly:\n\n- **Server SDK**: `@octavus/server-sdk` - For Node.js backends\n- **React SDK**: `@octavus/react` - For React applications\n- **Client SDK**: `@octavus/client-sdk` - For other frontend frameworks\n\nThe SDKs handle authentication, streaming, and tool execution automatically.\n\n",
161
170
  "excerpt": "API Reference The Octavus API is a RESTful API that enables programmatic access to agent management and session execution. Base URL Authentication All API requests require authentication using a...",
162
171
  "order": 1
163
172
  },
@@ -178,5 +187,32 @@
178
187
  "content": "\n# Agents API\n\nManage agent definitions including protocols and prompts.\n\n## List Agents\n\nGet all agents in the project.\n\n```\nGET /api/agents\n```\n\n### Response\n\n```json\n{\n \"agents\": [\n {\n \"id\": \"cm5xvz7k80001abcd\",\n \"slug\": \"support-chat\",\n \"name\": \"Support Chat\",\n \"description\": \"Customer support agent\",\n \"format\": \"interactive\",\n \"createdAt\": \"2024-01-10T08:00:00Z\",\n \"updatedAt\": \"2024-01-15T10:00:00Z\"\n }\n ]\n}\n```\n\n### Example\n\n```bash\ncurl https://octavus.ai/api/agents \\\n -H \"Authorization: Bearer YOUR_API_KEY\"\n```\n\n## Get Agent\n\nGet a single agent by ID or slug.\n\n```\nGET /api/agents/:id\nGET /api/agents/:slug?by=slug\n```\n\n### Response\n\n```json\n{\n \"id\": \"cm5xvz7k80001abcd\",\n \"settings\": {\n \"slug\": \"support-chat\",\n \"name\": \"Support Chat\",\n \"description\": \"Customer support agent\",\n \"format\": \"interactive\"\n },\n \"protocol\": \"input:\\n COMPANY_NAME: { type: string }\\n...\",\n \"prompts\": [\n {\n \"name\": \"system\",\n \"content\": \"You are a support agent for {{COMPANY_NAME}}...\"\n },\n {\n \"name\": \"user-message\",\n \"content\": \"{{USER_MESSAGE}}\"\n }\n ]\n}\n```\n\n### Example\n\n```bash\n# By ID\ncurl https://octavus.ai/api/agents/:agentId \\\n -H \"Authorization: Bearer YOUR_API_KEY\"\n\n# By slug\ncurl \"https://octavus.ai/api/agents/:slug?by=slug\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\"\n```\n\n## Create Agent\n\nCreate a new agent.\n\n```\nPOST /api/agents\n```\n\n### Request Body\n\n```json\n{\n \"settings\": {\n \"slug\": \"support-chat\",\n \"name\": \"Support Chat\",\n \"description\": \"Customer support agent\",\n \"format\": \"interactive\"\n },\n \"protocol\": \"input:\\n COMPANY_NAME: { type: string }\\n...\",\n \"prompts\": [\n {\n \"name\": \"system\",\n \"content\": \"You are a support agent...\"\n }\n ]\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `settings.slug` | string | Yes | URL-safe identifier |\n| `settings.name` | string | Yes | Display name |\n| `settings.description` | string | No | Agent description |\n| `settings.format` | string | Yes | `interactive` or `generation` |\n| `protocol` | string | Yes | YAML protocol definition |\n| `prompts` | array | Yes | Prompt files |\n\n### Response\n\n```json\n{\n \"agentId\": \"cm5xvz7k80001abcd\",\n \"message\": \"Agent created successfully\"\n}\n```\n\n### Example\n\n```bash\ncurl -X POST https://octavus.ai/api/agents \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"settings\": {\n \"slug\": \"my-agent\",\n \"name\": \"My Agent\",\n \"format\": \"interactive\"\n },\n \"protocol\": \"agent:\\n model: anthropic/claude-sonnet-4-5\\n system: system\",\n \"prompts\": [\n { \"name\": \"system\", \"content\": \"You are a helpful assistant.\" }\n ]\n }'\n```\n\n## Update Agent\n\nUpdate an existing agent.\n\n```\nPATCH /api/agents/:id\nPATCH /api/agents/:slug?by=slug\n```\n\n### Request Body\n\n```json\n{\n \"protocol\": \"input:\\n COMPANY_NAME: { type: string }\\n...\",\n \"prompts\": [\n {\n \"name\": \"system\",\n \"content\": \"Updated system prompt...\"\n }\n ]\n}\n```\n\nAll fields are optional. Only provided fields are updated.\n\n### Response\n\n```json\n{\n \"agentId\": \"cm5xvz7k80001abcd\",\n \"message\": \"Agent updated successfully\"\n}\n```\n\n### Example\n\n```bash\ncurl -X PATCH https://octavus.ai/api/agents/:agentId \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"protocol\": \"agent:\\n model: anthropic/claude-sonnet-4-5\\n system: system\\n thinking: high\"\n }'\n```\n\n## Sync Agent\n\nThe Server SDK provides a `sync` method that creates or updates an agent:\n\n```typescript\nconst { agentId, created } = await client.agents.sync({\n settings: {\n slug: 'support-chat',\n name: 'Support Chat',\n format: 'interactive',\n },\n protocol: protocolYaml,\n prompts: [\n { name: 'system', content: systemPrompt },\n ],\n});\n\nif (created) {\n console.log('Created new agent:', agentId);\n} else {\n console.log('Updated existing agent:', agentId);\n}\n```\n\nThis is useful for CI/CD pipelines to deploy agent updates.\n\n",
179
188
  "excerpt": "Agents API Manage agent definitions including protocols and prompts. List Agents Get all agents in the project. Response Example Get Agent Get a single agent by ID or slug. Response Example ...",
180
189
  "order": 3
190
+ },
191
+ {
192
+ "slug": "examples/overview",
193
+ "section": "examples",
194
+ "title": "Overview",
195
+ "description": "Complete integration examples for different architectures.",
196
+ "content": "\n# Examples\n\nThis section provides complete integration examples for different architectures. Each example walks through building a functional chat interface from scratch.\n\n## Available Examples\n\n| Example | Transport | Best For |\n|---------|-----------|----------|\n| [Next.js Chat](/docs/examples/nextjs-chat) | HTTP/SSE | Next.js, Remix, standard web apps |\n| [Socket Chat](/docs/examples/socket-chat) | SockJS | Meteor, Phoenix, real-time apps |\n\n## Choosing a Transport\n\n**Use HTTP Transport when:**\n- Building with Next.js, Remix, or similar frameworks\n- You want the simplest integration\n- Deploying to serverless (Vercel, Netlify, etc.)\n\n**Use Socket Transport when:**\n- Using Meteor, Phoenix, or socket-based frameworks\n- Need custom real-time events (typing indicators, presence)\n- Behind proxies that don't support SSE well\n",
197
+ "excerpt": "Examples This section provides complete integration examples for different architectures. Each example walks through building a functional chat interface from scratch. Available Examples | Example |...",
198
+ "order": 1
199
+ },
200
+ {
201
+ "slug": "examples/nextjs-chat",
202
+ "section": "examples",
203
+ "title": "Next.js Chat",
204
+ "description": "Building a chat interface with Next.js and HTTP transport.",
205
+ "content": "\n# Next.js Chat Example\n\nThis example builds a support chat interface using Next.js App Router with HTTP/SSE transport. This is the recommended pattern for most web applications.\n\n## What You're Building\n\nA chat interface that:\n- Creates sessions server-side\n- Streams AI responses in real-time\n- Handles tool calls on your server\n- Shows typing status during streaming\n\n## Architecture\n\n```mermaid\nflowchart LR\n Browser[\"Browser<br/>(React)\"] -->|\"POST /api/chat\"| NextJS[\"Next.js API<br/>Routes\"]\n NextJS -->|\"SSE\"| Browser\n NextJS --> Platform[\"Octavus Platform\"]\n```\n\n## Prerequisites\n\n- Next.js 14+ with App Router\n- Octavus account with API key\n- An agent configured in Octavus\n\n## Step 1: Install Dependencies\n\n```bash\nnpm install @octavus/server-sdk @octavus/react\n```\n\n## Step 2: Configure Environment\n\n```bash\n# .env.local\nOCTAVUS_API_URL=https://octavus.ai\nOCTAVUS_API_KEY=your-api-key\n```\n\n## Step 3: Create the Octavus Client\n\n```typescript\n// lib/octavus.ts\nimport { OctavusClient } from '@octavus/server-sdk';\n\nexport const octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n```\n\n## Step 4: Create Session Endpoint\n\nSessions hold conversation state. Create one when the user opens the chat:\n\n```typescript\n// app/api/sessions/route.ts\nimport { NextResponse } from 'next/server';\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { agentId, input } = await request.json();\n\n // Create a new session with initial input variables\n const sessionId = await octavus.agentSessions.create(agentId, input);\n\n return NextResponse.json({ sessionId });\n}\n```\n\n**Protocol Note:** The `input` object contains variables defined in your agent's protocol. For example, if your agent has `COMPANY_NAME` as an input variable:\n\n```typescript\nconst sessionId = await octavus.agentSessions.create(agentId, {\n COMPANY_NAME: 'Acme Corp',\n USER_ID: user.id,\n});\n```\n\n## Step 5: Create Trigger Endpoint\n\nTriggers execute agent actions. The `user-message` trigger is the most common:\n\n```typescript\n// app/api/trigger/route.ts\nimport { toSSEStream } from '@octavus/server-sdk';\nimport { octavus } from '@/lib/octavus';\n\nexport async function POST(request: Request) {\n const { sessionId, triggerName, input } = await request.json();\n\n // Attach to the session with tool handlers\n const session = octavus.agentSessions.attach(sessionId, {\n tools: {\n // Tool handlers run on YOUR server, not Octavus\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n // Fetch from your database\n const user = await db.users.findUnique({ where: { id: userId } });\n return {\n name: user.name,\n email: user.email,\n plan: user.plan,\n };\n },\n\n 'create-support-ticket': async (args) => {\n const ticket = await db.tickets.create({\n data: {\n summary: args.summary as string,\n priority: args.priority as string,\n },\n });\n return {\n ticketId: ticket.id,\n estimatedResponse: '24 hours',\n };\n },\n },\n });\n\n // trigger() returns parsed events, toSSEStream() converts to SSE format\n const events = session.trigger(triggerName, input);\n\n return new Response(toSSEStream(events), {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n}\n```\n\n**Protocol Note:** Tool names and arguments are defined in your agent's protocol YAML. The tool handlers here must match those definitions.\n\n## Step 6: Build the Chat Component\n\n```tsx\n// components/Chat.tsx\n'use client';\n\nimport { useState, useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport } from '@octavus/react';\n\ninterface ChatProps {\n sessionId: string;\n}\n\nexport function Chat({ sessionId }: ChatProps) {\n const [inputValue, setInputValue] = useState('');\n\n // Create transport - memoized on sessionId\n const transport = useMemo(\n () =>\n createHttpTransport({\n triggerRequest: (triggerName, input) =>\n fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n }),\n }),\n [sessionId],\n );\n\n const { messages, status, send } = useOctavusChat({ transport });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || status === 'streaming') return;\n\n const message = inputValue.trim();\n setInputValue('');\n\n // Send triggers the 'user-message' action\n // The third argument adds the user message to the UI\n await send(\n 'user-message',\n { USER_MESSAGE: message },\n { userMessage: { content: message } },\n );\n };\n\n return (\n <div className=\"flex flex-col h-screen\">\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.map((msg) => (\n <div\n key={msg.id}\n className={msg.role === 'user' ? 'text-right' : 'text-left'}\n >\n <div\n className={`inline-block p-3 rounded-lg ${\n msg.role === 'user'\n ? 'bg-blue-500 text-white'\n : 'bg-gray-100'\n }`}\n >\n {msg.parts.map((part, i) => {\n if (part.type === 'text') {\n return <p key={i}>{part.text}</p>;\n }\n if (part.type === 'tool-call') {\n return (\n <div key={i} className=\"text-sm opacity-70\">\n Using {part.toolName}...\n </div>\n );\n }\n return null;\n })}\n </div>\n </div>\n ))}\n </div>\n\n {/* Input */}\n <form onSubmit={handleSubmit} className=\"p-4 border-t\">\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n placeholder=\"Type a message...\"\n className=\"flex-1 px-4 py-2 border rounded-lg\"\n disabled={status === 'streaming'}\n />\n <button\n type=\"submit\"\n disabled={status === 'streaming'}\n className=\"px-4 py-2 bg-blue-500 text-white rounded-lg\"\n >\n {status === 'streaming' ? 'Sending...' : 'Send'}\n </button>\n </div>\n </form>\n </div>\n );\n}\n```\n\n## Step 7: Create the Page\n\n```tsx\n// app/chat/page.tsx\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Chat } from '@/components/Chat';\n\nconst AGENT_ID = 'your-agent-id'; // From Octavus dashboard\n\nexport default function ChatPage() {\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n useEffect(() => {\n // Create session on mount\n fetch('/api/sessions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n agentId: AGENT_ID,\n input: {\n COMPANY_NAME: 'Acme Corp',\n },\n }),\n })\n .then((res) => res.json())\n .then((data) => setSessionId(data.sessionId));\n }, []);\n\n if (!sessionId) {\n return <div className=\"p-8\">Loading...</div>;\n }\n\n return <Chat sessionId={sessionId} />;\n}\n```\n\n## Protocol Integration\n\nYour agent's protocol defines the triggers and tools. Here's how the code maps to protocol:\n\n### Triggers\n\n```yaml\n# In your agent's protocol.yaml\ntriggers:\n user-message:\n description: User sends a chat message\n input:\n USER_MESSAGE:\n type: string\n description: The user's message\n```\n\nThe `send()` call maps directly:\n\n```typescript\nawait send(\n 'user-message', // trigger name\n { USER_MESSAGE: message }, // trigger inputs\n { userMessage: { content: message } },\n);\n```\n\n### Tools\n\n```yaml\n# In your agent's protocol.yaml\ntools:\n get-user-account:\n description: Fetch user account details\n parameters:\n userId:\n type: string\n description: The user ID to look up\n```\n\nTool handlers receive the parameters as `args`:\n\n```typescript\n'get-user-account': async (args) => {\n const userId = args.userId as string;\n // ...\n}\n```\n\n## Next Steps\n\n- [Protocol Overview](/docs/protocol/overview) — Define agent behavior\n- [Messages](/docs/client-sdk/messages) — Rich message rendering\n- [Streaming](/docs/client-sdk/streaming) — Advanced streaming UI\n\n",
206
+ "excerpt": "Next.js Chat Example This example builds a support chat interface using Next.js App Router with HTTP/SSE transport. This is the recommended pattern for most web applications. What You're Building A...",
207
+ "order": 2
208
+ },
209
+ {
210
+ "slug": "examples/socket-chat",
211
+ "section": "examples",
212
+ "title": "Socket Chat",
213
+ "description": "Building a chat interface with SockJS for real-time frameworks.",
214
+ "content": "\n# Socket Chat Example\n\nThis example builds a chat interface using SockJS for bidirectional communication. Use this pattern for Meteor, Phoenix, or when you need custom real-time events.\n\n## What You're Building\n\nA chat interface that:\n- Uses SockJS for real-time streaming\n- Manages sessions server-side (client doesn't need sessionId)\n- Supports custom events alongside chat\n- Works with frameworks that use WebSocket-like transports\n\n## Architecture\n\n```mermaid\nflowchart LR\n Browser[\"Browser<br/>(React)\"] <-->|\"SockJS\"| Server[\"Your Server<br/>(Express)\"]\n Server --> Platform[\"Octavus Platform\"]\n```\n\n**Key difference from HTTP:** The server maintains a persistent socket connection and manages sessions internally. The client never needs to know about `sessionId`.\n\n## Prerequisites\n\n- Express (or similar Node.js server)\n- React frontend\n- `sockjs` (server) and `sockjs-client` (client)\n- Octavus account with API key\n\n## Step 1: Install Dependencies\n\n**Server:**\n```bash\nnpm install @octavus/server-sdk sockjs express\nnpm install -D @types/sockjs @types/express\n```\n\n**Client:**\n```bash\nnpm install @octavus/react sockjs-client\nnpm install -D @types/sockjs-client\n```\n\n## Step 2: Configure Environment\n\n```bash\n# .env\nOCTAVUS_API_URL=https://octavus.ai\nOCTAVUS_API_KEY=your-api-key\nOCTAVUS_AGENT_ID=your-agent-id\n```\n\n## Step 3: Create the Octavus Client (Server)\n\n```typescript\n// server/octavus/client.ts\nimport { OctavusClient } from '@octavus/server-sdk';\n\nexport const octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nexport const AGENT_ID = process.env.OCTAVUS_AGENT_ID!;\n```\n\n## Step 4: Create the Socket Handler (Server)\n\nThis is the core of socket integration. Each connection gets its own session:\n\n```typescript\n// server/octavus/socket-handler.ts\nimport type { Connection } from 'sockjs';\nimport { OctavusClient, type AgentSession } from '@octavus/server-sdk';\n\nconst octavus = new OctavusClient({\n baseUrl: process.env.OCTAVUS_API_URL!,\n apiKey: process.env.OCTAVUS_API_KEY!,\n});\n\nconst AGENT_ID = process.env.OCTAVUS_AGENT_ID!;\n\nexport function createSocketHandler() {\n return (conn: Connection) => {\n let session: AgentSession | null = null;\n let abortController: AbortController | null = null;\n\n conn.on('data', (rawData: string) => {\n void handleMessage(rawData);\n });\n\n async function handleMessage(rawData: string) {\n const msg = JSON.parse(rawData);\n\n // Handle stop request\n if (msg.type === 'stop') {\n abortController?.abort();\n return;\n }\n\n // Handle trigger\n if (msg.type === 'trigger') {\n // Create session lazily on first trigger\n if (!session) {\n const sessionId = await octavus.agentSessions.create(AGENT_ID, {\n // Initial input variables from your protocol\n COMPANY_NAME: 'Acme Corp',\n });\n\n session = octavus.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async () => {\n // Fetch from your database\n return { name: 'Demo User', plan: 'pro' };\n },\n 'create-support-ticket': async () => {\n return { ticketId: 'TKT-123', estimatedResponse: '24h' };\n },\n },\n });\n }\n\n abortController = new AbortController();\n\n // trigger() returns parsed events — iterate directly\n const events = session.trigger(msg.triggerName, msg.input);\n\n try {\n for await (const event of events) {\n if (abortController.signal.aborted) break;\n conn.write(JSON.stringify(event));\n }\n } catch {\n // Handle errors\n }\n }\n }\n\n conn.on('close', () => {\n abortController?.abort();\n });\n };\n}\n```\n\n## Step 5: Set Up the Express Server\n\n```typescript\n// server/index.ts\nimport express from 'express';\nimport http from 'http';\nimport sockjs from 'sockjs';\nimport { createSocketHandler } from './octavus/socket-handler';\n\nconst app = express();\nconst server = http.createServer(app);\n\n// Create SockJS server\nconst sockServer = sockjs.createServer({\n prefix: '/octavus',\n log: () => {}, // Silence logs\n});\n\n// Attach handler\nsockServer.on('connection', createSocketHandler());\nsockServer.installHandlers(server);\n\n// Serve your frontend\napp.use(express.static('dist/client'));\n\nserver.listen(3001, () => {\n console.log('Server running on http://localhost:3001');\n});\n```\n\n## Step 6: Create the Socket Hook (Client)\n\n```typescript\n// src/hooks/useOctavusSocket.ts\nimport { useMemo } from 'react';\nimport SockJS from 'sockjs-client';\nimport { useOctavusChat, createSocketTransport, type SocketLike } from '@octavus/react';\n\nfunction connectSocket(): Promise<SocketLike> {\n return new Promise((resolve, reject) => {\n const sock = new SockJS('/octavus');\n\n sock.onopen = () => resolve(sock);\n sock.onerror = () => reject(new Error('Connection failed'));\n });\n}\n\nexport function useOctavusSocket() {\n // Transport is stable - empty deps because server manages sessions\n const transport = useMemo(\n () => createSocketTransport({ connect: connectSocket }),\n [],\n );\n\n const { messages, status, error, send, stop } = useOctavusChat({\n transport,\n onError: (err) => console.error('Chat error:', err),\n });\n\n const sendMessage = async (message: string) => {\n await send(\n 'user-message',\n { USER_MESSAGE: message },\n { userMessage: { content: message } },\n );\n };\n\n return { messages, status, error, sendMessage, stop };\n}\n```\n\n## Step 7: Build the Chat Component\n\n```tsx\n// src/components/Chat.tsx\nimport { useState } from 'react';\nimport { useOctavusSocket } from '../hooks/useOctavusSocket';\n\nexport function Chat() {\n const [inputValue, setInputValue] = useState('');\n const { messages, status, sendMessage, stop } = useOctavusSocket();\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || status === 'streaming') return;\n\n const message = inputValue.trim();\n setInputValue('');\n await sendMessage(message);\n };\n\n return (\n <div className=\"flex flex-col h-screen\">\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.map((msg) => (\n <div\n key={msg.id}\n className={msg.role === 'user' ? 'text-right' : 'text-left'}\n >\n <div\n className={`inline-block p-3 rounded-lg ${\n msg.role === 'user'\n ? 'bg-blue-500 text-white'\n : 'bg-gray-100'\n }`}\n >\n {msg.parts.map((part, i) => {\n if (part.type === 'text') return <p key={i}>{part.text}</p>;\n return null;\n })}\n </div>\n </div>\n ))}\n </div>\n\n {/* Input */}\n <form onSubmit={handleSubmit} className=\"p-4 border-t flex gap-2\">\n <input\n type=\"text\"\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n placeholder=\"Type a message...\"\n className=\"flex-1 px-4 py-2 border rounded-lg\"\n disabled={status === 'streaming'}\n />\n {status === 'streaming' ? (\n <button\n type=\"button\"\n onClick={stop}\n className=\"px-4 py-2 bg-red-500 text-white rounded-lg\"\n >\n Stop\n </button>\n ) : (\n <button\n type=\"submit\"\n className=\"px-4 py-2 bg-blue-500 text-white rounded-lg\"\n >\n Send\n </button>\n )}\n </form>\n </div>\n );\n}\n```\n\n## Custom Events\n\nSocket transport supports custom events alongside Octavus events:\n\n```typescript\n// Client - handle custom events\nconst transport = useMemo(\n () =>\n createSocketTransport({\n connect: connectSocket,\n onMessage: (data) => {\n const msg = data as { type: string; [key: string]: unknown };\n\n if (msg.type === 'typing-indicator') {\n setAgentTyping(msg.isTyping as boolean);\n }\n\n if (msg.type === 'custom-notification') {\n showToast(msg.message as string);\n }\n\n // Octavus events (text-delta, finish, etc.) are handled automatically\n },\n }),\n [],\n);\n```\n\n```typescript\n// Server - send custom events\nconn.write(JSON.stringify({\n type: 'typing-indicator',\n isTyping: true,\n}));\n```\n\n## Protocol Integration\n\n### Triggers\n\nThe socket handler receives trigger messages and forwards them to Octavus:\n\n```typescript\n// Client sends:\n{ type: 'trigger', triggerName: 'user-message', input: { USER_MESSAGE: 'Hello' } }\n\n// Server handles:\nif (msg.type === 'trigger') {\n const events = session.trigger(msg.triggerName, msg.input);\n for await (const event of events) {\n conn.write(JSON.stringify(event));\n }\n}\n```\n\n### Tools\n\nTools are defined in your agent's protocol and handled server-side:\n\n```yaml\n# protocol.yaml\ntools:\n get-user-account:\n description: Fetch user details\n parameters:\n userId:\n type: string\n```\n\n```typescript\n// Server tool handler\ntools: {\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\n return await db.users.find(userId);\n },\n}\n```\n\n## Meteor Integration Note\n\nMeteor's bundler may have issues with ES6 imports of `sockjs-client`:\n\n```typescript\n// Use require() instead of import\nconst SockJS: typeof import('sockjs-client') = require('sockjs-client');\n```\n\n## Next Steps\n\n- [Socket Transport](/docs/client-sdk/socket-transport) — Advanced socket patterns\n- [Protocol Overview](/docs/protocol/overview) — Define agent behavior\n- [Tools](/docs/protocol/tools) — Building tool handlers\n\n",
215
+ "excerpt": "Socket Chat Example This example builds a chat interface using SockJS for bidirectional communication. Use this pattern for Meteor, Phoenix, or when you need custom real-time events. What You're...",
216
+ "order": 3
181
217
  }
182
218
  ]
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  getDocBySlug,
3
3
  getDocSections,
4
4
  getDocSlugs
5
- } from "./chunk-232K4EME.js";
5
+ } from "./chunk-H6JGSSAJ.js";
6
6
  export {
7
7
  getDocBySlug,
8
8
  getDocSections,