@octavus/docs 1.0.0 → 2.1.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/01-getting-started/02-quickstart.md +8 -5
- package/content/02-server-sdk/01-overview.md +22 -6
- package/content/02-server-sdk/02-sessions.md +80 -10
- package/content/02-server-sdk/03-tools.md +39 -14
- package/content/02-server-sdk/04-streaming.md +55 -7
- package/content/02-server-sdk/05-cli.md +9 -9
- package/content/03-client-sdk/01-overview.md +22 -9
- package/content/03-client-sdk/02-messages.md +6 -4
- package/content/03-client-sdk/03-streaming.md +7 -3
- package/content/03-client-sdk/05-socket-transport.md +40 -44
- package/content/03-client-sdk/06-http-transport.md +81 -17
- package/content/03-client-sdk/07-structured-output.md +3 -2
- package/content/03-client-sdk/08-file-uploads.md +6 -4
- package/content/03-client-sdk/10-client-tools.md +557 -0
- package/content/04-protocol/02-input-resources.md +12 -0
- package/content/04-protocol/03-triggers.md +8 -5
- package/content/04-protocol/06-handlers.md +10 -0
- package/content/04-protocol/07-agent-config.md +34 -1
- package/content/05-api-reference/01-overview.md +18 -0
- package/content/05-api-reference/02-sessions.md +2 -0
- package/content/05-api-reference/03-agents.md +12 -0
- package/content/06-examples/02-nextjs-chat.md +12 -7
- package/content/06-examples/03-socket-chat.md +34 -40
- package/content/07-migration/01-v1-to-v2.md +366 -0
- package/content/07-migration/_meta.md +4 -0
- package/dist/chunk-3ER2T7S7.js +663 -0
- package/dist/chunk-3ER2T7S7.js.map +1 -0
- package/dist/chunk-GI574O6S.js +1435 -0
- package/dist/chunk-GI574O6S.js.map +1 -0
- package/dist/{chunk-WJ2W3DUC.js → chunk-HFF2TVGV.js} +13 -13
- package/dist/chunk-HFF2TVGV.js.map +1 -0
- package/dist/chunk-KUB6BGPR.js +1435 -0
- package/dist/chunk-KUB6BGPR.js.map +1 -0
- package/dist/chunk-S5JUVAKE.js +1409 -0
- package/dist/chunk-S5JUVAKE.js.map +1 -0
- package/dist/chunk-TMJG4CJH.js +1409 -0
- package/dist/chunk-TMJG4CJH.js.map +1 -0
- package/dist/chunk-WKCT4ABS.js +1435 -0
- package/dist/chunk-WKCT4ABS.js.map +1 -0
- package/dist/chunk-YJPO6KOJ.js +1435 -0
- package/dist/chunk-YJPO6KOJ.js.map +1 -0
- package/dist/chunk-ZSCRYD5P.js +1409 -0
- package/dist/chunk-ZSCRYD5P.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +44 -26
- 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 +52 -26
- package/package.json +1 -1
- package/dist/chunk-WJ2W3DUC.js.map +0 -1
|
@@ -131,7 +131,7 @@ The server creates a session on first trigger message:
|
|
|
131
131
|
|
|
132
132
|
```typescript
|
|
133
133
|
import sockjs from 'sockjs';
|
|
134
|
-
import { OctavusClient, type AgentSession } from '@octavus/server-sdk';
|
|
134
|
+
import { OctavusClient, type AgentSession, type SocketMessage } from '@octavus/server-sdk';
|
|
135
135
|
|
|
136
136
|
const client = new OctavusClient({
|
|
137
137
|
baseUrl: process.env.OCTAVUS_API_URL!,
|
|
@@ -141,7 +141,8 @@ const client = new OctavusClient({
|
|
|
141
141
|
function createSocketHandler() {
|
|
142
142
|
return (conn: sockjs.Connection) => {
|
|
143
143
|
let session: AgentSession | null = null;
|
|
144
|
-
|
|
144
|
+
|
|
145
|
+
const send = (data: unknown) => conn.write(JSON.stringify(data));
|
|
145
146
|
|
|
146
147
|
conn.on('data', (rawData: string) => {
|
|
147
148
|
void handleMessage(rawData);
|
|
@@ -150,43 +151,30 @@ function createSocketHandler() {
|
|
|
150
151
|
async function handleMessage(rawData: string) {
|
|
151
152
|
const msg = JSON.parse(rawData);
|
|
152
153
|
|
|
153
|
-
if (msg.type === 'stop') {
|
|
154
|
-
abortController?.abort();
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (msg.type === 'trigger') {
|
|
154
|
+
if (msg.type === 'trigger' || msg.type === 'continue' || msg.type === 'stop') {
|
|
159
155
|
// Create session lazily on first trigger
|
|
160
|
-
if (!session) {
|
|
156
|
+
if (!session && msg.type === 'trigger') {
|
|
161
157
|
const sessionId = await client.agentSessions.create('your-agent-id', {
|
|
162
|
-
// Initial input variables
|
|
163
158
|
COMPANY_NAME: 'Acme Corp',
|
|
164
159
|
});
|
|
165
160
|
session = client.agentSessions.attach(sessionId, {
|
|
166
161
|
tools: {
|
|
167
|
-
//
|
|
162
|
+
// Server-side tool handlers only
|
|
163
|
+
// Tools without handlers are forwarded to the client
|
|
168
164
|
},
|
|
169
165
|
});
|
|
170
166
|
}
|
|
171
167
|
|
|
172
|
-
|
|
168
|
+
if (!session) return;
|
|
173
169
|
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
// handleSocketMessage manages abort controller internally
|
|
171
|
+
await session.handleSocketMessage(msg as SocketMessage, {
|
|
172
|
+
onEvent: send,
|
|
177
173
|
});
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
for await (const event of events) {
|
|
181
|
-
conn.write(JSON.stringify(event));
|
|
182
|
-
}
|
|
183
|
-
} catch {
|
|
184
|
-
// Handle errors
|
|
185
|
-
}
|
|
186
174
|
}
|
|
187
175
|
}
|
|
188
176
|
|
|
189
|
-
conn.on('close', () =>
|
|
177
|
+
conn.on('close', () => {});
|
|
190
178
|
};
|
|
191
179
|
}
|
|
192
180
|
|
|
@@ -241,9 +229,12 @@ When `sessionId` changes, the hook automatically reinitializes with the new tran
|
|
|
241
229
|
When using client-provided sessionId, the server must handle an `init` message:
|
|
242
230
|
|
|
243
231
|
```typescript
|
|
232
|
+
import type { SocketMessage } from '@octavus/server-sdk';
|
|
233
|
+
|
|
244
234
|
sockServer.on('connection', (conn) => {
|
|
245
235
|
let session: AgentSession | null = null;
|
|
246
|
-
|
|
236
|
+
|
|
237
|
+
const send = (data: unknown) => conn.write(JSON.stringify(data));
|
|
247
238
|
|
|
248
239
|
conn.on('data', (rawData: string) => {
|
|
249
240
|
void handleMessage(rawData);
|
|
@@ -256,33 +247,29 @@ sockServer.on('connection', (conn) => {
|
|
|
256
247
|
if (msg.type === 'init') {
|
|
257
248
|
session = client.agentSessions.attach(msg.sessionId, {
|
|
258
249
|
tools: {
|
|
259
|
-
|
|
250
|
+
// Server-side tool handlers
|
|
260
251
|
},
|
|
261
252
|
});
|
|
262
253
|
return;
|
|
263
254
|
}
|
|
264
255
|
|
|
265
|
-
if (msg.type === 'stop') {
|
|
266
|
-
abortController?.abort();
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
256
|
// All other messages require initialized session
|
|
271
257
|
if (!session) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}),
|
|
280
|
-
);
|
|
258
|
+
send({
|
|
259
|
+
type: 'error',
|
|
260
|
+
errorType: 'validation_error',
|
|
261
|
+
message: 'Session not initialized. Send init message first.',
|
|
262
|
+
source: 'platform',
|
|
263
|
+
retryable: false,
|
|
264
|
+
});
|
|
281
265
|
return;
|
|
282
266
|
}
|
|
283
267
|
|
|
284
|
-
|
|
285
|
-
|
|
268
|
+
// handleSocketMessage handles trigger, continue, and stop
|
|
269
|
+
if (msg.type === 'trigger' || msg.type === 'continue' || msg.type === 'stop') {
|
|
270
|
+
await session.handleSocketMessage(msg as SocketMessage, {
|
|
271
|
+
onEvent: send,
|
|
272
|
+
});
|
|
286
273
|
}
|
|
287
274
|
}
|
|
288
275
|
});
|
|
@@ -505,9 +492,12 @@ const SockJS: typeof import('sockjs-client') = require('sockjs-client');
|
|
|
505
492
|
// Initialize session (only for client-provided sessionId pattern)
|
|
506
493
|
{ type: 'init', sessionId: string }
|
|
507
494
|
|
|
508
|
-
// Trigger an action
|
|
495
|
+
// Trigger an action (start a new conversation turn)
|
|
509
496
|
{ type: 'trigger', triggerName: string, input?: Record<string, unknown> }
|
|
510
497
|
|
|
498
|
+
// Continue execution (after client-side tool handling)
|
|
499
|
+
{ type: 'continue', executionId: string, toolResults: ToolResult[] }
|
|
500
|
+
|
|
511
501
|
// Stop current stream
|
|
512
502
|
{ type: 'stop' }
|
|
513
503
|
```
|
|
@@ -518,13 +508,19 @@ The server sends Octavus `StreamEvent` objects as JSON. See [Streaming Events](/
|
|
|
518
508
|
|
|
519
509
|
```typescript
|
|
520
510
|
// Examples
|
|
521
|
-
{ type: 'start', messageId: '...' }
|
|
511
|
+
{ type: 'start', messageId: '...', executionId: '...' }
|
|
522
512
|
{ type: 'text-delta', id: '...', delta: 'Hello' }
|
|
523
513
|
{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user' }
|
|
524
514
|
{ type: 'finish', finishReason: 'stop' }
|
|
525
515
|
{ type: 'error', errorType: 'internal_error', message: 'Something went wrong', source: 'platform', retryable: false }
|
|
516
|
+
|
|
517
|
+
// Client tool request (tools without server handlers)
|
|
518
|
+
{ type: 'client-tool-request', executionId: '...', toolCalls: [...], serverToolResults: [...] }
|
|
519
|
+
{ type: 'finish', finishReason: 'client-tool-calls', executionId: '...' }
|
|
526
520
|
```
|
|
527
521
|
|
|
522
|
+
When a `client-tool-request` event is received, the client handles the tools and sends a `continue` message to resume.
|
|
523
|
+
|
|
528
524
|
## Full Example
|
|
529
525
|
|
|
530
526
|
For a complete walkthrough of building a chat interface with SockJS, see the [Socket Chat Example](/docs/examples/socket-chat).
|
|
@@ -28,11 +28,11 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
28
28
|
const transport = useMemo(
|
|
29
29
|
() =>
|
|
30
30
|
createHttpTransport({
|
|
31
|
-
|
|
31
|
+
request: (payload, options) =>
|
|
32
32
|
fetch('/api/trigger', {
|
|
33
33
|
method: 'POST',
|
|
34
34
|
headers: { 'Content-Type': 'application/json' },
|
|
35
|
-
body: JSON.stringify({ sessionId,
|
|
35
|
+
body: JSON.stringify({ sessionId, ...payload }),
|
|
36
36
|
signal: options?.signal,
|
|
37
37
|
}),
|
|
38
38
|
}),
|
|
@@ -61,7 +61,8 @@ const client = new OctavusClient({
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
export async function POST(request: Request) {
|
|
64
|
-
const
|
|
64
|
+
const body = await request.json();
|
|
65
|
+
const { sessionId, ...payload } = body;
|
|
65
66
|
|
|
66
67
|
const session = client.agentSessions.attach(sessionId, {
|
|
67
68
|
tools: {
|
|
@@ -71,8 +72,8 @@ export async function POST(request: Request) {
|
|
|
71
72
|
},
|
|
72
73
|
});
|
|
73
74
|
|
|
74
|
-
//
|
|
75
|
-
const events = session.
|
|
75
|
+
// execute() handles both triggers and client tool continuations
|
|
76
|
+
const events = session.execute(payload, { signal: request.signal });
|
|
76
77
|
|
|
77
78
|
return new Response(toSSEStream(events), {
|
|
78
79
|
headers: {
|
|
@@ -197,7 +198,7 @@ return (
|
|
|
197
198
|
);
|
|
198
199
|
```
|
|
199
200
|
|
|
200
|
-
> **Important**: For stop to work end-to-end, pass the `options.signal` to your `fetch()` call and forward `request.signal` to `session.
|
|
201
|
+
> **Important**: For stop to work end-to-end, pass the `options.signal` to your `fetch()` call and forward `request.signal` to `session.execute()` on the server.
|
|
201
202
|
|
|
202
203
|
## Express Server
|
|
203
204
|
|
|
@@ -208,21 +209,25 @@ import express from 'express';
|
|
|
208
209
|
import { OctavusClient, toSSEStream } from '@octavus/server-sdk';
|
|
209
210
|
|
|
210
211
|
const app = express();
|
|
212
|
+
app.use(express.json());
|
|
213
|
+
|
|
211
214
|
const client = new OctavusClient({
|
|
212
215
|
baseUrl: process.env.OCTAVUS_API_URL!,
|
|
213
216
|
apiKey: process.env.OCTAVUS_API_KEY!,
|
|
214
217
|
});
|
|
215
218
|
|
|
216
219
|
app.post('/api/trigger', async (req, res) => {
|
|
217
|
-
const { sessionId,
|
|
220
|
+
const { sessionId, ...payload } = req.body;
|
|
218
221
|
|
|
219
222
|
const session = client.agentSessions.attach(sessionId, {
|
|
220
223
|
tools: {
|
|
221
|
-
//
|
|
224
|
+
// Server-side tool handlers only
|
|
225
|
+
// Tools without handlers are forwarded to the client
|
|
222
226
|
},
|
|
223
227
|
});
|
|
224
228
|
|
|
225
|
-
|
|
229
|
+
// execute() handles both triggers and continuations
|
|
230
|
+
const events = session.execute(payload);
|
|
226
231
|
const stream = toSSEStream(events);
|
|
227
232
|
|
|
228
233
|
// Set SSE headers
|
|
@@ -250,27 +255,56 @@ app.post('/api/trigger', async (req, res) => {
|
|
|
250
255
|
|
|
251
256
|
```typescript
|
|
252
257
|
interface HttpTransportOptions {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
input?: Record<string, unknown>,
|
|
256
|
-
options?: TriggerRequestOptions,
|
|
257
|
-
) => Promise<Response>;
|
|
258
|
+
// Single request handler for both triggers and continuations
|
|
259
|
+
request: (request: HttpRequest, options?: HttpRequestOptions) => Promise<Response>;
|
|
258
260
|
}
|
|
259
261
|
|
|
260
|
-
interface
|
|
262
|
+
interface HttpRequestOptions {
|
|
261
263
|
signal?: AbortSignal;
|
|
262
264
|
}
|
|
265
|
+
|
|
266
|
+
// Discriminated union for request types
|
|
267
|
+
type HttpRequest = TriggerRequest | ContinueRequest;
|
|
268
|
+
|
|
269
|
+
// Start a new conversation turn
|
|
270
|
+
interface TriggerRequest {
|
|
271
|
+
type: 'trigger';
|
|
272
|
+
triggerName: string;
|
|
273
|
+
input?: Record<string, unknown>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Continue after client-side tool handling
|
|
277
|
+
interface ContinueRequest {
|
|
278
|
+
type: 'continue';
|
|
279
|
+
executionId: string;
|
|
280
|
+
toolResults: ToolResult[];
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
The `request` function receives a discriminated union. Spread the request onto your payload:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
request: (payload, options) =>
|
|
288
|
+
fetch('/api/trigger', {
|
|
289
|
+
method: 'POST',
|
|
290
|
+
headers: { 'Content-Type': 'application/json' },
|
|
291
|
+
body: JSON.stringify({ sessionId, ...payload }),
|
|
292
|
+
signal: options?.signal,
|
|
293
|
+
});
|
|
263
294
|
```
|
|
264
295
|
|
|
265
296
|
## Protocol
|
|
266
297
|
|
|
267
298
|
### Request Format
|
|
268
299
|
|
|
269
|
-
The `
|
|
300
|
+
The `request` function receives a discriminated union with `type` to identify the request kind:
|
|
301
|
+
|
|
302
|
+
**Trigger Request** (start a new turn):
|
|
270
303
|
|
|
271
304
|
```json
|
|
272
305
|
{
|
|
273
306
|
"sessionId": "sess_abc123",
|
|
307
|
+
"type": "trigger",
|
|
274
308
|
"triggerName": "user-message",
|
|
275
309
|
"input": {
|
|
276
310
|
"USER_MESSAGE": "Hello"
|
|
@@ -278,12 +312,29 @@ The `triggerRequest` function should send a POST request with:
|
|
|
278
312
|
}
|
|
279
313
|
```
|
|
280
314
|
|
|
315
|
+
**Continue Request** (after client tool handling):
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"sessionId": "sess_abc123",
|
|
320
|
+
"type": "continue",
|
|
321
|
+
"executionId": "exec_xyz789",
|
|
322
|
+
"toolResults": [
|
|
323
|
+
{
|
|
324
|
+
"toolCallId": "call_abc",
|
|
325
|
+
"toolName": "get-browser-location",
|
|
326
|
+
"result": { "lat": 40.7128, "lng": -74.006 }
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
281
332
|
### Response Format
|
|
282
333
|
|
|
283
334
|
The server responds with an SSE stream:
|
|
284
335
|
|
|
285
336
|
```
|
|
286
|
-
data: {"type":"start","messageId":"msg_xyz"}
|
|
337
|
+
data: {"type":"start","messageId":"msg_xyz","executionId":"exec_xyz789"}
|
|
287
338
|
|
|
288
339
|
data: {"type":"text-delta","id":"msg_xyz","delta":"Hello"}
|
|
289
340
|
|
|
@@ -294,11 +345,24 @@ data: {"type":"finish","finishReason":"stop"}
|
|
|
294
345
|
data: [DONE]
|
|
295
346
|
```
|
|
296
347
|
|
|
348
|
+
If client tools are needed, the stream pauses with a `client-tool-request` event:
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
data: {"type":"client-tool-request","executionId":"exec_xyz789","toolCalls":[...]}
|
|
352
|
+
|
|
353
|
+
data: {"type":"finish","finishReason":"client-tool-calls","executionId":"exec_xyz789"}
|
|
354
|
+
|
|
355
|
+
data: [DONE]
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The client handles the tools and sends a `continue` request to resume.
|
|
359
|
+
|
|
297
360
|
See [Streaming Events](/docs/server-sdk/streaming#event-types) for the full list of event types.
|
|
298
361
|
|
|
299
362
|
## Next Steps
|
|
300
363
|
|
|
301
364
|
- [Quick Start](/docs/getting-started/quickstart) — Complete Next.js integration guide
|
|
365
|
+
- [Client Tools](/docs/client-sdk/client-tools) — Handling tools on the client side
|
|
302
366
|
- [Messages](/docs/client-sdk/messages) — Working with message state
|
|
303
367
|
- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs
|
|
304
368
|
- [Error Handling](/docs/client-sdk/error-handling) — Handling errors with type guards
|
|
@@ -288,11 +288,12 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
288
288
|
const transport = useMemo(
|
|
289
289
|
() =>
|
|
290
290
|
createHttpTransport({
|
|
291
|
-
|
|
291
|
+
request: (payload, options) =>
|
|
292
292
|
fetch('/api/trigger', {
|
|
293
293
|
method: 'POST',
|
|
294
294
|
headers: { 'Content-Type': 'application/json' },
|
|
295
|
-
body: JSON.stringify({ sessionId,
|
|
295
|
+
body: JSON.stringify({ sessionId, ...payload }),
|
|
296
|
+
signal: options?.signal,
|
|
296
297
|
}),
|
|
297
298
|
}),
|
|
298
299
|
[sessionId],
|
|
@@ -50,11 +50,12 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
50
50
|
const transport = useMemo(
|
|
51
51
|
() =>
|
|
52
52
|
createHttpTransport({
|
|
53
|
-
|
|
53
|
+
request: (payload, options) =>
|
|
54
54
|
fetch('/api/trigger', {
|
|
55
55
|
method: 'POST',
|
|
56
56
|
headers: { 'Content-Type': 'application/json' },
|
|
57
|
-
body: JSON.stringify({ sessionId,
|
|
57
|
+
body: JSON.stringify({ sessionId, ...payload }),
|
|
58
|
+
signal: options?.signal,
|
|
58
59
|
}),
|
|
59
60
|
}),
|
|
60
61
|
[sessionId],
|
|
@@ -332,11 +333,12 @@ export function Chat({ sessionId }: { sessionId: string }) {
|
|
|
332
333
|
const transport = useMemo(
|
|
333
334
|
() =>
|
|
334
335
|
createHttpTransport({
|
|
335
|
-
|
|
336
|
+
request: (payload, options) =>
|
|
336
337
|
fetch('/api/trigger', {
|
|
337
338
|
method: 'POST',
|
|
338
339
|
headers: { 'Content-Type': 'application/json' },
|
|
339
|
-
body: JSON.stringify({ sessionId,
|
|
340
|
+
body: JSON.stringify({ sessionId, ...payload }),
|
|
341
|
+
signal: options?.signal,
|
|
340
342
|
}),
|
|
341
343
|
}),
|
|
342
344
|
[sessionId],
|