@octavus/client-sdk 2.11.0 → 2.13.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 CHANGED
@@ -134,6 +134,16 @@ chat.stop(); // Stops streaming and finalizes partial content
134
134
  ## File Uploads
135
135
 
136
136
  ```typescript
137
+ const chat = new OctavusChat({
138
+ transport,
139
+ requestUploadUrls, // Required for file uploads
140
+ uploadOptions: {
141
+ timeoutMs: 60_000, // Per-file timeout (default: 60s)
142
+ maxRetries: 2, // Retries on transient failures (default: 2)
143
+ retryDelayMs: 1_000, // Delay between retries (default: 1s)
144
+ },
145
+ });
146
+
137
147
  // Upload files separately (for progress tracking)
138
148
  const fileRefs = await chat.uploadFiles(fileInput.files, (index, progress) => {
139
149
  console.log(`File ${index}: ${progress}%`);
@@ -143,7 +153,7 @@ const fileRefs = await chat.uploadFiles(fileInput.files, (index, progress) => {
143
153
  await chat.send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });
144
154
  ```
145
155
 
146
- Note: File uploads require configuring `requestUploadUrls` in the chat options.
156
+ Uploads automatically retry on transient failures (network errors, timeouts, 5xx, 429). Non-retryable errors (4xx) fail immediately.
147
157
 
148
158
  ## Message Types
149
159
 
package/dist/index.d.ts CHANGED
@@ -2,6 +2,17 @@ import { StreamEvent, ToolResult, FileReference, UIMessage, OctavusError } from
2
2
  export * from '@octavus/core';
3
3
  export { AppError, ConflictError, ForbiddenError, MAIN_THREAD, NotFoundError, OCTAVUS_SKILL_TOOLS, OctavusError, ValidationError, createApiErrorEvent, createErrorEvent, createInternalErrorEvent, errorToStreamEvent, generateId, getSkillSlugFromToolCall, isAbortError, isAuthenticationError, isFileReference, isFileReferenceArray, isMainThread, isOctavusSkillTool, isOtherThread, isProviderError, isRateLimitError, isRetryableError, isToolError, isValidationError, resolveThread, safeParseStreamEvent, safeParseUIMessage, safeParseUIMessages, threadForPart } from '@octavus/core';
4
4
 
5
+ /**
6
+ * Options for trigger execution (e.g., retry with rollback).
7
+ */
8
+ interface TriggerOptions {
9
+ /**
10
+ * ID of the last message to keep in session state.
11
+ * Messages after this are removed before execution.
12
+ * Use `null` to truncate all messages (retry from empty history).
13
+ */
14
+ rollbackAfterMessageId?: string | null;
15
+ }
5
16
  /**
6
17
  * Transport interface for delivering events from server to client.
7
18
  *
@@ -14,8 +25,9 @@ interface Transport {
14
25
  * Trigger the agent and stream events.
15
26
  * @param triggerName - The trigger name defined in the agent's protocol
16
27
  * @param input - Input parameters for variable substitution
28
+ * @param options - Optional trigger options (e.g., rollback for retry)
17
29
  */
18
- trigger(triggerName: string, input?: Record<string, unknown>): AsyncIterable<StreamEvent>;
30
+ trigger(triggerName: string, input?: Record<string, unknown>, options?: TriggerOptions): AsyncIterable<StreamEvent>;
19
31
  /**
20
32
  * Continue execution with tool results after client-side tool handling.
21
33
  *
@@ -166,6 +178,12 @@ interface UploadFilesOptions {
166
178
  * @param progress - Progress percentage (0-100)
167
179
  */
168
180
  onProgress?: (fileIndex: number, progress: number) => void;
181
+ /** Upload timeout per file in milliseconds. Default: 60000 (60s). Set to 0 to disable. */
182
+ timeoutMs?: number;
183
+ /** Max retry attempts per file after initial failure. Default: 2. Set to 0 to disable retries. */
184
+ maxRetries?: number;
185
+ /** Delay between retries in milliseconds. Default: 1000 (1s). */
186
+ retryDelayMs?: number;
169
187
  }
170
188
  /**
171
189
  * Upload files to the Octavus platform.
@@ -175,6 +193,9 @@ interface UploadFilesOptions {
175
193
  * 2. Uploads each file directly to S3 with progress tracking
176
194
  * 3. Returns file references that can be used in trigger input
177
195
  *
196
+ * Uploads include automatic timeout (default 60s) and retry (default 2 retries)
197
+ * for transient failures like network errors or server issues.
198
+ *
178
199
  * @param files - Files to upload (from file input or drag/drop)
179
200
  * @param options - Upload configuration
180
201
  * @returns Array of file references with download URLs
@@ -291,6 +312,8 @@ interface OctavusChatOptions {
291
312
  * ```
292
313
  */
293
314
  requestUploadUrls?: UploadFilesOptions['requestUploadUrls'];
315
+ /** Upload timeout and retry configuration. Defaults: 60s timeout, 2 retries, 1s delay. */
316
+ uploadOptions?: Pick<UploadFilesOptions, 'timeoutMs' | 'maxRetries' | 'retryDelayMs'>;
294
317
  /**
295
318
  * Client-side tool handlers.
296
319
  * Register handlers for tools that should execute in the browser.
@@ -416,6 +439,7 @@ declare class OctavusChat {
416
439
  private _pendingExecutionId;
417
440
  private _readyToContinue;
418
441
  private _finishEventReceived;
442
+ private _lastTrigger;
419
443
  private listeners;
420
444
  constructor(options: OctavusChatOptions);
421
445
  /**
@@ -452,6 +476,11 @@ declare class OctavusChat {
452
476
  * ```
453
477
  */
454
478
  get pendingClientTools(): Record<string, InteractiveTool[]>;
479
+ /**
480
+ * Whether `retry()` can be called.
481
+ * True when a trigger has been sent and the chat is not currently streaming or awaiting input.
482
+ */
483
+ get canRetry(): boolean;
455
484
  /**
456
485
  * Subscribe to state changes. The callback is called whenever messages, status, or error changes.
457
486
  * @returns Unsubscribe function
@@ -488,6 +517,27 @@ declare class OctavusChat {
488
517
  send(triggerName: string, input?: Record<string, unknown>, sendOptions?: {
489
518
  userMessage?: UserMessageInput;
490
519
  }): Promise<void>;
520
+ /**
521
+ * Retry the last trigger from the same starting point.
522
+ * Rolls back messages to the state before the last trigger, re-adds the user message
523
+ * (if any), and re-executes. Files are not re-uploaded.
524
+ *
525
+ * No-op if no trigger has been sent yet.
526
+ *
527
+ * @example
528
+ * ```typescript
529
+ * // After an error or unsatisfactory result
530
+ * if (chat.canRetry) {
531
+ * await chat.retry();
532
+ * }
533
+ * ```
534
+ */
535
+ retry(): Promise<void>;
536
+ /**
537
+ * Shared streaming logic for `send()` and `retry()`.
538
+ * Sets up streaming state, consumes the transport stream, and handles errors.
539
+ */
540
+ private _executeTrigger;
491
541
  /**
492
542
  * Upload files directly without sending a message.
493
543
  * Useful for showing upload progress before sending.
@@ -570,6 +620,7 @@ interface TriggerRequest {
570
620
  type: 'trigger';
571
621
  triggerName: string;
572
622
  input?: Record<string, unknown>;
623
+ rollbackAfterMessageId?: string | null;
573
624
  }
574
625
  /** Continue execution after client-side tool handling */
575
626
  interface ContinueRequest {
@@ -746,4 +797,4 @@ interface SocketTransportOptions {
746
797
  */
747
798
  declare function createSocketTransport(options: SocketTransportOptions): SocketTransport;
748
799
 
749
- export { type ChatStatus, type ClientToolContext, type ClientToolHandler, type ConnectionState, type ConnectionStateListener, type ContinueRequest, type HttpRequest, type HttpRequestOptions, type HttpTransportOptions, type InteractiveTool, OctavusChat, type OctavusChatOptions, type SocketLike, type SocketTransport, type SocketTransportOptions, type Transport, type TriggerRequest, type UploadFilesOptions, type UploadUrlsResponse, type UserMessageInput, createHttpTransport, createSocketTransport, isSocketTransport, parseSSEStream, uploadFiles };
800
+ export { type ChatStatus, type ClientToolContext, type ClientToolHandler, type ConnectionState, type ConnectionStateListener, type ContinueRequest, type HttpRequest, type HttpRequestOptions, type HttpTransportOptions, type InteractiveTool, OctavusChat, type OctavusChatOptions, type SocketLike, type SocketTransport, type SocketTransportOptions, type Transport, type TriggerOptions, type TriggerRequest, type UploadFilesOptions, type UploadUrlsResponse, type UserMessageInput, createHttpTransport, createSocketTransport, isSocketTransport, parseSSEStream, uploadFiles };
package/dist/index.js CHANGED
@@ -7,9 +7,28 @@ import {
7
7
  } from "@octavus/core";
8
8
 
9
9
  // src/files.ts
10
- function uploadFileWithProgress(url, file, onProgress) {
10
+ var UPLOAD_DEFAULTS = {
11
+ timeoutMs: 6e4,
12
+ maxRetries: 2,
13
+ retryDelayMs: 1e3
14
+ };
15
+ var UploadError = class extends Error {
16
+ constructor(message, retryable, status) {
17
+ super(message);
18
+ this.retryable = retryable;
19
+ this.status = status;
20
+ this.name = "UploadError";
21
+ }
22
+ };
23
+ function uploadFileWithProgress(url, file, onProgress, timeoutMs) {
11
24
  return new Promise((resolve, reject) => {
12
25
  const xhr = new XMLHttpRequest();
26
+ if (timeoutMs !== void 0 && timeoutMs > 0) {
27
+ xhr.timeout = timeoutMs;
28
+ xhr.addEventListener("timeout", () => {
29
+ reject(new UploadError(`Upload timed out after ${timeoutMs}ms`, true));
30
+ });
31
+ }
13
32
  xhr.upload.addEventListener("progress", (event) => {
14
33
  if (event.lengthComputable) {
15
34
  const progress = Math.round(event.loaded / event.total * 100);
@@ -20,25 +39,59 @@ function uploadFileWithProgress(url, file, onProgress) {
20
39
  if (xhr.status >= 200 && xhr.status < 300) {
21
40
  resolve();
22
41
  } else {
23
- reject(new Error(`Upload failed with status ${xhr.status}`));
42
+ const detail = xhr.responseText ? `: ${xhr.responseText}` : "";
43
+ const retryable = xhr.status >= 500 || xhr.status === 429;
44
+ reject(
45
+ new UploadError(
46
+ `Upload failed with status ${xhr.status}${detail}`,
47
+ retryable,
48
+ xhr.status
49
+ )
50
+ );
24
51
  }
25
52
  });
26
53
  xhr.addEventListener("error", () => {
27
- reject(new Error("Upload failed: network error"));
54
+ reject(new UploadError("Upload failed: network error", true));
28
55
  });
29
56
  xhr.addEventListener("abort", () => {
30
- reject(new Error("Upload aborted"));
57
+ reject(new UploadError("Upload aborted", false));
31
58
  });
32
59
  xhr.open("PUT", url);
33
60
  xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
34
61
  xhr.send(file);
35
62
  });
36
63
  }
64
+ function delay(ms) {
65
+ return new Promise((resolve) => {
66
+ setTimeout(resolve, ms);
67
+ });
68
+ }
69
+ async function uploadFileWithRetry(url, file, onProgress, timeoutMs, maxRetries, retryDelayMs) {
70
+ let lastError;
71
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
72
+ try {
73
+ await uploadFileWithProgress(url, file, onProgress, timeoutMs);
74
+ return;
75
+ } catch (err) {
76
+ lastError = err;
77
+ const isRetryable = err instanceof UploadError && err.retryable;
78
+ if (!isRetryable || attempt >= maxRetries) {
79
+ break;
80
+ }
81
+ onProgress?.(0);
82
+ await delay(retryDelayMs);
83
+ }
84
+ }
85
+ throw lastError;
86
+ }
37
87
  async function uploadFiles(files, options) {
38
88
  const fileArray = Array.from(files);
39
89
  if (fileArray.length === 0) {
40
90
  return [];
41
91
  }
92
+ const timeoutMs = options.timeoutMs ?? UPLOAD_DEFAULTS.timeoutMs;
93
+ const maxRetries = options.maxRetries ?? UPLOAD_DEFAULTS.maxRetries;
94
+ const retryDelayMs = options.retryDelayMs ?? UPLOAD_DEFAULTS.retryDelayMs;
42
95
  const { files: uploadInfos } = await options.requestUploadUrls(
43
96
  fileArray.map((f) => ({
44
97
  filename: f.name,
@@ -50,9 +103,14 @@ async function uploadFiles(files, options) {
50
103
  for (let i = 0; i < fileArray.length; i++) {
51
104
  const file = fileArray[i];
52
105
  const uploadInfo = uploadInfos[i];
53
- await uploadFileWithProgress(uploadInfo.uploadUrl, file, (progress) => {
54
- options.onProgress?.(i, progress);
55
- });
106
+ await uploadFileWithRetry(
107
+ uploadInfo.uploadUrl,
108
+ file,
109
+ options.onProgress ? (progress) => options.onProgress(i, progress) : void 0,
110
+ timeoutMs,
111
+ maxRetries,
112
+ retryDelayMs
113
+ );
56
114
  references.push({
57
115
  id: uploadInfo.id,
58
116
  mediaType: file.type || "application/octet-stream",
@@ -235,6 +293,8 @@ var OctavusChat = class {
235
293
  // Flag indicating the finish event with client-tool-calls reason has been received
236
294
  // Used to handle the race condition where finish arrives before async tools complete
237
295
  _finishEventReceived = false;
296
+ // Last trigger snapshot for retry support
297
+ _lastTrigger = null;
238
298
  // Listener sets for reactive frameworks
239
299
  listeners = /* @__PURE__ */ new Set();
240
300
  constructor(options) {
@@ -289,6 +349,13 @@ var OctavusChat = class {
289
349
  get pendingClientTools() {
290
350
  return this._pendingClientToolsCache;
291
351
  }
352
+ /**
353
+ * Whether `retry()` can be called.
354
+ * True when a trigger has been sent and the chat is not currently streaming or awaiting input.
355
+ */
356
+ get canRetry() {
357
+ return this._lastTrigger !== null && this._status !== "streaming" && this._status !== "awaiting-input";
358
+ }
292
359
  // =========================================================================
293
360
  // Subscription Methods (for reactive frameworks)
294
361
  // =========================================================================
@@ -366,7 +433,8 @@ var OctavusChat = class {
366
433
  fileRefs = files;
367
434
  } else if (this.options.requestUploadUrls) {
368
435
  fileRefs = await uploadFiles(files, {
369
- requestUploadUrls: this.options.requestUploadUrls
436
+ requestUploadUrls: this.options.requestUploadUrls,
437
+ ...this.options.uploadOptions
370
438
  });
371
439
  } else {
372
440
  throw new Error(
@@ -379,16 +447,61 @@ var OctavusChat = class {
379
447
  if (this.options.requestUploadUrls) {
380
448
  const inputFiles = input.FILES;
381
449
  const uploadedRefs = fileRefs ?? await uploadFiles(inputFiles, {
382
- requestUploadUrls: this.options.requestUploadUrls
450
+ requestUploadUrls: this.options.requestUploadUrls,
451
+ ...this.options.uploadOptions
383
452
  });
384
453
  processedInput = { ...input, FILES: uploadedRefs };
385
454
  fileRefs = fileRefs ?? uploadedRefs;
386
455
  }
387
456
  }
457
+ const currentMessages = this._messages;
458
+ this._lastTrigger = {
459
+ triggerName,
460
+ input: processedInput,
461
+ sendOptions: sendOptions?.userMessage ? { userMessage: { content: sendOptions.userMessage.content, files: fileRefs } } : void 0,
462
+ rollbackAfterMessageId: currentMessages[currentMessages.length - 1]?.id ?? null,
463
+ messageCount: currentMessages.length
464
+ };
388
465
  if (sendOptions?.userMessage !== void 0) {
389
466
  const userMsg = createUserMessage(sendOptions.userMessage, fileRefs);
390
467
  this.setMessages([...this._messages, userMsg]);
391
468
  }
469
+ await this._executeTrigger(triggerName, processedInput);
470
+ }
471
+ /**
472
+ * Retry the last trigger from the same starting point.
473
+ * Rolls back messages to the state before the last trigger, re-adds the user message
474
+ * (if any), and re-executes. Files are not re-uploaded.
475
+ *
476
+ * No-op if no trigger has been sent yet.
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * // After an error or unsatisfactory result
481
+ * if (chat.canRetry) {
482
+ * await chat.retry();
483
+ * }
484
+ * ```
485
+ */
486
+ async retry() {
487
+ if (!this._lastTrigger) return;
488
+ this.transport.stop();
489
+ const { triggerName, input, sendOptions, rollbackAfterMessageId, messageCount } = this._lastTrigger;
490
+ const baseMessages = this._messages.slice(0, messageCount);
491
+ if (sendOptions?.userMessage) {
492
+ const fileRefs = sendOptions.userMessage.files;
493
+ const userMsg = createUserMessage(sendOptions.userMessage, fileRefs);
494
+ this.setMessages([...baseMessages, userMsg]);
495
+ } else {
496
+ this.setMessages(baseMessages);
497
+ }
498
+ await this._executeTrigger(triggerName, input, { rollbackAfterMessageId });
499
+ }
500
+ /**
501
+ * Shared streaming logic for `send()` and `retry()`.
502
+ * Sets up streaming state, consumes the transport stream, and handles errors.
503
+ */
504
+ async _executeTrigger(triggerName, input, triggerOptions) {
392
505
  this.setStatus("streaming");
393
506
  this.setError(null);
394
507
  this.streamingState = createEmptyStreamingState();
@@ -401,7 +514,7 @@ var OctavusChat = class {
401
514
  this._finishEventReceived = false;
402
515
  this.updatePendingClientToolsCache();
403
516
  try {
404
- for await (const event of this.transport.trigger(triggerName, processedInput)) {
517
+ for await (const event of this.transport.trigger(triggerName, input, triggerOptions)) {
405
518
  if (this.streamingState === null) break;
406
519
  this.handleStreamEvent(event, this.streamingState);
407
520
  }
@@ -466,7 +579,8 @@ var OctavusChat = class {
466
579
  }
467
580
  return await uploadFiles(files, {
468
581
  requestUploadUrls: this.options.requestUploadUrls,
469
- onProgress
582
+ onProgress,
583
+ ...this.options.uploadOptions
470
584
  });
471
585
  }
472
586
  /**
@@ -579,6 +693,9 @@ var OctavusChat = class {
579
693
  if (event.executionId) {
580
694
  this.options.onStart?.(event.executionId);
581
695
  }
696
+ if (event.lastMessageId !== void 0 && this._lastTrigger) {
697
+ this._lastTrigger.rollbackAfterMessageId = event.lastMessageId;
698
+ }
582
699
  break;
583
700
  case "block-start": {
584
701
  const workerId = event.workerId;
@@ -1526,12 +1643,13 @@ function createHttpTransport(options) {
1526
1643
  }
1527
1644
  }
1528
1645
  return {
1529
- async *trigger(triggerName, input) {
1646
+ async *trigger(triggerName, input, triggerOptions) {
1530
1647
  abortController = new AbortController();
1531
- const response = options.request(
1532
- { type: "trigger", triggerName, input },
1533
- { signal: abortController.signal }
1534
- );
1648
+ const request = { type: "trigger", triggerName, input };
1649
+ if (triggerOptions?.rollbackAfterMessageId !== void 0) {
1650
+ request.rollbackAfterMessageId = triggerOptions.rollbackAfterMessageId;
1651
+ }
1652
+ const response = options.request(request, { signal: abortController.signal });
1535
1653
  yield* streamResponse(response);
1536
1654
  },
1537
1655
  async *continueWithToolResults(executionId, toolResults) {
@@ -1669,18 +1787,16 @@ function createSocketTransport(options) {
1669
1787
  // =========================================================================
1670
1788
  // Streaming
1671
1789
  // =========================================================================
1672
- async *trigger(triggerName, input) {
1790
+ async *trigger(triggerName, input, triggerOptions) {
1673
1791
  await ensureConnected();
1674
1792
  eventQueue = [];
1675
1793
  eventResolver = null;
1676
1794
  isStreaming = true;
1677
- socket.send(
1678
- JSON.stringify({
1679
- type: "trigger",
1680
- triggerName,
1681
- input
1682
- })
1683
- );
1795
+ const message = { type: "trigger", triggerName, input };
1796
+ if (triggerOptions?.rollbackAfterMessageId !== void 0) {
1797
+ message.rollbackAfterMessageId = triggerOptions.rollbackAfterMessageId;
1798
+ }
1799
+ socket.send(JSON.stringify(message));
1684
1800
  while (true) {
1685
1801
  const event = await nextEvent();
1686
1802
  if (event === null) break;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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 UIWorkerPart,\n type DisplayMode,\n type StreamEvent,\n type FileReference,\n type PendingToolCall,\n type ToolResult,\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' | 'awaiting-input';\n\n/**\n * Context provided to client tool handlers.\n */\nexport interface ClientToolContext {\n /** Unique identifier for this tool call */\n toolCallId: string;\n /** Name of the tool being called */\n toolName: string;\n /** Signal for cancellation if user stops generation */\n signal: AbortSignal;\n /**\n * Register a file produced by this tool (e.g., a screenshot).\n * Files are sent to the platform alongside the tool result so the LLM\n * can see them as visual content rather than just a JSON URL.\n */\n addFile: (file: FileReference) => void;\n}\n\n/**\n * Handler function for client-side tool execution.\n * Can be:\n * - An async function that executes automatically and returns a result\n * - The string 'interactive' to indicate the tool requires user interaction\n */\nexport type ClientToolHandler =\n | ((args: Record<string, unknown>, ctx: ClientToolContext) => Promise<unknown>)\n | 'interactive';\n\n/**\n * Interactive tool call awaiting user interaction.\n * The `submit` and `cancel` methods are pre-bound to this tool call's ID.\n */\nexport interface InteractiveTool {\n /** Unique identifier for this tool call */\n toolCallId: string;\n /** Name of the tool being called */\n toolName: string;\n /** Arguments passed to the tool */\n args: Record<string, unknown>;\n /**\n * Submit a result for this tool call.\n * Call this when the user has provided input.\n *\n * @param result - The result from user interaction\n */\n submit: (result: unknown) => void;\n /**\n * Cancel this tool call with an optional reason.\n * Call this when the user dismisses the UI without providing input.\n *\n * @param reason - Optional reason for cancellation (default: 'User cancelled')\n */\n cancel: (reason?: string) => void;\n}\n\n/**\n * Internal pending tool state (before binding submit/cancel).\n */\ninterface PendingToolState {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n source?: 'llm' | 'block';\n outputVariable?: string;\n blockIndex?: number;\n thread?: string;\n /** Worker ID if this tool call is from a worker execution */\n workerId?: string;\n}\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 /**\n * Client-side tool handlers.\n * Register handlers for tools that should execute in the browser.\n *\n * - If a tool has a handler function: executes automatically\n * - If a tool is marked as 'interactive': appears in `pendingClientTools` with bound `submit()`/`cancel()`\n *\n * @example Automatic client tool\n * ```typescript\n * clientTools: {\n * 'get-browser-location': async () => {\n * const pos = await new Promise((resolve, reject) => {\n * navigator.geolocation.getCurrentPosition(resolve, reject);\n * });\n * return { lat: pos.coords.latitude, lng: pos.coords.longitude };\n * },\n * }\n * ```\n *\n * @example Interactive client tool (user input required)\n * ```typescript\n * clientTools: {\n * 'request-feedback': 'interactive',\n * }\n * // Then render UI based on pendingClientTools['request-feedback']\n * // and call tool.submit(result) or tool.cancel()\n * ```\n */\n clientTools?: Record<string, ClientToolHandler>;\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 * Callback when execution starts with the session/execution ID.\n * Useful for tracking the current execution for activity logs.\n *\n * @example\n * ```typescript\n * onStart: (sessionId) => {\n * setCurrentSessionId(sessionId);\n * }\n * ```\n */\n onStart?: (sessionId: string) => 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\n/** Tracks state for a worker part being populated */\ninterface WorkerPartState {\n partIndex: number;\n currentTextPartIndex: number | null;\n currentReasoningPartIndex: number | null;\n currentObjectPartIndex: number | null;\n accumulatedJson: string;\n /** Accumulated raw JSON text per tool call ID for progressive partial parsing */\n toolInputBuffers: Map<string, string>;\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 /** Active workers being populated: workerId -> worker state */\n activeWorkers: Map<string, WorkerPartState>;\n /** Accumulated raw JSON text per tool call ID for progressive partial parsing */\n toolInputBuffers: Map<string, 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 (escaped) {\n // If input ends with a dangling backslash, complete the escape sequence.\n fixed += '\\\\';\n }\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 activeWorkers: new Map(),\n toolInputBuffers: new Map(),\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 * Finalize parts when stream is stopped or errors.\n * Marks streaming parts as done, pending/running tools as cancelled,\n * and recursively finalizes worker parts.\n */\nfunction finalizeParts(parts: UIMessagePart[], workerError?: string): UIMessagePart[] {\n return parts.map((part): UIMessagePart => {\n if (part.type === 'text' || part.type === 'reasoning') {\n if (part.status === 'streaming') {\n return { ...part, status: 'done' };\n }\n }\n if (part.type === 'object' && part.status === 'streaming') {\n return { ...part, status: 'done' };\n }\n if (part.type === 'tool-call') {\n if (part.status === 'pending' || part.status === 'running') {\n return { ...part, status: 'cancelled' };\n }\n }\n if (part.type === 'operation' && part.status === 'running') {\n return { ...part, status: 'cancelled' };\n }\n if (part.type === 'worker' && part.status === 'running') {\n return {\n ...part,\n status: 'error',\n error: workerError,\n parts: finalizeParts(part.parts), // Recursive for nested parts\n };\n }\n return part;\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 * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\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 // Client tool state\n // Keyed by toolName -> array of pending tools for that name\n private _pendingToolsByName = new Map<string, PendingToolState[]>();\n // Keyed by toolCallId -> pending tool state (for internal lookup when submitting)\n private _pendingToolsByCallId = new Map<string, PendingToolState>();\n // Cache for React useSyncExternalStore compatibility\n private _pendingClientToolsCache: Record<string, InteractiveTool[]> = {};\n private _completedToolResults: ToolResult[] = [];\n private _clientToolAbortController: AbortController | null = null;\n // Server tool results from mixed server+client tools (for continuation)\n private _serverToolResults: ToolResult[] = [];\n // Execution ID for continuation (from client-tool-request event)\n private _pendingExecutionId: string | null = null;\n // Flag indicating automatic client tools have completed and are ready to continue\n // We wait for the finish event before actually continuing to avoid race conditions\n private _readyToContinue = false;\n // Flag indicating the finish event with client-tool-calls reason has been received\n // Used to handle the race condition where finish arrives before async tools complete\n private _finishEventReceived = false;\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 * Update mutable options (callbacks and tool handlers) without recreating the instance.\n * Used by the React hook to keep options fresh across renders, but can also be\n * called directly by non-React consumers.\n *\n * `transport` and `initialMessages` are excluded since they're only consumed at construction time.\n */\n updateOptions(updates: Partial<Omit<OctavusChatOptions, 'transport' | 'initialMessages'>>): void {\n this.options = { ...this.options, ...updates };\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 * Pending interactive tool calls keyed by tool name.\n * Each tool has bound `submit()` and `cancel()` methods.\n *\n * @example\n * ```tsx\n * const feedbackTools = pendingClientTools['request-feedback'] ?? [];\n *\n * {feedbackTools.map(tool => (\n * <FeedbackModal\n * key={tool.toolCallId}\n * {...tool.args}\n * onSubmit={(result) => tool.submit(result)}\n * onCancel={() => tool.cancel()}\n * />\n * ))}\n * ```\n */\n get pendingClientTools(): Record<string, InteractiveTool[]> {\n return this._pendingClientToolsCache;\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 private updatePendingClientToolsCache(): void {\n const cache: Record<string, InteractiveTool[]> = {};\n for (const [toolName, tools] of this._pendingToolsByName.entries()) {\n cache[toolName] = tools.map((tool) => ({\n toolCallId: tool.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n submit: (result: unknown) => this.submitToolResult(tool.toolCallId, result),\n cancel: (reason?: string) =>\n this.submitToolResult(tool.toolCallId, undefined, reason ?? 'User cancelled'),\n }));\n }\n this._pendingClientToolsCache = cache;\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 // Clear any previous client tool state\n this._pendingToolsByName.clear();\n this._pendingToolsByCallId.clear();\n this._completedToolResults = [];\n this._serverToolResults = [];\n this._pendingExecutionId = null;\n this._readyToContinue = false;\n this._finishEventReceived = false;\n this.updatePendingClientToolsCache();\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\n // Finalize any streaming message before setting error state\n const state = this.streamingState;\n if (state !== null) {\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n\n if (state.parts.length > 0) {\n const finalParts = finalizeParts(state.parts, 'Stream error');\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 if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n } else if (lastMsg?.id === state.messageId) {\n // No parts yet - remove the empty streaming message\n messages.pop();\n this.setMessages(messages);\n }\n }\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 /**\n * Internal: Submit a result for a pending tool.\n * Called by bound submit/cancel methods on InteractiveTool.\n */\n private submitToolResult(toolCallId: string, result?: unknown, error?: string): void {\n const pendingTool = this._pendingToolsByCallId.get(toolCallId);\n if (!pendingTool) {\n // Tool not found - may have been cancelled or already resolved\n return;\n }\n\n // Remove from both maps\n this._pendingToolsByCallId.delete(toolCallId);\n const toolsForName = this._pendingToolsByName.get(pendingTool.toolName);\n if (toolsForName) {\n const filtered = toolsForName.filter((t) => t.toolCallId !== toolCallId);\n if (filtered.length === 0) {\n this._pendingToolsByName.delete(pendingTool.toolName);\n } else {\n this._pendingToolsByName.set(pendingTool.toolName, filtered);\n }\n }\n this.updatePendingClientToolsCache();\n\n const toolResult: ToolResult = {\n toolCallId,\n toolName: pendingTool.toolName,\n result: error ? undefined : result,\n error,\n outputVariable: pendingTool.outputVariable,\n blockIndex: pendingTool.blockIndex,\n thread: pendingTool.thread,\n workerId: pendingTool.workerId,\n };\n this._completedToolResults.push(toolResult);\n\n if (error) {\n this.emitToolOutputError(toolCallId, error);\n } else {\n this.emitToolOutputAvailable(toolCallId, result);\n }\n\n if (this._pendingToolsByCallId.size === 0) {\n void this.continueWithClientToolResults();\n }\n\n this.notifyListeners();\n }\n\n /** Stop the current streaming and finalize any partial message */\n stop(): void {\n if (this._status !== 'streaming' && this._status !== 'awaiting-input') {\n return;\n }\n\n this._clientToolAbortController?.abort();\n this._clientToolAbortController = null;\n this._pendingToolsByName.clear();\n this._pendingToolsByCallId.clear();\n this._completedToolResults = [];\n this._serverToolResults = [];\n this._pendingExecutionId = null;\n this._readyToContinue = false;\n this._finishEventReceived = false;\n this.updatePendingClientToolsCache();\n\n this.transport.stop();\n\n const state = this.streamingState;\n if (state && state.parts.length > 0) {\n const finalParts = finalizeParts(state.parts, 'Stopped by user');\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 /**\n * IMMUTABILITY RULES — all event handlers must follow these patterns:\n *\n * 1. Never mutate an existing part/message object. Some environments (e.g.\n * React Native with Reanimated) freeze objects between renders, so\n * mutations silently fail or throw.\n *\n * 2. Always create a new object via spread and assign it back:\n * GOOD: state.parts[i] = { ...part, text: part.text + delta };\n * BAD: part.text += delta; state.parts[i] = { ...part };\n *\n * 3. For nested worker parts, copy the parts array too:\n * const updatedParts = [...workerPart.parts];\n * updatedParts[i] = { ...part, status: 'done' };\n * state.parts[wi] = { ...workerPart, parts: updatedParts };\n *\n * 4. For the messages array, copy before mutating:\n * const messages = [...this._messages];\n * messages[i] = newMessage; // or messages.pop()\n * this.setMessages(messages);\n */\n private handleStreamEvent(event: StreamEvent, state: StreamingState): void {\n switch (event.type) {\n case 'start':\n // Call onStart callback with execution/session ID\n if (event.executionId) {\n this.options.onStart?.(event.executionId);\n }\n break;\n\n case 'block-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\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\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, operationPart],\n };\n } else {\n state.parts.push(operationPart);\n }\n }\n\n state.currentTextPartIndex = null;\n state.currentReasoningPartIndex = null;\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'block-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Find operation in worker's nested parts\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const operationPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'operation' && p.operationId === event.blockId,\n );\n if (operationPartIndex >= 0) {\n const part = workerPart.parts[operationPartIndex] as UIOperationPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[operationPartIndex] = { ...part, status: 'done' };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\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\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 workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n const reasoningPart: UIReasoningPart = {\n type: 'reasoning',\n text: '',\n status: 'streaming',\n thread: threadForPart(state.activeBlock?.thread),\n };\n\n if (workerState) {\n // Add to worker's nested parts\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, reasoningPart];\n workerState.currentReasoningPartIndex = newParts.length - 1;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(reasoningPart);\n state.currentReasoningPartIndex = state.parts.length - 1;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Update worker's reasoning part\n if (workerState.currentReasoningPartIndex !== null) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const part = workerPart.parts[workerState.currentReasoningPartIndex] as UIReasoningPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentReasoningPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n state.parts[state.currentReasoningPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n }\n\n if (state.activeBlock) {\n state.activeBlock.reasoning += event.delta;\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Finalize worker's reasoning part\n if (workerState.currentReasoningPartIndex !== null) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const part = workerPart.parts[workerState.currentReasoningPartIndex] as UIReasoningPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentReasoningPartIndex] = {\n ...part,\n status: 'done',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n workerState.currentReasoningPartIndex = null;\n }\n } else if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n state.parts[state.currentReasoningPartIndex] = { ...part, status: 'done' };\n state.currentReasoningPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n const thread = threadForPart(state.activeBlock?.thread);\n const shouldAddPart = state.activeBlock?.outputToChat !== false || thread !== undefined;\n\n // For worker events, always add parts\n if (workerState || 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 if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, objectPart];\n workerState.currentObjectPartIndex = newParts.length - 1;\n workerState.accumulatedJson = '';\n workerState.currentTextPartIndex = null;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(objectPart);\n state.currentObjectPartIndex = state.parts.length - 1;\n state.accumulatedJson = '';\n state.currentTextPartIndex = null;\n }\n } else {\n const textPart: UITextPart = {\n type: 'text',\n text: '',\n status: 'streaming',\n thread,\n };\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, textPart];\n workerState.currentTextPartIndex = newParts.length - 1;\n workerState.currentObjectPartIndex = null;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(textPart);\n state.currentTextPartIndex = state.parts.length - 1;\n state.currentObjectPartIndex = null;\n }\n }\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Update worker's text or object part\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n if (workerState.currentObjectPartIndex !== null) {\n workerState.accumulatedJson += event.delta;\n const part = workerPart.parts[workerState.currentObjectPartIndex] as UIObjectPart;\n const parsed = parsePartialJson(workerState.accumulatedJson);\n if (parsed !== undefined) {\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentObjectPartIndex] = { ...part, partial: parsed };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else if (workerState.currentTextPartIndex !== null) {\n const part = workerPart.parts[workerState.currentTextPartIndex] as UITextPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentTextPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\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 state.parts[state.currentObjectPartIndex] = { ...part, partial: parsed };\n }\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n state.parts[state.currentTextPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n }\n\n if (state.activeBlock) {\n state.activeBlock.text += event.delta;\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Finalize worker's text or object part\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const updatedParts = [...workerPart.parts];\n if (workerState.currentObjectPartIndex !== null) {\n const part = workerPart.parts[workerState.currentObjectPartIndex] as UIObjectPart;\n try {\n const finalObject = JSON.parse(workerState.accumulatedJson) as unknown;\n updatedParts[workerState.currentObjectPartIndex] = {\n ...part,\n object: finalObject,\n partial: finalObject,\n status: 'done',\n };\n } catch {\n updatedParts[workerState.currentObjectPartIndex] = {\n ...part,\n status: 'error',\n error: 'Failed to parse response as JSON',\n };\n }\n workerState.currentObjectPartIndex = null;\n workerState.accumulatedJson = '';\n } else if (workerState.currentTextPartIndex !== null) {\n const part = workerPart.parts[workerState.currentTextPartIndex] as UITextPart;\n updatedParts[workerState.currentTextPartIndex] = {\n ...part,\n status: 'done',\n };\n workerState.currentTextPartIndex = null;\n }\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n } else 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 state.parts[state.currentObjectPartIndex] = {\n ...part,\n object: finalObject,\n partial: finalObject,\n status: 'done',\n };\n } catch {\n state.parts[state.currentObjectPartIndex] = {\n ...part,\n status: 'error',\n error: 'Failed to parse response as JSON',\n };\n }\n state.currentObjectPartIndex = null;\n state.accumulatedJson = '';\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n state.parts[state.currentTextPartIndex] = { ...part, status: 'done' };\n state.currentTextPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n const toolPart: UIToolCallPart = {\n type: 'tool-call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n displayName: event.title,\n args: {},\n result: undefined,\n error: undefined,\n status: 'pending',\n thread: threadForPart(state.activeBlock?.thread),\n };\n\n // Initialize the input buffer for this tool call\n if (workerState) {\n workerState.toolInputBuffers.set(event.toolCallId, '');\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, toolPart],\n };\n } else {\n state.toolInputBuffers.set(event.toolCallId, '');\n state.parts.push(toolPart);\n\n if (state.activeBlock) {\n state.activeBlock.toolCalls.set(event.toolCallId, toolPart);\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Accumulate the delta into the worker's buffer\n const existing = workerState.toolInputBuffers.get(event.toolCallId) ?? '';\n const accumulated = existing + event.inputTextDelta;\n workerState.toolInputBuffers.set(event.toolCallId, accumulated);\n\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const toolPart = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const parsed = parsePartialJson(accumulated);\n if (parsed !== undefined) {\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...toolPart,\n args: parsed as Record<string, unknown>,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n }\n } else {\n // Accumulate the delta into the top-level buffer\n const existing = state.toolInputBuffers.get(event.toolCallId) ?? '';\n const accumulated = existing + event.inputTextDelta;\n state.toolInputBuffers.set(event.toolCallId, accumulated);\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const toolPart = state.parts[toolPartIndex] as UIToolCallPart;\n const parsed = parsePartialJson(accumulated);\n if (parsed !== undefined) {\n state.parts[toolPartIndex] = {\n ...toolPart,\n args: parsed as Record<string, unknown>,\n };\n this.updateStreamingMessage();\n }\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 workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Clean up the worker buffer\n workerState.toolInputBuffers.delete(event.toolCallId);\n\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n args: event.input as Record<string, unknown>,\n status: 'running',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\n // Clean up the top-level buffer\n state.toolInputBuffers.delete(event.toolCallId);\n\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 state.parts[toolPartIndex] = {\n ...part,\n args: event.input as Record<string, unknown>,\n status: 'running',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'tool-output-available': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n result: event.output,\n status: 'done',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\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 state.parts[toolPartIndex] = {\n ...part,\n result: event.output,\n status: 'done',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'tool-output-error': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n error: event.error,\n status: 'error',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\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 state.parts[toolPartIndex] = {\n ...part,\n error: event.error,\n status: 'error',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'source': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\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 if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, sourcePart],\n };\n } else {\n state.parts.push(sourcePart);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'file-available': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\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\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, filePart],\n };\n } else {\n state.parts.push(filePart);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'resource-update':\n this.options.onResourceUpdate?.(event.name, event.value);\n break;\n\n case 'worker-start': {\n // Check if worker with same workerId already exists (for continuations)\n const existingIndex = state.parts.findIndex(\n (p) => p.type === 'worker' && p.workerId === event.workerId,\n );\n\n let partIndex: number;\n if (existingIndex !== -1) {\n // Re-use existing worker part (continuation)\n const existingPart = state.parts[existingIndex] as UIWorkerPart;\n state.parts[existingIndex] = { ...existingPart, status: 'running' };\n partIndex = existingIndex;\n } else {\n // Create a new worker part\n const workerPart: UIWorkerPart = {\n type: 'worker',\n workerId: event.workerId,\n workerSlug: event.workerSlug,\n description: event.description,\n parts: [],\n status: 'running',\n };\n state.parts.push(workerPart);\n partIndex = state.parts.length - 1;\n }\n\n // Track the worker for event routing\n const workerState: WorkerPartState = {\n partIndex,\n currentTextPartIndex: null,\n currentReasoningPartIndex: null,\n currentObjectPartIndex: null,\n accumulatedJson: '',\n toolInputBuffers: new Map(),\n };\n state.activeWorkers.set(event.workerId, workerState);\n this.updateStreamingMessage();\n break;\n }\n\n case 'worker-result': {\n const workerState = state.activeWorkers.get(event.workerId);\n if (workerState !== undefined) {\n const part = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...part,\n output: event.output,\n error: event.error,\n status: event.error ? 'error' : 'done',\n parts: part.parts.map((p): UIMessagePart => {\n if (p.type === 'text' || p.type === 'reasoning') {\n if (p.status === 'streaming') {\n return { ...p, status: 'done' };\n }\n }\n if (p.type === 'object' && p.status === 'streaming') {\n return { ...p, status: 'done' };\n }\n return p;\n }),\n };\n state.activeWorkers.delete(event.workerId);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'finish': {\n // Handle client-tool-calls finish reason\n if (event.finishReason === 'client-tool-calls') {\n // Mark that finish event has been received (for async tools that complete later)\n this._finishEventReceived = true;\n // Don't finalize message - we're waiting for client tools\n if (this._pendingToolsByCallId.size > 0) {\n this.setStatus('awaiting-input');\n } else if (this._readyToContinue) {\n // Automatic tools completed before finish event arrived - continue now\n this._readyToContinue = false;\n this._finishEventReceived = false;\n void this.continueWithClientToolResults();\n }\n return;\n }\n\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 const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n\n if (finalMessage.parts.length > 0) {\n if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n } else if (lastMsg?.id === state.messageId) {\n // No parts produced — remove the empty streaming message\n messages.pop();\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 case 'client-tool-request':\n // Store execution ID and server tool results for continuation\n this._pendingExecutionId = event.executionId;\n this._serverToolResults = event.serverToolResults ?? [];\n // Handle client-side tool execution\n void this.handleClientToolRequest(event.toolCalls, state);\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 /**\n * Emit a tool-output-available event for a client tool result.\n */\n private emitToolOutputAvailable(toolCallId: string, output: unknown): void {\n const state = this.streamingState;\n if (!state) return;\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n state.parts[toolPartIndex] = {\n ...part,\n result: output,\n status: 'done',\n };\n this.updateStreamingMessage();\n }\n }\n\n /**\n * Emit a tool-output-error event for a client tool result.\n */\n private emitToolOutputError(toolCallId: string, error: string): void {\n const state = this.streamingState;\n if (!state) return;\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n state.parts[toolPartIndex] = {\n ...part,\n error,\n status: 'error',\n };\n this.updateStreamingMessage();\n }\n }\n\n /**\n * Continue execution with collected client tool results.\n */\n private async continueWithClientToolResults(): Promise<void> {\n if (this._completedToolResults.length === 0) return;\n\n if (this._pendingExecutionId === null) {\n // Context lost - this shouldn't happen, but handle gracefully\n const errorObj = new OctavusError({\n errorType: 'internal_error',\n message: 'Cannot continue execution: execution ID was lost.',\n source: 'client',\n retryable: false,\n });\n this.setError(errorObj);\n this.setStatus('error');\n this.options.onError?.(errorObj);\n return;\n }\n\n // Combine server results (from mixed tools scenario) with client results\n const allResults = [...this._serverToolResults, ...this._completedToolResults];\n const executionId = this._pendingExecutionId;\n this._serverToolResults = [];\n this._completedToolResults = [];\n this._pendingExecutionId = null;\n\n this.setStatus('streaming');\n\n try {\n // Use the transport's continuation method (works for both HTTP and Socket)\n for await (const event of this.transport.continueWithToolResults(executionId, allResults)) {\n if (this.streamingState === null) break;\n this.handleStreamEvent(event, this.streamingState);\n }\n } catch (err) {\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\n this.setError(errorObj);\n this.setStatus('error');\n this.streamingState = null;\n this.options.onError?.(errorObj);\n }\n }\n\n /**\n * Handle client tool request event.\n *\n * IMPORTANT: Interactive tools must be registered synchronously (before any await)\n * to avoid a race condition where the finish event is processed before tools are added.\n */\n private async handleClientToolRequest(\n toolCalls: PendingToolCall[],\n state: StreamingState,\n ): Promise<void> {\n this._clientToolAbortController = new AbortController();\n\n // FIRST PASS: Register all interactive tools synchronously (no await)\n // This ensures pending tools are populated before finish event is processed\n for (const tc of toolCalls) {\n const handler = this.options.clientTools?.[tc.toolName];\n if (handler === 'interactive') {\n const toolState: PendingToolState = {\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n args: tc.args,\n source: tc.source,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n };\n // Add to both maps\n this._pendingToolsByCallId.set(tc.toolCallId, toolState);\n const existing = this._pendingToolsByName.get(tc.toolName) ?? [];\n this._pendingToolsByName.set(tc.toolName, [...existing, toolState]);\n }\n }\n if (this._pendingToolsByCallId.size > 0) {\n this.updatePendingClientToolsCache();\n }\n\n // SECOND PASS: Execute automatic handlers and handle missing handlers\n for (const tc of toolCalls) {\n const handler = this.options.clientTools?.[tc.toolName];\n\n if (handler === 'interactive') {\n // Already registered above, just update UI state\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === tc.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n // Keep running status - user will see the tool is \"executing\" while modal is open\n state.parts[toolPartIndex] = { ...part };\n }\n } else if (handler) {\n try {\n const collectedFiles: FileReference[] = [];\n const result = await handler(tc.args, {\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n signal: this._clientToolAbortController.signal,\n addFile: (file) => collectedFiles.push(file),\n });\n\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n result,\n files: collectedFiles.length > 0 ? collectedFiles : undefined,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputAvailable(tc.toolCallId, result);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Tool execution failed';\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n error: errorMessage,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputError(tc.toolCallId, errorMessage);\n }\n } else {\n // No handler registered - treat as error\n const errorMessage = `No client handler for tool: ${tc.toolName}`;\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n error: errorMessage,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputError(tc.toolCallId, errorMessage);\n }\n }\n\n // If no interactive tools, mark as ready to continue.\n // We wait for the finish event to arrive first to avoid a race condition where\n // the finish event gets delivered to the continuation's event resolver.\n if (this._pendingToolsByCallId.size === 0 && this._completedToolResults.length > 0) {\n this._readyToContinue = true;\n\n // If finish event already arrived while we were executing async tools,\n // trigger continuation now instead of waiting forever\n if (this._finishEventReceived) {\n this._readyToContinue = false;\n this._finishEventReceived = false;\n void this.continueWithClientToolResults();\n }\n }\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, ToolResult } 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 /**\n * Continue execution with tool results after client-side tool handling.\n *\n * @param executionId - The execution ID from the client-tool-request event\n * @param results - All tool results (server + client) to send\n */\n continueWithToolResults(executionId: string, results: ToolResult[]): 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, type ToolResult } from '@octavus/core';\nimport { parseSSEStream } from '@/stream/reader';\nimport type { Transport } from './types';\n\n// =============================================================================\n// Request Types\n// =============================================================================\n\n/** Start a new trigger execution */\nexport interface TriggerRequest {\n type: 'trigger';\n triggerName: string;\n input?: Record<string, unknown>;\n}\n\n/** Continue execution after client-side tool handling */\nexport interface ContinueRequest {\n type: 'continue';\n executionId: string;\n toolResults: ToolResult[];\n}\n\n/** All request types supported by the HTTP transport */\nexport type HttpRequest = TriggerRequest | ContinueRequest;\n\n// =============================================================================\n// Transport Options\n// =============================================================================\n\n/** Request options passed to the request callback */\nexport interface HttpRequestOptions {\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 requests to your backend.\n * Receives a discriminated union with `type` to identify the request kind.\n *\n * @param request - The request payload (check `request.type` for the kind)\n * @param options - Request options including abort signal\n * @returns Response with SSE stream body\n *\n * @example\n * ```typescript\n * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\n * })\n * ```\n */\n request: (request: HttpRequest, options?: HttpRequestOptions) => Promise<Response>;\n}\n\n// =============================================================================\n// Transport Implementation\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 * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\n * }),\n * });\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions): Transport {\n let abortController: AbortController | null = null;\n\n async function* streamResponse(responsePromise: Promise<Response>) {\n try {\n const response = await responsePromise;\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 if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n }\n\n return {\n async *trigger(triggerName, input) {\n abortController = new AbortController();\n const response = options.request(\n { type: 'trigger', triggerName, input },\n { signal: abortController.signal },\n );\n yield* streamResponse(response);\n },\n\n async *continueWithToolResults(executionId, toolResults) {\n abortController = new AbortController();\n const response = options.request(\n { type: 'continue', executionId, toolResults },\n { signal: abortController.signal },\n );\n yield* streamResponse(response);\n },\n\n stop() {\n abortController?.abort();\n abortController = null;\n },\n };\n}\n","import { safeParseStreamEvent, type StreamEvent, type ToolResult } 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 eventResolver = null; // Clear any pending resolver\n isStreaming = true;\n\n // Note: clientToolResults not sent here - socket uses sendClientToolResults() for continuation\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 * Continue execution with tool results after client-side tool handling.\n * @param executionId - The execution ID from the client-tool-request event\n * @param toolResults - All tool results (server + client) to send\n */\n async *continueWithToolResults(executionId: string, toolResults: ToolResult[]) {\n await ensureConnected();\n\n eventQueue = [];\n eventResolver = null; // Clear any pending resolver from previous operation\n isStreaming = true;\n\n socket!.send(\n JSON.stringify({\n type: 'continue',\n executionId,\n toolResults,\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}\n","export {\n OctavusChat,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\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 HttpRequestOptions,\n type HttpRequest,\n type TriggerRequest,\n type ContinueRequest,\n type SocketLike,\n type SocketTransportOptions,\n} from './transports';\n\nexport type * from '@octavus/core';\nexport {\n // Error classes\n AppError,\n NotFoundError,\n ValidationError,\n ConflictError,\n ForbiddenError,\n OctavusError,\n // Error type guards\n isRateLimitError,\n isAuthenticationError,\n isProviderError,\n isToolError,\n isRetryableError,\n isValidationError,\n // Error event helpers\n createErrorEvent,\n errorToStreamEvent,\n createInternalErrorEvent,\n createApiErrorEvent,\n // Utilities\n generateId,\n isAbortError,\n // Thread helpers\n MAIN_THREAD,\n resolveThread,\n isMainThread,\n threadForPart,\n isOtherThread,\n // Type guards\n isFileReference,\n isFileReferenceArray,\n // Safe parse helpers\n safeParseStreamEvent,\n safeParseUIMessage,\n safeParseUIMessages,\n // Skills\n OCTAVUS_SKILL_TOOLS,\n isOctavusSkillTool,\n getSkillSlugFromToolCall,\n} from '@octavus/core';\n"],"mappings":"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","names":["isAbortError","isAbortError","safeParseStreamEvent","OctavusError","generateId","isAbortError","threadForPart","isFileReferenceArray","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 UIWorkerPart,\n type DisplayMode,\n type StreamEvent,\n type FileReference,\n type PendingToolCall,\n type ToolResult,\n} from '@octavus/core';\nimport type { Transport, TriggerOptions } 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' | 'awaiting-input';\n\n/**\n * Context provided to client tool handlers.\n */\nexport interface ClientToolContext {\n /** Unique identifier for this tool call */\n toolCallId: string;\n /** Name of the tool being called */\n toolName: string;\n /** Signal for cancellation if user stops generation */\n signal: AbortSignal;\n /**\n * Register a file produced by this tool (e.g., a screenshot).\n * Files are sent to the platform alongside the tool result so the LLM\n * can see them as visual content rather than just a JSON URL.\n */\n addFile: (file: FileReference) => void;\n}\n\n/**\n * Handler function for client-side tool execution.\n * Can be:\n * - An async function that executes automatically and returns a result\n * - The string 'interactive' to indicate the tool requires user interaction\n */\nexport type ClientToolHandler =\n | ((args: Record<string, unknown>, ctx: ClientToolContext) => Promise<unknown>)\n | 'interactive';\n\n/**\n * Interactive tool call awaiting user interaction.\n * The `submit` and `cancel` methods are pre-bound to this tool call's ID.\n */\nexport interface InteractiveTool {\n /** Unique identifier for this tool call */\n toolCallId: string;\n /** Name of the tool being called */\n toolName: string;\n /** Arguments passed to the tool */\n args: Record<string, unknown>;\n /**\n * Submit a result for this tool call.\n * Call this when the user has provided input.\n *\n * @param result - The result from user interaction\n */\n submit: (result: unknown) => void;\n /**\n * Cancel this tool call with an optional reason.\n * Call this when the user dismisses the UI without providing input.\n *\n * @param reason - Optional reason for cancellation (default: 'User cancelled')\n */\n cancel: (reason?: string) => void;\n}\n\n/**\n * Internal pending tool state (before binding submit/cancel).\n */\ninterface PendingToolState {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n source?: 'llm' | 'block';\n outputVariable?: string;\n blockIndex?: number;\n thread?: string;\n /** Worker ID if this tool call is from a worker execution */\n workerId?: string;\n}\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 /** Upload timeout and retry configuration. Defaults: 60s timeout, 2 retries, 1s delay. */\n uploadOptions?: Pick<UploadFilesOptions, 'timeoutMs' | 'maxRetries' | 'retryDelayMs'>;\n\n /**\n * Client-side tool handlers.\n * Register handlers for tools that should execute in the browser.\n *\n * - If a tool has a handler function: executes automatically\n * - If a tool is marked as 'interactive': appears in `pendingClientTools` with bound `submit()`/`cancel()`\n *\n * @example Automatic client tool\n * ```typescript\n * clientTools: {\n * 'get-browser-location': async () => {\n * const pos = await new Promise((resolve, reject) => {\n * navigator.geolocation.getCurrentPosition(resolve, reject);\n * });\n * return { lat: pos.coords.latitude, lng: pos.coords.longitude };\n * },\n * }\n * ```\n *\n * @example Interactive client tool (user input required)\n * ```typescript\n * clientTools: {\n * 'request-feedback': 'interactive',\n * }\n * // Then render UI based on pendingClientTools['request-feedback']\n * // and call tool.submit(result) or tool.cancel()\n * ```\n */\n clientTools?: Record<string, ClientToolHandler>;\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 * Callback when execution starts with the session/execution ID.\n * Useful for tracking the current execution for activity logs.\n *\n * @example\n * ```typescript\n * onStart: (sessionId) => {\n * setCurrentSessionId(sessionId);\n * }\n * ```\n */\n onStart?: (sessionId: string) => 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\n/** Tracks state for a worker part being populated */\ninterface WorkerPartState {\n partIndex: number;\n currentTextPartIndex: number | null;\n currentReasoningPartIndex: number | null;\n currentObjectPartIndex: number | null;\n accumulatedJson: string;\n /** Accumulated raw JSON text per tool call ID for progressive partial parsing */\n toolInputBuffers: Map<string, string>;\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 /** Active workers being populated: workerId -> worker state */\n activeWorkers: Map<string, WorkerPartState>;\n /** Accumulated raw JSON text per tool call ID for progressive partial parsing */\n toolInputBuffers: Map<string, 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 (escaped) {\n // If input ends with a dangling backslash, complete the escape sequence.\n fixed += '\\\\';\n }\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 activeWorkers: new Map(),\n toolInputBuffers: new Map(),\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 * Finalize parts when stream is stopped or errors.\n * Marks streaming parts as done, pending/running tools as cancelled,\n * and recursively finalizes worker parts.\n */\nfunction finalizeParts(parts: UIMessagePart[], workerError?: string): UIMessagePart[] {\n return parts.map((part): UIMessagePart => {\n if (part.type === 'text' || part.type === 'reasoning') {\n if (part.status === 'streaming') {\n return { ...part, status: 'done' };\n }\n }\n if (part.type === 'object' && part.status === 'streaming') {\n return { ...part, status: 'done' };\n }\n if (part.type === 'tool-call') {\n if (part.status === 'pending' || part.status === 'running') {\n return { ...part, status: 'cancelled' };\n }\n }\n if (part.type === 'operation' && part.status === 'running') {\n return { ...part, status: 'cancelled' };\n }\n if (part.type === 'worker' && part.status === 'running') {\n return {\n ...part,\n status: 'error',\n error: workerError,\n parts: finalizeParts(part.parts), // Recursive for nested parts\n };\n }\n return part;\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 * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\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 // Client tool state\n // Keyed by toolName -> array of pending tools for that name\n private _pendingToolsByName = new Map<string, PendingToolState[]>();\n // Keyed by toolCallId -> pending tool state (for internal lookup when submitting)\n private _pendingToolsByCallId = new Map<string, PendingToolState>();\n // Cache for React useSyncExternalStore compatibility\n private _pendingClientToolsCache: Record<string, InteractiveTool[]> = {};\n private _completedToolResults: ToolResult[] = [];\n private _clientToolAbortController: AbortController | null = null;\n // Server tool results from mixed server+client tools (for continuation)\n private _serverToolResults: ToolResult[] = [];\n // Execution ID for continuation (from client-tool-request event)\n private _pendingExecutionId: string | null = null;\n // Flag indicating automatic client tools have completed and are ready to continue\n // We wait for the finish event before actually continuing to avoid race conditions\n private _readyToContinue = false;\n // Flag indicating the finish event with client-tool-calls reason has been received\n // Used to handle the race condition where finish arrives before async tools complete\n private _finishEventReceived = false;\n\n // Last trigger snapshot for retry support\n private _lastTrigger: {\n triggerName: string;\n input?: Record<string, unknown>;\n sendOptions?: { userMessage?: UserMessageInput };\n rollbackAfterMessageId: string | null;\n messageCount: number;\n } | 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 * Update mutable options (callbacks and tool handlers) without recreating the instance.\n * Used by the React hook to keep options fresh across renders, but can also be\n * called directly by non-React consumers.\n *\n * `transport` and `initialMessages` are excluded since they're only consumed at construction time.\n */\n updateOptions(updates: Partial<Omit<OctavusChatOptions, 'transport' | 'initialMessages'>>): void {\n this.options = { ...this.options, ...updates };\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 * Pending interactive tool calls keyed by tool name.\n * Each tool has bound `submit()` and `cancel()` methods.\n *\n * @example\n * ```tsx\n * const feedbackTools = pendingClientTools['request-feedback'] ?? [];\n *\n * {feedbackTools.map(tool => (\n * <FeedbackModal\n * key={tool.toolCallId}\n * {...tool.args}\n * onSubmit={(result) => tool.submit(result)}\n * onCancel={() => tool.cancel()}\n * />\n * ))}\n * ```\n */\n get pendingClientTools(): Record<string, InteractiveTool[]> {\n return this._pendingClientToolsCache;\n }\n\n /**\n * Whether `retry()` can be called.\n * True when a trigger has been sent and the chat is not currently streaming or awaiting input.\n */\n get canRetry(): boolean {\n return (\n this._lastTrigger !== null &&\n this._status !== 'streaming' &&\n this._status !== 'awaiting-input'\n );\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 private updatePendingClientToolsCache(): void {\n const cache: Record<string, InteractiveTool[]> = {};\n for (const [toolName, tools] of this._pendingToolsByName.entries()) {\n cache[toolName] = tools.map((tool) => ({\n toolCallId: tool.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n submit: (result: unknown) => this.submitToolResult(tool.toolCallId, result),\n cancel: (reason?: string) =>\n this.submitToolResult(tool.toolCallId, undefined, reason ?? 'User cancelled'),\n }));\n }\n this._pendingClientToolsCache = cache;\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 ...this.options.uploadOptions,\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 ...this.options.uploadOptions,\n }));\n processedInput = { ...input, FILES: uploadedRefs };\n fileRefs = fileRefs ?? uploadedRefs;\n }\n }\n\n // Store trigger snapshot for retry (after file processing, before message changes).\n // sendOptions is stored with resolved FileReference[] so retry skips re-upload.\n const currentMessages = this._messages;\n this._lastTrigger = {\n triggerName,\n input: processedInput,\n sendOptions: sendOptions?.userMessage\n ? { userMessage: { content: sendOptions.userMessage.content, files: fileRefs } }\n : undefined,\n rollbackAfterMessageId: currentMessages[currentMessages.length - 1]?.id ?? null,\n messageCount: currentMessages.length,\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 await this._executeTrigger(triggerName, processedInput);\n }\n\n /**\n * Retry the last trigger from the same starting point.\n * Rolls back messages to the state before the last trigger, re-adds the user message\n * (if any), and re-executes. Files are not re-uploaded.\n *\n * No-op if no trigger has been sent yet.\n *\n * @example\n * ```typescript\n * // After an error or unsatisfactory result\n * if (chat.canRetry) {\n * await chat.retry();\n * }\n * ```\n */\n async retry(): Promise<void> {\n if (!this._lastTrigger) return;\n\n this.transport.stop();\n\n const { triggerName, input, sendOptions, rollbackAfterMessageId, messageCount } =\n this._lastTrigger;\n\n // Roll back UI messages to pre-trigger state\n const baseMessages = this._messages.slice(0, messageCount);\n\n // Re-add optimistic user message (files are already FileReference[])\n if (sendOptions?.userMessage) {\n const fileRefs = sendOptions.userMessage.files as FileReference[] | undefined;\n const userMsg = createUserMessage(sendOptions.userMessage, fileRefs);\n this.setMessages([...baseMessages, userMsg]);\n } else {\n this.setMessages(baseMessages);\n }\n\n await this._executeTrigger(triggerName, input, { rollbackAfterMessageId });\n }\n\n /**\n * Shared streaming logic for `send()` and `retry()`.\n * Sets up streaming state, consumes the transport stream, and handles errors.\n */\n private async _executeTrigger(\n triggerName: string,\n input?: Record<string, unknown>,\n triggerOptions?: TriggerOptions,\n ): Promise<void> {\n this.setStatus('streaming');\n this.setError(null);\n this.streamingState = createEmptyStreamingState();\n\n // Clear any previous client tool state\n this._pendingToolsByName.clear();\n this._pendingToolsByCallId.clear();\n this._completedToolResults = [];\n this._serverToolResults = [];\n this._pendingExecutionId = null;\n this._readyToContinue = false;\n this._finishEventReceived = false;\n this.updatePendingClientToolsCache();\n\n try {\n for await (const event of this.transport.trigger(triggerName, input, triggerOptions)) {\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\n // Finalize any streaming message before setting error state\n const state = this.streamingState;\n if (state !== null) {\n const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n\n if (state.parts.length > 0) {\n const finalParts = finalizeParts(state.parts, 'Stream error');\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 if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n } else if (lastMsg?.id === state.messageId) {\n // No parts yet - remove the empty streaming message\n messages.pop();\n this.setMessages(messages);\n }\n }\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 ...this.options.uploadOptions,\n });\n }\n\n /**\n * Internal: Submit a result for a pending tool.\n * Called by bound submit/cancel methods on InteractiveTool.\n */\n private submitToolResult(toolCallId: string, result?: unknown, error?: string): void {\n const pendingTool = this._pendingToolsByCallId.get(toolCallId);\n if (!pendingTool) {\n // Tool not found - may have been cancelled or already resolved\n return;\n }\n\n // Remove from both maps\n this._pendingToolsByCallId.delete(toolCallId);\n const toolsForName = this._pendingToolsByName.get(pendingTool.toolName);\n if (toolsForName) {\n const filtered = toolsForName.filter((t) => t.toolCallId !== toolCallId);\n if (filtered.length === 0) {\n this._pendingToolsByName.delete(pendingTool.toolName);\n } else {\n this._pendingToolsByName.set(pendingTool.toolName, filtered);\n }\n }\n this.updatePendingClientToolsCache();\n\n const toolResult: ToolResult = {\n toolCallId,\n toolName: pendingTool.toolName,\n result: error ? undefined : result,\n error,\n outputVariable: pendingTool.outputVariable,\n blockIndex: pendingTool.blockIndex,\n thread: pendingTool.thread,\n workerId: pendingTool.workerId,\n };\n this._completedToolResults.push(toolResult);\n\n if (error) {\n this.emitToolOutputError(toolCallId, error);\n } else {\n this.emitToolOutputAvailable(toolCallId, result);\n }\n\n if (this._pendingToolsByCallId.size === 0) {\n void this.continueWithClientToolResults();\n }\n\n this.notifyListeners();\n }\n\n /** Stop the current streaming and finalize any partial message */\n stop(): void {\n if (this._status !== 'streaming' && this._status !== 'awaiting-input') {\n return;\n }\n\n this._clientToolAbortController?.abort();\n this._clientToolAbortController = null;\n this._pendingToolsByName.clear();\n this._pendingToolsByCallId.clear();\n this._completedToolResults = [];\n this._serverToolResults = [];\n this._pendingExecutionId = null;\n this._readyToContinue = false;\n this._finishEventReceived = false;\n this.updatePendingClientToolsCache();\n\n this.transport.stop();\n\n const state = this.streamingState;\n if (state && state.parts.length > 0) {\n const finalParts = finalizeParts(state.parts, 'Stopped by user');\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 /**\n * IMMUTABILITY RULES — all event handlers must follow these patterns:\n *\n * 1. Never mutate an existing part/message object. Some environments (e.g.\n * React Native with Reanimated) freeze objects between renders, so\n * mutations silently fail or throw.\n *\n * 2. Always create a new object via spread and assign it back:\n * GOOD: state.parts[i] = { ...part, text: part.text + delta };\n * BAD: part.text += delta; state.parts[i] = { ...part };\n *\n * 3. For nested worker parts, copy the parts array too:\n * const updatedParts = [...workerPart.parts];\n * updatedParts[i] = { ...part, status: 'done' };\n * state.parts[wi] = { ...workerPart, parts: updatedParts };\n *\n * 4. For the messages array, copy before mutating:\n * const messages = [...this._messages];\n * messages[i] = newMessage; // or messages.pop()\n * this.setMessages(messages);\n */\n private handleStreamEvent(event: StreamEvent, state: StreamingState): void {\n switch (event.type) {\n case 'start':\n if (event.executionId) {\n this.options.onStart?.(event.executionId);\n }\n // Sync rollback anchor with server-side message ID for accurate retry\n if (event.lastMessageId !== undefined && this._lastTrigger) {\n this._lastTrigger.rollbackAfterMessageId = event.lastMessageId;\n }\n break;\n\n case 'block-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\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\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, operationPart],\n };\n } else {\n state.parts.push(operationPart);\n }\n }\n\n state.currentTextPartIndex = null;\n state.currentReasoningPartIndex = null;\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'block-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Find operation in worker's nested parts\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const operationPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'operation' && p.operationId === event.blockId,\n );\n if (operationPartIndex >= 0) {\n const part = workerPart.parts[operationPartIndex] as UIOperationPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[operationPartIndex] = { ...part, status: 'done' };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\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\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 workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n const reasoningPart: UIReasoningPart = {\n type: 'reasoning',\n text: '',\n status: 'streaming',\n thread: threadForPart(state.activeBlock?.thread),\n };\n\n if (workerState) {\n // Add to worker's nested parts\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, reasoningPart];\n workerState.currentReasoningPartIndex = newParts.length - 1;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(reasoningPart);\n state.currentReasoningPartIndex = state.parts.length - 1;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Update worker's reasoning part\n if (workerState.currentReasoningPartIndex !== null) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const part = workerPart.parts[workerState.currentReasoningPartIndex] as UIReasoningPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentReasoningPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\n if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n state.parts[state.currentReasoningPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n }\n\n if (state.activeBlock) {\n state.activeBlock.reasoning += event.delta;\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'reasoning-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Finalize worker's reasoning part\n if (workerState.currentReasoningPartIndex !== null) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const part = workerPart.parts[workerState.currentReasoningPartIndex] as UIReasoningPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentReasoningPartIndex] = {\n ...part,\n status: 'done',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n workerState.currentReasoningPartIndex = null;\n }\n } else if (state.currentReasoningPartIndex !== null) {\n const part = state.parts[state.currentReasoningPartIndex] as UIReasoningPart;\n state.parts[state.currentReasoningPartIndex] = { ...part, status: 'done' };\n state.currentReasoningPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n const thread = threadForPart(state.activeBlock?.thread);\n const shouldAddPart = state.activeBlock?.outputToChat !== false || thread !== undefined;\n\n // For worker events, always add parts\n if (workerState || 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 if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, objectPart];\n workerState.currentObjectPartIndex = newParts.length - 1;\n workerState.accumulatedJson = '';\n workerState.currentTextPartIndex = null;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(objectPart);\n state.currentObjectPartIndex = state.parts.length - 1;\n state.accumulatedJson = '';\n state.currentTextPartIndex = null;\n }\n } else {\n const textPart: UITextPart = {\n type: 'text',\n text: '',\n status: 'streaming',\n thread,\n };\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const newParts = [...workerPart.parts, textPart];\n workerState.currentTextPartIndex = newParts.length - 1;\n workerState.currentObjectPartIndex = null;\n state.parts[workerState.partIndex] = { ...workerPart, parts: newParts };\n } else {\n state.parts.push(textPart);\n state.currentTextPartIndex = state.parts.length - 1;\n state.currentObjectPartIndex = null;\n }\n }\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Update worker's text or object part\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n if (workerState.currentObjectPartIndex !== null) {\n workerState.accumulatedJson += event.delta;\n const part = workerPart.parts[workerState.currentObjectPartIndex] as UIObjectPart;\n const parsed = parsePartialJson(workerState.accumulatedJson);\n if (parsed !== undefined) {\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentObjectPartIndex] = { ...part, partial: parsed };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else if (workerState.currentTextPartIndex !== null) {\n const part = workerPart.parts[workerState.currentTextPartIndex] as UITextPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[workerState.currentTextPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n }\n } else {\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 state.parts[state.currentObjectPartIndex] = { ...part, partial: parsed };\n }\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n state.parts[state.currentTextPartIndex] = {\n ...part,\n text: part.text + event.delta,\n };\n }\n\n if (state.activeBlock) {\n state.activeBlock.text += event.delta;\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'text-end': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Finalize worker's text or object part\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const updatedParts = [...workerPart.parts];\n if (workerState.currentObjectPartIndex !== null) {\n const part = workerPart.parts[workerState.currentObjectPartIndex] as UIObjectPart;\n try {\n const finalObject = JSON.parse(workerState.accumulatedJson) as unknown;\n updatedParts[workerState.currentObjectPartIndex] = {\n ...part,\n object: finalObject,\n partial: finalObject,\n status: 'done',\n };\n } catch {\n updatedParts[workerState.currentObjectPartIndex] = {\n ...part,\n status: 'error',\n error: 'Failed to parse response as JSON',\n };\n }\n workerState.currentObjectPartIndex = null;\n workerState.accumulatedJson = '';\n } else if (workerState.currentTextPartIndex !== null) {\n const part = workerPart.parts[workerState.currentTextPartIndex] as UITextPart;\n updatedParts[workerState.currentTextPartIndex] = {\n ...part,\n status: 'done',\n };\n workerState.currentTextPartIndex = null;\n }\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n } else 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 state.parts[state.currentObjectPartIndex] = {\n ...part,\n object: finalObject,\n partial: finalObject,\n status: 'done',\n };\n } catch {\n state.parts[state.currentObjectPartIndex] = {\n ...part,\n status: 'error',\n error: 'Failed to parse response as JSON',\n };\n }\n state.currentObjectPartIndex = null;\n state.accumulatedJson = '';\n } else if (state.currentTextPartIndex !== null) {\n const part = state.parts[state.currentTextPartIndex] as UITextPart;\n state.parts[state.currentTextPartIndex] = { ...part, status: 'done' };\n state.currentTextPartIndex = null;\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-start': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n const toolPart: UIToolCallPart = {\n type: 'tool-call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n displayName: event.title,\n args: {},\n result: undefined,\n error: undefined,\n status: 'pending',\n thread: threadForPart(state.activeBlock?.thread),\n };\n\n // Initialize the input buffer for this tool call\n if (workerState) {\n workerState.toolInputBuffers.set(event.toolCallId, '');\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, toolPart],\n };\n } else {\n state.toolInputBuffers.set(event.toolCallId, '');\n state.parts.push(toolPart);\n\n if (state.activeBlock) {\n state.activeBlock.toolCalls.set(event.toolCallId, toolPart);\n }\n }\n\n this.updateStreamingMessage();\n break;\n }\n\n case 'tool-input-delta': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Accumulate the delta into the worker's buffer\n const existing = workerState.toolInputBuffers.get(event.toolCallId) ?? '';\n const accumulated = existing + event.inputTextDelta;\n workerState.toolInputBuffers.set(event.toolCallId, accumulated);\n\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const toolPart = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const parsed = parsePartialJson(accumulated);\n if (parsed !== undefined) {\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...toolPart,\n args: parsed as Record<string, unknown>,\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n }\n } else {\n // Accumulate the delta into the top-level buffer\n const existing = state.toolInputBuffers.get(event.toolCallId) ?? '';\n const accumulated = existing + event.inputTextDelta;\n state.toolInputBuffers.set(event.toolCallId, accumulated);\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const toolPart = state.parts[toolPartIndex] as UIToolCallPart;\n const parsed = parsePartialJson(accumulated);\n if (parsed !== undefined) {\n state.parts[toolPartIndex] = {\n ...toolPart,\n args: parsed as Record<string, unknown>,\n };\n this.updateStreamingMessage();\n }\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 workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n // Clean up the worker buffer\n workerState.toolInputBuffers.delete(event.toolCallId);\n\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n args: event.input as Record<string, unknown>,\n status: 'running',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\n // Clean up the top-level buffer\n state.toolInputBuffers.delete(event.toolCallId);\n\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 state.parts[toolPartIndex] = {\n ...part,\n args: event.input as Record<string, unknown>,\n status: 'running',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'tool-output-available': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n result: event.output,\n status: 'done',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\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 state.parts[toolPartIndex] = {\n ...part,\n result: event.output,\n status: 'done',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'tool-output-error': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n const toolPartIndex = workerPart.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === event.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = workerPart.parts[toolPartIndex] as UIToolCallPart;\n const updatedParts = [...workerPart.parts];\n updatedParts[toolPartIndex] = {\n ...part,\n error: event.error,\n status: 'error',\n };\n state.parts[workerState.partIndex] = { ...workerPart, parts: updatedParts };\n this.updateStreamingMessage();\n }\n } else {\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 state.parts[toolPartIndex] = {\n ...part,\n error: event.error,\n status: 'error',\n };\n this.updateStreamingMessage();\n }\n }\n break;\n }\n\n case 'source': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\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 if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, sourcePart],\n };\n } else {\n state.parts.push(sourcePart);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'file-available': {\n const workerId = event.workerId;\n const workerState = workerId ? state.activeWorkers.get(workerId) : undefined;\n\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\n if (workerState) {\n const workerPart = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...workerPart,\n parts: [...workerPart.parts, filePart],\n };\n } else {\n state.parts.push(filePart);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'resource-update':\n this.options.onResourceUpdate?.(event.name, event.value);\n break;\n\n case 'worker-start': {\n // Check if worker with same workerId already exists (for continuations)\n const existingIndex = state.parts.findIndex(\n (p) => p.type === 'worker' && p.workerId === event.workerId,\n );\n\n let partIndex: number;\n if (existingIndex !== -1) {\n // Re-use existing worker part (continuation)\n const existingPart = state.parts[existingIndex] as UIWorkerPart;\n state.parts[existingIndex] = { ...existingPart, status: 'running' };\n partIndex = existingIndex;\n } else {\n // Create a new worker part\n const workerPart: UIWorkerPart = {\n type: 'worker',\n workerId: event.workerId,\n workerSlug: event.workerSlug,\n description: event.description,\n parts: [],\n status: 'running',\n };\n state.parts.push(workerPart);\n partIndex = state.parts.length - 1;\n }\n\n // Track the worker for event routing\n const workerState: WorkerPartState = {\n partIndex,\n currentTextPartIndex: null,\n currentReasoningPartIndex: null,\n currentObjectPartIndex: null,\n accumulatedJson: '',\n toolInputBuffers: new Map(),\n };\n state.activeWorkers.set(event.workerId, workerState);\n this.updateStreamingMessage();\n break;\n }\n\n case 'worker-result': {\n const workerState = state.activeWorkers.get(event.workerId);\n if (workerState !== undefined) {\n const part = state.parts[workerState.partIndex] as UIWorkerPart;\n state.parts[workerState.partIndex] = {\n ...part,\n output: event.output,\n error: event.error,\n status: event.error ? 'error' : 'done',\n parts: part.parts.map((p): UIMessagePart => {\n if (p.type === 'text' || p.type === 'reasoning') {\n if (p.status === 'streaming') {\n return { ...p, status: 'done' };\n }\n }\n if (p.type === 'object' && p.status === 'streaming') {\n return { ...p, status: 'done' };\n }\n return p;\n }),\n };\n state.activeWorkers.delete(event.workerId);\n }\n this.updateStreamingMessage();\n break;\n }\n\n case 'finish': {\n // Handle client-tool-calls finish reason\n if (event.finishReason === 'client-tool-calls') {\n // Mark that finish event has been received (for async tools that complete later)\n this._finishEventReceived = true;\n // Don't finalize message - we're waiting for client tools\n if (this._pendingToolsByCallId.size > 0) {\n this.setStatus('awaiting-input');\n } else if (this._readyToContinue) {\n // Automatic tools completed before finish event arrived - continue now\n this._readyToContinue = false;\n this._finishEventReceived = false;\n void this.continueWithClientToolResults();\n }\n return;\n }\n\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 const messages = [...this._messages];\n const lastMsg = messages[messages.length - 1];\n\n if (finalMessage.parts.length > 0) {\n if (lastMsg?.id === state.messageId) {\n messages[messages.length - 1] = finalMessage;\n } else {\n messages.push(finalMessage);\n }\n this.setMessages(messages);\n } else if (lastMsg?.id === state.messageId) {\n // No parts produced — remove the empty streaming message\n messages.pop();\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 case 'client-tool-request':\n // Store execution ID and server tool results for continuation\n this._pendingExecutionId = event.executionId;\n this._serverToolResults = event.serverToolResults ?? [];\n // Handle client-side tool execution\n void this.handleClientToolRequest(event.toolCalls, state);\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 /**\n * Emit a tool-output-available event for a client tool result.\n */\n private emitToolOutputAvailable(toolCallId: string, output: unknown): void {\n const state = this.streamingState;\n if (!state) return;\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n state.parts[toolPartIndex] = {\n ...part,\n result: output,\n status: 'done',\n };\n this.updateStreamingMessage();\n }\n }\n\n /**\n * Emit a tool-output-error event for a client tool result.\n */\n private emitToolOutputError(toolCallId: string, error: string): void {\n const state = this.streamingState;\n if (!state) return;\n\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n state.parts[toolPartIndex] = {\n ...part,\n error,\n status: 'error',\n };\n this.updateStreamingMessage();\n }\n }\n\n /**\n * Continue execution with collected client tool results.\n */\n private async continueWithClientToolResults(): Promise<void> {\n if (this._completedToolResults.length === 0) return;\n\n if (this._pendingExecutionId === null) {\n // Context lost - this shouldn't happen, but handle gracefully\n const errorObj = new OctavusError({\n errorType: 'internal_error',\n message: 'Cannot continue execution: execution ID was lost.',\n source: 'client',\n retryable: false,\n });\n this.setError(errorObj);\n this.setStatus('error');\n this.options.onError?.(errorObj);\n return;\n }\n\n // Combine server results (from mixed tools scenario) with client results\n const allResults = [...this._serverToolResults, ...this._completedToolResults];\n const executionId = this._pendingExecutionId;\n this._serverToolResults = [];\n this._completedToolResults = [];\n this._pendingExecutionId = null;\n\n this.setStatus('streaming');\n\n try {\n // Use the transport's continuation method (works for both HTTP and Socket)\n for await (const event of this.transport.continueWithToolResults(executionId, allResults)) {\n if (this.streamingState === null) break;\n this.handleStreamEvent(event, this.streamingState);\n }\n } catch (err) {\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\n this.setError(errorObj);\n this.setStatus('error');\n this.streamingState = null;\n this.options.onError?.(errorObj);\n }\n }\n\n /**\n * Handle client tool request event.\n *\n * IMPORTANT: Interactive tools must be registered synchronously (before any await)\n * to avoid a race condition where the finish event is processed before tools are added.\n */\n private async handleClientToolRequest(\n toolCalls: PendingToolCall[],\n state: StreamingState,\n ): Promise<void> {\n this._clientToolAbortController = new AbortController();\n\n // FIRST PASS: Register all interactive tools synchronously (no await)\n // This ensures pending tools are populated before finish event is processed\n for (const tc of toolCalls) {\n const handler = this.options.clientTools?.[tc.toolName];\n if (handler === 'interactive') {\n const toolState: PendingToolState = {\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n args: tc.args,\n source: tc.source,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n };\n // Add to both maps\n this._pendingToolsByCallId.set(tc.toolCallId, toolState);\n const existing = this._pendingToolsByName.get(tc.toolName) ?? [];\n this._pendingToolsByName.set(tc.toolName, [...existing, toolState]);\n }\n }\n if (this._pendingToolsByCallId.size > 0) {\n this.updatePendingClientToolsCache();\n }\n\n // SECOND PASS: Execute automatic handlers and handle missing handlers\n for (const tc of toolCalls) {\n const handler = this.options.clientTools?.[tc.toolName];\n\n if (handler === 'interactive') {\n // Already registered above, just update UI state\n const toolPartIndex = state.parts.findIndex(\n (p: UIMessagePart) => p.type === 'tool-call' && p.toolCallId === tc.toolCallId,\n );\n if (toolPartIndex >= 0) {\n const part = state.parts[toolPartIndex] as UIToolCallPart;\n // Keep running status - user will see the tool is \"executing\" while modal is open\n state.parts[toolPartIndex] = { ...part };\n }\n } else if (handler) {\n try {\n const collectedFiles: FileReference[] = [];\n const result = await handler(tc.args, {\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n signal: this._clientToolAbortController.signal,\n addFile: (file) => collectedFiles.push(file),\n });\n\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n result,\n files: collectedFiles.length > 0 ? collectedFiles : undefined,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputAvailable(tc.toolCallId, result);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Tool execution failed';\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n error: errorMessage,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputError(tc.toolCallId, errorMessage);\n }\n } else {\n // No handler registered - treat as error\n const errorMessage = `No client handler for tool: ${tc.toolName}`;\n this._completedToolResults.push({\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n error: errorMessage,\n outputVariable: tc.outputVariable,\n blockIndex: tc.blockIndex,\n thread: tc.thread,\n workerId: tc.workerId,\n });\n\n this.emitToolOutputError(tc.toolCallId, errorMessage);\n }\n }\n\n // If no interactive tools, mark as ready to continue.\n // We wait for the finish event to arrive first to avoid a race condition where\n // the finish event gets delivered to the continuation's event resolver.\n if (this._pendingToolsByCallId.size === 0 && this._completedToolResults.length > 0) {\n this._readyToContinue = true;\n\n // If finish event already arrived while we were executing async tools,\n // trigger continuation now instead of waiting forever\n if (this._finishEventReceived) {\n this._readyToContinue = false;\n this._finishEventReceived = false;\n void this.continueWithClientToolResults();\n }\n }\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 /** Upload timeout per file in milliseconds. Default: 60000 (60s). Set to 0 to disable. */\n timeoutMs?: number;\n\n /** Max retry attempts per file after initial failure. Default: 2. Set to 0 to disable retries. */\n maxRetries?: number;\n\n /** Delay between retries in milliseconds. Default: 1000 (1s). */\n retryDelayMs?: number;\n}\n\nconst UPLOAD_DEFAULTS = {\n timeoutMs: 60_000,\n maxRetries: 2,\n retryDelayMs: 1_000,\n} as const;\n\nclass UploadError extends Error {\n constructor(\n message: string,\n readonly retryable: boolean,\n readonly status?: number,\n ) {\n super(message);\n this.name = 'UploadError';\n }\n}\n\n/**\n * Upload a single file to S3 with progress tracking and timeout.\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 timeoutMs?: number,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n if (timeoutMs !== undefined && timeoutMs > 0) {\n xhr.timeout = timeoutMs;\n xhr.addEventListener('timeout', () => {\n reject(new UploadError(`Upload timed out after ${timeoutMs}ms`, true));\n });\n }\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 const detail = xhr.responseText ? `: ${xhr.responseText}` : '';\n const retryable = xhr.status >= 500 || xhr.status === 429;\n reject(\n new UploadError(\n `Upload failed with status ${xhr.status}${detail}`,\n retryable,\n xhr.status,\n ),\n );\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new UploadError('Upload failed: network error', true));\n });\n\n xhr.addEventListener('abort', () => {\n reject(new UploadError('Upload aborted', false));\n });\n\n xhr.open('PUT', url);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Upload a single file with automatic retries on transient failures.\n * Only the S3 PUT is retried — the presigned URL stays valid for 15 minutes.\n */\nasync function uploadFileWithRetry(\n url: string,\n file: File,\n onProgress: ((progress: number) => void) | undefined,\n timeoutMs: number,\n maxRetries: number,\n retryDelayMs: number,\n): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await uploadFileWithProgress(url, file, onProgress, timeoutMs);\n return;\n } catch (err) {\n lastError = err;\n\n const isRetryable = err instanceof UploadError && err.retryable;\n if (!isRetryable || attempt >= maxRetries) {\n break;\n }\n\n onProgress?.(0);\n await delay(retryDelayMs);\n }\n }\n\n throw lastError;\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 * Uploads include automatic timeout (default 60s) and retry (default 2 retries)\n * for transient failures like network errors or server issues.\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 timeoutMs = options.timeoutMs ?? UPLOAD_DEFAULTS.timeoutMs;\n const maxRetries = options.maxRetries ?? UPLOAD_DEFAULTS.maxRetries;\n const retryDelayMs = options.retryDelayMs ?? UPLOAD_DEFAULTS.retryDelayMs;\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 uploadFileWithRetry(\n uploadInfo.uploadUrl,\n file,\n options.onProgress ? (progress) => options.onProgress!(i, progress) : undefined,\n timeoutMs,\n maxRetries,\n retryDelayMs,\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, ToolResult } from '@octavus/core';\n\n// =============================================================================\n// Base Transport Interface\n// =============================================================================\n\n/**\n * Options for trigger execution (e.g., retry with rollback).\n */\nexport interface TriggerOptions {\n /**\n * ID of the last message to keep in session state.\n * Messages after this are removed before execution.\n * Use `null` to truncate all messages (retry from empty history).\n */\n rollbackAfterMessageId?: string | null;\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 * @param options - Optional trigger options (e.g., rollback for retry)\n */\n trigger(\n triggerName: string,\n input?: Record<string, unknown>,\n options?: TriggerOptions,\n ): AsyncIterable<StreamEvent>;\n\n /**\n * Continue execution with tool results after client-side tool handling.\n *\n * @param executionId - The execution ID from the client-tool-request event\n * @param results - All tool results (server + client) to send\n */\n continueWithToolResults(executionId: string, results: ToolResult[]): 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, type ToolResult } from '@octavus/core';\nimport { parseSSEStream } from '@/stream/reader';\nimport type { Transport, TriggerOptions } from './types';\n\n// =============================================================================\n// Request Types\n// =============================================================================\n\n/** Start a new trigger execution */\nexport interface TriggerRequest {\n type: 'trigger';\n triggerName: string;\n input?: Record<string, unknown>;\n rollbackAfterMessageId?: string | null;\n}\n\n/** Continue execution after client-side tool handling */\nexport interface ContinueRequest {\n type: 'continue';\n executionId: string;\n toolResults: ToolResult[];\n}\n\n/** All request types supported by the HTTP transport */\nexport type HttpRequest = TriggerRequest | ContinueRequest;\n\n// =============================================================================\n// Transport Options\n// =============================================================================\n\n/** Request options passed to the request callback */\nexport interface HttpRequestOptions {\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 requests to your backend.\n * Receives a discriminated union with `type` to identify the request kind.\n *\n * @param request - The request payload (check `request.type` for the kind)\n * @param options - Request options including abort signal\n * @returns Response with SSE stream body\n *\n * @example\n * ```typescript\n * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\n * })\n * ```\n */\n request: (request: HttpRequest, options?: HttpRequestOptions) => Promise<Response>;\n}\n\n// =============================================================================\n// Transport Implementation\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 * request: (payload, options) =>\n * fetch('/api/trigger', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ sessionId, ...payload }),\n * signal: options?.signal,\n * }),\n * });\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions): Transport {\n let abortController: AbortController | null = null;\n\n async function* streamResponse(responsePromise: Promise<Response>) {\n try {\n const response = await responsePromise;\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 if (isAbortError(err)) {\n return;\n }\n throw err;\n }\n }\n\n return {\n async *trigger(triggerName, input, triggerOptions?: TriggerOptions) {\n abortController = new AbortController();\n const request: TriggerRequest = { type: 'trigger', triggerName, input };\n if (triggerOptions?.rollbackAfterMessageId !== undefined) {\n request.rollbackAfterMessageId = triggerOptions.rollbackAfterMessageId;\n }\n const response = options.request(request, { signal: abortController.signal });\n yield* streamResponse(response);\n },\n\n async *continueWithToolResults(executionId, toolResults) {\n abortController = new AbortController();\n const response = options.request(\n { type: 'continue', executionId, toolResults },\n { signal: abortController.signal },\n );\n yield* streamResponse(response);\n },\n\n stop() {\n abortController?.abort();\n abortController = null;\n },\n };\n}\n","import { safeParseStreamEvent, type StreamEvent, type ToolResult } from '@octavus/core';\nimport type {\n SocketTransport,\n ConnectionState,\n ConnectionStateListener,\n TriggerOptions,\n} 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, triggerOptions?: TriggerOptions) {\n await ensureConnected();\n\n eventQueue = [];\n eventResolver = null;\n isStreaming = true;\n\n const message: Record<string, unknown> = { type: 'trigger', triggerName, input };\n if (triggerOptions?.rollbackAfterMessageId !== undefined) {\n message.rollbackAfterMessageId = triggerOptions.rollbackAfterMessageId;\n }\n socket!.send(JSON.stringify(message));\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 * Continue execution with tool results after client-side tool handling.\n * @param executionId - The execution ID from the client-tool-request event\n * @param toolResults - All tool results (server + client) to send\n */\n async *continueWithToolResults(executionId: string, toolResults: ToolResult[]) {\n await ensureConnected();\n\n eventQueue = [];\n eventResolver = null; // Clear any pending resolver from previous operation\n isStreaming = true;\n\n socket!.send(\n JSON.stringify({\n type: 'continue',\n executionId,\n toolResults,\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}\n","export {\n OctavusChat,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\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 TriggerOptions,\n type SocketTransport,\n type ConnectionState,\n type ConnectionStateListener,\n type HttpTransportOptions,\n type HttpRequestOptions,\n type HttpRequest,\n type TriggerRequest,\n type ContinueRequest,\n type SocketLike,\n type SocketTransportOptions,\n} from './transports';\n\nexport type * from '@octavus/core';\nexport {\n // Error classes\n AppError,\n NotFoundError,\n ValidationError,\n ConflictError,\n ForbiddenError,\n OctavusError,\n // Error type guards\n isRateLimitError,\n isAuthenticationError,\n isProviderError,\n isToolError,\n isRetryableError,\n isValidationError,\n // Error event helpers\n createErrorEvent,\n errorToStreamEvent,\n createInternalErrorEvent,\n createApiErrorEvent,\n // Utilities\n generateId,\n isAbortError,\n // Thread helpers\n MAIN_THREAD,\n resolveThread,\n isMainThread,\n threadForPart,\n isOtherThread,\n // Type guards\n isFileReference,\n isFileReferenceArray,\n // Safe parse helpers\n safeParseStreamEvent,\n safeParseUIMessage,\n safeParseUIMessages,\n // Skills\n OCTAVUS_SKILL_TOOLS,\n isOctavusSkillTool,\n getSkillSlugFromToolCall,\n} from '@octavus/core';\n"],"mappings":"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","names":["isAbortError","isAbortError","safeParseStreamEvent","OctavusError","generateId","isAbortError","threadForPart","isFileReferenceArray","safeParseStreamEvent"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octavus/client-sdk",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "Framework-agnostic client SDK for Octavus agents",
5
5
  "license": "MIT",
6
6
  "author": "Octavus AI <dev@octavus.ai>",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@octavus/core": "^2.11.0"
42
+ "@octavus/core": "^2.13.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "tsup": "^8.3.5",