@octavus/docs 0.0.6 → 0.0.7
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 +24 -16
- package/content/02-server-sdk/01-overview.md +24 -13
- package/content/03-client-sdk/01-overview.md +101 -42
- package/content/03-client-sdk/02-messages.md +71 -19
- package/content/03-client-sdk/03-streaming.md +38 -28
- package/content/03-client-sdk/05-socket-transport.md +304 -0
- package/content/04-protocol/03-triggers.md +39 -20
- package/content/04-protocol/04-tools.md +25 -15
- package/dist/chunk-232K4EME.js +439 -0
- package/dist/chunk-232K4EME.js.map +1 -0
- package/dist/chunk-2JDZLMS3.js +439 -0
- package/dist/chunk-2JDZLMS3.js.map +1 -0
- package/dist/chunk-7AS4ST73.js +421 -0
- package/dist/chunk-7AS4ST73.js.map +1 -0
- package/dist/chunk-OECAPVSX.js +439 -0
- package/dist/chunk-OECAPVSX.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +16 -7
- 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 +16 -7
- package/package.json +2 -2
|
@@ -118,14 +118,14 @@ export async function POST(request: Request) {
|
|
|
118
118
|
|
|
119
119
|
### 1. Create a Chat Component
|
|
120
120
|
|
|
121
|
-
Use the `useOctavusChat` hook
|
|
121
|
+
Use the `useOctavusChat` hook with the HTTP transport:
|
|
122
122
|
|
|
123
123
|
```tsx
|
|
124
124
|
// components/chat.tsx
|
|
125
125
|
'use client';
|
|
126
126
|
|
|
127
|
-
import {
|
|
128
|
-
import {
|
|
127
|
+
import { useState, useMemo } from 'react';
|
|
128
|
+
import { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';
|
|
129
129
|
|
|
130
130
|
interface ChatProps {
|
|
131
131
|
sessionId: string;
|
|
@@ -134,15 +134,21 @@ interface ChatProps {
|
|
|
134
134
|
export function Chat({ sessionId }: ChatProps) {
|
|
135
135
|
const [inputValue, setInputValue] = useState('');
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
// Create a stable transport instance
|
|
138
|
+
const transport = useMemo(
|
|
139
|
+
() =>
|
|
140
|
+
createHttpTransport({
|
|
141
|
+
triggerRequest: (triggerName, input) =>
|
|
142
|
+
fetch('/api/trigger', {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: { 'Content-Type': 'application/json' },
|
|
145
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
146
|
+
}),
|
|
147
|
+
}),
|
|
148
|
+
[sessionId],
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const { messages, status, error, send } = useOctavusChat({ transport });
|
|
146
152
|
|
|
147
153
|
const isStreaming = status === 'streaming';
|
|
148
154
|
|
|
@@ -154,9 +160,11 @@ export function Chat({ sessionId }: ChatProps) {
|
|
|
154
160
|
setInputValue('');
|
|
155
161
|
|
|
156
162
|
// Add user message and trigger in one call
|
|
157
|
-
await send(
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
await send(
|
|
164
|
+
'user-message',
|
|
165
|
+
{ USER_MESSAGE: message },
|
|
166
|
+
{ userMessage: { content: message } },
|
|
167
|
+
);
|
|
160
168
|
};
|
|
161
169
|
|
|
162
170
|
return (
|
|
@@ -208,7 +216,7 @@ function MessageBubble({ message }: { message: UIMessage }) {
|
|
|
208
216
|
}
|
|
209
217
|
return null;
|
|
210
218
|
})}
|
|
211
|
-
|
|
219
|
+
|
|
212
220
|
{/* Streaming indicator */}
|
|
213
221
|
{message.status === 'streaming' && (
|
|
214
222
|
<span className="inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1" />
|
|
@@ -34,13 +34,13 @@ Create and manage agent sessions:
|
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
36
|
// Create a new session
|
|
37
|
-
const sessionId = await client.agentSessions.create('
|
|
37
|
+
const sessionId = await client.agentSessions.create('agent-id', {
|
|
38
38
|
COMPANY_NAME: 'Acme Corp',
|
|
39
39
|
PRODUCT_NAME: 'Widget Pro',
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
// Get session
|
|
43
|
-
const
|
|
42
|
+
// Get UI-ready session messages (for session restore)
|
|
43
|
+
const session = await client.agentSessions.getMessages(sessionId);
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
### Tool Handlers
|
|
@@ -63,8 +63,8 @@ const session = client.agentSessions.attach(sessionId, {
|
|
|
63
63
|
All responses stream in real-time:
|
|
64
64
|
|
|
65
65
|
```typescript
|
|
66
|
-
const { stream } = session.trigger('user-message', {
|
|
67
|
-
USER_MESSAGE: 'Hello!'
|
|
66
|
+
const { stream } = session.trigger('user-message', {
|
|
67
|
+
USER_MESSAGE: 'Hello!',
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
// Use as a streaming response
|
|
@@ -88,7 +88,7 @@ interface OctavusClientConfig {
|
|
|
88
88
|
class OctavusClient {
|
|
89
89
|
readonly agents: AgentsApi;
|
|
90
90
|
readonly agentSessions: AgentSessionsApi;
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
constructor(config: OctavusClientConfig);
|
|
93
93
|
}
|
|
94
94
|
```
|
|
@@ -101,24 +101,35 @@ Manages agent sessions.
|
|
|
101
101
|
class AgentSessionsApi {
|
|
102
102
|
// Create a new session
|
|
103
103
|
async create(agentId: string, input?: Record<string, unknown>): Promise<string>;
|
|
104
|
-
|
|
105
|
-
// Get session state (
|
|
106
|
-
async get(sessionId: string): Promise<
|
|
107
|
-
|
|
104
|
+
|
|
105
|
+
// Get full session state (for debugging/internal use)
|
|
106
|
+
async get(sessionId: string): Promise<SessionState>;
|
|
107
|
+
|
|
108
|
+
// Get UI-ready messages (for client display)
|
|
109
|
+
async getMessages(sessionId: string): Promise<UISessionState>;
|
|
110
|
+
|
|
108
111
|
// Attach to a session for triggering
|
|
109
112
|
attach(sessionId: string, options?: SessionAttachOptions): AgentSession;
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
// Full session state (internal format)
|
|
116
|
+
interface SessionState {
|
|
113
117
|
id: string;
|
|
114
118
|
agentId: string;
|
|
115
119
|
input: Record<string, unknown>;
|
|
116
120
|
variables: Record<string, unknown>;
|
|
117
121
|
resources: Record<string, unknown>;
|
|
118
|
-
messages:
|
|
122
|
+
messages: ChatMessage[]; // Internal message format
|
|
119
123
|
createdAt: string;
|
|
120
124
|
updatedAt: string;
|
|
121
125
|
}
|
|
126
|
+
|
|
127
|
+
// UI-ready session state
|
|
128
|
+
interface UISessionState {
|
|
129
|
+
sessionId: string;
|
|
130
|
+
agentId: string;
|
|
131
|
+
messages: UIMessage[]; // UI-ready messages for frontend
|
|
132
|
+
}
|
|
122
133
|
```
|
|
123
134
|
|
|
124
135
|
### AgentSession
|
|
@@ -132,7 +143,7 @@ class AgentSession {
|
|
|
132
143
|
triggerName: string,
|
|
133
144
|
input?: Record<string, unknown>
|
|
134
145
|
): { stream: ReadableStream<Uint8Array> };
|
|
135
|
-
|
|
146
|
+
|
|
136
147
|
// Get the session ID
|
|
137
148
|
getSessionId(): string;
|
|
138
149
|
}
|
|
@@ -32,27 +32,46 @@ npm install @octavus/client-sdk
|
|
|
32
32
|
|
|
33
33
|
**Current version:** `{{VERSION:@octavus/client-sdk}}`
|
|
34
34
|
|
|
35
|
+
## Transport Pattern
|
|
36
|
+
|
|
37
|
+
The Client SDK uses a **transport abstraction** to handle communication with your backend. This gives you flexibility in how events are delivered:
|
|
38
|
+
|
|
39
|
+
| Transport | Use Case |
|
|
40
|
+
|-----------|----------|
|
|
41
|
+
| `createHttpTransport` | HTTP/SSE (Next.js, Express, etc.) |
|
|
42
|
+
| `createSocketTransport` | WebSocket, SockJS, or other socket protocols |
|
|
43
|
+
|
|
35
44
|
## React Usage
|
|
36
45
|
|
|
37
46
|
The `useOctavusChat` hook provides state management and streaming for React applications:
|
|
38
47
|
|
|
39
48
|
```tsx
|
|
40
|
-
import {
|
|
49
|
+
import { useMemo } from 'react';
|
|
50
|
+
import { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';
|
|
41
51
|
|
|
42
52
|
function Chat({ sessionId }: { sessionId: string }) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
// Create a stable transport instance (memoized on sessionId)
|
|
54
|
+
const transport = useMemo(
|
|
55
|
+
() =>
|
|
56
|
+
createHttpTransport({
|
|
57
|
+
triggerRequest: (triggerName, input) =>
|
|
58
|
+
fetch('/api/trigger', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json' },
|
|
61
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
62
|
+
}),
|
|
63
|
+
}),
|
|
64
|
+
[sessionId],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const { messages, status, send } = useOctavusChat({ transport });
|
|
51
68
|
|
|
52
69
|
const sendMessage = async (text: string) => {
|
|
53
|
-
await send(
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
await send(
|
|
71
|
+
'user-message',
|
|
72
|
+
{ USER_MESSAGE: text },
|
|
73
|
+
{ userMessage: { content: text } },
|
|
74
|
+
);
|
|
56
75
|
};
|
|
57
76
|
|
|
58
77
|
return (
|
|
@@ -83,17 +102,19 @@ function MessageBubble({ message }: { message: UIMessage }) {
|
|
|
83
102
|
The `OctavusChat` class can be used with any framework or vanilla JavaScript:
|
|
84
103
|
|
|
85
104
|
```typescript
|
|
86
|
-
import { OctavusChat } from '@octavus/client-sdk';
|
|
105
|
+
import { OctavusChat, createHttpTransport } from '@octavus/client-sdk';
|
|
87
106
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
107
|
+
const transport = createHttpTransport({
|
|
108
|
+
triggerRequest: (triggerName, input) =>
|
|
109
|
+
fetch('/api/trigger', {
|
|
91
110
|
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/json' },
|
|
92
112
|
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
93
|
-
})
|
|
94
|
-
},
|
|
113
|
+
}),
|
|
95
114
|
});
|
|
96
115
|
|
|
116
|
+
const chat = new OctavusChat({ transport });
|
|
117
|
+
|
|
97
118
|
// Subscribe to state changes
|
|
98
119
|
const unsubscribe = chat.subscribe(() => {
|
|
99
120
|
console.log('Messages:', chat.messages);
|
|
@@ -102,9 +123,11 @@ const unsubscribe = chat.subscribe(() => {
|
|
|
102
123
|
});
|
|
103
124
|
|
|
104
125
|
// Send a message
|
|
105
|
-
await chat.send(
|
|
106
|
-
|
|
107
|
-
}
|
|
126
|
+
await chat.send(
|
|
127
|
+
'user-message',
|
|
128
|
+
{ USER_MESSAGE: 'Hello' },
|
|
129
|
+
{ userMessage: { content: 'Hello' } },
|
|
130
|
+
);
|
|
108
131
|
|
|
109
132
|
// Cleanup when done
|
|
110
133
|
unsubscribe();
|
|
@@ -117,12 +140,14 @@ unsubscribe();
|
|
|
117
140
|
The `send` function handles both user message display and agent triggering in one call:
|
|
118
141
|
|
|
119
142
|
```tsx
|
|
120
|
-
const { send } = useOctavusChat({
|
|
143
|
+
const { send } = useOctavusChat({ transport });
|
|
121
144
|
|
|
122
145
|
// Add user message to UI and trigger agent
|
|
123
|
-
await send(
|
|
124
|
-
|
|
125
|
-
}
|
|
146
|
+
await send(
|
|
147
|
+
'user-message',
|
|
148
|
+
{ USER_MESSAGE: text },
|
|
149
|
+
{ userMessage: { content: text } },
|
|
150
|
+
);
|
|
126
151
|
|
|
127
152
|
// Trigger without adding a user message (e.g., button click)
|
|
128
153
|
await send('request-human');
|
|
@@ -133,7 +158,7 @@ await send('request-human');
|
|
|
133
158
|
Messages contain ordered `parts` for rich content:
|
|
134
159
|
|
|
135
160
|
```tsx
|
|
136
|
-
const { messages } = useOctavusChat({
|
|
161
|
+
const { messages } = useOctavusChat({ transport });
|
|
137
162
|
|
|
138
163
|
// Each message has typed parts
|
|
139
164
|
message.parts.map((part) => {
|
|
@@ -149,7 +174,7 @@ message.parts.map((part) => {
|
|
|
149
174
|
### Status Tracking
|
|
150
175
|
|
|
151
176
|
```tsx
|
|
152
|
-
const { status } = useOctavusChat({
|
|
177
|
+
const { status } = useOctavusChat({ transport });
|
|
153
178
|
|
|
154
179
|
// status: 'idle' | 'streaming' | 'error'
|
|
155
180
|
```
|
|
@@ -157,7 +182,7 @@ const { status } = useOctavusChat({...});
|
|
|
157
182
|
### Stop Streaming
|
|
158
183
|
|
|
159
184
|
```tsx
|
|
160
|
-
const { stop } = useOctavusChat({
|
|
185
|
+
const { stop } = useOctavusChat({ transport });
|
|
161
186
|
|
|
162
187
|
// Stop current stream and finalize message
|
|
163
188
|
stop();
|
|
@@ -171,12 +196,12 @@ stop();
|
|
|
171
196
|
function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn;
|
|
172
197
|
|
|
173
198
|
interface OctavusChatOptions {
|
|
174
|
-
// Required:
|
|
175
|
-
|
|
176
|
-
|
|
199
|
+
// Required: Transport for streaming events
|
|
200
|
+
transport: Transport;
|
|
201
|
+
|
|
177
202
|
// Optional: Pre-populate with existing messages (session restore)
|
|
178
203
|
initialMessages?: UIMessage[];
|
|
179
|
-
|
|
204
|
+
|
|
180
205
|
// Optional: Callbacks
|
|
181
206
|
onError?: (error: Error) => void;
|
|
182
207
|
onFinish?: () => void;
|
|
@@ -188,7 +213,7 @@ interface UseOctavusChatReturn {
|
|
|
188
213
|
messages: UIMessage[];
|
|
189
214
|
status: ChatStatus; // 'idle' | 'streaming' | 'error'
|
|
190
215
|
error: Error | null;
|
|
191
|
-
|
|
216
|
+
|
|
192
217
|
// Actions
|
|
193
218
|
send: (
|
|
194
219
|
triggerName: string,
|
|
@@ -198,16 +223,49 @@ interface UseOctavusChatReturn {
|
|
|
198
223
|
stop: () => void;
|
|
199
224
|
}
|
|
200
225
|
|
|
201
|
-
type TriggerFunction = (
|
|
202
|
-
triggerName: string,
|
|
203
|
-
input?: Record<string, unknown>,
|
|
204
|
-
) => Promise<Response>;
|
|
205
|
-
|
|
206
226
|
interface UserMessageInput {
|
|
207
227
|
content: string;
|
|
208
228
|
}
|
|
209
229
|
```
|
|
210
230
|
|
|
231
|
+
## Transport Reference
|
|
232
|
+
|
|
233
|
+
### createHttpTransport
|
|
234
|
+
|
|
235
|
+
Creates an HTTP/SSE transport using native `fetch()`:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { createHttpTransport } from '@octavus/react';
|
|
239
|
+
|
|
240
|
+
const transport = createHttpTransport({
|
|
241
|
+
triggerRequest: (triggerName, input) =>
|
|
242
|
+
fetch('/api/trigger', {
|
|
243
|
+
method: 'POST',
|
|
244
|
+
headers: { 'Content-Type': 'application/json' },
|
|
245
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
246
|
+
}),
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### createSocketTransport
|
|
251
|
+
|
|
252
|
+
Creates a WebSocket/SockJS transport for real-time connections:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { createSocketTransport } from '@octavus/react';
|
|
256
|
+
|
|
257
|
+
const transport = createSocketTransport({
|
|
258
|
+
connect: () =>
|
|
259
|
+
new Promise((resolve, reject) => {
|
|
260
|
+
const ws = new WebSocket(`wss://api.example.com/stream?sessionId=${sessionId}`);
|
|
261
|
+
ws.onopen = () => resolve(ws);
|
|
262
|
+
ws.onerror = () => reject(new Error('Connection failed'));
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
For detailed WebSocket/SockJS usage including custom events, reconnection patterns, and server-side implementation, see [Socket Transport](/docs/client-sdk/socket-transport).
|
|
268
|
+
|
|
211
269
|
## Class Reference (Framework-Agnostic)
|
|
212
270
|
|
|
213
271
|
### OctavusChat
|
|
@@ -215,12 +273,12 @@ interface UserMessageInput {
|
|
|
215
273
|
```typescript
|
|
216
274
|
class OctavusChat {
|
|
217
275
|
constructor(options: OctavusChatOptions);
|
|
218
|
-
|
|
276
|
+
|
|
219
277
|
// State (read-only)
|
|
220
278
|
readonly messages: UIMessage[];
|
|
221
279
|
readonly status: ChatStatus;
|
|
222
280
|
readonly error: Error | null;
|
|
223
|
-
|
|
281
|
+
|
|
224
282
|
// Actions
|
|
225
283
|
send(
|
|
226
284
|
triggerName: string,
|
|
@@ -228,7 +286,7 @@ class OctavusChat {
|
|
|
228
286
|
options?: { userMessage?: UserMessageInput }
|
|
229
287
|
): Promise<void>;
|
|
230
288
|
stop(): void;
|
|
231
|
-
|
|
289
|
+
|
|
232
290
|
// Subscription
|
|
233
291
|
subscribe(callback: () => void): () => void; // Returns unsubscribe function
|
|
234
292
|
}
|
|
@@ -238,4 +296,5 @@ class OctavusChat {
|
|
|
238
296
|
|
|
239
297
|
- [Messages](/docs/client-sdk/messages) — Working with message state
|
|
240
298
|
- [Streaming](/docs/client-sdk/streaming) — Building streaming UIs
|
|
241
|
-
- [
|
|
299
|
+
- [Operations](/docs/client-sdk/execution-blocks) — Showing agent progress
|
|
300
|
+
- [Socket Transport](/docs/client-sdk/socket-transport) — WebSocket and SockJS integration
|
|
@@ -24,10 +24,10 @@ interface UIMessage {
|
|
|
24
24
|
Messages contain ordered `parts` that preserve content ordering:
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
type UIMessagePart =
|
|
28
|
-
| UITextPart
|
|
29
|
-
| UIReasoningPart
|
|
30
|
-
| UIToolCallPart
|
|
27
|
+
type UIMessagePart =
|
|
28
|
+
| UITextPart
|
|
29
|
+
| UIReasoningPart
|
|
30
|
+
| UIToolCallPart
|
|
31
31
|
| UIOperationPart;
|
|
32
32
|
|
|
33
33
|
// Text content
|
|
@@ -73,13 +73,35 @@ interface UIOperationPart {
|
|
|
73
73
|
## Sending Messages
|
|
74
74
|
|
|
75
75
|
```tsx
|
|
76
|
-
|
|
76
|
+
import { useMemo } from 'react';
|
|
77
|
+
import { useOctavusChat, createHttpTransport } from '@octavus/react';
|
|
78
|
+
|
|
79
|
+
function Chat({ sessionId }: { sessionId: string }) {
|
|
80
|
+
const transport = useMemo(
|
|
81
|
+
() =>
|
|
82
|
+
createHttpTransport({
|
|
83
|
+
triggerRequest: (triggerName, input) =>
|
|
84
|
+
fetch('/api/trigger', {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers: { 'Content-Type': 'application/json' },
|
|
87
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
88
|
+
}),
|
|
89
|
+
}),
|
|
90
|
+
[sessionId],
|
|
91
|
+
);
|
|
77
92
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
const { send } = useOctavusChat({ transport });
|
|
94
|
+
|
|
95
|
+
async function handleSend(text: string) {
|
|
96
|
+
// Add user message to UI and trigger agent
|
|
97
|
+
await send(
|
|
98
|
+
'user-message',
|
|
99
|
+
{ USER_MESSAGE: text },
|
|
100
|
+
{ userMessage: { content: text } },
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ...
|
|
83
105
|
}
|
|
84
106
|
```
|
|
85
107
|
|
|
@@ -201,24 +223,54 @@ function PartRenderer({ part }: { part: UIMessagePart }) {
|
|
|
201
223
|
|
|
202
224
|
## Session Restore
|
|
203
225
|
|
|
204
|
-
When restoring a session, pass
|
|
226
|
+
When restoring a session, fetch messages from your backend and pass them to the hook:
|
|
205
227
|
|
|
206
228
|
```tsx
|
|
207
|
-
|
|
208
|
-
|
|
229
|
+
import { useMemo } from 'react';
|
|
230
|
+
import { useOctavusChat, createHttpTransport, type UIMessage } from '@octavus/react';
|
|
209
231
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
initialMessages:
|
|
213
|
-
|
|
214
|
-
|
|
232
|
+
interface ChatProps {
|
|
233
|
+
sessionId: string;
|
|
234
|
+
initialMessages: UIMessage[];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function Chat({ sessionId, initialMessages }: ChatProps) {
|
|
238
|
+
const transport = useMemo(
|
|
239
|
+
() =>
|
|
240
|
+
createHttpTransport({
|
|
241
|
+
triggerRequest: (triggerName, input) =>
|
|
242
|
+
fetch('/api/trigger', {
|
|
243
|
+
method: 'POST',
|
|
244
|
+
headers: { 'Content-Type': 'application/json' },
|
|
245
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
246
|
+
}),
|
|
247
|
+
}),
|
|
248
|
+
[sessionId],
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Pass existing messages to restore the conversation
|
|
252
|
+
const { messages } = useOctavusChat({
|
|
253
|
+
transport,
|
|
254
|
+
initialMessages,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ...
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
On your backend, use `agentSessions.getMessages()` to fetch UI-ready messages:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// Server-side
|
|
265
|
+
const session = await client.agentSessions.getMessages(sessionId);
|
|
266
|
+
// session.messages is UIMessage[] ready for the client
|
|
215
267
|
```
|
|
216
268
|
|
|
217
269
|
## Callbacks
|
|
218
270
|
|
|
219
271
|
```tsx
|
|
220
272
|
useOctavusChat({
|
|
221
|
-
|
|
273
|
+
transport,
|
|
222
274
|
onFinish: () => {
|
|
223
275
|
console.log('Stream completed');
|
|
224
276
|
// Scroll to bottom, play sound, etc.
|
|
@@ -10,7 +10,7 @@ The Client SDK provides real-time access to streaming content through the messag
|
|
|
10
10
|
## Streaming State
|
|
11
11
|
|
|
12
12
|
```tsx
|
|
13
|
-
const { messages, status, error } = useOctavusChat({
|
|
13
|
+
const { messages, status, error } = useOctavusChat({ transport });
|
|
14
14
|
|
|
15
15
|
// status: 'idle' | 'streaming' | 'error'
|
|
16
16
|
// Each message has status: 'streaming' | 'done'
|
|
@@ -20,8 +20,24 @@ const { messages, status, error } = useOctavusChat({...});
|
|
|
20
20
|
## Building a Streaming UI
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
import { useMemo } from 'react';
|
|
24
|
+
import { useOctavusChat, createHttpTransport } from '@octavus/react';
|
|
25
|
+
|
|
26
|
+
function Chat({ sessionId }: { sessionId: string }) {
|
|
27
|
+
const transport = useMemo(
|
|
28
|
+
() =>
|
|
29
|
+
createHttpTransport({
|
|
30
|
+
triggerRequest: (triggerName, input) =>
|
|
31
|
+
fetch('/api/trigger', {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: { 'Content-Type': 'application/json' },
|
|
34
|
+
body: JSON.stringify({ sessionId, triggerName, input }),
|
|
35
|
+
}),
|
|
36
|
+
}),
|
|
37
|
+
[sessionId],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const { messages, status, error, send, stop } = useOctavusChat({ transport });
|
|
25
41
|
|
|
26
42
|
return (
|
|
27
43
|
<div>
|
|
@@ -31,14 +47,10 @@ function Chat() {
|
|
|
31
47
|
))}
|
|
32
48
|
|
|
33
49
|
{/* Error state */}
|
|
34
|
-
{error &&
|
|
35
|
-
<div className="text-red-500">{error.message}</div>
|
|
36
|
-
)}
|
|
50
|
+
{error && <div className="text-red-500">{error.message}</div>}
|
|
37
51
|
|
|
38
52
|
{/* Stop button during streaming */}
|
|
39
|
-
{status === 'streaming' &&
|
|
40
|
-
<button onClick={stop}>Stop</button>
|
|
41
|
-
)}
|
|
53
|
+
{status === 'streaming' && <button onClick={stop}>Stop</button>}
|
|
42
54
|
</div>
|
|
43
55
|
);
|
|
44
56
|
}
|
|
@@ -72,11 +84,9 @@ function ReasoningPart({ part }: { part: UIReasoningPart }) {
|
|
|
72
84
|
{part.status === 'streaming' ? '💭 Thinking...' : '💭 Thought process'}
|
|
73
85
|
{expanded ? '▼' : '▶'}
|
|
74
86
|
</button>
|
|
75
|
-
|
|
87
|
+
|
|
76
88
|
{expanded && (
|
|
77
|
-
<pre className="mt-2 text-sm text-gray-600">
|
|
78
|
-
{part.text}
|
|
79
|
-
</pre>
|
|
89
|
+
<pre className="mt-2 text-sm text-gray-600">{part.text}</pre>
|
|
80
90
|
)}
|
|
81
91
|
</div>
|
|
82
92
|
);
|
|
@@ -95,19 +105,17 @@ function ToolCallPart({ part }: { part: UIToolCallPart }) {
|
|
|
95
105
|
<div className="border rounded p-3">
|
|
96
106
|
<div className="flex items-center gap-2">
|
|
97
107
|
<span className="text-lg">🔧</span>
|
|
98
|
-
<span className="font-medium">
|
|
99
|
-
{part.displayName || part.toolName}
|
|
100
|
-
</span>
|
|
108
|
+
<span className="font-medium">{part.displayName || part.toolName}</span>
|
|
101
109
|
<StatusBadge status={part.status} />
|
|
102
110
|
</div>
|
|
103
|
-
|
|
111
|
+
|
|
104
112
|
{/* Show result when done */}
|
|
105
113
|
{part.status === 'done' && part.result && (
|
|
106
114
|
<pre className="mt-2 text-xs bg-gray-50 p-2 rounded">
|
|
107
115
|
{JSON.stringify(part.result, null, 2)}
|
|
108
116
|
</pre>
|
|
109
117
|
)}
|
|
110
|
-
|
|
118
|
+
|
|
111
119
|
{/* Show error if failed */}
|
|
112
120
|
{part.status === 'error' && (
|
|
113
121
|
<p className="mt-2 text-red-500 text-sm">{part.error}</p>
|
|
@@ -133,9 +141,7 @@ function StatusBadge({ status }: { status: UIToolCallPart['status'] }) {
|
|
|
133
141
|
## Status Indicator
|
|
134
142
|
|
|
135
143
|
```tsx
|
|
136
|
-
function StatusIndicator() {
|
|
137
|
-
const { status } = useOctavusChat({...});
|
|
138
|
-
|
|
144
|
+
function StatusIndicator({ status }: { status: ChatStatus }) {
|
|
139
145
|
switch (status) {
|
|
140
146
|
case 'idle':
|
|
141
147
|
return null;
|
|
@@ -151,7 +157,7 @@ function StatusIndicator() {
|
|
|
151
157
|
|
|
152
158
|
```tsx
|
|
153
159
|
useOctavusChat({
|
|
154
|
-
|
|
160
|
+
transport,
|
|
155
161
|
onFinish: () => {
|
|
156
162
|
console.log('Stream completed');
|
|
157
163
|
// Scroll to bottom, play sound, etc.
|
|
@@ -168,7 +174,7 @@ useOctavusChat({
|
|
|
168
174
|
Stop the current stream and finalize any partial message:
|
|
169
175
|
|
|
170
176
|
```tsx
|
|
171
|
-
const { status, stop } = useOctavusChat({
|
|
177
|
+
const { status, stop } = useOctavusChat({ transport });
|
|
172
178
|
|
|
173
179
|
// Stop button
|
|
174
180
|
{status === 'streaming' && (
|
|
@@ -188,17 +194,19 @@ When `stop()` is called:
|
|
|
188
194
|
Content from named threads (like "summary") streams separately and is identified by the `thread` property:
|
|
189
195
|
|
|
190
196
|
```tsx
|
|
191
|
-
import { isOtherThread } from '@octavus/react';
|
|
197
|
+
import { isOtherThread, type UIMessage } from '@octavus/react';
|
|
192
198
|
|
|
193
199
|
function MessageBubble({ message }: { message: UIMessage }) {
|
|
194
200
|
// Separate main thread from named threads
|
|
195
|
-
const mainParts = message.parts.filter(p => !isOtherThread(p));
|
|
196
|
-
const otherParts = message.parts.filter(p => isOtherThread(p));
|
|
201
|
+
const mainParts = message.parts.filter((p) => !isOtherThread(p));
|
|
202
|
+
const otherParts = message.parts.filter((p) => isOtherThread(p));
|
|
197
203
|
|
|
198
204
|
return (
|
|
199
205
|
<div>
|
|
200
206
|
{/* Main conversation */}
|
|
201
|
-
{mainParts.map((part, i) =>
|
|
207
|
+
{mainParts.map((part, i) => (
|
|
208
|
+
<PartRenderer key={i} part={part} />
|
|
209
|
+
))}
|
|
202
210
|
|
|
203
211
|
{/* Named thread content (e.g., summarization) */}
|
|
204
212
|
{otherParts.length > 0 && (
|
|
@@ -206,7 +214,9 @@ function MessageBubble({ message }: { message: UIMessage }) {
|
|
|
206
214
|
<div className="text-amber-600 font-medium mb-2">
|
|
207
215
|
Background processing
|
|
208
216
|
</div>
|
|
209
|
-
{otherParts.map((part, i) =>
|
|
217
|
+
{otherParts.map((part, i) => (
|
|
218
|
+
<PartRenderer key={i} part={part} />
|
|
219
|
+
))}
|
|
210
220
|
</div>
|
|
211
221
|
)}
|
|
212
222
|
</div>
|