@octavus/docs 0.0.5 → 0.0.7
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.
- package/content/01-getting-started/01-introduction.md +1 -1
- package/content/01-getting-started/02-quickstart.md +26 -18
- package/content/02-server-sdk/01-overview.md +24 -13
- package/content/03-client-sdk/01-overview.md +173 -37
- package/content/03-client-sdk/02-messages.md +73 -21
- package/content/03-client-sdk/03-streaming.md +40 -30
- package/content/03-client-sdk/04-execution-blocks.md +2 -2
- package/content/03-client-sdk/05-socket-transport.md +304 -0
- package/content/03-client-sdk/_meta.md +1 -1
- package/content/04-protocol/02-input-resources.md +2 -0
- package/content/04-protocol/03-triggers.md +39 -20
- package/content/04-protocol/04-tools.md +25 -15
- package/dist/chunk-232K4EME.js +439 -0
- package/dist/chunk-232K4EME.js.map +1 -0
- package/dist/chunk-2JDZLMS3.js +439 -0
- package/dist/chunk-2JDZLMS3.js.map +1 -0
- package/dist/chunk-4WWUKU4V.js +421 -0
- package/dist/chunk-4WWUKU4V.js.map +1 -0
- package/dist/chunk-7AS4ST73.js +421 -0
- package/dist/chunk-7AS4ST73.js.map +1 -0
- package/dist/chunk-IUKE3XDN.js +421 -0
- package/dist/chunk-IUKE3XDN.js.map +1 -0
- package/dist/chunk-JOB6YWEF.js +421 -0
- package/dist/chunk-JOB6YWEF.js.map +1 -0
- package/dist/chunk-OECAPVSX.js +439 -0
- package/dist/chunk-OECAPVSX.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +21 -12
- package/dist/index.js +1 -1
- package/dist/search-index.json +1 -1
- package/dist/search.js +1 -1
- package/dist/search.js.map +1 -1
- package/dist/sections.json +22 -13
- package/package.json +2 -2
package/dist/sections.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"section": "getting-started",
|
|
11
11
|
"title": "Introduction",
|
|
12
12
|
"description": "Overview of Octavus AI - an agent orchestration platform for developers.",
|
|
13
|
-
"content": "\n# Introduction to Octavus\n\nOctavus is an agent orchestration platform that lets developers define, manage, and deploy AI agents through a unified service. It handles the orchestration layer so teams can focus on their agent logic and business requirements.\n\n## What is Octavus?\n\nBuilding and managing AI agents is complex. Developers face challenges with:\n\n- **Fragmented tooling** — No unified way to define, manage, and deploy agents\n- **Prompt management** — Prompts are scattered across codebases, hard to version and iterate\n- **Integration complexity** — Connecting agents to tools, resources, and other agents requires significant custom work\n- **Observability** — Difficult to debug, monitor, and understand agent behavior in production\n- **Infrastructure overhead** — Teams rebuild the same agent infrastructure repeatedly\n\nOctavus solves these problems by providing:\n\n- A **protocol-based approach** to defining agent behavior\n- **Server and client SDKs** for easy integration\n- **Built-in streaming** support for real-time responses\n- **Tool execution** that runs on your servers with your data\n- **Session management** for stateful conversations\n\n## Core Concepts\n\n### Agents\n\nAn **Agent** is the main entity in Octavus — a self-contained unit that defines how an AI agent behaves. Agents are defined using YAML protocols that specify:\n\n- Input variables the agent accepts\n- Triggers that invoke the agent (user messages, button clicks, API calls)\n- Tools the agent can use\n- Handlers that define execution flow\n\n### Sessions\n\nA **Session** represents a conversation with an agent. Sessions:\n\n- Store conversation history\n- Track resources and variables\n- Enable stateful interactions across multiple messages\n\n### Triggers\n\n**Triggers** define how an agent is invoked:\n\n- **User Message** — Respond to a text message in a chat interface\n- **User Action** — Respond to UI actions (button clicks, form submissions)\n- **API Call** — Direct invocation via SDK\n\n### Tools\n\n**Tools** extend what agents can do:\n\n- **External Tools** — Consumer-defined tools that call back to your systems\n- **Internal Tools** — Built-in capabilities (web search, code execution)\n\nTools execute on your server, not on Octavus, giving you full control over data and authentication.\n\n## Architecture Overview\n\n```mermaid\nsequenceDiagram\n participant App as Your App\n participant API as Octavus API\n participant LLM as LLM Provider\n\n App->>API: 1. Trigger action\n API->>LLM: 2. Execute protocol\n LLM-->>API: Response\n API-->>App: 3. Stream events\n \n Note over App: Tool request received\n API-->>App: 4. Tool request\n Note over App: 5. Execute tool locally\n App->>API: 6. Return results\n \n API->>LLM: 7. Continue\n LLM-->>API: Response\n API-->>App: 8. Stream response\n```\n\n## Next Steps\n\n- [Quick Start](/docs/getting-started/quickstart) — Get your first agent running in minutes\n- [Server SDK](/docs/server-sdk/overview) — Learn about backend integration\n- [Client SDK](/docs/client-sdk/overview) — Build chat interfaces with React\n- [Protocol Reference](/docs/protocol/overview) — Deep dive into agent protocols\n\n",
|
|
13
|
+
"content": "\n# Introduction to Octavus\n\nOctavus is an agent orchestration platform that lets developers define, manage, and deploy AI agents through a unified service. It handles the orchestration layer so teams can focus on their agent logic and business requirements.\n\n## What is Octavus?\n\nBuilding and managing AI agents is complex. Developers face challenges with:\n\n- **Fragmented tooling** — No unified way to define, manage, and deploy agents\n- **Prompt management** — Prompts are scattered across codebases, hard to version and iterate\n- **Integration complexity** — Connecting agents to tools, resources, and other agents requires significant custom work\n- **Observability** — Difficult to debug, monitor, and understand agent behavior in production\n- **Infrastructure overhead** — Teams rebuild the same agent infrastructure repeatedly\n\nOctavus solves these problems by providing:\n\n- A **protocol-based approach** to defining agent behavior\n- **Server and client SDKs** for easy integration\n- **Built-in streaming** support for real-time responses\n- **Tool execution** that runs on your servers with your data\n- **Session management** for stateful conversations\n\n## Core Concepts\n\n### Agents\n\nAn **Agent** is the main entity in Octavus — a self-contained unit that defines how an AI agent behaves. Agents are defined using YAML protocols that specify:\n\n- Input variables the agent accepts\n- Triggers that invoke the agent (user messages, button clicks, API calls)\n- Tools the agent can use\n- Handlers that define execution flow\n\n### Sessions\n\nA **Session** represents a conversation with an agent. Sessions:\n\n- Store conversation history\n- Track resources and variables\n- Enable stateful interactions across multiple messages\n\n### Triggers\n\n**Triggers** define how an agent is invoked:\n\n- **User Message** — Respond to a text message in a chat interface\n- **User Action** — Respond to UI actions (button clicks, form submissions)\n- **API Call** — Direct invocation via SDK\n\n### Tools\n\n**Tools** extend what agents can do:\n\n- **External Tools** — Consumer-defined tools that call back to your systems\n- **Internal Tools** — Built-in capabilities (web search, code execution)\n\nTools execute on your server, not on Octavus, giving you full control over data and authentication.\n\n## Architecture Overview\n\n```mermaid\nsequenceDiagram\n participant App as Your App\n participant API as Octavus API\n participant LLM as LLM Provider\n\n App->>API: 1. Trigger action\n API->>LLM: 2. Execute protocol\n LLM-->>API: Response\n API-->>App: 3. Stream events\n \n Note over App: Tool request received\n API-->>App: 4. Tool request\n Note over App: 5. Execute tool locally\n App->>API: 6. Return results\n \n API->>LLM: 7. Continue\n LLM-->>API: Response\n API-->>App: 8. Stream response\n```\n\n## Next Steps\n\n- [Quick Start](/docs/getting-started/quickstart) — Get your first agent running in minutes\n- [Server SDK](/docs/server-sdk/overview) — Learn about backend integration\n- [Client SDK](/docs/client-sdk/overview) — Build chat interfaces with React (or other frameworks)\n- [Protocol Reference](/docs/protocol/overview) — Deep dive into agent protocols\n\n",
|
|
14
14
|
"excerpt": "Introduction to Octavus Octavus is an agent orchestration platform that lets developers define, manage, and deploy AI agents through a unified service. It handles the orchestration layer so teams can...",
|
|
15
15
|
"order": 1
|
|
16
16
|
},
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"section": "getting-started",
|
|
20
20
|
"title": "Quick Start",
|
|
21
21
|
"description": "Get your first Octavus agent running in minutes.",
|
|
22
|
-
"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#
|
|
22
|
+
"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",
|
|
23
23
|
"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...",
|
|
24
24
|
"order": 2
|
|
25
25
|
}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"section": "server-sdk",
|
|
37
37
|
"title": "Overview",
|
|
38
38
|
"description": "Introduction to the Octavus Server SDK for backend integration.",
|
|
39
|
-
"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.
|
|
39
|
+
"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",
|
|
40
40
|
"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...",
|
|
41
41
|
"order": 1
|
|
42
42
|
},
|
|
@@ -72,16 +72,16 @@
|
|
|
72
72
|
{
|
|
73
73
|
"slug": "client-sdk",
|
|
74
74
|
"title": "Client SDK",
|
|
75
|
-
"description": "Frontend integration with @octavus/client-sdk for
|
|
75
|
+
"description": "Frontend integration with @octavus/react for React applications and @octavus/client-sdk for other frameworks.",
|
|
76
76
|
"order": 3,
|
|
77
77
|
"docs": [
|
|
78
78
|
{
|
|
79
79
|
"slug": "client-sdk/overview",
|
|
80
80
|
"section": "client-sdk",
|
|
81
81
|
"title": "Overview",
|
|
82
|
-
"description": "Introduction to the Octavus Client
|
|
83
|
-
"content": "\n# Client SDK Overview\n\
|
|
84
|
-
"excerpt": "Client SDK Overview
|
|
82
|
+
"description": "Introduction to the Octavus Client SDKs for building chat interfaces.",
|
|
83
|
+
"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",
|
|
84
|
+
"excerpt": "Client SDK Overview Octavus provides two packages for frontend integration: | Package | Purpose | Use When | |---------|---------|----------| | | React hooks and bindings | Building React...",
|
|
85
85
|
"order": 1
|
|
86
86
|
},
|
|
87
87
|
{
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"section": "client-sdk",
|
|
90
90
|
"title": "Messages",
|
|
91
91
|
"description": "Working with message state in the Client SDK.",
|
|
92
|
-
"content": "\n# Messages\n\nMessages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content through typed parts.\n\n## Message Structure\n\n```typescript\ninterface UIMessage {\n id: string;\n role: 'user' | 'assistant';\n parts: UIMessagePart[];\n status: 'streaming' | 'done';\n createdAt: Date;\n}\n```\n\n### Message Parts\n\nMessages contain ordered `parts` that preserve content ordering:\n\n```typescript\ntype UIMessagePart
|
|
92
|
+
"content": "\n# Messages\n\nMessages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content through typed parts.\n\n## Message Structure\n\n```typescript\ninterface UIMessage {\n id: string;\n role: 'user' | 'assistant';\n parts: UIMessagePart[];\n status: 'streaming' | 'done';\n createdAt: Date;\n}\n```\n\n### Message Parts\n\nMessages contain ordered `parts` that preserve content ordering:\n\n```typescript\ntype UIMessagePart =\n | UITextPart\n | UIReasoningPart\n | UIToolCallPart\n | UIOperationPart;\n\n// Text content\ninterface UITextPart {\n type: 'text';\n text: string;\n status: 'streaming' | 'done';\n thread?: string; // For named threads (e.g., \"summary\")\n}\n\n// Extended reasoning/thinking\ninterface UIReasoningPart {\n type: 'reasoning';\n text: string;\n status: 'streaming' | 'done';\n thread?: string;\n}\n\n// Tool execution\ninterface UIToolCallPart {\n type: 'tool-call';\n toolCallId: string;\n toolName: string;\n displayName?: string; // Human-readable name\n args: Record<string, unknown>;\n result?: unknown;\n error?: string;\n status: 'pending' | 'running' | 'done' | 'error';\n thread?: string;\n}\n\n// Internal operations (set-resource, serialize-thread)\ninterface UIOperationPart {\n type: 'operation';\n operationId: string;\n name: string;\n operationType: string;\n status: 'running' | 'done';\n thread?: string;\n}\n```\n\n## Sending Messages\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 async function handleSend(text: string) {\n // Add user message to UI and trigger agent\n await send(\n 'user-message',\n { USER_MESSAGE: text },\n { userMessage: { content: text } },\n );\n }\n\n // ...\n}\n```\n\nThe `send` function:\n1. Adds the user message to the UI immediately (if `userMessage` is provided)\n2. Triggers the agent with the specified trigger name and input\n3. Streams the assistant's response back\n\n## Rendering Messages\n\n### Basic Rendering\n\n```tsx\nfunction MessageList({ messages }: { messages: UIMessage[] }) {\n return (\n <div className=\"space-y-4\">\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n </div>\n );\n}\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n const isUser = message.role === 'user';\n\n return (\n <div className={isUser ? 'text-right' : 'text-left'}>\n <div className=\"inline-block p-3 rounded-lg\">\n {message.parts.map((part, i) => (\n <PartRenderer key={i} part={part} />\n ))}\n </div>\n </div>\n );\n}\n```\n\n### Rendering Parts\n\n```tsx\nimport { isOtherThread, type UIMessagePart } from '@octavus/react';\n\nfunction PartRenderer({ part }: { part: UIMessagePart }) {\n // Check if part belongs to a named thread (e.g., \"summary\")\n if (isOtherThread(part)) {\n return <OtherThreadPart part={part} />;\n }\n\n switch (part.type) {\n case 'text':\n return <TextPart part={part} />;\n\n case 'reasoning':\n return (\n <details className=\"text-gray-500\">\n <summary>Thinking...</summary>\n <pre className=\"text-sm\">{part.text}</pre>\n </details>\n );\n\n case 'tool-call':\n return (\n <div className=\"bg-gray-100 p-2 rounded text-sm\">\n 🔧 {part.displayName || part.toolName}\n {part.status === 'done' && ' ✓'}\n {part.status === 'error' && ` ✗ ${part.error}`}\n </div>\n );\n\n case 'operation':\n return (\n <div className=\"text-gray-500 text-sm\">\n {part.name}\n {part.status === 'done' && ' ✓'}\n </div>\n );\n\n default:\n return null;\n }\n}\n\nfunction TextPart({ part }: { part: UITextPart }) {\n return (\n <p>\n {part.text}\n {part.status === 'streaming' && (\n <span className=\"inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1\" />\n )}\n </p>\n );\n}\n```\n\n## Named Threads\n\nContent from named threads (like \"summary\") is identified by the `thread` property. Use the `isOtherThread` helper:\n\n```tsx\nimport { isOtherThread } from '@octavus/react';\n\nfunction PartRenderer({ part }: { part: UIMessagePart }) {\n if (isOtherThread(part)) {\n // Render differently for named threads\n return (\n <div className=\"bg-amber-50 p-2 rounded border border-amber-200\">\n <span className=\"text-amber-600 text-sm\">\n {part.thread}: {part.type === 'text' && part.text}\n </span>\n </div>\n );\n }\n\n // Regular rendering for main thread\n // ...\n}\n```\n\n## Session Restore\n\nWhen restoring a session, fetch messages from your backend and pass them to the hook:\n\n```tsx\nimport { useMemo } from 'react';\nimport { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';\n\ninterface ChatProps {\n sessionId: string;\n initialMessages: UIMessage[];\n}\n\nfunction Chat({ sessionId, initialMessages }: ChatProps) {\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 // Pass existing messages to restore the conversation\n const { messages } = useOctavusChat({\n transport,\n initialMessages,\n });\n\n // ...\n}\n```\n\nOn your backend, use `agentSessions.getMessages()` to fetch UI-ready messages:\n\n```typescript\n// Server-side\nconst session = await client.agentSessions.getMessages(sessionId);\n// session.messages is UIMessage[] ready for the client\n```\n\n## Callbacks\n\n```tsx\nuseOctavusChat({\n transport,\n onFinish: () => {\n console.log('Stream completed');\n // Scroll to bottom, play sound, etc.\n },\n onError: (error) => {\n console.error('Error:', error);\n toast.error('Failed to get response');\n },\n onResourceUpdate: (name, value) => {\n console.log('Resource updated:', name, value);\n },\n});\n```\n",
|
|
93
93
|
"excerpt": "Messages Messages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content through typed parts. Message Structure Message...",
|
|
94
94
|
"order": 2
|
|
95
95
|
},
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"section": "client-sdk",
|
|
99
99
|
"title": "Streaming",
|
|
100
100
|
"description": "Building streaming UIs with the Client SDK.",
|
|
101
|
-
"content": "\n# Streaming\n\nThe Client SDK provides real-time access to streaming content through the message `parts` array. Each part has its own status, enabling responsive UIs that update as the agent generates responses.\n\n## Streaming State\n\n```tsx\nconst { messages, status, error } = useOctavusChat({
|
|
101
|
+
"content": "\n# Streaming\n\nThe Client SDK provides real-time access to streaming content through the message `parts` array. Each part has its own status, enabling responsive UIs that update as the agent generates responses.\n\n## Streaming State\n\n```tsx\nconst { messages, status, error } = useOctavusChat({ transport });\n\n// status: 'idle' | 'streaming' | 'error'\n// Each message has status: 'streaming' | 'done'\n// Each part has its own status too\n```\n\n## Building a Streaming UI\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 return (\n <div>\n {/* Messages with streaming parts */}\n {messages.map((msg) => (\n <MessageBubble key={msg.id} message={msg} />\n ))}\n\n {/* Error state */}\n {error && <div className=\"text-red-500\">{error.message}</div>}\n\n {/* Stop button during streaming */}\n {status === 'streaming' && <button onClick={stop}>Stop</button>}\n </div>\n );\n}\n```\n\n## Rendering Streaming Parts\n\nParts update in real-time during streaming. Use the part's `status` to show appropriate UI:\n\n```tsx\nimport type { UITextPart, UIReasoningPart } from '@octavus/react';\n\nfunction TextPart({ part }: { part: UITextPart }) {\n return (\n <div>\n {part.text}\n {part.status === 'streaming' && (\n <span className=\"inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1\" />\n )}\n </div>\n );\n}\n\nfunction ReasoningPart({ part }: { part: UIReasoningPart }) {\n // Expand while streaming, collapse when done\n const [expanded, setExpanded] = useState(part.status === 'streaming');\n\n return (\n <div className=\"bg-purple-50 p-3 rounded-lg\">\n <button onClick={() => setExpanded(!expanded)}>\n {part.status === 'streaming' ? '💭 Thinking...' : '💭 Thought process'}\n {expanded ? '▼' : '▶'}\n </button>\n\n {expanded && (\n <pre className=\"mt-2 text-sm text-gray-600\">{part.text}</pre>\n )}\n </div>\n );\n}\n```\n\n## Tool Call States\n\nTool calls progress through multiple states:\n\n```tsx\nimport type { UIToolCallPart } from '@octavus/react';\n\nfunction ToolCallPart({ part }: { part: UIToolCallPart }) {\n return (\n <div className=\"border rounded p-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-lg\">🔧</span>\n <span className=\"font-medium\">{part.displayName || part.toolName}</span>\n <StatusBadge status={part.status} />\n </div>\n\n {/* Show result when done */}\n {part.status === 'done' && part.result && (\n <pre className=\"mt-2 text-xs bg-gray-50 p-2 rounded\">\n {JSON.stringify(part.result, null, 2)}\n </pre>\n )}\n\n {/* Show error if failed */}\n {part.status === 'error' && (\n <p className=\"mt-2 text-red-500 text-sm\">{part.error}</p>\n )}\n </div>\n );\n}\n\nfunction StatusBadge({ status }: { status: UIToolCallPart['status'] }) {\n switch (status) {\n case 'pending':\n return <span className=\"text-gray-400\">○</span>;\n case 'running':\n return <span className=\"text-blue-500 animate-spin\">◐</span>;\n case 'done':\n return <span className=\"text-green-500\">✓</span>;\n case 'error':\n return <span className=\"text-red-500\">✗</span>;\n }\n}\n```\n\n## Status Indicator\n\n```tsx\nfunction StatusIndicator({ status }: { status: ChatStatus }) {\n switch (status) {\n case 'idle':\n return null;\n case 'streaming':\n return <div>Agent is responding...</div>;\n case 'error':\n return <div className=\"text-red-500\">Something went wrong</div>;\n }\n}\n```\n\n## Handling Completion\n\n```tsx\nuseOctavusChat({\n transport,\n onFinish: () => {\n console.log('Stream completed');\n // Scroll to bottom, play sound, etc.\n },\n onError: (error) => {\n console.error('Stream error:', error);\n toast.error('Failed to get response');\n },\n});\n```\n\n## Stop Function\n\nStop the current stream and finalize any partial message:\n\n```tsx\nconst { status, stop } = useOctavusChat({ transport });\n\n// Stop button\n{status === 'streaming' && (\n <button onClick={stop} className=\"text-gray-500\">\n Stop generating\n </button>\n)}\n```\n\nWhen `stop()` is called:\n1. The current request is aborted\n2. Any partial message is finalized with current content\n3. Status changes to `'idle'`\n\n## Named Thread Content\n\nContent from named threads (like \"summary\") streams separately and is identified by the `thread` property:\n\n```tsx\nimport { isOtherThread, type UIMessage } from '@octavus/react';\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n // Separate main thread from named threads\n const mainParts = message.parts.filter((p) => !isOtherThread(p));\n const otherParts = message.parts.filter((p) => isOtherThread(p));\n\n return (\n <div>\n {/* Main conversation */}\n {mainParts.map((part, i) => (\n <PartRenderer key={i} part={part} />\n ))}\n\n {/* Named thread content (e.g., summarization) */}\n {otherParts.length > 0 && (\n <div className=\"bg-amber-50 p-3 rounded mt-4 border border-amber-200\">\n <div className=\"text-amber-600 font-medium mb-2\">\n Background processing\n </div>\n {otherParts.map((part, i) => (\n <PartRenderer key={i} part={part} />\n ))}\n </div>\n )}\n </div>\n );\n}\n```\n",
|
|
102
102
|
"excerpt": "Streaming The Client SDK provides real-time access to streaming content through the message array. Each part has its own status, enabling responsive UIs that update as the agent generates responses....",
|
|
103
103
|
"order": 3
|
|
104
104
|
},
|
|
@@ -107,9 +107,18 @@
|
|
|
107
107
|
"section": "client-sdk",
|
|
108
108
|
"title": "Operations",
|
|
109
109
|
"description": "Showing agent operations and progress with the Client SDK.",
|
|
110
|
-
"content": "\n# Operations\n\nOperations represent internal agent activities like setting resources or serializing threads. They appear as `operation` parts in messages and help users understand what the agent is doing.\n\n## Operation Structure\n\n```typescript\ninterface UIOperationPart {\n type: 'operation';\n operationId: string;\n name: string; // Human-readable name\n operationType: string; // e.g., 'set-resource', 'serialize-thread'\n status: 'running' | 'done';\n thread?: string; // For named threads\n}\n```\n\n## Rendering Operations\n\nOperations are typically shown as compact status indicators:\n\n```tsx\nimport type { UIOperationPart } from '@octavus/
|
|
110
|
+
"content": "\n# Operations\n\nOperations represent internal agent activities like setting resources or serializing threads. They appear as `operation` parts in messages and help users understand what the agent is doing.\n\n## Operation Structure\n\n```typescript\ninterface UIOperationPart {\n type: 'operation';\n operationId: string;\n name: string; // Human-readable name\n operationType: string; // e.g., 'set-resource', 'serialize-thread'\n status: 'running' | 'done';\n thread?: string; // For named threads\n}\n```\n\n## Rendering Operations\n\nOperations are typically shown as compact status indicators:\n\n```tsx\nimport type { UIOperationPart } from '@octavus/react';\n\nfunction OperationCard({ operation }: { operation: UIOperationPart }) {\n return (\n <div className=\"flex items-center gap-2 text-sm text-gray-500\">\n {operation.status === 'running' ? (\n <span className=\"h-2 w-2 animate-pulse rounded-full bg-blue-500\" />\n ) : (\n <span className=\"text-green-500\">✓</span>\n )}\n <span>{operation.name}</span>\n </div>\n );\n}\n```\n\n## Operations in Messages\n\nOperations appear alongside text, reasoning, and tool calls in the message's `parts` array:\n\n```tsx\nimport type { UIMessage, UIMessagePart } from '@octavus/react';\n\nfunction MessageBubble({ message }: { message: UIMessage }) {\n return (\n <div>\n {message.parts.map((part, i) => (\n <PartRenderer key={i} part={part} />\n ))}\n </div>\n );\n}\n\nfunction PartRenderer({ part }: { part: UIMessagePart }) {\n switch (part.type) {\n case 'text':\n return <TextPart part={part} />;\n case 'reasoning':\n return <ReasoningPart part={part} />;\n case 'tool-call':\n return <ToolCallCard part={part} />;\n case 'operation':\n return <OperationCard operation={part} />;\n default:\n return null;\n }\n}\n```\n\n## Common Operation Types\n\n| Type | Description |\n|------|-------------|\n| `set-resource` | Updating a resource value |\n| `serialize-thread` | Converting thread messages to text |\n\n## Example: Progress During Escalation\n\nWhen a user clicks \"Talk to Human\", multiple operations may occur:\n\n```tsx\nfunction EscalationProgress({ message }: { message: UIMessage }) {\n const operations = message.parts.filter(\n (p): p is UIOperationPart => p.type === 'operation'\n );\n\n return (\n <div className=\"space-y-2\">\n {operations.map((op) => (\n <div key={op.operationId} className=\"flex items-center gap-2 text-sm\">\n {op.status === 'running' ? '⏳' : '✓'}\n <span>{op.name}</span>\n </div>\n ))}\n </div>\n );\n}\n\n// Example output during escalation:\n// ✓ Serialize conversation\n// ✓ Save conversation summary\n// ⏳ Creating support ticket...\n```\n\n## Display Modes\n\nOperations are only sent to the client if their protocol block has a visible display mode (`name`, `description`, or `stream`). Hidden operations (`display: hidden`) are filtered out by the platform before reaching the client.\n\nThis means you can safely render all operations without checking display mode — hidden ones won't be in the message parts.\n\n## Named Thread Operations\n\nOperations can belong to named threads. Use the `thread` property to identify them:\n\n```tsx\nfunction OperationCard({ operation }: { operation: UIOperationPart }) {\n return (\n <div className=\"flex items-center gap-2 text-sm\">\n {operation.thread && (\n <span className=\"text-amber-500\">[{operation.thread}]</span>\n )}\n <span>{operation.name}</span>\n {operation.status === 'done' && <span className=\"text-green-500\">✓</span>}\n </div>\n );\n}\n```\n",
|
|
111
111
|
"excerpt": "Operations Operations represent internal agent activities like setting resources or serializing threads. They appear as parts in messages and help users understand what the agent is doing. ...",
|
|
112
112
|
"order": 4
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"slug": "client-sdk/socket-transport",
|
|
116
|
+
"section": "client-sdk",
|
|
117
|
+
"title": "Socket Transport",
|
|
118
|
+
"description": "Using WebSocket or SockJS for real-time streaming with Octavus.",
|
|
119
|
+
"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",
|
|
120
|
+
"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...",
|
|
121
|
+
"order": 5
|
|
113
122
|
}
|
|
114
123
|
]
|
|
115
124
|
},
|
|
@@ -133,7 +142,7 @@
|
|
|
133
142
|
"section": "protocol",
|
|
134
143
|
"title": "Input & Resources",
|
|
135
144
|
"description": "Defining agent inputs and persistent resources.",
|
|
136
|
-
"content": "\n# Input & Resources\n\nInputs are provided when creating a session. Resources are persistent state the agent can read and write.\n\n## Input Variables\n\nDefine inputs that consumers must (or may) provide:\n\n```yaml\ninput:\n # Required input\n COMPANY_NAME:\n type: string\n description: The company name to use in responses\n\n # Required input with description\n PRODUCT_NAME:\n type: string\n description: Product being supported\n\n # Optional input (defaults to \"NONE\")\n SUPPORT_POLICIES:\n type: string\n description: Company policies for support\n optional: true\n\n # Optional input with custom default\n USER_ID:\n type: string\n description: Current user's ID\n optional: true\n default: \"\"\n```\n\n### Input Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this input is for |\n| `optional` | No | If true, consumer doesn't have to provide it |\n| `default` | No | Default value if not provided (defaults to `\"NONE\"`) |\n\n### Using Inputs\n\nWhen creating a session, pass input values:\n\n```typescript\nconst sessionId = await client.agentSessions.create('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n SUPPORT_POLICIES: 'Refunds within 30 days...',\n // USER_ID is optional, not provided\n});\n```\n\nIn prompts, reference with `{{INPUT_NAME}}`:\n\n```markdown\nYou are a support agent for {{COMPANY_NAME}}.\n```\n\n## Resources\n\nResources are persistent state that:\n- Survive across triggers\n- Can be read and written by the agent\n- Are synced to the consumer's application\n\n```yaml\nresources:\n # String resource with default\n CONVERSATION_SUMMARY:\n type: string\n description: Running summary of the conversation\n default: \"\"\n\n # Resource with unknown type (for complex data)\n USER_CONTEXT:\n type: unknown\n description: Cached user information\n default: {}\n\n # Read-only resource (agent can read but not write)\n SYSTEM_CONFIG:\n type: unknown\n description: System configuration\n readonly: true\n default:\n maxRetries: 3\n timeout: 30000\n```\n\n### Resource Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes the resource purpose |\n| `default` | No | Initial value |\n| `readonly` | No | If true, agent cannot write to it |\n\n### Writing Resources\n\nUse the `set-resource` block in handlers:\n\n```yaml\nhandlers:\n request-human:\n # ... generate summary ...\n \n Save summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY # Variable containing the value\n```\n\n### Resource Events\n\nWhen a resource is updated, the client SDK receives a `resource-update` event:\n\n```typescript\nuseOctavusChat({\n onResourceUpdate: (name, value) => {\n if (name === 'CONVERSATION_SUMMARY') {\n console.log('Summary updated:', value);\n }\n },\n});\n```\n\n## Variables\n\nVariables are internal state managed by block outputs. They persist across triggers but are not synced to the consumer (unlike resources).\n\n```yaml\nvariables:\n SUMMARY:\n type: string\n description: Generated summary text\n TICKET:\n type: unknown\n description: Ticket creation result\n CONVERSATION_TEXT:\n type: string\n description: Serialized conversation\n```\n\n### Variable Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this variable stores |\n| `default` | No | Initial value |\n\n### Using Variables\n\nSet variables as output from blocks:\n\n```yaml\nhandlers:\n request-human:\n Serialize conversation:\n type: serialize-thread\n format: markdown\n output: CONVERSATION_TEXT # Stores result in variable\n \n Generate summary:\n type: next-message\n output: SUMMARY # LLM output stored in variable\n \n Create ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY # Use variable as input\n output: TICKET\n```\n\n## Scoping\n\n| Type | Scope | Persistence | Synced to Consumer |\n|------|-------|-------------|---------------------|\n| `input` | Session | Immutable | Yes (at creation) |\n| `resources` | Session | Persists across triggers | Yes (via callbacks) |\n| `variables` | Session | Persists across triggers | No (internal only) |\n\n",
|
|
145
|
+
"content": "\n# Input & Resources\n\nInputs are provided when creating a session. Resources are persistent state the agent can read and write.\n\n## Input Variables\n\nDefine inputs that consumers must (or may) provide:\n\n```yaml\ninput:\n # Required input\n COMPANY_NAME:\n type: string\n description: The company name to use in responses\n\n # Required input with description\n PRODUCT_NAME:\n type: string\n description: Product being supported\n\n # Optional input (defaults to \"NONE\")\n SUPPORT_POLICIES:\n type: string\n description: Company policies for support\n optional: true\n\n # Optional input with custom default\n USER_ID:\n type: string\n description: Current user's ID\n optional: true\n default: \"\"\n```\n\n### Input Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this input is for |\n| `optional` | No | If true, consumer doesn't have to provide it |\n| `default` | No | Default value if not provided (defaults to `\"NONE\"`) |\n\n### Using Inputs\n\nWhen creating a session, pass input values:\n\n```typescript\nconst sessionId = await client.agentSessions.create('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n SUPPORT_POLICIES: 'Refunds within 30 days...',\n // USER_ID is optional, not provided\n});\n```\n\nIn prompts, reference with `{{INPUT_NAME}}`:\n\n```markdown\nYou are a support agent for {{COMPANY_NAME}}.\n```\n\n> **Note:** Variables must be `UPPER_SNAKE_CASE`. Nested properties (dot notation like `{{VAR.property}}`) are not supported. Objects are serialized as JSON when interpolated.\n\n## Resources\n\nResources are persistent state that:\n- Survive across triggers\n- Can be read and written by the agent\n- Are synced to the consumer's application\n\n```yaml\nresources:\n # String resource with default\n CONVERSATION_SUMMARY:\n type: string\n description: Running summary of the conversation\n default: \"\"\n\n # Resource with unknown type (for complex data)\n USER_CONTEXT:\n type: unknown\n description: Cached user information\n default: {}\n\n # Read-only resource (agent can read but not write)\n SYSTEM_CONFIG:\n type: unknown\n description: System configuration\n readonly: true\n default:\n maxRetries: 3\n timeout: 30000\n```\n\n### Resource Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes the resource purpose |\n| `default` | No | Initial value |\n| `readonly` | No | If true, agent cannot write to it |\n\n### Writing Resources\n\nUse the `set-resource` block in handlers:\n\n```yaml\nhandlers:\n request-human:\n # ... generate summary ...\n \n Save summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY # Variable containing the value\n```\n\n### Resource Events\n\nWhen a resource is updated, the client SDK receives a `resource-update` event:\n\n```typescript\nuseOctavusChat({\n onResourceUpdate: (name, value) => {\n if (name === 'CONVERSATION_SUMMARY') {\n console.log('Summary updated:', value);\n }\n },\n});\n```\n\n## Variables\n\nVariables are internal state managed by block outputs. They persist across triggers but are not synced to the consumer (unlike resources).\n\n```yaml\nvariables:\n SUMMARY:\n type: string\n description: Generated summary text\n TICKET:\n type: unknown\n description: Ticket creation result\n CONVERSATION_TEXT:\n type: string\n description: Serialized conversation\n```\n\n### Variable Definition\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this variable stores |\n| `default` | No | Initial value |\n\n### Using Variables\n\nSet variables as output from blocks:\n\n```yaml\nhandlers:\n request-human:\n Serialize conversation:\n type: serialize-thread\n format: markdown\n output: CONVERSATION_TEXT # Stores result in variable\n \n Generate summary:\n type: next-message\n output: SUMMARY # LLM output stored in variable\n \n Create ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY # Use variable as input\n output: TICKET\n```\n\n## Scoping\n\n| Type | Scope | Persistence | Synced to Consumer |\n|------|-------|-------------|---------------------|\n| `input` | Session | Immutable | Yes (at creation) |\n| `resources` | Session | Persists across triggers | Yes (via callbacks) |\n| `variables` | Session | Persists across triggers | No (internal only) |\n\n",
|
|
137
146
|
"excerpt": "Input & Resources Inputs are provided when creating a session. Resources are persistent state the agent can read and write. Input Variables Define inputs that consumers must (or may) provide: Input...",
|
|
138
147
|
"order": 2
|
|
139
148
|
},
|
|
@@ -142,7 +151,7 @@
|
|
|
142
151
|
"section": "protocol",
|
|
143
152
|
"title": "Triggers",
|
|
144
153
|
"description": "Defining how agents are invoked.",
|
|
145
|
-
"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
|
|
154
|
+
"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",
|
|
146
155
|
"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...",
|
|
147
156
|
"order": 3
|
|
148
157
|
},
|
|
@@ -151,7 +160,7 @@
|
|
|
151
160
|
"section": "protocol",
|
|
152
161
|
"title": "Tools",
|
|
153
162
|
"description": "Defining external tools agents can use.",
|
|
154
|
-
"content": "\n# Tools\n\nTools extend what agents can do. They're defined in the protocol and implemented in your backend.\n\n## Tool Definition\n\n```yaml\ntools:\n get-user-account:\n description: Looking up your account information\n display: description\n parameters:\n userId:\n type: string\n description: The user ID to look up\n```\n\n### Tool Fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `description` | Yes | What the tool does (shown to LLM and optionally user) |\n| `display` | No | How to show in UI: `hidden`, `name`, `description`, `stream` |\n| `parameters` | No | Input parameters the tool accepts |\n\n### Display Modes\n\n| Mode | Behavior |\n|------|----------|\n| `hidden` | Tool runs silently, user doesn't see it |\n| `name` | Shows tool name while executing |\n| `description` | Shows description while executing (default) |\n| `stream` | Streams tool progress if available |\n\n## Parameters\n\n### Parameter Fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this parameter is for |\n| `optional` | No | If true, parameter is not required (default: false) |\n\n### Optional Parameters\n\nParameters are **required by default**. Use `optional: true` to make a parameter optional:\n\n```yaml\ntools:\n search-products:\n description: Search the product catalog\n parameters:\n query:\n type: string\n description: Search query\n
|
|
163
|
+
"content": "\n# Tools\n\nTools extend what agents can do. They're defined in the protocol and implemented in your backend.\n\n## Tool Definition\n\n```yaml\ntools:\n get-user-account:\n description: Looking up your account information\n display: description\n parameters:\n userId:\n type: string\n description: The user ID to look up\n```\n\n### Tool Fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `description` | Yes | What the tool does (shown to LLM and optionally user) |\n| `display` | No | How to show in UI: `hidden`, `name`, `description`, `stream` |\n| `parameters` | No | Input parameters the tool accepts |\n\n### Display Modes\n\n| Mode | Behavior |\n|------|----------|\n| `hidden` | Tool runs silently, user doesn't see it |\n| `name` | Shows tool name while executing |\n| `description` | Shows description while executing (default) |\n| `stream` | Streams tool progress if available |\n\n## Parameters\n\n### Parameter Fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `type` | Yes | Data type: `string`, `number`, `boolean`, `unknown` |\n| `description` | No | Describes what this parameter is for |\n| `optional` | No | If true, parameter is not required (default: false) |\n\n### Optional Parameters\n\nParameters are **required by default**. Use `optional: true` to make a parameter optional:\n\n```yaml\ntools:\n search-products:\n description: Search the product catalog\n parameters:\n query:\n type: string\n description: Search query\n\n category:\n type: string\n description: Filter by category\n optional: true\n\n maxPrice:\n type: number\n description: Maximum price filter\n optional: true\n\n inStock:\n type: boolean\n description: Only show in-stock items\n optional: true\n```\n\n## Making Tools Available\n\nTools defined in `tools:` are available. To make them usable by the LLM, add them to `agent.tools`:\n\n```yaml\ntools:\n get-user-account:\n description: Look up user account\n parameters:\n userId: { type: string }\n\n create-support-ticket:\n description: Create a support ticket\n parameters:\n summary: { type: string }\n priority: { type: string } # low, medium, high, urgent\n\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system\n tools:\n - get-user-account\n - create-support-ticket # LLM can decide when to call these\n agentic: true\n```\n\n## Tool Invocation Modes\n\n### LLM-Decided (Agentic)\n\nThe LLM decides when to call tools based on the conversation:\n\n```yaml\nagent:\n tools: [get-user-account, create-support-ticket]\n agentic: true # Allow multiple tool calls\n maxSteps: 10 # Max tool call cycles\n```\n\n### Deterministic (Block-Based)\n\nForce tool calls at specific points in the handler:\n\n```yaml\nhandlers:\n request-human:\n # Always create a ticket when escalating\n Create support ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY # From variable\n priority: medium # Literal value\n output: TICKET # Store result\n```\n\n## Tool Results\n\n### In Prompts\n\nTool results are stored in variables. Reference the variable in prompts:\n\n```markdown\n<!-- prompts/ticket-directive.md -->\nA support ticket has been created:\n{{TICKET}}\n\nLet the user know their ticket has been created.\n```\n\nWhen the `TICKET` variable contains an object, it's automatically serialized as JSON in the prompt:\n\n```\nA support ticket has been created:\n{\n \"ticketId\": \"TKT-123ABC\",\n \"estimatedResponse\": \"24 hours\"\n}\n\nLet the user know their ticket has been created.\n```\n\n> **Note**: Variables use `{{VARIABLE_NAME}}` syntax with `UPPERCASE_SNAKE_CASE`. Dot notation (like `{{TICKET.ticketId}}`) is not supported. Objects are automatically JSON-serialized.\n\n### In Variables\n\nStore tool results for later use:\n\n```yaml\nhandlers:\n request-human:\n Get account:\n type: tool-call\n tool: get-user-account\n input:\n userId: USER_ID\n output: ACCOUNT # Result stored here\n\n Create ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY\n priority: medium\n output: TICKET\n```\n\n## Implementing Tools\n\nTools are implemented in your backend:\n\n```typescript\nconst session = client.agentSessions.attach(sessionId, {\n tools: {\n 'get-user-account': async (args) => {\n const userId = args.userId as string;\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 ticket = await ticketService.create({\n summary: args.summary as string,\n priority: args.priority as string,\n });\n\n return {\n ticketId: ticket.id,\n estimatedResponse: getEstimatedTime(args.priority),\n };\n },\n },\n});\n```\n\n## Tool Best Practices\n\n### 1. Clear Descriptions\n\n```yaml\ntools:\n # Good - clear and specific\n get-user-account:\n description: >\n Retrieves the user's account information including name, email,\n subscription plan, and account creation date. Use this when the\n user asks about their account or you need to verify their identity.\n\n # Avoid - vague\n get-data:\n description: Gets some data\n```\n\n### 2. Document Constrained Values\n\n```yaml\ntools:\n create-support-ticket:\n parameters:\n priority:\n type: string\n description: Ticket priority level (low, medium, high, urgent)\n```\n",
|
|
155
164
|
"excerpt": "Tools Tools extend what agents can do. They're defined in the protocol and implemented in your backend. Tool Definition Tool Fields | Field | Required | Description |...",
|
|
156
165
|
"order": 4
|
|
157
166
|
},
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octavus/docs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Documentation content for Octavus SDKs",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"author": "Octavus AI <
|
|
6
|
+
"author": "Octavus AI <dev@octavus.ai>",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"octavus",
|
|
9
9
|
"ai",
|