@octavus/client-sdk 0.2.0 → 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 ADDED
@@ -0,0 +1,196 @@
1
+ # @octavus/client-sdk
2
+
3
+ Framework-agnostic client SDK for Octavus agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @octavus/client-sdk
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ This package provides a framework-agnostic client for streaming Octavus agent responses. It handles message state management, streaming events, and transport abstraction.
14
+
15
+ For React applications, use [`@octavus/react`](https://www.npmjs.com/package/@octavus/react) instead—it provides React hooks that wrap this SDK.
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { OctavusChat, createHttpTransport } from '@octavus/client-sdk';
21
+
22
+ // Create transport
23
+ const transport = createHttpTransport({
24
+ triggerRequest: (triggerName, input, options) =>
25
+ fetch('/api/octavus', {
26
+ method: 'POST',
27
+ headers: { 'Content-Type': 'application/json' },
28
+ body: JSON.stringify({ sessionId, triggerName, input }),
29
+ signal: options?.signal,
30
+ }),
31
+ });
32
+
33
+ // Create chat client
34
+ const chat = new OctavusChat({ transport });
35
+
36
+ // Subscribe to state changes
37
+ const unsubscribe = chat.subscribe(() => {
38
+ console.log('Messages:', chat.messages);
39
+ console.log('Status:', chat.status);
40
+ });
41
+
42
+ // Send a message
43
+ await chat.send('user-message', { USER_MESSAGE: 'Hello!' }, { userMessage: { content: 'Hello!' } });
44
+
45
+ // Cleanup
46
+ unsubscribe();
47
+ ```
48
+
49
+ ## Transports
50
+
51
+ ### HTTP Transport (SSE)
52
+
53
+ Best for Next.js, Express, and HTTP-based applications:
54
+
55
+ ```typescript
56
+ import { createHttpTransport } from '@octavus/client-sdk';
57
+
58
+ const transport = createHttpTransport({
59
+ triggerRequest: (triggerName, input, options) =>
60
+ fetch('/api/octavus', {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({ sessionId, triggerName, input }),
64
+ signal: options?.signal,
65
+ }),
66
+ });
67
+ ```
68
+
69
+ ### Socket Transport (WebSocket/SockJS)
70
+
71
+ Best for real-time applications with persistent connections:
72
+
73
+ ```typescript
74
+ import { createSocketTransport } from '@octavus/client-sdk';
75
+
76
+ const transport = createSocketTransport({
77
+ connect: () =>
78
+ new Promise((resolve, reject) => {
79
+ const ws = new WebSocket(`wss://api.example.com/stream?sessionId=${sessionId}`);
80
+ ws.onopen = () => resolve(ws);
81
+ ws.onerror = () => reject(new Error('Connection failed'));
82
+ }),
83
+ });
84
+
85
+ // Optional: eagerly connect and monitor state
86
+ transport.onConnectionStateChange((state, error) => {
87
+ console.log('Connection state:', state);
88
+ });
89
+ await transport.connect();
90
+ ```
91
+
92
+ ## Chat Client
93
+
94
+ ### Creating a Chat Instance
95
+
96
+ ```typescript
97
+ const chat = new OctavusChat({
98
+ transport,
99
+ initialMessages: [], // Optional: restore from server
100
+ onError: (error) => console.error(error),
101
+ onFinish: () => console.log('Done'),
102
+ onResourceUpdate: (name, value) => console.log(`Resource ${name}:`, value),
103
+ });
104
+ ```
105
+
106
+ ### Sending Messages
107
+
108
+ ```typescript
109
+ // Text message
110
+ await chat.send('user-message', { USER_MESSAGE: message }, { userMessage: { content: message } });
111
+
112
+ // With file attachments
113
+ await chat.send(
114
+ 'user-message',
115
+ { USER_MESSAGE: message, FILES: fileRefs },
116
+ { userMessage: { content: message, files: fileRefs } },
117
+ );
118
+ ```
119
+
120
+ ### State Properties
121
+
122
+ ```typescript
123
+ chat.messages; // UIMessage[] - all messages
124
+ chat.status; // 'idle' | 'streaming' | 'error'
125
+ chat.error; // OctavusError | null
126
+ ```
127
+
128
+ ### Stopping Generation
129
+
130
+ ```typescript
131
+ chat.stop(); // Stops streaming and finalizes partial content
132
+ ```
133
+
134
+ ## File Uploads
135
+
136
+ ```typescript
137
+ // Upload files separately (for progress tracking)
138
+ const fileRefs = await chat.uploadFiles(fileInput.files, (index, progress) => {
139
+ console.log(`File ${index}: ${progress}%`);
140
+ });
141
+
142
+ // Use the references in a message
143
+ await chat.send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });
144
+ ```
145
+
146
+ Note: File uploads require configuring `requestUploadUrls` in the chat options.
147
+
148
+ ## Message Types
149
+
150
+ Messages contain ordered `parts` with typed content:
151
+
152
+ ```typescript
153
+ type UIMessagePart =
154
+ | UITextPart // Text content with streaming status
155
+ | UIReasoningPart // Model reasoning/thinking content
156
+ | UIToolCallPart // Tool call with args, result, and status
157
+ | UIOperationPart // Internal operations (e.g., set-resource)
158
+ | UISourcePart // URL or document sources
159
+ | UIFilePart // File attachments (uploaded or generated)
160
+ | UIObjectPart; // Structured output objects
161
+ ```
162
+
163
+ Each part includes a `type` discriminator and relevant fields. See TypeScript types for full field definitions.
164
+
165
+ ## Error Handling
166
+
167
+ Errors are structured with type classification:
168
+
169
+ ```typescript
170
+ import { isRateLimitError, isAuthenticationError } from '@octavus/client-sdk';
171
+
172
+ const chat = new OctavusChat({
173
+ transport,
174
+ onError: (error) => {
175
+ if (isRateLimitError(error)) {
176
+ showRetryButton(error.retryAfter);
177
+ } else if (isAuthenticationError(error)) {
178
+ redirectToLogin();
179
+ }
180
+ },
181
+ });
182
+ ```
183
+
184
+ ## Re-exports
185
+
186
+ This package re-exports everything from `@octavus/core`, so you don't need to install it separately.
187
+
188
+ ## Related Packages
189
+
190
+ - [`@octavus/react`](https://www.npmjs.com/package/@octavus/react) - React hooks and bindings
191
+ - [`@octavus/server-sdk`](https://www.npmjs.com/package/@octavus/server-sdk) - Server-side SDK
192
+ - [`@octavus/core`](https://www.npmjs.com/package/@octavus/core) - Shared types
193
+
194
+ ## License
195
+
196
+ MIT
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { StreamEvent, FileReference, UIMessage } from '@octavus/core';
1
+ import { StreamEvent, FileReference, UIMessage, OctavusError } from '@octavus/core';
2
2
  export * from '@octavus/core';
3
- export { isFileReference, isFileReferenceArray, isOtherThread } from '@octavus/core';
4
3
 
5
4
  /**
6
5
  * Transport interface for delivering events from server to client.
@@ -236,8 +235,28 @@ interface OctavusChatOptions {
236
235
  requestUploadUrls?: UploadFilesOptions['requestUploadUrls'];
237
236
  /** Initial messages (for session refresh) */
238
237
  initialMessages?: UIMessage[];
239
- /** Callback when an error occurs */
240
- onError?: (error: Error) => void;
238
+ /**
239
+ * Callback when an error occurs.
240
+ * Receives an OctavusError with structured error information.
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * onError: (error) => {
245
+ * console.error('Chat error:', {
246
+ * type: error.errorType,
247
+ * message: error.message,
248
+ * retryable: error.retryable,
249
+ * provider: error.provider,
250
+ * });
251
+ *
252
+ * // Handle specific error types
253
+ * if (isRateLimitError(error)) {
254
+ * showRetryButton(error.retryAfter);
255
+ * }
256
+ * }
257
+ * ```
258
+ */
259
+ onError?: (error: OctavusError) => void;
241
260
  /** Callback when streaming finishes successfully */
242
261
  onFinish?: () => void;
243
262
  /** Callback when streaming is stopped by user */
@@ -291,7 +310,11 @@ declare class OctavusChat {
291
310
  constructor(options: OctavusChatOptions);
292
311
  get messages(): UIMessage[];
293
312
  get status(): ChatStatus;
294
- get error(): Error | null;
313
+ /**
314
+ * The current error, if any.
315
+ * Contains structured error information including type, source, and retryability.
316
+ */
317
+ get error(): OctavusError | null;
295
318
  /**
296
319
  * Subscribe to state changes. The callback is called whenever messages, status, or error changes.
297
320
  * @returns Unsubscribe function
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  generateId,
4
4
  threadForPart,
5
- isFileReferenceArray
5
+ isFileReferenceArray,
6
+ OctavusError
6
7
  } from "@octavus/core";
7
8
 
8
9
  // src/files.ts
@@ -196,6 +197,10 @@ var OctavusChat = class {
196
197
  get status() {
197
198
  return this._status;
198
199
  }
200
+ /**
201
+ * The current error, if any.
202
+ * Contains structured error information including type, source, and retryability.
203
+ */
199
204
  get error() {
200
205
  return this._error;
201
206
  }
@@ -295,7 +300,13 @@ var OctavusChat = class {
295
300
  this.handleStreamEvent(event, this.streamingState);
296
301
  }
297
302
  } catch (err) {
298
- const errorObj = err instanceof Error ? err : new Error("Unknown error");
303
+ const errorObj = OctavusError.isInstance(err) ? err : new OctavusError({
304
+ errorType: "internal_error",
305
+ message: err instanceof Error ? err.message : "Unknown error",
306
+ source: "client",
307
+ retryable: false,
308
+ cause: err
309
+ });
299
310
  this.setError(errorObj);
300
311
  this.setStatus("error");
301
312
  this.streamingState = null;
@@ -372,7 +383,7 @@ var OctavusChat = class {
372
383
  };
373
384
  const messages = [...this._messages];
374
385
  const lastMsg = messages[messages.length - 1];
375
- if (lastMsg && lastMsg.id === state.messageId) {
386
+ if (lastMsg?.id === state.messageId) {
376
387
  messages[messages.length - 1] = finalMessage;
377
388
  } else {
378
389
  messages.push(finalMessage);
@@ -615,7 +626,7 @@ var OctavusChat = class {
615
626
  );
616
627
  if (toolPartIndex >= 0) {
617
628
  const part = state.parts[toolPartIndex];
618
- part.error = event.errorText;
629
+ part.error = event.error;
619
630
  part.status = "error";
620
631
  state.parts[toolPartIndex] = { ...part };
621
632
  this.updateStreamingMessage();
@@ -681,7 +692,7 @@ var OctavusChat = class {
681
692
  if (finalMessage.parts.length > 0) {
682
693
  const messages = [...this._messages];
683
694
  const lastMsg = messages[messages.length - 1];
684
- if (lastMsg && lastMsg.id === state.messageId) {
695
+ if (lastMsg?.id === state.messageId) {
685
696
  messages[messages.length - 1] = finalMessage;
686
697
  } else {
687
698
  messages.push(finalMessage);
@@ -693,8 +704,18 @@ var OctavusChat = class {
693
704
  this.options.onFinish?.();
694
705
  break;
695
706
  }
696
- case "error":
697
- throw new Error(event.errorText);
707
+ case "error": {
708
+ throw new OctavusError({
709
+ errorType: event.errorType,
710
+ message: event.message,
711
+ source: event.source,
712
+ retryable: event.retryable,
713
+ retryAfter: event.retryAfter,
714
+ code: event.code,
715
+ provider: event.provider,
716
+ tool: event.tool
717
+ });
718
+ }
698
719
  case "tool-request":
699
720
  break;
700
721
  }
@@ -705,7 +726,7 @@ var OctavusChat = class {
705
726
  const msg = buildMessageFromState(state, "streaming");
706
727
  const messages = [...this._messages];
707
728
  const lastMsg = messages[messages.length - 1];
708
- if (lastMsg && lastMsg.id === state.messageId) {
729
+ if (lastMsg?.id === state.messageId) {
709
730
  messages[messages.length - 1] = msg;
710
731
  } else {
711
732
  messages.push(msg);
@@ -763,9 +784,6 @@ async function* parseSSEStream(response, signal) {
763
784
  }
764
785
  }
765
786
 
766
- // src/index.ts
767
- import { isOtherThread, isFileReference, isFileReferenceArray as isFileReferenceArray2 } from "@octavus/core";
768
-
769
787
  // src/transports/types.ts
770
788
  function isSocketTransport(transport) {
771
789
  return "connect" in transport && "disconnect" in transport && "connectionState" in transport && "onConnectionStateChange" in transport;
@@ -959,13 +977,13 @@ function createSocketTransport(options) {
959
977
  }
960
978
  };
961
979
  }
980
+
981
+ // src/index.ts
982
+ export * from "@octavus/core";
962
983
  export {
963
984
  OctavusChat,
964
985
  createHttpTransport,
965
986
  createSocketTransport,
966
- isFileReference,
967
- isFileReferenceArray2 as isFileReferenceArray,
968
- isOtherThread,
969
987
  isSocketTransport,
970
988
  parseSSEStream,
971
989
  uploadFiles
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chat.ts","../src/files.ts","../src/stream/reader.ts","../src/index.ts","../src/transports/types.ts","../src/transports/http.ts","../src/transports/socket.ts"],"sourcesContent":["import {\n generateId,\n threadForPart,\n isFileReferenceArray,\n type UIMessage,\n type UIMessagePart,\n type UITextPart,\n type UIReasoningPart,\n type UIToolCallPart,\n type UIOperationPart,\n type UISourcePart,\n type UIFilePart,\n type UIObjectPart,\n type DisplayMode,\n type StreamEvent,\n type FileReference,\n} from '@octavus/core';\nimport type { Transport } from './transports/types';\nimport { uploadFiles, type UploadFilesOptions } from './files';\n\n/** Block types that are internal operations (not LLM-driven) */\nconst OPERATION_BLOCK_TYPES = new Set(['set-resource', 'serialize-thread', 'generate-image']);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ChatStatus = 'idle' | 'streaming' | 'error';\n\n/**\n * Input for creating a user message.\n * Supports text content, structured object content, and file attachments.\n */\nexport interface UserMessageInput {\n /**\n * Content of the message. Can be:\n * - string: Creates a text part\n * - object: Creates an object part (uses `type` field as typeName if present)\n */\n content?: string | Record<string, unknown>;\n /**\n * File attachments (shorthand). Can be:\n * - FileList: From file input element (will be uploaded via uploadFiles)\n * - File[]: Array of File objects (will be uploaded via uploadFiles)\n * - FileReference[]: Already uploaded files (used directly)\n */\n files?: FileList | File[] | FileReference[];\n}\n\nexport interface OctavusChatOptions {\n /**\n * Transport for streaming events.\n * Use `createHttpTransport` for HTTP/SSE or `createSocketTransport` for WebSocket/SockJS.\n */\n transport: Transport;\n\n /**\n * Function to request upload URLs from the platform.\n * Required if you want to use file uploads with FileList/File[].\n *\n * @example\n * ```typescript\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * }\n * ```\n */\n requestUploadUrls?: UploadFilesOptions['requestUploadUrls'];\n\n /** Initial messages (for session refresh) */\n initialMessages?: UIMessage[];\n /** Callback when an error occurs */\n onError?: (error: Error) => void;\n /** Callback when streaming finishes successfully */\n onFinish?: () => void;\n /** Callback when streaming is stopped by user */\n onStop?: () => void;\n /** Callback when a resource is updated */\n onResourceUpdate?: (name: string, value: unknown) => void;\n}\n\n// =============================================================================\n// Internal Types\n// =============================================================================\n\ninterface BlockState {\n blockId: string;\n blockName: string;\n blockType: string;\n display: DisplayMode;\n description?: string;\n outputToChat: boolean;\n thread?: string;\n reasoning: string;\n text: string;\n toolCalls: Map<string, UIToolCallPart>;\n}\n\ninterface StreamingState {\n messageId: string;\n parts: UIMessagePart[];\n activeBlock: BlockState | null;\n blocks: Map<string, BlockState>;\n currentTextPartIndex: number | null;\n currentReasoningPartIndex: number | null;\n currentObjectPartIndex: number | null;\n accumulatedJson: string;\n}\n\ntype Listener = () => void;\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Create a user message from input with optional file attachments.\n * Parts order: files first (for vision models), then content (text or object).\n */\nfunction createUserMessage(input: UserMessageInput, files?: FileReference[]): UIMessage {\n const parts: UIMessagePart[] = [];\n\n // Add file parts first (vision models expect images before text)\n if (files && files.length > 0) {\n for (const file of files) {\n parts.push({\n type: 'file',\n id: file.id,\n mediaType: file.mediaType,\n url: file.url,\n filename: file.filename,\n size: file.size,\n });\n }\n }\n\n // Add content part after files\n if (input.content !== undefined) {\n if (typeof input.content === 'string') {\n // String content → text part\n parts.push({ type: 'text', text: input.content, status: 'done' });\n } else {\n // Object content → object part\n // Use the object's `type` field as typeName if present, otherwise fallback to 'object'\n const typeName = (input.content as { type?: string }).type ?? 'object';\n parts.push({\n type: 'object',\n id: generateId(),\n typeName,\n object: input.content,\n status: 'done',\n });\n }\n }\n\n return {\n id: generateId(),\n role: 'user',\n parts,\n status: 'done',\n createdAt: new Date(),\n };\n}\n\n/**\n * Parse partial JSON by fixing incomplete structures (unclosed strings, brackets, braces).\n */\nfunction parsePartialJson(jsonText: string): unknown {\n if (!jsonText.trim()) {\n return undefined;\n }\n\n try {\n return JSON.parse(jsonText) as unknown;\n } catch {\n // Continue to fix incomplete JSON\n }\n\n let fixed = jsonText;\n\n // Count unclosed brackets/braces while tracking string boundaries\n let openBraces = 0;\n let openBrackets = 0;\n let inString = false;\n let escaped = false;\n\n for (const char of fixed) {\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (char === '\\\\') {\n escaped = true;\n continue;\n }\n\n if (char === '\"') {\n inString = !inString;\n continue;\n }\n\n if (!inString) {\n if (char === '{') openBraces += 1;\n else if (char === '}') openBraces -= 1;\n else if (char === '[') openBrackets += 1;\n else if (char === ']') openBrackets -= 1;\n }\n }\n\n // Close unclosed structures\n if (inString) {\n fixed += '\"';\n }\n while (openBrackets > 0) {\n fixed += ']';\n openBrackets -= 1;\n }\n while (openBraces > 0) {\n fixed += '}';\n openBraces -= 1;\n }\n\n try {\n return JSON.parse(fixed) as unknown;\n } catch {\n return undefined;\n }\n}\n\nfunction createEmptyStreamingState(): StreamingState {\n return {\n messageId: generateId(),\n parts: [],\n activeBlock: null,\n blocks: new Map(),\n currentTextPartIndex: null,\n currentReasoningPartIndex: null,\n currentObjectPartIndex: null,\n accumulatedJson: '',\n };\n}\n\nfunction buildMessageFromState(state: StreamingState, status: 'streaming' | 'done'): UIMessage {\n return {\n id: state.messageId,\n role: 'assistant',\n parts: [...state.parts],\n status,\n createdAt: new Date(),\n };\n}\n\n// =============================================================================\n// OctavusChat Class\n// =============================================================================\n\n/**\n * Framework-agnostic chat client for Octavus agents.\n * Manages chat state and streaming, allowing reactive frameworks to subscribe to updates.\n *\n * @example HTTP transport (Next.js, etc.)\n * ```typescript\n * import { OctavusChat, createHttpTransport } from '@octavus/client-sdk';\n *\n * const chat = new OctavusChat({\n * transport: createHttpTransport({\n * triggerRequest: (triggerName, input) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * }),\n * }),\n * });\n * ```\n *\n * @example Socket transport (WebSocket, SockJS, Meteor)\n * ```typescript\n * import { OctavusChat, createSocketTransport } from '@octavus/client-sdk';\n *\n * const chat = new OctavusChat({\n * transport: createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket(`wss://api.octavus.ai/stream?sessionId=${sessionId}`);\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * }),\n * }),\n * });\n * ```\n */\nexport class OctavusChat {\n // Private state\n private _messages: UIMessage[];\n private _status: ChatStatus = 'idle';\n private _error: Error | null = null;\n private options: OctavusChatOptions;\n private transport: Transport;\n private streamingState: StreamingState | null = null;\n\n // Listener sets for reactive frameworks\n private listeners = new Set<Listener>();\n\n constructor(options: OctavusChatOptions) {\n this.options = options;\n this._messages = options.initialMessages ?? [];\n this.transport = options.transport;\n }\n\n // =========================================================================\n // Public Getters\n // =========================================================================\n\n get messages(): UIMessage[] {\n return this._messages;\n }\n\n get status(): ChatStatus {\n return this._status;\n }\n\n get error(): Error | null {\n return this._error;\n }\n\n // =========================================================================\n // Subscription Methods (for reactive frameworks)\n // =========================================================================\n\n /**\n * Subscribe to state changes. The callback is called whenever messages, status, or error changes.\n * @returns Unsubscribe function\n */\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notifyListeners(): void {\n this.listeners.forEach((l) => l());\n }\n\n // =========================================================================\n // Private Setters (notify listeners)\n // =========================================================================\n\n private setMessages(messages: UIMessage[]): void {\n this._messages = messages;\n this.notifyListeners();\n }\n\n private setStatus(status: ChatStatus): void {\n this._status = status;\n this.notifyListeners();\n }\n\n private setError(error: Error | null): void {\n this._error = error;\n this.notifyListeners();\n }\n\n // =========================================================================\n // Public Methods\n // =========================================================================\n\n /**\n * Trigger the agent and optionally add a user message to the chat.\n *\n * @param triggerName - The trigger name defined in the agent's protocol.yaml\n * @param input - Input parameters for the trigger (variable substitutions)\n * @param options.userMessage - If provided, adds a user message to the chat before triggering\n *\n * @example Send a text message\n * ```typescript\n * await chat.send('user-message',\n * { USER_MESSAGE: message },\n * { userMessage: { content: message } }\n * );\n * ```\n *\n * @example Send a message with file attachments\n * ```typescript\n * await chat.send('user-message',\n * { USER_MESSAGE: message, FILES: fileRefs },\n * { userMessage: { content: message, files: fileRefs } }\n * );\n * ```\n */\n async send(\n triggerName: string,\n input?: Record<string, unknown>,\n sendOptions?: { userMessage?: UserMessageInput },\n ): Promise<void> {\n this.transport.stop();\n\n let fileRefs: FileReference[] | undefined;\n if (sendOptions?.userMessage?.files) {\n const files = sendOptions.userMessage.files;\n if (isFileReferenceArray(files)) {\n fileRefs = files;\n } else if (this.options.requestUploadUrls) {\n fileRefs = await uploadFiles(files, {\n requestUploadUrls: this.options.requestUploadUrls,\n });\n } else {\n throw new Error(\n 'File upload requires requestUploadUrls option. Either provide FileReference[] or configure requestUploadUrls.',\n );\n }\n }\n\n // Auto-upload FILES in trigger input if needed\n let processedInput = input;\n if (input?.FILES !== undefined && !isFileReferenceArray(input.FILES)) {\n if (this.options.requestUploadUrls) {\n const inputFiles = input.FILES as FileList | File[];\n const uploadedRefs =\n fileRefs ??\n (await uploadFiles(inputFiles, {\n requestUploadUrls: this.options.requestUploadUrls,\n }));\n processedInput = { ...input, FILES: uploadedRefs };\n fileRefs = fileRefs ?? uploadedRefs;\n }\n }\n\n // Optimistic UI: add user message before server responds\n if (sendOptions?.userMessage !== undefined) {\n const userMsg = createUserMessage(sendOptions.userMessage, fileRefs);\n this.setMessages([...this._messages, userMsg]);\n }\n\n this.setStatus('streaming');\n this.setError(null);\n this.streamingState = createEmptyStreamingState();\n\n try {\n for await (const event of this.transport.trigger(triggerName, processedInput)) {\n if (this.streamingState === null) break;\n\n this.handleStreamEvent(event, this.streamingState);\n }\n } catch (err) {\n const errorObj = err instanceof Error ? err : new Error('Unknown error');\n this.setError(errorObj);\n this.setStatus('error');\n this.streamingState = null;\n this.options.onError?.(errorObj);\n }\n }\n\n /**\n * Upload files directly without sending a message.\n * Useful for showing upload progress before sending.\n *\n * @param files - Files to upload\n * @param onProgress - Optional progress callback\n * @returns Array of file references\n *\n * @example\n * ```typescript\n * const fileRefs = await chat.uploadFiles(fileInput.files, (i, progress) => {\n * console.log(`File ${i}: ${progress}%`);\n * });\n * // Later...\n * await chat.send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });\n * ```\n */\n async uploadFiles(\n files: FileList | File[],\n onProgress?: (fileIndex: number, progress: number) => void,\n ): Promise<FileReference[]> {\n if (!this.options.requestUploadUrls) {\n throw new Error('File upload requires requestUploadUrls option');\n }\n return await uploadFiles(files, {\n requestUploadUrls: this.options.requestUploadUrls,\n onProgress,\n });\n }\n\n /** Stop the current streaming and finalize any partial message */\n stop(): void {\n if (this._status !== 'streaming') {\n return;\n }\n\n this.transport.stop();\n\n const state = this.streamingState;\n if (state && state.parts.length > 0) {\n // Mark in-progress parts as cancelled/done\n const finalParts = state.parts.map((part): UIMessagePart => {\n if (part.type === 'tool-call') {\n const toolPart = part;\n // Mark pending/running tools as cancelled\n if (toolPart.status === 'pending' || toolPart.status === 'running') {\n return { ...toolPart, status: 'cancelled' };\n }\n }\n if (part.type === 'operation') {\n const opPart = part;\n // Mark running operations as cancelled\n if (opPart.status === 'running') {\n return { ...opPart, status: 'cancelled' };\n }\n }\n if (part.type === 'text' || part.type === 'reasoning') {\n const textPart = part;\n // Mark streaming text/reasoning as done (it's not an error)\n if (textPart.status === 'streaming') {\n return { ...textPart, status: 'done' };\n }\n }\n if (part.type === 'object') {\n const objPart = part;\n // Mark streaming objects as done\n if (objPart.status === 'streaming') {\n return { ...objPart, status: 'done' };\n }\n }\n return part;\n });\n\n const finalMessage: UIMessage = {\n id: state.messageId,\n role: 'assistant',\n parts: finalParts,\n status: 'done',\n createdAt: new Date(),\n };\n\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n if (lastMsg && lastMsg.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n }\n\n this.streamingState = null;\n this.setStatus('idle');\n this.options.onStop?.();\n }\n\n // =========================================================================\n // Private Helpers\n // =========================================================================\n\n private handleStreamEvent(event: StreamEvent, state: StreamingState): void {\n switch (event.type) {\n case 'start':\n break;\n\n case 'block-start': {\n const block: BlockState = {\n blockId: event.blockId,\n blockName: event.blockName,\n blockType: event.blockType,\n display: event.display,\n description: event.description,\n outputToChat: event.outputToChat ?? true,\n thread: event.thread,\n reasoning: '',\n text: '',\n toolCalls: new Map(),\n };\n state.blocks.set(event.blockId, block);\n state.activeBlock = block;\n\n const isOperation = OPERATION_BLOCK_TYPES.has(event.blockType);\n const isHidden = event.display === 'hidden';\n if (isOperation && !isHidden) {\n const thread = event.thread;\n const operationPart: UIOperationPart = {\n type: 'operation',\n operationId: event.blockId,\n name: event.description ?? event.blockName,\n operationType: event.blockType,\n status: 'running',\n thread: threadForPart(thread),\n };\n state.parts.push(operationPart);\n }\n\n state.currentTextPartIndex = null;\n state.currentReasoningPartIndex = null;\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'block-end': {\n const operationPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'operation' && p.operationId === event.blockId,\n );\n if (operationPartIndex >= 0) {\n const part = state.parts[operationPartIndex] as UIOperationPart;\n state.parts[operationPartIndex] = { ...part, status: 'done' };\n }\n\n if (state.activeBlock?.blockId === event.blockId) {\n state.activeBlock = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-start': {\n const reasoningPart: UIReasoningPart = {\n type: 'reasoning',\n text: '',\n status: 'streaming',\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(reasoningPart);\n state.currentReasoningPartIndex = state.parts.length - 1;\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-delta': {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n part.text += event.delta;\n state.parts[state.currentReasoningPartIndex] = { ...part };\n }\n\n if (state.activeBlock) {\n state.activeBlock.reasoning += event.delta;\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-end': {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n part.status = 'done';\n state.parts[state.currentReasoningPartIndex] = { ...part };\n state.currentReasoningPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-start': {\n const thread = threadForPart(state.activeBlock?.thread);\n const shouldAddPart = state.activeBlock?.outputToChat !== false || thread !== undefined;\n\n if (shouldAddPart) {\n // Structured output mode: accumulate JSON and parse progressively\n if (event.responseType) {\n const objectPart: UIObjectPart = {\n type: 'object',\n id: event.id,\n typeName: event.responseType,\n partial: undefined,\n object: undefined,\n status: 'streaming',\n thread,\n };\n state.parts.push(objectPart);\n state.currentObjectPartIndex = state.parts.length - 1;\n state.accumulatedJson = '';\n state.currentTextPartIndex = null;\n } else {\n const textPart: UITextPart = {\n type: 'text',\n text: '',\n status: 'streaming',\n thread,\n };\n state.parts.push(textPart);\n state.currentTextPartIndex = state.parts.length - 1;\n state.currentObjectPartIndex = null;\n }\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-delta': {\n if (state.currentObjectPartIndex !== null) {\n state.accumulatedJson += event.delta;\n const part = state.parts[state.currentObjectPartIndex] as UIObjectPart;\n const parsed = parsePartialJson(state.accumulatedJson);\n if (parsed !== undefined) {\n part.partial = parsed;\n state.parts[state.currentObjectPartIndex] = { ...part };\n }\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n part.text += event.delta;\n state.parts[state.currentTextPartIndex] = { ...part };\n }\n\n if (state.activeBlock) {\n state.activeBlock.text += event.delta;\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-end': {\n if (state.currentObjectPartIndex !== null) {\n const part = state.parts[state.currentObjectPartIndex] as UIObjectPart;\n try {\n const finalObject = JSON.parse(state.accumulatedJson) as unknown;\n part.object = finalObject;\n part.partial = finalObject;\n part.status = 'done';\n } catch {\n // Keep partial data but mark as error\n part.status = 'error';\n part.error = 'Failed to parse response as JSON';\n }\n state.parts[state.currentObjectPartIndex] = { ...part };\n state.currentObjectPartIndex = null;\n state.accumulatedJson = '';\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n part.status = 'done';\n state.parts[state.currentTextPartIndex] = { ...part };\n state.currentTextPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-start': {\n const toolPart: UIToolCallPart = {\n type: 'tool-call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n displayName: event.title,\n args: {},\n status: 'pending',\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(toolPart);\n\n if (state.activeBlock) {\n state.activeBlock.toolCalls.set(event.toolCallId, toolPart);\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-delta': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n try {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.args = JSON.parse(event.inputTextDelta) as Record<string, unknown>;\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n } catch {\n // Partial JSON, ignore\n }\n }\n break;\n }\n\n case 'tool-input-end':\n // Input streaming ended, wait for tool-input-available\n break;\n\n case 'tool-input-available': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.args = event.input as Record<string, unknown>;\n part.status = 'running';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'tool-output-available': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.result = event.output;\n part.status = 'done';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'tool-output-error': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.error = event.errorText;\n part.status = 'error';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'source': {\n // Add source (URL or document) as a part - aligned with Vercel AI SDK\n const thread = threadForPart(state.activeBlock?.thread);\n\n let sourcePart: UISourcePart;\n if (event.sourceType === 'url') {\n sourcePart = {\n type: 'source',\n sourceType: 'url',\n id: event.id,\n url: event.url,\n title: event.title,\n thread,\n };\n } else {\n sourcePart = {\n type: 'source',\n sourceType: 'document',\n id: event.id,\n mediaType: event.mediaType,\n title: event.title,\n filename: event.filename,\n thread,\n };\n }\n\n state.parts.push(sourcePart);\n this.updateStreamingMessage();\n break;\n }\n\n case 'file-available': {\n // Add generated file as a part (aligned with Vercel AI SDK FilePart)\n const filePart: UIFilePart = {\n type: 'file',\n id: event.id,\n mediaType: event.mediaType,\n url: event.url,\n filename: event.filename,\n size: event.size,\n toolCallId: event.toolCallId,\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(filePart);\n this.updateStreamingMessage();\n break;\n }\n\n case 'resource-update':\n this.options.onResourceUpdate?.(event.name, event.value);\n break;\n\n case 'finish': {\n const finalMessage = buildMessageFromState(state, 'done');\n\n finalMessage.parts = finalMessage.parts.map((part) => {\n if (part.type === 'text' || part.type === 'reasoning') {\n return { ...part, status: 'done' as const };\n }\n if (part.type === 'object' && part.status === 'streaming') {\n return { ...part, status: 'done' as const };\n }\n return part;\n });\n\n if (finalMessage.parts.length > 0) {\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n if (lastMsg && lastMsg.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n }\n\n this.setStatus('idle');\n this.streamingState = null;\n this.options.onFinish?.();\n break;\n }\n\n case 'error':\n throw new Error(event.errorText);\n\n case 'tool-request':\n // Handled by server-sdk, not relevant for UI\n break;\n }\n }\n\n private updateStreamingMessage(): void {\n const state = this.streamingState;\n if (!state) return;\n\n const msg = buildMessageFromState(state, 'streaming');\n const messages = [...this._messages];\n\n const lastMsg = messages[messages.length - 1];\n if (lastMsg && lastMsg.id === state.messageId) {\n messages[messages.length - 1] = msg;\n } else {\n messages.push(msg);\n }\n\n this.setMessages(messages);\n }\n}\n","import type { FileReference } from '@octavus/core';\n\n/**\n * Response from the upload URLs endpoint\n */\nexport interface UploadUrlsResponse {\n files: {\n id: string;\n uploadUrl: string;\n downloadUrl: string;\n }[];\n}\n\n/**\n * Options for uploading files\n */\nexport interface UploadFilesOptions {\n /**\n * Function to request upload URLs from the platform.\n * Consumer apps must implement this to authenticate with the platform.\n *\n * @param files - Array of file metadata to request URLs for\n * @returns Response with presigned upload and download URLs\n *\n * @example\n * ```typescript\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * }\n * ```\n */\n requestUploadUrls: (\n files: { filename: string; mediaType: string; size: number }[],\n ) => Promise<UploadUrlsResponse>;\n\n /**\n * Callback for upload progress (0-100 per file).\n * Called multiple times during upload with real-time progress.\n *\n * @param fileIndex - Index of the file being uploaded\n * @param progress - Progress percentage (0-100)\n */\n onProgress?: (fileIndex: number, progress: number) => void;\n}\n\n/**\n * Upload a single file to S3 with progress tracking.\n * Uses XMLHttpRequest for upload progress events (fetch doesn't support this).\n */\nfunction uploadFileWithProgress(\n url: string,\n file: File,\n onProgress?: (progress: number) => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n onProgress?.(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed: network error'));\n });\n\n xhr.addEventListener('abort', () => {\n reject(new Error('Upload aborted'));\n });\n\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n}\n\n/**\n * Upload files to the Octavus platform.\n *\n * This function:\n * 1. Requests presigned upload URLs from the platform\n * 2. Uploads each file directly to S3 with progress tracking\n * 3. Returns file references that can be used in trigger input\n *\n * @param files - Files to upload (from file input or drag/drop)\n * @param options - Upload configuration\n * @returns Array of file references with download URLs\n *\n * @example\n * ```typescript\n * const fileRefs = await uploadFiles(fileInputRef.current.files, {\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * },\n * onProgress: (fileIndex, progress) => {\n * console.log(`File ${fileIndex}: ${progress}%`);\n * },\n * });\n * ```\n */\nexport async function uploadFiles(\n files: FileList | File[],\n options: UploadFilesOptions,\n): Promise<FileReference[]> {\n const fileArray = Array.from(files);\n\n if (fileArray.length === 0) {\n return [];\n }\n\n const { files: uploadInfos } = await options.requestUploadUrls(\n fileArray.map((f) => ({\n filename: f.name,\n mediaType: f.type || 'application/octet-stream',\n size: f.size,\n })),\n );\n\n const references: FileReference[] = [];\n\n for (let i = 0; i < fileArray.length; i++) {\n const file = fileArray[i]!;\n const uploadInfo = uploadInfos[i]!;\n\n await uploadFileWithProgress(uploadInfo.uploadUrl, file, (progress) => {\n options.onProgress?.(i, progress);\n });\n\n references.push({\n id: uploadInfo.id,\n mediaType: file.type || 'application/octet-stream',\n url: uploadInfo.downloadUrl,\n filename: file.name,\n size: file.size,\n });\n }\n\n return references;\n}\n","import { safeParseStreamEvent, isAbortError, type StreamEvent } from '@octavus/core';\n\n/**\n * Parse SSE stream events.\n *\n * @param response - The HTTP response with SSE body\n * @param signal - Optional abort signal to cancel reading\n */\nexport async function* parseSSEStream(\n response: Response,\n signal?: AbortSignal,\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 // Check if aborted before reading\n if (signal?.aborted) {\n return;\n }\n\n let readResult: ReadableStreamReadResult<Uint8Array>;\n try {\n readResult = await reader.read();\n } catch (err) {\n // Handle abort errors gracefully - exit without throwing\n if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n\n const { done, value } = readResult;\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","export {\n OctavusChat,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n} from './chat';\n\nexport { uploadFiles, type UploadFilesOptions, type UploadUrlsResponse } from './files';\n\nexport { parseSSEStream } from './stream/reader';\n\n// Re-export utility functions from core\nexport { isOtherThread, isFileReference, isFileReferenceArray } from '@octavus/core';\n\n// Transport exports\nexport {\n createHttpTransport,\n createSocketTransport,\n isSocketTransport,\n type Transport,\n type SocketTransport,\n type ConnectionState,\n type ConnectionStateListener,\n type HttpTransportOptions,\n type TriggerRequestOptions,\n type SocketLike,\n type SocketTransportOptions,\n} from './transports';\n\n// Re-export all types from core so consumers don't need to install @octavus/core separately\nexport type * from '@octavus/core';\n","import type { StreamEvent } from '@octavus/core';\n\n// =============================================================================\n// Base Transport Interface\n// =============================================================================\n\n/**\n * Transport interface for delivering events from server to client.\n *\n * Abstracts the connection mechanism (HTTP/SSE or WebSocket) behind a unified\n * async iterator interface. Use `createHttpTransport` or `createSocketTransport`\n * to create an implementation.\n */\nexport interface Transport {\n /**\n * Trigger the agent and stream events.\n * @param triggerName - The trigger name defined in the agent's protocol\n * @param input - Input parameters for variable substitution\n */\n trigger(triggerName: string, input?: Record<string, unknown>): AsyncIterable<StreamEvent>;\n\n /** Stop the current stream. Safe to call when no stream is active. */\n stop(): void;\n}\n\n// =============================================================================\n// Socket Transport (extends Transport with connection management)\n// =============================================================================\n\n/**\n * Connection states for socket transport.\n *\n * - `disconnected`: Not connected (initial state or after disconnect)\n * - `connecting`: Connection attempt in progress\n * - `connected`: Successfully connected and ready\n * - `error`: Connection failed (check error in listener callback)\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error';\n\n/**\n * Callback for connection state changes.\n */\nexport type ConnectionStateListener = (state: ConnectionState, error?: Error) => void;\n\n/**\n * Socket transport with connection management capabilities.\n *\n * Extends the base Transport interface with methods for managing persistent\n * WebSocket/SockJS connections. Use this when you need:\n * - Eager connection (connect before first message)\n * - Connection status UI indicators\n * - Manual connection lifecycle control\n *\n * Created via `createSocketTransport()`.\n */\nexport interface SocketTransport extends Transport {\n /**\n * Current connection state.\n *\n * - `disconnected`: Not connected (initial state)\n * - `connecting`: Connection in progress\n * - `connected`: Ready to send/receive\n * - `error`: Connection failed\n */\n readonly connectionState: ConnectionState;\n\n /**\n * Subscribe to connection state changes.\n *\n * The listener is called immediately with the current state, then again\n * whenever the state changes.\n *\n * @param listener - Callback invoked on state changes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = transport.onConnectionStateChange((state, error) => {\n * setConnectionState(state);\n * if (error) setConnectionError(error);\n * });\n * ```\n */\n onConnectionStateChange(listener: ConnectionStateListener): () => void;\n\n /**\n * Eagerly establish the connection.\n *\n * By default, socket transport connects lazily on first `trigger()`. Call\n * this method to establish the connection early (e.g., on component mount):\n * - Faster first message response\n * - Show accurate connection status in UI\n * - Handle connection errors before user interaction\n *\n * Safe to call multiple times - resolves immediately if already connected.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * transport.connect()\n * .then(() => console.log('Connected'))\n * .catch((err) => console.error('Failed:', err));\n *\n * return () => transport.disconnect();\n * }, [transport]);\n * ```\n */\n connect(): Promise<void>;\n\n /**\n * Close the connection and clean up resources.\n *\n * The transport will reconnect automatically on next `trigger()` call.\n */\n disconnect(): void;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a transport is a SocketTransport with connection management.\n *\n * @example\n * ```typescript\n * if (isSocketTransport(transport)) {\n * transport.connect(); // TypeScript knows this is available\n * }\n * ```\n */\nexport function isSocketTransport(transport: Transport): transport is SocketTransport {\n return (\n 'connect' in transport &&\n 'disconnect' in transport &&\n 'connectionState' in transport &&\n 'onConnectionStateChange' in transport\n );\n}\n","import { isAbortError } from '@octavus/core';\nimport { parseSSEStream } from '@/stream/reader';\nimport type { Transport } from './types';\n\n/**\n * Request options passed to the triggerRequest function.\n */\nexport interface TriggerRequestOptions {\n /** Abort signal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Options for creating an HTTP transport.\n */\nexport interface HttpTransportOptions {\n /**\n * Function to make the trigger request.\n * Called each time `send()` is invoked on the chat.\n *\n * @param triggerName - The trigger name (e.g., 'user-message')\n * @param input - Input parameters for the trigger\n * @param options - Optional request options including abort signal\n * @returns Response with SSE stream body\n *\n * @example\n * ```typescript\n * triggerRequest: (triggerName, input, options) =>\n * fetch('/api/octavus', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * signal: options?.signal,\n * }),\n * ```\n */\n triggerRequest: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: TriggerRequestOptions,\n ) => Promise<Response>;\n}\n\n/**\n * Create an HTTP transport using native fetch() and SSE parsing.\n * This is the default transport for Next.js and other HTTP-based applications.\n *\n * @example\n * ```typescript\n * const transport = createHttpTransport({\n * triggerRequest: (triggerName, input, options) =>\n * fetch('/api/octavus', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * signal: options?.signal,\n * }),\n * });\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions): Transport {\n let abortController: AbortController | null = null;\n\n return {\n async *trigger(triggerName, input) {\n abortController = new AbortController();\n\n try {\n const response = await options.triggerRequest(triggerName, input, {\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => `Request failed: ${response.status}`);\n throw new Error(errorText);\n }\n\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n\n for await (const event of parseSSEStream(response, abortController.signal)) {\n if (abortController.signal.aborted) {\n break;\n }\n yield event;\n }\n } catch (err) {\n // Handle abort errors gracefully - don't throw, just exit\n if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n },\n\n stop() {\n abortController?.abort();\n abortController = null;\n },\n };\n}\n","import { safeParseStreamEvent, type StreamEvent } from '@octavus/core';\nimport type { SocketTransport, ConnectionState, ConnectionStateListener } from './types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Socket interface compatible with both WebSocket and SockJS.\n *\n * Uses MessageEvent for the message handler, which both WebSocket and SockJS support.\n * The `| undefined` union accommodates SockJS's optional property typing.\n */\nexport interface SocketLike {\n send(data: string): void;\n close(): void;\n readyState: number;\n onmessage: ((event: MessageEvent) => void) | null | undefined;\n onclose: ((event: CloseEvent) => void) | null | undefined;\n}\n\n/** WebSocket readyState constants */\nconst SOCKET_OPEN = 1;\n\n// =============================================================================\n// Transport Options\n// =============================================================================\n\n/**\n * Options for creating a socket transport.\n */\nexport interface SocketTransportOptions {\n /**\n * Function to create and connect the socket.\n * Works directly with WebSocket and SockJS - no wrappers needed.\n *\n * @example Native WebSocket\n * ```typescript\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket('wss://api.example.com/stream?sessionId=xxx');\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * })\n * ```\n *\n * @example SockJS\n * ```typescript\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/chat-service');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * })\n * ```\n */\n connect: () => Promise<SocketLike>;\n\n /**\n * Called for every message received (parsed as JSON).\n * Use this to handle custom (non-Octavus) events.\n * Octavus StreamEvents are handled automatically by the transport.\n *\n * @example\n * ```typescript\n * onMessage: (data) => {\n * const msg = data as { type: string };\n * if (msg.type === 'typing-indicator') {\n * setIsTyping(true);\n * }\n * if (msg.type === 'presence-update') {\n * updatePresence(msg.users);\n * }\n * }\n * ```\n */\n onMessage?: (data: unknown) => void;\n\n /**\n * Called when the socket connection closes.\n * Use this for cleanup or reconnection logic.\n */\n onClose?: () => void;\n}\n\n/**\n * Create a socket transport that works with any WebSocket-like connection.\n * Supports native WebSocket, SockJS, or any compatible socket implementation.\n *\n * The server should send StreamEvent format (same as SSE) over the socket.\n * Unknown events are safely ignored using Zod validation.\n *\n * ## Connection Lifecycle\n *\n * By default, the socket connects **lazily** on the first `send()` call.\n * Use `connect()` to establish the connection eagerly (e.g., on component mount):\n *\n * ```typescript\n * // Eager connection for UI status indicators\n * useEffect(() => {\n * transport.connect()\n * .then(() => console.log('Connected'))\n * .catch((err) => console.error('Failed:', err));\n *\n * return () => transport.disconnect();\n * }, [transport]);\n * ```\n *\n * @example Basic usage with WebSocket\n * ```typescript\n * const transport = createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket(`wss://api.octavus.ai/stream?sessionId=${sessionId}`);\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * }),\n * });\n * ```\n *\n * @example With SockJS and connection state\n * ```typescript\n * const transport = createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/octavus-stream');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * }),\n * });\n *\n * // Subscribe to connection state changes\n * transport.onConnectionStateChange((state, error) => {\n * setConnectionState(state);\n * if (error) setConnectionError(error);\n * });\n * ```\n */\nexport function createSocketTransport(options: SocketTransportOptions): SocketTransport {\n let socket: SocketLike | null = null;\n let eventQueue: StreamEvent[] = [];\n let eventResolver: ((event: StreamEvent | null) => void) | null = null;\n let isStreaming = false;\n\n let connectionState: ConnectionState = 'disconnected';\n let connectionError: Error | undefined;\n let connectionPromise: Promise<void> | null = null;\n const connectionListeners = new Set<ConnectionStateListener>();\n\n function setConnectionState(state: ConnectionState, error?: Error) {\n connectionState = state;\n connectionError = error;\n connectionListeners.forEach((listener) => listener(state, error));\n }\n\n function enqueueEvent(event: StreamEvent) {\n if (eventResolver) {\n eventResolver(event);\n eventResolver = null;\n } else {\n eventQueue.push(event);\n }\n }\n\n function nextEvent(): Promise<StreamEvent | null> {\n if (eventQueue.length > 0) {\n return Promise.resolve(eventQueue.shift()!);\n }\n if (!isStreaming) {\n return Promise.resolve(null);\n }\n return new Promise((resolve) => {\n eventResolver = resolve;\n });\n }\n\n function setupSocketHandlers(sock: SocketLike): void {\n sock.onmessage = (e: MessageEvent) => {\n try {\n const data: unknown = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n\n options.onMessage?.(data);\n\n const result = safeParseStreamEvent(data);\n if (result.success) {\n const event = result.data;\n enqueueEvent(event);\n\n if (event.type === 'finish' || event.type === 'error') {\n isStreaming = false;\n }\n }\n } catch {\n // Malformed JSON, skip\n }\n };\n\n sock.onclose = () => {\n socket = null;\n connectionPromise = null;\n setConnectionState('disconnected');\n options.onClose?.();\n\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n };\n }\n\n async function ensureConnected(): Promise<void> {\n // Already connected\n if (socket?.readyState === SOCKET_OPEN) {\n return;\n }\n\n // Connection in progress - wait for it\n if (connectionPromise) {\n await connectionPromise;\n return;\n }\n\n // Start new connection\n setConnectionState('connecting');\n\n connectionPromise = (async () => {\n try {\n const sock = await options.connect();\n socket = sock;\n setupSocketHandlers(sock);\n setConnectionState('connected');\n } catch (err) {\n socket = null;\n connectionPromise = null;\n const error = err instanceof Error ? err : new Error('Connection failed');\n setConnectionState('error', error);\n throw error;\n }\n })();\n\n await connectionPromise;\n }\n\n return {\n // =========================================================================\n // Connection Management\n // =========================================================================\n\n get connectionState(): ConnectionState {\n return connectionState;\n },\n\n onConnectionStateChange(listener: ConnectionStateListener): () => void {\n connectionListeners.add(listener);\n // Immediately notify with current state\n listener(connectionState, connectionError);\n return () => connectionListeners.delete(listener);\n },\n\n async connect(): Promise<void> {\n await ensureConnected();\n },\n\n disconnect(): void {\n if (socket) {\n socket.close();\n socket = null;\n }\n connectionPromise = null;\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n setConnectionState('disconnected');\n },\n\n // =========================================================================\n // Streaming\n // =========================================================================\n\n async *trigger(triggerName, input) {\n await ensureConnected();\n\n eventQueue = [];\n isStreaming = true;\n\n socket!.send(\n JSON.stringify({\n type: 'trigger',\n triggerName,\n input,\n }),\n );\n\n while (true) {\n const event = await nextEvent();\n if (event === null) break;\n yield event;\n if (event.type === 'finish' || event.type === 'error') break;\n }\n },\n\n stop() {\n if (socket?.readyState === SOCKET_OPEN) {\n socket.send(JSON.stringify({ type: 'stop' }));\n }\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n },\n };\n}\n"],"mappings":"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","names":["isFileReferenceArray","isAbortError","isAbortError","safeParseStreamEvent"]}
1
+ {"version":3,"sources":["../src/chat.ts","../src/files.ts","../src/stream/reader.ts","../src/transports/types.ts","../src/transports/http.ts","../src/transports/socket.ts","../src/index.ts"],"sourcesContent":["import {\n generateId,\n threadForPart,\n isFileReferenceArray,\n OctavusError,\n type UIMessage,\n type UIMessagePart,\n type UITextPart,\n type UIReasoningPart,\n type UIToolCallPart,\n type UIOperationPart,\n type UISourcePart,\n type UIFilePart,\n type UIObjectPart,\n type DisplayMode,\n type StreamEvent,\n type FileReference,\n} from '@octavus/core';\nimport type { Transport } from './transports/types';\nimport { uploadFiles, type UploadFilesOptions } from './files';\n\n/** Block types that are internal operations (not LLM-driven) */\nconst OPERATION_BLOCK_TYPES = new Set(['set-resource', 'serialize-thread', 'generate-image']);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ChatStatus = 'idle' | 'streaming' | 'error';\n\n/**\n * Input for creating a user message.\n * Supports text content, structured object content, and file attachments.\n */\nexport interface UserMessageInput {\n /**\n * Content of the message. Can be:\n * - string: Creates a text part\n * - object: Creates an object part (uses `type` field as typeName if present)\n */\n content?: string | Record<string, unknown>;\n /**\n * File attachments (shorthand). Can be:\n * - FileList: From file input element (will be uploaded via uploadFiles)\n * - File[]: Array of File objects (will be uploaded via uploadFiles)\n * - FileReference[]: Already uploaded files (used directly)\n */\n files?: FileList | File[] | FileReference[];\n}\n\nexport interface OctavusChatOptions {\n /**\n * Transport for streaming events.\n * Use `createHttpTransport` for HTTP/SSE or `createSocketTransport` for WebSocket/SockJS.\n */\n transport: Transport;\n\n /**\n * Function to request upload URLs from the platform.\n * Required if you want to use file uploads with FileList/File[].\n *\n * @example\n * ```typescript\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * }\n * ```\n */\n requestUploadUrls?: UploadFilesOptions['requestUploadUrls'];\n\n /** Initial messages (for session refresh) */\n initialMessages?: UIMessage[];\n /**\n * Callback when an error occurs.\n * Receives an OctavusError with structured error information.\n *\n * @example\n * ```typescript\n * onError: (error) => {\n * console.error('Chat error:', {\n * type: error.errorType,\n * message: error.message,\n * retryable: error.retryable,\n * provider: error.provider,\n * });\n *\n * // Handle specific error types\n * if (isRateLimitError(error)) {\n * showRetryButton(error.retryAfter);\n * }\n * }\n * ```\n */\n onError?: (error: OctavusError) => void;\n /** Callback when streaming finishes successfully */\n onFinish?: () => void;\n /** Callback when streaming is stopped by user */\n onStop?: () => void;\n /** Callback when a resource is updated */\n onResourceUpdate?: (name: string, value: unknown) => void;\n}\n\n// =============================================================================\n// Internal Types\n// =============================================================================\n\ninterface BlockState {\n blockId: string;\n blockName: string;\n blockType: string;\n display: DisplayMode;\n description?: string;\n outputToChat: boolean;\n thread?: string;\n reasoning: string;\n text: string;\n toolCalls: Map<string, UIToolCallPart>;\n}\n\ninterface StreamingState {\n messageId: string;\n parts: UIMessagePart[];\n activeBlock: BlockState | null;\n blocks: Map<string, BlockState>;\n currentTextPartIndex: number | null;\n currentReasoningPartIndex: number | null;\n currentObjectPartIndex: number | null;\n accumulatedJson: string;\n}\n\ntype Listener = () => void;\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Create a user message from input with optional file attachments.\n * Parts order: files first (for vision models), then content (text or object).\n */\nfunction createUserMessage(input: UserMessageInput, files?: FileReference[]): UIMessage {\n const parts: UIMessagePart[] = [];\n\n // Add file parts first (vision models expect images before text)\n if (files && files.length > 0) {\n for (const file of files) {\n parts.push({\n type: 'file',\n id: file.id,\n mediaType: file.mediaType,\n url: file.url,\n filename: file.filename,\n size: file.size,\n });\n }\n }\n\n // Add content part after files\n if (input.content !== undefined) {\n if (typeof input.content === 'string') {\n // String content → text part\n parts.push({ type: 'text', text: input.content, status: 'done' });\n } else {\n // Object content → object part\n // Use the object's `type` field as typeName if present, otherwise fallback to 'object'\n const typeName = (input.content as { type?: string }).type ?? 'object';\n parts.push({\n type: 'object',\n id: generateId(),\n typeName,\n object: input.content,\n status: 'done',\n });\n }\n }\n\n return {\n id: generateId(),\n role: 'user',\n parts,\n status: 'done',\n createdAt: new Date(),\n };\n}\n\n/**\n * Parse partial JSON by fixing incomplete structures (unclosed strings, brackets, braces).\n */\nfunction parsePartialJson(jsonText: string): unknown {\n if (!jsonText.trim()) {\n return undefined;\n }\n\n try {\n return JSON.parse(jsonText) as unknown;\n } catch {\n // Continue to fix incomplete JSON\n }\n\n let fixed = jsonText;\n\n // Count unclosed brackets/braces while tracking string boundaries\n let openBraces = 0;\n let openBrackets = 0;\n let inString = false;\n let escaped = false;\n\n for (const char of fixed) {\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (char === '\\\\') {\n escaped = true;\n continue;\n }\n\n if (char === '\"') {\n inString = !inString;\n continue;\n }\n\n if (!inString) {\n if (char === '{') openBraces += 1;\n else if (char === '}') openBraces -= 1;\n else if (char === '[') openBrackets += 1;\n else if (char === ']') openBrackets -= 1;\n }\n }\n\n // Close unclosed structures\n if (inString) {\n fixed += '\"';\n }\n while (openBrackets > 0) {\n fixed += ']';\n openBrackets -= 1;\n }\n while (openBraces > 0) {\n fixed += '}';\n openBraces -= 1;\n }\n\n try {\n return JSON.parse(fixed) as unknown;\n } catch {\n return undefined;\n }\n}\n\nfunction createEmptyStreamingState(): StreamingState {\n return {\n messageId: generateId(),\n parts: [],\n activeBlock: null,\n blocks: new Map(),\n currentTextPartIndex: null,\n currentReasoningPartIndex: null,\n currentObjectPartIndex: null,\n accumulatedJson: '',\n };\n}\n\nfunction buildMessageFromState(state: StreamingState, status: 'streaming' | 'done'): UIMessage {\n return {\n id: state.messageId,\n role: 'assistant',\n parts: [...state.parts],\n status,\n createdAt: new Date(),\n };\n}\n\n// =============================================================================\n// OctavusChat Class\n// =============================================================================\n\n/**\n * Framework-agnostic chat client for Octavus agents.\n * Manages chat state and streaming, allowing reactive frameworks to subscribe to updates.\n *\n * @example HTTP transport (Next.js, etc.)\n * ```typescript\n * import { OctavusChat, createHttpTransport } from '@octavus/client-sdk';\n *\n * const chat = new OctavusChat({\n * transport: createHttpTransport({\n * triggerRequest: (triggerName, input) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * }),\n * }),\n * });\n * ```\n *\n * @example Socket transport (WebSocket, SockJS, Meteor)\n * ```typescript\n * import { OctavusChat, createSocketTransport } from '@octavus/client-sdk';\n *\n * const chat = new OctavusChat({\n * transport: createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket(`wss://api.octavus.ai/stream?sessionId=${sessionId}`);\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * }),\n * }),\n * });\n * ```\n */\nexport class OctavusChat {\n // Private state\n private _messages: UIMessage[];\n private _status: ChatStatus = 'idle';\n private _error: OctavusError | null = null;\n private options: OctavusChatOptions;\n private transport: Transport;\n private streamingState: StreamingState | null = null;\n\n // Listener sets for reactive frameworks\n private listeners = new Set<Listener>();\n\n constructor(options: OctavusChatOptions) {\n this.options = options;\n this._messages = options.initialMessages ?? [];\n this.transport = options.transport;\n }\n\n // =========================================================================\n // Public Getters\n // =========================================================================\n\n get messages(): UIMessage[] {\n return this._messages;\n }\n\n get status(): ChatStatus {\n return this._status;\n }\n\n /**\n * The current error, if any.\n * Contains structured error information including type, source, and retryability.\n */\n get error(): OctavusError | null {\n return this._error;\n }\n\n // =========================================================================\n // Subscription Methods (for reactive frameworks)\n // =========================================================================\n\n /**\n * Subscribe to state changes. The callback is called whenever messages, status, or error changes.\n * @returns Unsubscribe function\n */\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notifyListeners(): void {\n this.listeners.forEach((l) => l());\n }\n\n // =========================================================================\n // Private Setters (notify listeners)\n // =========================================================================\n\n private setMessages(messages: UIMessage[]): void {\n this._messages = messages;\n this.notifyListeners();\n }\n\n private setStatus(status: ChatStatus): void {\n this._status = status;\n this.notifyListeners();\n }\n\n private setError(error: OctavusError | null): void {\n this._error = error;\n this.notifyListeners();\n }\n\n // =========================================================================\n // Public Methods\n // =========================================================================\n\n /**\n * Trigger the agent and optionally add a user message to the chat.\n *\n * @param triggerName - The trigger name defined in the agent's protocol.yaml\n * @param input - Input parameters for the trigger (variable substitutions)\n * @param options.userMessage - If provided, adds a user message to the chat before triggering\n *\n * @example Send a text message\n * ```typescript\n * await chat.send('user-message',\n * { USER_MESSAGE: message },\n * { userMessage: { content: message } }\n * );\n * ```\n *\n * @example Send a message with file attachments\n * ```typescript\n * await chat.send('user-message',\n * { USER_MESSAGE: message, FILES: fileRefs },\n * { userMessage: { content: message, files: fileRefs } }\n * );\n * ```\n */\n async send(\n triggerName: string,\n input?: Record<string, unknown>,\n sendOptions?: { userMessage?: UserMessageInput },\n ): Promise<void> {\n this.transport.stop();\n\n let fileRefs: FileReference[] | undefined;\n if (sendOptions?.userMessage?.files) {\n const files = sendOptions.userMessage.files;\n if (isFileReferenceArray(files)) {\n fileRefs = files;\n } else if (this.options.requestUploadUrls) {\n fileRefs = await uploadFiles(files, {\n requestUploadUrls: this.options.requestUploadUrls,\n });\n } else {\n throw new Error(\n 'File upload requires requestUploadUrls option. Either provide FileReference[] or configure requestUploadUrls.',\n );\n }\n }\n\n // Auto-upload FILES in trigger input if needed\n let processedInput = input;\n if (input?.FILES !== undefined && !isFileReferenceArray(input.FILES)) {\n if (this.options.requestUploadUrls) {\n const inputFiles = input.FILES as FileList | File[];\n const uploadedRefs =\n fileRefs ??\n (await uploadFiles(inputFiles, {\n requestUploadUrls: this.options.requestUploadUrls,\n }));\n processedInput = { ...input, FILES: uploadedRefs };\n fileRefs = fileRefs ?? uploadedRefs;\n }\n }\n\n // Optimistic UI: add user message before server responds\n if (sendOptions?.userMessage !== undefined) {\n const userMsg = createUserMessage(sendOptions.userMessage, fileRefs);\n this.setMessages([...this._messages, userMsg]);\n }\n\n this.setStatus('streaming');\n this.setError(null);\n this.streamingState = createEmptyStreamingState();\n\n try {\n for await (const event of this.transport.trigger(triggerName, processedInput)) {\n if (this.streamingState === null) break;\n\n this.handleStreamEvent(event, this.streamingState);\n }\n } catch (err) {\n // Convert unknown errors to OctavusError\n const errorObj = OctavusError.isInstance(err)\n ? err\n : new OctavusError({\n errorType: 'internal_error',\n message: err instanceof Error ? err.message : 'Unknown error',\n source: 'client',\n retryable: false,\n cause: err,\n });\n this.setError(errorObj);\n this.setStatus('error');\n this.streamingState = null;\n this.options.onError?.(errorObj);\n }\n }\n\n /**\n * Upload files directly without sending a message.\n * Useful for showing upload progress before sending.\n *\n * @param files - Files to upload\n * @param onProgress - Optional progress callback\n * @returns Array of file references\n *\n * @example\n * ```typescript\n * const fileRefs = await chat.uploadFiles(fileInput.files, (i, progress) => {\n * console.log(`File ${i}: ${progress}%`);\n * });\n * // Later...\n * await chat.send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });\n * ```\n */\n async uploadFiles(\n files: FileList | File[],\n onProgress?: (fileIndex: number, progress: number) => void,\n ): Promise<FileReference[]> {\n if (!this.options.requestUploadUrls) {\n throw new Error('File upload requires requestUploadUrls option');\n }\n return await uploadFiles(files, {\n requestUploadUrls: this.options.requestUploadUrls,\n onProgress,\n });\n }\n\n /** Stop the current streaming and finalize any partial message */\n stop(): void {\n if (this._status !== 'streaming') {\n return;\n }\n\n this.transport.stop();\n\n const state = this.streamingState;\n if (state && state.parts.length > 0) {\n // Mark in-progress parts as cancelled/done\n const finalParts = state.parts.map((part): UIMessagePart => {\n if (part.type === 'tool-call') {\n const toolPart = part;\n // Mark pending/running tools as cancelled\n if (toolPart.status === 'pending' || toolPart.status === 'running') {\n return { ...toolPart, status: 'cancelled' };\n }\n }\n if (part.type === 'operation') {\n const opPart = part;\n // Mark running operations as cancelled\n if (opPart.status === 'running') {\n return { ...opPart, status: 'cancelled' };\n }\n }\n if (part.type === 'text' || part.type === 'reasoning') {\n const textPart = part;\n // Mark streaming text/reasoning as done (it's not an error)\n if (textPart.status === 'streaming') {\n return { ...textPart, status: 'done' };\n }\n }\n if (part.type === 'object') {\n const objPart = part;\n // Mark streaming objects as done\n if (objPart.status === 'streaming') {\n return { ...objPart, status: 'done' };\n }\n }\n return part;\n });\n\n const finalMessage: UIMessage = {\n id: state.messageId,\n role: 'assistant',\n parts: finalParts,\n status: 'done',\n createdAt: new Date(),\n };\n\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n }\n\n this.streamingState = null;\n this.setStatus('idle');\n this.options.onStop?.();\n }\n\n // =========================================================================\n // Private Helpers\n // =========================================================================\n\n private handleStreamEvent(event: StreamEvent, state: StreamingState): void {\n switch (event.type) {\n case 'start':\n break;\n\n case 'block-start': {\n const block: BlockState = {\n blockId: event.blockId,\n blockName: event.blockName,\n blockType: event.blockType,\n display: event.display,\n description: event.description,\n outputToChat: event.outputToChat ?? true,\n thread: event.thread,\n reasoning: '',\n text: '',\n toolCalls: new Map(),\n };\n state.blocks.set(event.blockId, block);\n state.activeBlock = block;\n\n const isOperation = OPERATION_BLOCK_TYPES.has(event.blockType);\n const isHidden = event.display === 'hidden';\n if (isOperation && !isHidden) {\n const thread = event.thread;\n const operationPart: UIOperationPart = {\n type: 'operation',\n operationId: event.blockId,\n name: event.description ?? event.blockName,\n operationType: event.blockType,\n status: 'running',\n thread: threadForPart(thread),\n };\n state.parts.push(operationPart);\n }\n\n state.currentTextPartIndex = null;\n state.currentReasoningPartIndex = null;\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'block-end': {\n const operationPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'operation' && p.operationId === event.blockId,\n );\n if (operationPartIndex >= 0) {\n const part = state.parts[operationPartIndex] as UIOperationPart;\n state.parts[operationPartIndex] = { ...part, status: 'done' };\n }\n\n if (state.activeBlock?.blockId === event.blockId) {\n state.activeBlock = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-start': {\n const reasoningPart: UIReasoningPart = {\n type: 'reasoning',\n text: '',\n status: 'streaming',\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(reasoningPart);\n state.currentReasoningPartIndex = state.parts.length - 1;\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-delta': {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n part.text += event.delta;\n state.parts[state.currentReasoningPartIndex] = { ...part };\n }\n\n if (state.activeBlock) {\n state.activeBlock.reasoning += event.delta;\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-end': {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n part.status = 'done';\n state.parts[state.currentReasoningPartIndex] = { ...part };\n state.currentReasoningPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-start': {\n const thread = threadForPart(state.activeBlock?.thread);\n const shouldAddPart = state.activeBlock?.outputToChat !== false || thread !== undefined;\n\n if (shouldAddPart) {\n // Structured output mode: accumulate JSON and parse progressively\n if (event.responseType) {\n const objectPart: UIObjectPart = {\n type: 'object',\n id: event.id,\n typeName: event.responseType,\n partial: undefined,\n object: undefined,\n status: 'streaming',\n thread,\n };\n state.parts.push(objectPart);\n state.currentObjectPartIndex = state.parts.length - 1;\n state.accumulatedJson = '';\n state.currentTextPartIndex = null;\n } else {\n const textPart: UITextPart = {\n type: 'text',\n text: '',\n status: 'streaming',\n thread,\n };\n state.parts.push(textPart);\n state.currentTextPartIndex = state.parts.length - 1;\n state.currentObjectPartIndex = null;\n }\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-delta': {\n if (state.currentObjectPartIndex !== null) {\n state.accumulatedJson += event.delta;\n const part = state.parts[state.currentObjectPartIndex] as UIObjectPart;\n const parsed = parsePartialJson(state.accumulatedJson);\n if (parsed !== undefined) {\n part.partial = parsed;\n state.parts[state.currentObjectPartIndex] = { ...part };\n }\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n part.text += event.delta;\n state.parts[state.currentTextPartIndex] = { ...part };\n }\n\n if (state.activeBlock) {\n state.activeBlock.text += event.delta;\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-end': {\n if (state.currentObjectPartIndex !== null) {\n const part = state.parts[state.currentObjectPartIndex] as UIObjectPart;\n try {\n const finalObject = JSON.parse(state.accumulatedJson) as unknown;\n part.object = finalObject;\n part.partial = finalObject;\n part.status = 'done';\n } catch {\n // Keep partial data but mark as error\n part.status = 'error';\n part.error = 'Failed to parse response as JSON';\n }\n state.parts[state.currentObjectPartIndex] = { ...part };\n state.currentObjectPartIndex = null;\n state.accumulatedJson = '';\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n part.status = 'done';\n state.parts[state.currentTextPartIndex] = { ...part };\n state.currentTextPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-start': {\n const toolPart: UIToolCallPart = {\n type: 'tool-call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n displayName: event.title,\n args: {},\n status: 'pending',\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(toolPart);\n\n if (state.activeBlock) {\n state.activeBlock.toolCalls.set(event.toolCallId, toolPart);\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-delta': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n try {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.args = JSON.parse(event.inputTextDelta) as Record<string, unknown>;\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n } catch {\n // Partial JSON, ignore\n }\n }\n break;\n }\n\n case 'tool-input-end':\n // Input streaming ended, wait for tool-input-available\n break;\n\n case 'tool-input-available': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.args = event.input as Record<string, unknown>;\n part.status = 'running';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'tool-output-available': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.result = event.output;\n part.status = 'done';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'tool-output-error': {\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n part.error = event.error;\n part.status = 'error';\n state.parts[toolPartIndex] = { ...part };\n this.updateStreamingMessage();\n }\n break;\n }\n\n case 'source': {\n // Add source (URL or document) as a part\n const thread = threadForPart(state.activeBlock?.thread);\n\n let sourcePart: UISourcePart;\n if (event.sourceType === 'url') {\n sourcePart = {\n type: 'source',\n sourceType: 'url',\n id: event.id,\n url: event.url,\n title: event.title,\n thread,\n };\n } else {\n sourcePart = {\n type: 'source',\n sourceType: 'document',\n id: event.id,\n mediaType: event.mediaType,\n title: event.title,\n filename: event.filename,\n thread,\n };\n }\n\n state.parts.push(sourcePart);\n this.updateStreamingMessage();\n break;\n }\n\n case 'file-available': {\n // Add generated file as a part\n const filePart: UIFilePart = {\n type: 'file',\n id: event.id,\n mediaType: event.mediaType,\n url: event.url,\n filename: event.filename,\n size: event.size,\n toolCallId: event.toolCallId,\n thread: threadForPart(state.activeBlock?.thread),\n };\n state.parts.push(filePart);\n this.updateStreamingMessage();\n break;\n }\n\n case 'resource-update':\n this.options.onResourceUpdate?.(event.name, event.value);\n break;\n\n case 'finish': {\n const finalMessage = buildMessageFromState(state, 'done');\n\n finalMessage.parts = finalMessage.parts.map((part) => {\n if (part.type === 'text' || part.type === 'reasoning') {\n return { ...part, status: 'done' as const };\n }\n if (part.type === 'object' && part.status === 'streaming') {\n return { ...part, status: 'done' as const };\n }\n return part;\n });\n\n if (finalMessage.parts.length > 0) {\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n }\n\n this.setStatus('idle');\n this.streamingState = null;\n this.options.onFinish?.();\n break;\n }\n\n case 'error': {\n // Create structured error from the error event\n throw new OctavusError({\n errorType: event.errorType,\n message: event.message,\n source: event.source,\n retryable: event.retryable,\n retryAfter: event.retryAfter,\n code: event.code,\n provider: event.provider,\n tool: event.tool,\n });\n }\n\n case 'tool-request':\n // Handled by server-sdk, not relevant for UI\n break;\n }\n }\n\n private updateStreamingMessage(): void {\n const state = this.streamingState;\n if (!state) return;\n\n const msg = buildMessageFromState(state, 'streaming');\n const messages = [...this._messages];\n\n const lastMsg = messages[messages.length - 1];\n if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = msg;\n } else {\n messages.push(msg);\n }\n\n this.setMessages(messages);\n }\n}\n","import type { FileReference } from '@octavus/core';\n\n/**\n * Response from the upload URLs endpoint\n */\nexport interface UploadUrlsResponse {\n files: {\n id: string;\n uploadUrl: string;\n downloadUrl: string;\n }[];\n}\n\n/**\n * Options for uploading files\n */\nexport interface UploadFilesOptions {\n /**\n * Function to request upload URLs from the platform.\n * Consumer apps must implement this to authenticate with the platform.\n *\n * @param files - Array of file metadata to request URLs for\n * @returns Response with presigned upload and download URLs\n *\n * @example\n * ```typescript\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * }\n * ```\n */\n requestUploadUrls: (\n files: { filename: string; mediaType: string; size: number }[],\n ) => Promise<UploadUrlsResponse>;\n\n /**\n * Callback for upload progress (0-100 per file).\n * Called multiple times during upload with real-time progress.\n *\n * @param fileIndex - Index of the file being uploaded\n * @param progress - Progress percentage (0-100)\n */\n onProgress?: (fileIndex: number, progress: number) => void;\n}\n\n/**\n * Upload a single file to S3 with progress tracking.\n * Uses XMLHttpRequest for upload progress events (fetch doesn't support this).\n */\nfunction uploadFileWithProgress(\n url: string,\n file: File,\n onProgress?: (progress: number) => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n onProgress?.(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed: network error'));\n });\n\n xhr.addEventListener('abort', () => {\n reject(new Error('Upload aborted'));\n });\n\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n}\n\n/**\n * Upload files to the Octavus platform.\n *\n * This function:\n * 1. Requests presigned upload URLs from the platform\n * 2. Uploads each file directly to S3 with progress tracking\n * 3. Returns file references that can be used in trigger input\n *\n * @param files - Files to upload (from file input or drag/drop)\n * @param options - Upload configuration\n * @returns Array of file references with download URLs\n *\n * @example\n * ```typescript\n * const fileRefs = await uploadFiles(fileInputRef.current.files, {\n * requestUploadUrls: async (files) => {\n * const response = await fetch('/api/upload-urls', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, files }),\n * });\n * return response.json();\n * },\n * onProgress: (fileIndex, progress) => {\n * console.log(`File ${fileIndex}: ${progress}%`);\n * },\n * });\n * ```\n */\nexport async function uploadFiles(\n files: FileList | File[],\n options: UploadFilesOptions,\n): Promise<FileReference[]> {\n const fileArray = Array.from(files);\n\n if (fileArray.length === 0) {\n return [];\n }\n\n const { files: uploadInfos } = await options.requestUploadUrls(\n fileArray.map((f) => ({\n filename: f.name,\n mediaType: f.type || 'application/octet-stream',\n size: f.size,\n })),\n );\n\n const references: FileReference[] = [];\n\n for (let i = 0; i < fileArray.length; i++) {\n const file = fileArray[i]!;\n const uploadInfo = uploadInfos[i]!;\n\n await uploadFileWithProgress(uploadInfo.uploadUrl, file, (progress) => {\n options.onProgress?.(i, progress);\n });\n\n references.push({\n id: uploadInfo.id,\n mediaType: file.type || 'application/octet-stream',\n url: uploadInfo.downloadUrl,\n filename: file.name,\n size: file.size,\n });\n }\n\n return references;\n}\n","import { safeParseStreamEvent, isAbortError, type StreamEvent } from '@octavus/core';\n\n/**\n * Parse SSE stream events.\n *\n * @param response - The HTTP response with SSE body\n * @param signal - Optional abort signal to cancel reading\n */\nexport async function* parseSSEStream(\n response: Response,\n signal?: AbortSignal,\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 // Check if aborted before reading\n if (signal?.aborted) {\n return;\n }\n\n let readResult: ReadableStreamReadResult<Uint8Array>;\n try {\n readResult = await reader.read();\n } catch (err) {\n // Handle abort errors gracefully - exit without throwing\n if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n\n const { done, value } = readResult;\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","import type { StreamEvent } from '@octavus/core';\n\n// =============================================================================\n// Base Transport Interface\n// =============================================================================\n\n/**\n * Transport interface for delivering events from server to client.\n *\n * Abstracts the connection mechanism (HTTP/SSE or WebSocket) behind a unified\n * async iterator interface. Use `createHttpTransport` or `createSocketTransport`\n * to create an implementation.\n */\nexport interface Transport {\n /**\n * Trigger the agent and stream events.\n * @param triggerName - The trigger name defined in the agent's protocol\n * @param input - Input parameters for variable substitution\n */\n trigger(triggerName: string, input?: Record<string, unknown>): AsyncIterable<StreamEvent>;\n\n /** Stop the current stream. Safe to call when no stream is active. */\n stop(): void;\n}\n\n// =============================================================================\n// Socket Transport (extends Transport with connection management)\n// =============================================================================\n\n/**\n * Connection states for socket transport.\n *\n * - `disconnected`: Not connected (initial state or after disconnect)\n * - `connecting`: Connection attempt in progress\n * - `connected`: Successfully connected and ready\n * - `error`: Connection failed (check error in listener callback)\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error';\n\n/**\n * Callback for connection state changes.\n */\nexport type ConnectionStateListener = (state: ConnectionState, error?: Error) => void;\n\n/**\n * Socket transport with connection management capabilities.\n *\n * Extends the base Transport interface with methods for managing persistent\n * WebSocket/SockJS connections. Use this when you need:\n * - Eager connection (connect before first message)\n * - Connection status UI indicators\n * - Manual connection lifecycle control\n *\n * Created via `createSocketTransport()`.\n */\nexport interface SocketTransport extends Transport {\n /**\n * Current connection state.\n *\n * - `disconnected`: Not connected (initial state)\n * - `connecting`: Connection in progress\n * - `connected`: Ready to send/receive\n * - `error`: Connection failed\n */\n readonly connectionState: ConnectionState;\n\n /**\n * Subscribe to connection state changes.\n *\n * The listener is called immediately with the current state, then again\n * whenever the state changes.\n *\n * @param listener - Callback invoked on state changes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = transport.onConnectionStateChange((state, error) => {\n * setConnectionState(state);\n * if (error) setConnectionError(error);\n * });\n * ```\n */\n onConnectionStateChange(listener: ConnectionStateListener): () => void;\n\n /**\n * Eagerly establish the connection.\n *\n * By default, socket transport connects lazily on first `trigger()`. Call\n * this method to establish the connection early (e.g., on component mount):\n * - Faster first message response\n * - Show accurate connection status in UI\n * - Handle connection errors before user interaction\n *\n * Safe to call multiple times - resolves immediately if already connected.\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * transport.connect()\n * .then(() => console.log('Connected'))\n * .catch((err) => console.error('Failed:', err));\n *\n * return () => transport.disconnect();\n * }, [transport]);\n * ```\n */\n connect(): Promise<void>;\n\n /**\n * Close the connection and clean up resources.\n *\n * The transport will reconnect automatically on next `trigger()` call.\n */\n disconnect(): void;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a transport is a SocketTransport with connection management.\n *\n * @example\n * ```typescript\n * if (isSocketTransport(transport)) {\n * transport.connect(); // TypeScript knows this is available\n * }\n * ```\n */\nexport function isSocketTransport(transport: Transport): transport is SocketTransport {\n return (\n 'connect' in transport &&\n 'disconnect' in transport &&\n 'connectionState' in transport &&\n 'onConnectionStateChange' in transport\n );\n}\n","import { isAbortError } from '@octavus/core';\nimport { parseSSEStream } from '@/stream/reader';\nimport type { Transport } from './types';\n\n/**\n * Request options passed to the triggerRequest function.\n */\nexport interface TriggerRequestOptions {\n /** Abort signal to cancel the request */\n signal?: AbortSignal;\n}\n\n/**\n * Options for creating an HTTP transport.\n */\nexport interface HttpTransportOptions {\n /**\n * Function to make the trigger request.\n * Called each time `send()` is invoked on the chat.\n *\n * @param triggerName - The trigger name (e.g., 'user-message')\n * @param input - Input parameters for the trigger\n * @param options - Optional request options including abort signal\n * @returns Response with SSE stream body\n *\n * @example\n * ```typescript\n * triggerRequest: (triggerName, input, options) =>\n * fetch('/api/octavus', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * signal: options?.signal,\n * }),\n * ```\n */\n triggerRequest: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: TriggerRequestOptions,\n ) => Promise<Response>;\n}\n\n/**\n * Create an HTTP transport using native fetch() and SSE parsing.\n * This is the default transport for Next.js and other HTTP-based applications.\n *\n * @example\n * ```typescript\n * const transport = createHttpTransport({\n * triggerRequest: (triggerName, input, options) =>\n * fetch('/api/octavus', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, triggerName, input }),\n * signal: options?.signal,\n * }),\n * });\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions): Transport {\n let abortController: AbortController | null = null;\n\n return {\n async *trigger(triggerName, input) {\n abortController = new AbortController();\n\n try {\n const response = await options.triggerRequest(triggerName, input, {\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => `Request failed: ${response.status}`);\n throw new Error(errorText);\n }\n\n if (!response.body) {\n throw new Error('Response body is empty');\n }\n\n for await (const event of parseSSEStream(response, abortController.signal)) {\n if (abortController.signal.aborted) {\n break;\n }\n yield event;\n }\n } catch (err) {\n // Handle abort errors gracefully - don't throw, just exit\n if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n },\n\n stop() {\n abortController?.abort();\n abortController = null;\n },\n };\n}\n","import { safeParseStreamEvent, type StreamEvent } from '@octavus/core';\nimport type { SocketTransport, ConnectionState, ConnectionStateListener } from './types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Socket interface compatible with both WebSocket and SockJS.\n *\n * Uses MessageEvent for the message handler, which both WebSocket and SockJS support.\n * The `| undefined` union accommodates SockJS's optional property typing.\n */\nexport interface SocketLike {\n send(data: string): void;\n close(): void;\n readyState: number;\n onmessage: ((event: MessageEvent) => void) | null | undefined;\n onclose: ((event: CloseEvent) => void) | null | undefined;\n}\n\n/** WebSocket readyState constants */\nconst SOCKET_OPEN = 1;\n\n// =============================================================================\n// Transport Options\n// =============================================================================\n\n/**\n * Options for creating a socket transport.\n */\nexport interface SocketTransportOptions {\n /**\n * Function to create and connect the socket.\n * Works directly with WebSocket and SockJS - no wrappers needed.\n *\n * @example Native WebSocket\n * ```typescript\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket('wss://api.example.com/stream?sessionId=xxx');\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * })\n * ```\n *\n * @example SockJS\n * ```typescript\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/chat-service');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * })\n * ```\n */\n connect: () => Promise<SocketLike>;\n\n /**\n * Called for every message received (parsed as JSON).\n * Use this to handle custom (non-Octavus) events.\n * Octavus StreamEvents are handled automatically by the transport.\n *\n * @example\n * ```typescript\n * onMessage: (data) => {\n * const msg = data as { type: string };\n * if (msg.type === 'typing-indicator') {\n * setIsTyping(true);\n * }\n * if (msg.type === 'presence-update') {\n * updatePresence(msg.users);\n * }\n * }\n * ```\n */\n onMessage?: (data: unknown) => void;\n\n /**\n * Called when the socket connection closes.\n * Use this for cleanup or reconnection logic.\n */\n onClose?: () => void;\n}\n\n/**\n * Create a socket transport that works with any WebSocket-like connection.\n * Supports native WebSocket, SockJS, or any compatible socket implementation.\n *\n * The server should send StreamEvent format (same as SSE) over the socket.\n * Unknown events are safely ignored using Zod validation.\n *\n * ## Connection Lifecycle\n *\n * By default, the socket connects **lazily** on the first `send()` call.\n * Use `connect()` to establish the connection eagerly (e.g., on component mount):\n *\n * ```typescript\n * // Eager connection for UI status indicators\n * useEffect(() => {\n * transport.connect()\n * .then(() => console.log('Connected'))\n * .catch((err) => console.error('Failed:', err));\n *\n * return () => transport.disconnect();\n * }, [transport]);\n * ```\n *\n * @example Basic usage with WebSocket\n * ```typescript\n * const transport = createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const ws = new WebSocket(`wss://api.octavus.ai/stream?sessionId=${sessionId}`);\n * ws.onopen = () => resolve(ws);\n * ws.onerror = () => reject(new Error('Connection failed'));\n * }),\n * });\n * ```\n *\n * @example With SockJS and connection state\n * ```typescript\n * const transport = createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/octavus-stream');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * }),\n * });\n *\n * // Subscribe to connection state changes\n * transport.onConnectionStateChange((state, error) => {\n * setConnectionState(state);\n * if (error) setConnectionError(error);\n * });\n * ```\n */\nexport function createSocketTransport(options: SocketTransportOptions): SocketTransport {\n let socket: SocketLike | null = null;\n let eventQueue: StreamEvent[] = [];\n let eventResolver: ((event: StreamEvent | null) => void) | null = null;\n let isStreaming = false;\n\n let connectionState: ConnectionState = 'disconnected';\n let connectionError: Error | undefined;\n let connectionPromise: Promise<void> | null = null;\n const connectionListeners = new Set<ConnectionStateListener>();\n\n function setConnectionState(state: ConnectionState, error?: Error) {\n connectionState = state;\n connectionError = error;\n connectionListeners.forEach((listener) => listener(state, error));\n }\n\n function enqueueEvent(event: StreamEvent) {\n if (eventResolver) {\n eventResolver(event);\n eventResolver = null;\n } else {\n eventQueue.push(event);\n }\n }\n\n function nextEvent(): Promise<StreamEvent | null> {\n if (eventQueue.length > 0) {\n return Promise.resolve(eventQueue.shift()!);\n }\n if (!isStreaming) {\n return Promise.resolve(null);\n }\n return new Promise((resolve) => {\n eventResolver = resolve;\n });\n }\n\n function setupSocketHandlers(sock: SocketLike): void {\n sock.onmessage = (e: MessageEvent) => {\n try {\n const data: unknown = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n\n options.onMessage?.(data);\n\n const result = safeParseStreamEvent(data);\n if (result.success) {\n const event = result.data;\n enqueueEvent(event);\n\n if (event.type === 'finish' || event.type === 'error') {\n isStreaming = false;\n }\n }\n } catch {\n // Malformed JSON, skip\n }\n };\n\n sock.onclose = () => {\n socket = null;\n connectionPromise = null;\n setConnectionState('disconnected');\n options.onClose?.();\n\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n };\n }\n\n async function ensureConnected(): Promise<void> {\n // Already connected\n if (socket?.readyState === SOCKET_OPEN) {\n return;\n }\n\n // Connection in progress - wait for it\n if (connectionPromise) {\n await connectionPromise;\n return;\n }\n\n // Start new connection\n setConnectionState('connecting');\n\n connectionPromise = (async () => {\n try {\n const sock = await options.connect();\n socket = sock;\n setupSocketHandlers(sock);\n setConnectionState('connected');\n } catch (err) {\n socket = null;\n connectionPromise = null;\n const error = err instanceof Error ? err : new Error('Connection failed');\n setConnectionState('error', error);\n throw error;\n }\n })();\n\n await connectionPromise;\n }\n\n return {\n // =========================================================================\n // Connection Management\n // =========================================================================\n\n get connectionState(): ConnectionState {\n return connectionState;\n },\n\n onConnectionStateChange(listener: ConnectionStateListener): () => void {\n connectionListeners.add(listener);\n // Immediately notify with current state\n listener(connectionState, connectionError);\n return () => connectionListeners.delete(listener);\n },\n\n async connect(): Promise<void> {\n await ensureConnected();\n },\n\n disconnect(): void {\n if (socket) {\n socket.close();\n socket = null;\n }\n connectionPromise = null;\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n setConnectionState('disconnected');\n },\n\n // =========================================================================\n // Streaming\n // =========================================================================\n\n async *trigger(triggerName, input) {\n await ensureConnected();\n\n eventQueue = [];\n isStreaming = true;\n\n socket!.send(\n JSON.stringify({\n type: 'trigger',\n triggerName,\n input,\n }),\n );\n\n while (true) {\n const event = await nextEvent();\n if (event === null) break;\n yield event;\n if (event.type === 'finish' || event.type === 'error') break;\n }\n },\n\n stop() {\n if (socket?.readyState === SOCKET_OPEN) {\n socket.send(JSON.stringify({ type: 'stop' }));\n }\n isStreaming = false;\n if (eventResolver) {\n eventResolver(null);\n eventResolver = null;\n }\n },\n };\n}\n","export {\n OctavusChat,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n} from './chat';\n\nexport { uploadFiles, type UploadFilesOptions, type UploadUrlsResponse } from './files';\n\nexport { parseSSEStream } from './stream/reader';\n\n// Transport exports\nexport {\n createHttpTransport,\n createSocketTransport,\n isSocketTransport,\n type Transport,\n type SocketTransport,\n type ConnectionState,\n type ConnectionStateListener,\n type HttpTransportOptions,\n type TriggerRequestOptions,\n type SocketLike,\n type SocketTransportOptions,\n} from './transports';\n\n// Re-export everything from core so consumers don't need to install @octavus/core separately\nexport * from '@octavus/core';\n"],"mappings":"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","names":["isAbortError","isAbortError","safeParseStreamEvent"]}
package/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "name": "@octavus/client-sdk",
3
- "version": "0.2.0",
3
+ "version": "1.0.0",
4
4
  "description": "Framework-agnostic client SDK for Octavus agents",
5
5
  "license": "MIT",
6
6
  "author": "Octavus AI <dev@octavus.ai>",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/octavus-ai/js-sdk.git",
10
+ "directory": "packages/client-sdk"
11
+ },
12
+ "homepage": "https://octavus.ai",
13
+ "bugs": {
14
+ "url": "https://github.com/octavus-ai/js-sdk/issues"
15
+ },
7
16
  "keywords": [
8
17
  "octavus",
9
18
  "ai",
10
19
  "agents",
11
20
  "sdk",
12
- "streaming"
21
+ "client",
22
+ "streaming",
23
+ "chat"
13
24
  ],
14
25
  "type": "module",
15
26
  "sideEffects": false,
@@ -28,7 +39,7 @@
28
39
  "access": "public"
29
40
  },
30
41
  "dependencies": {
31
- "@octavus/core": "^0.2.0"
42
+ "@octavus/core": "^1.0.0"
32
43
  },
33
44
  "devDependencies": {
34
45
  "tsup": "^8.3.5",