@octavus/docs 0.0.9 → 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.
- package/README.md +127 -0
- package/content/01-getting-started/01-introduction.md +3 -3
- package/content/01-getting-started/02-quickstart.md +40 -17
- package/content/02-server-sdk/01-overview.md +54 -11
- package/content/02-server-sdk/02-sessions.md +166 -15
- package/content/02-server-sdk/03-tools.md +21 -21
- package/content/02-server-sdk/04-streaming.md +50 -20
- package/content/02-server-sdk/05-cli.md +247 -0
- package/content/03-client-sdk/01-overview.md +65 -35
- package/content/03-client-sdk/02-messages.md +116 -8
- package/content/03-client-sdk/03-streaming.md +36 -17
- package/content/03-client-sdk/04-execution-blocks.md +8 -12
- package/content/03-client-sdk/05-socket-transport.md +161 -45
- package/content/03-client-sdk/06-http-transport.md +48 -24
- package/content/03-client-sdk/07-structured-output.md +412 -0
- package/content/03-client-sdk/08-file-uploads.md +473 -0
- package/content/03-client-sdk/09-error-handling.md +274 -0
- package/content/04-protocol/01-overview.md +24 -14
- package/content/04-protocol/02-input-resources.md +35 -35
- package/content/04-protocol/03-triggers.md +9 -11
- package/content/04-protocol/04-tools.md +63 -29
- package/content/04-protocol/05-skills.md +304 -0
- package/content/04-protocol/06-handlers.md +304 -0
- package/content/04-protocol/07-agent-config.md +334 -0
- package/content/04-protocol/{07-provider-options.md → 08-provider-options.md} +54 -35
- package/content/04-protocol/09-skills-advanced.md +439 -0
- package/content/04-protocol/10-types.md +719 -0
- package/content/05-api-reference/01-overview.md +20 -21
- package/content/05-api-reference/02-sessions.md +192 -37
- package/content/05-api-reference/03-agents.md +25 -37
- package/content/06-examples/01-overview.md +6 -4
- package/content/06-examples/02-nextjs-chat.md +28 -18
- package/content/06-examples/03-socket-chat.md +53 -30
- package/content/06-examples/_meta.md +0 -1
- package/dist/chunk-WJ2W3DUC.js +663 -0
- package/dist/chunk-WJ2W3DUC.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +99 -36
- 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 +99 -36
- package/package.json +12 -2
- package/content/04-protocol/05-handlers.md +0 -251
- package/content/04-protocol/06-agent-config.md +0 -242
- package/dist/chunk-232K4EME.js +0 -439
- package/dist/chunk-232K4EME.js.map +0 -1
- package/dist/chunk-2JDZLMS3.js +0 -439
- package/dist/chunk-2JDZLMS3.js.map +0 -1
- package/dist/chunk-2YMRODFE.js +0 -421
- package/dist/chunk-2YMRODFE.js.map +0 -1
- package/dist/chunk-2ZBPX5QB.js +0 -421
- package/dist/chunk-2ZBPX5QB.js.map +0 -1
- package/dist/chunk-3PIIST4D.js +0 -421
- package/dist/chunk-3PIIST4D.js.map +0 -1
- package/dist/chunk-42JETGDO.js +0 -421
- package/dist/chunk-42JETGDO.js.map +0 -1
- package/dist/chunk-4WWUKU4V.js +0 -421
- package/dist/chunk-4WWUKU4V.js.map +0 -1
- package/dist/chunk-5M7DS4DF.js +0 -519
- package/dist/chunk-5M7DS4DF.js.map +0 -1
- package/dist/chunk-6JQ3OMGF.js +0 -421
- package/dist/chunk-6JQ3OMGF.js.map +0 -1
- package/dist/chunk-7AOWCJHW.js +0 -421
- package/dist/chunk-7AOWCJHW.js.map +0 -1
- package/dist/chunk-7AS4ST73.js +0 -421
- package/dist/chunk-7AS4ST73.js.map +0 -1
- package/dist/chunk-7F5WOCIL.js +0 -421
- package/dist/chunk-7F5WOCIL.js.map +0 -1
- package/dist/chunk-7FPUAWSX.js +0 -421
- package/dist/chunk-7FPUAWSX.js.map +0 -1
- package/dist/chunk-7KXF63FV.js +0 -537
- package/dist/chunk-7KXF63FV.js.map +0 -1
- package/dist/chunk-APASMJBS.js +0 -421
- package/dist/chunk-APASMJBS.js.map +0 -1
- package/dist/chunk-BCEV3WV2.js +0 -421
- package/dist/chunk-BCEV3WV2.js.map +0 -1
- package/dist/chunk-CHGY4G27.js +0 -421
- package/dist/chunk-CHGY4G27.js.map +0 -1
- package/dist/chunk-CI7JDWKU.js +0 -421
- package/dist/chunk-CI7JDWKU.js.map +0 -1
- package/dist/chunk-CVFWWRL7.js +0 -421
- package/dist/chunk-CVFWWRL7.js.map +0 -1
- package/dist/chunk-EPDM2NIJ.js +0 -421
- package/dist/chunk-EPDM2NIJ.js.map +0 -1
- package/dist/chunk-ESGSYVGK.js +0 -421
- package/dist/chunk-ESGSYVGK.js.map +0 -1
- package/dist/chunk-GDCTM2SV.js +0 -421
- package/dist/chunk-GDCTM2SV.js.map +0 -1
- package/dist/chunk-GJ6FMIPD.js +0 -421
- package/dist/chunk-GJ6FMIPD.js.map +0 -1
- package/dist/chunk-H6JGSSAJ.js +0 -519
- package/dist/chunk-H6JGSSAJ.js.map +0 -1
- package/dist/chunk-IKQHGGUZ.js +0 -421
- package/dist/chunk-IKQHGGUZ.js.map +0 -1
- package/dist/chunk-IUKE3XDN.js +0 -421
- package/dist/chunk-IUKE3XDN.js.map +0 -1
- package/dist/chunk-J26MLMLN.js +0 -421
- package/dist/chunk-J26MLMLN.js.map +0 -1
- package/dist/chunk-J7BMB3ZW.js +0 -421
- package/dist/chunk-J7BMB3ZW.js.map +0 -1
- package/dist/chunk-JCBQRD5N.js +0 -421
- package/dist/chunk-JCBQRD5N.js.map +0 -1
- package/dist/chunk-JOB6YWEF.js +0 -421
- package/dist/chunk-JOB6YWEF.js.map +0 -1
- package/dist/chunk-JZRABTHU.js +0 -519
- package/dist/chunk-JZRABTHU.js.map +0 -1
- package/dist/chunk-K3GFQUMC.js +0 -421
- package/dist/chunk-K3GFQUMC.js.map +0 -1
- package/dist/chunk-LWYMRXBF.js +0 -421
- package/dist/chunk-LWYMRXBF.js.map +0 -1
- package/dist/chunk-M2R2NDPR.js +0 -421
- package/dist/chunk-M2R2NDPR.js.map +0 -1
- package/dist/chunk-MA3P7WCA.js +0 -421
- package/dist/chunk-MA3P7WCA.js.map +0 -1
- package/dist/chunk-MDMRCS4W.mjs +0 -421
- package/dist/chunk-MDMRCS4W.mjs.map +0 -1
- package/dist/chunk-MJXTA2R6.js +0 -421
- package/dist/chunk-MJXTA2R6.js.map +0 -1
- package/dist/chunk-NFVJQNDP.js +0 -421
- package/dist/chunk-NFVJQNDP.js.map +0 -1
- package/dist/chunk-O5TLYMQP.js +0 -421
- package/dist/chunk-O5TLYMQP.js.map +0 -1
- package/dist/chunk-OECAPVSX.js +0 -439
- package/dist/chunk-OECAPVSX.js.map +0 -1
- package/dist/chunk-OL5QDJ42.js +0 -483
- package/dist/chunk-OL5QDJ42.js.map +0 -1
- package/dist/chunk-PMOVVTHO.js +0 -519
- package/dist/chunk-PMOVVTHO.js.map +0 -1
- package/dist/chunk-QCHDPR2D.js +0 -421
- package/dist/chunk-QCHDPR2D.js.map +0 -1
- package/dist/chunk-R5MTVABN.js +0 -439
- package/dist/chunk-R5MTVABN.js.map +0 -1
- package/dist/chunk-RJ4H4YVA.js +0 -519
- package/dist/chunk-RJ4H4YVA.js.map +0 -1
- package/dist/chunk-S5U4IWCR.js +0 -439
- package/dist/chunk-S5U4IWCR.js.map +0 -1
- package/dist/chunk-SCKIOGKI.js +0 -421
- package/dist/chunk-SCKIOGKI.js.map +0 -1
- package/dist/chunk-TGJSIJYP.js +0 -421
- package/dist/chunk-TGJSIJYP.js.map +0 -1
- package/dist/chunk-TQJG6EBM.js +0 -537
- package/dist/chunk-TQJG6EBM.js.map +0 -1
- package/dist/chunk-TQZRBMU7.js +0 -421
- package/dist/chunk-TQZRBMU7.js.map +0 -1
- package/dist/chunk-TRL4RSEO.js +0 -421
- package/dist/chunk-TRL4RSEO.js.map +0 -1
- package/dist/chunk-TWUMRHQ7.js +0 -421
- package/dist/chunk-TWUMRHQ7.js.map +0 -1
- package/dist/chunk-UCJE36LL.js +0 -519
- package/dist/chunk-UCJE36LL.js.map +0 -1
- package/dist/chunk-VCASA6KL.js +0 -421
- package/dist/chunk-VCASA6KL.js.map +0 -1
- package/dist/chunk-VWPQ6ORV.js +0 -421
- package/dist/chunk-VWPQ6ORV.js.map +0 -1
- package/dist/chunk-WPXKIHLT.js +0 -421
- package/dist/chunk-WPXKIHLT.js.map +0 -1
- package/dist/chunk-WUNFFJ32.js +0 -421
- package/dist/chunk-WUNFFJ32.js.map +0 -1
- package/dist/chunk-WW7TRC7S.js +0 -519
- package/dist/chunk-WW7TRC7S.js.map +0 -1
- package/dist/chunk-XVSMRXBJ.js +0 -421
- package/dist/chunk-XVSMRXBJ.js.map +0 -1
- package/dist/chunk-YPPXXV3I.js +0 -421
- package/dist/chunk-YPPXXV3I.js.map +0 -1
- package/dist/chunk-ZKZVV4OQ.js +0 -421
- package/dist/chunk-ZKZVV4OQ.js.map +0 -1
- package/dist/chunk-ZOFEX73I.js +0 -421
- package/dist/chunk-ZOFEX73I.js.map +0 -1
- package/dist/content.mjs +0 -17
- package/dist/content.mjs.map +0 -1
- package/dist/index.mjs +0 -11
- package/dist/index.mjs.map +0 -1
- package/dist/search.mjs +0 -30
- package/dist/search.mjs.map +0 -1
- package/dist/types-BltYGlWI.d.ts +0 -36
|
@@ -9,22 +9,80 @@ The socket transport enables real-time bidirectional communication using WebSock
|
|
|
9
9
|
|
|
10
10
|
## When to Use Socket Transport
|
|
11
11
|
|
|
12
|
-
| Use Case
|
|
13
|
-
|
|
14
|
-
| Standard web apps (Next.js, etc.)
|
|
15
|
-
| Real-time apps with custom events
|
|
16
|
-
| Apps behind proxies that don't support SSE
|
|
17
|
-
| Need for typing indicators, presence, etc.
|
|
18
|
-
| Meteor, Phoenix, or socket-based frameworks | Socket
|
|
12
|
+
| Use Case | Recommended Transport |
|
|
13
|
+
| ------------------------------------------- | -------------------------------- |
|
|
14
|
+
| Standard web apps (Next.js, etc.) | HTTP (`createHttpTransport`) |
|
|
15
|
+
| Real-time apps with custom events | Socket (`createSocketTransport`) |
|
|
16
|
+
| Apps behind proxies that don't support SSE | Socket |
|
|
17
|
+
| Need for typing indicators, presence, etc. | Socket |
|
|
18
|
+
| Meteor, Phoenix, or socket-based frameworks | Socket |
|
|
19
|
+
|
|
20
|
+
## Connection Lifecycle
|
|
21
|
+
|
|
22
|
+
By default, socket transport uses **lazy connection** — the socket connects only when you first call `send()`. This is efficient but can be surprising if you want to show connection status.
|
|
23
|
+
|
|
24
|
+
For UI indicators, use **eager connection**:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { useEffect, useMemo } from 'react';
|
|
28
|
+
import SockJS from 'sockjs-client';
|
|
29
|
+
import { useOctavusChat, createSocketTransport, type SocketLike } from '@octavus/react';
|
|
30
|
+
|
|
31
|
+
function Chat() {
|
|
32
|
+
const transport = useMemo(
|
|
33
|
+
() => createSocketTransport({
|
|
34
|
+
connect: () => new Promise((resolve, reject) => {
|
|
35
|
+
const sock = new SockJS('/octavus');
|
|
36
|
+
sock.onopen = () => resolve(sock);
|
|
37
|
+
sock.onerror = () => reject(new Error('Connection failed'));
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
[],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
messages,
|
|
45
|
+
status,
|
|
46
|
+
send,
|
|
47
|
+
// Socket-specific connection state
|
|
48
|
+
connectionState, // 'disconnected' | 'connecting' | 'connected' | 'error'
|
|
49
|
+
connectionError, // Error object if connectionState is 'error'
|
|
50
|
+
connect, // () => Promise<void>
|
|
51
|
+
disconnect, // () => void
|
|
52
|
+
} = useOctavusChat({ transport });
|
|
53
|
+
|
|
54
|
+
// Eagerly connect on mount
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
connect?.();
|
|
57
|
+
return () => disconnect?.();
|
|
58
|
+
}, [connect, disconnect]);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div>
|
|
62
|
+
<ConnectionIndicator state={connectionState} />
|
|
63
|
+
{/* Chat UI */}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Connection States
|
|
70
|
+
|
|
71
|
+
| State | Description |
|
|
72
|
+
| -------------- | ----------------------------------------------------- |
|
|
73
|
+
| `disconnected` | Not connected (initial state or after `disconnect()`) |
|
|
74
|
+
| `connecting` | Connection attempt in progress |
|
|
75
|
+
| `connected` | Socket is open and ready |
|
|
76
|
+
| `error` | Connection failed (check `connectionError`) |
|
|
19
77
|
|
|
20
78
|
## Patterns Overview
|
|
21
79
|
|
|
22
80
|
There are two main patterns for socket-based integrations:
|
|
23
81
|
|
|
24
|
-
| Pattern
|
|
25
|
-
|
|
82
|
+
| Pattern | When to Use |
|
|
83
|
+
| --------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
26
84
|
| [Server-Managed Sessions](#server-managed-sessions-recommended) | **Recommended.** Server creates sessions lazily. Client doesn't need sessionId. |
|
|
27
|
-
| [Client-Provided Session ID](#client-provided-session-id)
|
|
85
|
+
| [Client-Provided Session ID](#client-provided-session-id) | When client must control session creation or pass sessionId from URL. |
|
|
28
86
|
|
|
29
87
|
## Server-Managed Sessions (Recommended)
|
|
30
88
|
|
|
@@ -33,7 +91,7 @@ The cleanest pattern is to have the server manage session lifecycle. The client
|
|
|
33
91
|
### Client Setup
|
|
34
92
|
|
|
35
93
|
```typescript
|
|
36
|
-
import { useMemo } from 'react';
|
|
94
|
+
import { useEffect, useMemo } from 'react';
|
|
37
95
|
import SockJS from 'sockjs-client';
|
|
38
96
|
import { useOctavusChat, createSocketTransport, type SocketLike } from '@octavus/react';
|
|
39
97
|
|
|
@@ -47,22 +105,23 @@ function connectSocket(): Promise<SocketLike> {
|
|
|
47
105
|
|
|
48
106
|
function Chat() {
|
|
49
107
|
// Transport is stable — no dependencies on sessionId
|
|
50
|
-
const transport = useMemo(
|
|
51
|
-
() => createSocketTransport({ connect: connectSocket }),
|
|
52
|
-
[],
|
|
53
|
-
);
|
|
108
|
+
const transport = useMemo(() => createSocketTransport({ connect: connectSocket }), []);
|
|
54
109
|
|
|
55
|
-
const { messages, status, send } = useOctavusChat({
|
|
110
|
+
const { messages, status, send, stop, connectionState, connect, disconnect } = useOctavusChat({
|
|
111
|
+
transport,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Eagerly connect for UI status indicator
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
connect?.();
|
|
117
|
+
return () => disconnect?.();
|
|
118
|
+
}, [connect, disconnect]);
|
|
56
119
|
|
|
57
120
|
const sendMessage = async (text: string) => {
|
|
58
|
-
await send(
|
|
59
|
-
'user-message',
|
|
60
|
-
{ USER_MESSAGE: text },
|
|
61
|
-
{ userMessage: { content: text } },
|
|
62
|
-
);
|
|
121
|
+
await send('user-message', { USER_MESSAGE: text }, { userMessage: { content: text } });
|
|
63
122
|
};
|
|
64
123
|
|
|
65
|
-
// ... render
|
|
124
|
+
// ... render chat UI
|
|
66
125
|
}
|
|
67
126
|
```
|
|
68
127
|
|
|
@@ -113,11 +172,12 @@ function createSocketHandler() {
|
|
|
113
172
|
abortController = new AbortController();
|
|
114
173
|
|
|
115
174
|
// Iterate events directly — no SSE parsing needed
|
|
116
|
-
const events = session.trigger(msg.triggerName, msg.input
|
|
175
|
+
const events = session.trigger(msg.triggerName, msg.input, {
|
|
176
|
+
signal: abortController.signal,
|
|
177
|
+
});
|
|
117
178
|
|
|
118
179
|
try {
|
|
119
180
|
for await (const event of events) {
|
|
120
|
-
if (abortController.signal.aborted) break;
|
|
121
181
|
conn.write(JSON.stringify(event));
|
|
122
182
|
}
|
|
123
183
|
} catch {
|
|
@@ -136,6 +196,7 @@ sockServer.installHandlers(httpServer);
|
|
|
136
196
|
```
|
|
137
197
|
|
|
138
198
|
**Benefits of this pattern:**
|
|
199
|
+
|
|
139
200
|
- Client code is simple — no sessionId management
|
|
140
201
|
- No transport caching issues
|
|
141
202
|
- Session is created only when needed
|
|
@@ -194,7 +255,9 @@ sockServer.on('connection', (conn) => {
|
|
|
194
255
|
// Handle session initialization
|
|
195
256
|
if (msg.type === 'init') {
|
|
196
257
|
session = client.agentSessions.attach(msg.sessionId, {
|
|
197
|
-
tools: {
|
|
258
|
+
tools: {
|
|
259
|
+
/* ... */
|
|
260
|
+
},
|
|
198
261
|
});
|
|
199
262
|
return;
|
|
200
263
|
}
|
|
@@ -206,10 +269,15 @@ sockServer.on('connection', (conn) => {
|
|
|
206
269
|
|
|
207
270
|
// All other messages require initialized session
|
|
208
271
|
if (!session) {
|
|
209
|
-
conn.write(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
272
|
+
conn.write(
|
|
273
|
+
JSON.stringify({
|
|
274
|
+
type: 'error',
|
|
275
|
+
errorType: 'validation_error',
|
|
276
|
+
message: 'Session not initialized. Send init message first.',
|
|
277
|
+
source: 'platform',
|
|
278
|
+
retryable: false,
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
213
281
|
return;
|
|
214
282
|
}
|
|
215
283
|
|
|
@@ -233,7 +301,7 @@ function ChatPage() {
|
|
|
233
301
|
const [sessionId, setSessionId] = useState<string | null>(null);
|
|
234
302
|
|
|
235
303
|
useEffect(() => {
|
|
236
|
-
api.createSession().then(res => setSessionId(res.sessionId));
|
|
304
|
+
api.createSession().then((res) => setSessionId(res.sessionId));
|
|
237
305
|
}, []);
|
|
238
306
|
|
|
239
307
|
// Don't render until sessionId is ready
|
|
@@ -261,9 +329,7 @@ const transport = useMemo(
|
|
|
261
329
|
createSocketTransport({
|
|
262
330
|
connect: () =>
|
|
263
331
|
new Promise((resolve, reject) => {
|
|
264
|
-
const ws = new WebSocket(
|
|
265
|
-
`wss://your-server.com/octavus?sessionId=${sessionId}`
|
|
266
|
-
);
|
|
332
|
+
const ws = new WebSocket(`wss://your-server.com/octavus?sessionId=${sessionId}`);
|
|
267
333
|
ws.onopen = () => resolve(ws);
|
|
268
334
|
ws.onerror = () => reject(new Error('WebSocket connection failed'));
|
|
269
335
|
}),
|
|
@@ -306,6 +372,59 @@ const transport = createSocketTransport({
|
|
|
306
372
|
|
|
307
373
|
## Connection Management
|
|
308
374
|
|
|
375
|
+
### Connection State API
|
|
376
|
+
|
|
377
|
+
The socket transport provides full connection lifecycle control:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
const transport = createSocketTransport({
|
|
381
|
+
connect: () =>
|
|
382
|
+
new Promise((resolve, reject) => {
|
|
383
|
+
const sock = new SockJS('/octavus');
|
|
384
|
+
sock.onopen = () => resolve(sock);
|
|
385
|
+
sock.onerror = () => reject(new Error('Connection failed'));
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Access connection state
|
|
390
|
+
console.log(transport.connectionState); // 'disconnected' | 'connecting' | 'connected' | 'error'
|
|
391
|
+
|
|
392
|
+
// Subscribe to state changes
|
|
393
|
+
const unsubscribe = transport.onConnectionStateChange((state, error) => {
|
|
394
|
+
console.log('Connection state:', state);
|
|
395
|
+
if (error) console.error('Error:', error);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Eager connection
|
|
399
|
+
await transport.connect();
|
|
400
|
+
|
|
401
|
+
// Manual disconnect
|
|
402
|
+
transport.disconnect();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Using with useOctavusChat
|
|
406
|
+
|
|
407
|
+
The React hook exposes connection state automatically for socket transports:
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
const {
|
|
411
|
+
messages,
|
|
412
|
+
status,
|
|
413
|
+
send,
|
|
414
|
+
// Socket-specific (undefined for HTTP transport)
|
|
415
|
+
connectionState,
|
|
416
|
+
connectionError,
|
|
417
|
+
connect,
|
|
418
|
+
disconnect,
|
|
419
|
+
} = useOctavusChat({ transport });
|
|
420
|
+
|
|
421
|
+
// Eagerly connect on mount
|
|
422
|
+
useEffect(() => {
|
|
423
|
+
connect?.();
|
|
424
|
+
return () => disconnect?.();
|
|
425
|
+
}, [connect, disconnect]);
|
|
426
|
+
```
|
|
427
|
+
|
|
309
428
|
### Handling Disconnections
|
|
310
429
|
|
|
311
430
|
```typescript
|
|
@@ -314,7 +433,7 @@ const transport = createSocketTransport({
|
|
|
314
433
|
|
|
315
434
|
onClose: () => {
|
|
316
435
|
console.log('Socket disconnected');
|
|
317
|
-
|
|
436
|
+
// Connection state is automatically updated to 'disconnected'
|
|
318
437
|
},
|
|
319
438
|
});
|
|
320
439
|
```
|
|
@@ -351,10 +470,7 @@ function useReconnectingTransport() {
|
|
|
351
470
|
});
|
|
352
471
|
}, []);
|
|
353
472
|
|
|
354
|
-
return useMemo(
|
|
355
|
-
() => createSocketTransport({ connect }),
|
|
356
|
-
[connect],
|
|
357
|
-
);
|
|
473
|
+
return useMemo(() => createSocketTransport({ connect }), [connect]);
|
|
358
474
|
}
|
|
359
475
|
```
|
|
360
476
|
|
|
@@ -374,12 +490,12 @@ const SockJS: typeof import('sockjs-client') = require('sockjs-client');
|
|
|
374
490
|
|
|
375
491
|
### SockJS vs WebSocket
|
|
376
492
|
|
|
377
|
-
| Feature
|
|
378
|
-
|
|
379
|
-
| Browser support
|
|
380
|
-
| Session ID
|
|
381
|
-
| Proxy compatibility | Varies
|
|
382
|
-
| Setup complexity
|
|
493
|
+
| Feature | WebSocket | SockJS |
|
|
494
|
+
| ------------------- | -------------------- | -------------------------------- |
|
|
495
|
+
| Browser support | Modern browsers | All browsers (with fallbacks) |
|
|
496
|
+
| Session ID | Via URL query params | Via init message |
|
|
497
|
+
| Proxy compatibility | Varies | Excellent (polling fallback) |
|
|
498
|
+
| Setup complexity | Lower | Higher (requires server library) |
|
|
383
499
|
|
|
384
500
|
## Protocol Reference
|
|
385
501
|
|
|
@@ -406,7 +522,7 @@ The server sends Octavus `StreamEvent` objects as JSON. See [Streaming Events](/
|
|
|
406
522
|
{ type: 'text-delta', id: '...', delta: 'Hello' }
|
|
407
523
|
{ type: 'tool-input-start', toolCallId: '...', toolName: 'get-user' }
|
|
408
524
|
{ type: 'finish', finishReason: 'stop' }
|
|
409
|
-
{ type: 'error',
|
|
525
|
+
{ type: 'error', errorType: 'internal_error', message: 'Something went wrong', source: 'platform', retryable: false }
|
|
410
526
|
```
|
|
411
527
|
|
|
412
528
|
## Full Example
|
|
@@ -9,12 +9,12 @@ The HTTP transport uses standard HTTP requests with Server-Sent Events (SSE) for
|
|
|
9
9
|
|
|
10
10
|
## When to Use HTTP Transport
|
|
11
11
|
|
|
12
|
-
| Use Case
|
|
13
|
-
|
|
14
|
-
| Next.js, Remix, or similar frameworks
|
|
15
|
-
| Standard web apps without special requirements | ✅ Use HTTP
|
|
16
|
-
| Serverless deployments (Vercel, etc.)
|
|
17
|
-
| Need custom real-time events
|
|
12
|
+
| Use Case | Recommendation |
|
|
13
|
+
| ---------------------------------------------- | -------------------------------------------------------------- |
|
|
14
|
+
| Next.js, Remix, or similar frameworks | ✅ Use HTTP |
|
|
15
|
+
| Standard web apps without special requirements | ✅ Use HTTP |
|
|
16
|
+
| Serverless deployments (Vercel, etc.) | ✅ Use HTTP |
|
|
17
|
+
| Need custom real-time events | Consider [Socket Transport](/docs/client-sdk/socket-transport) |
|
|
18
18
|
|
|
19
19
|
## Basic Setup
|
|
20
20
|
|
|
@@ -28,11 +28,12 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
28
28
|
const transport = useMemo(
|
|
29
29
|
() =>
|
|
30
30
|
createHttpTransport({
|
|
31
|
-
triggerRequest: (triggerName, input) =>
|
|
31
|
+
triggerRequest: (triggerName, input, options) =>
|
|
32
32
|
fetch('/api/trigger', {
|
|
33
33
|
method: 'POST',
|
|
34
34
|
headers: { 'Content-Type': 'application/json' },
|
|
35
35
|
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
36
|
+
signal: options?.signal,
|
|
36
37
|
}),
|
|
37
38
|
}),
|
|
38
39
|
[sessionId],
|
|
@@ -41,11 +42,7 @@ function Chat({ sessionId }: { sessionId: string }) {
|
|
|
41
42
|
const { messages, status, error, send, stop } = useOctavusChat({ transport });
|
|
42
43
|
|
|
43
44
|
const sendMessage = async (text: string) => {
|
|
44
|
-
await send(
|
|
45
|
-
'user-message',
|
|
46
|
-
{ USER_MESSAGE: text },
|
|
47
|
-
{ userMessage: { content: text } },
|
|
48
|
-
);
|
|
45
|
+
await send('user-message', { USER_MESSAGE: text }, { userMessage: { content: text } });
|
|
49
46
|
};
|
|
50
47
|
|
|
51
48
|
// ... render chat
|
|
@@ -74,8 +71,8 @@ export async function POST(request: Request) {
|
|
|
74
71
|
},
|
|
75
72
|
});
|
|
76
73
|
|
|
77
|
-
// trigger() returns
|
|
78
|
-
const events = session.trigger(triggerName, input);
|
|
74
|
+
// trigger() returns an async generator, toSSEStream() converts to SSE format
|
|
75
|
+
const events = session.trigger(triggerName, input, { signal: request.signal });
|
|
79
76
|
|
|
80
77
|
return new Response(toSSEStream(events), {
|
|
81
78
|
headers: {
|
|
@@ -112,8 +109,8 @@ export default function ChatPage() {
|
|
|
112
109
|
input: { COMPANY_NAME: 'Acme Corp' },
|
|
113
110
|
}),
|
|
114
111
|
})
|
|
115
|
-
.then(res => res.json())
|
|
116
|
-
.then(data => setSessionId(data.sessionId));
|
|
112
|
+
.then((res) => res.json())
|
|
113
|
+
.then((data) => setSessionId(data.sessionId));
|
|
117
114
|
}, []);
|
|
118
115
|
|
|
119
116
|
if (!sessionId) {
|
|
@@ -145,14 +142,23 @@ This pattern is cleaner as the session is ready before the component renders.
|
|
|
145
142
|
|
|
146
143
|
## Error Handling
|
|
147
144
|
|
|
148
|
-
Handle errors
|
|
145
|
+
Handle errors with structured error information:
|
|
149
146
|
|
|
150
147
|
```tsx
|
|
148
|
+
import { isRateLimitError, isProviderError } from '@octavus/react';
|
|
149
|
+
|
|
151
150
|
const { messages, status, error, send } = useOctavusChat({
|
|
152
151
|
transport,
|
|
153
152
|
onError: (err) => {
|
|
154
|
-
console.error('Stream error:', err);
|
|
155
|
-
|
|
153
|
+
console.error('Stream error:', err.errorType, err.message);
|
|
154
|
+
|
|
155
|
+
if (isRateLimitError(err)) {
|
|
156
|
+
toast.error(`Rate limited. Try again in ${err.retryAfter}s`);
|
|
157
|
+
} else if (isProviderError(err)) {
|
|
158
|
+
toast.error('AI service temporarily unavailable');
|
|
159
|
+
} else {
|
|
160
|
+
toast.error('Something went wrong');
|
|
161
|
+
}
|
|
156
162
|
},
|
|
157
163
|
});
|
|
158
164
|
|
|
@@ -162,12 +168,24 @@ if (error) {
|
|
|
162
168
|
}
|
|
163
169
|
```
|
|
164
170
|
|
|
171
|
+
See [Error Handling](/docs/client-sdk/error-handling) for comprehensive error handling patterns.
|
|
172
|
+
|
|
165
173
|
## Stop Streaming
|
|
166
174
|
|
|
167
|
-
Allow users to cancel ongoing streams:
|
|
175
|
+
Allow users to cancel ongoing streams. When `stop()` is called:
|
|
176
|
+
|
|
177
|
+
1. The HTTP request is aborted via the signal
|
|
178
|
+
2. Any partial content is preserved in the message
|
|
179
|
+
3. Tool calls in progress are marked as `cancelled`
|
|
180
|
+
4. Status changes to `idle`
|
|
168
181
|
|
|
169
182
|
```tsx
|
|
170
|
-
const { send, stop, status } = useOctavusChat({
|
|
183
|
+
const { send, stop, status } = useOctavusChat({
|
|
184
|
+
transport,
|
|
185
|
+
onStop: () => {
|
|
186
|
+
console.log('User stopped generation');
|
|
187
|
+
},
|
|
188
|
+
});
|
|
171
189
|
|
|
172
190
|
return (
|
|
173
191
|
<button
|
|
@@ -179,6 +197,8 @@ return (
|
|
|
179
197
|
);
|
|
180
198
|
```
|
|
181
199
|
|
|
200
|
+
> **Important**: For stop to work end-to-end, pass the `options.signal` to your `fetch()` call and forward `request.signal` to `session.trigger()` on the server.
|
|
201
|
+
|
|
182
202
|
## Express Server
|
|
183
203
|
|
|
184
204
|
For non-Next.js backends:
|
|
@@ -230,12 +250,16 @@ app.post('/api/trigger', async (req, res) => {
|
|
|
230
250
|
|
|
231
251
|
```typescript
|
|
232
252
|
interface HttpTransportOptions {
|
|
233
|
-
// Function that makes the HTTP request
|
|
234
253
|
triggerRequest: (
|
|
235
254
|
triggerName: string,
|
|
236
|
-
input?: Record<string, unknown
|
|
255
|
+
input?: Record<string, unknown>,
|
|
256
|
+
options?: TriggerRequestOptions,
|
|
237
257
|
) => Promise<Response>;
|
|
238
258
|
}
|
|
259
|
+
|
|
260
|
+
interface TriggerRequestOptions {
|
|
261
|
+
signal?: AbortSignal;
|
|
262
|
+
}
|
|
239
263
|
```
|
|
240
264
|
|
|
241
265
|
## Protocol
|
|
@@ -277,4 +301,4 @@ See [Streaming Events](/docs/server-sdk/streaming#event-types) for the full list
|
|
|
277
301
|
- [Quick Start](/docs/getting-started/quickstart) — Complete Next.js integration guide
|
|
278
302
|
- [Messages](/docs/client-sdk/messages) — Working with message state
|
|
279
303
|
- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs
|
|
280
|
-
|
|
304
|
+
- [Error Handling](/docs/client-sdk/error-handling) — Handling errors with type guards
|