@octavus/react 2.19.0 → 2.21.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/dist/index.cjs +240 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +244 -0
- package/dist/index.d.ts +42 -1
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -5
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AppError: () => import_client_sdk2.AppError,
|
|
24
|
+
ConflictError: () => import_client_sdk2.ConflictError,
|
|
25
|
+
ForbiddenError: () => import_client_sdk2.ForbiddenError,
|
|
26
|
+
MAIN_THREAD: () => import_client_sdk2.MAIN_THREAD,
|
|
27
|
+
NotFoundError: () => import_client_sdk2.NotFoundError,
|
|
28
|
+
OCTAVUS_SKILL_TOOLS: () => import_client_sdk2.OCTAVUS_SKILL_TOOLS,
|
|
29
|
+
OctavusChat: () => import_client_sdk2.OctavusChat,
|
|
30
|
+
OctavusError: () => import_client_sdk2.OctavusError,
|
|
31
|
+
ValidationError: () => import_client_sdk2.ValidationError,
|
|
32
|
+
createApiErrorEvent: () => import_client_sdk2.createApiErrorEvent,
|
|
33
|
+
createErrorEvent: () => import_client_sdk2.createErrorEvent,
|
|
34
|
+
createHttpTransport: () => import_client_sdk2.createHttpTransport,
|
|
35
|
+
createInternalErrorEvent: () => import_client_sdk2.createInternalErrorEvent,
|
|
36
|
+
createPollingTransport: () => import_client_sdk2.createPollingTransport,
|
|
37
|
+
createSocketTransport: () => import_client_sdk2.createSocketTransport,
|
|
38
|
+
errorToStreamEvent: () => import_client_sdk2.errorToStreamEvent,
|
|
39
|
+
generateId: () => import_client_sdk2.generateId,
|
|
40
|
+
getSkillSlugFromToolCall: () => import_client_sdk2.getSkillSlugFromToolCall,
|
|
41
|
+
isAbortError: () => import_client_sdk2.isAbortError,
|
|
42
|
+
isAuthenticationError: () => import_client_sdk2.isAuthenticationError,
|
|
43
|
+
isFileReference: () => import_client_sdk2.isFileReference,
|
|
44
|
+
isFileReferenceArray: () => import_client_sdk2.isFileReferenceArray,
|
|
45
|
+
isMainThread: () => import_client_sdk2.isMainThread,
|
|
46
|
+
isOctavusSkillTool: () => import_client_sdk2.isOctavusSkillTool,
|
|
47
|
+
isOtherThread: () => import_client_sdk2.isOtherThread,
|
|
48
|
+
isProviderError: () => import_client_sdk2.isProviderError,
|
|
49
|
+
isRateLimitError: () => import_client_sdk2.isRateLimitError,
|
|
50
|
+
isRetryableError: () => import_client_sdk2.isRetryableError,
|
|
51
|
+
isSocketTransport: () => import_client_sdk2.isSocketTransport,
|
|
52
|
+
isToolError: () => import_client_sdk2.isToolError,
|
|
53
|
+
isValidationError: () => import_client_sdk2.isValidationError,
|
|
54
|
+
parseSSEStream: () => import_client_sdk2.parseSSEStream,
|
|
55
|
+
resolveThread: () => import_client_sdk2.resolveThread,
|
|
56
|
+
safeParseStreamEvent: () => import_client_sdk2.safeParseStreamEvent,
|
|
57
|
+
safeParseUIMessage: () => import_client_sdk2.safeParseUIMessage,
|
|
58
|
+
safeParseUIMessages: () => import_client_sdk2.safeParseUIMessages,
|
|
59
|
+
threadForPart: () => import_client_sdk2.threadForPart,
|
|
60
|
+
uploadFiles: () => import_client_sdk2.uploadFiles,
|
|
61
|
+
useAutoScroll: () => useAutoScroll,
|
|
62
|
+
useOctavusChat: () => useOctavusChat
|
|
63
|
+
});
|
|
64
|
+
module.exports = __toCommonJS(index_exports);
|
|
65
|
+
|
|
66
|
+
// src/hooks/use-octavus-chat.ts
|
|
67
|
+
var import_react = require("react");
|
|
68
|
+
var import_client_sdk = require("@octavus/client-sdk");
|
|
69
|
+
function useOctavusChat(options) {
|
|
70
|
+
const chatRef = (0, import_react.useRef)(null);
|
|
71
|
+
const transportRef = (0, import_react.useRef)(null);
|
|
72
|
+
const [sessionId, setSessionId] = (0, import_react.useState)(null);
|
|
73
|
+
const sessionIdSetterRef = (0, import_react.useRef)(setSessionId);
|
|
74
|
+
sessionIdSetterRef.current = setSessionId;
|
|
75
|
+
if (transportRef.current !== options.transport) {
|
|
76
|
+
chatRef.current?.stop();
|
|
77
|
+
setSessionId(null);
|
|
78
|
+
chatRef.current = new import_client_sdk.OctavusChat(options);
|
|
79
|
+
transportRef.current = options.transport;
|
|
80
|
+
}
|
|
81
|
+
const chat = chatRef.current;
|
|
82
|
+
chat.updateOptions({
|
|
83
|
+
clientTools: options.clientTools,
|
|
84
|
+
onError: options.onError,
|
|
85
|
+
onFinish: options.onFinish,
|
|
86
|
+
onStop: options.onStop,
|
|
87
|
+
onResourceUpdate: options.onResourceUpdate,
|
|
88
|
+
onStart: (id) => {
|
|
89
|
+
sessionIdSetterRef.current(id);
|
|
90
|
+
options.onStart?.(id);
|
|
91
|
+
},
|
|
92
|
+
requestUploadUrls: options.requestUploadUrls,
|
|
93
|
+
uploadOptions: options.uploadOptions
|
|
94
|
+
});
|
|
95
|
+
const transport = options.transport;
|
|
96
|
+
const subscribe = (0, import_react.useCallback)((callback) => chat.subscribe(callback), [chat]);
|
|
97
|
+
const getMessagesSnapshot = (0, import_react.useCallback)(() => chat.messages, [chat]);
|
|
98
|
+
const getStatusSnapshot = (0, import_react.useCallback)(() => chat.status, [chat]);
|
|
99
|
+
const getErrorSnapshot = (0, import_react.useCallback)(() => chat.error, [chat]);
|
|
100
|
+
const getPendingClientToolsSnapshot = (0, import_react.useCallback)(() => chat.pendingClientTools, [chat]);
|
|
101
|
+
const getCanRetrySnapshot = (0, import_react.useCallback)(() => chat.canRetry, [chat]);
|
|
102
|
+
const messages = (0, import_react.useSyncExternalStore)(subscribe, getMessagesSnapshot, getMessagesSnapshot);
|
|
103
|
+
const status = (0, import_react.useSyncExternalStore)(subscribe, getStatusSnapshot, getStatusSnapshot);
|
|
104
|
+
const error = (0, import_react.useSyncExternalStore)(subscribe, getErrorSnapshot, getErrorSnapshot);
|
|
105
|
+
const pendingClientTools = (0, import_react.useSyncExternalStore)(
|
|
106
|
+
subscribe,
|
|
107
|
+
getPendingClientToolsSnapshot,
|
|
108
|
+
getPendingClientToolsSnapshot
|
|
109
|
+
);
|
|
110
|
+
const canRetry = (0, import_react.useSyncExternalStore)(subscribe, getCanRetrySnapshot, getCanRetrySnapshot);
|
|
111
|
+
const socketTransport = (0, import_client_sdk.isSocketTransport)(transport) ? transport : null;
|
|
112
|
+
const [connectionState, setConnectionState] = (0, import_react.useState)(
|
|
113
|
+
socketTransport?.connectionState
|
|
114
|
+
);
|
|
115
|
+
const [connectionError, setConnectionError] = (0, import_react.useState)(void 0);
|
|
116
|
+
(0, import_react.useEffect)(() => {
|
|
117
|
+
if (!socketTransport) {
|
|
118
|
+
setConnectionState(void 0);
|
|
119
|
+
setConnectionError(void 0);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const unsubscribe = socketTransport.onConnectionStateChange((state, err) => {
|
|
123
|
+
setConnectionState(state);
|
|
124
|
+
setConnectionError(err);
|
|
125
|
+
});
|
|
126
|
+
return unsubscribe;
|
|
127
|
+
}, [socketTransport]);
|
|
128
|
+
const send = (0, import_react.useCallback)(
|
|
129
|
+
(triggerName, input, sendOptions) => chat.send(triggerName, input, sendOptions),
|
|
130
|
+
[chat]
|
|
131
|
+
);
|
|
132
|
+
const stop = (0, import_react.useCallback)(() => chat.stop(), [chat]);
|
|
133
|
+
const retry = (0, import_react.useCallback)(() => chat.retry(), [chat]);
|
|
134
|
+
const observe = (0, import_react.useCallback)(() => chat.observe(), [chat]);
|
|
135
|
+
const replaceMessages = (0, import_react.useCallback)((msgs) => chat.replaceMessages(msgs), [chat]);
|
|
136
|
+
const uploadFiles2 = (0, import_react.useCallback)(
|
|
137
|
+
(files, onProgress) => chat.uploadFiles(files, onProgress),
|
|
138
|
+
[chat]
|
|
139
|
+
);
|
|
140
|
+
const connect = (0, import_react.useCallback)(
|
|
141
|
+
() => socketTransport?.connect() ?? Promise.resolve(),
|
|
142
|
+
[socketTransport]
|
|
143
|
+
);
|
|
144
|
+
const disconnect = (0, import_react.useCallback)(() => socketTransport?.disconnect(), [socketTransport]);
|
|
145
|
+
return {
|
|
146
|
+
messages,
|
|
147
|
+
status,
|
|
148
|
+
error,
|
|
149
|
+
sessionId,
|
|
150
|
+
connectionState,
|
|
151
|
+
connectionError,
|
|
152
|
+
pendingClientTools,
|
|
153
|
+
send,
|
|
154
|
+
stop,
|
|
155
|
+
retry,
|
|
156
|
+
observe,
|
|
157
|
+
replaceMessages,
|
|
158
|
+
canRetry,
|
|
159
|
+
connect: socketTransport ? connect : void 0,
|
|
160
|
+
disconnect: socketTransport ? disconnect : void 0,
|
|
161
|
+
uploadFiles: uploadFiles2
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/hooks/use-auto-scroll.ts
|
|
166
|
+
var import_react2 = require("react");
|
|
167
|
+
var DEFAULT_THRESHOLD_PX = 80;
|
|
168
|
+
function useAutoScroll(options = {}) {
|
|
169
|
+
const internalRef = (0, import_react2.useRef)(null);
|
|
170
|
+
const scrollRef = options.scrollRef ?? internalRef;
|
|
171
|
+
const threshold = options.threshold ?? DEFAULT_THRESHOLD_PX;
|
|
172
|
+
const shouldAutoScrollRef = (0, import_react2.useRef)(true);
|
|
173
|
+
const handleScroll = (0, import_react2.useCallback)(() => {
|
|
174
|
+
const el = scrollRef.current;
|
|
175
|
+
if (!el) return;
|
|
176
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
177
|
+
shouldAutoScrollRef.current = distanceFromBottom <= threshold;
|
|
178
|
+
}, [scrollRef, threshold]);
|
|
179
|
+
const scrollOnUpdate = (0, import_react2.useCallback)(() => {
|
|
180
|
+
const el = scrollRef.current;
|
|
181
|
+
if (!el) return;
|
|
182
|
+
if (shouldAutoScrollRef.current) {
|
|
183
|
+
el.scrollTop = el.scrollHeight;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
187
|
+
shouldAutoScrollRef.current = distanceFromBottom <= threshold;
|
|
188
|
+
}, [scrollRef, threshold]);
|
|
189
|
+
const resetAutoScroll = (0, import_react2.useCallback)(() => {
|
|
190
|
+
shouldAutoScrollRef.current = true;
|
|
191
|
+
}, []);
|
|
192
|
+
return { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/index.ts
|
|
196
|
+
var import_client_sdk2 = require("@octavus/client-sdk");
|
|
197
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
198
|
+
0 && (module.exports = {
|
|
199
|
+
AppError,
|
|
200
|
+
ConflictError,
|
|
201
|
+
ForbiddenError,
|
|
202
|
+
MAIN_THREAD,
|
|
203
|
+
NotFoundError,
|
|
204
|
+
OCTAVUS_SKILL_TOOLS,
|
|
205
|
+
OctavusChat,
|
|
206
|
+
OctavusError,
|
|
207
|
+
ValidationError,
|
|
208
|
+
createApiErrorEvent,
|
|
209
|
+
createErrorEvent,
|
|
210
|
+
createHttpTransport,
|
|
211
|
+
createInternalErrorEvent,
|
|
212
|
+
createPollingTransport,
|
|
213
|
+
createSocketTransport,
|
|
214
|
+
errorToStreamEvent,
|
|
215
|
+
generateId,
|
|
216
|
+
getSkillSlugFromToolCall,
|
|
217
|
+
isAbortError,
|
|
218
|
+
isAuthenticationError,
|
|
219
|
+
isFileReference,
|
|
220
|
+
isFileReferenceArray,
|
|
221
|
+
isMainThread,
|
|
222
|
+
isOctavusSkillTool,
|
|
223
|
+
isOtherThread,
|
|
224
|
+
isProviderError,
|
|
225
|
+
isRateLimitError,
|
|
226
|
+
isRetryableError,
|
|
227
|
+
isSocketTransport,
|
|
228
|
+
isToolError,
|
|
229
|
+
isValidationError,
|
|
230
|
+
parseSSEStream,
|
|
231
|
+
resolveThread,
|
|
232
|
+
safeParseStreamEvent,
|
|
233
|
+
safeParseUIMessage,
|
|
234
|
+
safeParseUIMessages,
|
|
235
|
+
threadForPart,
|
|
236
|
+
uploadFiles,
|
|
237
|
+
useAutoScroll,
|
|
238
|
+
useOctavusChat
|
|
239
|
+
});
|
|
240
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/use-octavus-chat.ts","../src/hooks/use-auto-scroll.ts"],"sourcesContent":["export {\n useOctavusChat,\n type UseOctavusChatReturn,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from './hooks/use-octavus-chat';\n\nexport { useAutoScroll, type UseAutoScrollOptions } from './hooks/use-auto-scroll';\n\nexport type * from '@octavus/client-sdk';\nexport {\n // Chat\n OctavusChat,\n // Files\n uploadFiles,\n // Stream\n parseSSEStream,\n // Transports\n createHttpTransport,\n createSocketTransport,\n isSocketTransport,\n createPollingTransport,\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/client-sdk';\n","'use client';\n\nimport { useRef, useCallback, useSyncExternalStore, useState, useEffect } from 'react';\nimport {\n OctavusChat,\n type OctavusError,\n isSocketTransport,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type UIMessage,\n type Transport,\n type ConnectionState,\n type FileReference,\n type UploadFilesOptions,\n type UploadUrlsResponse,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from '@octavus/client-sdk';\n\nexport type {\n OctavusChatOptions,\n ChatStatus,\n UserMessageInput,\n FileReference,\n UploadFilesOptions,\n UploadUrlsResponse,\n ClientToolContext,\n ClientToolHandler,\n InteractiveTool,\n};\n\nexport interface UseOctavusChatReturn {\n /** All messages including the currently streaming one */\n messages: UIMessage[];\n /** Current status of the chat */\n status: ChatStatus;\n /**\n * Error if status is 'error'.\n * Contains structured error information including type, source, and retryability.\n * Use type guards like `isRateLimitError()` or `isProviderError()` to check specific error types.\n */\n error: OctavusError | null;\n /**\n * The current session/execution ID from the most recent `send()` call.\n * Updated when the server responds with a `start` event containing an execution ID.\n * Useful for tracking activity logs or debugging.\n *\n * For workers, this is the execution ID. For interactive sessions, this is the session ID.\n */\n sessionId: string | null;\n /**\n * Socket connection state (socket transport only).\n * For HTTP transport, this is always `undefined`.\n *\n * - `disconnected`: Not connected (initial state before first send)\n * - `connecting`: Connection attempt in progress\n * - `connected`: Successfully connected\n * - `error`: Connection failed (check `connectionError`)\n */\n connectionState: ConnectionState | undefined;\n /**\n * Connection error if `connectionState` is 'error'.\n */\n connectionError: Error | undefined;\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 pendingClientTools: Record<string, InteractiveTool[]>;\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 send: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput },\n ) => Promise<void>;\n /** Stop the current streaming and finalize any partial message */\n stop: () => void;\n /**\n * Retry the last trigger from the same starting point.\n * Rolls back messages, re-adds the user message (if any), and re-executes.\n * No-op if no trigger has been sent yet.\n */\n retry: () => Promise<void>;\n /**\n * Observe an already-active execution without triggering a new one.\n * Only works with transports that support `observe()` (e.g., polling transport).\n * Use when the page loads and the session is already streaming.\n */\n observe: () => Promise<void>;\n /**\n * Replace the message list with externally-provided messages.\n * Use to sync with server-authoritative state (e.g., multi-observer scenarios).\n * Must NOT be called while streaming.\n */\n replaceMessages: (messages: UIMessage[]) => void;\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 canRetry: boolean;\n /**\n * Eagerly connect to the socket (socket transport only).\n * Returns a promise that resolves when connected or rejects on error.\n * Safe to call multiple times - subsequent calls resolve immediately if already connected.\n *\n * For HTTP transport, this is `undefined`.\n */\n connect: (() => Promise<void>) | undefined;\n /**\n * Disconnect the socket (socket transport only).\n * The transport will reconnect automatically on next send().\n *\n * For HTTP transport, this is `undefined`.\n */\n disconnect: (() => void) | undefined;\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 uploadFiles(fileInput.files, (i, progress) => {\n * console.log(`File ${i}: ${progress}%`);\n * });\n * // Later...\n * await send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });\n * ```\n */\n uploadFiles: (\n files: FileList | File[],\n onProgress?: (fileIndex: number, progress: number) => void,\n ) => Promise<FileReference[]>;\n}\n\n/**\n * React hook for interacting with Octavus agents.\n * Provides chat state management and streaming support.\n *\n * When the transport changes (e.g., sessionId changes), the hook automatically\n * reinitializes with a fresh chat instance. Use `initialMessages` if you need\n * to preserve messages across transport changes.\n *\n * @example Basic usage with HTTP transport\n * ```tsx\n * import { useOctavusChat, createHttpTransport } from '@octavus/react';\n *\n * function Chat({ sessionId }) {\n * const transport = useMemo(\n * () => 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 * [sessionId],\n * );\n *\n * const { messages, status, send } = useOctavusChat({ transport });\n *\n * return (\n * <div>\n * {messages.map((msg) => (\n * <Message key={msg.id} message={msg} />\n * ))}\n * <button onClick={() => send('user-message', { USER_MESSAGE: 'Hello' })}>\n * Send\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @example Socket transport with eager connection\n * ```tsx\n * import { useOctavusChat, createSocketTransport } from '@octavus/react';\n *\n * function Chat() {\n * const transport = useMemo(\n * () => createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/octavus');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * }),\n * }),\n * [],\n * );\n *\n * const { messages, status, send, connectionState, connect, disconnect } =\n * useOctavusChat({ transport });\n *\n * // Eager connection on mount\n * useEffect(() => {\n * connect?.();\n * return () => disconnect?.();\n * }, [connect, disconnect]);\n *\n * return (\n * <div>\n * <StatusIndicator state={connectionState} />\n * {messages.map((msg) => <Message key={msg.id} message={msg} />)}\n * </div>\n * );\n * }\n * ```\n */\nexport function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn {\n const chatRef = useRef<OctavusChat | null>(null);\n const transportRef = useRef<Transport | null>(null);\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n const sessionIdSetterRef = useRef(setSessionId);\n sessionIdSetterRef.current = setSessionId;\n\n if (transportRef.current !== options.transport) {\n chatRef.current?.stop();\n setSessionId(null);\n chatRef.current = new OctavusChat(options);\n transportRef.current = options.transport;\n }\n\n const chat = chatRef.current!;\n\n // Keep all mutable options (callbacks, tool handlers) fresh on every render.\n // This ensures handlers always reference the latest closures instead of going stale.\n chat.updateOptions({\n clientTools: options.clientTools,\n onError: options.onError,\n onFinish: options.onFinish,\n onStop: options.onStop,\n onResourceUpdate: options.onResourceUpdate,\n onStart: (id) => {\n sessionIdSetterRef.current(id);\n options.onStart?.(id);\n },\n requestUploadUrls: options.requestUploadUrls,\n uploadOptions: options.uploadOptions,\n });\n const transport = options.transport;\n\n const subscribe = useCallback((callback: () => void) => chat.subscribe(callback), [chat]);\n const getMessagesSnapshot = useCallback(() => chat.messages, [chat]);\n const getStatusSnapshot = useCallback(() => chat.status, [chat]);\n const getErrorSnapshot = useCallback(() => chat.error, [chat]);\n const getPendingClientToolsSnapshot = useCallback(() => chat.pendingClientTools, [chat]);\n const getCanRetrySnapshot = useCallback(() => chat.canRetry, [chat]);\n\n const messages = useSyncExternalStore(subscribe, getMessagesSnapshot, getMessagesSnapshot);\n const status = useSyncExternalStore(subscribe, getStatusSnapshot, getStatusSnapshot);\n const error = useSyncExternalStore(subscribe, getErrorSnapshot, getErrorSnapshot);\n const pendingClientTools = useSyncExternalStore(\n subscribe,\n getPendingClientToolsSnapshot,\n getPendingClientToolsSnapshot,\n );\n const canRetry = useSyncExternalStore(subscribe, getCanRetrySnapshot, getCanRetrySnapshot);\n\n const socketTransport = isSocketTransport(transport) ? transport : null;\n const [connectionState, setConnectionState] = useState<ConnectionState | undefined>(\n socketTransport?.connectionState,\n );\n const [connectionError, setConnectionError] = useState<Error | undefined>(undefined);\n\n useEffect(() => {\n if (!socketTransport) {\n setConnectionState(undefined);\n setConnectionError(undefined);\n return;\n }\n\n const unsubscribe = socketTransport.onConnectionStateChange((state, err) => {\n setConnectionState(state);\n setConnectionError(err);\n });\n\n return unsubscribe;\n }, [socketTransport]);\n\n const send = useCallback(\n (\n triggerName: string,\n input?: Record<string, unknown>,\n sendOptions?: { userMessage?: UserMessageInput },\n ) => chat.send(triggerName, input, sendOptions),\n [chat],\n );\n\n const stop = useCallback(() => chat.stop(), [chat]);\n const retry = useCallback(() => chat.retry(), [chat]);\n const observe = useCallback(() => chat.observe(), [chat]);\n const replaceMessages = useCallback((msgs: UIMessage[]) => chat.replaceMessages(msgs), [chat]);\n\n const uploadFiles = useCallback(\n (files: FileList | File[], onProgress?: (fileIndex: number, progress: number) => void) =>\n chat.uploadFiles(files, onProgress),\n [chat],\n );\n\n // Stable references for connect/disconnect (socket transport only)\n const connect = useCallback(\n () => socketTransport?.connect() ?? Promise.resolve(),\n [socketTransport],\n );\n const disconnect = useCallback(() => socketTransport?.disconnect(), [socketTransport]);\n\n return {\n messages,\n status,\n error,\n sessionId,\n connectionState,\n connectionError,\n pendingClientTools,\n send,\n stop,\n retry,\n observe,\n replaceMessages,\n canRetry,\n connect: socketTransport ? connect : undefined,\n disconnect: socketTransport ? disconnect : undefined,\n uploadFiles,\n };\n}\n","'use client';\n\nimport { type RefObject, useRef, useCallback } from 'react';\n\nconst DEFAULT_THRESHOLD_PX = 80;\n\nexport interface UseAutoScrollOptions {\n /**\n * Provide your own ref if you need to share the scroll container\n * with other logic. When omitted, an internal ref is created.\n */\n scrollRef?: RefObject<HTMLDivElement | null>;\n\n /**\n * Distance from the bottom (in pixels) within which auto-scroll\n * stays active. Defaults to 80.\n */\n threshold?: number;\n}\n\n/**\n * Smart auto-scroll for chat interfaces.\n *\n * Scrolls to bottom when new content arrives, but pauses if the user\n * has scrolled up to read earlier messages. Re-enables once the user\n * scrolls back near the bottom.\n *\n * @example\n * ```tsx\n * const { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll } = useAutoScroll();\n *\n * useEffect(() => {\n * const id = requestAnimationFrame(scrollOnUpdate);\n * return () => cancelAnimationFrame(id);\n * }, [messages, scrollOnUpdate]);\n *\n * <div ref={scrollRef} onScroll={handleScroll}>...</div>\n *\n * // On send: resetAutoScroll() to force-scroll on next update\n * ```\n */\nexport function useAutoScroll(options: UseAutoScrollOptions = {}) {\n const internalRef = useRef<HTMLDivElement>(null);\n const scrollRef = options.scrollRef ?? internalRef;\n const threshold = options.threshold ?? DEFAULT_THRESHOLD_PX;\n const shouldAutoScrollRef = useRef(true);\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;\n shouldAutoScrollRef.current = distanceFromBottom <= threshold;\n }, [scrollRef, threshold]);\n\n const scrollOnUpdate = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n if (shouldAutoScrollRef.current) {\n el.scrollTop = el.scrollHeight;\n return;\n }\n\n const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;\n shouldAutoScrollRef.current = distanceFromBottom <= threshold;\n }, [scrollRef, threshold]);\n\n const resetAutoScroll = useCallback(() => {\n shouldAutoScrollRef.current = true;\n }, []);\n\n return { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll };\n}\n"],"mappings":"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","names":["uploadFiles","import_react","import_client_sdk"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { OctavusChatOptions, UIMessage, ChatStatus, OctavusError, ConnectionState, InteractiveTool, UserMessageInput, FileReference } from '@octavus/client-sdk';
|
|
2
|
+
export * from '@octavus/client-sdk';
|
|
3
|
+
export { AppError, ChatStatus, ClientToolContext, ClientToolHandler, ConflictError, ForbiddenError, InteractiveTool, MAIN_THREAD, NotFoundError, OCTAVUS_SKILL_TOOLS, OctavusChat, OctavusChatOptions, OctavusError, UserMessageInput, ValidationError, createApiErrorEvent, createErrorEvent, createHttpTransport, createInternalErrorEvent, createPollingTransport, createSocketTransport, errorToStreamEvent, generateId, getSkillSlugFromToolCall, isAbortError, isAuthenticationError, isFileReference, isFileReferenceArray, isMainThread, isOctavusSkillTool, isOtherThread, isProviderError, isRateLimitError, isRetryableError, isSocketTransport, isToolError, isValidationError, parseSSEStream, resolveThread, safeParseStreamEvent, safeParseUIMessage, safeParseUIMessages, threadForPart, uploadFiles } from '@octavus/client-sdk';
|
|
4
|
+
import { RefObject } from 'react';
|
|
5
|
+
|
|
6
|
+
interface UseOctavusChatReturn {
|
|
7
|
+
/** All messages including the currently streaming one */
|
|
8
|
+
messages: UIMessage[];
|
|
9
|
+
/** Current status of the chat */
|
|
10
|
+
status: ChatStatus;
|
|
11
|
+
/**
|
|
12
|
+
* Error if status is 'error'.
|
|
13
|
+
* Contains structured error information including type, source, and retryability.
|
|
14
|
+
* Use type guards like `isRateLimitError()` or `isProviderError()` to check specific error types.
|
|
15
|
+
*/
|
|
16
|
+
error: OctavusError | null;
|
|
17
|
+
/**
|
|
18
|
+
* The current session/execution ID from the most recent `send()` call.
|
|
19
|
+
* Updated when the server responds with a `start` event containing an execution ID.
|
|
20
|
+
* Useful for tracking activity logs or debugging.
|
|
21
|
+
*
|
|
22
|
+
* For workers, this is the execution ID. For interactive sessions, this is the session ID.
|
|
23
|
+
*/
|
|
24
|
+
sessionId: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Socket connection state (socket transport only).
|
|
27
|
+
* For HTTP transport, this is always `undefined`.
|
|
28
|
+
*
|
|
29
|
+
* - `disconnected`: Not connected (initial state before first send)
|
|
30
|
+
* - `connecting`: Connection attempt in progress
|
|
31
|
+
* - `connected`: Successfully connected
|
|
32
|
+
* - `error`: Connection failed (check `connectionError`)
|
|
33
|
+
*/
|
|
34
|
+
connectionState: ConnectionState | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Connection error if `connectionState` is 'error'.
|
|
37
|
+
*/
|
|
38
|
+
connectionError: Error | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Pending interactive tool calls keyed by tool name.
|
|
41
|
+
* Each tool has bound `submit()` and `cancel()` methods.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* const feedbackTools = pendingClientTools['request-feedback'] ?? [];
|
|
46
|
+
*
|
|
47
|
+
* {feedbackTools.map(tool => (
|
|
48
|
+
* <FeedbackModal
|
|
49
|
+
* key={tool.toolCallId}
|
|
50
|
+
* {...tool.args}
|
|
51
|
+
* onSubmit={(result) => tool.submit(result)}
|
|
52
|
+
* onCancel={() => tool.cancel()}
|
|
53
|
+
* />
|
|
54
|
+
* ))}
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
pendingClientTools: Record<string, InteractiveTool[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Trigger the agent and optionally add a user message to the chat.
|
|
60
|
+
*
|
|
61
|
+
* @param triggerName - The trigger name defined in the agent's protocol.yaml
|
|
62
|
+
* @param input - Input parameters for the trigger (variable substitutions)
|
|
63
|
+
* @param options.userMessage - If provided, adds a user message to the chat before triggering
|
|
64
|
+
*/
|
|
65
|
+
send: (triggerName: string, input?: Record<string, unknown>, options?: {
|
|
66
|
+
userMessage?: UserMessageInput;
|
|
67
|
+
}) => Promise<void>;
|
|
68
|
+
/** Stop the current streaming and finalize any partial message */
|
|
69
|
+
stop: () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Retry the last trigger from the same starting point.
|
|
72
|
+
* Rolls back messages, re-adds the user message (if any), and re-executes.
|
|
73
|
+
* No-op if no trigger has been sent yet.
|
|
74
|
+
*/
|
|
75
|
+
retry: () => Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Observe an already-active execution without triggering a new one.
|
|
78
|
+
* Only works with transports that support `observe()` (e.g., polling transport).
|
|
79
|
+
* Use when the page loads and the session is already streaming.
|
|
80
|
+
*/
|
|
81
|
+
observe: () => Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Replace the message list with externally-provided messages.
|
|
84
|
+
* Use to sync with server-authoritative state (e.g., multi-observer scenarios).
|
|
85
|
+
* Must NOT be called while streaming.
|
|
86
|
+
*/
|
|
87
|
+
replaceMessages: (messages: UIMessage[]) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Whether `retry()` can be called.
|
|
90
|
+
* True when a trigger has been sent and the chat is not currently streaming or awaiting input.
|
|
91
|
+
*/
|
|
92
|
+
canRetry: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Eagerly connect to the socket (socket transport only).
|
|
95
|
+
* Returns a promise that resolves when connected or rejects on error.
|
|
96
|
+
* Safe to call multiple times - subsequent calls resolve immediately if already connected.
|
|
97
|
+
*
|
|
98
|
+
* For HTTP transport, this is `undefined`.
|
|
99
|
+
*/
|
|
100
|
+
connect: (() => Promise<void>) | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Disconnect the socket (socket transport only).
|
|
103
|
+
* The transport will reconnect automatically on next send().
|
|
104
|
+
*
|
|
105
|
+
* For HTTP transport, this is `undefined`.
|
|
106
|
+
*/
|
|
107
|
+
disconnect: (() => void) | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Upload files directly without sending a message.
|
|
110
|
+
* Useful for showing upload progress before sending.
|
|
111
|
+
*
|
|
112
|
+
* @param files - Files to upload
|
|
113
|
+
* @param onProgress - Optional progress callback
|
|
114
|
+
* @returns Array of file references
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const fileRefs = await uploadFiles(fileInput.files, (i, progress) => {
|
|
119
|
+
* console.log(`File ${i}: ${progress}%`);
|
|
120
|
+
* });
|
|
121
|
+
* // Later...
|
|
122
|
+
* await send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
uploadFiles: (files: FileList | File[], onProgress?: (fileIndex: number, progress: number) => void) => Promise<FileReference[]>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* React hook for interacting with Octavus agents.
|
|
129
|
+
* Provides chat state management and streaming support.
|
|
130
|
+
*
|
|
131
|
+
* When the transport changes (e.g., sessionId changes), the hook automatically
|
|
132
|
+
* reinitializes with a fresh chat instance. Use `initialMessages` if you need
|
|
133
|
+
* to preserve messages across transport changes.
|
|
134
|
+
*
|
|
135
|
+
* @example Basic usage with HTTP transport
|
|
136
|
+
* ```tsx
|
|
137
|
+
* import { useOctavusChat, createHttpTransport } from '@octavus/react';
|
|
138
|
+
*
|
|
139
|
+
* function Chat({ sessionId }) {
|
|
140
|
+
* const transport = useMemo(
|
|
141
|
+
* () => createHttpTransport({
|
|
142
|
+
* request: (payload, options) =>
|
|
143
|
+
* fetch('/api/trigger', {
|
|
144
|
+
* method: 'POST',
|
|
145
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
146
|
+
* body: JSON.stringify({ sessionId, ...payload }),
|
|
147
|
+
* signal: options?.signal,
|
|
148
|
+
* }),
|
|
149
|
+
* }),
|
|
150
|
+
* [sessionId],
|
|
151
|
+
* );
|
|
152
|
+
*
|
|
153
|
+
* const { messages, status, send } = useOctavusChat({ transport });
|
|
154
|
+
*
|
|
155
|
+
* return (
|
|
156
|
+
* <div>
|
|
157
|
+
* {messages.map((msg) => (
|
|
158
|
+
* <Message key={msg.id} message={msg} />
|
|
159
|
+
* ))}
|
|
160
|
+
* <button onClick={() => send('user-message', { USER_MESSAGE: 'Hello' })}>
|
|
161
|
+
* Send
|
|
162
|
+
* </button>
|
|
163
|
+
* </div>
|
|
164
|
+
* );
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @example Socket transport with eager connection
|
|
169
|
+
* ```tsx
|
|
170
|
+
* import { useOctavusChat, createSocketTransport } from '@octavus/react';
|
|
171
|
+
*
|
|
172
|
+
* function Chat() {
|
|
173
|
+
* const transport = useMemo(
|
|
174
|
+
* () => createSocketTransport({
|
|
175
|
+
* connect: () => new Promise((resolve, reject) => {
|
|
176
|
+
* const sock = new SockJS('/octavus');
|
|
177
|
+
* sock.onopen = () => resolve(sock);
|
|
178
|
+
* sock.onerror = () => reject(new Error('Connection failed'));
|
|
179
|
+
* }),
|
|
180
|
+
* }),
|
|
181
|
+
* [],
|
|
182
|
+
* );
|
|
183
|
+
*
|
|
184
|
+
* const { messages, status, send, connectionState, connect, disconnect } =
|
|
185
|
+
* useOctavusChat({ transport });
|
|
186
|
+
*
|
|
187
|
+
* // Eager connection on mount
|
|
188
|
+
* useEffect(() => {
|
|
189
|
+
* connect?.();
|
|
190
|
+
* return () => disconnect?.();
|
|
191
|
+
* }, [connect, disconnect]);
|
|
192
|
+
*
|
|
193
|
+
* return (
|
|
194
|
+
* <div>
|
|
195
|
+
* <StatusIndicator state={connectionState} />
|
|
196
|
+
* {messages.map((msg) => <Message key={msg.id} message={msg} />)}
|
|
197
|
+
* </div>
|
|
198
|
+
* );
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
declare function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn;
|
|
203
|
+
|
|
204
|
+
interface UseAutoScrollOptions {
|
|
205
|
+
/**
|
|
206
|
+
* Provide your own ref if you need to share the scroll container
|
|
207
|
+
* with other logic. When omitted, an internal ref is created.
|
|
208
|
+
*/
|
|
209
|
+
scrollRef?: RefObject<HTMLDivElement | null>;
|
|
210
|
+
/**
|
|
211
|
+
* Distance from the bottom (in pixels) within which auto-scroll
|
|
212
|
+
* stays active. Defaults to 80.
|
|
213
|
+
*/
|
|
214
|
+
threshold?: number;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Smart auto-scroll for chat interfaces.
|
|
218
|
+
*
|
|
219
|
+
* Scrolls to bottom when new content arrives, but pauses if the user
|
|
220
|
+
* has scrolled up to read earlier messages. Re-enables once the user
|
|
221
|
+
* scrolls back near the bottom.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```tsx
|
|
225
|
+
* const { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll } = useAutoScroll();
|
|
226
|
+
*
|
|
227
|
+
* useEffect(() => {
|
|
228
|
+
* const id = requestAnimationFrame(scrollOnUpdate);
|
|
229
|
+
* return () => cancelAnimationFrame(id);
|
|
230
|
+
* }, [messages, scrollOnUpdate]);
|
|
231
|
+
*
|
|
232
|
+
* <div ref={scrollRef} onScroll={handleScroll}>...</div>
|
|
233
|
+
*
|
|
234
|
+
* // On send: resetAutoScroll() to force-scroll on next update
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare function useAutoScroll(options?: UseAutoScrollOptions): {
|
|
238
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
239
|
+
handleScroll: () => void;
|
|
240
|
+
scrollOnUpdate: () => void;
|
|
241
|
+
resetAutoScroll: () => void;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export { type UseAutoScrollOptions, type UseOctavusChatReturn, useAutoScroll, useOctavusChat };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OctavusChatOptions, UIMessage, ChatStatus, OctavusError, ConnectionState, InteractiveTool, UserMessageInput, FileReference } from '@octavus/client-sdk';
|
|
2
2
|
export * from '@octavus/client-sdk';
|
|
3
3
|
export { AppError, ChatStatus, ClientToolContext, ClientToolHandler, ConflictError, ForbiddenError, InteractiveTool, MAIN_THREAD, NotFoundError, OCTAVUS_SKILL_TOOLS, OctavusChat, OctavusChatOptions, OctavusError, UserMessageInput, ValidationError, createApiErrorEvent, createErrorEvent, createHttpTransport, createInternalErrorEvent, createPollingTransport, createSocketTransport, errorToStreamEvent, generateId, getSkillSlugFromToolCall, isAbortError, isAuthenticationError, isFileReference, isFileReferenceArray, isMainThread, isOctavusSkillTool, isOtherThread, isProviderError, isRateLimitError, isRetryableError, isSocketTransport, isToolError, isValidationError, parseSSEStream, resolveThread, safeParseStreamEvent, safeParseUIMessage, safeParseUIMessages, threadForPart, uploadFiles } from '@octavus/client-sdk';
|
|
4
|
+
import { RefObject } from 'react';
|
|
4
5
|
|
|
5
6
|
interface UseOctavusChatReturn {
|
|
6
7
|
/** All messages including the currently streaming one */
|
|
@@ -200,4 +201,44 @@ interface UseOctavusChatReturn {
|
|
|
200
201
|
*/
|
|
201
202
|
declare function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn;
|
|
202
203
|
|
|
203
|
-
|
|
204
|
+
interface UseAutoScrollOptions {
|
|
205
|
+
/**
|
|
206
|
+
* Provide your own ref if you need to share the scroll container
|
|
207
|
+
* with other logic. When omitted, an internal ref is created.
|
|
208
|
+
*/
|
|
209
|
+
scrollRef?: RefObject<HTMLDivElement | null>;
|
|
210
|
+
/**
|
|
211
|
+
* Distance from the bottom (in pixels) within which auto-scroll
|
|
212
|
+
* stays active. Defaults to 80.
|
|
213
|
+
*/
|
|
214
|
+
threshold?: number;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Smart auto-scroll for chat interfaces.
|
|
218
|
+
*
|
|
219
|
+
* Scrolls to bottom when new content arrives, but pauses if the user
|
|
220
|
+
* has scrolled up to read earlier messages. Re-enables once the user
|
|
221
|
+
* scrolls back near the bottom.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```tsx
|
|
225
|
+
* const { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll } = useAutoScroll();
|
|
226
|
+
*
|
|
227
|
+
* useEffect(() => {
|
|
228
|
+
* const id = requestAnimationFrame(scrollOnUpdate);
|
|
229
|
+
* return () => cancelAnimationFrame(id);
|
|
230
|
+
* }, [messages, scrollOnUpdate]);
|
|
231
|
+
*
|
|
232
|
+
* <div ref={scrollRef} onScroll={handleScroll}>...</div>
|
|
233
|
+
*
|
|
234
|
+
* // On send: resetAutoScroll() to force-scroll on next update
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare function useAutoScroll(options?: UseAutoScrollOptions): {
|
|
238
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
239
|
+
handleScroll: () => void;
|
|
240
|
+
scrollOnUpdate: () => void;
|
|
241
|
+
resetAutoScroll: () => void;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export { type UseAutoScrollOptions, type UseOctavusChatReturn, useAutoScroll, useOctavusChat };
|
package/dist/index.js
CHANGED
|
@@ -100,6 +100,36 @@ function useOctavusChat(options) {
|
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
// src/hooks/use-auto-scroll.ts
|
|
104
|
+
import { useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
105
|
+
var DEFAULT_THRESHOLD_PX = 80;
|
|
106
|
+
function useAutoScroll(options = {}) {
|
|
107
|
+
const internalRef = useRef2(null);
|
|
108
|
+
const scrollRef = options.scrollRef ?? internalRef;
|
|
109
|
+
const threshold = options.threshold ?? DEFAULT_THRESHOLD_PX;
|
|
110
|
+
const shouldAutoScrollRef = useRef2(true);
|
|
111
|
+
const handleScroll = useCallback2(() => {
|
|
112
|
+
const el = scrollRef.current;
|
|
113
|
+
if (!el) return;
|
|
114
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
115
|
+
shouldAutoScrollRef.current = distanceFromBottom <= threshold;
|
|
116
|
+
}, [scrollRef, threshold]);
|
|
117
|
+
const scrollOnUpdate = useCallback2(() => {
|
|
118
|
+
const el = scrollRef.current;
|
|
119
|
+
if (!el) return;
|
|
120
|
+
if (shouldAutoScrollRef.current) {
|
|
121
|
+
el.scrollTop = el.scrollHeight;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
125
|
+
shouldAutoScrollRef.current = distanceFromBottom <= threshold;
|
|
126
|
+
}, [scrollRef, threshold]);
|
|
127
|
+
const resetAutoScroll = useCallback2(() => {
|
|
128
|
+
shouldAutoScrollRef.current = true;
|
|
129
|
+
}, []);
|
|
130
|
+
return { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll };
|
|
131
|
+
}
|
|
132
|
+
|
|
103
133
|
// src/index.ts
|
|
104
134
|
import {
|
|
105
135
|
OctavusChat as OctavusChat2,
|
|
@@ -180,6 +210,7 @@ export {
|
|
|
180
210
|
safeParseUIMessages,
|
|
181
211
|
threadForPart,
|
|
182
212
|
uploadFiles,
|
|
213
|
+
useAutoScroll,
|
|
183
214
|
useOctavusChat
|
|
184
215
|
};
|
|
185
216
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-octavus-chat.ts","../src/index.ts"],"sourcesContent":["'use client';\n\nimport { useRef, useCallback, useSyncExternalStore, useState, useEffect } from 'react';\nimport {\n OctavusChat,\n type OctavusError,\n isSocketTransport,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type UIMessage,\n type Transport,\n type ConnectionState,\n type FileReference,\n type UploadFilesOptions,\n type UploadUrlsResponse,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from '@octavus/client-sdk';\n\nexport type {\n OctavusChatOptions,\n ChatStatus,\n UserMessageInput,\n FileReference,\n UploadFilesOptions,\n UploadUrlsResponse,\n ClientToolContext,\n ClientToolHandler,\n InteractiveTool,\n};\n\nexport interface UseOctavusChatReturn {\n /** All messages including the currently streaming one */\n messages: UIMessage[];\n /** Current status of the chat */\n status: ChatStatus;\n /**\n * Error if status is 'error'.\n * Contains structured error information including type, source, and retryability.\n * Use type guards like `isRateLimitError()` or `isProviderError()` to check specific error types.\n */\n error: OctavusError | null;\n /**\n * The current session/execution ID from the most recent `send()` call.\n * Updated when the server responds with a `start` event containing an execution ID.\n * Useful for tracking activity logs or debugging.\n *\n * For workers, this is the execution ID. For interactive sessions, this is the session ID.\n */\n sessionId: string | null;\n /**\n * Socket connection state (socket transport only).\n * For HTTP transport, this is always `undefined`.\n *\n * - `disconnected`: Not connected (initial state before first send)\n * - `connecting`: Connection attempt in progress\n * - `connected`: Successfully connected\n * - `error`: Connection failed (check `connectionError`)\n */\n connectionState: ConnectionState | undefined;\n /**\n * Connection error if `connectionState` is 'error'.\n */\n connectionError: Error | undefined;\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 pendingClientTools: Record<string, InteractiveTool[]>;\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 send: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput },\n ) => Promise<void>;\n /** Stop the current streaming and finalize any partial message */\n stop: () => void;\n /**\n * Retry the last trigger from the same starting point.\n * Rolls back messages, re-adds the user message (if any), and re-executes.\n * No-op if no trigger has been sent yet.\n */\n retry: () => Promise<void>;\n /**\n * Observe an already-active execution without triggering a new one.\n * Only works with transports that support `observe()` (e.g., polling transport).\n * Use when the page loads and the session is already streaming.\n */\n observe: () => Promise<void>;\n /**\n * Replace the message list with externally-provided messages.\n * Use to sync with server-authoritative state (e.g., multi-observer scenarios).\n * Must NOT be called while streaming.\n */\n replaceMessages: (messages: UIMessage[]) => void;\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 canRetry: boolean;\n /**\n * Eagerly connect to the socket (socket transport only).\n * Returns a promise that resolves when connected or rejects on error.\n * Safe to call multiple times - subsequent calls resolve immediately if already connected.\n *\n * For HTTP transport, this is `undefined`.\n */\n connect: (() => Promise<void>) | undefined;\n /**\n * Disconnect the socket (socket transport only).\n * The transport will reconnect automatically on next send().\n *\n * For HTTP transport, this is `undefined`.\n */\n disconnect: (() => void) | undefined;\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 uploadFiles(fileInput.files, (i, progress) => {\n * console.log(`File ${i}: ${progress}%`);\n * });\n * // Later...\n * await send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });\n * ```\n */\n uploadFiles: (\n files: FileList | File[],\n onProgress?: (fileIndex: number, progress: number) => void,\n ) => Promise<FileReference[]>;\n}\n\n/**\n * React hook for interacting with Octavus agents.\n * Provides chat state management and streaming support.\n *\n * When the transport changes (e.g., sessionId changes), the hook automatically\n * reinitializes with a fresh chat instance. Use `initialMessages` if you need\n * to preserve messages across transport changes.\n *\n * @example Basic usage with HTTP transport\n * ```tsx\n * import { useOctavusChat, createHttpTransport } from '@octavus/react';\n *\n * function Chat({ sessionId }) {\n * const transport = useMemo(\n * () => 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 * [sessionId],\n * );\n *\n * const { messages, status, send } = useOctavusChat({ transport });\n *\n * return (\n * <div>\n * {messages.map((msg) => (\n * <Message key={msg.id} message={msg} />\n * ))}\n * <button onClick={() => send('user-message', { USER_MESSAGE: 'Hello' })}>\n * Send\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @example Socket transport with eager connection\n * ```tsx\n * import { useOctavusChat, createSocketTransport } from '@octavus/react';\n *\n * function Chat() {\n * const transport = useMemo(\n * () => createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/octavus');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * }),\n * }),\n * [],\n * );\n *\n * const { messages, status, send, connectionState, connect, disconnect } =\n * useOctavusChat({ transport });\n *\n * // Eager connection on mount\n * useEffect(() => {\n * connect?.();\n * return () => disconnect?.();\n * }, [connect, disconnect]);\n *\n * return (\n * <div>\n * <StatusIndicator state={connectionState} />\n * {messages.map((msg) => <Message key={msg.id} message={msg} />)}\n * </div>\n * );\n * }\n * ```\n */\nexport function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn {\n const chatRef = useRef<OctavusChat | null>(null);\n const transportRef = useRef<Transport | null>(null);\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n const sessionIdSetterRef = useRef(setSessionId);\n sessionIdSetterRef.current = setSessionId;\n\n if (transportRef.current !== options.transport) {\n chatRef.current?.stop();\n setSessionId(null);\n chatRef.current = new OctavusChat(options);\n transportRef.current = options.transport;\n }\n\n const chat = chatRef.current!;\n\n // Keep all mutable options (callbacks, tool handlers) fresh on every render.\n // This ensures handlers always reference the latest closures instead of going stale.\n chat.updateOptions({\n clientTools: options.clientTools,\n onError: options.onError,\n onFinish: options.onFinish,\n onStop: options.onStop,\n onResourceUpdate: options.onResourceUpdate,\n onStart: (id) => {\n sessionIdSetterRef.current(id);\n options.onStart?.(id);\n },\n requestUploadUrls: options.requestUploadUrls,\n uploadOptions: options.uploadOptions,\n });\n const transport = options.transport;\n\n const subscribe = useCallback((callback: () => void) => chat.subscribe(callback), [chat]);\n const getMessagesSnapshot = useCallback(() => chat.messages, [chat]);\n const getStatusSnapshot = useCallback(() => chat.status, [chat]);\n const getErrorSnapshot = useCallback(() => chat.error, [chat]);\n const getPendingClientToolsSnapshot = useCallback(() => chat.pendingClientTools, [chat]);\n const getCanRetrySnapshot = useCallback(() => chat.canRetry, [chat]);\n\n const messages = useSyncExternalStore(subscribe, getMessagesSnapshot, getMessagesSnapshot);\n const status = useSyncExternalStore(subscribe, getStatusSnapshot, getStatusSnapshot);\n const error = useSyncExternalStore(subscribe, getErrorSnapshot, getErrorSnapshot);\n const pendingClientTools = useSyncExternalStore(\n subscribe,\n getPendingClientToolsSnapshot,\n getPendingClientToolsSnapshot,\n );\n const canRetry = useSyncExternalStore(subscribe, getCanRetrySnapshot, getCanRetrySnapshot);\n\n const socketTransport = isSocketTransport(transport) ? transport : null;\n const [connectionState, setConnectionState] = useState<ConnectionState | undefined>(\n socketTransport?.connectionState,\n );\n const [connectionError, setConnectionError] = useState<Error | undefined>(undefined);\n\n useEffect(() => {\n if (!socketTransport) {\n setConnectionState(undefined);\n setConnectionError(undefined);\n return;\n }\n\n const unsubscribe = socketTransport.onConnectionStateChange((state, err) => {\n setConnectionState(state);\n setConnectionError(err);\n });\n\n return unsubscribe;\n }, [socketTransport]);\n\n const send = useCallback(\n (\n triggerName: string,\n input?: Record<string, unknown>,\n sendOptions?: { userMessage?: UserMessageInput },\n ) => chat.send(triggerName, input, sendOptions),\n [chat],\n );\n\n const stop = useCallback(() => chat.stop(), [chat]);\n const retry = useCallback(() => chat.retry(), [chat]);\n const observe = useCallback(() => chat.observe(), [chat]);\n const replaceMessages = useCallback((msgs: UIMessage[]) => chat.replaceMessages(msgs), [chat]);\n\n const uploadFiles = useCallback(\n (files: FileList | File[], onProgress?: (fileIndex: number, progress: number) => void) =>\n chat.uploadFiles(files, onProgress),\n [chat],\n );\n\n // Stable references for connect/disconnect (socket transport only)\n const connect = useCallback(\n () => socketTransport?.connect() ?? Promise.resolve(),\n [socketTransport],\n );\n const disconnect = useCallback(() => socketTransport?.disconnect(), [socketTransport]);\n\n return {\n messages,\n status,\n error,\n sessionId,\n connectionState,\n connectionError,\n pendingClientTools,\n send,\n stop,\n retry,\n observe,\n replaceMessages,\n canRetry,\n connect: socketTransport ? connect : undefined,\n disconnect: socketTransport ? disconnect : undefined,\n uploadFiles,\n };\n}\n","export {\n useOctavusChat,\n type UseOctavusChatReturn,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from './hooks/use-octavus-chat';\n\nexport type * from '@octavus/client-sdk';\nexport {\n // Chat\n OctavusChat,\n // Files\n uploadFiles,\n // Stream\n parseSSEStream,\n // Transports\n createHttpTransport,\n createSocketTransport,\n isSocketTransport,\n createPollingTransport,\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/client-sdk';\n"],"mappings":"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","names":["uploadFiles","OctavusChat","isSocketTransport"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-octavus-chat.ts","../src/hooks/use-auto-scroll.ts","../src/index.ts"],"sourcesContent":["'use client';\n\nimport { useRef, useCallback, useSyncExternalStore, useState, useEffect } from 'react';\nimport {\n OctavusChat,\n type OctavusError,\n isSocketTransport,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type UIMessage,\n type Transport,\n type ConnectionState,\n type FileReference,\n type UploadFilesOptions,\n type UploadUrlsResponse,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from '@octavus/client-sdk';\n\nexport type {\n OctavusChatOptions,\n ChatStatus,\n UserMessageInput,\n FileReference,\n UploadFilesOptions,\n UploadUrlsResponse,\n ClientToolContext,\n ClientToolHandler,\n InteractiveTool,\n};\n\nexport interface UseOctavusChatReturn {\n /** All messages including the currently streaming one */\n messages: UIMessage[];\n /** Current status of the chat */\n status: ChatStatus;\n /**\n * Error if status is 'error'.\n * Contains structured error information including type, source, and retryability.\n * Use type guards like `isRateLimitError()` or `isProviderError()` to check specific error types.\n */\n error: OctavusError | null;\n /**\n * The current session/execution ID from the most recent `send()` call.\n * Updated when the server responds with a `start` event containing an execution ID.\n * Useful for tracking activity logs or debugging.\n *\n * For workers, this is the execution ID. For interactive sessions, this is the session ID.\n */\n sessionId: string | null;\n /**\n * Socket connection state (socket transport only).\n * For HTTP transport, this is always `undefined`.\n *\n * - `disconnected`: Not connected (initial state before first send)\n * - `connecting`: Connection attempt in progress\n * - `connected`: Successfully connected\n * - `error`: Connection failed (check `connectionError`)\n */\n connectionState: ConnectionState | undefined;\n /**\n * Connection error if `connectionState` is 'error'.\n */\n connectionError: Error | undefined;\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 pendingClientTools: Record<string, InteractiveTool[]>;\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 send: (\n triggerName: string,\n input?: Record<string, unknown>,\n options?: { userMessage?: UserMessageInput },\n ) => Promise<void>;\n /** Stop the current streaming and finalize any partial message */\n stop: () => void;\n /**\n * Retry the last trigger from the same starting point.\n * Rolls back messages, re-adds the user message (if any), and re-executes.\n * No-op if no trigger has been sent yet.\n */\n retry: () => Promise<void>;\n /**\n * Observe an already-active execution without triggering a new one.\n * Only works with transports that support `observe()` (e.g., polling transport).\n * Use when the page loads and the session is already streaming.\n */\n observe: () => Promise<void>;\n /**\n * Replace the message list with externally-provided messages.\n * Use to sync with server-authoritative state (e.g., multi-observer scenarios).\n * Must NOT be called while streaming.\n */\n replaceMessages: (messages: UIMessage[]) => void;\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 canRetry: boolean;\n /**\n * Eagerly connect to the socket (socket transport only).\n * Returns a promise that resolves when connected or rejects on error.\n * Safe to call multiple times - subsequent calls resolve immediately if already connected.\n *\n * For HTTP transport, this is `undefined`.\n */\n connect: (() => Promise<void>) | undefined;\n /**\n * Disconnect the socket (socket transport only).\n * The transport will reconnect automatically on next send().\n *\n * For HTTP transport, this is `undefined`.\n */\n disconnect: (() => void) | undefined;\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 uploadFiles(fileInput.files, (i, progress) => {\n * console.log(`File ${i}: ${progress}%`);\n * });\n * // Later...\n * await send('user-message', { FILES: fileRefs }, { userMessage: { files: fileRefs } });\n * ```\n */\n uploadFiles: (\n files: FileList | File[],\n onProgress?: (fileIndex: number, progress: number) => void,\n ) => Promise<FileReference[]>;\n}\n\n/**\n * React hook for interacting with Octavus agents.\n * Provides chat state management and streaming support.\n *\n * When the transport changes (e.g., sessionId changes), the hook automatically\n * reinitializes with a fresh chat instance. Use `initialMessages` if you need\n * to preserve messages across transport changes.\n *\n * @example Basic usage with HTTP transport\n * ```tsx\n * import { useOctavusChat, createHttpTransport } from '@octavus/react';\n *\n * function Chat({ sessionId }) {\n * const transport = useMemo(\n * () => 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 * [sessionId],\n * );\n *\n * const { messages, status, send } = useOctavusChat({ transport });\n *\n * return (\n * <div>\n * {messages.map((msg) => (\n * <Message key={msg.id} message={msg} />\n * ))}\n * <button onClick={() => send('user-message', { USER_MESSAGE: 'Hello' })}>\n * Send\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @example Socket transport with eager connection\n * ```tsx\n * import { useOctavusChat, createSocketTransport } from '@octavus/react';\n *\n * function Chat() {\n * const transport = useMemo(\n * () => createSocketTransport({\n * connect: () => new Promise((resolve, reject) => {\n * const sock = new SockJS('/octavus');\n * sock.onopen = () => resolve(sock);\n * sock.onerror = () => reject(new Error('Connection failed'));\n * }),\n * }),\n * [],\n * );\n *\n * const { messages, status, send, connectionState, connect, disconnect } =\n * useOctavusChat({ transport });\n *\n * // Eager connection on mount\n * useEffect(() => {\n * connect?.();\n * return () => disconnect?.();\n * }, [connect, disconnect]);\n *\n * return (\n * <div>\n * <StatusIndicator state={connectionState} />\n * {messages.map((msg) => <Message key={msg.id} message={msg} />)}\n * </div>\n * );\n * }\n * ```\n */\nexport function useOctavusChat(options: OctavusChatOptions): UseOctavusChatReturn {\n const chatRef = useRef<OctavusChat | null>(null);\n const transportRef = useRef<Transport | null>(null);\n const [sessionId, setSessionId] = useState<string | null>(null);\n\n const sessionIdSetterRef = useRef(setSessionId);\n sessionIdSetterRef.current = setSessionId;\n\n if (transportRef.current !== options.transport) {\n chatRef.current?.stop();\n setSessionId(null);\n chatRef.current = new OctavusChat(options);\n transportRef.current = options.transport;\n }\n\n const chat = chatRef.current!;\n\n // Keep all mutable options (callbacks, tool handlers) fresh on every render.\n // This ensures handlers always reference the latest closures instead of going stale.\n chat.updateOptions({\n clientTools: options.clientTools,\n onError: options.onError,\n onFinish: options.onFinish,\n onStop: options.onStop,\n onResourceUpdate: options.onResourceUpdate,\n onStart: (id) => {\n sessionIdSetterRef.current(id);\n options.onStart?.(id);\n },\n requestUploadUrls: options.requestUploadUrls,\n uploadOptions: options.uploadOptions,\n });\n const transport = options.transport;\n\n const subscribe = useCallback((callback: () => void) => chat.subscribe(callback), [chat]);\n const getMessagesSnapshot = useCallback(() => chat.messages, [chat]);\n const getStatusSnapshot = useCallback(() => chat.status, [chat]);\n const getErrorSnapshot = useCallback(() => chat.error, [chat]);\n const getPendingClientToolsSnapshot = useCallback(() => chat.pendingClientTools, [chat]);\n const getCanRetrySnapshot = useCallback(() => chat.canRetry, [chat]);\n\n const messages = useSyncExternalStore(subscribe, getMessagesSnapshot, getMessagesSnapshot);\n const status = useSyncExternalStore(subscribe, getStatusSnapshot, getStatusSnapshot);\n const error = useSyncExternalStore(subscribe, getErrorSnapshot, getErrorSnapshot);\n const pendingClientTools = useSyncExternalStore(\n subscribe,\n getPendingClientToolsSnapshot,\n getPendingClientToolsSnapshot,\n );\n const canRetry = useSyncExternalStore(subscribe, getCanRetrySnapshot, getCanRetrySnapshot);\n\n const socketTransport = isSocketTransport(transport) ? transport : null;\n const [connectionState, setConnectionState] = useState<ConnectionState | undefined>(\n socketTransport?.connectionState,\n );\n const [connectionError, setConnectionError] = useState<Error | undefined>(undefined);\n\n useEffect(() => {\n if (!socketTransport) {\n setConnectionState(undefined);\n setConnectionError(undefined);\n return;\n }\n\n const unsubscribe = socketTransport.onConnectionStateChange((state, err) => {\n setConnectionState(state);\n setConnectionError(err);\n });\n\n return unsubscribe;\n }, [socketTransport]);\n\n const send = useCallback(\n (\n triggerName: string,\n input?: Record<string, unknown>,\n sendOptions?: { userMessage?: UserMessageInput },\n ) => chat.send(triggerName, input, sendOptions),\n [chat],\n );\n\n const stop = useCallback(() => chat.stop(), [chat]);\n const retry = useCallback(() => chat.retry(), [chat]);\n const observe = useCallback(() => chat.observe(), [chat]);\n const replaceMessages = useCallback((msgs: UIMessage[]) => chat.replaceMessages(msgs), [chat]);\n\n const uploadFiles = useCallback(\n (files: FileList | File[], onProgress?: (fileIndex: number, progress: number) => void) =>\n chat.uploadFiles(files, onProgress),\n [chat],\n );\n\n // Stable references for connect/disconnect (socket transport only)\n const connect = useCallback(\n () => socketTransport?.connect() ?? Promise.resolve(),\n [socketTransport],\n );\n const disconnect = useCallback(() => socketTransport?.disconnect(), [socketTransport]);\n\n return {\n messages,\n status,\n error,\n sessionId,\n connectionState,\n connectionError,\n pendingClientTools,\n send,\n stop,\n retry,\n observe,\n replaceMessages,\n canRetry,\n connect: socketTransport ? connect : undefined,\n disconnect: socketTransport ? disconnect : undefined,\n uploadFiles,\n };\n}\n","'use client';\n\nimport { type RefObject, useRef, useCallback } from 'react';\n\nconst DEFAULT_THRESHOLD_PX = 80;\n\nexport interface UseAutoScrollOptions {\n /**\n * Provide your own ref if you need to share the scroll container\n * with other logic. When omitted, an internal ref is created.\n */\n scrollRef?: RefObject<HTMLDivElement | null>;\n\n /**\n * Distance from the bottom (in pixels) within which auto-scroll\n * stays active. Defaults to 80.\n */\n threshold?: number;\n}\n\n/**\n * Smart auto-scroll for chat interfaces.\n *\n * Scrolls to bottom when new content arrives, but pauses if the user\n * has scrolled up to read earlier messages. Re-enables once the user\n * scrolls back near the bottom.\n *\n * @example\n * ```tsx\n * const { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll } = useAutoScroll();\n *\n * useEffect(() => {\n * const id = requestAnimationFrame(scrollOnUpdate);\n * return () => cancelAnimationFrame(id);\n * }, [messages, scrollOnUpdate]);\n *\n * <div ref={scrollRef} onScroll={handleScroll}>...</div>\n *\n * // On send: resetAutoScroll() to force-scroll on next update\n * ```\n */\nexport function useAutoScroll(options: UseAutoScrollOptions = {}) {\n const internalRef = useRef<HTMLDivElement>(null);\n const scrollRef = options.scrollRef ?? internalRef;\n const threshold = options.threshold ?? DEFAULT_THRESHOLD_PX;\n const shouldAutoScrollRef = useRef(true);\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;\n shouldAutoScrollRef.current = distanceFromBottom <= threshold;\n }, [scrollRef, threshold]);\n\n const scrollOnUpdate = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n if (shouldAutoScrollRef.current) {\n el.scrollTop = el.scrollHeight;\n return;\n }\n\n const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;\n shouldAutoScrollRef.current = distanceFromBottom <= threshold;\n }, [scrollRef, threshold]);\n\n const resetAutoScroll = useCallback(() => {\n shouldAutoScrollRef.current = true;\n }, []);\n\n return { scrollRef, handleScroll, scrollOnUpdate, resetAutoScroll };\n}\n","export {\n useOctavusChat,\n type UseOctavusChatReturn,\n type OctavusChatOptions,\n type ChatStatus,\n type UserMessageInput,\n type ClientToolContext,\n type ClientToolHandler,\n type InteractiveTool,\n} from './hooks/use-octavus-chat';\n\nexport { useAutoScroll, type UseAutoScrollOptions } from './hooks/use-auto-scroll';\n\nexport type * from '@octavus/client-sdk';\nexport {\n // Chat\n OctavusChat,\n // Files\n uploadFiles,\n // Stream\n parseSSEStream,\n // Transports\n createHttpTransport,\n createSocketTransport,\n isSocketTransport,\n createPollingTransport,\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/client-sdk';\n"],"mappings":"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","names":["uploadFiles","useRef","useCallback","OctavusChat","isSocketTransport"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octavus/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.0",
|
|
4
4
|
"description": "React bindings for Octavus agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Octavus AI <dev@octavus.ai>",
|
|
@@ -25,12 +25,19 @@
|
|
|
25
25
|
],
|
|
26
26
|
"type": "module",
|
|
27
27
|
"sideEffects": false,
|
|
28
|
-
"main": "./dist/index.
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"module": "./dist/index.js",
|
|
29
30
|
"types": "./dist/index.d.ts",
|
|
30
31
|
"exports": {
|
|
31
32
|
".": {
|
|
32
|
-
"
|
|
33
|
-
|
|
33
|
+
"import": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"require": {
|
|
38
|
+
"types": "./dist/index.d.cts",
|
|
39
|
+
"default": "./dist/index.cjs"
|
|
40
|
+
}
|
|
34
41
|
}
|
|
35
42
|
},
|
|
36
43
|
"files": [
|
|
@@ -40,7 +47,7 @@
|
|
|
40
47
|
"access": "public"
|
|
41
48
|
},
|
|
42
49
|
"dependencies": {
|
|
43
|
-
"@octavus/client-sdk": "^2.
|
|
50
|
+
"@octavus/client-sdk": "^2.21.0"
|
|
44
51
|
},
|
|
45
52
|
"peerDependencies": {
|
|
46
53
|
"react": ">=18.0.0"
|