@octavus/docs 2.10.0 → 2.12.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.
- package/content/02-server-sdk/01-overview.md +16 -0
- package/content/02-server-sdk/05-cli.md +9 -3
- package/content/02-server-sdk/06-workers.md +218 -143
- package/content/03-client-sdk/08-file-uploads.md +57 -3
- package/content/04-protocol/01-overview.md +33 -6
- package/content/04-protocol/05-skills.md +43 -7
- package/content/04-protocol/06-handlers.md +3 -0
- package/content/04-protocol/07-agent-config.md +38 -13
- package/content/04-protocol/09-skills-advanced.md +50 -29
- package/content/04-protocol/11-workers.md +40 -5
- package/content/04-protocol/12-references.md +189 -0
- package/content/05-api-reference/03-agents.md +31 -9
- package/dist/{chunk-HPVIPOLY.js → chunk-PQ5AGOPY.js} +27 -27
- package/dist/chunk-PQ5AGOPY.js.map +1 -0
- package/dist/chunk-RRXIH3DI.js +1507 -0
- package/dist/chunk-RRXIH3DI.js.map +1 -0
- package/dist/{chunk-RZZE5BMI.js → chunk-SAB5XUB6.js} +49 -31
- package/dist/chunk-SAB5XUB6.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +24 -15
- package/dist/index.js +1 -1
- package/dist/search-index.json +1 -1
- package/dist/search.js +1 -1
- package/dist/search.js.map +1 -1
- package/dist/sections.json +24 -15
- package/package.json +1 -1
- package/dist/chunk-HPVIPOLY.js.map +0 -1
- package/dist/chunk-RZZE5BMI.js.map +0 -1
|
@@ -96,6 +96,22 @@ return new Response(toSSEStream(events), {
|
|
|
96
96
|
});
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
### Workers
|
|
100
|
+
|
|
101
|
+
Execute worker agents for task-based processing:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Non-streaming: get the output directly
|
|
105
|
+
const { output } = await client.workers.generate(agentId, {
|
|
106
|
+
TOPIC: 'AI safety',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Streaming: observe events in real-time
|
|
110
|
+
for await (const event of client.workers.execute(agentId, input)) {
|
|
111
|
+
// Handle stream events
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
99
115
|
## API Reference
|
|
100
116
|
|
|
101
117
|
### OctavusClient
|
|
@@ -169,11 +169,17 @@ The CLI expects agent definitions in a specific directory structure:
|
|
|
169
169
|
my-agent/
|
|
170
170
|
├── settings.json # Required: Agent metadata
|
|
171
171
|
├── protocol.yaml # Required: Agent protocol
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
├── prompts/ # Optional: Prompt templates
|
|
173
|
+
│ ├── system.md
|
|
174
|
+
│ └── user-message.md
|
|
175
|
+
└── references/ # Optional: Reference documents
|
|
176
|
+
└── api-guidelines.md
|
|
175
177
|
```
|
|
176
178
|
|
|
179
|
+
### references/
|
|
180
|
+
|
|
181
|
+
Reference files are markdown documents with YAML frontmatter containing a `description`. The agent can fetch these on demand during execution. See [References](/docs/protocol/references) for details.
|
|
182
|
+
|
|
177
183
|
### settings.json
|
|
178
184
|
|
|
179
185
|
```json
|
|
@@ -17,59 +17,56 @@ const client = new OctavusClient({
|
|
|
17
17
|
apiKey: 'your-api-key',
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const events = client.workers.execute(agentId, {
|
|
20
|
+
const { output, sessionId } = await client.workers.generate(agentId, {
|
|
22
21
|
TOPIC: 'AI safety',
|
|
23
22
|
DEPTH: 'detailed',
|
|
24
23
|
});
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
}
|
|
25
|
+
console.log('Result:', output);
|
|
26
|
+
console.log(`Debug: ${client.baseUrl}/sessions/${sessionId}`);
|
|
38
27
|
```
|
|
39
28
|
|
|
40
29
|
## WorkersApi Reference
|
|
41
30
|
|
|
42
|
-
###
|
|
31
|
+
### generate()
|
|
43
32
|
|
|
44
|
-
Execute a worker and
|
|
33
|
+
Execute a worker and return the output directly.
|
|
45
34
|
|
|
46
35
|
```typescript
|
|
47
|
-
async
|
|
36
|
+
async generate(
|
|
48
37
|
agentId: string,
|
|
49
38
|
input: Record<string, unknown>,
|
|
50
39
|
options?: WorkerExecuteOptions
|
|
51
|
-
):
|
|
40
|
+
): Promise<WorkerGenerateResult>
|
|
52
41
|
```
|
|
53
42
|
|
|
54
|
-
|
|
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 |
|
|
43
|
+
Runs the worker to completion and returns the output value. This is the simplest way to execute a worker.
|
|
61
44
|
|
|
62
|
-
**
|
|
45
|
+
**Returns:**
|
|
63
46
|
|
|
64
47
|
```typescript
|
|
65
|
-
interface
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
|
|
48
|
+
interface WorkerGenerateResult {
|
|
49
|
+
/** The worker's output value */
|
|
50
|
+
output: unknown;
|
|
51
|
+
/** Session ID for debugging (usable for session URLs) */
|
|
52
|
+
sessionId: string;
|
|
70
53
|
}
|
|
71
54
|
```
|
|
72
55
|
|
|
56
|
+
**Throws:** `WorkerError` if the worker fails or completes without producing output.
|
|
57
|
+
|
|
58
|
+
### execute()
|
|
59
|
+
|
|
60
|
+
Execute a worker and stream the response. Use this when you need to observe intermediate events like text deltas, tool calls, or progress tracking.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
async *execute(
|
|
64
|
+
agentId: string,
|
|
65
|
+
input: Record<string, unknown>,
|
|
66
|
+
options?: WorkerExecuteOptions
|
|
67
|
+
): AsyncGenerator<StreamEvent>
|
|
68
|
+
```
|
|
69
|
+
|
|
73
70
|
### continue()
|
|
74
71
|
|
|
75
72
|
Continue execution after client-side tool handling.
|
|
@@ -85,19 +82,39 @@ async *continue(
|
|
|
85
82
|
|
|
86
83
|
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
84
|
|
|
85
|
+
### Shared Options
|
|
86
|
+
|
|
87
|
+
All methods accept the same options:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface WorkerExecuteOptions {
|
|
91
|
+
/** Tool handlers for server-side tool execution */
|
|
92
|
+
tools?: ToolHandlers;
|
|
93
|
+
/** Abort signal to cancel the execution */
|
|
94
|
+
signal?: AbortSignal;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
|
|
100
|
+
| Parameter | Type | Description |
|
|
101
|
+
| --------- | ------------------------- | --------------------------- |
|
|
102
|
+
| `agentId` | `string` | The worker agent ID |
|
|
103
|
+
| `input` | `Record<string, unknown>` | Input values for the worker |
|
|
104
|
+
| `options` | `WorkerExecuteOptions` | Optional configuration |
|
|
105
|
+
|
|
88
106
|
## Tool Handlers
|
|
89
107
|
|
|
90
108
|
Provide tool handlers to execute tools server-side:
|
|
91
109
|
|
|
92
110
|
```typescript
|
|
93
|
-
const
|
|
111
|
+
const { output } = await client.workers.generate(
|
|
94
112
|
agentId,
|
|
95
113
|
{ TOPIC: 'AI safety' },
|
|
96
114
|
{
|
|
97
115
|
tools: {
|
|
98
116
|
'web-search': async (args) => {
|
|
99
|
-
|
|
100
|
-
return results;
|
|
117
|
+
return await searchWeb(args.query);
|
|
101
118
|
},
|
|
102
119
|
'get-user-data': async (args) => {
|
|
103
120
|
return await db.users.findById(args.userId);
|
|
@@ -109,85 +126,141 @@ const events = client.workers.execute(
|
|
|
109
126
|
|
|
110
127
|
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
128
|
|
|
112
|
-
##
|
|
129
|
+
## Error Handling
|
|
113
130
|
|
|
114
|
-
|
|
131
|
+
### WorkerError (generate)
|
|
115
132
|
|
|
116
|
-
|
|
133
|
+
`generate()` throws a `WorkerError` on failure. The error includes an optional `sessionId` for constructing debug URLs:
|
|
117
134
|
|
|
118
135
|
```typescript
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
import { OctavusClient, WorkerError } from '@octavus/server-sdk';
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const { output } = await client.workers.generate(agentId, input);
|
|
140
|
+
console.log('Result:', output);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof WorkerError) {
|
|
143
|
+
console.error('Worker failed:', error.message);
|
|
144
|
+
if (error.sessionId) {
|
|
145
|
+
console.error(`Debug: ${client.baseUrl}/sessions/${error.sessionId}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
125
148
|
}
|
|
149
|
+
```
|
|
126
150
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
151
|
+
### Stream Errors (execute)
|
|
152
|
+
|
|
153
|
+
When using `execute()`, errors appear as stream events:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
for await (const event of client.workers.execute(agentId, input)) {
|
|
157
|
+
if (event.type === 'error') {
|
|
158
|
+
console.error(`Error: ${event.message}`);
|
|
159
|
+
console.error(`Type: ${event.errorType}`);
|
|
160
|
+
console.error(`Retryable: ${event.retryable}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (event.type === 'worker-result' && event.error) {
|
|
164
|
+
console.error(`Worker failed: ${event.error}`);
|
|
165
|
+
}
|
|
133
166
|
}
|
|
134
167
|
```
|
|
135
168
|
|
|
136
|
-
###
|
|
169
|
+
### Error Types
|
|
137
170
|
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
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 |
|
|
171
|
+
| Type | Description |
|
|
172
|
+
| ------------------ | --------------------- |
|
|
173
|
+
| `validation_error` | Invalid input |
|
|
174
|
+
| `not_found_error` | Worker not found |
|
|
175
|
+
| `provider_error` | LLM provider error |
|
|
176
|
+
| `tool_error` | Tool execution failed |
|
|
177
|
+
| `execution_error` | Worker step failed |
|
|
151
178
|
|
|
152
|
-
##
|
|
179
|
+
## Cancellation
|
|
153
180
|
|
|
154
|
-
|
|
181
|
+
Use an abort signal to cancel execution:
|
|
155
182
|
|
|
156
183
|
```typescript
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
): Promise<unknown> {
|
|
162
|
-
const events = client.workers.execute(agentId, input);
|
|
184
|
+
const { output } = await client.workers.generate(agentId, input, {
|
|
185
|
+
signal: AbortSignal.timeout(30_000),
|
|
186
|
+
});
|
|
187
|
+
```
|
|
163
188
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
189
|
+
With `execute()` and a manual controller:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const controller = new AbortController();
|
|
193
|
+
setTimeout(() => controller.abort(), 30000);
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
for await (const event of client.workers.execute(agentId, input, {
|
|
197
|
+
signal: controller.signal,
|
|
198
|
+
})) {
|
|
199
|
+
// Process events
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (error.name === 'AbortError') {
|
|
203
|
+
console.log('Worker cancelled');
|
|
171
204
|
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Streaming
|
|
172
209
|
|
|
173
|
-
|
|
210
|
+
When you need real-time visibility into the worker's execution — text generation, tool calls, or progress — use `execute()` instead of `generate()`.
|
|
211
|
+
|
|
212
|
+
### Basic Streaming
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const events = client.workers.execute(agentId, {
|
|
216
|
+
TOPIC: 'AI safety',
|
|
217
|
+
DEPTH: 'detailed',
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
for await (const event of events) {
|
|
221
|
+
if (event.type === 'worker-start') {
|
|
222
|
+
console.log(`Worker ${event.workerSlug} started`);
|
|
223
|
+
}
|
|
224
|
+
if (event.type === 'text-delta') {
|
|
225
|
+
process.stdout.write(event.delta);
|
|
226
|
+
}
|
|
227
|
+
if (event.type === 'worker-result') {
|
|
228
|
+
console.log('Output:', event.output);
|
|
229
|
+
}
|
|
174
230
|
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Streaming to HTTP Response
|
|
234
|
+
|
|
235
|
+
Convert worker events to an SSE stream:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { toSSEStream } from '@octavus/server-sdk';
|
|
239
|
+
|
|
240
|
+
export async function POST(request: Request) {
|
|
241
|
+
const { agentId, input } = await request.json();
|
|
242
|
+
|
|
243
|
+
const events = client.workers.execute(agentId, input, {
|
|
244
|
+
tools: {
|
|
245
|
+
search: async (args) => await search(args.query),
|
|
246
|
+
},
|
|
247
|
+
});
|
|
175
248
|
|
|
176
|
-
|
|
177
|
-
|
|
249
|
+
return new Response(toSSEStream(events), {
|
|
250
|
+
headers: { 'Content-Type': 'text/event-stream' },
|
|
251
|
+
});
|
|
252
|
+
}
|
|
178
253
|
```
|
|
179
254
|
|
|
180
|
-
|
|
255
|
+
### Client Tool Continuation
|
|
181
256
|
|
|
182
257
|
When workers have tools without handlers, execution pauses:
|
|
183
258
|
|
|
184
259
|
```typescript
|
|
185
260
|
for await (const event of client.workers.execute(agentId, input)) {
|
|
186
261
|
if (event.type === 'client-tool-request') {
|
|
187
|
-
// Execute tools client-side
|
|
188
262
|
const results = await executeClientTools(event.toolCalls);
|
|
189
263
|
|
|
190
|
-
// Continue execution
|
|
191
264
|
for await (const ev of client.workers.continue(agentId, event.executionId, results)) {
|
|
192
265
|
// Handle remaining events
|
|
193
266
|
}
|
|
@@ -210,84 +283,87 @@ The `client-tool-request` event includes:
|
|
|
210
283
|
}
|
|
211
284
|
```
|
|
212
285
|
|
|
213
|
-
|
|
286
|
+
### Stream Events
|
|
214
287
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
import { toSSEStream } from '@octavus/server-sdk';
|
|
288
|
+
Workers emit standard stream events plus worker-specific events.
|
|
219
289
|
|
|
220
|
-
|
|
221
|
-
const { agentId, input } = await request.json();
|
|
290
|
+
#### Worker Events
|
|
222
291
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
292
|
+
```typescript
|
|
293
|
+
// Worker started
|
|
294
|
+
{
|
|
295
|
+
type: 'worker-start',
|
|
296
|
+
workerId: string, // Unique ID (also used as session ID for debug)
|
|
297
|
+
workerSlug: string, // The worker's slug
|
|
298
|
+
description?: string, // Display description for UI
|
|
299
|
+
}
|
|
228
300
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
301
|
+
// Worker completed
|
|
302
|
+
{
|
|
303
|
+
type: 'worker-result',
|
|
304
|
+
workerId: string,
|
|
305
|
+
output?: unknown, // The worker's output value
|
|
306
|
+
error?: string, // Error message if worker failed
|
|
232
307
|
}
|
|
233
308
|
```
|
|
234
309
|
|
|
235
|
-
|
|
310
|
+
#### Common Events
|
|
236
311
|
|
|
237
|
-
|
|
312
|
+
| Event | Description |
|
|
313
|
+
| ----------------------- | --------------------------- |
|
|
314
|
+
| `start` | Execution started |
|
|
315
|
+
| `finish` | Execution completed |
|
|
316
|
+
| `text-start` | Text generation started |
|
|
317
|
+
| `text-delta` | Text chunk received |
|
|
318
|
+
| `text-end` | Text generation ended |
|
|
319
|
+
| `block-start` | Step started |
|
|
320
|
+
| `block-end` | Step completed |
|
|
321
|
+
| `tool-input-available` | Tool arguments ready |
|
|
322
|
+
| `tool-output-available` | Tool result ready |
|
|
323
|
+
| `client-tool-request` | Client tools need execution |
|
|
324
|
+
| `error` | Error occurred |
|
|
238
325
|
|
|
239
|
-
|
|
240
|
-
const controller = new AbortController();
|
|
326
|
+
## Full Examples
|
|
241
327
|
|
|
242
|
-
|
|
243
|
-
|
|
328
|
+
### generate()
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { OctavusClient, WorkerError } from '@octavus/server-sdk';
|
|
244
332
|
|
|
245
|
-
const
|
|
246
|
-
|
|
333
|
+
const client = new OctavusClient({
|
|
334
|
+
baseUrl: 'https://octavus.ai',
|
|
335
|
+
apiKey: process.env.OCTAVUS_API_KEY!,
|
|
247
336
|
});
|
|
248
337
|
|
|
249
338
|
try {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
}
|
|
339
|
+
const { output, sessionId } = await client.workers.generate(
|
|
340
|
+
'research-assistant-id',
|
|
341
|
+
{
|
|
342
|
+
TOPIC: 'AI safety best practices',
|
|
343
|
+
DEPTH: 'detailed',
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
tools: {
|
|
347
|
+
'web-search': async ({ query }) => await performWebSearch(query),
|
|
348
|
+
},
|
|
349
|
+
signal: AbortSignal.timeout(120_000),
|
|
350
|
+
},
|
|
351
|
+
);
|
|
272
352
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
353
|
+
console.log('Result:', output);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (error instanceof WorkerError) {
|
|
356
|
+
console.error('Failed:', error.message);
|
|
357
|
+
if (error.sessionId) {
|
|
358
|
+
console.error(`Debug: ${client.baseUrl}/sessions/${error.sessionId}`);
|
|
359
|
+
}
|
|
276
360
|
}
|
|
277
361
|
}
|
|
278
362
|
```
|
|
279
363
|
|
|
280
|
-
|
|
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 |
|
|
364
|
+
### execute()
|
|
289
365
|
|
|
290
|
-
|
|
366
|
+
For full control over streaming events and progress tracking:
|
|
291
367
|
|
|
292
368
|
```typescript
|
|
293
369
|
import { OctavusClient, type StreamEvent } from '@octavus/server-sdk';
|
|
@@ -348,7 +424,6 @@ async function runResearchWorker(topic: string) {
|
|
|
348
424
|
return output;
|
|
349
425
|
}
|
|
350
426
|
|
|
351
|
-
// Run the worker
|
|
352
427
|
const result = await runResearchWorker('AI safety best practices');
|
|
353
428
|
console.log('Result:', result);
|
|
354
429
|
```
|
|
@@ -77,6 +77,12 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
77
77
|
const { messages, status, send, uploadFiles } = useOctavusChat({
|
|
78
78
|
transport,
|
|
79
79
|
requestUploadUrls,
|
|
80
|
+
// Optional: configure upload timeout and retry behavior
|
|
81
|
+
uploadOptions: {
|
|
82
|
+
timeoutMs: 60_000, // Per-file timeout (default: 60s, set to 0 to disable)
|
|
83
|
+
maxRetries: 2, // Retry attempts on transient failures (default: 2)
|
|
84
|
+
retryDelayMs: 1_000, // Delay between retries (default: 1s)
|
|
85
|
+
},
|
|
80
86
|
});
|
|
81
87
|
|
|
82
88
|
// ...
|
|
@@ -176,6 +182,54 @@ async function handleSend(message: string, files?: File[]) {
|
|
|
176
182
|
|
|
177
183
|
The SDK automatically uploads the files before sending. Note: This doesn't provide upload progress.
|
|
178
184
|
|
|
185
|
+
## Upload Reliability
|
|
186
|
+
|
|
187
|
+
Uploads include built-in timeout and retry logic for handling transient failures (network errors, server issues, mobile network switches).
|
|
188
|
+
|
|
189
|
+
**Default behavior:**
|
|
190
|
+
|
|
191
|
+
- **Timeout**: 60 seconds per file — prevents uploads from hanging on stalled connections
|
|
192
|
+
- **Retries**: 2 automatic retries on transient failures (network errors, 5xx, 429)
|
|
193
|
+
- **Retry delay**: 1 second between retries
|
|
194
|
+
- **Non-retryable errors** (4xx like 403, 404) fail immediately without retrying
|
|
195
|
+
|
|
196
|
+
Only the S3 upload is retried — the presigned URL stays valid for 15 minutes. On retry, the progress callback resets to 0%.
|
|
197
|
+
|
|
198
|
+
Configure via `uploadOptions`:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const { send, uploadFiles } = useOctavusChat({
|
|
202
|
+
transport,
|
|
203
|
+
requestUploadUrls,
|
|
204
|
+
uploadOptions: {
|
|
205
|
+
timeoutMs: 120_000, // 2 minutes for large files
|
|
206
|
+
maxRetries: 3,
|
|
207
|
+
retryDelayMs: 2_000,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
To disable timeout or retries:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
uploadOptions: {
|
|
216
|
+
timeoutMs: 0, // No timeout
|
|
217
|
+
maxRetries: 0, // No retries
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Using `OctavusChat` Directly
|
|
222
|
+
|
|
223
|
+
When using the `OctavusChat` class directly (without the React hook), pass `uploadOptions` in the constructor:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const chat = new OctavusChat({
|
|
227
|
+
transport,
|
|
228
|
+
requestUploadUrls,
|
|
229
|
+
uploadOptions: { timeoutMs: 120_000, maxRetries: 3 },
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
179
233
|
## FileReference Type
|
|
180
234
|
|
|
181
235
|
File references contain metadata and URLs:
|
|
@@ -234,15 +288,15 @@ The `file` type is a built-in type representing uploaded files. Use `file[]` for
|
|
|
234
288
|
| Type | Media Types |
|
|
235
289
|
| --------- | -------------------------------------------------------------------- |
|
|
236
290
|
| Images | `image/jpeg`, `image/png`, `image/gif`, `image/webp` |
|
|
291
|
+
| Video | `video/mp4`, `video/webm`, `video/quicktime`, `video/mpeg` |
|
|
237
292
|
| Documents | `application/pdf`, `text/plain`, `text/markdown`, `application/json` |
|
|
238
293
|
|
|
239
294
|
## File Limits
|
|
240
295
|
|
|
241
296
|
| Limit | Value |
|
|
242
297
|
| --------------------- | ---------- |
|
|
243
|
-
| Max file size |
|
|
244
|
-
| Max total per request |
|
|
245
|
-
| Max files per request | 20 |
|
|
298
|
+
| Max file size | 100 MB |
|
|
299
|
+
| Max total per request | 200 MB |
|
|
246
300
|
| Upload URL expiry | 15 minutes |
|
|
247
301
|
| Download URL expiry | 24 hours |
|
|
248
302
|
|
|
@@ -105,12 +105,20 @@ Each agent is a folder with:
|
|
|
105
105
|
my-agent/
|
|
106
106
|
├── protocol.yaml # Main logic (required)
|
|
107
107
|
├── settings.json # Agent metadata (required)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
├── prompts/ # Prompt templates (supports subdirectories)
|
|
109
|
+
│ ├── system.md
|
|
110
|
+
│ ├── user-message.md
|
|
111
|
+
│ └── shared/
|
|
112
|
+
│ ├── company-info.md
|
|
113
|
+
│ └── formatting-rules.md
|
|
114
|
+
└── references/ # On-demand context documents (optional)
|
|
115
|
+
└── api-guidelines.md
|
|
112
116
|
```
|
|
113
117
|
|
|
118
|
+
Prompts can be organized in subdirectories. In the protocol, reference nested prompts by their path relative to `prompts/` (without `.md`): `shared/company-info`.
|
|
119
|
+
|
|
120
|
+
References are markdown files with YAML frontmatter that the agent can fetch on demand during execution. See [References](/docs/protocol/references).
|
|
121
|
+
|
|
114
122
|
### settings.json
|
|
115
123
|
|
|
116
124
|
```json
|
|
@@ -133,7 +141,7 @@ my-agent/
|
|
|
133
141
|
|
|
134
142
|
- **Slugs**: `lowercase-with-dashes`
|
|
135
143
|
- **Variables**: `UPPERCASE_SNAKE_CASE`
|
|
136
|
-
- **Prompts**: `lowercase-with-dashes.md`
|
|
144
|
+
- **Prompts**: `lowercase-with-dashes.md` (paths use `/` for subdirectories)
|
|
137
145
|
- **Tools**: `lowercase-with-dashes`
|
|
138
146
|
- **Triggers**: `lowercase-with-dashes`
|
|
139
147
|
|
|
@@ -153,7 +161,25 @@ Help users with their {{PRODUCT_NAME}} questions.
|
|
|
153
161
|
{{SUPPORT_POLICIES}}
|
|
154
162
|
```
|
|
155
163
|
|
|
156
|
-
Variables are replaced with their values at runtime. If a variable is not provided,
|
|
164
|
+
Variables are replaced with their values at runtime. If a variable is not provided, the placeholder is kept as-is.
|
|
165
|
+
|
|
166
|
+
## Prompt Interpolation
|
|
167
|
+
|
|
168
|
+
Include other prompts inside a prompt with `{{@path.md}}`:
|
|
169
|
+
|
|
170
|
+
```markdown
|
|
171
|
+
<!-- prompts/system.md -->
|
|
172
|
+
|
|
173
|
+
You are a customer support agent.
|
|
174
|
+
|
|
175
|
+
{{@shared/company-info.md}}
|
|
176
|
+
|
|
177
|
+
{{@shared/formatting-rules.md}}
|
|
178
|
+
|
|
179
|
+
Help users with their questions.
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The referenced prompt content is inserted before variable interpolation, so variables in included prompts work the same way. Circular references are not allowed and will be caught during validation.
|
|
157
183
|
|
|
158
184
|
## Next Steps
|
|
159
185
|
|
|
@@ -161,6 +187,7 @@ Variables are replaced with their values at runtime. If a variable is not provid
|
|
|
161
187
|
- [Triggers](/docs/protocol/triggers) — How agents are invoked
|
|
162
188
|
- [Tools](/docs/protocol/tools) — External capabilities
|
|
163
189
|
- [Skills](/docs/protocol/skills) — Code execution and knowledge packages
|
|
190
|
+
- [References](/docs/protocol/references) — On-demand context documents
|
|
164
191
|
- [Handlers](/docs/protocol/handlers) — Execution blocks
|
|
165
192
|
- [Agent Config](/docs/protocol/agent-config) — Model and settings
|
|
166
193
|
- [Workers](/docs/protocol/workers) — Worker agent format
|