@octavus/client-sdk 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Octavus AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,82 @@
1
+ import { ToolCallInfo, DisplayMode, MessagePart } from '@octavus/core';
2
+ export { ChatMessage, DisplayMode, MessagePart, MessagePartType, StreamEvent, ToolCallInfo } from '@octavus/core';
3
+
4
+ interface ToolCallWithDescription extends ToolCallInfo {
5
+ description?: string;
6
+ display?: DisplayMode;
7
+ }
8
+ interface ExecutionStep {
9
+ id: string;
10
+ name: string;
11
+ type: string;
12
+ display: DisplayMode;
13
+ description?: string;
14
+ outputToChat: boolean;
15
+ summary?: string;
16
+ fullOutput?: string;
17
+ toolCalls?: ToolCallWithDescription[];
18
+ thread?: string;
19
+ }
20
+ interface Message {
21
+ id: string;
22
+ role: 'user' | 'assistant' | 'system';
23
+ content: string;
24
+ toolCalls?: ToolCallWithDescription[];
25
+ executionSteps?: ExecutionStep[];
26
+ /** If false, message is not shown to user (internal directive) */
27
+ visible?: boolean;
28
+ /** Ordered message parts - single source of truth for display */
29
+ parts?: MessagePart[];
30
+ thinking?: string;
31
+ createdAt: Date;
32
+ }
33
+ type BlockStatus = 'pending' | 'running' | 'completed' | 'error';
34
+ interface ExecutionBlock {
35
+ id: string;
36
+ name: string;
37
+ type: string;
38
+ status: BlockStatus;
39
+ display: DisplayMode;
40
+ description?: string;
41
+ /** False for independent blocks */
42
+ outputToChat: boolean;
43
+ thread?: string;
44
+ streamingText: string;
45
+ summary?: string;
46
+ thinking?: string;
47
+ toolCalls: ToolCallWithDescription[];
48
+ startedAt: Date;
49
+ completedAt?: Date;
50
+ }
51
+ type ChatStatus = 'idle' | 'loading' | 'streaming' | 'error';
52
+ type TriggerFunction = (triggerName: string, input?: Record<string, unknown>) => Promise<Response>;
53
+ interface UseOctavusChatOptions {
54
+ onTrigger: TriggerFunction;
55
+ initialMessages?: Message[];
56
+ onMessage?: (message: Message) => void;
57
+ onError?: (error: Error) => void;
58
+ onDone?: () => void;
59
+ onResourceUpdate?: (name: string, value: unknown) => void;
60
+ onBlockStart?: (block: ExecutionBlock) => void;
61
+ onBlockEnd?: (block: ExecutionBlock) => void;
62
+ }
63
+ interface UseOctavusChatReturn {
64
+ messages: Message[];
65
+ status: ChatStatus;
66
+ isLoading: boolean;
67
+ error: Error | null;
68
+ /**
69
+ * Add a user message to the UI state.
70
+ * Does NOT trigger the agent - call triggerAction() after.
71
+ */
72
+ addUserMessage: (content: string) => void;
73
+ triggerAction: (triggerName: string, input?: Record<string, unknown>) => Promise<void>;
74
+ streamingText: string;
75
+ /** Streaming parts in MessagePart format - single source of truth */
76
+ streamingParts: MessagePart[];
77
+ executionBlocks: ExecutionBlock[];
78
+ thinkingText: string;
79
+ }
80
+ declare function useOctavusChat(options: UseOctavusChatOptions): UseOctavusChatReturn;
81
+
82
+ export { type BlockStatus, type ChatStatus, type ExecutionBlock, type ExecutionStep, type Message, type ToolCallWithDescription, type TriggerFunction, type UseOctavusChatOptions, type UseOctavusChatReturn, useOctavusChat };
package/dist/index.js ADDED
@@ -0,0 +1,418 @@
1
+ // src/hooks/use-octavus-chat.ts
2
+ import { useState, useCallback, useRef } from "react";
3
+ import { generateId } from "@octavus/core";
4
+
5
+ // src/stream/reader.ts
6
+ import { safeParseStreamEvent } from "@octavus/core";
7
+ async function* parseSSEStream(response) {
8
+ const reader = response.body?.getReader();
9
+ if (!reader) {
10
+ throw new Error("Response body is not readable");
11
+ }
12
+ const decoder = new TextDecoder();
13
+ let buffer = "";
14
+ try {
15
+ let reading = true;
16
+ while (reading) {
17
+ const { done, value } = await reader.read();
18
+ if (done) {
19
+ reading = false;
20
+ continue;
21
+ }
22
+ buffer += decoder.decode(value, { stream: true });
23
+ const lines = buffer.split("\n");
24
+ buffer = lines.pop() ?? "";
25
+ for (const line of lines) {
26
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
27
+ try {
28
+ const parsed = safeParseStreamEvent(JSON.parse(line.slice(6)));
29
+ if (parsed.success) {
30
+ yield parsed.data;
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+ }
36
+ }
37
+ } finally {
38
+ reader.releaseLock();
39
+ }
40
+ }
41
+
42
+ // src/hooks/use-octavus-chat.ts
43
+ async function parseErrorResponse(response) {
44
+ try {
45
+ const data = await response.json();
46
+ return data.error ?? data.message ?? `Request failed: ${response.status}`;
47
+ } catch {
48
+ return `Request failed: ${response.status}`;
49
+ }
50
+ }
51
+ function findOrCreateTextPart(parts, thread) {
52
+ for (let i = parts.length - 1; i >= 0; i--) {
53
+ const part = parts[i];
54
+ if (!part) continue;
55
+ if (part.type === "text" && part.thread === thread) {
56
+ return { part, index: i };
57
+ }
58
+ if (part.type !== "text") break;
59
+ }
60
+ const newPart = {
61
+ type: "text",
62
+ visible: true,
63
+ content: "",
64
+ thread
65
+ };
66
+ parts.push(newPart);
67
+ return { part: newPart, index: parts.length - 1 };
68
+ }
69
+ function useOctavusChat(options) {
70
+ const {
71
+ onTrigger,
72
+ initialMessages = [],
73
+ onMessage,
74
+ onError,
75
+ onDone,
76
+ onResourceUpdate,
77
+ onBlockStart,
78
+ onBlockEnd
79
+ } = options;
80
+ const [messages, setMessages] = useState(initialMessages);
81
+ const [status, setStatus] = useState("idle");
82
+ const [error, setError] = useState(null);
83
+ const [streamingText, setStreamingText] = useState("");
84
+ const [streamingParts, setStreamingParts] = useState([]);
85
+ const [executionBlocks, setExecutionBlocks] = useState([]);
86
+ const [thinkingText, setThinkingText] = useState("");
87
+ const abortControllerRef = useRef(null);
88
+ const triggerAction = useCallback(
89
+ async (triggerName, input) => {
90
+ abortControllerRef.current?.abort();
91
+ abortControllerRef.current = null;
92
+ const abortController = new AbortController();
93
+ abortControllerRef.current = abortController;
94
+ setStatus("loading");
95
+ setError(null);
96
+ setStreamingText("");
97
+ setStreamingParts([]);
98
+ setExecutionBlocks([]);
99
+ setThinkingText("");
100
+ const blocks = [];
101
+ let activeBlock = null;
102
+ const toolCalls = [];
103
+ let visibleFullText = "";
104
+ let executionThinkingText = "";
105
+ const thinkingStack = [];
106
+ const getCurrentThinking = () => thinkingStack[thinkingStack.length - 1];
107
+ const parts = [];
108
+ try {
109
+ const response = await onTrigger(triggerName, input);
110
+ if (!response.ok) {
111
+ const errorMessage = await parseErrorResponse(response);
112
+ throw new Error(errorMessage);
113
+ }
114
+ setStatus("streaming");
115
+ for await (const event of parseSSEStream(response)) {
116
+ if (abortController.signal.aborted) {
117
+ break;
118
+ }
119
+ switch (event.type) {
120
+ case "block-start": {
121
+ const newBlock = {
122
+ id: event.blockId,
123
+ name: event.blockName,
124
+ type: event.blockType,
125
+ status: "running",
126
+ display: event.display,
127
+ description: event.description,
128
+ outputToChat: event.outputToChat ?? false,
129
+ streamingText: "",
130
+ toolCalls: [],
131
+ startedAt: /* @__PURE__ */ new Date()
132
+ };
133
+ blocks.push(newBlock);
134
+ activeBlock = newBlock;
135
+ setExecutionBlocks([...blocks]);
136
+ onBlockStart?.(newBlock);
137
+ break;
138
+ }
139
+ case "block-end": {
140
+ if (activeBlock && activeBlock.id === event.blockId) {
141
+ activeBlock.status = "completed";
142
+ activeBlock.summary = event.summary;
143
+ activeBlock.completedAt = /* @__PURE__ */ new Date();
144
+ setExecutionBlocks([...blocks]);
145
+ onBlockEnd?.(activeBlock);
146
+ activeBlock = null;
147
+ }
148
+ break;
149
+ }
150
+ case "text-delta":
151
+ if (activeBlock) {
152
+ activeBlock.streamingText += event.content;
153
+ setExecutionBlocks([...blocks]);
154
+ const isNonMainThread = activeBlock.thread !== void 0 && activeBlock.thread !== "main";
155
+ const shouldCaptureText = activeBlock.outputToChat || isNonMainThread;
156
+ if (shouldCaptureText) {
157
+ const { part, index } = findOrCreateTextPart(parts, activeBlock.thread);
158
+ part.content = (part.content ?? "") + event.content;
159
+ parts[index] = { ...part };
160
+ if (activeBlock.outputToChat) {
161
+ visibleFullText += event.content;
162
+ setStreamingText(visibleFullText);
163
+ }
164
+ setStreamingParts([...parts]);
165
+ }
166
+ }
167
+ break;
168
+ case "text-start":
169
+ case "text-end":
170
+ break;
171
+ case "thinking-start": {
172
+ const isNonMainThread = event.thread !== void 0 && event.thread !== "main";
173
+ const shouldCapture = (activeBlock?.outputToChat ?? false) || isNonMainThread;
174
+ const newPart = {
175
+ type: "thinking",
176
+ visible: false,
177
+ content: "",
178
+ thread: event.thread
179
+ };
180
+ parts.push(newPart);
181
+ thinkingStack.push({
182
+ thread: event.thread,
183
+ outputToChat: shouldCapture,
184
+ partIndex: parts.length - 1
185
+ });
186
+ setThinkingText("");
187
+ if (activeBlock && event.thread) {
188
+ activeBlock.thread = event.thread;
189
+ setExecutionBlocks([...blocks]);
190
+ }
191
+ break;
192
+ }
193
+ case "thinking-delta": {
194
+ const ctx = getCurrentThinking();
195
+ const thinkingPart = ctx ? parts[ctx.partIndex] : void 0;
196
+ if (ctx && thinkingPart) {
197
+ thinkingPart.content = (thinkingPart.content ?? "") + event.content;
198
+ parts[ctx.partIndex] = { ...thinkingPart };
199
+ }
200
+ if (activeBlock?.outputToChat) {
201
+ executionThinkingText += event.content;
202
+ }
203
+ setThinkingText((prev) => prev + event.content);
204
+ if (activeBlock) {
205
+ activeBlock.thinking = (activeBlock.thinking ?? "") + event.content;
206
+ if (event.thread && !activeBlock.thread) {
207
+ activeBlock.thread = event.thread;
208
+ }
209
+ setExecutionBlocks([...blocks]);
210
+ }
211
+ if (ctx?.outputToChat) {
212
+ setStreamingParts([...parts]);
213
+ }
214
+ break;
215
+ }
216
+ case "thinking-end": {
217
+ const ctx = thinkingStack.pop();
218
+ setThinkingText("");
219
+ const endThinkingPart = ctx ? parts[ctx.partIndex] : void 0;
220
+ if (ctx && endThinkingPart && !endThinkingPart.content?.trim()) {
221
+ parts.splice(ctx.partIndex, 1);
222
+ }
223
+ if (ctx?.outputToChat) {
224
+ setStreamingParts([...parts]);
225
+ }
226
+ break;
227
+ }
228
+ case "tool-call-start": {
229
+ const newToolCall = {
230
+ id: event.toolCallId,
231
+ name: event.toolName,
232
+ arguments: {},
233
+ status: "in_progress"
234
+ };
235
+ if ("toolDescription" in event && event.toolDescription) {
236
+ newToolCall.description = event.toolDescription;
237
+ }
238
+ if ("toolDisplay" in event && event.toolDisplay) {
239
+ newToolCall.display = event.toolDisplay;
240
+ }
241
+ toolCalls.push(newToolCall);
242
+ if (activeBlock) {
243
+ activeBlock.toolCalls = [...activeBlock.toolCalls, newToolCall];
244
+ setExecutionBlocks([...blocks]);
245
+ }
246
+ const isVisibleBlock = activeBlock?.display !== "hidden";
247
+ if (isVisibleBlock) {
248
+ const toolPart = {
249
+ type: "tool-call",
250
+ visible: newToolCall.display !== "hidden",
251
+ toolCall: newToolCall,
252
+ thread: activeBlock?.thread
253
+ };
254
+ parts.push(toolPart);
255
+ setStreamingParts([...parts]);
256
+ }
257
+ break;
258
+ }
259
+ case "tool-call-args": {
260
+ const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);
261
+ if (toolCall) {
262
+ try {
263
+ toolCall.arguments = JSON.parse(event.argsJson);
264
+ } catch {
265
+ }
266
+ const argsPart = parts.find(
267
+ (p) => p.type === "tool-call" && p.toolCall?.id === event.toolCallId
268
+ );
269
+ if (argsPart?.toolCall) {
270
+ argsPart.toolCall = { ...argsPart.toolCall, arguments: toolCall.arguments };
271
+ setStreamingParts([...parts]);
272
+ }
273
+ if (activeBlock) {
274
+ setExecutionBlocks([...blocks]);
275
+ }
276
+ }
277
+ break;
278
+ }
279
+ case "tool-call-result": {
280
+ const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);
281
+ if (toolCall) {
282
+ toolCall.status = "completed";
283
+ toolCall.result = event.result;
284
+ const resultPart = parts.find(
285
+ (p) => p.type === "tool-call" && p.toolCall?.id === event.toolCallId
286
+ );
287
+ if (resultPart?.toolCall) {
288
+ resultPart.toolCall = {
289
+ ...resultPart.toolCall,
290
+ status: "completed",
291
+ result: event.result
292
+ };
293
+ setStreamingParts([...parts]);
294
+ }
295
+ if (activeBlock) {
296
+ setExecutionBlocks([...blocks]);
297
+ }
298
+ }
299
+ break;
300
+ }
301
+ case "tool-call-error": {
302
+ const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);
303
+ if (toolCall) {
304
+ toolCall.status = "error";
305
+ toolCall.error = event.error;
306
+ const errorPart = parts.find(
307
+ (p) => p.type === "tool-call" && p.toolCall?.id === event.toolCallId
308
+ );
309
+ if (errorPart?.toolCall) {
310
+ errorPart.toolCall = {
311
+ ...errorPart.toolCall,
312
+ status: "error",
313
+ error: event.error
314
+ };
315
+ setStreamingParts([...parts]);
316
+ }
317
+ if (activeBlock) {
318
+ setExecutionBlocks([...blocks]);
319
+ }
320
+ }
321
+ break;
322
+ }
323
+ case "resource-update":
324
+ onResourceUpdate?.(event.name, event.value);
325
+ break;
326
+ case "done": {
327
+ while (thinkingStack.length > 0) {
328
+ const ctx = thinkingStack.pop();
329
+ const remainingPart = ctx ? parts[ctx.partIndex] : void 0;
330
+ if (ctx && remainingPart && !remainingPart.content?.trim()) {
331
+ parts.splice(ctx.partIndex, 1);
332
+ }
333
+ }
334
+ const executionSteps = blocks.filter((b) => b.status === "completed").map((b) => ({
335
+ id: b.id,
336
+ name: b.name,
337
+ type: b.type,
338
+ display: b.display,
339
+ description: b.description,
340
+ outputToChat: b.outputToChat,
341
+ summary: b.summary,
342
+ fullOutput: b.streamingText || void 0,
343
+ toolCalls: b.toolCalls.length > 0 ? b.toolCalls : void 0,
344
+ thread: b.thread
345
+ }));
346
+ if (visibleFullText || executionSteps.length > 0 || executionThinkingText) {
347
+ const assistantMessage = {
348
+ id: generateId(),
349
+ role: "assistant",
350
+ content: visibleFullText,
351
+ toolCalls: toolCalls.filter((tc) => tc.status === "completed"),
352
+ executionSteps: executionSteps.length > 0 ? executionSteps : void 0,
353
+ parts: parts.length > 0 ? parts : void 0,
354
+ thinking: executionThinkingText || void 0,
355
+ createdAt: /* @__PURE__ */ new Date()
356
+ };
357
+ setMessages((prev) => [...prev, assistantMessage]);
358
+ onMessage?.(assistantMessage);
359
+ }
360
+ setStatus("idle");
361
+ setStreamingText("");
362
+ setStreamingParts([]);
363
+ setExecutionBlocks([]);
364
+ setThinkingText("");
365
+ onDone?.();
366
+ break;
367
+ }
368
+ case "error":
369
+ throw new Error(event.message);
370
+ case "tool-request":
371
+ break;
372
+ }
373
+ }
374
+ } catch (err) {
375
+ const errorObj = err instanceof Error ? err : new Error("Unknown error");
376
+ setError(errorObj);
377
+ setStatus("error");
378
+ if (activeBlock) {
379
+ activeBlock.status = "error";
380
+ setExecutionBlocks([...blocks]);
381
+ }
382
+ onError?.(errorObj);
383
+ } finally {
384
+ abortControllerRef.current = null;
385
+ }
386
+ },
387
+ [onTrigger, onMessage, onError, onDone, onResourceUpdate, onBlockStart, onBlockEnd]
388
+ );
389
+ const addUserMessage = useCallback(
390
+ (content) => {
391
+ const userMessage = {
392
+ id: generateId(),
393
+ role: "user",
394
+ content,
395
+ createdAt: /* @__PURE__ */ new Date()
396
+ };
397
+ setMessages((prev) => [...prev, userMessage]);
398
+ onMessage?.(userMessage);
399
+ },
400
+ [onMessage]
401
+ );
402
+ return {
403
+ messages,
404
+ status,
405
+ isLoading: status === "loading" || status === "streaming",
406
+ error,
407
+ addUserMessage,
408
+ triggerAction,
409
+ streamingText,
410
+ streamingParts,
411
+ executionBlocks,
412
+ thinkingText
413
+ };
414
+ }
415
+ export {
416
+ useOctavusChat
417
+ };
418
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-octavus-chat.ts","../src/stream/reader.ts"],"sourcesContent":["'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport { generateId, type ToolCallInfo, type DisplayMode, type MessagePart } from '@octavus/core';\nimport { parseSSEStream } from '@/stream/reader';\n\nexport interface ToolCallWithDescription extends ToolCallInfo {\n description?: string;\n display?: DisplayMode;\n}\n\nexport interface ExecutionStep {\n id: string;\n name: string;\n type: string;\n display: DisplayMode;\n description?: string;\n outputToChat: boolean;\n summary?: string;\n fullOutput?: string;\n toolCalls?: ToolCallWithDescription[];\n thread?: string;\n}\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n toolCalls?: ToolCallWithDescription[];\n executionSteps?: ExecutionStep[];\n /** If false, message is not shown to user (internal directive) */\n visible?: boolean;\n /** Ordered message parts - single source of truth for display */\n parts?: MessagePart[];\n thinking?: string;\n createdAt: Date;\n}\n\nexport type BlockStatus = 'pending' | 'running' | 'completed' | 'error';\n\nexport interface ExecutionBlock {\n id: string;\n name: string;\n type: string;\n status: BlockStatus;\n display: DisplayMode;\n description?: string;\n /** False for independent blocks */\n outputToChat: boolean;\n thread?: string;\n streamingText: string;\n summary?: string;\n thinking?: string;\n toolCalls: ToolCallWithDescription[];\n startedAt: Date;\n completedAt?: Date;\n}\n\nexport type ChatStatus = 'idle' | 'loading' | 'streaming' | 'error';\n\nexport type TriggerFunction = (\n triggerName: string,\n input?: Record<string, unknown>,\n) => Promise<Response>;\n\nexport interface UseOctavusChatOptions {\n onTrigger: TriggerFunction;\n initialMessages?: Message[];\n onMessage?: (message: Message) => void;\n onError?: (error: Error) => void;\n onDone?: () => void;\n onResourceUpdate?: (name: string, value: unknown) => void;\n onBlockStart?: (block: ExecutionBlock) => void;\n onBlockEnd?: (block: ExecutionBlock) => void;\n}\n\nexport interface UseOctavusChatReturn {\n messages: Message[];\n status: ChatStatus;\n isLoading: boolean;\n error: Error | null;\n /**\n * Add a user message to the UI state.\n * Does NOT trigger the agent - call triggerAction() after.\n */\n addUserMessage: (content: string) => void;\n triggerAction: (triggerName: string, input?: Record<string, unknown>) => Promise<void>;\n streamingText: string;\n /** Streaming parts in MessagePart format - single source of truth */\n streamingParts: MessagePart[];\n executionBlocks: ExecutionBlock[];\n thinkingText: string;\n}\n\ninterface ErrorResponse {\n error?: string;\n message?: string;\n}\n\nasync function parseErrorResponse(response: Response): Promise<string> {\n try {\n const data = (await response.json()) as ErrorResponse;\n return data.error ?? data.message ?? `Request failed: ${response.status}`;\n } catch {\n return `Request failed: ${response.status}`;\n }\n}\n\n/**\n * Helper to find or create a text part for the current block\n */\nfunction findOrCreateTextPart(\n parts: MessagePart[],\n thread: string | undefined,\n): { part: MessagePart; index: number } {\n // Look for an existing text part for this thread at the end\n for (let i = parts.length - 1; i >= 0; i--) {\n const part = parts[i];\n if (!part) continue;\n if (part.type === 'text' && part.thread === thread) {\n return { part, index: i };\n }\n // If we hit a different part type, stop looking\n if (part.type !== 'text') break;\n }\n // Create new text part\n const newPart: MessagePart = {\n type: 'text',\n visible: true,\n content: '',\n thread,\n };\n parts.push(newPart);\n return { part: newPart, index: parts.length - 1 };\n}\n\nexport function useOctavusChat(options: UseOctavusChatOptions): UseOctavusChatReturn {\n const {\n onTrigger,\n initialMessages = [],\n onMessage,\n onError,\n onDone,\n onResourceUpdate,\n onBlockStart,\n onBlockEnd,\n } = options;\n\n const [messages, setMessages] = useState<Message[]>(initialMessages);\n const [status, setStatus] = useState<ChatStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [streamingText, setStreamingText] = useState('');\n const [streamingParts, setStreamingParts] = useState<MessagePart[]>([]);\n const [executionBlocks, setExecutionBlocks] = useState<ExecutionBlock[]>([]);\n const [thinkingText, setThinkingText] = useState('');\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const triggerAction = useCallback(\n async (triggerName: string, input?: Record<string, unknown>) => {\n // Abort any previous request\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n setStatus('loading');\n setError(null);\n setStreamingText('');\n setStreamingParts([]);\n setExecutionBlocks([]);\n setThinkingText('');\n\n const blocks: ExecutionBlock[] = [];\n let activeBlock: ExecutionBlock | null = null;\n const toolCalls: ToolCallInfo[] = [];\n\n let visibleFullText = '';\n let executionThinkingText = '';\n\n // Track current thinking context (thread and whether to show)\n interface ThinkingContext {\n thread: string | undefined;\n outputToChat: boolean;\n partIndex: number;\n }\n const thinkingStack: ThinkingContext[] = [];\n const getCurrentThinking = () => thinkingStack[thinkingStack.length - 1];\n\n // Build MessagePart[] directly during streaming\n const parts: MessagePart[] = [];\n\n try {\n const response = await onTrigger(triggerName, input);\n\n if (!response.ok) {\n const errorMessage = await parseErrorResponse(response);\n throw new Error(errorMessage);\n }\n\n setStatus('streaming');\n\n for await (const event of parseSSEStream(response)) {\n if (abortController.signal.aborted) {\n break;\n }\n\n switch (event.type) {\n case 'block-start': {\n const newBlock: ExecutionBlock = {\n id: event.blockId,\n name: event.blockName,\n type: event.blockType,\n status: 'running',\n display: event.display,\n description: event.description,\n outputToChat: event.outputToChat ?? false,\n streamingText: '',\n toolCalls: [],\n startedAt: new Date(),\n };\n blocks.push(newBlock);\n activeBlock = newBlock;\n setExecutionBlocks([...blocks]);\n onBlockStart?.(newBlock);\n break;\n }\n\n case 'block-end': {\n if (activeBlock && activeBlock.id === event.blockId) {\n activeBlock.status = 'completed';\n activeBlock.summary = event.summary;\n activeBlock.completedAt = new Date();\n setExecutionBlocks([...blocks]);\n onBlockEnd?.(activeBlock);\n activeBlock = null;\n }\n break;\n }\n\n case 'text-delta':\n if (activeBlock) {\n activeBlock.streamingText += event.content;\n setExecutionBlocks([...blocks]);\n\n // Capture text if outputToChat OR non-main thread\n const isNonMainThread =\n activeBlock.thread !== undefined && activeBlock.thread !== 'main';\n const shouldCaptureText = activeBlock.outputToChat || isNonMainThread;\n\n if (shouldCaptureText) {\n // Find or create the text part and append content\n const { part, index } = findOrCreateTextPart(parts, activeBlock.thread);\n part.content = (part.content ?? '') + event.content;\n parts[index] = { ...part };\n\n // Update main visible text if outputToChat\n if (activeBlock.outputToChat) {\n visibleFullText += event.content;\n setStreamingText(visibleFullText);\n }\n\n setStreamingParts([...parts]);\n }\n }\n break;\n\n case 'text-start':\n case 'text-end':\n break;\n\n case 'thinking-start': {\n // Non-main threads always capture content (shown as orange cards)\n const isNonMainThread = event.thread !== undefined && event.thread !== 'main';\n const shouldCapture = (activeBlock?.outputToChat ?? false) || isNonMainThread;\n\n // Create new thinking part\n const newPart: MessagePart = {\n type: 'thinking',\n visible: false,\n content: '',\n thread: event.thread,\n };\n parts.push(newPart);\n\n // Push thinking context onto stack\n thinkingStack.push({\n thread: event.thread,\n outputToChat: shouldCapture,\n partIndex: parts.length - 1,\n });\n\n setThinkingText('');\n if (activeBlock && event.thread) {\n activeBlock.thread = event.thread;\n setExecutionBlocks([...blocks]);\n }\n break;\n }\n\n case 'thinking-delta': {\n const ctx = getCurrentThinking();\n const thinkingPart = ctx ? parts[ctx.partIndex] : undefined;\n if (ctx && thinkingPart) {\n thinkingPart.content = (thinkingPart.content ?? '') + event.content;\n parts[ctx.partIndex] = { ...thinkingPart };\n }\n\n if (activeBlock?.outputToChat) {\n executionThinkingText += event.content;\n }\n setThinkingText((prev) => prev + event.content);\n\n if (activeBlock) {\n activeBlock.thinking = (activeBlock.thinking ?? '') + event.content;\n if (event.thread && !activeBlock.thread) {\n activeBlock.thread = event.thread;\n }\n setExecutionBlocks([...blocks]);\n }\n\n // Update streaming parts if should capture\n if (ctx?.outputToChat) {\n setStreamingParts([...parts]);\n }\n break;\n }\n\n case 'thinking-end': {\n // Pop the thinking context from stack\n const ctx = thinkingStack.pop();\n setThinkingText('');\n\n // If the thinking part is empty, remove it\n const endThinkingPart = ctx ? parts[ctx.partIndex] : undefined;\n if (ctx && endThinkingPart && !endThinkingPart.content?.trim()) {\n parts.splice(ctx.partIndex, 1);\n }\n\n // Update streaming parts\n if (ctx?.outputToChat) {\n setStreamingParts([...parts]);\n }\n break;\n }\n\n case 'tool-call-start': {\n const newToolCall: ToolCallWithDescription = {\n id: event.toolCallId,\n name: event.toolName,\n arguments: {},\n status: 'in_progress',\n };\n if ('toolDescription' in event && event.toolDescription) {\n newToolCall.description = event.toolDescription;\n }\n if ('toolDisplay' in event && event.toolDisplay) {\n newToolCall.display = event.toolDisplay;\n }\n toolCalls.push(newToolCall);\n\n if (activeBlock) {\n activeBlock.toolCalls = [...activeBlock.toolCalls, newToolCall];\n setExecutionBlocks([...blocks]);\n }\n\n // Add tool call part (visible unless hidden)\n const isVisibleBlock = activeBlock?.display !== 'hidden';\n if (isVisibleBlock) {\n const toolPart: MessagePart = {\n type: 'tool-call',\n visible: newToolCall.display !== 'hidden',\n toolCall: newToolCall,\n thread: activeBlock?.thread,\n };\n parts.push(toolPart);\n setStreamingParts([...parts]);\n }\n break;\n }\n\n case 'tool-call-args': {\n const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);\n if (toolCall) {\n try {\n toolCall.arguments = JSON.parse(event.argsJson) as Record<string, unknown>;\n } catch {\n // Ignore parse errors for partial args\n }\n\n // Update the tool call in parts\n const argsPart = parts.find(\n (p) => p.type === 'tool-call' && p.toolCall?.id === event.toolCallId,\n );\n if (argsPart?.toolCall) {\n argsPart.toolCall = { ...argsPart.toolCall, arguments: toolCall.arguments };\n setStreamingParts([...parts]);\n }\n\n if (activeBlock) {\n setExecutionBlocks([...blocks]);\n }\n }\n break;\n }\n\n case 'tool-call-result': {\n const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);\n if (toolCall) {\n toolCall.status = 'completed';\n toolCall.result = event.result;\n\n // Update the tool call in parts\n const resultPart = parts.find(\n (p) => p.type === 'tool-call' && p.toolCall?.id === event.toolCallId,\n );\n if (resultPart?.toolCall) {\n resultPart.toolCall = {\n ...resultPart.toolCall,\n status: 'completed',\n result: event.result,\n };\n setStreamingParts([...parts]);\n }\n\n if (activeBlock) {\n setExecutionBlocks([...blocks]);\n }\n }\n break;\n }\n\n case 'tool-call-error': {\n const toolCall = toolCalls.find((tc) => tc.id === event.toolCallId);\n if (toolCall) {\n toolCall.status = 'error';\n toolCall.error = event.error;\n\n // Update the tool call in parts\n const errorPart = parts.find(\n (p) => p.type === 'tool-call' && p.toolCall?.id === event.toolCallId,\n );\n if (errorPart?.toolCall) {\n errorPart.toolCall = {\n ...errorPart.toolCall,\n status: 'error',\n error: event.error,\n };\n setStreamingParts([...parts]);\n }\n\n if (activeBlock) {\n setExecutionBlocks([...blocks]);\n }\n }\n break;\n }\n\n case 'resource-update':\n onResourceUpdate?.(event.name, event.value);\n break;\n\n case 'done': {\n // Finalize any remaining thinking contexts\n while (thinkingStack.length > 0) {\n const ctx = thinkingStack.pop();\n const remainingPart = ctx ? parts[ctx.partIndex] : undefined;\n if (ctx && remainingPart && !remainingPart.content?.trim()) {\n parts.splice(ctx.partIndex, 1);\n }\n }\n\n // Build execution steps\n const executionSteps: ExecutionStep[] = blocks\n .filter((b) => b.status === 'completed')\n .map((b) => ({\n id: b.id,\n name: b.name,\n type: b.type,\n display: b.display,\n description: b.description,\n outputToChat: b.outputToChat,\n summary: b.summary,\n fullOutput: b.streamingText || undefined,\n toolCalls: b.toolCalls.length > 0 ? b.toolCalls : undefined,\n thread: b.thread,\n }));\n\n // Create assistant message if we have any content\n if (visibleFullText || executionSteps.length > 0 || executionThinkingText) {\n const assistantMessage: Message = {\n id: generateId(),\n role: 'assistant',\n content: visibleFullText,\n toolCalls: toolCalls.filter((tc) => tc.status === 'completed'),\n executionSteps: executionSteps.length > 0 ? executionSteps : undefined,\n parts: parts.length > 0 ? parts : undefined,\n thinking: executionThinkingText || undefined,\n createdAt: new Date(),\n };\n setMessages((prev) => [...prev, assistantMessage]);\n onMessage?.(assistantMessage);\n }\n setStatus('idle');\n setStreamingText('');\n setStreamingParts([]);\n setExecutionBlocks([]);\n setThinkingText('');\n onDone?.();\n break;\n }\n\n case 'error':\n throw new Error(event.message);\n\n case 'tool-request':\n // Handled by server-sdk, should not reach client\n break;\n }\n }\n } catch (err) {\n const errorObj = err instanceof Error ? err : new Error('Unknown error');\n setError(errorObj);\n setStatus('error');\n\n if (activeBlock) {\n activeBlock.status = 'error';\n setExecutionBlocks([...blocks]);\n }\n\n onError?.(errorObj);\n } finally {\n abortControllerRef.current = null;\n }\n },\n [onTrigger, onMessage, onError, onDone, onResourceUpdate, onBlockStart, onBlockEnd],\n );\n\n const addUserMessage = useCallback(\n (content: string) => {\n const userMessage: Message = {\n id: generateId(),\n role: 'user',\n content,\n createdAt: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n onMessage?.(userMessage);\n },\n [onMessage],\n );\n\n return {\n messages,\n status,\n isLoading: status === 'loading' || status === 'streaming',\n error,\n addUserMessage,\n triggerAction,\n streamingText,\n streamingParts,\n executionBlocks,\n thinkingText,\n };\n}\n","import { safeParseStreamEvent, type StreamEvent } from '@octavus/core';\n\n/**\n * Parse SSE stream events\n */\nexport async function* parseSSEStream(\n response: Response,\n): AsyncGenerator<StreamEvent, void, unknown> {\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body is not readable');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n let reading = true;\n while (reading) {\n const { done, value } = await reader.read();\n\n if (done) {\n reading = false;\n continue;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const parsed = safeParseStreamEvent(JSON.parse(line.slice(6)));\n if (parsed.success) {\n yield parsed.data;\n }\n // Skip malformed events silently\n } catch {\n // Skip malformed JSON - no logging in production\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@octavus/client-sdk",
3
+ "version": "0.0.1",
4
+ "description": "Client SDK for streaming Octavus agent responses",
5
+ "license": "MIT",
6
+ "author": "Octavus AI <hello@octavus.ai>",
7
+ "homepage": "https://octavus.dev",
8
+ "keywords": [
9
+ "octavus",
10
+ "ai",
11
+ "agents",
12
+ "sdk",
13
+ "react",
14
+ "streaming"
15
+ ],
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "@octavus/core": "^0.0.1"
34
+ },
35
+ "peerDependencies": {
36
+ "react": ">=18.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^19.0.0",
40
+ "react": "^19.0.0",
41
+ "tsup": "^8.3.5",
42
+ "typescript": "^5.6.3"
43
+ },
44
+ "scripts": {
45
+ "build": "tsup",
46
+ "dev": "tsup --watch",
47
+ "lint": "eslint src/ --max-warnings 0",
48
+ "lint:fix": "eslint src/ --max-warnings 0 --fix",
49
+ "type-check": "tsc --noEmit",
50
+ "clean": "rm -rf dist .turbo"
51
+ }
52
+ }