@meetsmore-oss/use-ai-client 1.7.0 → 1.8.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/bundled.js +18427 -18352
- package/dist/bundled.js.map +1 -1
- package/dist/index.d.ts +212 -140
- package/dist/index.js +488 -425
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,13 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-STF3H6F5.js";
|
|
5
5
|
|
|
6
6
|
// src/useAI.ts
|
|
7
|
-
import { useState as useState14, useEffect as
|
|
7
|
+
import { useState as useState14, useEffect as useEffect12, useLayoutEffect, useRef as useRef14, useCallback as useCallback13, useMemo as useMemo6 } from "react";
|
|
8
8
|
|
|
9
9
|
// src/providers/useAIProvider.tsx
|
|
10
|
-
import { createContext as createContext4, useContext as useContext4, useState as useState13, useEffect as
|
|
11
|
-
|
|
12
|
-
// src/types.ts
|
|
13
|
-
import { EventType, ErrorCode, TOOL_APPROVAL_REQUEST } from "@meetsmore-oss/use-ai-core";
|
|
10
|
+
import { createContext as createContext4, useContext as useContext4, useState as useState13, useEffect as useEffect11, useCallback as useCallback12, useRef as useRef12 } from "react";
|
|
14
11
|
|
|
15
12
|
// src/theme/strings.ts
|
|
16
13
|
import { createContext, useContext } from "react";
|
|
@@ -3051,7 +3048,7 @@ function UseAIChat({ floating = false }) {
|
|
|
3051
3048
|
|
|
3052
3049
|
// src/client.ts
|
|
3053
3050
|
import { io } from "socket.io-client";
|
|
3054
|
-
import { EventType
|
|
3051
|
+
import { EventType } from "@meetsmore-oss/use-ai-core";
|
|
3055
3052
|
import { v4 as uuidv42 } from "uuid";
|
|
3056
3053
|
var UseAIClient = class {
|
|
3057
3054
|
/**
|
|
@@ -3146,7 +3143,7 @@ var UseAIClient = class {
|
|
|
3146
3143
|
});
|
|
3147
3144
|
}
|
|
3148
3145
|
handleEvent(event) {
|
|
3149
|
-
if (event.type ===
|
|
3146
|
+
if (event.type === EventType.RUN_STARTED) {
|
|
3150
3147
|
this._currentAssistantMessage = {
|
|
3151
3148
|
id: uuidv42(),
|
|
3152
3149
|
role: "assistant",
|
|
@@ -3154,31 +3151,31 @@ var UseAIClient = class {
|
|
|
3154
3151
|
};
|
|
3155
3152
|
this._currentAssistantToolCalls = [];
|
|
3156
3153
|
}
|
|
3157
|
-
if (event.type ===
|
|
3154
|
+
if (event.type === EventType.TEXT_MESSAGE_START) {
|
|
3158
3155
|
const e = event;
|
|
3159
3156
|
this._currentMessageId = e.messageId;
|
|
3160
3157
|
this._currentMessageContent = "";
|
|
3161
|
-
} else if (event.type ===
|
|
3158
|
+
} else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
|
|
3162
3159
|
const e = event;
|
|
3163
3160
|
this._currentMessageContent += e.delta;
|
|
3164
|
-
} else if (event.type ===
|
|
3161
|
+
} else if (event.type === EventType.TEXT_MESSAGE_END) {
|
|
3165
3162
|
if (this._currentAssistantMessage) {
|
|
3166
3163
|
this._currentAssistantMessage.content = this._currentMessageContent;
|
|
3167
3164
|
}
|
|
3168
3165
|
this._currentMessageId = null;
|
|
3169
|
-
} else if (event.type ===
|
|
3166
|
+
} else if (event.type === EventType.TOOL_CALL_START) {
|
|
3170
3167
|
const e = event;
|
|
3171
3168
|
this.currentToolCalls.set(e.toolCallId, {
|
|
3172
3169
|
name: e.toolCallName,
|
|
3173
3170
|
args: ""
|
|
3174
3171
|
});
|
|
3175
|
-
} else if (event.type ===
|
|
3172
|
+
} else if (event.type === EventType.TOOL_CALL_ARGS) {
|
|
3176
3173
|
const e = event;
|
|
3177
3174
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3178
3175
|
if (toolCall) {
|
|
3179
3176
|
toolCall.args += e.delta;
|
|
3180
3177
|
}
|
|
3181
|
-
} else if (event.type ===
|
|
3178
|
+
} else if (event.type === EventType.TOOL_CALL_END) {
|
|
3182
3179
|
const e = event;
|
|
3183
3180
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3184
3181
|
if (toolCall) {
|
|
@@ -3191,7 +3188,7 @@ var UseAIClient = class {
|
|
|
3191
3188
|
}
|
|
3192
3189
|
});
|
|
3193
3190
|
}
|
|
3194
|
-
} else if (event.type ===
|
|
3191
|
+
} else if (event.type === EventType.RUN_FINISHED) {
|
|
3195
3192
|
if (this._currentAssistantMessage) {
|
|
3196
3193
|
const assistantMessage = {
|
|
3197
3194
|
id: this._currentAssistantMessage.id,
|
|
@@ -3308,7 +3305,13 @@ var UseAIClient = class {
|
|
|
3308
3305
|
messageId: uuidv42(),
|
|
3309
3306
|
toolCallId,
|
|
3310
3307
|
content: JSON.stringify(result),
|
|
3311
|
-
role: "tool"
|
|
3308
|
+
role: "tool",
|
|
3309
|
+
// use-ai extension: include current tools and state for mid-run updates
|
|
3310
|
+
// (e.g., when navigation causes new components to mount)
|
|
3311
|
+
forwardedProps: {
|
|
3312
|
+
tools: this._tools,
|
|
3313
|
+
state: this._state
|
|
3314
|
+
}
|
|
3312
3315
|
}
|
|
3313
3316
|
};
|
|
3314
3317
|
const toolResultMsg = {
|
|
@@ -3371,7 +3374,7 @@ var UseAIClient = class {
|
|
|
3371
3374
|
*/
|
|
3372
3375
|
onTextMessage(handler) {
|
|
3373
3376
|
return this.onEvent("text-message-handler", (event) => {
|
|
3374
|
-
if (event.type ===
|
|
3377
|
+
if (event.type === EventType.TEXT_MESSAGE_END && this._currentMessageContent) {
|
|
3375
3378
|
handler(this._currentMessageContent);
|
|
3376
3379
|
}
|
|
3377
3380
|
});
|
|
@@ -3385,7 +3388,7 @@ var UseAIClient = class {
|
|
|
3385
3388
|
*/
|
|
3386
3389
|
onToolCall(handler) {
|
|
3387
3390
|
return this.onEvent("tool-call-handler", (event) => {
|
|
3388
|
-
if (event.type ===
|
|
3391
|
+
if (event.type === EventType.TOOL_CALL_END) {
|
|
3389
3392
|
const e = event;
|
|
3390
3393
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3391
3394
|
if (toolCall) {
|
|
@@ -3850,11 +3853,7 @@ function useChatManagement({
|
|
|
3850
3853
|
clientRef,
|
|
3851
3854
|
messages,
|
|
3852
3855
|
setMessages,
|
|
3853
|
-
|
|
3854
|
-
setOpen,
|
|
3855
|
-
connected,
|
|
3856
|
-
loading,
|
|
3857
|
-
hasPendingApproval
|
|
3856
|
+
connected
|
|
3858
3857
|
}) {
|
|
3859
3858
|
const [currentChatId, setCurrentChatId] = useState6(null);
|
|
3860
3859
|
const [pendingChatId, setPendingChatId] = useState6(null);
|
|
@@ -3885,7 +3884,7 @@ function useChatManagement({
|
|
|
3885
3884
|
const reloadMessages = useCallback4(async (chatId) => {
|
|
3886
3885
|
const loadedMessages = await loadChatMessages(chatId);
|
|
3887
3886
|
setMessages(loadedMessages);
|
|
3888
|
-
}, [loadChatMessages]);
|
|
3887
|
+
}, [loadChatMessages, setMessages]);
|
|
3889
3888
|
const createNewChat = useCallback4(async (options) => {
|
|
3890
3889
|
console.log("[ChatManagement] createNewChat called - currentChatId:", currentChatId, "pendingChatId:", pendingChatId, "messages.length:", messages.length);
|
|
3891
3890
|
if (pendingChatId && messages.length === 0) {
|
|
@@ -3906,7 +3905,7 @@ function useChatManagement({
|
|
|
3906
3905
|
}
|
|
3907
3906
|
console.log("[ChatManagement] Created pending chat:", chatId, "(will activate on first message)");
|
|
3908
3907
|
return chatId;
|
|
3909
|
-
}, [currentChatId, pendingChatId, messages, repository, clientRef]);
|
|
3908
|
+
}, [currentChatId, pendingChatId, messages, repository, clientRef, setMessages]);
|
|
3910
3909
|
const loadChat = useCallback4(async (chatId) => {
|
|
3911
3910
|
setPendingChatId(chatId);
|
|
3912
3911
|
await reloadMessages(chatId);
|
|
@@ -3927,7 +3926,7 @@ function useChatManagement({
|
|
|
3927
3926
|
setMessages([]);
|
|
3928
3927
|
}
|
|
3929
3928
|
console.log("[ChatManagement] Deleted chat:", chatId);
|
|
3930
|
-
}, [currentChatId, pendingChatId, repository]);
|
|
3929
|
+
}, [currentChatId, pendingChatId, repository, setMessages]);
|
|
3931
3930
|
const listChats = useCallback4(async () => {
|
|
3932
3931
|
return await repository.listChats();
|
|
3933
3932
|
}, [repository]);
|
|
@@ -3941,7 +3940,7 @@ function useChatManagement({
|
|
|
3941
3940
|
console.log("[ChatManagement] Cleared current chat:", currentChatId);
|
|
3942
3941
|
}
|
|
3943
3942
|
}
|
|
3944
|
-
}, [currentChatId, repository]);
|
|
3943
|
+
}, [currentChatId, repository, setMessages]);
|
|
3945
3944
|
const getCurrentChat = useCallback4(async () => {
|
|
3946
3945
|
const chatId = pendingChatId || currentChatId;
|
|
3947
3946
|
if (!chatId) return null;
|
|
@@ -4068,76 +4067,8 @@ function useChatManagement({
|
|
|
4068
4067
|
}
|
|
4069
4068
|
})();
|
|
4070
4069
|
}
|
|
4071
|
-
}, [currentChatId, pendingChatId, createNewChat, repository, loadChatMessages, clientRef]);
|
|
4070
|
+
}, [currentChatId, pendingChatId, createNewChat, repository, loadChatMessages, clientRef, setMessages]);
|
|
4072
4071
|
const displayedChatId = pendingChatId || currentChatId;
|
|
4073
|
-
const pendingMessagesRef = useRef5([]);
|
|
4074
|
-
const isProcessingQueueRef = useRef5(false);
|
|
4075
|
-
const loadingRef = useRef5(loading);
|
|
4076
|
-
useEffect5(() => {
|
|
4077
|
-
loadingRef.current = loading;
|
|
4078
|
-
}, [loading]);
|
|
4079
|
-
const hasPendingApprovalRef = useRef5(hasPendingApproval);
|
|
4080
|
-
useEffect5(() => {
|
|
4081
|
-
hasPendingApprovalRef.current = hasPendingApproval;
|
|
4082
|
-
}, [hasPendingApproval]);
|
|
4083
|
-
const processMessageQueue = useCallback4(async () => {
|
|
4084
|
-
if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0 || !onSendMessage) {
|
|
4085
|
-
return;
|
|
4086
|
-
}
|
|
4087
|
-
isProcessingQueueRef.current = true;
|
|
4088
|
-
while (pendingMessagesRef.current.length > 0) {
|
|
4089
|
-
const { message, options } = pendingMessagesRef.current.shift();
|
|
4090
|
-
const { newChat = false, attachments = [], openChat = true, metadata, forwardedProps } = options ?? {};
|
|
4091
|
-
if (newChat) {
|
|
4092
|
-
await createNewChat({ metadata });
|
|
4093
|
-
}
|
|
4094
|
-
const fileAttachments = await Promise.all(
|
|
4095
|
-
attachments.map(async (file) => {
|
|
4096
|
-
let preview;
|
|
4097
|
-
if (file.type.startsWith("image/")) {
|
|
4098
|
-
preview = await new Promise((resolve) => {
|
|
4099
|
-
const reader = new FileReader();
|
|
4100
|
-
reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : void 0);
|
|
4101
|
-
reader.onerror = () => resolve(void 0);
|
|
4102
|
-
reader.readAsDataURL(file);
|
|
4103
|
-
});
|
|
4104
|
-
}
|
|
4105
|
-
return {
|
|
4106
|
-
id: crypto.randomUUID(),
|
|
4107
|
-
file,
|
|
4108
|
-
preview
|
|
4109
|
-
};
|
|
4110
|
-
})
|
|
4111
|
-
);
|
|
4112
|
-
await onSendMessage(message, fileAttachments.length > 0 ? fileAttachments : void 0, forwardedProps);
|
|
4113
|
-
if (openChat && setOpen) {
|
|
4114
|
-
setOpen(true);
|
|
4115
|
-
}
|
|
4116
|
-
await new Promise((resolve) => {
|
|
4117
|
-
const checkReady = () => {
|
|
4118
|
-
setTimeout(() => {
|
|
4119
|
-
if (!loadingRef.current && !hasPendingApprovalRef.current) {
|
|
4120
|
-
resolve();
|
|
4121
|
-
} else {
|
|
4122
|
-
checkReady();
|
|
4123
|
-
}
|
|
4124
|
-
}, 100);
|
|
4125
|
-
};
|
|
4126
|
-
checkReady();
|
|
4127
|
-
});
|
|
4128
|
-
}
|
|
4129
|
-
isProcessingQueueRef.current = false;
|
|
4130
|
-
}, [onSendMessage, createNewChat, setOpen]);
|
|
4131
|
-
const sendMessage = useCallback4(async (message, options) => {
|
|
4132
|
-
if (!onSendMessage) {
|
|
4133
|
-
throw new Error("sendMessage is not available (onSendMessage callback not provided)");
|
|
4134
|
-
}
|
|
4135
|
-
if (!connected) {
|
|
4136
|
-
throw new Error("Not connected to UseAI server");
|
|
4137
|
-
}
|
|
4138
|
-
pendingMessagesRef.current.push({ message, options });
|
|
4139
|
-
await processMessageQueue();
|
|
4140
|
-
}, [onSendMessage, connected, processMessageQueue]);
|
|
4141
4072
|
return {
|
|
4142
4073
|
currentChatId,
|
|
4143
4074
|
pendingChatId,
|
|
@@ -4151,7 +4082,6 @@ function useChatManagement({
|
|
|
4151
4082
|
saveUserMessage,
|
|
4152
4083
|
saveAIResponse,
|
|
4153
4084
|
reloadMessages,
|
|
4154
|
-
sendMessage,
|
|
4155
4085
|
getCurrentChat,
|
|
4156
4086
|
updateMetadata,
|
|
4157
4087
|
currentChatIdSnapshot,
|
|
@@ -4399,16 +4329,25 @@ function useCommandManagement({
|
|
|
4399
4329
|
};
|
|
4400
4330
|
}
|
|
4401
4331
|
|
|
4402
|
-
// src/hooks/
|
|
4332
|
+
// src/hooks/useToolSystem.ts
|
|
4403
4333
|
import { useState as useState9, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
|
|
4404
|
-
function
|
|
4334
|
+
function useToolSystem({
|
|
4335
|
+
clientRef,
|
|
4336
|
+
buildState
|
|
4337
|
+
}) {
|
|
4405
4338
|
const toolRegistryRef = useRef7(/* @__PURE__ */ new Map());
|
|
4406
4339
|
const [toolRegistryVersion, setToolRegistryVersion] = useState9(0);
|
|
4407
4340
|
const toolOwnershipRef = useRef7(/* @__PURE__ */ new Map());
|
|
4408
4341
|
const invisibleRef = useRef7(/* @__PURE__ */ new Set());
|
|
4342
|
+
const readyStateRef = useRef7(/* @__PURE__ */ new Map());
|
|
4343
|
+
const readyListenersRef = useRef7(/* @__PURE__ */ new Set());
|
|
4344
|
+
const waitersRef = useRef7(/* @__PURE__ */ new Map());
|
|
4345
|
+
const [pendingApprovals, setPendingApprovals] = useState9([]);
|
|
4346
|
+
const pendingApprovalToolCallsRef = useRef7(/* @__PURE__ */ new Map());
|
|
4409
4347
|
const registerTools = useCallback7((id, tools, options) => {
|
|
4410
4348
|
const existingTools = toolRegistryRef.current.get(id);
|
|
4411
4349
|
toolRegistryRef.current.set(id, tools);
|
|
4350
|
+
readyStateRef.current.set(id, false);
|
|
4412
4351
|
if (existingTools) {
|
|
4413
4352
|
const existingKeys = Object.keys(existingTools).sort().join(",");
|
|
4414
4353
|
const newKeys = Object.keys(tools).sort().join(",");
|
|
@@ -4427,6 +4366,13 @@ function useToolRegistry() {
|
|
|
4427
4366
|
invisibleRef.current.delete(id);
|
|
4428
4367
|
}
|
|
4429
4368
|
}, []);
|
|
4369
|
+
const signalReady = useCallback7((id) => {
|
|
4370
|
+
if (!toolRegistryRef.current.has(id)) {
|
|
4371
|
+
return;
|
|
4372
|
+
}
|
|
4373
|
+
readyStateRef.current.set(id, true);
|
|
4374
|
+
readyListenersRef.current.forEach((listener) => listener());
|
|
4375
|
+
}, []);
|
|
4430
4376
|
const unregisterTools = useCallback7((id) => {
|
|
4431
4377
|
const tools = toolRegistryRef.current.get(id);
|
|
4432
4378
|
if (tools) {
|
|
@@ -4435,8 +4381,10 @@ function useToolRegistry() {
|
|
|
4435
4381
|
});
|
|
4436
4382
|
}
|
|
4437
4383
|
toolRegistryRef.current.delete(id);
|
|
4384
|
+
readyStateRef.current.delete(id);
|
|
4438
4385
|
setToolRegistryVersion((v) => v + 1);
|
|
4439
4386
|
invisibleRef.current.delete(id);
|
|
4387
|
+
readyListenersRef.current.forEach((listener) => listener());
|
|
4440
4388
|
}, []);
|
|
4441
4389
|
const isInvisible = useCallback7((id) => {
|
|
4442
4390
|
return invisibleRef.current.has(id);
|
|
@@ -4451,14 +4399,159 @@ function useToolRegistry() {
|
|
|
4451
4399
|
const hasTools = toolRegistryRef.current.size > 0;
|
|
4452
4400
|
const aggregatedToolsRef = useRef7(aggregatedTools);
|
|
4453
4401
|
aggregatedToolsRef.current = aggregatedTools;
|
|
4402
|
+
const waitForToolsToStabilize = useCallback7(async () => {
|
|
4403
|
+
const maxWaitMs = 500;
|
|
4404
|
+
const checkAllReady = () => {
|
|
4405
|
+
if (readyStateRef.current.size === 0) return true;
|
|
4406
|
+
for (const ready of readyStateRef.current.values()) {
|
|
4407
|
+
if (!ready) return false;
|
|
4408
|
+
}
|
|
4409
|
+
return true;
|
|
4410
|
+
};
|
|
4411
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4412
|
+
if (checkAllReady()) {
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4415
|
+
return new Promise((resolve) => {
|
|
4416
|
+
let safetyTimeout = null;
|
|
4417
|
+
let resolved = false;
|
|
4418
|
+
const cleanup = () => {
|
|
4419
|
+
if (resolved) return;
|
|
4420
|
+
resolved = true;
|
|
4421
|
+
if (safetyTimeout) clearTimeout(safetyTimeout);
|
|
4422
|
+
readyListenersRef.current.delete(onReadyChange);
|
|
4423
|
+
};
|
|
4424
|
+
const onReadyChange = () => {
|
|
4425
|
+
if (resolved) return;
|
|
4426
|
+
if (checkAllReady()) {
|
|
4427
|
+
cleanup();
|
|
4428
|
+
resolve();
|
|
4429
|
+
}
|
|
4430
|
+
};
|
|
4431
|
+
safetyTimeout = setTimeout(() => {
|
|
4432
|
+
cleanup();
|
|
4433
|
+
resolve();
|
|
4434
|
+
}, maxWaitMs);
|
|
4435
|
+
readyListenersRef.current.add(onReadyChange);
|
|
4436
|
+
onReadyChange();
|
|
4437
|
+
});
|
|
4438
|
+
}, []);
|
|
4439
|
+
const registerWaiter = useCallback7((id, waiter) => {
|
|
4440
|
+
waitersRef.current.set(id, waiter);
|
|
4441
|
+
}, []);
|
|
4442
|
+
const unregisterWaiter = useCallback7((id) => {
|
|
4443
|
+
waitersRef.current.delete(id);
|
|
4444
|
+
}, []);
|
|
4445
|
+
const getWaiter = useCallback7((id) => {
|
|
4446
|
+
return waitersRef.current.get(id);
|
|
4447
|
+
}, []);
|
|
4448
|
+
const handleApprovalRequest = useCallback7((event) => {
|
|
4449
|
+
console.log("[useToolSystem] Tool approval requested:", event.toolCallName, event.toolCallId);
|
|
4450
|
+
setPendingApprovals((prev) => [
|
|
4451
|
+
...prev,
|
|
4452
|
+
{
|
|
4453
|
+
toolCallId: event.toolCallId,
|
|
4454
|
+
toolCallName: event.toolCallName,
|
|
4455
|
+
toolCallArgs: event.toolCallArgs,
|
|
4456
|
+
annotations: event.annotations
|
|
4457
|
+
}
|
|
4458
|
+
]);
|
|
4459
|
+
}, []);
|
|
4460
|
+
const executeToolCall = useCallback7(async (toolCallId, name, input) => {
|
|
4461
|
+
const client = clientRef.current;
|
|
4462
|
+
if (!client) {
|
|
4463
|
+
console.error("[useToolSystem] No client available for tool execution");
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
try {
|
|
4467
|
+
const ownerId = toolOwnershipRef.current.get(name);
|
|
4468
|
+
console.log(`[useToolSystem] Tool "${name}" owned by component:`, ownerId);
|
|
4469
|
+
console.log("[useToolSystem] Executing tool...");
|
|
4470
|
+
const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
|
|
4471
|
+
const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
|
|
4472
|
+
const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
|
|
4473
|
+
if (ownerId && !isErrorResult && !ownerIsInvisible) {
|
|
4474
|
+
const waiter = getWaiter(ownerId);
|
|
4475
|
+
if (waiter) {
|
|
4476
|
+
console.log(`[useToolSystem] Waiting for prompt change from ${ownerId}...`);
|
|
4477
|
+
await waiter();
|
|
4478
|
+
console.log("[useToolSystem] Prompt change wait complete");
|
|
4479
|
+
}
|
|
4480
|
+
} else if (isErrorResult) {
|
|
4481
|
+
console.log("[useToolSystem] Tool returned error, skipping prompt wait");
|
|
4482
|
+
} else if (ownerIsInvisible) {
|
|
4483
|
+
console.log("[useToolSystem] Component is invisible, skipping prompt wait");
|
|
4484
|
+
}
|
|
4485
|
+
console.log("[useToolSystem] Waiting for tools to stabilize...");
|
|
4486
|
+
await waitForToolsToStabilize();
|
|
4487
|
+
console.log("[useToolSystem] Tools stabilized");
|
|
4488
|
+
const updatedState = buildState();
|
|
4489
|
+
console.log(`[useToolSystem] Updated state (aggregated from all hooks)`);
|
|
4490
|
+
client.sendToolResponse(toolCallId, result, updatedState);
|
|
4491
|
+
} catch (err) {
|
|
4492
|
+
console.error("Tool execution error:", err);
|
|
4493
|
+
client.sendToolResponse(toolCallId, {
|
|
4494
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
4495
|
+
});
|
|
4496
|
+
}
|
|
4497
|
+
}, [clientRef, isInvisible, getWaiter, waitForToolsToStabilize, buildState]);
|
|
4498
|
+
const storePendingToolCall = useCallback7((toolCallId, name, input, toolCallData) => {
|
|
4499
|
+
console.log(`[useToolSystem] Storing pending tool call "${name}" for approval`);
|
|
4500
|
+
pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
|
|
4501
|
+
}, []);
|
|
4502
|
+
const executePendingToolAfterApproval = useCallback7(async (toolCallId) => {
|
|
4503
|
+
const pendingTool = pendingApprovalToolCallsRef.current.get(toolCallId);
|
|
4504
|
+
if (!pendingTool) {
|
|
4505
|
+
console.warn(`[useToolSystem] No pending tool found for ${toolCallId}`);
|
|
4506
|
+
return;
|
|
4507
|
+
}
|
|
4508
|
+
pendingApprovalToolCallsRef.current.delete(toolCallId);
|
|
4509
|
+
await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
|
|
4510
|
+
}, [executeToolCall]);
|
|
4511
|
+
const approveAll = useCallback7(async () => {
|
|
4512
|
+
if (!clientRef.current) return;
|
|
4513
|
+
console.log("[useToolSystem] Approving all tool calls:", pendingApprovals.length);
|
|
4514
|
+
const pendingTools = [...pendingApprovals];
|
|
4515
|
+
for (const pending of pendingTools) {
|
|
4516
|
+
clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
|
|
4517
|
+
}
|
|
4518
|
+
setPendingApprovals([]);
|
|
4519
|
+
for (const tool of pendingTools) {
|
|
4520
|
+
await executePendingToolAfterApproval(tool.toolCallId);
|
|
4521
|
+
}
|
|
4522
|
+
}, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
|
|
4523
|
+
const rejectAll = useCallback7((reason) => {
|
|
4524
|
+
if (!clientRef.current) return;
|
|
4525
|
+
console.log("[useToolSystem] Rejecting all tool calls:", pendingApprovals.length, reason);
|
|
4526
|
+
const pendingTools = [...pendingApprovals];
|
|
4527
|
+
for (const pending of pendingTools) {
|
|
4528
|
+
clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
|
|
4529
|
+
}
|
|
4530
|
+
setPendingApprovals([]);
|
|
4531
|
+
for (const tool of pendingTools) {
|
|
4532
|
+
pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
|
|
4533
|
+
}
|
|
4534
|
+
}, [clientRef, pendingApprovals]);
|
|
4454
4535
|
return {
|
|
4536
|
+
// Registry
|
|
4455
4537
|
registerTools,
|
|
4456
4538
|
unregisterTools,
|
|
4457
4539
|
isInvisible,
|
|
4458
4540
|
aggregatedTools,
|
|
4459
4541
|
hasTools,
|
|
4460
4542
|
aggregatedToolsRef,
|
|
4461
|
-
|
|
4543
|
+
signalReady,
|
|
4544
|
+
toolRegistryVersion,
|
|
4545
|
+
// Waiters
|
|
4546
|
+
registerWaiter,
|
|
4547
|
+
unregisterWaiter,
|
|
4548
|
+
// Execution
|
|
4549
|
+
pendingApprovals,
|
|
4550
|
+
handleApprovalRequest,
|
|
4551
|
+
executeToolCall,
|
|
4552
|
+
storePendingToolCall,
|
|
4553
|
+
approveAll,
|
|
4554
|
+
rejectAll
|
|
4462
4555
|
};
|
|
4463
4556
|
}
|
|
4464
4557
|
|
|
@@ -4471,7 +4564,6 @@ function usePromptState({
|
|
|
4471
4564
|
}) {
|
|
4472
4565
|
const promptsRef = useRef8(/* @__PURE__ */ new Map());
|
|
4473
4566
|
const suggestionsRef = useRef8(/* @__PURE__ */ new Map());
|
|
4474
|
-
const waitersRef = useRef8(/* @__PURE__ */ new Map());
|
|
4475
4567
|
const [suggestionsVersion, setSuggestionsVersion] = useState10(0);
|
|
4476
4568
|
const buildStateFromPrompts = useCallback8(() => {
|
|
4477
4569
|
const promptParts = [];
|
|
@@ -4508,15 +4600,6 @@ function usePromptState({
|
|
|
4508
4600
|
clientRef.current.updateState(buildStateFromPrompts());
|
|
4509
4601
|
}
|
|
4510
4602
|
}, [buildStateFromPrompts, clientRef, connected]);
|
|
4511
|
-
const registerWaiter = useCallback8((id, waiter) => {
|
|
4512
|
-
waitersRef.current.set(id, waiter);
|
|
4513
|
-
}, []);
|
|
4514
|
-
const unregisterWaiter = useCallback8((id) => {
|
|
4515
|
-
waitersRef.current.delete(id);
|
|
4516
|
-
}, []);
|
|
4517
|
-
const getWaiter = useCallback8((id) => {
|
|
4518
|
-
return waitersRef.current.get(id);
|
|
4519
|
-
}, []);
|
|
4520
4603
|
const aggregatedSuggestions = useMemo5(() => {
|
|
4521
4604
|
const allSuggestions = [];
|
|
4522
4605
|
suggestionsRef.current.forEach((suggestions) => {
|
|
@@ -4526,11 +4609,8 @@ function usePromptState({
|
|
|
4526
4609
|
}, [suggestionsVersion]);
|
|
4527
4610
|
return {
|
|
4528
4611
|
updatePrompt,
|
|
4529
|
-
registerWaiter,
|
|
4530
|
-
unregisterWaiter,
|
|
4531
|
-
getWaiter,
|
|
4532
4612
|
aggregatedSuggestions,
|
|
4533
|
-
|
|
4613
|
+
buildStateFromPrompts
|
|
4534
4614
|
};
|
|
4535
4615
|
}
|
|
4536
4616
|
|
|
@@ -4596,116 +4676,190 @@ function useFeedback({
|
|
|
4596
4676
|
};
|
|
4597
4677
|
}
|
|
4598
4678
|
|
|
4599
|
-
// src/hooks/
|
|
4679
|
+
// src/hooks/useServerEvents.ts
|
|
4600
4680
|
import { useState as useState12, useCallback as useCallback10, useRef as useRef10 } from "react";
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4681
|
+
|
|
4682
|
+
// src/types.ts
|
|
4683
|
+
import { EventType as EventType2, ErrorCode, TOOL_APPROVAL_REQUEST } from "@meetsmore-oss/use-ai-core";
|
|
4684
|
+
|
|
4685
|
+
// src/hooks/useServerEvents.ts
|
|
4686
|
+
function useServerEvents({
|
|
4687
|
+
toolSystem,
|
|
4688
|
+
saveAIResponse,
|
|
4689
|
+
strings
|
|
4608
4690
|
}) {
|
|
4609
|
-
const [
|
|
4610
|
-
const
|
|
4611
|
-
const
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4691
|
+
const [loading, setLoading] = useState12(false);
|
|
4692
|
+
const [streamingText, setStreamingText] = useState12("");
|
|
4693
|
+
const streamingChatIdRef = useRef10(null);
|
|
4694
|
+
const [executingToolRaw, setExecutingTool] = useState12(null);
|
|
4695
|
+
const executingToolFallbackRef = useRef10(null);
|
|
4696
|
+
const clearStreamingText = useCallback10(() => {
|
|
4697
|
+
setStreamingText("");
|
|
4698
|
+
}, []);
|
|
4699
|
+
const toolSystemRef = useRef10(toolSystem);
|
|
4700
|
+
toolSystemRef.current = toolSystem;
|
|
4701
|
+
const saveAIResponseRef = useRef10(saveAIResponse);
|
|
4702
|
+
saveAIResponseRef.current = saveAIResponse;
|
|
4703
|
+
const stringsRef = useRef10(strings);
|
|
4704
|
+
stringsRef.current = strings;
|
|
4705
|
+
const handleServerEvent = useCallback10(async (client, event) => {
|
|
4706
|
+
const ts = toolSystemRef.current;
|
|
4707
|
+
const strs = stringsRef.current;
|
|
4708
|
+
if (event.type === EventType2.TOOL_CALL_START) {
|
|
4709
|
+
const e = event;
|
|
4710
|
+
const tool = ts.aggregatedToolsRef.current[e.toolCallName];
|
|
4711
|
+
const title = e.annotations?.title ?? tool?._options?.annotations?.title ?? null;
|
|
4712
|
+
if (!title) {
|
|
4713
|
+
const fallbacks = strs.toolExecution.fallbackMessages;
|
|
4714
|
+
executingToolFallbackRef.current = fallbacks[Math.floor(Math.random() * fallbacks.length)];
|
|
4620
4715
|
}
|
|
4621
|
-
|
|
4716
|
+
setExecutingTool({ toolCallId: e.toolCallId, title });
|
|
4717
|
+
} else if (event.type === EventType2.TOOL_CALL_END) {
|
|
4718
|
+
const toolCallEnd = event;
|
|
4719
|
+
const toolCallId = toolCallEnd.toolCallId;
|
|
4720
|
+
setExecutingTool((prev) => prev?.toolCallId === toolCallId ? null : prev);
|
|
4721
|
+
const toolCallData = client.currentToolCalls.get(toolCallId);
|
|
4722
|
+
if (!toolCallData) {
|
|
4723
|
+
console.error(`[ServerEvents] Tool call ${toolCallId} not found`);
|
|
4724
|
+
return;
|
|
4725
|
+
}
|
|
4726
|
+
const name = toolCallData.name;
|
|
4727
|
+
const input = JSON.parse(toolCallData.args);
|
|
4728
|
+
const tool = ts.aggregatedToolsRef.current[name];
|
|
4729
|
+
if (!tool) {
|
|
4730
|
+
console.log(`[ServerEvents] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
|
|
4731
|
+
return;
|
|
4732
|
+
}
|
|
4733
|
+
if (tool._options?.annotations?.destructiveHint === true) {
|
|
4734
|
+
console.log(`[ServerEvents] Tool "${name}" requires approval, deferring execution`);
|
|
4735
|
+
ts.storePendingToolCall(toolCallId, name, input, toolCallData);
|
|
4736
|
+
return;
|
|
4737
|
+
}
|
|
4738
|
+
await ts.executeToolCall(toolCallId, name, input);
|
|
4739
|
+
} else if (event.type === TOOL_APPROVAL_REQUEST) {
|
|
4740
|
+
const e = event;
|
|
4741
|
+
ts.handleApprovalRequest(e);
|
|
4742
|
+
} else if (event.type === EventType2.TEXT_MESSAGE_CONTENT) {
|
|
4743
|
+
const contentEvent = event;
|
|
4744
|
+
setStreamingText((prev) => prev + contentEvent.delta);
|
|
4745
|
+
} else if (event.type === EventType2.TEXT_MESSAGE_END) {
|
|
4746
|
+
setStreamingText("");
|
|
4747
|
+
streamingChatIdRef.current = null;
|
|
4748
|
+
} else if (event.type === EventType2.RUN_FINISHED) {
|
|
4749
|
+
const content = client.currentMessageContent;
|
|
4750
|
+
if (content) {
|
|
4751
|
+
const finishedEvent = event;
|
|
4752
|
+
const traceId = finishedEvent.runId;
|
|
4753
|
+
saveAIResponseRef.current(content, void 0, traceId);
|
|
4754
|
+
}
|
|
4755
|
+
setLoading(false);
|
|
4756
|
+
} else if (event.type === EventType2.RUN_ERROR) {
|
|
4757
|
+
const errorEvent = event;
|
|
4758
|
+
const errorCode = errorEvent.message;
|
|
4759
|
+
console.error("[ServerEvents] Run error:", errorCode);
|
|
4760
|
+
const userMessage = strs.errors[errorCode] || strs.errors[ErrorCode.UNKNOWN_ERROR];
|
|
4761
|
+
saveAIResponseRef.current(userMessage, "error");
|
|
4762
|
+
setStreamingText("");
|
|
4763
|
+
streamingChatIdRef.current = null;
|
|
4764
|
+
setLoading(false);
|
|
4765
|
+
}
|
|
4622
4766
|
}, []);
|
|
4623
|
-
const
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4767
|
+
const executingTool = executingToolRaw ? {
|
|
4768
|
+
displayText: executingToolRaw.title ?? executingToolFallbackRef.current ?? strings.toolExecution.fallbackMessages[0]
|
|
4769
|
+
} : null;
|
|
4770
|
+
return {
|
|
4771
|
+
loading,
|
|
4772
|
+
setLoading,
|
|
4773
|
+
streamingText,
|
|
4774
|
+
clearStreamingText,
|
|
4775
|
+
executingTool,
|
|
4776
|
+
streamingChatIdRef,
|
|
4777
|
+
handleServerEvent
|
|
4778
|
+
};
|
|
4779
|
+
}
|
|
4780
|
+
|
|
4781
|
+
// src/hooks/useMessageQueue.ts
|
|
4782
|
+
import { useCallback as useCallback11, useRef as useRef11, useEffect as useEffect10 } from "react";
|
|
4783
|
+
function useMessageQueue({
|
|
4784
|
+
sendFn,
|
|
4785
|
+
createNewChat,
|
|
4786
|
+
setOpen,
|
|
4787
|
+
connected,
|
|
4788
|
+
loading,
|
|
4789
|
+
hasPendingApproval
|
|
4790
|
+
}) {
|
|
4791
|
+
const pendingMessagesRef = useRef11([]);
|
|
4792
|
+
const isProcessingQueueRef = useRef11(false);
|
|
4793
|
+
const sendFnRef = useRef11(sendFn);
|
|
4794
|
+
sendFnRef.current = sendFn;
|
|
4795
|
+
const createNewChatRef = useRef11(createNewChat);
|
|
4796
|
+
createNewChatRef.current = createNewChat;
|
|
4797
|
+
const setOpenRef = useRef11(setOpen);
|
|
4798
|
+
setOpenRef.current = setOpen;
|
|
4799
|
+
const loadingRef = useRef11(loading);
|
|
4800
|
+
useEffect10(() => {
|
|
4801
|
+
loadingRef.current = loading;
|
|
4802
|
+
}, [loading]);
|
|
4803
|
+
const hasPendingApprovalRef = useRef11(hasPendingApproval);
|
|
4804
|
+
useEffect10(() => {
|
|
4805
|
+
hasPendingApprovalRef.current = hasPendingApproval;
|
|
4806
|
+
}, [hasPendingApproval]);
|
|
4807
|
+
const processMessageQueue = useCallback11(async () => {
|
|
4808
|
+
if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0) {
|
|
4627
4809
|
return;
|
|
4628
4810
|
}
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
|
|
4636
|
-
if (ownerId && !isErrorResult && !ownerIsInvisible) {
|
|
4637
|
-
const waiter = getWaiter(ownerId);
|
|
4638
|
-
if (waiter) {
|
|
4639
|
-
console.log(`[useToolExecution] Waiting for prompt change from ${ownerId}...`);
|
|
4640
|
-
await waiter();
|
|
4641
|
-
console.log("[useToolExecution] Prompt change wait complete");
|
|
4642
|
-
}
|
|
4643
|
-
} else if (isErrorResult) {
|
|
4644
|
-
console.log("[useToolExecution] Tool returned error, skipping prompt wait");
|
|
4645
|
-
} else if (ownerIsInvisible) {
|
|
4646
|
-
console.log("[useToolExecution] Component is invisible, skipping prompt wait");
|
|
4811
|
+
isProcessingQueueRef.current = true;
|
|
4812
|
+
while (pendingMessagesRef.current.length > 0) {
|
|
4813
|
+
const { message, options } = pendingMessagesRef.current.shift();
|
|
4814
|
+
const { newChat = false, attachments = [], openChat = true, metadata, forwardedProps } = options ?? {};
|
|
4815
|
+
if (newChat) {
|
|
4816
|
+
await createNewChatRef.current({ metadata });
|
|
4647
4817
|
}
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4818
|
+
const fileAttachments = await Promise.all(
|
|
4819
|
+
attachments.map(async (file) => {
|
|
4820
|
+
let preview;
|
|
4821
|
+
if (file.type.startsWith("image/")) {
|
|
4822
|
+
preview = await new Promise((resolve) => {
|
|
4823
|
+
const reader = new FileReader();
|
|
4824
|
+
reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : void 0);
|
|
4825
|
+
reader.onerror = () => resolve(void 0);
|
|
4826
|
+
reader.readAsDataURL(file);
|
|
4827
|
+
});
|
|
4828
|
+
}
|
|
4829
|
+
return {
|
|
4830
|
+
id: crypto.randomUUID(),
|
|
4831
|
+
file,
|
|
4832
|
+
preview
|
|
4833
|
+
};
|
|
4834
|
+
})
|
|
4835
|
+
);
|
|
4836
|
+
await sendFnRef.current(message, fileAttachments.length > 0 ? fileAttachments : void 0, forwardedProps);
|
|
4837
|
+
if (openChat && setOpenRef.current) {
|
|
4838
|
+
setOpenRef.current(true);
|
|
4655
4839
|
}
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4840
|
+
await new Promise((resolve) => {
|
|
4841
|
+
const checkReady = () => {
|
|
4842
|
+
setTimeout(() => {
|
|
4843
|
+
if (!loadingRef.current && !hasPendingApprovalRef.current) {
|
|
4844
|
+
resolve();
|
|
4845
|
+
} else {
|
|
4846
|
+
checkReady();
|
|
4847
|
+
}
|
|
4848
|
+
}, 100);
|
|
4849
|
+
};
|
|
4850
|
+
checkReady();
|
|
4661
4851
|
});
|
|
4662
4852
|
}
|
|
4663
|
-
|
|
4664
|
-
const storePendingToolCall = useCallback10((toolCallId, name, input, toolCallData) => {
|
|
4665
|
-
console.log(`[useToolExecution] Storing pending tool call "${name}" for approval`);
|
|
4666
|
-
pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
|
|
4853
|
+
isProcessingQueueRef.current = false;
|
|
4667
4854
|
}, []);
|
|
4668
|
-
const
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
console.warn(`[useToolExecution] No pending tool found for ${toolCallId}`);
|
|
4672
|
-
return;
|
|
4673
|
-
}
|
|
4674
|
-
pendingApprovalToolCallsRef.current.delete(toolCallId);
|
|
4675
|
-
await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
|
|
4676
|
-
}, [executeToolCall]);
|
|
4677
|
-
const approveAll = useCallback10(async () => {
|
|
4678
|
-
if (!clientRef.current) return;
|
|
4679
|
-
console.log("[useToolExecution] Approving all tool calls:", pendingApprovals.length);
|
|
4680
|
-
const pendingTools = [...pendingApprovals];
|
|
4681
|
-
for (const pending of pendingTools) {
|
|
4682
|
-
clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
|
|
4683
|
-
}
|
|
4684
|
-
setPendingApprovals([]);
|
|
4685
|
-
for (const tool of pendingTools) {
|
|
4686
|
-
await executePendingToolAfterApproval(tool.toolCallId);
|
|
4687
|
-
}
|
|
4688
|
-
}, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
|
|
4689
|
-
const rejectAll = useCallback10((reason) => {
|
|
4690
|
-
if (!clientRef.current) return;
|
|
4691
|
-
console.log("[useToolExecution] Rejecting all tool calls:", pendingApprovals.length, reason);
|
|
4692
|
-
const pendingTools = [...pendingApprovals];
|
|
4693
|
-
for (const pending of pendingTools) {
|
|
4694
|
-
clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
|
|
4695
|
-
}
|
|
4696
|
-
setPendingApprovals([]);
|
|
4697
|
-
for (const tool of pendingTools) {
|
|
4698
|
-
pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
|
|
4855
|
+
const sendMessage = useCallback11(async (message, options) => {
|
|
4856
|
+
if (!connected) {
|
|
4857
|
+
throw new Error("Not connected to UseAI server");
|
|
4699
4858
|
}
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
executeToolCall,
|
|
4705
|
-
storePendingToolCall,
|
|
4706
|
-
approveAll,
|
|
4707
|
-
rejectAll
|
|
4708
|
-
};
|
|
4859
|
+
pendingMessagesRef.current.push({ message, options });
|
|
4860
|
+
await processMessageQueue();
|
|
4861
|
+
}, [connected, processMessageQueue]);
|
|
4862
|
+
return { sendMessage };
|
|
4709
4863
|
}
|
|
4710
4864
|
|
|
4711
4865
|
// src/providers/useAIProvider.tsx
|
|
@@ -4720,16 +4874,18 @@ var noOpContextValue = {
|
|
|
4720
4874
|
register: () => {
|
|
4721
4875
|
},
|
|
4722
4876
|
unregister: () => {
|
|
4723
|
-
}
|
|
4724
|
-
|
|
4725
|
-
prompts: {
|
|
4726
|
-
update: () => {
|
|
4877
|
+
},
|
|
4878
|
+
signalReady: () => {
|
|
4727
4879
|
},
|
|
4728
4880
|
registerWaiter: () => {
|
|
4729
4881
|
},
|
|
4730
4882
|
unregisterWaiter: () => {
|
|
4731
4883
|
}
|
|
4732
4884
|
},
|
|
4885
|
+
prompts: {
|
|
4886
|
+
update: () => {
|
|
4887
|
+
}
|
|
4888
|
+
},
|
|
4733
4889
|
chat: {
|
|
4734
4890
|
currentId: null,
|
|
4735
4891
|
create: async () => "",
|
|
@@ -4791,87 +4947,41 @@ function UseAIProvider({
|
|
|
4791
4947
|
const strings = { ...defaultStrings, ...customStrings };
|
|
4792
4948
|
const [connected, setConnected] = useState13(false);
|
|
4793
4949
|
const [isChatOpen, setIsChatOpen] = useState13(false);
|
|
4794
|
-
const [loading, setLoading] = useState13(false);
|
|
4795
4950
|
const [messages, setMessages] = useState13([]);
|
|
4796
4951
|
const [fileProcessingState, setFileProcessingState] = useState13(null);
|
|
4797
|
-
const handleSetChatOpen =
|
|
4952
|
+
const handleSetChatOpen = useCallback12((open) => {
|
|
4798
4953
|
setIsChatOpen(open);
|
|
4799
4954
|
onOpenChange?.(open);
|
|
4800
4955
|
}, [onOpenChange]);
|
|
4801
|
-
const
|
|
4802
|
-
const
|
|
4803
|
-
const [executingTool, setExecutingTool] = useState13(null);
|
|
4804
|
-
const executingToolFallbackRef = useRef11(null);
|
|
4805
|
-
const clientRef = useRef11(null);
|
|
4806
|
-
const repositoryRef = useRef11(
|
|
4956
|
+
const clientRef = useRef12(null);
|
|
4957
|
+
const repositoryRef = useRef12(
|
|
4807
4958
|
chatRepository || new LocalStorageChatRepository()
|
|
4808
4959
|
);
|
|
4809
|
-
const
|
|
4810
|
-
const {
|
|
4811
|
-
registerTools,
|
|
4812
|
-
unregisterTools,
|
|
4813
|
-
isInvisible,
|
|
4814
|
-
aggregatedTools,
|
|
4815
|
-
hasTools,
|
|
4816
|
-
aggregatedToolsRef,
|
|
4817
|
-
toolOwnershipRef
|
|
4818
|
-
} = useToolRegistry();
|
|
4819
|
-
const {
|
|
4820
|
-
updatePrompt,
|
|
4821
|
-
registerWaiter,
|
|
4822
|
-
unregisterWaiter,
|
|
4823
|
-
getWaiter,
|
|
4824
|
-
aggregatedSuggestions,
|
|
4825
|
-
promptsRef
|
|
4826
|
-
} = usePromptState({
|
|
4960
|
+
const promptState = usePromptState({
|
|
4827
4961
|
systemPrompt,
|
|
4828
4962
|
clientRef,
|
|
4829
4963
|
connected
|
|
4830
4964
|
});
|
|
4831
|
-
const
|
|
4832
|
-
if (handleSendMessageRef.current) {
|
|
4833
|
-
await handleSendMessageRef.current(message, attachments, forwardedProps);
|
|
4834
|
-
}
|
|
4835
|
-
}, []);
|
|
4836
|
-
const toolExecution = useToolExecution({
|
|
4965
|
+
const toolSystem = useToolSystem({
|
|
4837
4966
|
clientRef,
|
|
4838
|
-
|
|
4839
|
-
toolOwnershipRef,
|
|
4840
|
-
promptsRef,
|
|
4841
|
-
isInvisible,
|
|
4842
|
-
getWaiter
|
|
4967
|
+
buildState: promptState.buildStateFromPrompts
|
|
4843
4968
|
});
|
|
4844
4969
|
const chatManagement = useChatManagement({
|
|
4845
4970
|
repository: repositoryRef.current,
|
|
4846
4971
|
clientRef,
|
|
4847
4972
|
messages,
|
|
4848
4973
|
setMessages,
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4974
|
+
connected
|
|
4975
|
+
});
|
|
4976
|
+
const serverEvents = useServerEvents({
|
|
4977
|
+
toolSystem,
|
|
4978
|
+
saveAIResponse: chatManagement.saveAIResponse,
|
|
4979
|
+
strings
|
|
4854
4980
|
});
|
|
4855
|
-
const {
|
|
4856
|
-
currentChatId,
|
|
4857
|
-
pendingChatId,
|
|
4858
|
-
displayedChatId,
|
|
4859
|
-
createNewChat,
|
|
4860
|
-
loadChat,
|
|
4861
|
-
deleteChat,
|
|
4862
|
-
listChats,
|
|
4863
|
-
clearCurrentChat,
|
|
4864
|
-
activatePendingChat,
|
|
4865
|
-
saveUserMessage,
|
|
4866
|
-
saveAIResponse,
|
|
4867
|
-
sendMessage,
|
|
4868
|
-
getCurrentChat,
|
|
4869
|
-
updateMetadata
|
|
4870
|
-
} = chatManagement;
|
|
4871
4981
|
const feedback = useFeedback({
|
|
4872
4982
|
clientRef,
|
|
4873
4983
|
repository: repositoryRef.current,
|
|
4874
|
-
getDisplayedChatId: () => displayedChatId,
|
|
4984
|
+
getDisplayedChatId: () => chatManagement.displayedChatId,
|
|
4875
4985
|
setMessages
|
|
4876
4986
|
});
|
|
4877
4987
|
const {
|
|
@@ -4887,7 +4997,9 @@ function UseAIProvider({
|
|
|
4887
4997
|
renameCommand,
|
|
4888
4998
|
deleteCommand
|
|
4889
4999
|
} = useCommandManagement({ repository: commandRepository });
|
|
4890
|
-
|
|
5000
|
+
const handleServerEventRef = useRef12(serverEvents.handleServerEvent);
|
|
5001
|
+
handleServerEventRef.current = serverEvents.handleServerEvent;
|
|
5002
|
+
useEffect11(() => {
|
|
4891
5003
|
console.log("[UseAIProvider] Initializing client with serverUrl:", serverUrl);
|
|
4892
5004
|
const client = new UseAIClient(serverUrl);
|
|
4893
5005
|
const unsubscribeConnection = client.onConnectionStateChange((isConnected) => {
|
|
@@ -4897,64 +5009,7 @@ function UseAIProvider({
|
|
|
4897
5009
|
console.log("[UseAIProvider] Connecting...");
|
|
4898
5010
|
client.connect();
|
|
4899
5011
|
const unsubscribe = client.onEvent("globalChat", async (event) => {
|
|
4900
|
-
|
|
4901
|
-
const e = event;
|
|
4902
|
-
const tool = aggregatedToolsRef.current[e.toolCallName];
|
|
4903
|
-
const title = e.annotations?.title ?? tool?._options?.annotations?.title ?? null;
|
|
4904
|
-
if (!title) {
|
|
4905
|
-
const fallbacks = strings.toolExecution.fallbackMessages;
|
|
4906
|
-
executingToolFallbackRef.current = fallbacks[Math.floor(Math.random() * fallbacks.length)];
|
|
4907
|
-
}
|
|
4908
|
-
setExecutingTool({ toolCallId: e.toolCallId, title });
|
|
4909
|
-
} else if (event.type === EventType.TOOL_CALL_END) {
|
|
4910
|
-
const toolCallEnd = event;
|
|
4911
|
-
const toolCallId = toolCallEnd.toolCallId;
|
|
4912
|
-
setExecutingTool((prev) => prev?.toolCallId === toolCallId ? null : prev);
|
|
4913
|
-
const toolCallData = client["currentToolCalls"].get(toolCallId);
|
|
4914
|
-
if (!toolCallData) {
|
|
4915
|
-
console.error(`[Provider] Tool call ${toolCallId} not found`);
|
|
4916
|
-
return;
|
|
4917
|
-
}
|
|
4918
|
-
const name = toolCallData.name;
|
|
4919
|
-
const input = JSON.parse(toolCallData.args);
|
|
4920
|
-
const tool = aggregatedToolsRef.current[name];
|
|
4921
|
-
if (!tool) {
|
|
4922
|
-
console.log(`[Provider] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
|
|
4923
|
-
return;
|
|
4924
|
-
}
|
|
4925
|
-
if (tool._options?.annotations?.destructiveHint === true) {
|
|
4926
|
-
console.log(`[Provider] Tool "${name}" requires approval, deferring execution`);
|
|
4927
|
-
toolExecution.storePendingToolCall(toolCallId, name, input, toolCallData);
|
|
4928
|
-
return;
|
|
4929
|
-
}
|
|
4930
|
-
await toolExecution.executeToolCall(toolCallId, name, input);
|
|
4931
|
-
} else if (event.type === TOOL_APPROVAL_REQUEST) {
|
|
4932
|
-
const e = event;
|
|
4933
|
-
toolExecution.handleApprovalRequest(e);
|
|
4934
|
-
} else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
|
|
4935
|
-
const contentEvent = event;
|
|
4936
|
-
setStreamingText((prev) => prev + contentEvent.delta);
|
|
4937
|
-
} else if (event.type === EventType.TEXT_MESSAGE_END) {
|
|
4938
|
-
setStreamingText("");
|
|
4939
|
-
streamingChatIdRef.current = null;
|
|
4940
|
-
} else if (event.type === EventType.RUN_FINISHED) {
|
|
4941
|
-
const content = client.currentMessageContent;
|
|
4942
|
-
if (content) {
|
|
4943
|
-
const finishedEvent = event;
|
|
4944
|
-
const traceId = finishedEvent.runId;
|
|
4945
|
-
saveAIResponse(content, void 0, traceId);
|
|
4946
|
-
}
|
|
4947
|
-
setLoading(false);
|
|
4948
|
-
} else if (event.type === EventType.RUN_ERROR) {
|
|
4949
|
-
const errorEvent = event;
|
|
4950
|
-
const errorCode = errorEvent.message;
|
|
4951
|
-
console.error("[Provider] Run error:", errorCode);
|
|
4952
|
-
const userMessage = strings.errors[errorCode] || strings.errors[ErrorCode.UNKNOWN_ERROR];
|
|
4953
|
-
saveAIResponse(userMessage, "error");
|
|
4954
|
-
setStreamingText("");
|
|
4955
|
-
streamingChatIdRef.current = null;
|
|
4956
|
-
setLoading(false);
|
|
4957
|
-
}
|
|
5012
|
+
await handleServerEventRef.current(client, event);
|
|
4958
5013
|
});
|
|
4959
5014
|
clientRef.current = client;
|
|
4960
5015
|
return () => {
|
|
@@ -4963,11 +5018,11 @@ function UseAIProvider({
|
|
|
4963
5018
|
client.disconnect();
|
|
4964
5019
|
};
|
|
4965
5020
|
}, [serverUrl]);
|
|
4966
|
-
const lastRegisteredToolsRef =
|
|
4967
|
-
|
|
5021
|
+
const lastRegisteredToolsRef = useRef12("");
|
|
5022
|
+
useEffect11(() => {
|
|
4968
5023
|
const client = clientRef.current;
|
|
4969
|
-
if (!client || !client.isConnected() || !hasTools) return;
|
|
4970
|
-
const toolKeys = Object.keys(aggregatedTools).sort().join(",");
|
|
5024
|
+
if (!client || !client.isConnected() || !toolSystem.hasTools) return;
|
|
5025
|
+
const toolKeys = Object.keys(toolSystem.aggregatedTools).sort().join(",");
|
|
4971
5026
|
if (toolKeys === lastRegisteredToolsRef.current) {
|
|
4972
5027
|
console.log("[Provider] Skipping re-registration, tools unchanged");
|
|
4973
5028
|
return;
|
|
@@ -4975,19 +5030,19 @@ function UseAIProvider({
|
|
|
4975
5030
|
lastRegisteredToolsRef.current = toolKeys;
|
|
4976
5031
|
console.log("[Provider] Registering tools:", toolKeys);
|
|
4977
5032
|
try {
|
|
4978
|
-
const toolDefinitions = convertToolsToDefinitions(aggregatedTools);
|
|
5033
|
+
const toolDefinitions = convertToolsToDefinitions(toolSystem.aggregatedTools);
|
|
4979
5034
|
console.log(`[Provider] Registering ${toolDefinitions.length} tools`);
|
|
4980
5035
|
client.registerTools(toolDefinitions);
|
|
4981
5036
|
} catch (err) {
|
|
4982
5037
|
console.error("Failed to register tools:", err);
|
|
4983
5038
|
}
|
|
4984
|
-
}, [hasTools, aggregatedTools, connected]);
|
|
4985
|
-
const handleSendMessage =
|
|
5039
|
+
}, [toolSystem.hasTools, toolSystem.aggregatedTools, connected]);
|
|
5040
|
+
const handleSendMessage = useCallback12(async (message, attachments, messageForwardedProps) => {
|
|
4986
5041
|
if (!clientRef.current) return;
|
|
4987
|
-
|
|
4988
|
-
const activatedChatId = activatePendingChat();
|
|
4989
|
-
const activeChatId = activatedChatId || currentChatId;
|
|
4990
|
-
streamingChatIdRef.current = activeChatId;
|
|
5042
|
+
serverEvents.clearStreamingText();
|
|
5043
|
+
const activatedChatId = chatManagement.activatePendingChat();
|
|
5044
|
+
const activeChatId = activatedChatId || chatManagement.currentChatId;
|
|
5045
|
+
serverEvents.streamingChatIdRef.current = activeChatId;
|
|
4991
5046
|
let persistedContent = message;
|
|
4992
5047
|
let multimodalContent;
|
|
4993
5048
|
if (attachments && attachments.length > 0) {
|
|
@@ -5007,12 +5062,12 @@ function UseAIProvider({
|
|
|
5007
5062
|
}
|
|
5008
5063
|
persistedContent = persistedParts;
|
|
5009
5064
|
if (activeChatId) {
|
|
5010
|
-
await saveUserMessage(activeChatId, persistedContent);
|
|
5065
|
+
await chatManagement.saveUserMessage(activeChatId, persistedContent);
|
|
5011
5066
|
}
|
|
5012
|
-
setLoading(true);
|
|
5067
|
+
serverEvents.setLoading(true);
|
|
5013
5068
|
try {
|
|
5014
5069
|
const fileContent = await processAttachments(attachments, {
|
|
5015
|
-
getCurrentChat,
|
|
5070
|
+
getCurrentChat: chatManagement.getCurrentChat,
|
|
5016
5071
|
backend: fileUploadConfig?.backend,
|
|
5017
5072
|
transformers: fileUploadConfig?.transformers,
|
|
5018
5073
|
onFileProgress: (_fileId, state) => {
|
|
@@ -5025,16 +5080,16 @@ function UseAIProvider({
|
|
|
5025
5080
|
}
|
|
5026
5081
|
multimodalContent.push(...fileContent);
|
|
5027
5082
|
} catch (error) {
|
|
5028
|
-
setLoading(false);
|
|
5083
|
+
serverEvents.setLoading(false);
|
|
5029
5084
|
throw error;
|
|
5030
5085
|
} finally {
|
|
5031
5086
|
setFileProcessingState(null);
|
|
5032
5087
|
}
|
|
5033
5088
|
} else {
|
|
5034
5089
|
if (activeChatId) {
|
|
5035
|
-
await saveUserMessage(activeChatId, persistedContent);
|
|
5090
|
+
await chatManagement.saveUserMessage(activeChatId, persistedContent);
|
|
5036
5091
|
}
|
|
5037
|
-
setLoading(true);
|
|
5092
|
+
serverEvents.setLoading(true);
|
|
5038
5093
|
}
|
|
5039
5094
|
const providerResult = forwardedPropsProvider ? forwardedPropsProvider() : {};
|
|
5040
5095
|
const providerProps = providerResult instanceof Promise ? await providerResult : providerResult;
|
|
@@ -5047,31 +5102,39 @@ function UseAIProvider({
|
|
|
5047
5102
|
multimodalContent,
|
|
5048
5103
|
Object.keys(mergedForwardedProps).length > 0 ? mergedForwardedProps : void 0
|
|
5049
5104
|
);
|
|
5050
|
-
}, [
|
|
5051
|
-
|
|
5105
|
+
}, [chatManagement, serverEvents, fileUploadConfig, forwardedPropsProvider]);
|
|
5106
|
+
const messageQueue = useMessageQueue({
|
|
5107
|
+
sendFn: handleSendMessage,
|
|
5108
|
+
createNewChat: chatManagement.createNewChat,
|
|
5109
|
+
setOpen: handleSetChatOpen,
|
|
5110
|
+
connected,
|
|
5111
|
+
loading: serverEvents.loading,
|
|
5112
|
+
hasPendingApproval: toolSystem.pendingApprovals.length > 0
|
|
5113
|
+
});
|
|
5052
5114
|
const value = {
|
|
5053
5115
|
serverUrl,
|
|
5054
5116
|
connected,
|
|
5055
5117
|
client: clientRef.current,
|
|
5056
5118
|
tools: {
|
|
5057
|
-
register: registerTools,
|
|
5058
|
-
unregister: unregisterTools
|
|
5119
|
+
register: toolSystem.registerTools,
|
|
5120
|
+
unregister: toolSystem.unregisterTools,
|
|
5121
|
+
signalReady: toolSystem.signalReady,
|
|
5122
|
+
registerWaiter: toolSystem.registerWaiter,
|
|
5123
|
+
unregisterWaiter: toolSystem.unregisterWaiter
|
|
5059
5124
|
},
|
|
5060
5125
|
prompts: {
|
|
5061
|
-
update: updatePrompt
|
|
5062
|
-
registerWaiter,
|
|
5063
|
-
unregisterWaiter
|
|
5126
|
+
update: promptState.updatePrompt
|
|
5064
5127
|
},
|
|
5065
5128
|
chat: {
|
|
5066
|
-
currentId: currentChatId,
|
|
5067
|
-
create: createNewChat,
|
|
5068
|
-
load: loadChat,
|
|
5069
|
-
delete: deleteChat,
|
|
5070
|
-
list: listChats,
|
|
5071
|
-
clear: clearCurrentChat,
|
|
5072
|
-
sendMessage,
|
|
5073
|
-
get: getCurrentChat,
|
|
5074
|
-
updateMetadata
|
|
5129
|
+
currentId: chatManagement.currentChatId,
|
|
5130
|
+
create: chatManagement.createNewChat,
|
|
5131
|
+
load: chatManagement.loadChat,
|
|
5132
|
+
delete: chatManagement.deleteChat,
|
|
5133
|
+
list: chatManagement.listChats,
|
|
5134
|
+
clear: chatManagement.clearCurrentChat,
|
|
5135
|
+
sendMessage: messageQueue.sendMessage,
|
|
5136
|
+
get: chatManagement.getCurrentChat,
|
|
5137
|
+
updateMetadata: chatManagement.updateMetadata
|
|
5075
5138
|
},
|
|
5076
5139
|
agents: {
|
|
5077
5140
|
available: availableAgents,
|
|
@@ -5087,26 +5150,23 @@ function UseAIProvider({
|
|
|
5087
5150
|
delete: deleteCommand
|
|
5088
5151
|
}
|
|
5089
5152
|
};
|
|
5090
|
-
const effectiveStreamingText = streamingChatIdRef.current === displayedChatId ? streamingText : "";
|
|
5091
|
-
const executingToolDisplay = executingTool ? {
|
|
5092
|
-
displayText: executingTool.title ?? executingToolFallbackRef.current ?? strings.toolExecution.fallbackMessages[0]
|
|
5093
|
-
} : null;
|
|
5153
|
+
const effectiveStreamingText = serverEvents.streamingChatIdRef.current === chatManagement.displayedChatId ? serverEvents.streamingText : "";
|
|
5094
5154
|
const chatUIContextValue = {
|
|
5095
5155
|
connected,
|
|
5096
|
-
loading,
|
|
5156
|
+
loading: serverEvents.loading,
|
|
5097
5157
|
sendMessage: handleSendMessage,
|
|
5098
5158
|
messages,
|
|
5099
5159
|
streamingText: effectiveStreamingText,
|
|
5100
|
-
suggestions: aggregatedSuggestions,
|
|
5160
|
+
suggestions: promptState.aggregatedSuggestions,
|
|
5101
5161
|
fileUploadConfig,
|
|
5102
5162
|
fileProcessing: fileProcessingState,
|
|
5103
5163
|
history: {
|
|
5104
|
-
currentId: displayedChatId,
|
|
5105
|
-
create: createNewChat,
|
|
5106
|
-
load: loadChat,
|
|
5107
|
-
delete: deleteChat,
|
|
5108
|
-
list: listChats,
|
|
5109
|
-
get: getCurrentChat
|
|
5164
|
+
currentId: chatManagement.displayedChatId,
|
|
5165
|
+
create: chatManagement.createNewChat,
|
|
5166
|
+
load: chatManagement.loadChat,
|
|
5167
|
+
delete: chatManagement.deleteChat,
|
|
5168
|
+
list: chatManagement.listChats,
|
|
5169
|
+
get: chatManagement.getCurrentChat
|
|
5110
5170
|
},
|
|
5111
5171
|
agents: {
|
|
5112
5172
|
available: availableAgents,
|
|
@@ -5125,11 +5185,11 @@ function UseAIProvider({
|
|
|
5125
5185
|
setOpen: handleSetChatOpen
|
|
5126
5186
|
},
|
|
5127
5187
|
tools: {
|
|
5128
|
-
executing:
|
|
5188
|
+
executing: serverEvents.executingTool,
|
|
5129
5189
|
pending: {
|
|
5130
|
-
tools:
|
|
5131
|
-
approveAll:
|
|
5132
|
-
rejectAll:
|
|
5190
|
+
tools: toolSystem.pendingApprovals,
|
|
5191
|
+
approveAll: toolSystem.approveAll,
|
|
5192
|
+
rejectAll: toolSystem.rejectAll
|
|
5133
5193
|
}
|
|
5134
5194
|
},
|
|
5135
5195
|
feedback: {
|
|
@@ -5143,15 +5203,15 @@ function UseAIProvider({
|
|
|
5143
5203
|
const chatPanelProps = {
|
|
5144
5204
|
onSendMessage: handleSendMessage,
|
|
5145
5205
|
messages,
|
|
5146
|
-
loading,
|
|
5206
|
+
loading: serverEvents.loading,
|
|
5147
5207
|
connected,
|
|
5148
5208
|
streamingText: effectiveStreamingText,
|
|
5149
|
-
currentChatId: displayedChatId,
|
|
5150
|
-
onNewChat: createNewChat,
|
|
5151
|
-
onLoadChat: loadChat,
|
|
5152
|
-
onDeleteChat: deleteChat,
|
|
5153
|
-
onListChats: listChats,
|
|
5154
|
-
suggestions: aggregatedSuggestions,
|
|
5209
|
+
currentChatId: chatManagement.displayedChatId,
|
|
5210
|
+
onNewChat: chatManagement.createNewChat,
|
|
5211
|
+
onLoadChat: chatManagement.loadChat,
|
|
5212
|
+
onDeleteChat: chatManagement.deleteChat,
|
|
5213
|
+
onListChats: chatManagement.listChats,
|
|
5214
|
+
suggestions: promptState.aggregatedSuggestions,
|
|
5155
5215
|
availableAgents,
|
|
5156
5216
|
defaultAgent,
|
|
5157
5217
|
selectedAgent,
|
|
@@ -5162,12 +5222,12 @@ function UseAIProvider({
|
|
|
5162
5222
|
onSaveCommand: saveCommand,
|
|
5163
5223
|
onRenameCommand: renameCommand,
|
|
5164
5224
|
onDeleteCommand: deleteCommand,
|
|
5165
|
-
executingTool:
|
|
5225
|
+
executingTool: serverEvents.executingTool,
|
|
5166
5226
|
feedbackEnabled: feedback.enabled,
|
|
5167
5227
|
onFeedback: feedback.submitFeedback,
|
|
5168
|
-
pendingApprovals:
|
|
5169
|
-
onApproveToolCall:
|
|
5170
|
-
onRejectToolCall:
|
|
5228
|
+
pendingApprovals: toolSystem.pendingApprovals,
|
|
5229
|
+
onApproveToolCall: toolSystem.pendingApprovals.length > 0 ? toolSystem.approveAll : void 0,
|
|
5230
|
+
onRejectToolCall: toolSystem.pendingApprovals.length > 0 ? toolSystem.rejectAll : void 0
|
|
5171
5231
|
};
|
|
5172
5232
|
const renderDefaultChat = () => {
|
|
5173
5233
|
if (isUIDisabled) return null;
|
|
@@ -5188,9 +5248,9 @@ function UseAIProvider({
|
|
|
5188
5248
|
onClose: () => handleSetChatOpen(false),
|
|
5189
5249
|
onSendMessage: handleSendMessage,
|
|
5190
5250
|
messages,
|
|
5191
|
-
loading,
|
|
5251
|
+
loading: serverEvents.loading,
|
|
5192
5252
|
connected,
|
|
5193
|
-
suggestions: aggregatedSuggestions,
|
|
5253
|
+
suggestions: promptState.aggregatedSuggestions,
|
|
5194
5254
|
availableAgents,
|
|
5195
5255
|
defaultAgent,
|
|
5196
5256
|
selectedAgent,
|
|
@@ -5231,11 +5291,11 @@ function useAIContext() {
|
|
|
5231
5291
|
}
|
|
5232
5292
|
|
|
5233
5293
|
// src/hooks/useStableTools.ts
|
|
5234
|
-
import { useRef as
|
|
5294
|
+
import { useRef as useRef13 } from "react";
|
|
5235
5295
|
function useStableTools(tools) {
|
|
5236
|
-
const latestToolsRef =
|
|
5237
|
-
const stableToolsRef =
|
|
5238
|
-
const prevToolNamesRef =
|
|
5296
|
+
const latestToolsRef = useRef13({});
|
|
5297
|
+
const stableToolsRef = useRef13({});
|
|
5298
|
+
const prevToolNamesRef = useRef13("");
|
|
5239
5299
|
if (!tools) {
|
|
5240
5300
|
latestToolsRef.current = {};
|
|
5241
5301
|
return void 0;
|
|
@@ -5303,27 +5363,27 @@ function namespaceTools(tools, namespace) {
|
|
|
5303
5363
|
function useAI(options = {}) {
|
|
5304
5364
|
const { enabled = true } = options;
|
|
5305
5365
|
const { connected, tools, client, prompts } = useAIContext();
|
|
5306
|
-
const { register: registerTools, unregister: unregisterTools } = tools;
|
|
5307
|
-
const { update: updatePrompt
|
|
5366
|
+
const { register: registerTools, unregister: unregisterTools, signalReady, registerWaiter, unregisterWaiter } = tools;
|
|
5367
|
+
const { update: updatePrompt } = prompts;
|
|
5308
5368
|
const [response, setResponse] = useState14(null);
|
|
5309
5369
|
const [loading, setLoading] = useState14(false);
|
|
5310
5370
|
const [error, setError] = useState14(null);
|
|
5311
|
-
const hookId =
|
|
5312
|
-
const toolsRef =
|
|
5313
|
-
const componentRef =
|
|
5314
|
-
const promptChangeResolvers =
|
|
5371
|
+
const hookId = useRef14(`useAI-${Math.random().toString(36).substr(2, 9)}`);
|
|
5372
|
+
const toolsRef = useRef14({});
|
|
5373
|
+
const componentRef = useRef14(null);
|
|
5374
|
+
const promptChangeResolvers = useRef14([]);
|
|
5315
5375
|
const stableTools = useStableTools(options.tools);
|
|
5316
5376
|
const toolsKey = useMemo6(() => {
|
|
5317
5377
|
if (!options.tools) return "";
|
|
5318
5378
|
return Object.keys(options.tools).sort().join(",");
|
|
5319
5379
|
}, [options.tools]);
|
|
5320
5380
|
const memoizedSuggestions = useMemo6(() => options.suggestions, [options.suggestions]);
|
|
5321
|
-
|
|
5381
|
+
useEffect12(() => {
|
|
5322
5382
|
if (componentRef.current) {
|
|
5323
5383
|
componentRef.current.setAttribute("data-useai-context", "true");
|
|
5324
5384
|
}
|
|
5325
5385
|
}, []);
|
|
5326
|
-
const waitForPromptChange =
|
|
5386
|
+
const waitForPromptChange = useCallback13(() => {
|
|
5327
5387
|
return new Promise((resolve) => {
|
|
5328
5388
|
const timeoutMs = 100;
|
|
5329
5389
|
const timeoutId = setTimeout(() => {
|
|
@@ -5340,14 +5400,14 @@ function useAI(options = {}) {
|
|
|
5340
5400
|
promptChangeResolvers.current.push(resolveAndCleanup);
|
|
5341
5401
|
});
|
|
5342
5402
|
}, []);
|
|
5343
|
-
|
|
5403
|
+
useEffect12(() => {
|
|
5344
5404
|
if (!enabled || options.invisible) return;
|
|
5345
5405
|
registerWaiter(hookId.current, waitForPromptChange);
|
|
5346
5406
|
return () => {
|
|
5347
5407
|
unregisterWaiter(hookId.current);
|
|
5348
5408
|
};
|
|
5349
5409
|
}, [enabled, options.invisible, registerWaiter, unregisterWaiter, waitForPromptChange]);
|
|
5350
|
-
|
|
5410
|
+
useEffect12(() => {
|
|
5351
5411
|
if (!enabled) return;
|
|
5352
5412
|
updatePrompt(hookId.current, options.prompt, memoizedSuggestions);
|
|
5353
5413
|
if (promptChangeResolvers.current.length > 0) {
|
|
@@ -5355,29 +5415,30 @@ function useAI(options = {}) {
|
|
|
5355
5415
|
promptChangeResolvers.current = [];
|
|
5356
5416
|
}
|
|
5357
5417
|
}, [enabled, options.prompt, memoizedSuggestions, updatePrompt]);
|
|
5358
|
-
const updatePromptRef =
|
|
5418
|
+
const updatePromptRef = useRef14(updatePrompt);
|
|
5359
5419
|
updatePromptRef.current = updatePrompt;
|
|
5360
|
-
|
|
5420
|
+
useEffect12(() => {
|
|
5361
5421
|
const id = hookId.current;
|
|
5362
5422
|
return () => {
|
|
5363
5423
|
updatePromptRef.current(id, void 0, void 0);
|
|
5364
5424
|
};
|
|
5365
5425
|
}, []);
|
|
5366
|
-
|
|
5426
|
+
useLayoutEffect(() => {
|
|
5367
5427
|
if (!enabled) return;
|
|
5368
5428
|
if (stableTools) {
|
|
5369
5429
|
const componentId = options.id || componentRef.current?.id;
|
|
5370
5430
|
const toolsToRegister = componentId ? namespaceTools(stableTools, componentId) : stableTools;
|
|
5371
5431
|
registerTools(hookId.current, toolsToRegister, { invisible: options.invisible });
|
|
5372
5432
|
toolsRef.current = toolsToRegister;
|
|
5433
|
+
signalReady(hookId.current);
|
|
5373
5434
|
}
|
|
5374
5435
|
return () => {
|
|
5375
5436
|
if (stableTools) {
|
|
5376
5437
|
unregisterTools(hookId.current);
|
|
5377
5438
|
}
|
|
5378
5439
|
};
|
|
5379
|
-
}, [enabled, toolsKey, stableTools, options.id, options.invisible, registerTools, unregisterTools]);
|
|
5380
|
-
|
|
5440
|
+
}, [enabled, toolsKey, stableTools, options.id, options.invisible, registerTools, unregisterTools, signalReady]);
|
|
5441
|
+
useEffect12(() => {
|
|
5381
5442
|
if (!enabled || !client) return;
|
|
5382
5443
|
const unsubscribe = client.onEvent(hookId.current, (event) => {
|
|
5383
5444
|
handleAGUIEvent(event);
|
|
@@ -5386,9 +5447,9 @@ function useAI(options = {}) {
|
|
|
5386
5447
|
unsubscribe();
|
|
5387
5448
|
};
|
|
5388
5449
|
}, [enabled, client]);
|
|
5389
|
-
const handleAGUIEvent =
|
|
5450
|
+
const handleAGUIEvent = useCallback13(async (event) => {
|
|
5390
5451
|
switch (event.type) {
|
|
5391
|
-
case
|
|
5452
|
+
case EventType2.TEXT_MESSAGE_END: {
|
|
5392
5453
|
const content = client?.currentMessageContent;
|
|
5393
5454
|
if (content) {
|
|
5394
5455
|
setResponse(content);
|
|
@@ -5396,7 +5457,7 @@ function useAI(options = {}) {
|
|
|
5396
5457
|
}
|
|
5397
5458
|
break;
|
|
5398
5459
|
}
|
|
5399
|
-
case
|
|
5460
|
+
case EventType2.RUN_ERROR: {
|
|
5400
5461
|
const errorEvent = event;
|
|
5401
5462
|
const error2 = new Error(errorEvent.message);
|
|
5402
5463
|
setError(error2);
|
|
@@ -5406,7 +5467,7 @@ function useAI(options = {}) {
|
|
|
5406
5467
|
}
|
|
5407
5468
|
}
|
|
5408
5469
|
}, [client, options.onError]);
|
|
5409
|
-
const generate =
|
|
5470
|
+
const generate = useCallback13(async (prompt) => {
|
|
5410
5471
|
if (!enabled) {
|
|
5411
5472
|
const error2 = new Error("AI features are disabled");
|
|
5412
5473
|
setError(error2);
|
|
@@ -5442,7 +5503,7 @@ function useAI(options = {}) {
|
|
|
5442
5503
|
}
|
|
5443
5504
|
|
|
5444
5505
|
// src/useAIWorkflow.ts
|
|
5445
|
-
import { useState as useState15, useCallback as
|
|
5506
|
+
import { useState as useState15, useCallback as useCallback14, useRef as useRef15, useEffect as useEffect13 } from "react";
|
|
5446
5507
|
import { EventType as EventType3 } from "@meetsmore-oss/use-ai-core";
|
|
5447
5508
|
import { v4 as uuidv43 } from "uuid";
|
|
5448
5509
|
function useAIWorkflow(runner, workflowId) {
|
|
@@ -5450,9 +5511,9 @@ function useAIWorkflow(runner, workflowId) {
|
|
|
5450
5511
|
const [status, setStatus] = useState15("idle");
|
|
5451
5512
|
const [text, setText] = useState15(null);
|
|
5452
5513
|
const [error, setError] = useState15(null);
|
|
5453
|
-
const currentWorkflowRef =
|
|
5454
|
-
const eventListenerIdRef =
|
|
5455
|
-
const handleWorkflowEvent =
|
|
5514
|
+
const currentWorkflowRef = useRef15(null);
|
|
5515
|
+
const eventListenerIdRef = useRef15(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
|
|
5516
|
+
const handleWorkflowEvent = useCallback14(async (event) => {
|
|
5456
5517
|
const currentWorkflow = currentWorkflowRef.current;
|
|
5457
5518
|
if (!currentWorkflow) return;
|
|
5458
5519
|
if (event.type === EventType3.RUN_STARTED) {
|
|
@@ -5537,14 +5598,14 @@ function useAIWorkflow(runner, workflowId) {
|
|
|
5537
5598
|
}
|
|
5538
5599
|
}
|
|
5539
5600
|
}, [client]);
|
|
5540
|
-
|
|
5601
|
+
useEffect13(() => {
|
|
5541
5602
|
if (!client) return;
|
|
5542
5603
|
const unsubscribe = client.onEvent(eventListenerIdRef.current, handleWorkflowEvent);
|
|
5543
5604
|
return () => {
|
|
5544
5605
|
unsubscribe();
|
|
5545
5606
|
};
|
|
5546
5607
|
}, [client, handleWorkflowEvent]);
|
|
5547
|
-
const trigger =
|
|
5608
|
+
const trigger = useCallback14(async (options) => {
|
|
5548
5609
|
if (!client?.isConnected()) {
|
|
5549
5610
|
const err = new Error("Not connected to server");
|
|
5550
5611
|
setError(err);
|
|
@@ -5635,12 +5696,14 @@ export {
|
|
|
5635
5696
|
useDropdownState,
|
|
5636
5697
|
useFeedback,
|
|
5637
5698
|
useFileUpload,
|
|
5699
|
+
useMessageQueue,
|
|
5638
5700
|
usePromptState,
|
|
5701
|
+
useServerEvents,
|
|
5639
5702
|
useSlashCommands,
|
|
5640
5703
|
useStableTools,
|
|
5641
5704
|
useStrings,
|
|
5642
5705
|
useTheme,
|
|
5643
|
-
|
|
5706
|
+
useToolSystem,
|
|
5644
5707
|
validateCommandName,
|
|
5645
5708
|
z2 as z
|
|
5646
5709
|
};
|