@octavus/docs 0.0.8 → 1.0.0

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 (173) hide show
  1. package/README.md +127 -0
  2. package/content/01-getting-started/01-introduction.md +3 -3
  3. package/content/01-getting-started/02-quickstart.md +40 -17
  4. package/content/02-server-sdk/01-overview.md +54 -11
  5. package/content/02-server-sdk/02-sessions.md +166 -15
  6. package/content/02-server-sdk/03-tools.md +21 -21
  7. package/content/02-server-sdk/04-streaming.md +50 -20
  8. package/content/02-server-sdk/05-cli.md +247 -0
  9. package/content/03-client-sdk/01-overview.md +65 -35
  10. package/content/03-client-sdk/02-messages.md +116 -8
  11. package/content/03-client-sdk/03-streaming.md +36 -17
  12. package/content/03-client-sdk/04-execution-blocks.md +8 -12
  13. package/content/03-client-sdk/05-socket-transport.md +161 -45
  14. package/content/03-client-sdk/06-http-transport.md +48 -24
  15. package/content/03-client-sdk/07-structured-output.md +412 -0
  16. package/content/03-client-sdk/08-file-uploads.md +473 -0
  17. package/content/03-client-sdk/09-error-handling.md +274 -0
  18. package/content/04-protocol/01-overview.md +25 -14
  19. package/content/04-protocol/02-input-resources.md +35 -35
  20. package/content/04-protocol/03-triggers.md +9 -11
  21. package/content/04-protocol/04-tools.md +72 -29
  22. package/content/04-protocol/05-skills.md +304 -0
  23. package/content/04-protocol/06-handlers.md +304 -0
  24. package/content/04-protocol/07-agent-config.md +334 -0
  25. package/content/04-protocol/08-provider-options.md +294 -0
  26. package/content/04-protocol/09-skills-advanced.md +439 -0
  27. package/content/04-protocol/10-types.md +719 -0
  28. package/content/05-api-reference/01-overview.md +20 -21
  29. package/content/05-api-reference/02-sessions.md +192 -37
  30. package/content/05-api-reference/03-agents.md +25 -37
  31. package/content/06-examples/01-overview.md +6 -4
  32. package/content/06-examples/02-nextjs-chat.md +28 -18
  33. package/content/06-examples/03-socket-chat.md +53 -30
  34. package/content/06-examples/_meta.md +0 -1
  35. package/dist/chunk-WJ2W3DUC.js +663 -0
  36. package/dist/chunk-WJ2W3DUC.js.map +1 -0
  37. package/dist/content.js +1 -1
  38. package/dist/docs.json +106 -34
  39. package/dist/index.js +1 -1
  40. package/dist/search-index.json +1 -1
  41. package/dist/search.js +1 -1
  42. package/dist/search.js.map +1 -1
  43. package/dist/sections.json +106 -34
  44. package/package.json +12 -2
  45. package/content/04-protocol/05-handlers.md +0 -251
  46. package/content/04-protocol/06-agent-config.md +0 -209
  47. package/dist/chunk-232K4EME.js +0 -439
  48. package/dist/chunk-232K4EME.js.map +0 -1
  49. package/dist/chunk-2JDZLMS3.js +0 -439
  50. package/dist/chunk-2JDZLMS3.js.map +0 -1
  51. package/dist/chunk-2YMRODFE.js +0 -421
  52. package/dist/chunk-2YMRODFE.js.map +0 -1
  53. package/dist/chunk-2ZBPX5QB.js +0 -421
  54. package/dist/chunk-2ZBPX5QB.js.map +0 -1
  55. package/dist/chunk-3PIIST4D.js +0 -421
  56. package/dist/chunk-3PIIST4D.js.map +0 -1
  57. package/dist/chunk-42JETGDO.js +0 -421
  58. package/dist/chunk-42JETGDO.js.map +0 -1
  59. package/dist/chunk-4WWUKU4V.js +0 -421
  60. package/dist/chunk-4WWUKU4V.js.map +0 -1
  61. package/dist/chunk-5M7DS4DF.js +0 -519
  62. package/dist/chunk-5M7DS4DF.js.map +0 -1
  63. package/dist/chunk-6JQ3OMGF.js +0 -421
  64. package/dist/chunk-6JQ3OMGF.js.map +0 -1
  65. package/dist/chunk-7AOWCJHW.js +0 -421
  66. package/dist/chunk-7AOWCJHW.js.map +0 -1
  67. package/dist/chunk-7AS4ST73.js +0 -421
  68. package/dist/chunk-7AS4ST73.js.map +0 -1
  69. package/dist/chunk-7F5WOCIL.js +0 -421
  70. package/dist/chunk-7F5WOCIL.js.map +0 -1
  71. package/dist/chunk-7FPUAWSX.js +0 -421
  72. package/dist/chunk-7FPUAWSX.js.map +0 -1
  73. package/dist/chunk-APASMJBS.js +0 -421
  74. package/dist/chunk-APASMJBS.js.map +0 -1
  75. package/dist/chunk-BCEV3WV2.js +0 -421
  76. package/dist/chunk-BCEV3WV2.js.map +0 -1
  77. package/dist/chunk-CHGY4G27.js +0 -421
  78. package/dist/chunk-CHGY4G27.js.map +0 -1
  79. package/dist/chunk-CI7JDWKU.js +0 -421
  80. package/dist/chunk-CI7JDWKU.js.map +0 -1
  81. package/dist/chunk-CVFWWRL7.js +0 -421
  82. package/dist/chunk-CVFWWRL7.js.map +0 -1
  83. package/dist/chunk-EPDM2NIJ.js +0 -421
  84. package/dist/chunk-EPDM2NIJ.js.map +0 -1
  85. package/dist/chunk-ESGSYVGK.js +0 -421
  86. package/dist/chunk-ESGSYVGK.js.map +0 -1
  87. package/dist/chunk-GDCTM2SV.js +0 -421
  88. package/dist/chunk-GDCTM2SV.js.map +0 -1
  89. package/dist/chunk-GJ6FMIPD.js +0 -421
  90. package/dist/chunk-GJ6FMIPD.js.map +0 -1
  91. package/dist/chunk-H6JGSSAJ.js +0 -519
  92. package/dist/chunk-H6JGSSAJ.js.map +0 -1
  93. package/dist/chunk-IKQHGGUZ.js +0 -421
  94. package/dist/chunk-IKQHGGUZ.js.map +0 -1
  95. package/dist/chunk-IUKE3XDN.js +0 -421
  96. package/dist/chunk-IUKE3XDN.js.map +0 -1
  97. package/dist/chunk-J26MLMLN.js +0 -421
  98. package/dist/chunk-J26MLMLN.js.map +0 -1
  99. package/dist/chunk-J7BMB3ZW.js +0 -421
  100. package/dist/chunk-J7BMB3ZW.js.map +0 -1
  101. package/dist/chunk-JCBQRD5N.js +0 -421
  102. package/dist/chunk-JCBQRD5N.js.map +0 -1
  103. package/dist/chunk-JOB6YWEF.js +0 -421
  104. package/dist/chunk-JOB6YWEF.js.map +0 -1
  105. package/dist/chunk-JZRABTHU.js +0 -519
  106. package/dist/chunk-JZRABTHU.js.map +0 -1
  107. package/dist/chunk-K3GFQUMC.js +0 -421
  108. package/dist/chunk-K3GFQUMC.js.map +0 -1
  109. package/dist/chunk-LWYMRXBF.js +0 -421
  110. package/dist/chunk-LWYMRXBF.js.map +0 -1
  111. package/dist/chunk-M2R2NDPR.js +0 -421
  112. package/dist/chunk-M2R2NDPR.js.map +0 -1
  113. package/dist/chunk-MA3P7WCA.js +0 -421
  114. package/dist/chunk-MA3P7WCA.js.map +0 -1
  115. package/dist/chunk-MDMRCS4W.mjs +0 -421
  116. package/dist/chunk-MDMRCS4W.mjs.map +0 -1
  117. package/dist/chunk-MJXTA2R6.js +0 -421
  118. package/dist/chunk-MJXTA2R6.js.map +0 -1
  119. package/dist/chunk-NFVJQNDP.js +0 -421
  120. package/dist/chunk-NFVJQNDP.js.map +0 -1
  121. package/dist/chunk-O5TLYMQP.js +0 -421
  122. package/dist/chunk-O5TLYMQP.js.map +0 -1
  123. package/dist/chunk-OECAPVSX.js +0 -439
  124. package/dist/chunk-OECAPVSX.js.map +0 -1
  125. package/dist/chunk-OL5QDJ42.js +0 -483
  126. package/dist/chunk-OL5QDJ42.js.map +0 -1
  127. package/dist/chunk-PMOVVTHO.js +0 -519
  128. package/dist/chunk-PMOVVTHO.js.map +0 -1
  129. package/dist/chunk-QCHDPR2D.js +0 -421
  130. package/dist/chunk-QCHDPR2D.js.map +0 -1
  131. package/dist/chunk-R5MTVABN.js +0 -439
  132. package/dist/chunk-R5MTVABN.js.map +0 -1
  133. package/dist/chunk-RJ4H4YVA.js +0 -519
  134. package/dist/chunk-RJ4H4YVA.js.map +0 -1
  135. package/dist/chunk-S5U4IWCR.js +0 -439
  136. package/dist/chunk-S5U4IWCR.js.map +0 -1
  137. package/dist/chunk-SCKIOGKI.js +0 -421
  138. package/dist/chunk-SCKIOGKI.js.map +0 -1
  139. package/dist/chunk-TGJSIJYP.js +0 -421
  140. package/dist/chunk-TGJSIJYP.js.map +0 -1
  141. package/dist/chunk-TQZRBMU7.js +0 -421
  142. package/dist/chunk-TQZRBMU7.js.map +0 -1
  143. package/dist/chunk-TRL4RSEO.js +0 -421
  144. package/dist/chunk-TRL4RSEO.js.map +0 -1
  145. package/dist/chunk-TWUMRHQ7.js +0 -421
  146. package/dist/chunk-TWUMRHQ7.js.map +0 -1
  147. package/dist/chunk-UCJE36LL.js +0 -519
  148. package/dist/chunk-UCJE36LL.js.map +0 -1
  149. package/dist/chunk-VCASA6KL.js +0 -421
  150. package/dist/chunk-VCASA6KL.js.map +0 -1
  151. package/dist/chunk-VWPQ6ORV.js +0 -421
  152. package/dist/chunk-VWPQ6ORV.js.map +0 -1
  153. package/dist/chunk-WPXKIHLT.js +0 -421
  154. package/dist/chunk-WPXKIHLT.js.map +0 -1
  155. package/dist/chunk-WUNFFJ32.js +0 -421
  156. package/dist/chunk-WUNFFJ32.js.map +0 -1
  157. package/dist/chunk-WW7TRC7S.js +0 -519
  158. package/dist/chunk-WW7TRC7S.js.map +0 -1
  159. package/dist/chunk-XVSMRXBJ.js +0 -421
  160. package/dist/chunk-XVSMRXBJ.js.map +0 -1
  161. package/dist/chunk-YPPXXV3I.js +0 -421
  162. package/dist/chunk-YPPXXV3I.js.map +0 -1
  163. package/dist/chunk-ZKZVV4OQ.js +0 -421
  164. package/dist/chunk-ZKZVV4OQ.js.map +0 -1
  165. package/dist/chunk-ZOFEX73I.js +0 -421
  166. package/dist/chunk-ZOFEX73I.js.map +0 -1
  167. package/dist/content.mjs +0 -17
  168. package/dist/content.mjs.map +0 -1
  169. package/dist/index.mjs +0 -11
  170. package/dist/index.mjs.map +0 -1
  171. package/dist/search.mjs +0 -30
  172. package/dist/search.mjs.map +0 -1
  173. package/dist/types-BltYGlWI.d.ts +0 -36
@@ -1,421 +0,0 @@
1
- // dist/docs.json
2
- var docs_default = [
3
- {
4
- slug: "getting-started/introduction",
5
- section: "getting-started",
6
- title: "Introduction",
7
- description: "Overview of Octavus AI - an agent orchestration platform for developers.",
8
- 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** \u2014 No unified way to define, manage, and deploy agents\n- **Prompt management** \u2014 Prompts are scattered across codebases, hard to version and iterate\n- **Integration complexity** \u2014 Connecting agents to tools, resources, and other agents requires significant custom work\n- **Observability** \u2014 Difficult to debug, monitor, and understand agent behavior in production\n- **Infrastructure overhead** \u2014 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 \u2014 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** \u2014 Respond to a text message in a chat interface\n- **User Action** \u2014 Respond to UI actions (button clicks, form submissions)\n- **API Call** \u2014 Direct invocation via SDK\n\n### Tools\n\n**Tools** extend what agents can do:\n\n- **External Tools** \u2014 Consumer-defined tools that call back to your systems\n- **Internal Tools** \u2014 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) \u2014 Get your first agent running in minutes\n- [Server SDK](/docs/server-sdk/overview) \u2014 Learn about backend integration\n- [Client SDK](/docs/client-sdk/overview) \u2014 Build chat interfaces with React\n- [Protocol Reference](/docs/protocol/overview) \u2014 Deep dive into agent protocols\n\n",
9
- 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...",
10
- order: 1
11
- },
12
- {
13
- slug: "getting-started/quickstart",
14
- section: "getting-started",
15
- title: "Quick Start",
16
- description: "Get your first Octavus agent running in minutes.",
17
- 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# Client SDK for frontend (React)\nnpm install @octavus/client-sdk\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 to build a chat interface:\n\n```tsx\n// components/chat.tsx\n'use client';\n\nimport { useOctavusChat } from '@octavus/client-sdk';\nimport { useState } from 'react';\n\ninterface ChatProps {\n sessionId: string;\n}\n\nexport function Chat({ sessionId }: ChatProps) {\n const [inputValue, setInputValue] = useState('');\n\n const {\n messages,\n status,\n isLoading,\n streamingText,\n addUserMessage,\n triggerAction,\n } = useOctavusChat({\n onTrigger: async (triggerName, input) => {\n return fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n });\n },\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || isLoading) return;\n\n const message = inputValue.trim();\n setInputValue('');\n\n // Add user message to UI\n addUserMessage(message);\n\n // Trigger the agent\n await triggerAction('user-message', { USER_MESSAGE: message });\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 <div\n key={msg.id}\n className={`p-3 rounded-lg ${\n msg.role === 'user'\n ? 'bg-blue-500 text-white ml-auto max-w-xs'\n : 'bg-gray-100 max-w-md'\n }`}\n >\n {msg.content}\n </div>\n ))}\n\n {/* Streaming text */}\n {streamingText && (\n <div className=\"bg-gray-100 p-3 rounded-lg max-w-md\">\n {streamingText}\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={isLoading}\n />\n <button\n type=\"submit\"\n disabled={isLoading}\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```\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\n",
18
- 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...",
19
- order: 2
20
- },
21
- {
22
- slug: "server-sdk/overview",
23
- section: "server-sdk",
24
- title: "Overview",
25
- description: "Introduction to the Octavus Server SDK for backend integration.",
26
- 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.1.0`\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('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n});\n\n// Get session state\nconst state = await client.agentSessions.get(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 session state\n async get(sessionId: string): Promise<SessionState>;\n \n // Attach to a session for triggering\n attach(sessionId: string, options?: SessionAttachOptions): AgentSession;\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) \u2014 Deep dive into session management\n- [Tools](/docs/server-sdk/tools) \u2014 Implementing tool handlers\n- [Streaming](/docs/server-sdk/streaming) \u2014 Understanding stream events\n\n",
27
- 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...",
28
- order: 1
29
- },
30
- {
31
- slug: "server-sdk/sessions",
32
- section: "server-sdk",
33
- title: "Sessions",
34
- description: "Managing agent sessions with the Server SDK.",
35
- 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## Session State\n\nRetrieve the current state of a session:\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,\n resources: state.resources,\n variables: state.variables,\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n});\n```\n\n### SessionState Interface\n\n```typescript\ninterface SessionState {\n id: string;\n agentId: string;\n input: Record<string, unknown>; // Initial input (immutable)\n variables: Record<string, unknown>; // Mutable session variables\n resources: Record<string, unknown>; // Resources (synced to consumer)\n messages: ChatMessage[]; // Conversation history\n createdAt: string;\n updatedAt: string;\n}\n```\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.get()**\n Get current state\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 state = await client.agentSessions.get(sessionId);\n\n// Pass messages to frontend to restore UI\nreturn {\n sessionId,\n messages: state.messages,\n resources: state.resources,\n};\n```\n\nThe `messages` array includes all conversation history with proper content ordering (text, tool calls, thinking blocks), enabling accurate UI restoration.\n\n## Error Handling\n\n```typescript\nimport { ApiError } from '@octavus/server-sdk';\n\ntry {\n const state = await client.agentSessions.get(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\n",
36
- 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...",
37
- order: 2
38
- },
39
- {
40
- slug: "server-sdk/tools",
41
- section: "server-sdk",
42
- title: "Tools",
43
- description: "Implementing tool handlers with the Server SDK.",
44
- 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- \u2705 **Full data access** \u2014 Query your database directly\n- \u2705 **Your authentication** \u2014 Use your existing auth context\n- \u2705 **No data exposure** \u2014 Sensitive data never leaves your infrastructure\n- \u2705 **Custom logic** \u2014 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",
45
- 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...",
46
- order: 3
47
- },
48
- {
49
- slug: "server-sdk/streaming",
50
- section: "server-sdk",
51
- title: "Streaming",
52
- description: "Understanding stream events from the Server SDK.",
53
- 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## Handling Streams Manually\n\nIf you need to process the stream server-side:\n\n```typescript\nimport { safeParseStreamEvent } from '@octavus/core';\n\nconst { stream } = session.trigger('user-message', { USER_MESSAGE: 'Hello' });\n\nconst reader = stream.getReader();\nconst decoder = new TextDecoder();\n\nlet buffer = '';\n\nwhile (true) {\n const { done, value } = await reader.read();\n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n \n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n const parsed = safeParseStreamEvent(JSON.parse(line.slice(6)));\n if (parsed.success) {\n const event = parsed.data;\n \n switch (event.type) {\n case 'text-delta':\n process.stdout.write(event.delta);\n break;\n case 'finish':\n console.log('\\nDone:', event.finishReason);\n break;\n }\n }\n }\n }\n}\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",
54
- 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...",
55
- order: 4
56
- },
57
- {
58
- slug: "client-sdk/overview",
59
- section: "client-sdk",
60
- title: "Overview",
61
- description: "Introduction to the Octavus Client SDK for building chat interfaces.",
62
- content: "\n# Client SDK Overview\n\nThe `@octavus/client-sdk` package provides React hooks for building chat interfaces with Octavus agents. It handles streaming, message state, and execution blocks.\n\n**Current version:** `0.1.0`\n\n## Installation\n\n```bash\nnpm install @octavus/client-sdk\n```\n\n## Basic Usage\n\n```tsx\nimport { useOctavusChat } from '@octavus/client-sdk';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const {\n messages,\n status,\n isLoading,\n streamingText,\n addUserMessage,\n triggerAction,\n } = useOctavusChat({\n onTrigger: async (triggerName, input) => {\n return fetch(`/api/chat/${sessionId}/trigger`, {\n method: 'POST',\n body: JSON.stringify({ triggerName, input }),\n });\n },\n });\n\n const sendMessage = async (text: string) => {\n addUserMessage(text);\n await triggerAction('user-message', { USER_MESSAGE: text });\n };\n\n return (\n <div>\n {messages.map((msg) => (\n <div key={msg.id}>{msg.content}</div>\n ))}\n {streamingText && <div>{streamingText}</div>}\n </div>\n );\n}\n```\n\n## Key Features\n\n### Real-time Streaming\n\nText streams incrementally as the LLM generates it:\n\n```tsx\nconst { streamingText, streamingParts } = useOctavusChat({...});\n\n// streamingText: Current streaming text\n// streamingParts: Structured parts (text, reasoning, tool calls)\n```\n\n### Message History\n\nMessages are tracked automatically:\n\n```tsx\nconst { messages } = useOctavusChat({...});\n\n// Each message includes:\n// - id: Unique identifier\n// - role: 'user' | 'assistant'\n// - content: Text content\n// - parts: Ordered content parts\n// - toolCalls: Tool call information\n// - reasoning: Extended reasoning (if enabled)\n```\n\n### Execution Blocks\n\nTrack what the agent is doing:\n\n```tsx\nconst { executionBlocks } = useOctavusChat({...});\n\n// Shows active execution steps\n// Useful for progress indicators\n```\n\n### Status Tracking\n\n```tsx\nconst { status, isLoading } = useOctavusChat({...});\n\n// status: 'idle' | 'loading' | 'streaming' | 'error'\n// isLoading: true during loading or streaming\n```\n\n## Hook Reference\n\n### useOctavusChat\n\n```typescript\nfunction useOctavusChat(options: UseOctavusChatOptions): UseOctavusChatReturn;\n\ninterface UseOctavusChatOptions {\n // Required: Function that calls your backend trigger endpoint\n onTrigger: TriggerFunction;\n \n // Optional: Pre-populate with existing messages (session restore)\n initialMessages?: Message[];\n \n // Optional: Callbacks\n onMessage?: (message: Message) => void;\n onError?: (error: Error) => void;\n onDone?: () => void;\n onResourceUpdate?: (name: string, value: unknown) => void;\n onBlockStart?: (block: ExecutionBlock) => void;\n onBlockEnd?: (block: ExecutionBlock) => void;\n}\n\ninterface UseOctavusChatReturn {\n // State\n messages: Message[];\n status: ChatStatus;\n isLoading: boolean;\n error: Error | null;\n streamingText: string;\n streamingParts: MessagePart[];\n executionBlocks: ExecutionBlock[];\n reasoningText: string;\n \n // Actions\n addUserMessage: (content: string) => void;\n triggerAction: (triggerName: string, input?: Record<string, unknown>) => Promise<void>;\n}\n```\n\n## Next Steps\n\n- [Messages](/docs/client-sdk/messages) \u2014 Working with message state\n- [Streaming](/docs/client-sdk/streaming) \u2014 Building streaming UIs\n- [Execution Blocks](/docs/client-sdk/execution-blocks) \u2014 Showing agent progress\n",
63
- excerpt: "Client SDK Overview The package provides React hooks for building chat interfaces with Octavus agents. It handles streaming, message state, and execution blocks. Current version: Installation ...",
64
- order: 1
65
- },
66
- {
67
- slug: "client-sdk/messages",
68
- section: "client-sdk",
69
- title: "Messages",
70
- description: "Working with message state in the Client SDK.",
71
- content: "\n# Messages\n\nMessages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content.\n\n## Message Structure\n\n```typescript\ninterface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n parts?: MessagePart[];\n toolCalls?: ToolCallWithDescription[];\n reasoning?: string;\n visible?: boolean;\n createdAt: Date;\n}\n```\n\n### Message Parts\n\nFor rich content display, use the `parts` array which preserves content ordering:\n\n```typescript\ninterface MessagePart {\n type: 'text' | 'reasoning' | 'tool-call';\n visible: boolean;\n content?: string; // For text and reasoning\n toolCall?: ToolCallInfo; // For tool-call\n thread?: string; // For non-main thread content\n}\n```\n\n## Adding User Messages\n\n```tsx\nconst { addUserMessage, triggerAction } = useOctavusChat({...});\n\nasync function sendMessage(text: string) {\n // 1. Add message to UI immediately\n addUserMessage(text);\n \n // 2. Trigger the agent\n await triggerAction('user-message', { USER_MESSAGE: text });\n}\n```\n\n**Important**: `addUserMessage` only updates UI state. You must call `triggerAction` to actually send the message to the agent.\n\n## Rendering Messages\n\n### Basic Rendering\n\n```tsx\nfunction MessageList({ messages }: { messages: Message[] }) {\n return (\n <div className=\"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 className=\"inline-block p-3 rounded-lg\">\n {msg.content}\n </div>\n </div>\n ))}\n </div>\n );\n}\n```\n\n### Rich Rendering with Parts\n\nFor messages with tool calls and reasoning, render parts in order:\n\n```tsx\nfunction MessageContent({ message }: { message: Message }) {\n if (!message.parts) {\n return <p>{message.content}</p>;\n }\n\n return (\n <div className=\"space-y-2\">\n {message.parts.map((part, i) => {\n if (!part.visible) return null;\n\n switch (part.type) {\n case 'text':\n return <p key={i}>{part.content}</p>;\n\n case 'reasoning':\n return (\n <details key={i} className=\"text-gray-500\">\n <summary>Thinking...</summary>\n <pre className=\"text-sm\">{part.content}</pre>\n </details>\n );\n\n case 'tool-call':\n return (\n <div key={i} className=\"bg-gray-100 p-2 rounded text-sm\">\n \u{1F527} {part.toolCall?.name}\n {part.toolCall?.status === 'available' && ' \u2713'}\n </div>\n );\n\n default:\n return null;\n }\n })}\n </div>\n );\n}\n```\n\n## Tool Calls in Messages\n\nTool calls include status, arguments, and results:\n\n```typescript\ninterface ToolCallInfo {\n id: string;\n name: string;\n description?: string;\n arguments: Record<string, unknown>;\n status: 'pending' | 'streaming' | 'available' | 'error';\n result?: unknown;\n error?: string;\n}\n```\n\n### Rendering Tool Calls\n\n```tsx\nfunction ToolCallCard({ toolCall }: { toolCall: ToolCallInfo }) {\n return (\n <div className=\"border rounded p-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-lg\">\u{1F527}</span>\n <span className=\"font-medium\">{toolCall.description || toolCall.name}</span>\n <StatusBadge status={toolCall.status} />\n </div>\n \n {toolCall.status === 'available' && toolCall.result && (\n <pre className=\"mt-2 text-xs bg-gray-50 p-2 rounded\">\n {JSON.stringify(toolCall.result, null, 2)}\n </pre>\n )}\n \n {toolCall.status === 'error' && (\n <p className=\"mt-2 text-red-500 text-sm\">{toolCall.error}</p>\n )}\n </div>\n );\n}\n```\n\n## Session Restore\n\nWhen restoring a session, pass existing messages:\n\n```tsx\n// Fetch session state from your backend\nconst sessionState = await fetchSession(sessionId);\n\n// Convert ChatMessage[] to Message[]\nconst initialMessages = sessionState.messages\n .filter(msg => msg.visible !== false)\n .map(msg => ({\n id: msg.id,\n role: msg.role,\n content: msg.content,\n parts: msg.parts,\n toolCalls: msg.toolCalls,\n reasoning: msg.reasoning,\n createdAt: new Date(msg.createdAt),\n }));\n\n// Pass to hook\nconst { messages } = useOctavusChat({\n initialMessages,\n onTrigger: ...\n});\n```\n\n## Message Callbacks\n\nGet notified when messages are added:\n\n```tsx\nuseOctavusChat({\n onTrigger: ...,\n onMessage: (message) => {\n console.log('New message:', message.role, message.content);\n \n // Analytics, logging, etc.\n trackMessage(message);\n },\n});\n```\n",
72
- excerpt: "Messages Messages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content. Message Structure Message Parts For rich content...",
73
- order: 2
74
- },
75
- {
76
- slug: "client-sdk/streaming",
77
- section: "client-sdk",
78
- title: "Streaming",
79
- description: "Building streaming UIs with the Client SDK.",
80
- content: "\n# Streaming\n\nThe Client SDK provides real-time access to streaming content, enabling responsive UIs that update as the agent generates responses.\n\n## Streaming State\n\n```tsx\nconst {\n streamingText, // Current visible text being streamed\n streamingParts, // Structured parts being streamed\n reasoningText, // Current reasoning content\n status, // 'idle' | 'loading' | 'streaming' | 'error'\n isLoading, // true during loading or streaming\n} = useOctavusChat({...});\n```\n\n## Basic Streaming UI\n\n```tsx\nfunction Chat() {\n const { messages, streamingText, isLoading } = useOctavusChat({...});\n\n return (\n <div>\n {/* Completed messages */}\n {messages.map((msg) => (\n <div key={msg.id}>{msg.content}</div>\n ))}\n\n {/* Currently streaming */}\n {streamingText && (\n <div className=\"animate-pulse\">\n {streamingText}\n <span className=\"inline-block w-2 h-4 bg-gray-400 ml-1\" />\n </div>\n )}\n </div>\n );\n}\n```\n\n## Streaming Parts\n\nFor rich streaming UIs, use `streamingParts`:\n\n```tsx\nfunction StreamingContent() {\n const { streamingParts } = useOctavusChat({...});\n\n return (\n <div>\n {streamingParts.map((part, i) => {\n switch (part.type) {\n case 'text':\n return <span key={i}>{part.content}</span>;\n\n case 'reasoning':\n return (\n <div key={i} className=\"text-gray-500 italic\">\n \u{1F4AD} {part.content}\n </div>\n );\n\n case 'tool-call':\n return (\n <div key={i} className=\"flex items-center gap-2\">\n <Spinner />\n <span>{part.toolCall?.description}</span>\n </div>\n );\n }\n })}\n </div>\n );\n}\n```\n\n## Reasoning Indicator\n\nShow when the model is using extended reasoning:\n\n```tsx\nfunction ReasoningIndicator() {\n const { reasoningText, status } = useOctavusChat({...});\n\n if (!reasoningText || status !== 'streaming') {\n return null;\n }\n\n return (\n <div className=\"bg-purple-50 p-3 rounded-lg\">\n <div className=\"flex items-center gap-2 text-purple-600\">\n <Brain className=\"w-4 h-4 animate-pulse\" />\n <span className=\"font-medium\">Thinking...</span>\n </div>\n <p className=\"mt-2 text-sm text-gray-600 line-clamp-3\">\n {reasoningText}\n </p>\n </div>\n );\n}\n```\n\n## Status Indicator\n\n```tsx\nfunction StatusIndicator() {\n const { status } = useOctavusChat({...});\n\n switch (status) {\n case 'idle':\n return null;\n case 'loading':\n return <div>Starting...</div>;\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 Stream Completion\n\n```tsx\nuseOctavusChat({\n onTrigger: ...,\n onDone: () => {\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## Streaming with Tool Calls\n\nWhen tools are called, streaming continues after tool execution:\n\n```\n1. User sends message\n2. streamingText starts filling: \"Let me look that up...\"\n3. Tool call starts (visible in streamingParts)\n4. Tool executes (handled by server-sdk)\n5. streamingText continues: \"I found your account...\"\n6. Stream completes, message finalized\n```\n\n```tsx\nfunction ChatWithTools() {\n const { messages, streamingText, streamingParts } = useOctavusChat({...});\n\n // Find active tool call\n const activeToolCall = streamingParts.find(\n p => p.type === 'tool-call' && p.toolCall?.status === 'streaming'\n );\n\n return (\n <div>\n {messages.map(msg => <Message key={msg.id} message={msg} />)}\n\n {/* Show streaming text */}\n {streamingText && <p>{streamingText}</p>}\n\n {/* Show active tool */}\n {activeToolCall && (\n <div className=\"flex items-center gap-2 text-blue-600\">\n <Spinner />\n {activeToolCall.toolCall?.description}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Non-Main Thread Content\n\nNamed threads (like summarization) stream separately:\n\n```tsx\nfunction StreamingContent() {\n const { streamingParts } = useOctavusChat({...});\n\n // Group by thread\n const mainParts = streamingParts.filter(p => !p.thread || p.thread === 'main');\n const otherParts = streamingParts.filter(p => p.thread && p.thread !== 'main');\n\n return (\n <div>\n {/* Main conversation */}\n <div>{mainParts.map(renderPart)}</div>\n\n {/* Named thread (e.g., summarization) */}\n {otherParts.length > 0 && (\n <div className=\"bg-orange-50 p-3 rounded mt-4\">\n <div className=\"text-orange-600 font-medium\">\n Processing in background...\n </div>\n {otherParts.map(renderPart)}\n </div>\n )}\n </div>\n );\n}\n```\n",
81
- excerpt: "Streaming The Client SDK provides real-time access to streaming content, enabling responsive UIs that update as the agent generates responses. Streaming State Basic Streaming UI Streaming Parts...",
82
- order: 3
83
- },
84
- {
85
- slug: "client-sdk/execution-blocks",
86
- section: "client-sdk",
87
- title: "Execution Blocks",
88
- description: "Tracking agent execution progress with the Client SDK.",
89
- content: '\n# Execution Blocks\n\nExecution blocks let you show users what the agent is doing. Each block represents a step in the agent\'s execution flow.\n\n## Block Structure\n\n```typescript\ninterface ExecutionBlock {\n id: string;\n name: string; // Human-readable name from protocol\n type: string; // Block type (next-message, tool-call, etc.)\n status: BlockStatus; // pending | running | completed | error\n display: DisplayMode; // hidden | name | description | stream\n description?: string;\n outputToChat: boolean; // Whether output goes to main chat\n thread?: string; // For named threads\n streamingText: string; // Current streaming content\n reasoning?: string; // Extended reasoning content\n toolCalls: ToolCallWithDescription[];\n startedAt: Date;\n completedAt?: Date;\n}\n```\n\n## Accessing Blocks\n\n```tsx\nconst { executionBlocks, onBlockStart, onBlockEnd } = useOctavusChat({\n onTrigger: ...,\n onBlockStart: (block) => {\n console.log(\'Block started:\', block.name);\n },\n onBlockEnd: (block) => {\n console.log(\'Block completed:\', block.name, block.status);\n },\n});\n```\n\n## Showing Execution Progress\n\n```tsx\nfunction ExecutionProgress() {\n const { executionBlocks, status } = useOctavusChat({...});\n\n if (status !== \'streaming\' || executionBlocks.length === 0) {\n return null;\n }\n\n return (\n <div className="space-y-2">\n {executionBlocks.map((block) => (\n <ExecutionBlockCard key={block.id} block={block} />\n ))}\n </div>\n );\n}\n\nfunction ExecutionBlockCard({ block }: { block: ExecutionBlock }) {\n return (\n <div className="border rounded p-3">\n <div className="flex items-center gap-2">\n <BlockStatusIcon status={block.status} />\n <span className="font-medium">{block.name}</span>\n </div>\n\n {block.description && (\n <p className="text-sm text-gray-500 mt-1">{block.description}</p>\n )}\n\n {/* Show streaming content for stream display mode */}\n {block.display === \'stream\' && block.streamingText && (\n <div className="mt-2 text-sm">\n {block.streamingText}\n </div>\n )}\n\n {/* Show tool calls */}\n {block.toolCalls.length > 0 && (\n <div className="mt-2 space-y-1">\n {block.toolCalls.map((tc) => (\n <div key={tc.id} className="text-sm flex items-center gap-1">\n \u{1F527} {tc.description || tc.name}\n {tc.status === \'available\' && \' \u2713\'}\n {tc.status === \'error\' && \' \u2717\'}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Display Modes\n\nBlocks have different display modes that control visibility:\n\n| Mode | Description | UI Recommendation |\n|------|-------------|-------------------|\n| `hidden` | Not shown to user | Don\'t render |\n| `name` | Shows block name | Show name only |\n| `description` | Shows description | Show name + description |\n| `stream` | Streams content | Show full streaming content |\n\n```tsx\nfunction ExecutionBlockCard({ block }: { block: ExecutionBlock }) {\n // Hidden blocks aren\'t sent to client, but check just in case\n if (block.display === \'hidden\') {\n return null;\n }\n\n return (\n <div className="border rounded p-3">\n {/* Always show name */}\n <div className="font-medium">{block.name}</div>\n\n {/* Show description if display mode is description or stream */}\n {(block.display === \'description\' || block.display === \'stream\') && \n block.description && (\n <p className="text-sm text-gray-500">{block.description}</p>\n )}\n\n {/* Show content if display mode is stream */}\n {block.display === \'stream\' && (\n <div className="mt-2">\n {block.streamingText}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Named Threads\n\nBlocks can belong to named threads (like "summary"). Use the `thread` property:\n\n```tsx\nfunction ExecutionProgress() {\n const { executionBlocks } = useOctavusChat({...});\n\n // Group by thread\n const mainBlocks = executionBlocks.filter(b => !b.thread || b.thread === \'main\');\n const namedThreads = new Map<string, ExecutionBlock[]>();\n\n executionBlocks.forEach(b => {\n if (b.thread && b.thread !== \'main\') {\n if (!namedThreads.has(b.thread)) {\n namedThreads.set(b.thread, []);\n }\n namedThreads.get(b.thread)!.push(b);\n }\n });\n\n return (\n <div>\n {/* Main execution */}\n <div className="space-y-2">\n {mainBlocks.map(b => <BlockCard key={b.id} block={b} />)}\n </div>\n\n {/* Named threads */}\n {Array.from(namedThreads.entries()).map(([thread, blocks]) => (\n <div key={thread} className="mt-4 bg-orange-50 p-3 rounded">\n <div className="text-orange-600 font-medium mb-2">\n Thread: {thread}\n </div>\n {blocks.map(b => <BlockCard key={b.id} block={b} />)}\n </div>\n ))}\n </div>\n );\n}\n```\n\n## Block Status Icons\n\n```tsx\nfunction BlockStatusIcon({ status }: { status: BlockStatus }) {\n switch (status) {\n case \'pending\':\n return <Circle className="w-4 h-4 text-gray-400" />;\n case \'running\':\n return <Loader className="w-4 h-4 text-blue-500 animate-spin" />;\n case \'completed\':\n return <CheckCircle className="w-4 h-4 text-green-500" />;\n case \'error\':\n return <XCircle className="w-4 h-4 text-red-500" />;\n }\n}\n```\n\n## Example: Support Chat with Escalation\n\nWhen a user clicks "Talk to Human", the agent runs multiple blocks:\n\n```tsx\nfunction SupportChatProgress() {\n const { executionBlocks } = useOctavusChat({...});\n\n // Show blocks while streaming\n return (\n <div className="space-y-2">\n {executionBlocks.map((block) => (\n <div key={block.id} className="flex items-center gap-2">\n <BlockStatusIcon status={block.status} />\n <span>{getBlockLabel(block)}</span>\n </div>\n ))}\n </div>\n );\n}\n\nfunction getBlockLabel(block: ExecutionBlock): string {\n // Use description if available, otherwise name\n return block.description || block.name;\n}\n\n// Example output during escalation:\n// \u2713 Serialize conversation\n// \u2713 Start summary thread\n// \u25CF Summarizing your conversation (streaming...)\n// \u25CB Creating a support ticket\n// \u25CB Respond with ticket info\n```\n',
90
- excerpt: "Execution Blocks Execution blocks let you show users what the agent is doing. Each block represents a step in the agent's execution flow. Block Structure Accessing Blocks Showing Execution...",
91
- order: 4
92
- },
93
- {
94
- slug: "protocol/overview",
95
- section: "protocol",
96
- title: "Overview",
97
- description: "Introduction to Octavus agent protocols.",
98
- content: '\n# Protocol Overview\n\nAgent protocols define how an AI agent behaves. They\'re written in YAML and specify inputs, triggers, tools, and execution handlers.\n\n## Why Protocols?\n\nProtocols provide:\n\n- **Declarative definition** \u2014 Define behavior, not implementation\n- **Portable agents** \u2014 Move agents between projects\n- **Versioning** \u2014 Track changes with git\n- **Validation** \u2014 Catch errors before runtime\n- **Visualization** \u2014 Debug execution flows\n\n## Protocol Structure\n\n```yaml\n# Agent inputs (provided when creating a session)\ninput:\n COMPANY_NAME: { type: string }\n USER_ID: { type: string, optional: true }\n\n# Persistent resources the agent can read/write\nresources:\n CONVERSATION_SUMMARY:\n description: Summary for handoff\n default: ""\n\n# How the agent can be invoked\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n request-human:\n description: User clicks "Talk to Human"\n\n# Temporary variables for execution (with types)\nvariables:\n SUMMARY:\n type: string\n TICKET:\n type: unknown\n\n# Tools the agent can use\ntools:\n get-user-account:\n description: Looking up your account\n parameters:\n userId: { type: string }\n returns:\n name: { type: string }\n email: { type: string }\n\n# Agent configuration (model, tools, etc.)\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system # References prompts/system.md\n tools: [get-user-account]\n agentic: true # Allow multiple tool calls\n thinking: medium # Extended reasoning\n\n# What happens when triggers fire\nhandlers:\n user-message:\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n \n Respond to user:\n type: next-message\n```\n\n## File Structure\n\nEach agent is a folder with:\n\n```\nmy-agent/\n\u251C\u2500\u2500 protocol.yaml # Main logic (required)\n\u251C\u2500\u2500 settings.json # Agent metadata (required)\n\u2514\u2500\u2500 prompts/ # Prompt templates\n \u251C\u2500\u2500 system.md\n \u251C\u2500\u2500 user-message.md\n \u2514\u2500\u2500 escalation-summary.md\n```\n\n### settings.json\n\n```json\n{\n "slug": "my-agent",\n "name": "My Agent",\n "description": "What this agent does",\n "format": "interactive"\n}\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `slug` | Yes | URL-safe identifier (lowercase, digits, dashes) |\n| `name` | Yes | Human-readable name |\n| `description` | No | Brief description |\n| `format` | Yes | `interactive` (chat) or `generation` (background) |\n\n## Naming Conventions\n\n- **Slugs**: `lowercase-with-dashes`\n- **Variables**: `UPPERCASE_SNAKE_CASE`\n- **Prompts**: `lowercase-with-dashes.md`\n- **Tools**: `lowercase-with-dashes`\n- **Triggers**: `lowercase-with-dashes`\n\n## Variables in Prompts\n\nReference variables with `{{VARIABLE_NAME}}`:\n\n```markdown\n<!-- prompts/system.md -->\nYou are a support agent for {{COMPANY_NAME}}.\n\nHelp users with their {{PRODUCT_NAME}} questions.\n\n## Support Policies\n\n{{SUPPORT_POLICIES}}\n```\n\nVariables are replaced with their values at runtime. If a variable is not provided, it\'s replaced with an empty string.\n\n## Next Steps\n\n- [Input & Resources](/docs/protocol/input-resources) \u2014 Defining agent inputs\n- [Triggers](/docs/protocol/triggers) \u2014 How agents are invoked\n- [Tools](/docs/protocol/tools) \u2014 External capabilities\n- [Handlers](/docs/protocol/handlers) \u2014 Execution blocks\n- [Agent Config](/docs/protocol/agent-config) \u2014 Model and settings\n\n',
99
- excerpt: "Protocol Overview Agent protocols define how an AI agent behaves. They're written in YAML and specify inputs, triggers, tools, and execution handlers. Why Protocols? Protocols provide: - Declarative...",
100
- order: 1
101
- },
102
- {
103
- slug: "protocol/input-resources",
104
- section: "protocol",
105
- title: "Input & Resources",
106
- description: "Defining agent inputs and persistent resources.",
107
- 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",
108
- 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...",
109
- order: 2
110
- },
111
- {
112
- slug: "protocol/triggers",
113
- section: "protocol",
114
- title: "Triggers",
115
- description: "Defining how agents are invoked.",
116
- 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 \u2014 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```typescript\n// User message trigger\nawait triggerAction('user-message', { \n USER_MESSAGE: 'How do I reset my password?' \n});\n\n// User action trigger (no input)\nawait triggerAction('request-human');\n\n// Action with input\nawait triggerAction('submit-feedback', { \n RATING: 5, \n 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\n",
117
- 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 \u2014 when a user sends a...",
118
- order: 3
119
- },
120
- {
121
- slug: "protocol/tools",
122
- section: "protocol",
123
- title: "Tools",
124
- description: "Defining external tools agents can use.",
125
- 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 returns:\n name: { type: string }\n email: { type: string }\n plan: { type: string }\n createdAt: { type: string }\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| `required` | No | List of required parameter names |\n| `returns` | No | Schema of the return value (for documentation) |\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## Parameter Types\n\nSupported types: `string`, `number`, `boolean`, `unknown`\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 (electronics, clothing, books, home)\n \n maxPrice:\n type: number\n description: Maximum price filter\n \n inStock:\n type: boolean\n description: Only show in-stock items\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\nReference tool results in prompts:\n\n```markdown\n<!-- prompts/ticket-directive.md -->\nA support ticket has been created:\n- Ticket ID: {{TICKET.ticketId}}\n- Estimated Response: {{TICKET.estimatedResponse}}\n\nLet the user know their ticket has been created.\n```\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 # Can reference ACCOUNT here\n email: ACCOUNT.email\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. Define Expected Returns\n\n```yaml\ntools:\n search-products:\n description: Search products\n parameters:\n query: { type: string }\n returns:\n products:\n type: unknown\n description: Array of product objects\n totalCount:\n type: number\n```\n\n### 3. 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\n",
126
- 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 |...",
127
- order: 4
128
- },
129
- {
130
- slug: "protocol/handlers",
131
- section: "protocol",
132
- title: "Handlers",
133
- description: "Defining execution handlers with blocks.",
134
- content: "\n# Handlers\n\nHandlers define what happens when a trigger fires. They contain execution blocks that run in sequence.\n\n## Handler Structure\n\n```yaml\nhandlers:\n trigger-name:\n Block Name:\n type: block-type\n # block-specific properties\n \n Another Block:\n type: another-type\n # ...\n```\n\nEach block has a human-readable name (shown in debug UI) and a type that determines its behavior.\n\n## Block Types\n\n### next-message\n\nGenerate a response from the LLM:\n\n```yaml\nhandlers:\n user-message:\n Respond to user:\n type: next-message\n # Uses main conversation thread by default\n # Display defaults to 'stream'\n```\n\nWith options:\n\n```yaml\nGenerate summary:\n type: next-message\n thread: summary # Use named thread\n display: stream # Show streaming content\n independent: true # Don't add to main chat\n output: SUMMARY # Store output in variable\n description: Generating summary # Shown in UI\n```\n\n### add-message\n\nAdd a message to the conversation:\n\n```yaml\nAdd user message:\n type: add-message\n role: user # user | assistant | system\n prompt: user-message # Reference to prompt file\n input: [USER_MESSAGE] # Variables to interpolate\n display: hidden # Don't show in UI\n```\n\nFor internal directives (LLM sees it, user doesn't):\n\n```yaml\nAdd internal directive:\n type: add-message\n role: user\n prompt: ticket-directive\n input: [TICKET_DETAILS]\n visible: false # LLM sees this, user doesn't\n```\n\n### tool-call\n\nCall a tool deterministically:\n\n```yaml\nCreate ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY # Variable reference\n priority: medium # Literal value\n output: TICKET # Store result\n```\n\n### set-resource\n\nUpdate a persistent resource:\n\n```yaml\nSave summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY # Variable to save\n display: name # Show block name\n```\n\n### start-thread\n\nCreate a named conversation thread:\n\n```yaml\nStart summary thread:\n type: start-thread\n thread: summary # Thread name\n model: anthropic/claude-sonnet-4-5 # Optional: different model\n thinking: low # Extended reasoning level\n maxSteps: 1 # Tool call limit\n system: escalation-summary # System prompt\n input: [COMPANY_NAME] # Variables for prompt\n```\n\n### serialize-thread\n\nConvert conversation to text:\n\n```yaml\nSerialize conversation:\n type: serialize-thread\n thread: main # Which thread (default: main)\n format: markdown # markdown | json\n output: CONVERSATION_TEXT # Variable to store result\n```\n\n## Display Modes\n\nEvery block has a `display` property:\n\n| Mode | Default For | Behavior |\n|------|-------------|----------|\n| `hidden` | add-message | Not shown to user |\n| `name` | set-resource | Shows block name |\n| `description` | tool-call | Shows description |\n| `stream` | next-message | Streams content |\n\n## Complete Example\n\n```yaml\nhandlers:\n user-message:\n # Add the user's message to conversation\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n display: hidden\n \n # Generate response (LLM may call tools)\n Respond to user:\n type: next-message\n # display: stream (default)\n\n request-human:\n # Step 1: Serialize conversation for summary\n Serialize conversation:\n type: serialize-thread\n format: markdown\n output: CONVERSATION_TEXT\n \n # Step 2: Create separate thread for summarization\n Start summary thread:\n type: start-thread\n thread: summary\n model: anthropic/claude-sonnet-4-5\n thinking: low\n system: escalation-summary\n input: [COMPANY_NAME]\n \n # Step 3: Add request to summary thread\n Add summarize request:\n type: add-message\n thread: summary\n role: user\n prompt: summarize-request\n input:\n - CONVERSATION: CONVERSATION_TEXT\n \n # Step 4: Generate summary\n Generate summary:\n type: next-message\n thread: summary\n display: stream\n description: Summarizing your conversation\n independent: true\n output: SUMMARY\n \n # Step 5: Save to resource\n Save summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY\n \n # Step 6: Create support ticket\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 # Step 7: Add directive for response\n Add directive:\n type: add-message\n role: user\n prompt: ticket-directive\n input: [TICKET_DETAILS: TICKET]\n visible: false\n \n # Step 8: Respond to user\n Respond:\n type: next-message\n```\n\n## Block Input Mapping\n\nMap variables to block inputs:\n\n```yaml\n# Simple list (variable name = prompt variable)\ninput: [USER_MESSAGE, COMPANY_NAME]\n\n# Mapping (different names)\ninput:\n - CONVERSATION: CONVERSATION_TEXT # CONVERSATION in prompt = CONVERSATION_TEXT\n - TICKET_DETAILS: TICKET\n```\n\n## Independent Blocks\n\nUse `independent: true` for content that shouldn't go to the main chat:\n\n```yaml\nGenerate summary:\n type: next-message\n thread: summary\n independent: true # Output stored in variable, not main chat\n output: SUMMARY\n```\n\nThis is useful for:\n- Background processing\n- Summarization in separate threads\n- Generating content for tools\n\n",
135
- excerpt: "Handlers Handlers define what happens when a trigger fires. They contain execution blocks that run in sequence. Handler Structure Each block has a human-readable name (shown in debug UI) and a type...",
136
- order: 5
137
- },
138
- {
139
- slug: "protocol/agent-config",
140
- section: "protocol",
141
- title: "Agent Config",
142
- description: "Configuring the agent model and behavior.",
143
- content: "\n# Agent Config\n\nThe `agent` section configures the LLM model, system prompt, tools, and behavior.\n\n## Basic Configuration\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system # References prompts/system.md\n tools: [get-user-account] # Available tools\n```\n\n## Configuration Options\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `model` | Yes | Model identifier (provider/model-id) |\n| `system` | Yes | System prompt filename (without .md) |\n| `input` | No | Variables to interpolate in system prompt |\n| `tools` | No | List of tools the LLM can call |\n| `agentic` | No | Allow multiple tool call cycles |\n| `maxSteps` | No | Maximum agentic steps (default: 10) |\n| `temperature` | No | Model temperature (0-2) |\n| `thinking` | No | Extended reasoning level |\n\n## Models\n\nSpecify models in `provider/model-id` format:\n\n```yaml\n# Anthropic\nagent:\n model: anthropic/claude-sonnet-4-5 # Claude 4.5 Sonnet\n model: anthropic/claude-opus-4 # Claude 4 Opus\n\n# OpenAI\nagent:\n model: openai/gpt-4o # GPT-4o\n model: openai/gpt-4o-mini # GPT-4o Mini\n model: openai/o1 # O1\n model: openai/o3-mini # O3 Mini\n```\n\n## System Prompt\n\nThe system prompt sets the agent's persona and instructions:\n\n```yaml\nagent:\n system: system # Uses prompts/system.md\n input:\n - COMPANY_NAME\n - PRODUCT_NAME\n - SUPPORT_POLICIES\n```\n\nExample `prompts/system.md`:\n\n```markdown\nYou are a friendly support agent for {{COMPANY_NAME}}.\n\n## Your Role\n\nHelp users with questions about {{PRODUCT_NAME}}.\n\n## Guidelines\n\n- Be helpful and professional\n- If you can't help, offer to escalate\n- Never share internal information\n\n{{#if SUPPORT_POLICIES}}\n## Support Policies\n\n{{SUPPORT_POLICIES}}\n{{/if}}\n```\n\n## Agentic Mode\n\nEnable multi-step tool calling:\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system\n tools: [get-user-account, search-docs, create-ticket]\n agentic: true # LLM can call multiple tools\n maxSteps: 10 # Limit cycles to prevent runaway\n```\n\n**How it works:**\n1. LLM receives user message\n2. LLM decides to call a tool\n3. Tool executes, result returned to LLM\n4. LLM decides if more tools needed\n5. Repeat until LLM responds or maxSteps reached\n\n## Extended Thinking\n\nEnable extended reasoning for complex tasks:\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n thinking: medium # low | medium | high\n```\n\n| Level | Token Budget | Use Case |\n|-------|-------------|----------|\n| `low` | ~5,000 | Simple reasoning |\n| `medium` | ~10,000 | Moderate complexity |\n| `high` | ~20,000 | Complex analysis |\n\nThinking content streams to the UI and can be displayed to users.\n\n## Temperature\n\nControl response randomness:\n\n```yaml\nagent:\n model: openai/gpt-4o\n temperature: 0.7 # 0 = deterministic, 2 = creative\n```\n\n**Guidelines:**\n- `0 - 0.3`: Factual, consistent responses\n- `0.4 - 0.7`: Balanced (good default)\n- `0.8 - 1.2`: Creative, varied responses\n- `> 1.2`: Very creative (may be inconsistent)\n\n## Thread-Specific Config\n\nOverride config for named threads:\n\n```yaml\nhandlers:\n request-human:\n Start summary thread:\n type: start-thread\n thread: summary\n model: anthropic/claude-sonnet-4-5 # Different model\n thinking: low # Different thinking\n maxSteps: 1 # Limit tool calls\n system: escalation-summary # Different prompt\n```\n\n## Full Example\n\n```yaml\ninput:\n COMPANY_NAME: { type: string }\n PRODUCT_NAME: { type: string }\n USER_ID: { type: string, optional: true }\n\nresources:\n CONVERSATION_SUMMARY:\n type: string\n default: \"\"\n\ntools:\n get-user-account:\n description: Look up user account\n parameters:\n userId: { type: string }\n \n search-docs:\n description: Search help documentation\n parameters:\n query: { 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\n\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system\n input:\n - COMPANY_NAME\n - PRODUCT_NAME\n tools:\n - get-user-account\n - search-docs\n - create-support-ticket\n agentic: true\n maxSteps: 10\n thinking: medium\n\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n\nhandlers:\n user-message:\n Add message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n display: hidden\n \n Respond:\n type: next-message\n```\n\n",
144
- excerpt: "Agent Config The section configures the LLM model, system prompt, tools, and behavior. Basic Configuration Configuration Options | Field | Required | Description |...",
145
- order: 6
146
- },
147
- {
148
- slug: "api-reference/overview",
149
- section: "api-reference",
150
- title: "Overview",
151
- description: "REST API overview and authentication.",
152
- 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 \u2192 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',
153
- 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...",
154
- order: 1
155
- },
156
- {
157
- slug: "api-reference/sessions",
158
- section: "api-reference",
159
- title: "Sessions",
160
- description: "Session management API endpoints.",
161
- content: '\n# Sessions API\n\nSessions represent conversations with agents. They store conversation history, resources, and variables.\n\n## Create Session\n\nCreate a new agent session.\n\n```\nPOST /api/agent-sessions\n```\n\n### Request Body\n\n```json\n{\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro",\n "USER_ID": "user-123"\n }\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `agentId` | string | Yes | Agent ID (the `id` field, not `slug`) |\n| `input` | object | No | Input variables for the agent |\n\n> To get the agent ID, copy it from the platform URL, use [Get Agent by slug](/docs/api-reference/agents#get-agent) (`GET /api/agents/:slug?by=slug`), or the SDK\'s `agents.getBySlug()` method.\n\n### Response\n\n```json\n{\n "sessionId": "cm5xyz123abc456def"\n}\n```\n\n### Example\n\n```bash\ncurl -X POST https://octavus.ai/api/agent-sessions \\\n -H "Authorization: Bearer YOUR_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro"\n }\n }\'\n```\n\n## Get Session\n\nRetrieve session state including messages and resources.\n\n```\nGET /api/agent-sessions/:sessionId\n```\n\n### Response\n\n```json\n{\n "id": "cm5xyz123abc456def",\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro"\n },\n "variables": {},\n "resources": {\n "CONVERSATION_SUMMARY": ""\n },\n "messages": [\n {\n "id": "1702345800000-xyz789a",\n "role": "user",\n "parts": [\n { "type": "text", "visible": true, "content": "How do I reset my password?" }\n ],\n "content": "How do I reset my password?",\n "createdAt": "2024-01-15T10:30:00Z"\n },\n {\n "id": "1702345805000-def456b",\n "role": "assistant",\n "parts": [\n { "type": "text", "visible": true, "content": "I can help you reset your password..." }\n ],\n "content": "I can help you reset your password...",\n "createdAt": "2024-01-15T10:30:05Z"\n }\n ],\n "createdAt": "2024-01-15T10:30:00Z",\n "updatedAt": "2024-01-15T10:30:05Z"\n}\n```\n\n### Example\n\n```bash\ncurl https://octavus.ai/api/agent-sessions/:sessionId \\\n -H "Authorization: Bearer YOUR_API_KEY"\n```\n\n## Trigger Session\n\nExecute a trigger on a session. Returns a Server-Sent Events stream.\n\n```\nPOST /api/agent-sessions/:sessionId/trigger\n```\n\n### Request Body\n\n```json\n{\n "triggerName": "user-message",\n "input": {\n "USER_MESSAGE": "How do I reset my password?"\n },\n "toolResults": []\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `triggerName` | string | Yes | Name of the trigger to execute |\n| `input` | object | No | Input variables for the trigger |\n| `toolResults` | array | No | Tool results for continuation (handled by SDK) |\n\n### Response\n\nReturns `text/event-stream` with SSE events:\n\n```\ndata: {"type":"start","messageId":"msg-123"}\n\ndata: {"type":"block-start","blockId":"b1","blockName":"Add user message","blockType":"add-message","display":"hidden"}\n\ndata: {"type":"block-end","blockId":"b1"}\n\ndata: {"type":"block-start","blockId":"b2","blockName":"Respond to user","blockType":"next-message","display":"stream","outputToChat":true}\n\ndata: {"type":"text-start","id":"t1"}\n\ndata: {"type":"text-delta","id":"t1","delta":"I"}\n\ndata: {"type":"text-delta","id":"t1","delta":" can"}\n\ndata: {"type":"text-delta","id":"t1","delta":" help"}\n\ndata: {"type":"text-delta","id":"t1","delta":" you"}\n\ndata: {"type":"text-delta","id":"t1","delta":" reset"}\n\ndata: {"type":"text-delta","id":"t1","delta":" your"}\n\ndata: {"type":"text-delta","id":"t1","delta":" password"}\n\ndata: {"type":"text-delta","id":"t1","delta":"!"}\n\ndata: {"type":"text-end","id":"t1"}\n\ndata: {"type":"block-end","blockId":"b2"}\n\ndata: {"type":"finish","finishReason":"stop"}\n\ndata: [DONE]\n```\n\n### Event Types\n\n| Event | Description |\n|-------|-------------|\n| `start` | Stream started |\n| `finish` | Execution complete |\n| `error` | Error occurred |\n| `block-start` | Execution block started |\n| `block-end` | Execution block completed |\n| `text-start` | Text generation started |\n| `text-delta` | Incremental text content |\n| `text-end` | Text generation ended |\n| `reasoning-start` | Extended reasoning started |\n| `reasoning-delta` | Reasoning content |\n| `reasoning-end` | Extended reasoning ended |\n| `tool-input-start` | Tool call initiated |\n| `tool-input-delta` | Tool arguments streaming |\n| `tool-input-end` | Tool arguments streaming ended |\n| `tool-input-available` | Tool input complete |\n| `tool-output-available` | Tool completed with result |\n| `tool-output-error` | Tool failed |\n| `tool-request` | Platform requesting tool execution |\n| `resource-update` | Resource value changed |\n\n### Example\n\n```bash\ncurl -N -X POST https://octavus.ai/api/agent-sessions/:sessionId/trigger \\\n -H "Authorization: Bearer YOUR_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "triggerName": "user-message",\n "input": { "USER_MESSAGE": "How do I reset my password?" }\n }\'\n```\n\n## Tool Continuation\n\nWhen the agent calls external tools, you\'ll receive a `tool-request` event. Execute the tools and send results back:\n\n```json\n{\n "triggerName": "user-message",\n "input": { "USER_MESSAGE": "..." },\n "toolResults": [\n {\n "toolCallId": "tc_123",\n "toolName": "get-user-account",\n "result": {\n "name": "Demo User",\n "email": "demo@example.com"\n }\n }\n ]\n}\n```\n\nThe Server SDK handles this continuation pattern automatically.\n',
162
- excerpt: "Sessions API Sessions represent conversations with agents. They store conversation history, resources, and variables. Create Session Create a new agent session. Request Body | Field | Type |...",
163
- order: 2
164
- },
165
- {
166
- slug: "api-reference/agents",
167
- section: "api-reference",
168
- title: "Agents",
169
- description: "Agent management API endpoints.",
170
- 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',
171
- 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 ...",
172
- order: 3
173
- }
174
- ];
175
-
176
- // dist/sections.json
177
- var sections_default = [
178
- {
179
- slug: "getting-started",
180
- title: "Getting Started",
181
- description: "Learn the basics of Octavus and how to integrate AI agents into your application.",
182
- order: 1,
183
- docs: [
184
- {
185
- slug: "getting-started/introduction",
186
- section: "getting-started",
187
- title: "Introduction",
188
- description: "Overview of Octavus AI - an agent orchestration platform for developers.",
189
- 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** \u2014 No unified way to define, manage, and deploy agents\n- **Prompt management** \u2014 Prompts are scattered across codebases, hard to version and iterate\n- **Integration complexity** \u2014 Connecting agents to tools, resources, and other agents requires significant custom work\n- **Observability** \u2014 Difficult to debug, monitor, and understand agent behavior in production\n- **Infrastructure overhead** \u2014 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 \u2014 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** \u2014 Respond to a text message in a chat interface\n- **User Action** \u2014 Respond to UI actions (button clicks, form submissions)\n- **API Call** \u2014 Direct invocation via SDK\n\n### Tools\n\n**Tools** extend what agents can do:\n\n- **External Tools** \u2014 Consumer-defined tools that call back to your systems\n- **Internal Tools** \u2014 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) \u2014 Get your first agent running in minutes\n- [Server SDK](/docs/server-sdk/overview) \u2014 Learn about backend integration\n- [Client SDK](/docs/client-sdk/overview) \u2014 Build chat interfaces with React\n- [Protocol Reference](/docs/protocol/overview) \u2014 Deep dive into agent protocols\n\n",
190
- 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...",
191
- order: 1
192
- },
193
- {
194
- slug: "getting-started/quickstart",
195
- section: "getting-started",
196
- title: "Quick Start",
197
- description: "Get your first Octavus agent running in minutes.",
198
- 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# Client SDK for frontend (React)\nnpm install @octavus/client-sdk\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 to build a chat interface:\n\n```tsx\n// components/chat.tsx\n'use client';\n\nimport { useOctavusChat } from '@octavus/client-sdk';\nimport { useState } from 'react';\n\ninterface ChatProps {\n sessionId: string;\n}\n\nexport function Chat({ sessionId }: ChatProps) {\n const [inputValue, setInputValue] = useState('');\n\n const {\n messages,\n status,\n isLoading,\n streamingText,\n addUserMessage,\n triggerAction,\n } = useOctavusChat({\n onTrigger: async (triggerName, input) => {\n return fetch('/api/trigger', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId, triggerName, input }),\n });\n },\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!inputValue.trim() || isLoading) return;\n\n const message = inputValue.trim();\n setInputValue('');\n\n // Add user message to UI\n addUserMessage(message);\n\n // Trigger the agent\n await triggerAction('user-message', { USER_MESSAGE: message });\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 <div\n key={msg.id}\n className={`p-3 rounded-lg ${\n msg.role === 'user'\n ? 'bg-blue-500 text-white ml-auto max-w-xs'\n : 'bg-gray-100 max-w-md'\n }`}\n >\n {msg.content}\n </div>\n ))}\n\n {/* Streaming text */}\n {streamingText && (\n <div className=\"bg-gray-100 p-3 rounded-lg max-w-md\">\n {streamingText}\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={isLoading}\n />\n <button\n type=\"submit\"\n disabled={isLoading}\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```\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\n",
199
- 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...",
200
- order: 2
201
- }
202
- ]
203
- },
204
- {
205
- slug: "server-sdk",
206
- title: "Server SDK",
207
- description: "Backend integration with @octavus/server-sdk for Node.js applications.",
208
- order: 2,
209
- docs: [
210
- {
211
- slug: "server-sdk/overview",
212
- section: "server-sdk",
213
- title: "Overview",
214
- description: "Introduction to the Octavus Server SDK for backend integration.",
215
- 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.1.0`\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('support-chat', {\n COMPANY_NAME: 'Acme Corp',\n PRODUCT_NAME: 'Widget Pro',\n});\n\n// Get session state\nconst state = await client.agentSessions.get(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 session state\n async get(sessionId: string): Promise<SessionState>;\n \n // Attach to a session for triggering\n attach(sessionId: string, options?: SessionAttachOptions): AgentSession;\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) \u2014 Deep dive into session management\n- [Tools](/docs/server-sdk/tools) \u2014 Implementing tool handlers\n- [Streaming](/docs/server-sdk/streaming) \u2014 Understanding stream events\n\n",
216
- 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...",
217
- order: 1
218
- },
219
- {
220
- slug: "server-sdk/sessions",
221
- section: "server-sdk",
222
- title: "Sessions",
223
- description: "Managing agent sessions with the Server SDK.",
224
- 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## Session State\n\nRetrieve the current state of a session:\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,\n resources: state.resources,\n variables: state.variables,\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n});\n```\n\n### SessionState Interface\n\n```typescript\ninterface SessionState {\n id: string;\n agentId: string;\n input: Record<string, unknown>; // Initial input (immutable)\n variables: Record<string, unknown>; // Mutable session variables\n resources: Record<string, unknown>; // Resources (synced to consumer)\n messages: ChatMessage[]; // Conversation history\n createdAt: string;\n updatedAt: string;\n}\n```\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.get()**\n Get current state\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 state = await client.agentSessions.get(sessionId);\n\n// Pass messages to frontend to restore UI\nreturn {\n sessionId,\n messages: state.messages,\n resources: state.resources,\n};\n```\n\nThe `messages` array includes all conversation history with proper content ordering (text, tool calls, thinking blocks), enabling accurate UI restoration.\n\n## Error Handling\n\n```typescript\nimport { ApiError } from '@octavus/server-sdk';\n\ntry {\n const state = await client.agentSessions.get(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\n",
225
- 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...",
226
- order: 2
227
- },
228
- {
229
- slug: "server-sdk/tools",
230
- section: "server-sdk",
231
- title: "Tools",
232
- description: "Implementing tool handlers with the Server SDK.",
233
- 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- \u2705 **Full data access** \u2014 Query your database directly\n- \u2705 **Your authentication** \u2014 Use your existing auth context\n- \u2705 **No data exposure** \u2014 Sensitive data never leaves your infrastructure\n- \u2705 **Custom logic** \u2014 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",
234
- 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...",
235
- order: 3
236
- },
237
- {
238
- slug: "server-sdk/streaming",
239
- section: "server-sdk",
240
- title: "Streaming",
241
- description: "Understanding stream events from the Server SDK.",
242
- 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## Handling Streams Manually\n\nIf you need to process the stream server-side:\n\n```typescript\nimport { safeParseStreamEvent } from '@octavus/core';\n\nconst { stream } = session.trigger('user-message', { USER_MESSAGE: 'Hello' });\n\nconst reader = stream.getReader();\nconst decoder = new TextDecoder();\n\nlet buffer = '';\n\nwhile (true) {\n const { done, value } = await reader.read();\n if (done) break;\n \n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n \n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n const parsed = safeParseStreamEvent(JSON.parse(line.slice(6)));\n if (parsed.success) {\n const event = parsed.data;\n \n switch (event.type) {\n case 'text-delta':\n process.stdout.write(event.delta);\n break;\n case 'finish':\n console.log('\\nDone:', event.finishReason);\n break;\n }\n }\n }\n }\n}\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",
243
- 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...",
244
- order: 4
245
- }
246
- ]
247
- },
248
- {
249
- slug: "client-sdk",
250
- title: "Client SDK",
251
- description: "Frontend integration with @octavus/client-sdk for React applications.",
252
- order: 3,
253
- docs: [
254
- {
255
- slug: "client-sdk/overview",
256
- section: "client-sdk",
257
- title: "Overview",
258
- description: "Introduction to the Octavus Client SDK for building chat interfaces.",
259
- content: "\n# Client SDK Overview\n\nThe `@octavus/client-sdk` package provides React hooks for building chat interfaces with Octavus agents. It handles streaming, message state, and execution blocks.\n\n**Current version:** `0.1.0`\n\n## Installation\n\n```bash\nnpm install @octavus/client-sdk\n```\n\n## Basic Usage\n\n```tsx\nimport { useOctavusChat } from '@octavus/client-sdk';\n\nfunction Chat({ sessionId }: { sessionId: string }) {\n const {\n messages,\n status,\n isLoading,\n streamingText,\n addUserMessage,\n triggerAction,\n } = useOctavusChat({\n onTrigger: async (triggerName, input) => {\n return fetch(`/api/chat/${sessionId}/trigger`, {\n method: 'POST',\n body: JSON.stringify({ triggerName, input }),\n });\n },\n });\n\n const sendMessage = async (text: string) => {\n addUserMessage(text);\n await triggerAction('user-message', { USER_MESSAGE: text });\n };\n\n return (\n <div>\n {messages.map((msg) => (\n <div key={msg.id}>{msg.content}</div>\n ))}\n {streamingText && <div>{streamingText}</div>}\n </div>\n );\n}\n```\n\n## Key Features\n\n### Real-time Streaming\n\nText streams incrementally as the LLM generates it:\n\n```tsx\nconst { streamingText, streamingParts } = useOctavusChat({...});\n\n// streamingText: Current streaming text\n// streamingParts: Structured parts (text, reasoning, tool calls)\n```\n\n### Message History\n\nMessages are tracked automatically:\n\n```tsx\nconst { messages } = useOctavusChat({...});\n\n// Each message includes:\n// - id: Unique identifier\n// - role: 'user' | 'assistant'\n// - content: Text content\n// - parts: Ordered content parts\n// - toolCalls: Tool call information\n// - reasoning: Extended reasoning (if enabled)\n```\n\n### Execution Blocks\n\nTrack what the agent is doing:\n\n```tsx\nconst { executionBlocks } = useOctavusChat({...});\n\n// Shows active execution steps\n// Useful for progress indicators\n```\n\n### Status Tracking\n\n```tsx\nconst { status, isLoading } = useOctavusChat({...});\n\n// status: 'idle' | 'loading' | 'streaming' | 'error'\n// isLoading: true during loading or streaming\n```\n\n## Hook Reference\n\n### useOctavusChat\n\n```typescript\nfunction useOctavusChat(options: UseOctavusChatOptions): UseOctavusChatReturn;\n\ninterface UseOctavusChatOptions {\n // Required: Function that calls your backend trigger endpoint\n onTrigger: TriggerFunction;\n \n // Optional: Pre-populate with existing messages (session restore)\n initialMessages?: Message[];\n \n // Optional: Callbacks\n onMessage?: (message: Message) => void;\n onError?: (error: Error) => void;\n onDone?: () => void;\n onResourceUpdate?: (name: string, value: unknown) => void;\n onBlockStart?: (block: ExecutionBlock) => void;\n onBlockEnd?: (block: ExecutionBlock) => void;\n}\n\ninterface UseOctavusChatReturn {\n // State\n messages: Message[];\n status: ChatStatus;\n isLoading: boolean;\n error: Error | null;\n streamingText: string;\n streamingParts: MessagePart[];\n executionBlocks: ExecutionBlock[];\n reasoningText: string;\n \n // Actions\n addUserMessage: (content: string) => void;\n triggerAction: (triggerName: string, input?: Record<string, unknown>) => Promise<void>;\n}\n```\n\n## Next Steps\n\n- [Messages](/docs/client-sdk/messages) \u2014 Working with message state\n- [Streaming](/docs/client-sdk/streaming) \u2014 Building streaming UIs\n- [Execution Blocks](/docs/client-sdk/execution-blocks) \u2014 Showing agent progress\n",
260
- excerpt: "Client SDK Overview The package provides React hooks for building chat interfaces with Octavus agents. It handles streaming, message state, and execution blocks. Current version: Installation ...",
261
- order: 1
262
- },
263
- {
264
- slug: "client-sdk/messages",
265
- section: "client-sdk",
266
- title: "Messages",
267
- description: "Working with message state in the Client SDK.",
268
- content: "\n# Messages\n\nMessages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content.\n\n## Message Structure\n\n```typescript\ninterface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n parts?: MessagePart[];\n toolCalls?: ToolCallWithDescription[];\n reasoning?: string;\n visible?: boolean;\n createdAt: Date;\n}\n```\n\n### Message Parts\n\nFor rich content display, use the `parts` array which preserves content ordering:\n\n```typescript\ninterface MessagePart {\n type: 'text' | 'reasoning' | 'tool-call';\n visible: boolean;\n content?: string; // For text and reasoning\n toolCall?: ToolCallInfo; // For tool-call\n thread?: string; // For non-main thread content\n}\n```\n\n## Adding User Messages\n\n```tsx\nconst { addUserMessage, triggerAction } = useOctavusChat({...});\n\nasync function sendMessage(text: string) {\n // 1. Add message to UI immediately\n addUserMessage(text);\n \n // 2. Trigger the agent\n await triggerAction('user-message', { USER_MESSAGE: text });\n}\n```\n\n**Important**: `addUserMessage` only updates UI state. You must call `triggerAction` to actually send the message to the agent.\n\n## Rendering Messages\n\n### Basic Rendering\n\n```tsx\nfunction MessageList({ messages }: { messages: Message[] }) {\n return (\n <div className=\"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 className=\"inline-block p-3 rounded-lg\">\n {msg.content}\n </div>\n </div>\n ))}\n </div>\n );\n}\n```\n\n### Rich Rendering with Parts\n\nFor messages with tool calls and reasoning, render parts in order:\n\n```tsx\nfunction MessageContent({ message }: { message: Message }) {\n if (!message.parts) {\n return <p>{message.content}</p>;\n }\n\n return (\n <div className=\"space-y-2\">\n {message.parts.map((part, i) => {\n if (!part.visible) return null;\n\n switch (part.type) {\n case 'text':\n return <p key={i}>{part.content}</p>;\n\n case 'reasoning':\n return (\n <details key={i} className=\"text-gray-500\">\n <summary>Thinking...</summary>\n <pre className=\"text-sm\">{part.content}</pre>\n </details>\n );\n\n case 'tool-call':\n return (\n <div key={i} className=\"bg-gray-100 p-2 rounded text-sm\">\n \u{1F527} {part.toolCall?.name}\n {part.toolCall?.status === 'available' && ' \u2713'}\n </div>\n );\n\n default:\n return null;\n }\n })}\n </div>\n );\n}\n```\n\n## Tool Calls in Messages\n\nTool calls include status, arguments, and results:\n\n```typescript\ninterface ToolCallInfo {\n id: string;\n name: string;\n description?: string;\n arguments: Record<string, unknown>;\n status: 'pending' | 'streaming' | 'available' | 'error';\n result?: unknown;\n error?: string;\n}\n```\n\n### Rendering Tool Calls\n\n```tsx\nfunction ToolCallCard({ toolCall }: { toolCall: ToolCallInfo }) {\n return (\n <div className=\"border rounded p-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-lg\">\u{1F527}</span>\n <span className=\"font-medium\">{toolCall.description || toolCall.name}</span>\n <StatusBadge status={toolCall.status} />\n </div>\n \n {toolCall.status === 'available' && toolCall.result && (\n <pre className=\"mt-2 text-xs bg-gray-50 p-2 rounded\">\n {JSON.stringify(toolCall.result, null, 2)}\n </pre>\n )}\n \n {toolCall.status === 'error' && (\n <p className=\"mt-2 text-red-500 text-sm\">{toolCall.error}</p>\n )}\n </div>\n );\n}\n```\n\n## Session Restore\n\nWhen restoring a session, pass existing messages:\n\n```tsx\n// Fetch session state from your backend\nconst sessionState = await fetchSession(sessionId);\n\n// Convert ChatMessage[] to Message[]\nconst initialMessages = sessionState.messages\n .filter(msg => msg.visible !== false)\n .map(msg => ({\n id: msg.id,\n role: msg.role,\n content: msg.content,\n parts: msg.parts,\n toolCalls: msg.toolCalls,\n reasoning: msg.reasoning,\n createdAt: new Date(msg.createdAt),\n }));\n\n// Pass to hook\nconst { messages } = useOctavusChat({\n initialMessages,\n onTrigger: ...\n});\n```\n\n## Message Callbacks\n\nGet notified when messages are added:\n\n```tsx\nuseOctavusChat({\n onTrigger: ...,\n onMessage: (message) => {\n console.log('New message:', message.role, message.content);\n \n // Analytics, logging, etc.\n trackMessage(message);\n },\n});\n```\n",
269
- excerpt: "Messages Messages represent the conversation history. The Client SDK tracks messages automatically and provides structured access to their content. Message Structure Message Parts For rich content...",
270
- order: 2
271
- },
272
- {
273
- slug: "client-sdk/streaming",
274
- section: "client-sdk",
275
- title: "Streaming",
276
- description: "Building streaming UIs with the Client SDK.",
277
- content: "\n# Streaming\n\nThe Client SDK provides real-time access to streaming content, enabling responsive UIs that update as the agent generates responses.\n\n## Streaming State\n\n```tsx\nconst {\n streamingText, // Current visible text being streamed\n streamingParts, // Structured parts being streamed\n reasoningText, // Current reasoning content\n status, // 'idle' | 'loading' | 'streaming' | 'error'\n isLoading, // true during loading or streaming\n} = useOctavusChat({...});\n```\n\n## Basic Streaming UI\n\n```tsx\nfunction Chat() {\n const { messages, streamingText, isLoading } = useOctavusChat({...});\n\n return (\n <div>\n {/* Completed messages */}\n {messages.map((msg) => (\n <div key={msg.id}>{msg.content}</div>\n ))}\n\n {/* Currently streaming */}\n {streamingText && (\n <div className=\"animate-pulse\">\n {streamingText}\n <span className=\"inline-block w-2 h-4 bg-gray-400 ml-1\" />\n </div>\n )}\n </div>\n );\n}\n```\n\n## Streaming Parts\n\nFor rich streaming UIs, use `streamingParts`:\n\n```tsx\nfunction StreamingContent() {\n const { streamingParts } = useOctavusChat({...});\n\n return (\n <div>\n {streamingParts.map((part, i) => {\n switch (part.type) {\n case 'text':\n return <span key={i}>{part.content}</span>;\n\n case 'reasoning':\n return (\n <div key={i} className=\"text-gray-500 italic\">\n \u{1F4AD} {part.content}\n </div>\n );\n\n case 'tool-call':\n return (\n <div key={i} className=\"flex items-center gap-2\">\n <Spinner />\n <span>{part.toolCall?.description}</span>\n </div>\n );\n }\n })}\n </div>\n );\n}\n```\n\n## Reasoning Indicator\n\nShow when the model is using extended reasoning:\n\n```tsx\nfunction ReasoningIndicator() {\n const { reasoningText, status } = useOctavusChat({...});\n\n if (!reasoningText || status !== 'streaming') {\n return null;\n }\n\n return (\n <div className=\"bg-purple-50 p-3 rounded-lg\">\n <div className=\"flex items-center gap-2 text-purple-600\">\n <Brain className=\"w-4 h-4 animate-pulse\" />\n <span className=\"font-medium\">Thinking...</span>\n </div>\n <p className=\"mt-2 text-sm text-gray-600 line-clamp-3\">\n {reasoningText}\n </p>\n </div>\n );\n}\n```\n\n## Status Indicator\n\n```tsx\nfunction StatusIndicator() {\n const { status } = useOctavusChat({...});\n\n switch (status) {\n case 'idle':\n return null;\n case 'loading':\n return <div>Starting...</div>;\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 Stream Completion\n\n```tsx\nuseOctavusChat({\n onTrigger: ...,\n onDone: () => {\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## Streaming with Tool Calls\n\nWhen tools are called, streaming continues after tool execution:\n\n```\n1. User sends message\n2. streamingText starts filling: \"Let me look that up...\"\n3. Tool call starts (visible in streamingParts)\n4. Tool executes (handled by server-sdk)\n5. streamingText continues: \"I found your account...\"\n6. Stream completes, message finalized\n```\n\n```tsx\nfunction ChatWithTools() {\n const { messages, streamingText, streamingParts } = useOctavusChat({...});\n\n // Find active tool call\n const activeToolCall = streamingParts.find(\n p => p.type === 'tool-call' && p.toolCall?.status === 'streaming'\n );\n\n return (\n <div>\n {messages.map(msg => <Message key={msg.id} message={msg} />)}\n\n {/* Show streaming text */}\n {streamingText && <p>{streamingText}</p>}\n\n {/* Show active tool */}\n {activeToolCall && (\n <div className=\"flex items-center gap-2 text-blue-600\">\n <Spinner />\n {activeToolCall.toolCall?.description}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Non-Main Thread Content\n\nNamed threads (like summarization) stream separately:\n\n```tsx\nfunction StreamingContent() {\n const { streamingParts } = useOctavusChat({...});\n\n // Group by thread\n const mainParts = streamingParts.filter(p => !p.thread || p.thread === 'main');\n const otherParts = streamingParts.filter(p => p.thread && p.thread !== 'main');\n\n return (\n <div>\n {/* Main conversation */}\n <div>{mainParts.map(renderPart)}</div>\n\n {/* Named thread (e.g., summarization) */}\n {otherParts.length > 0 && (\n <div className=\"bg-orange-50 p-3 rounded mt-4\">\n <div className=\"text-orange-600 font-medium\">\n Processing in background...\n </div>\n {otherParts.map(renderPart)}\n </div>\n )}\n </div>\n );\n}\n```\n",
278
- excerpt: "Streaming The Client SDK provides real-time access to streaming content, enabling responsive UIs that update as the agent generates responses. Streaming State Basic Streaming UI Streaming Parts...",
279
- order: 3
280
- },
281
- {
282
- slug: "client-sdk/execution-blocks",
283
- section: "client-sdk",
284
- title: "Execution Blocks",
285
- description: "Tracking agent execution progress with the Client SDK.",
286
- content: '\n# Execution Blocks\n\nExecution blocks let you show users what the agent is doing. Each block represents a step in the agent\'s execution flow.\n\n## Block Structure\n\n```typescript\ninterface ExecutionBlock {\n id: string;\n name: string; // Human-readable name from protocol\n type: string; // Block type (next-message, tool-call, etc.)\n status: BlockStatus; // pending | running | completed | error\n display: DisplayMode; // hidden | name | description | stream\n description?: string;\n outputToChat: boolean; // Whether output goes to main chat\n thread?: string; // For named threads\n streamingText: string; // Current streaming content\n reasoning?: string; // Extended reasoning content\n toolCalls: ToolCallWithDescription[];\n startedAt: Date;\n completedAt?: Date;\n}\n```\n\n## Accessing Blocks\n\n```tsx\nconst { executionBlocks, onBlockStart, onBlockEnd } = useOctavusChat({\n onTrigger: ...,\n onBlockStart: (block) => {\n console.log(\'Block started:\', block.name);\n },\n onBlockEnd: (block) => {\n console.log(\'Block completed:\', block.name, block.status);\n },\n});\n```\n\n## Showing Execution Progress\n\n```tsx\nfunction ExecutionProgress() {\n const { executionBlocks, status } = useOctavusChat({...});\n\n if (status !== \'streaming\' || executionBlocks.length === 0) {\n return null;\n }\n\n return (\n <div className="space-y-2">\n {executionBlocks.map((block) => (\n <ExecutionBlockCard key={block.id} block={block} />\n ))}\n </div>\n );\n}\n\nfunction ExecutionBlockCard({ block }: { block: ExecutionBlock }) {\n return (\n <div className="border rounded p-3">\n <div className="flex items-center gap-2">\n <BlockStatusIcon status={block.status} />\n <span className="font-medium">{block.name}</span>\n </div>\n\n {block.description && (\n <p className="text-sm text-gray-500 mt-1">{block.description}</p>\n )}\n\n {/* Show streaming content for stream display mode */}\n {block.display === \'stream\' && block.streamingText && (\n <div className="mt-2 text-sm">\n {block.streamingText}\n </div>\n )}\n\n {/* Show tool calls */}\n {block.toolCalls.length > 0 && (\n <div className="mt-2 space-y-1">\n {block.toolCalls.map((tc) => (\n <div key={tc.id} className="text-sm flex items-center gap-1">\n \u{1F527} {tc.description || tc.name}\n {tc.status === \'available\' && \' \u2713\'}\n {tc.status === \'error\' && \' \u2717\'}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Display Modes\n\nBlocks have different display modes that control visibility:\n\n| Mode | Description | UI Recommendation |\n|------|-------------|-------------------|\n| `hidden` | Not shown to user | Don\'t render |\n| `name` | Shows block name | Show name only |\n| `description` | Shows description | Show name + description |\n| `stream` | Streams content | Show full streaming content |\n\n```tsx\nfunction ExecutionBlockCard({ block }: { block: ExecutionBlock }) {\n // Hidden blocks aren\'t sent to client, but check just in case\n if (block.display === \'hidden\') {\n return null;\n }\n\n return (\n <div className="border rounded p-3">\n {/* Always show name */}\n <div className="font-medium">{block.name}</div>\n\n {/* Show description if display mode is description or stream */}\n {(block.display === \'description\' || block.display === \'stream\') && \n block.description && (\n <p className="text-sm text-gray-500">{block.description}</p>\n )}\n\n {/* Show content if display mode is stream */}\n {block.display === \'stream\' && (\n <div className="mt-2">\n {block.streamingText}\n </div>\n )}\n </div>\n );\n}\n```\n\n## Named Threads\n\nBlocks can belong to named threads (like "summary"). Use the `thread` property:\n\n```tsx\nfunction ExecutionProgress() {\n const { executionBlocks } = useOctavusChat({...});\n\n // Group by thread\n const mainBlocks = executionBlocks.filter(b => !b.thread || b.thread === \'main\');\n const namedThreads = new Map<string, ExecutionBlock[]>();\n\n executionBlocks.forEach(b => {\n if (b.thread && b.thread !== \'main\') {\n if (!namedThreads.has(b.thread)) {\n namedThreads.set(b.thread, []);\n }\n namedThreads.get(b.thread)!.push(b);\n }\n });\n\n return (\n <div>\n {/* Main execution */}\n <div className="space-y-2">\n {mainBlocks.map(b => <BlockCard key={b.id} block={b} />)}\n </div>\n\n {/* Named threads */}\n {Array.from(namedThreads.entries()).map(([thread, blocks]) => (\n <div key={thread} className="mt-4 bg-orange-50 p-3 rounded">\n <div className="text-orange-600 font-medium mb-2">\n Thread: {thread}\n </div>\n {blocks.map(b => <BlockCard key={b.id} block={b} />)}\n </div>\n ))}\n </div>\n );\n}\n```\n\n## Block Status Icons\n\n```tsx\nfunction BlockStatusIcon({ status }: { status: BlockStatus }) {\n switch (status) {\n case \'pending\':\n return <Circle className="w-4 h-4 text-gray-400" />;\n case \'running\':\n return <Loader className="w-4 h-4 text-blue-500 animate-spin" />;\n case \'completed\':\n return <CheckCircle className="w-4 h-4 text-green-500" />;\n case \'error\':\n return <XCircle className="w-4 h-4 text-red-500" />;\n }\n}\n```\n\n## Example: Support Chat with Escalation\n\nWhen a user clicks "Talk to Human", the agent runs multiple blocks:\n\n```tsx\nfunction SupportChatProgress() {\n const { executionBlocks } = useOctavusChat({...});\n\n // Show blocks while streaming\n return (\n <div className="space-y-2">\n {executionBlocks.map((block) => (\n <div key={block.id} className="flex items-center gap-2">\n <BlockStatusIcon status={block.status} />\n <span>{getBlockLabel(block)}</span>\n </div>\n ))}\n </div>\n );\n}\n\nfunction getBlockLabel(block: ExecutionBlock): string {\n // Use description if available, otherwise name\n return block.description || block.name;\n}\n\n// Example output during escalation:\n// \u2713 Serialize conversation\n// \u2713 Start summary thread\n// \u25CF Summarizing your conversation (streaming...)\n// \u25CB Creating a support ticket\n// \u25CB Respond with ticket info\n```\n',
287
- excerpt: "Execution Blocks Execution blocks let you show users what the agent is doing. Each block represents a step in the agent's execution flow. Block Structure Accessing Blocks Showing Execution...",
288
- order: 4
289
- }
290
- ]
291
- },
292
- {
293
- slug: "protocol",
294
- title: "Protocol",
295
- description: "Agent protocol reference - how to define agent behavior with YAML.",
296
- order: 4,
297
- docs: [
298
- {
299
- slug: "protocol/overview",
300
- section: "protocol",
301
- title: "Overview",
302
- description: "Introduction to Octavus agent protocols.",
303
- content: '\n# Protocol Overview\n\nAgent protocols define how an AI agent behaves. They\'re written in YAML and specify inputs, triggers, tools, and execution handlers.\n\n## Why Protocols?\n\nProtocols provide:\n\n- **Declarative definition** \u2014 Define behavior, not implementation\n- **Portable agents** \u2014 Move agents between projects\n- **Versioning** \u2014 Track changes with git\n- **Validation** \u2014 Catch errors before runtime\n- **Visualization** \u2014 Debug execution flows\n\n## Protocol Structure\n\n```yaml\n# Agent inputs (provided when creating a session)\ninput:\n COMPANY_NAME: { type: string }\n USER_ID: { type: string, optional: true }\n\n# Persistent resources the agent can read/write\nresources:\n CONVERSATION_SUMMARY:\n description: Summary for handoff\n default: ""\n\n# How the agent can be invoked\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n request-human:\n description: User clicks "Talk to Human"\n\n# Temporary variables for execution (with types)\nvariables:\n SUMMARY:\n type: string\n TICKET:\n type: unknown\n\n# Tools the agent can use\ntools:\n get-user-account:\n description: Looking up your account\n parameters:\n userId: { type: string }\n returns:\n name: { type: string }\n email: { type: string }\n\n# Agent configuration (model, tools, etc.)\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system # References prompts/system.md\n tools: [get-user-account]\n agentic: true # Allow multiple tool calls\n thinking: medium # Extended reasoning\n\n# What happens when triggers fire\nhandlers:\n user-message:\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n \n Respond to user:\n type: next-message\n```\n\n## File Structure\n\nEach agent is a folder with:\n\n```\nmy-agent/\n\u251C\u2500\u2500 protocol.yaml # Main logic (required)\n\u251C\u2500\u2500 settings.json # Agent metadata (required)\n\u2514\u2500\u2500 prompts/ # Prompt templates\n \u251C\u2500\u2500 system.md\n \u251C\u2500\u2500 user-message.md\n \u2514\u2500\u2500 escalation-summary.md\n```\n\n### settings.json\n\n```json\n{\n "slug": "my-agent",\n "name": "My Agent",\n "description": "What this agent does",\n "format": "interactive"\n}\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `slug` | Yes | URL-safe identifier (lowercase, digits, dashes) |\n| `name` | Yes | Human-readable name |\n| `description` | No | Brief description |\n| `format` | Yes | `interactive` (chat) or `generation` (background) |\n\n## Naming Conventions\n\n- **Slugs**: `lowercase-with-dashes`\n- **Variables**: `UPPERCASE_SNAKE_CASE`\n- **Prompts**: `lowercase-with-dashes.md`\n- **Tools**: `lowercase-with-dashes`\n- **Triggers**: `lowercase-with-dashes`\n\n## Variables in Prompts\n\nReference variables with `{{VARIABLE_NAME}}`:\n\n```markdown\n<!-- prompts/system.md -->\nYou are a support agent for {{COMPANY_NAME}}.\n\nHelp users with their {{PRODUCT_NAME}} questions.\n\n## Support Policies\n\n{{SUPPORT_POLICIES}}\n```\n\nVariables are replaced with their values at runtime. If a variable is not provided, it\'s replaced with an empty string.\n\n## Next Steps\n\n- [Input & Resources](/docs/protocol/input-resources) \u2014 Defining agent inputs\n- [Triggers](/docs/protocol/triggers) \u2014 How agents are invoked\n- [Tools](/docs/protocol/tools) \u2014 External capabilities\n- [Handlers](/docs/protocol/handlers) \u2014 Execution blocks\n- [Agent Config](/docs/protocol/agent-config) \u2014 Model and settings\n\n',
304
- excerpt: "Protocol Overview Agent protocols define how an AI agent behaves. They're written in YAML and specify inputs, triggers, tools, and execution handlers. Why Protocols? Protocols provide: - Declarative...",
305
- order: 1
306
- },
307
- {
308
- slug: "protocol/input-resources",
309
- section: "protocol",
310
- title: "Input & Resources",
311
- description: "Defining agent inputs and persistent resources.",
312
- 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",
313
- 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...",
314
- order: 2
315
- },
316
- {
317
- slug: "protocol/triggers",
318
- section: "protocol",
319
- title: "Triggers",
320
- description: "Defining how agents are invoked.",
321
- 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 \u2014 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```typescript\n// User message trigger\nawait triggerAction('user-message', { \n USER_MESSAGE: 'How do I reset my password?' \n});\n\n// User action trigger (no input)\nawait triggerAction('request-human');\n\n// Action with input\nawait triggerAction('submit-feedback', { \n RATING: 5, \n 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\n",
322
- 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 \u2014 when a user sends a...",
323
- order: 3
324
- },
325
- {
326
- slug: "protocol/tools",
327
- section: "protocol",
328
- title: "Tools",
329
- description: "Defining external tools agents can use.",
330
- 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 returns:\n name: { type: string }\n email: { type: string }\n plan: { type: string }\n createdAt: { type: string }\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| `required` | No | List of required parameter names |\n| `returns` | No | Schema of the return value (for documentation) |\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## Parameter Types\n\nSupported types: `string`, `number`, `boolean`, `unknown`\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 (electronics, clothing, books, home)\n \n maxPrice:\n type: number\n description: Maximum price filter\n \n inStock:\n type: boolean\n description: Only show in-stock items\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\nReference tool results in prompts:\n\n```markdown\n<!-- prompts/ticket-directive.md -->\nA support ticket has been created:\n- Ticket ID: {{TICKET.ticketId}}\n- Estimated Response: {{TICKET.estimatedResponse}}\n\nLet the user know their ticket has been created.\n```\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 # Can reference ACCOUNT here\n email: ACCOUNT.email\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. Define Expected Returns\n\n```yaml\ntools:\n search-products:\n description: Search products\n parameters:\n query: { type: string }\n returns:\n products:\n type: unknown\n description: Array of product objects\n totalCount:\n type: number\n```\n\n### 3. 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\n",
331
- 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 |...",
332
- order: 4
333
- },
334
- {
335
- slug: "protocol/handlers",
336
- section: "protocol",
337
- title: "Handlers",
338
- description: "Defining execution handlers with blocks.",
339
- content: "\n# Handlers\n\nHandlers define what happens when a trigger fires. They contain execution blocks that run in sequence.\n\n## Handler Structure\n\n```yaml\nhandlers:\n trigger-name:\n Block Name:\n type: block-type\n # block-specific properties\n \n Another Block:\n type: another-type\n # ...\n```\n\nEach block has a human-readable name (shown in debug UI) and a type that determines its behavior.\n\n## Block Types\n\n### next-message\n\nGenerate a response from the LLM:\n\n```yaml\nhandlers:\n user-message:\n Respond to user:\n type: next-message\n # Uses main conversation thread by default\n # Display defaults to 'stream'\n```\n\nWith options:\n\n```yaml\nGenerate summary:\n type: next-message\n thread: summary # Use named thread\n display: stream # Show streaming content\n independent: true # Don't add to main chat\n output: SUMMARY # Store output in variable\n description: Generating summary # Shown in UI\n```\n\n### add-message\n\nAdd a message to the conversation:\n\n```yaml\nAdd user message:\n type: add-message\n role: user # user | assistant | system\n prompt: user-message # Reference to prompt file\n input: [USER_MESSAGE] # Variables to interpolate\n display: hidden # Don't show in UI\n```\n\nFor internal directives (LLM sees it, user doesn't):\n\n```yaml\nAdd internal directive:\n type: add-message\n role: user\n prompt: ticket-directive\n input: [TICKET_DETAILS]\n visible: false # LLM sees this, user doesn't\n```\n\n### tool-call\n\nCall a tool deterministically:\n\n```yaml\nCreate ticket:\n type: tool-call\n tool: create-support-ticket\n input:\n summary: SUMMARY # Variable reference\n priority: medium # Literal value\n output: TICKET # Store result\n```\n\n### set-resource\n\nUpdate a persistent resource:\n\n```yaml\nSave summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY # Variable to save\n display: name # Show block name\n```\n\n### start-thread\n\nCreate a named conversation thread:\n\n```yaml\nStart summary thread:\n type: start-thread\n thread: summary # Thread name\n model: anthropic/claude-sonnet-4-5 # Optional: different model\n thinking: low # Extended reasoning level\n maxSteps: 1 # Tool call limit\n system: escalation-summary # System prompt\n input: [COMPANY_NAME] # Variables for prompt\n```\n\n### serialize-thread\n\nConvert conversation to text:\n\n```yaml\nSerialize conversation:\n type: serialize-thread\n thread: main # Which thread (default: main)\n format: markdown # markdown | json\n output: CONVERSATION_TEXT # Variable to store result\n```\n\n## Display Modes\n\nEvery block has a `display` property:\n\n| Mode | Default For | Behavior |\n|------|-------------|----------|\n| `hidden` | add-message | Not shown to user |\n| `name` | set-resource | Shows block name |\n| `description` | tool-call | Shows description |\n| `stream` | next-message | Streams content |\n\n## Complete Example\n\n```yaml\nhandlers:\n user-message:\n # Add the user's message to conversation\n Add user message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n display: hidden\n \n # Generate response (LLM may call tools)\n Respond to user:\n type: next-message\n # display: stream (default)\n\n request-human:\n # Step 1: Serialize conversation for summary\n Serialize conversation:\n type: serialize-thread\n format: markdown\n output: CONVERSATION_TEXT\n \n # Step 2: Create separate thread for summarization\n Start summary thread:\n type: start-thread\n thread: summary\n model: anthropic/claude-sonnet-4-5\n thinking: low\n system: escalation-summary\n input: [COMPANY_NAME]\n \n # Step 3: Add request to summary thread\n Add summarize request:\n type: add-message\n thread: summary\n role: user\n prompt: summarize-request\n input:\n - CONVERSATION: CONVERSATION_TEXT\n \n # Step 4: Generate summary\n Generate summary:\n type: next-message\n thread: summary\n display: stream\n description: Summarizing your conversation\n independent: true\n output: SUMMARY\n \n # Step 5: Save to resource\n Save summary:\n type: set-resource\n resource: CONVERSATION_SUMMARY\n value: SUMMARY\n \n # Step 6: Create support ticket\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 # Step 7: Add directive for response\n Add directive:\n type: add-message\n role: user\n prompt: ticket-directive\n input: [TICKET_DETAILS: TICKET]\n visible: false\n \n # Step 8: Respond to user\n Respond:\n type: next-message\n```\n\n## Block Input Mapping\n\nMap variables to block inputs:\n\n```yaml\n# Simple list (variable name = prompt variable)\ninput: [USER_MESSAGE, COMPANY_NAME]\n\n# Mapping (different names)\ninput:\n - CONVERSATION: CONVERSATION_TEXT # CONVERSATION in prompt = CONVERSATION_TEXT\n - TICKET_DETAILS: TICKET\n```\n\n## Independent Blocks\n\nUse `independent: true` for content that shouldn't go to the main chat:\n\n```yaml\nGenerate summary:\n type: next-message\n thread: summary\n independent: true # Output stored in variable, not main chat\n output: SUMMARY\n```\n\nThis is useful for:\n- Background processing\n- Summarization in separate threads\n- Generating content for tools\n\n",
340
- excerpt: "Handlers Handlers define what happens when a trigger fires. They contain execution blocks that run in sequence. Handler Structure Each block has a human-readable name (shown in debug UI) and a type...",
341
- order: 5
342
- },
343
- {
344
- slug: "protocol/agent-config",
345
- section: "protocol",
346
- title: "Agent Config",
347
- description: "Configuring the agent model and behavior.",
348
- content: "\n# Agent Config\n\nThe `agent` section configures the LLM model, system prompt, tools, and behavior.\n\n## Basic Configuration\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system # References prompts/system.md\n tools: [get-user-account] # Available tools\n```\n\n## Configuration Options\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `model` | Yes | Model identifier (provider/model-id) |\n| `system` | Yes | System prompt filename (without .md) |\n| `input` | No | Variables to interpolate in system prompt |\n| `tools` | No | List of tools the LLM can call |\n| `agentic` | No | Allow multiple tool call cycles |\n| `maxSteps` | No | Maximum agentic steps (default: 10) |\n| `temperature` | No | Model temperature (0-2) |\n| `thinking` | No | Extended reasoning level |\n\n## Models\n\nSpecify models in `provider/model-id` format:\n\n```yaml\n# Anthropic\nagent:\n model: anthropic/claude-sonnet-4-5 # Claude 4.5 Sonnet\n model: anthropic/claude-opus-4 # Claude 4 Opus\n\n# OpenAI\nagent:\n model: openai/gpt-4o # GPT-4o\n model: openai/gpt-4o-mini # GPT-4o Mini\n model: openai/o1 # O1\n model: openai/o3-mini # O3 Mini\n```\n\n## System Prompt\n\nThe system prompt sets the agent's persona and instructions:\n\n```yaml\nagent:\n system: system # Uses prompts/system.md\n input:\n - COMPANY_NAME\n - PRODUCT_NAME\n - SUPPORT_POLICIES\n```\n\nExample `prompts/system.md`:\n\n```markdown\nYou are a friendly support agent for {{COMPANY_NAME}}.\n\n## Your Role\n\nHelp users with questions about {{PRODUCT_NAME}}.\n\n## Guidelines\n\n- Be helpful and professional\n- If you can't help, offer to escalate\n- Never share internal information\n\n{{#if SUPPORT_POLICIES}}\n## Support Policies\n\n{{SUPPORT_POLICIES}}\n{{/if}}\n```\n\n## Agentic Mode\n\nEnable multi-step tool calling:\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system\n tools: [get-user-account, search-docs, create-ticket]\n agentic: true # LLM can call multiple tools\n maxSteps: 10 # Limit cycles to prevent runaway\n```\n\n**How it works:**\n1. LLM receives user message\n2. LLM decides to call a tool\n3. Tool executes, result returned to LLM\n4. LLM decides if more tools needed\n5. Repeat until LLM responds or maxSteps reached\n\n## Extended Thinking\n\nEnable extended reasoning for complex tasks:\n\n```yaml\nagent:\n model: anthropic/claude-sonnet-4-5\n thinking: medium # low | medium | high\n```\n\n| Level | Token Budget | Use Case |\n|-------|-------------|----------|\n| `low` | ~5,000 | Simple reasoning |\n| `medium` | ~10,000 | Moderate complexity |\n| `high` | ~20,000 | Complex analysis |\n\nThinking content streams to the UI and can be displayed to users.\n\n## Temperature\n\nControl response randomness:\n\n```yaml\nagent:\n model: openai/gpt-4o\n temperature: 0.7 # 0 = deterministic, 2 = creative\n```\n\n**Guidelines:**\n- `0 - 0.3`: Factual, consistent responses\n- `0.4 - 0.7`: Balanced (good default)\n- `0.8 - 1.2`: Creative, varied responses\n- `> 1.2`: Very creative (may be inconsistent)\n\n## Thread-Specific Config\n\nOverride config for named threads:\n\n```yaml\nhandlers:\n request-human:\n Start summary thread:\n type: start-thread\n thread: summary\n model: anthropic/claude-sonnet-4-5 # Different model\n thinking: low # Different thinking\n maxSteps: 1 # Limit tool calls\n system: escalation-summary # Different prompt\n```\n\n## Full Example\n\n```yaml\ninput:\n COMPANY_NAME: { type: string }\n PRODUCT_NAME: { type: string }\n USER_ID: { type: string, optional: true }\n\nresources:\n CONVERSATION_SUMMARY:\n type: string\n default: \"\"\n\ntools:\n get-user-account:\n description: Look up user account\n parameters:\n userId: { type: string }\n \n search-docs:\n description: Search help documentation\n parameters:\n query: { 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\n\nagent:\n model: anthropic/claude-sonnet-4-5\n system: system\n input:\n - COMPANY_NAME\n - PRODUCT_NAME\n tools:\n - get-user-account\n - search-docs\n - create-support-ticket\n agentic: true\n maxSteps: 10\n thinking: medium\n\ntriggers:\n user-message:\n input:\n USER_MESSAGE: { type: string }\n\nhandlers:\n user-message:\n Add message:\n type: add-message\n role: user\n prompt: user-message\n input: [USER_MESSAGE]\n display: hidden\n \n Respond:\n type: next-message\n```\n\n",
349
- excerpt: "Agent Config The section configures the LLM model, system prompt, tools, and behavior. Basic Configuration Configuration Options | Field | Required | Description |...",
350
- order: 6
351
- }
352
- ]
353
- },
354
- {
355
- slug: "api-reference",
356
- title: "API Reference",
357
- description: "REST API reference for the Octavus platform.",
358
- order: 5,
359
- docs: [
360
- {
361
- slug: "api-reference/overview",
362
- section: "api-reference",
363
- title: "Overview",
364
- description: "REST API overview and authentication.",
365
- 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 \u2192 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',
366
- 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...",
367
- order: 1
368
- },
369
- {
370
- slug: "api-reference/sessions",
371
- section: "api-reference",
372
- title: "Sessions",
373
- description: "Session management API endpoints.",
374
- content: '\n# Sessions API\n\nSessions represent conversations with agents. They store conversation history, resources, and variables.\n\n## Create Session\n\nCreate a new agent session.\n\n```\nPOST /api/agent-sessions\n```\n\n### Request Body\n\n```json\n{\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro",\n "USER_ID": "user-123"\n }\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `agentId` | string | Yes | Agent ID (the `id` field, not `slug`) |\n| `input` | object | No | Input variables for the agent |\n\n> To get the agent ID, copy it from the platform URL, use [Get Agent by slug](/docs/api-reference/agents#get-agent) (`GET /api/agents/:slug?by=slug`), or the SDK\'s `agents.getBySlug()` method.\n\n### Response\n\n```json\n{\n "sessionId": "cm5xyz123abc456def"\n}\n```\n\n### Example\n\n```bash\ncurl -X POST https://octavus.ai/api/agent-sessions \\\n -H "Authorization: Bearer YOUR_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro"\n }\n }\'\n```\n\n## Get Session\n\nRetrieve session state including messages and resources.\n\n```\nGET /api/agent-sessions/:sessionId\n```\n\n### Response\n\n```json\n{\n "id": "cm5xyz123abc456def",\n "agentId": "cm5xvz7k80001abcd",\n "input": {\n "COMPANY_NAME": "Acme Corp",\n "PRODUCT_NAME": "Widget Pro"\n },\n "variables": {},\n "resources": {\n "CONVERSATION_SUMMARY": ""\n },\n "messages": [\n {\n "id": "1702345800000-xyz789a",\n "role": "user",\n "parts": [\n { "type": "text", "visible": true, "content": "How do I reset my password?" }\n ],\n "content": "How do I reset my password?",\n "createdAt": "2024-01-15T10:30:00Z"\n },\n {\n "id": "1702345805000-def456b",\n "role": "assistant",\n "parts": [\n { "type": "text", "visible": true, "content": "I can help you reset your password..." }\n ],\n "content": "I can help you reset your password...",\n "createdAt": "2024-01-15T10:30:05Z"\n }\n ],\n "createdAt": "2024-01-15T10:30:00Z",\n "updatedAt": "2024-01-15T10:30:05Z"\n}\n```\n\n### Example\n\n```bash\ncurl https://octavus.ai/api/agent-sessions/:sessionId \\\n -H "Authorization: Bearer YOUR_API_KEY"\n```\n\n## Trigger Session\n\nExecute a trigger on a session. Returns a Server-Sent Events stream.\n\n```\nPOST /api/agent-sessions/:sessionId/trigger\n```\n\n### Request Body\n\n```json\n{\n "triggerName": "user-message",\n "input": {\n "USER_MESSAGE": "How do I reset my password?"\n },\n "toolResults": []\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `triggerName` | string | Yes | Name of the trigger to execute |\n| `input` | object | No | Input variables for the trigger |\n| `toolResults` | array | No | Tool results for continuation (handled by SDK) |\n\n### Response\n\nReturns `text/event-stream` with SSE events:\n\n```\ndata: {"type":"start","messageId":"msg-123"}\n\ndata: {"type":"block-start","blockId":"b1","blockName":"Add user message","blockType":"add-message","display":"hidden"}\n\ndata: {"type":"block-end","blockId":"b1"}\n\ndata: {"type":"block-start","blockId":"b2","blockName":"Respond to user","blockType":"next-message","display":"stream","outputToChat":true}\n\ndata: {"type":"text-start","id":"t1"}\n\ndata: {"type":"text-delta","id":"t1","delta":"I"}\n\ndata: {"type":"text-delta","id":"t1","delta":" can"}\n\ndata: {"type":"text-delta","id":"t1","delta":" help"}\n\ndata: {"type":"text-delta","id":"t1","delta":" you"}\n\ndata: {"type":"text-delta","id":"t1","delta":" reset"}\n\ndata: {"type":"text-delta","id":"t1","delta":" your"}\n\ndata: {"type":"text-delta","id":"t1","delta":" password"}\n\ndata: {"type":"text-delta","id":"t1","delta":"!"}\n\ndata: {"type":"text-end","id":"t1"}\n\ndata: {"type":"block-end","blockId":"b2"}\n\ndata: {"type":"finish","finishReason":"stop"}\n\ndata: [DONE]\n```\n\n### Event Types\n\n| Event | Description |\n|-------|-------------|\n| `start` | Stream started |\n| `finish` | Execution complete |\n| `error` | Error occurred |\n| `block-start` | Execution block started |\n| `block-end` | Execution block completed |\n| `text-start` | Text generation started |\n| `text-delta` | Incremental text content |\n| `text-end` | Text generation ended |\n| `reasoning-start` | Extended reasoning started |\n| `reasoning-delta` | Reasoning content |\n| `reasoning-end` | Extended reasoning ended |\n| `tool-input-start` | Tool call initiated |\n| `tool-input-delta` | Tool arguments streaming |\n| `tool-input-end` | Tool arguments streaming ended |\n| `tool-input-available` | Tool input complete |\n| `tool-output-available` | Tool completed with result |\n| `tool-output-error` | Tool failed |\n| `tool-request` | Platform requesting tool execution |\n| `resource-update` | Resource value changed |\n\n### Example\n\n```bash\ncurl -N -X POST https://octavus.ai/api/agent-sessions/:sessionId/trigger \\\n -H "Authorization: Bearer YOUR_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "triggerName": "user-message",\n "input": { "USER_MESSAGE": "How do I reset my password?" }\n }\'\n```\n\n## Tool Continuation\n\nWhen the agent calls external tools, you\'ll receive a `tool-request` event. Execute the tools and send results back:\n\n```json\n{\n "triggerName": "user-message",\n "input": { "USER_MESSAGE": "..." },\n "toolResults": [\n {\n "toolCallId": "tc_123",\n "toolName": "get-user-account",\n "result": {\n "name": "Demo User",\n "email": "demo@example.com"\n }\n }\n ]\n}\n```\n\nThe Server SDK handles this continuation pattern automatically.\n',
375
- excerpt: "Sessions API Sessions represent conversations with agents. They store conversation history, resources, and variables. Create Session Create a new agent session. Request Body | Field | Type |...",
376
- order: 2
377
- },
378
- {
379
- slug: "api-reference/agents",
380
- section: "api-reference",
381
- title: "Agents",
382
- description: "Agent management API endpoints.",
383
- 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',
384
- 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 ...",
385
- order: 3
386
- }
387
- ]
388
- }
389
- ];
390
-
391
- // src/content.ts
392
- var docs = docs_default;
393
- var sections = sections_default;
394
- function getAllDocs() {
395
- return docs;
396
- }
397
- function getDocSections() {
398
- return sections;
399
- }
400
- function getDocsData() {
401
- return { docs, sections };
402
- }
403
- function getDocBySlug(slug) {
404
- return docs.find((doc) => doc.slug === slug) ?? null;
405
- }
406
- function getDocSlugs() {
407
- return docs.map((doc) => doc.slug);
408
- }
409
- function getSectionBySlug(sectionSlug) {
410
- return sections.find((section) => section.slug === sectionSlug) ?? null;
411
- }
412
-
413
- export {
414
- getAllDocs,
415
- getDocSections,
416
- getDocsData,
417
- getDocBySlug,
418
- getDocSlugs,
419
- getSectionBySlug
420
- };
421
- //# sourceMappingURL=chunk-ZKZVV4OQ.js.map