@octavus/docs 2.1.0 → 2.3.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.
@@ -111,6 +111,7 @@ interface OctavusClientConfig {
111
111
  class OctavusClient {
112
112
  readonly agents: AgentsApi;
113
113
  readonly agentSessions: AgentSessionsApi;
114
+ readonly workers: WorkersApi;
114
115
  readonly files: FilesApi;
115
116
 
116
117
  constructor(config: OctavusClientConfig);
@@ -219,3 +220,4 @@ The client uploads files directly to S3 using the presigned upload URL. See [Fil
219
220
  - [Sessions](/docs/server-sdk/sessions) — Deep dive into session management
220
221
  - [Tools](/docs/server-sdk/tools) — Implementing tool handlers
221
222
  - [Streaming](/docs/server-sdk/streaming) — Understanding stream events
223
+ - [Workers](/docs/server-sdk/workers) — Executing worker agents
@@ -0,0 +1,360 @@
1
+ ---
2
+ title: Workers
3
+ description: Executing worker agents with the Server SDK.
4
+ ---
5
+
6
+ # Workers API
7
+
8
+ The `WorkersApi` enables executing worker agents from your server. Workers are task-based agents that run steps sequentially and return an output value.
9
+
10
+ ## Basic Usage
11
+
12
+ ```typescript
13
+ import { OctavusClient } from '@octavus/server-sdk';
14
+
15
+ const client = new OctavusClient({
16
+ baseUrl: 'https://octavus.ai',
17
+ apiKey: 'your-api-key',
18
+ });
19
+
20
+ // Execute a worker
21
+ const events = client.workers.execute(agentId, {
22
+ TOPIC: 'AI safety',
23
+ DEPTH: 'detailed',
24
+ });
25
+
26
+ // Process events
27
+ for await (const event of events) {
28
+ if (event.type === 'worker-start') {
29
+ console.log(`Worker ${event.workerSlug} started`);
30
+ }
31
+ if (event.type === 'text-delta') {
32
+ process.stdout.write(event.delta);
33
+ }
34
+ if (event.type === 'worker-result') {
35
+ console.log('Output:', event.output);
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## WorkersApi Reference
41
+
42
+ ### execute()
43
+
44
+ Execute a worker and stream the response.
45
+
46
+ ```typescript
47
+ async *execute(
48
+ agentId: string,
49
+ input: Record<string, unknown>,
50
+ options?: WorkerExecuteOptions
51
+ ): AsyncGenerator<StreamEvent>
52
+ ```
53
+
54
+ **Parameters:**
55
+
56
+ | Parameter | Type | Description |
57
+ | --------- | ------------------------- | --------------------------- |
58
+ | `agentId` | `string` | The worker agent ID |
59
+ | `input` | `Record<string, unknown>` | Input values for the worker |
60
+ | `options` | `WorkerExecuteOptions` | Optional configuration |
61
+
62
+ **Options:**
63
+
64
+ ```typescript
65
+ interface WorkerExecuteOptions {
66
+ /** Tool handlers for server-side tool execution */
67
+ tools?: ToolHandlers;
68
+ /** Abort signal to cancel the execution */
69
+ signal?: AbortSignal;
70
+ }
71
+ ```
72
+
73
+ ### continue()
74
+
75
+ Continue execution after client-side tool handling.
76
+
77
+ ```typescript
78
+ async *continue(
79
+ agentId: string,
80
+ executionId: string,
81
+ toolResults: ToolResult[],
82
+ options?: WorkerExecuteOptions
83
+ ): AsyncGenerator<StreamEvent>
84
+ ```
85
+
86
+ Use this when the worker has tools without server-side handlers. The execution pauses with a `client-tool-request` event, you execute the tools, then call `continue()` to resume.
87
+
88
+ ## Tool Handlers
89
+
90
+ Provide tool handlers to execute tools server-side:
91
+
92
+ ```typescript
93
+ const events = client.workers.execute(
94
+ agentId,
95
+ { TOPIC: 'AI safety' },
96
+ {
97
+ tools: {
98
+ 'web-search': async (args) => {
99
+ const results = await searchWeb(args.query);
100
+ return results;
101
+ },
102
+ 'get-user-data': async (args) => {
103
+ return await db.users.findById(args.userId);
104
+ },
105
+ },
106
+ },
107
+ );
108
+ ```
109
+
110
+ Tools defined in the worker protocol but not provided as handlers become client tools — the execution pauses and emits a `client-tool-request` event.
111
+
112
+ ## Stream Events
113
+
114
+ Workers emit standard stream events plus worker-specific events.
115
+
116
+ ### Worker Events
117
+
118
+ ```typescript
119
+ // Worker started
120
+ {
121
+ type: 'worker-start',
122
+ workerId: string, // Unique ID (also used as session ID for debug)
123
+ workerSlug: string, // The worker's slug
124
+ description?: string, // Display description for UI
125
+ }
126
+
127
+ // Worker completed
128
+ {
129
+ type: 'worker-result',
130
+ workerId: string,
131
+ output?: unknown, // The worker's output value
132
+ error?: string, // Error message if worker failed
133
+ }
134
+ ```
135
+
136
+ ### Common Events
137
+
138
+ | Event | Description |
139
+ | ----------------------- | --------------------------- |
140
+ | `start` | Execution started |
141
+ | `finish` | Execution completed |
142
+ | `text-start` | Text generation started |
143
+ | `text-delta` | Text chunk received |
144
+ | `text-end` | Text generation ended |
145
+ | `block-start` | Step started |
146
+ | `block-end` | Step completed |
147
+ | `tool-input-available` | Tool arguments ready |
148
+ | `tool-output-available` | Tool result ready |
149
+ | `client-tool-request` | Client tools need execution |
150
+ | `error` | Error occurred |
151
+
152
+ ## Extracting Output
153
+
154
+ To get just the worker's output value:
155
+
156
+ ```typescript
157
+ async function executeWorker(
158
+ client: OctavusClient,
159
+ agentId: string,
160
+ input: Record<string, unknown>,
161
+ ): Promise<unknown> {
162
+ const events = client.workers.execute(agentId, input);
163
+
164
+ for await (const event of events) {
165
+ if (event.type === 'worker-result') {
166
+ if (event.error) {
167
+ throw new Error(event.error);
168
+ }
169
+ return event.output;
170
+ }
171
+ }
172
+
173
+ return undefined;
174
+ }
175
+
176
+ // Usage
177
+ const analysis = await executeWorker(client, agentId, { TOPIC: 'AI' });
178
+ ```
179
+
180
+ ## Client Tool Continuation
181
+
182
+ When workers have tools without handlers, execution pauses:
183
+
184
+ ```typescript
185
+ for await (const event of client.workers.execute(agentId, input)) {
186
+ if (event.type === 'client-tool-request') {
187
+ // Execute tools client-side
188
+ const results = await executeClientTools(event.toolCalls);
189
+
190
+ // Continue execution
191
+ for await (const ev of client.workers.continue(agentId, event.executionId, results)) {
192
+ // Handle remaining events
193
+ }
194
+ break;
195
+ }
196
+ }
197
+ ```
198
+
199
+ The `client-tool-request` event includes:
200
+
201
+ ```typescript
202
+ {
203
+ type: 'client-tool-request',
204
+ executionId: string, // Pass to continue()
205
+ toolCalls: [{
206
+ toolCallId: string,
207
+ toolName: string,
208
+ args: Record<string, unknown>,
209
+ }],
210
+ }
211
+ ```
212
+
213
+ ## Streaming to HTTP Response
214
+
215
+ Convert worker events to an SSE stream:
216
+
217
+ ```typescript
218
+ import { toSSEStream } from '@octavus/server-sdk';
219
+
220
+ export async function POST(request: Request) {
221
+ const { agentId, input } = await request.json();
222
+
223
+ const events = client.workers.execute(agentId, input, {
224
+ tools: {
225
+ search: async (args) => await search(args.query),
226
+ },
227
+ });
228
+
229
+ return new Response(toSSEStream(events), {
230
+ headers: { 'Content-Type': 'text/event-stream' },
231
+ });
232
+ }
233
+ ```
234
+
235
+ ## Cancellation
236
+
237
+ Use an abort signal to cancel execution:
238
+
239
+ ```typescript
240
+ const controller = new AbortController();
241
+
242
+ // Cancel after 30 seconds
243
+ setTimeout(() => controller.abort(), 30000);
244
+
245
+ const events = client.workers.execute(agentId, input, {
246
+ signal: controller.signal,
247
+ });
248
+
249
+ try {
250
+ for await (const event of events) {
251
+ // Process events
252
+ }
253
+ } catch (error) {
254
+ if (error.name === 'AbortError') {
255
+ console.log('Worker cancelled');
256
+ }
257
+ }
258
+ ```
259
+
260
+ ## Error Handling
261
+
262
+ Errors can occur at different levels:
263
+
264
+ ```typescript
265
+ for await (const event of client.workers.execute(agentId, input)) {
266
+ // Stream-level error event
267
+ if (event.type === 'error') {
268
+ console.error(`Error: ${event.message}`);
269
+ console.error(`Type: ${event.errorType}`);
270
+ console.error(`Retryable: ${event.retryable}`);
271
+ }
272
+
273
+ // Worker-level error in result
274
+ if (event.type === 'worker-result' && event.error) {
275
+ console.error(`Worker failed: ${event.error}`);
276
+ }
277
+ }
278
+ ```
279
+
280
+ Error types include:
281
+
282
+ | Type | Description |
283
+ | ------------------ | --------------------- |
284
+ | `validation_error` | Invalid input |
285
+ | `not_found_error` | Worker not found |
286
+ | `provider_error` | LLM provider error |
287
+ | `tool_error` | Tool execution failed |
288
+ | `execution_error` | Worker step failed |
289
+
290
+ ## Full Example
291
+
292
+ ```typescript
293
+ import { OctavusClient, type StreamEvent } from '@octavus/server-sdk';
294
+
295
+ const client = new OctavusClient({
296
+ baseUrl: 'https://octavus.ai',
297
+ apiKey: process.env.OCTAVUS_API_KEY!,
298
+ });
299
+
300
+ async function runResearchWorker(topic: string) {
301
+ console.log(`Researching: ${topic}\n`);
302
+
303
+ const events = client.workers.execute(
304
+ 'research-assistant-id',
305
+ {
306
+ TOPIC: topic,
307
+ DEPTH: 'detailed',
308
+ },
309
+ {
310
+ tools: {
311
+ 'web-search': async ({ query }) => {
312
+ console.log(`Searching: ${query}`);
313
+ return await performWebSearch(query);
314
+ },
315
+ },
316
+ },
317
+ );
318
+
319
+ let output: unknown;
320
+
321
+ for await (const event of events) {
322
+ switch (event.type) {
323
+ case 'worker-start':
324
+ console.log(`Started: ${event.workerSlug}`);
325
+ break;
326
+
327
+ case 'block-start':
328
+ console.log(`Step: ${event.blockName}`);
329
+ break;
330
+
331
+ case 'text-delta':
332
+ process.stdout.write(event.delta);
333
+ break;
334
+
335
+ case 'worker-result':
336
+ if (event.error) {
337
+ throw new Error(event.error);
338
+ }
339
+ output = event.output;
340
+ break;
341
+
342
+ case 'error':
343
+ throw new Error(event.message);
344
+ }
345
+ }
346
+
347
+ console.log('\n\nResearch complete!');
348
+ return output;
349
+ }
350
+
351
+ // Run the worker
352
+ const result = await runResearchWorker('AI safety best practices');
353
+ console.log('Result:', result);
354
+ ```
355
+
356
+ ## Next Steps
357
+
358
+ - [Workers Protocol](/docs/protocol/workers) — Worker protocol reference
359
+ - [Streaming](/docs/server-sdk/streaming) — Understanding stream events
360
+ - [Tools](/docs/server-sdk/tools) — Tool handler patterns
@@ -17,7 +17,22 @@ Protocols provide:
17
17
  - **Validation** — Catch errors before runtime
18
18
  - **Visualization** — Debug execution flows
19
19
 
20
- ## Protocol Structure
20
+ ## Agent Formats
21
+
22
+ Octavus supports two agent formats:
23
+
24
+ | Format | Use Case | Structure |
25
+ | ------------- | ------------------------------ | --------------------------------- |
26
+ | `interactive` | Chat and multi-turn dialogue | `triggers` + `handlers` + `agent` |
27
+ | `worker` | Background tasks and pipelines | `steps` + `output` |
28
+
29
+ **Interactive agents** handle conversations — they respond to triggers (like user messages) and maintain session state across interactions.
30
+
31
+ **Worker agents** execute tasks — they run steps sequentially and return an output value. Workers can be called independently or composed into interactive agents.
32
+
33
+ See [Workers](/docs/protocol/workers) for the worker protocol reference.
34
+
35
+ ## Interactive Protocol Structure
21
36
 
22
37
  ```yaml
23
38
  # Agent inputs (provided when creating a session)
@@ -148,5 +163,6 @@ Variables are replaced with their values at runtime. If a variable is not provid
148
163
  - [Skills](/docs/protocol/skills) — Code execution and knowledge packages
149
164
  - [Handlers](/docs/protocol/handlers) — Execution blocks
150
165
  - [Agent Config](/docs/protocol/agent-config) — Model and settings
166
+ - [Workers](/docs/protocol/workers) — Worker agent format
151
167
  - [Provider Options](/docs/protocol/provider-options) — Provider-specific features
152
168
  - [Types](/docs/protocol/types) — Custom type definitions
@@ -288,6 +288,19 @@ agent:
288
288
  skills: [custom-analysis]
289
289
  ```
290
290
 
291
+ ## Sandbox Timeout
292
+
293
+ The default sandbox timeout is 5 minutes. For long-running operations, you can configure a custom timeout using `sandboxTimeout` in the agent config:
294
+
295
+ ```yaml
296
+ agent:
297
+ model: anthropic/claude-sonnet-4-5
298
+ skills: [data-analysis]
299
+ sandboxTimeout: 1800000 # 30 minutes (in milliseconds)
300
+ ```
301
+
302
+ `sandboxTimeout` Maximum: 1 hour (3,600,000 ms)
303
+
291
304
  ## Security
292
305
 
293
306
  Skills run in isolated sandbox environments:
@@ -295,7 +308,7 @@ Skills run in isolated sandbox environments:
295
308
  - **No network access** (unless explicitly configured)
296
309
  - **No persistent storage** (sandbox destroyed after execution)
297
310
  - **File output only** via `/output/` directory
298
- - **Time limits** enforced (5-minute default timeout)
311
+ - **Time limits** enforced (5-minute default, configurable via `sandboxTimeout`)
299
312
 
300
313
  ## Next Steps
301
314
 
@@ -220,11 +220,22 @@ This means:
220
220
 
221
221
  ### Timeout Limits
222
222
 
223
- Sandboxes have a 5-minute default timeout:
223
+ Sandboxes have a 5-minute default timeout, which can be configured via `sandboxTimeout`:
224
224
 
225
- - **Short operations**: QR codes, simple calculations
226
- - **Medium operations**: Data analysis, report generation
227
- - **Long operations**: May need to split into multiple steps
225
+ ```yaml
226
+ agent:
227
+ model: anthropic/claude-sonnet-4-5
228
+ skills: [data-analysis]
229
+ sandboxTimeout: 1800000 # 30 minutes for long-running analysis
230
+ ```
231
+
232
+ `sandboxTimeout` Maximum: 1 hour (3,600,000 ms)
233
+
234
+ **Timeout guidelines:**
235
+
236
+ - **Short operations** (default 5 min): QR codes, simple calculations
237
+ - **Medium operations** (10-30 min): Data analysis, report generation
238
+ - **Long operations** (30+ min): Complex processing, large dataset analysis
228
239
 
229
240
  ### Sandbox Lifecycle
230
241
 
@@ -339,7 +350,7 @@ The LLM sees these errors and can retry or explain to users.
339
350
  - **No network access** (unless explicitly configured)
340
351
  - **No persistent storage** (sandbox destroyed after execution)
341
352
  - **File output only** via `/output/` directory
342
- - **Time limits** enforced (5-minute default)
353
+ - **Time limits** enforced (5-minute default, configurable via `sandboxTimeout`)
343
354
 
344
355
  ### Input Validation
345
356