@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.
Files changed (177) 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 +24 -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 +63 -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/{07-provider-options.md → 08-provider-options.md} +54 -35
  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 +99 -36
  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 +99 -36
  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 -242
  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-7KXF63FV.js +0 -537
  74. package/dist/chunk-7KXF63FV.js.map +0 -1
  75. package/dist/chunk-APASMJBS.js +0 -421
  76. package/dist/chunk-APASMJBS.js.map +0 -1
  77. package/dist/chunk-BCEV3WV2.js +0 -421
  78. package/dist/chunk-BCEV3WV2.js.map +0 -1
  79. package/dist/chunk-CHGY4G27.js +0 -421
  80. package/dist/chunk-CHGY4G27.js.map +0 -1
  81. package/dist/chunk-CI7JDWKU.js +0 -421
  82. package/dist/chunk-CI7JDWKU.js.map +0 -1
  83. package/dist/chunk-CVFWWRL7.js +0 -421
  84. package/dist/chunk-CVFWWRL7.js.map +0 -1
  85. package/dist/chunk-EPDM2NIJ.js +0 -421
  86. package/dist/chunk-EPDM2NIJ.js.map +0 -1
  87. package/dist/chunk-ESGSYVGK.js +0 -421
  88. package/dist/chunk-ESGSYVGK.js.map +0 -1
  89. package/dist/chunk-GDCTM2SV.js +0 -421
  90. package/dist/chunk-GDCTM2SV.js.map +0 -1
  91. package/dist/chunk-GJ6FMIPD.js +0 -421
  92. package/dist/chunk-GJ6FMIPD.js.map +0 -1
  93. package/dist/chunk-H6JGSSAJ.js +0 -519
  94. package/dist/chunk-H6JGSSAJ.js.map +0 -1
  95. package/dist/chunk-IKQHGGUZ.js +0 -421
  96. package/dist/chunk-IKQHGGUZ.js.map +0 -1
  97. package/dist/chunk-IUKE3XDN.js +0 -421
  98. package/dist/chunk-IUKE3XDN.js.map +0 -1
  99. package/dist/chunk-J26MLMLN.js +0 -421
  100. package/dist/chunk-J26MLMLN.js.map +0 -1
  101. package/dist/chunk-J7BMB3ZW.js +0 -421
  102. package/dist/chunk-J7BMB3ZW.js.map +0 -1
  103. package/dist/chunk-JCBQRD5N.js +0 -421
  104. package/dist/chunk-JCBQRD5N.js.map +0 -1
  105. package/dist/chunk-JOB6YWEF.js +0 -421
  106. package/dist/chunk-JOB6YWEF.js.map +0 -1
  107. package/dist/chunk-JZRABTHU.js +0 -519
  108. package/dist/chunk-JZRABTHU.js.map +0 -1
  109. package/dist/chunk-K3GFQUMC.js +0 -421
  110. package/dist/chunk-K3GFQUMC.js.map +0 -1
  111. package/dist/chunk-LWYMRXBF.js +0 -421
  112. package/dist/chunk-LWYMRXBF.js.map +0 -1
  113. package/dist/chunk-M2R2NDPR.js +0 -421
  114. package/dist/chunk-M2R2NDPR.js.map +0 -1
  115. package/dist/chunk-MA3P7WCA.js +0 -421
  116. package/dist/chunk-MA3P7WCA.js.map +0 -1
  117. package/dist/chunk-MDMRCS4W.mjs +0 -421
  118. package/dist/chunk-MDMRCS4W.mjs.map +0 -1
  119. package/dist/chunk-MJXTA2R6.js +0 -421
  120. package/dist/chunk-MJXTA2R6.js.map +0 -1
  121. package/dist/chunk-NFVJQNDP.js +0 -421
  122. package/dist/chunk-NFVJQNDP.js.map +0 -1
  123. package/dist/chunk-O5TLYMQP.js +0 -421
  124. package/dist/chunk-O5TLYMQP.js.map +0 -1
  125. package/dist/chunk-OECAPVSX.js +0 -439
  126. package/dist/chunk-OECAPVSX.js.map +0 -1
  127. package/dist/chunk-OL5QDJ42.js +0 -483
  128. package/dist/chunk-OL5QDJ42.js.map +0 -1
  129. package/dist/chunk-PMOVVTHO.js +0 -519
  130. package/dist/chunk-PMOVVTHO.js.map +0 -1
  131. package/dist/chunk-QCHDPR2D.js +0 -421
  132. package/dist/chunk-QCHDPR2D.js.map +0 -1
  133. package/dist/chunk-R5MTVABN.js +0 -439
  134. package/dist/chunk-R5MTVABN.js.map +0 -1
  135. package/dist/chunk-RJ4H4YVA.js +0 -519
  136. package/dist/chunk-RJ4H4YVA.js.map +0 -1
  137. package/dist/chunk-S5U4IWCR.js +0 -439
  138. package/dist/chunk-S5U4IWCR.js.map +0 -1
  139. package/dist/chunk-SCKIOGKI.js +0 -421
  140. package/dist/chunk-SCKIOGKI.js.map +0 -1
  141. package/dist/chunk-TGJSIJYP.js +0 -421
  142. package/dist/chunk-TGJSIJYP.js.map +0 -1
  143. package/dist/chunk-TQJG6EBM.js +0 -537
  144. package/dist/chunk-TQJG6EBM.js.map +0 -1
  145. package/dist/chunk-TQZRBMU7.js +0 -421
  146. package/dist/chunk-TQZRBMU7.js.map +0 -1
  147. package/dist/chunk-TRL4RSEO.js +0 -421
  148. package/dist/chunk-TRL4RSEO.js.map +0 -1
  149. package/dist/chunk-TWUMRHQ7.js +0 -421
  150. package/dist/chunk-TWUMRHQ7.js.map +0 -1
  151. package/dist/chunk-UCJE36LL.js +0 -519
  152. package/dist/chunk-UCJE36LL.js.map +0 -1
  153. package/dist/chunk-VCASA6KL.js +0 -421
  154. package/dist/chunk-VCASA6KL.js.map +0 -1
  155. package/dist/chunk-VWPQ6ORV.js +0 -421
  156. package/dist/chunk-VWPQ6ORV.js.map +0 -1
  157. package/dist/chunk-WPXKIHLT.js +0 -421
  158. package/dist/chunk-WPXKIHLT.js.map +0 -1
  159. package/dist/chunk-WUNFFJ32.js +0 -421
  160. package/dist/chunk-WUNFFJ32.js.map +0 -1
  161. package/dist/chunk-WW7TRC7S.js +0 -519
  162. package/dist/chunk-WW7TRC7S.js.map +0 -1
  163. package/dist/chunk-XVSMRXBJ.js +0 -421
  164. package/dist/chunk-XVSMRXBJ.js.map +0 -1
  165. package/dist/chunk-YPPXXV3I.js +0 -421
  166. package/dist/chunk-YPPXXV3I.js.map +0 -1
  167. package/dist/chunk-ZKZVV4OQ.js +0 -421
  168. package/dist/chunk-ZKZVV4OQ.js.map +0 -1
  169. package/dist/chunk-ZOFEX73I.js +0 -421
  170. package/dist/chunk-ZOFEX73I.js.map +0 -1
  171. package/dist/content.mjs +0 -17
  172. package/dist/content.mjs.map +0 -1
  173. package/dist/index.mjs +0 -11
  174. package/dist/index.mjs.map +0 -1
  175. package/dist/search.mjs +0 -30
  176. package/dist/search.mjs.map +0 -1
  177. 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 | 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 |
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 | When to Use |
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) | When client must control session creation or pass sessionId from URL. |
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({ transport });
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 messages
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(JSON.stringify({
210
- type: 'error',
211
- errorText: 'Session not initialized. Send init message first.',
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
- setConnectionStatus('disconnected');
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 | WebSocket | SockJS |
378
- |---------|-----------|--------|
379
- | Browser support | Modern browsers | All browsers (with fallbacks) |
380
- | Session ID | Via URL query params | Via init message |
381
- | Proxy compatibility | Varies | Excellent (polling fallback) |
382
- | Setup complexity | Lower | Higher (requires server library) |
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', errorText: 'Something went wrong' }
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 | 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) |
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 parsed events, toSSEStream() converts to SSE format
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 in both the transport and the hook:
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
- // Show toast, update UI, etc.
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({ transport });
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