@meetsmore-oss/use-ai-client 1.6.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 +18447 -18389
- package/dist/bundled.js.map +1 -1
- package/dist/index.d.ts +252 -174
- package/dist/index.js +505 -459
- 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
|
/**
|
|
@@ -3072,8 +3069,6 @@ var UseAIClient = class {
|
|
|
3072
3069
|
_tools = [];
|
|
3073
3070
|
_messages = [];
|
|
3074
3071
|
_state = null;
|
|
3075
|
-
// MCP headers provider
|
|
3076
|
-
mcpHeadersProvider;
|
|
3077
3072
|
// Agent selection
|
|
3078
3073
|
_availableAgents = [];
|
|
3079
3074
|
_defaultAgent = null;
|
|
@@ -3148,7 +3143,7 @@ var UseAIClient = class {
|
|
|
3148
3143
|
});
|
|
3149
3144
|
}
|
|
3150
3145
|
handleEvent(event) {
|
|
3151
|
-
if (event.type ===
|
|
3146
|
+
if (event.type === EventType.RUN_STARTED) {
|
|
3152
3147
|
this._currentAssistantMessage = {
|
|
3153
3148
|
id: uuidv42(),
|
|
3154
3149
|
role: "assistant",
|
|
@@ -3156,31 +3151,31 @@ var UseAIClient = class {
|
|
|
3156
3151
|
};
|
|
3157
3152
|
this._currentAssistantToolCalls = [];
|
|
3158
3153
|
}
|
|
3159
|
-
if (event.type ===
|
|
3154
|
+
if (event.type === EventType.TEXT_MESSAGE_START) {
|
|
3160
3155
|
const e = event;
|
|
3161
3156
|
this._currentMessageId = e.messageId;
|
|
3162
3157
|
this._currentMessageContent = "";
|
|
3163
|
-
} else if (event.type ===
|
|
3158
|
+
} else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
|
|
3164
3159
|
const e = event;
|
|
3165
3160
|
this._currentMessageContent += e.delta;
|
|
3166
|
-
} else if (event.type ===
|
|
3161
|
+
} else if (event.type === EventType.TEXT_MESSAGE_END) {
|
|
3167
3162
|
if (this._currentAssistantMessage) {
|
|
3168
3163
|
this._currentAssistantMessage.content = this._currentMessageContent;
|
|
3169
3164
|
}
|
|
3170
3165
|
this._currentMessageId = null;
|
|
3171
|
-
} else if (event.type ===
|
|
3166
|
+
} else if (event.type === EventType.TOOL_CALL_START) {
|
|
3172
3167
|
const e = event;
|
|
3173
3168
|
this.currentToolCalls.set(e.toolCallId, {
|
|
3174
3169
|
name: e.toolCallName,
|
|
3175
3170
|
args: ""
|
|
3176
3171
|
});
|
|
3177
|
-
} else if (event.type ===
|
|
3172
|
+
} else if (event.type === EventType.TOOL_CALL_ARGS) {
|
|
3178
3173
|
const e = event;
|
|
3179
3174
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3180
3175
|
if (toolCall) {
|
|
3181
3176
|
toolCall.args += e.delta;
|
|
3182
3177
|
}
|
|
3183
|
-
} else if (event.type ===
|
|
3178
|
+
} else if (event.type === EventType.TOOL_CALL_END) {
|
|
3184
3179
|
const e = event;
|
|
3185
3180
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3186
3181
|
if (toolCall) {
|
|
@@ -3193,7 +3188,7 @@ var UseAIClient = class {
|
|
|
3193
3188
|
}
|
|
3194
3189
|
});
|
|
3195
3190
|
}
|
|
3196
|
-
} else if (event.type ===
|
|
3191
|
+
} else if (event.type === EventType.RUN_FINISHED) {
|
|
3197
3192
|
if (this._currentAssistantMessage) {
|
|
3198
3193
|
const assistantMessage = {
|
|
3199
3194
|
id: this._currentAssistantMessage.id,
|
|
@@ -3232,22 +3227,15 @@ var UseAIClient = class {
|
|
|
3232
3227
|
updateState(state) {
|
|
3233
3228
|
this._state = state;
|
|
3234
3229
|
}
|
|
3235
|
-
/**
|
|
3236
|
-
* Sets the MCP headers provider.
|
|
3237
|
-
* The provider will be called each time a message is sent to get fresh headers.
|
|
3238
|
-
*
|
|
3239
|
-
* @param provider - Function that returns MCP headers configuration
|
|
3240
|
-
*/
|
|
3241
|
-
setMcpHeadersProvider(provider) {
|
|
3242
|
-
this.mcpHeadersProvider = provider;
|
|
3243
|
-
}
|
|
3244
3230
|
/**
|
|
3245
3231
|
* Sends a user prompt to the AI.
|
|
3246
3232
|
*
|
|
3247
3233
|
* @param prompt - The user's prompt/question (text part)
|
|
3248
3234
|
* @param multimodalContent - Optional multimodal content (text, images, files)
|
|
3235
|
+
* @param forwardedProps - Optional props to forward to the server (e.g., telemetryMetadata, mcpHeaders).
|
|
3236
|
+
* Internally merged with other forwardedProps.
|
|
3249
3237
|
*/
|
|
3250
|
-
async sendPrompt(prompt, multimodalContent) {
|
|
3238
|
+
async sendPrompt(prompt, multimodalContent, forwardedProps) {
|
|
3251
3239
|
let messageContent = prompt;
|
|
3252
3240
|
if (multimodalContent && multimodalContent.length > 0) {
|
|
3253
3241
|
messageContent = multimodalContent.map((part) => {
|
|
@@ -3277,14 +3265,6 @@ var UseAIClient = class {
|
|
|
3277
3265
|
// Type cast needed for Message type compatibility
|
|
3278
3266
|
};
|
|
3279
3267
|
this._messages.push(userMessage);
|
|
3280
|
-
let mcpHeaders;
|
|
3281
|
-
if (this.mcpHeadersProvider) {
|
|
3282
|
-
try {
|
|
3283
|
-
mcpHeaders = await this.mcpHeadersProvider();
|
|
3284
|
-
} catch (error) {
|
|
3285
|
-
console.error("[UseAIClient] Failed to get MCP headers:", error);
|
|
3286
|
-
}
|
|
3287
|
-
}
|
|
3288
3268
|
const runInput = {
|
|
3289
3269
|
threadId: this.threadId,
|
|
3290
3270
|
// Use getter to ensure non-null
|
|
@@ -3299,8 +3279,8 @@ var UseAIClient = class {
|
|
|
3299
3279
|
state: this._state,
|
|
3300
3280
|
context: [],
|
|
3301
3281
|
forwardedProps: {
|
|
3302
|
-
...
|
|
3303
|
-
...
|
|
3282
|
+
...this._selectedAgent ? { agent: this._selectedAgent } : {},
|
|
3283
|
+
...forwardedProps || {}
|
|
3304
3284
|
}
|
|
3305
3285
|
};
|
|
3306
3286
|
this.send({
|
|
@@ -3325,7 +3305,13 @@ var UseAIClient = class {
|
|
|
3325
3305
|
messageId: uuidv42(),
|
|
3326
3306
|
toolCallId,
|
|
3327
3307
|
content: JSON.stringify(result),
|
|
3328
|
-
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
|
+
}
|
|
3329
3315
|
}
|
|
3330
3316
|
};
|
|
3331
3317
|
const toolResultMsg = {
|
|
@@ -3388,7 +3374,7 @@ var UseAIClient = class {
|
|
|
3388
3374
|
*/
|
|
3389
3375
|
onTextMessage(handler) {
|
|
3390
3376
|
return this.onEvent("text-message-handler", (event) => {
|
|
3391
|
-
if (event.type ===
|
|
3377
|
+
if (event.type === EventType.TEXT_MESSAGE_END && this._currentMessageContent) {
|
|
3392
3378
|
handler(this._currentMessageContent);
|
|
3393
3379
|
}
|
|
3394
3380
|
});
|
|
@@ -3402,7 +3388,7 @@ var UseAIClient = class {
|
|
|
3402
3388
|
*/
|
|
3403
3389
|
onToolCall(handler) {
|
|
3404
3390
|
return this.onEvent("tool-call-handler", (event) => {
|
|
3405
|
-
if (event.type ===
|
|
3391
|
+
if (event.type === EventType.TOOL_CALL_END) {
|
|
3406
3392
|
const e = event;
|
|
3407
3393
|
const toolCall = this.currentToolCalls.get(e.toolCallId);
|
|
3408
3394
|
if (toolCall) {
|
|
@@ -3867,11 +3853,7 @@ function useChatManagement({
|
|
|
3867
3853
|
clientRef,
|
|
3868
3854
|
messages,
|
|
3869
3855
|
setMessages,
|
|
3870
|
-
|
|
3871
|
-
setOpen,
|
|
3872
|
-
connected,
|
|
3873
|
-
loading,
|
|
3874
|
-
hasPendingApproval
|
|
3856
|
+
connected
|
|
3875
3857
|
}) {
|
|
3876
3858
|
const [currentChatId, setCurrentChatId] = useState6(null);
|
|
3877
3859
|
const [pendingChatId, setPendingChatId] = useState6(null);
|
|
@@ -3902,7 +3884,7 @@ function useChatManagement({
|
|
|
3902
3884
|
const reloadMessages = useCallback4(async (chatId) => {
|
|
3903
3885
|
const loadedMessages = await loadChatMessages(chatId);
|
|
3904
3886
|
setMessages(loadedMessages);
|
|
3905
|
-
}, [loadChatMessages]);
|
|
3887
|
+
}, [loadChatMessages, setMessages]);
|
|
3906
3888
|
const createNewChat = useCallback4(async (options) => {
|
|
3907
3889
|
console.log("[ChatManagement] createNewChat called - currentChatId:", currentChatId, "pendingChatId:", pendingChatId, "messages.length:", messages.length);
|
|
3908
3890
|
if (pendingChatId && messages.length === 0) {
|
|
@@ -3923,7 +3905,7 @@ function useChatManagement({
|
|
|
3923
3905
|
}
|
|
3924
3906
|
console.log("[ChatManagement] Created pending chat:", chatId, "(will activate on first message)");
|
|
3925
3907
|
return chatId;
|
|
3926
|
-
}, [currentChatId, pendingChatId, messages, repository, clientRef]);
|
|
3908
|
+
}, [currentChatId, pendingChatId, messages, repository, clientRef, setMessages]);
|
|
3927
3909
|
const loadChat = useCallback4(async (chatId) => {
|
|
3928
3910
|
setPendingChatId(chatId);
|
|
3929
3911
|
await reloadMessages(chatId);
|
|
@@ -3944,7 +3926,7 @@ function useChatManagement({
|
|
|
3944
3926
|
setMessages([]);
|
|
3945
3927
|
}
|
|
3946
3928
|
console.log("[ChatManagement] Deleted chat:", chatId);
|
|
3947
|
-
}, [currentChatId, pendingChatId, repository]);
|
|
3929
|
+
}, [currentChatId, pendingChatId, repository, setMessages]);
|
|
3948
3930
|
const listChats = useCallback4(async () => {
|
|
3949
3931
|
return await repository.listChats();
|
|
3950
3932
|
}, [repository]);
|
|
@@ -3958,7 +3940,7 @@ function useChatManagement({
|
|
|
3958
3940
|
console.log("[ChatManagement] Cleared current chat:", currentChatId);
|
|
3959
3941
|
}
|
|
3960
3942
|
}
|
|
3961
|
-
}, [currentChatId, repository]);
|
|
3943
|
+
}, [currentChatId, repository, setMessages]);
|
|
3962
3944
|
const getCurrentChat = useCallback4(async () => {
|
|
3963
3945
|
const chatId = pendingChatId || currentChatId;
|
|
3964
3946
|
if (!chatId) return null;
|
|
@@ -4085,76 +4067,8 @@ function useChatManagement({
|
|
|
4085
4067
|
}
|
|
4086
4068
|
})();
|
|
4087
4069
|
}
|
|
4088
|
-
}, [currentChatId, pendingChatId, createNewChat, repository, loadChatMessages, clientRef]);
|
|
4070
|
+
}, [currentChatId, pendingChatId, createNewChat, repository, loadChatMessages, clientRef, setMessages]);
|
|
4089
4071
|
const displayedChatId = pendingChatId || currentChatId;
|
|
4090
|
-
const pendingMessagesRef = useRef5([]);
|
|
4091
|
-
const isProcessingQueueRef = useRef5(false);
|
|
4092
|
-
const loadingRef = useRef5(loading);
|
|
4093
|
-
useEffect5(() => {
|
|
4094
|
-
loadingRef.current = loading;
|
|
4095
|
-
}, [loading]);
|
|
4096
|
-
const hasPendingApprovalRef = useRef5(hasPendingApproval);
|
|
4097
|
-
useEffect5(() => {
|
|
4098
|
-
hasPendingApprovalRef.current = hasPendingApproval;
|
|
4099
|
-
}, [hasPendingApproval]);
|
|
4100
|
-
const processMessageQueue = useCallback4(async () => {
|
|
4101
|
-
if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0 || !onSendMessage) {
|
|
4102
|
-
return;
|
|
4103
|
-
}
|
|
4104
|
-
isProcessingQueueRef.current = true;
|
|
4105
|
-
while (pendingMessagesRef.current.length > 0) {
|
|
4106
|
-
const { message, options } = pendingMessagesRef.current.shift();
|
|
4107
|
-
const { newChat = false, attachments = [], openChat = true, metadata } = options ?? {};
|
|
4108
|
-
if (newChat) {
|
|
4109
|
-
await createNewChat({ metadata });
|
|
4110
|
-
}
|
|
4111
|
-
const fileAttachments = await Promise.all(
|
|
4112
|
-
attachments.map(async (file) => {
|
|
4113
|
-
let preview;
|
|
4114
|
-
if (file.type.startsWith("image/")) {
|
|
4115
|
-
preview = await new Promise((resolve) => {
|
|
4116
|
-
const reader = new FileReader();
|
|
4117
|
-
reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : void 0);
|
|
4118
|
-
reader.onerror = () => resolve(void 0);
|
|
4119
|
-
reader.readAsDataURL(file);
|
|
4120
|
-
});
|
|
4121
|
-
}
|
|
4122
|
-
return {
|
|
4123
|
-
id: crypto.randomUUID(),
|
|
4124
|
-
file,
|
|
4125
|
-
preview
|
|
4126
|
-
};
|
|
4127
|
-
})
|
|
4128
|
-
);
|
|
4129
|
-
await onSendMessage(message, fileAttachments.length > 0 ? fileAttachments : void 0);
|
|
4130
|
-
if (openChat && setOpen) {
|
|
4131
|
-
setOpen(true);
|
|
4132
|
-
}
|
|
4133
|
-
await new Promise((resolve) => {
|
|
4134
|
-
const checkReady = () => {
|
|
4135
|
-
setTimeout(() => {
|
|
4136
|
-
if (!loadingRef.current && !hasPendingApprovalRef.current) {
|
|
4137
|
-
resolve();
|
|
4138
|
-
} else {
|
|
4139
|
-
checkReady();
|
|
4140
|
-
}
|
|
4141
|
-
}, 100);
|
|
4142
|
-
};
|
|
4143
|
-
checkReady();
|
|
4144
|
-
});
|
|
4145
|
-
}
|
|
4146
|
-
isProcessingQueueRef.current = false;
|
|
4147
|
-
}, [onSendMessage, createNewChat, setOpen]);
|
|
4148
|
-
const sendMessage = useCallback4(async (message, options) => {
|
|
4149
|
-
if (!onSendMessage) {
|
|
4150
|
-
throw new Error("sendMessage is not available (onSendMessage callback not provided)");
|
|
4151
|
-
}
|
|
4152
|
-
if (!connected) {
|
|
4153
|
-
throw new Error("Not connected to UseAI server");
|
|
4154
|
-
}
|
|
4155
|
-
pendingMessagesRef.current.push({ message, options });
|
|
4156
|
-
await processMessageQueue();
|
|
4157
|
-
}, [onSendMessage, connected, processMessageQueue]);
|
|
4158
4072
|
return {
|
|
4159
4073
|
currentChatId,
|
|
4160
4074
|
pendingChatId,
|
|
@@ -4168,7 +4082,6 @@ function useChatManagement({
|
|
|
4168
4082
|
saveUserMessage,
|
|
4169
4083
|
saveAIResponse,
|
|
4170
4084
|
reloadMessages,
|
|
4171
|
-
sendMessage,
|
|
4172
4085
|
getCurrentChat,
|
|
4173
4086
|
updateMetadata,
|
|
4174
4087
|
currentChatIdSnapshot,
|
|
@@ -4416,16 +4329,25 @@ function useCommandManagement({
|
|
|
4416
4329
|
};
|
|
4417
4330
|
}
|
|
4418
4331
|
|
|
4419
|
-
// src/hooks/
|
|
4332
|
+
// src/hooks/useToolSystem.ts
|
|
4420
4333
|
import { useState as useState9, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
|
|
4421
|
-
function
|
|
4334
|
+
function useToolSystem({
|
|
4335
|
+
clientRef,
|
|
4336
|
+
buildState
|
|
4337
|
+
}) {
|
|
4422
4338
|
const toolRegistryRef = useRef7(/* @__PURE__ */ new Map());
|
|
4423
4339
|
const [toolRegistryVersion, setToolRegistryVersion] = useState9(0);
|
|
4424
4340
|
const toolOwnershipRef = useRef7(/* @__PURE__ */ new Map());
|
|
4425
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());
|
|
4426
4347
|
const registerTools = useCallback7((id, tools, options) => {
|
|
4427
4348
|
const existingTools = toolRegistryRef.current.get(id);
|
|
4428
4349
|
toolRegistryRef.current.set(id, tools);
|
|
4350
|
+
readyStateRef.current.set(id, false);
|
|
4429
4351
|
if (existingTools) {
|
|
4430
4352
|
const existingKeys = Object.keys(existingTools).sort().join(",");
|
|
4431
4353
|
const newKeys = Object.keys(tools).sort().join(",");
|
|
@@ -4444,6 +4366,13 @@ function useToolRegistry() {
|
|
|
4444
4366
|
invisibleRef.current.delete(id);
|
|
4445
4367
|
}
|
|
4446
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
|
+
}, []);
|
|
4447
4376
|
const unregisterTools = useCallback7((id) => {
|
|
4448
4377
|
const tools = toolRegistryRef.current.get(id);
|
|
4449
4378
|
if (tools) {
|
|
@@ -4452,8 +4381,10 @@ function useToolRegistry() {
|
|
|
4452
4381
|
});
|
|
4453
4382
|
}
|
|
4454
4383
|
toolRegistryRef.current.delete(id);
|
|
4384
|
+
readyStateRef.current.delete(id);
|
|
4455
4385
|
setToolRegistryVersion((v) => v + 1);
|
|
4456
4386
|
invisibleRef.current.delete(id);
|
|
4387
|
+
readyListenersRef.current.forEach((listener) => listener());
|
|
4457
4388
|
}, []);
|
|
4458
4389
|
const isInvisible = useCallback7((id) => {
|
|
4459
4390
|
return invisibleRef.current.has(id);
|
|
@@ -4468,14 +4399,159 @@ function useToolRegistry() {
|
|
|
4468
4399
|
const hasTools = toolRegistryRef.current.size > 0;
|
|
4469
4400
|
const aggregatedToolsRef = useRef7(aggregatedTools);
|
|
4470
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]);
|
|
4471
4535
|
return {
|
|
4536
|
+
// Registry
|
|
4472
4537
|
registerTools,
|
|
4473
4538
|
unregisterTools,
|
|
4474
4539
|
isInvisible,
|
|
4475
4540
|
aggregatedTools,
|
|
4476
4541
|
hasTools,
|
|
4477
4542
|
aggregatedToolsRef,
|
|
4478
|
-
|
|
4543
|
+
signalReady,
|
|
4544
|
+
toolRegistryVersion,
|
|
4545
|
+
// Waiters
|
|
4546
|
+
registerWaiter,
|
|
4547
|
+
unregisterWaiter,
|
|
4548
|
+
// Execution
|
|
4549
|
+
pendingApprovals,
|
|
4550
|
+
handleApprovalRequest,
|
|
4551
|
+
executeToolCall,
|
|
4552
|
+
storePendingToolCall,
|
|
4553
|
+
approveAll,
|
|
4554
|
+
rejectAll
|
|
4479
4555
|
};
|
|
4480
4556
|
}
|
|
4481
4557
|
|
|
@@ -4488,7 +4564,6 @@ function usePromptState({
|
|
|
4488
4564
|
}) {
|
|
4489
4565
|
const promptsRef = useRef8(/* @__PURE__ */ new Map());
|
|
4490
4566
|
const suggestionsRef = useRef8(/* @__PURE__ */ new Map());
|
|
4491
|
-
const waitersRef = useRef8(/* @__PURE__ */ new Map());
|
|
4492
4567
|
const [suggestionsVersion, setSuggestionsVersion] = useState10(0);
|
|
4493
4568
|
const buildStateFromPrompts = useCallback8(() => {
|
|
4494
4569
|
const promptParts = [];
|
|
@@ -4525,15 +4600,6 @@ function usePromptState({
|
|
|
4525
4600
|
clientRef.current.updateState(buildStateFromPrompts());
|
|
4526
4601
|
}
|
|
4527
4602
|
}, [buildStateFromPrompts, clientRef, connected]);
|
|
4528
|
-
const registerWaiter = useCallback8((id, waiter) => {
|
|
4529
|
-
waitersRef.current.set(id, waiter);
|
|
4530
|
-
}, []);
|
|
4531
|
-
const unregisterWaiter = useCallback8((id) => {
|
|
4532
|
-
waitersRef.current.delete(id);
|
|
4533
|
-
}, []);
|
|
4534
|
-
const getWaiter = useCallback8((id) => {
|
|
4535
|
-
return waitersRef.current.get(id);
|
|
4536
|
-
}, []);
|
|
4537
4603
|
const aggregatedSuggestions = useMemo5(() => {
|
|
4538
4604
|
const allSuggestions = [];
|
|
4539
4605
|
suggestionsRef.current.forEach((suggestions) => {
|
|
@@ -4543,11 +4609,8 @@ function usePromptState({
|
|
|
4543
4609
|
}, [suggestionsVersion]);
|
|
4544
4610
|
return {
|
|
4545
4611
|
updatePrompt,
|
|
4546
|
-
registerWaiter,
|
|
4547
|
-
unregisterWaiter,
|
|
4548
|
-
getWaiter,
|
|
4549
4612
|
aggregatedSuggestions,
|
|
4550
|
-
|
|
4613
|
+
buildStateFromPrompts
|
|
4551
4614
|
};
|
|
4552
4615
|
}
|
|
4553
4616
|
|
|
@@ -4613,116 +4676,190 @@ function useFeedback({
|
|
|
4613
4676
|
};
|
|
4614
4677
|
}
|
|
4615
4678
|
|
|
4616
|
-
// src/hooks/
|
|
4679
|
+
// src/hooks/useServerEvents.ts
|
|
4617
4680
|
import { useState as useState12, useCallback as useCallback10, useRef as useRef10 } from "react";
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
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
|
|
4625
4690
|
}) {
|
|
4626
|
-
const [
|
|
4627
|
-
const
|
|
4628
|
-
const
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
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)];
|
|
4637
4715
|
}
|
|
4638
|
-
|
|
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
|
+
}
|
|
4639
4766
|
}, []);
|
|
4640
|
-
const
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
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) {
|
|
4644
4809
|
return;
|
|
4645
4810
|
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
|
|
4653
|
-
if (ownerId && !isErrorResult && !ownerIsInvisible) {
|
|
4654
|
-
const waiter = getWaiter(ownerId);
|
|
4655
|
-
if (waiter) {
|
|
4656
|
-
console.log(`[useToolExecution] Waiting for prompt change from ${ownerId}...`);
|
|
4657
|
-
await waiter();
|
|
4658
|
-
console.log("[useToolExecution] Prompt change wait complete");
|
|
4659
|
-
}
|
|
4660
|
-
} else if (isErrorResult) {
|
|
4661
|
-
console.log("[useToolExecution] Tool returned error, skipping prompt wait");
|
|
4662
|
-
} else if (ownerIsInvisible) {
|
|
4663
|
-
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 });
|
|
4664
4817
|
}
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
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);
|
|
4672
4839
|
}
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
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();
|
|
4678
4851
|
});
|
|
4679
4852
|
}
|
|
4680
|
-
|
|
4681
|
-
const storePendingToolCall = useCallback10((toolCallId, name, input, toolCallData) => {
|
|
4682
|
-
console.log(`[useToolExecution] Storing pending tool call "${name}" for approval`);
|
|
4683
|
-
pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
|
|
4853
|
+
isProcessingQueueRef.current = false;
|
|
4684
4854
|
}, []);
|
|
4685
|
-
const
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
console.warn(`[useToolExecution] No pending tool found for ${toolCallId}`);
|
|
4689
|
-
return;
|
|
4690
|
-
}
|
|
4691
|
-
pendingApprovalToolCallsRef.current.delete(toolCallId);
|
|
4692
|
-
await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
|
|
4693
|
-
}, [executeToolCall]);
|
|
4694
|
-
const approveAll = useCallback10(async () => {
|
|
4695
|
-
if (!clientRef.current) return;
|
|
4696
|
-
console.log("[useToolExecution] Approving all tool calls:", pendingApprovals.length);
|
|
4697
|
-
const pendingTools = [...pendingApprovals];
|
|
4698
|
-
for (const pending of pendingTools) {
|
|
4699
|
-
clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
|
|
4700
|
-
}
|
|
4701
|
-
setPendingApprovals([]);
|
|
4702
|
-
for (const tool of pendingTools) {
|
|
4703
|
-
await executePendingToolAfterApproval(tool.toolCallId);
|
|
4704
|
-
}
|
|
4705
|
-
}, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
|
|
4706
|
-
const rejectAll = useCallback10((reason) => {
|
|
4707
|
-
if (!clientRef.current) return;
|
|
4708
|
-
console.log("[useToolExecution] Rejecting all tool calls:", pendingApprovals.length, reason);
|
|
4709
|
-
const pendingTools = [...pendingApprovals];
|
|
4710
|
-
for (const pending of pendingTools) {
|
|
4711
|
-
clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
|
|
4712
|
-
}
|
|
4713
|
-
setPendingApprovals([]);
|
|
4714
|
-
for (const tool of pendingTools) {
|
|
4715
|
-
pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
|
|
4855
|
+
const sendMessage = useCallback11(async (message, options) => {
|
|
4856
|
+
if (!connected) {
|
|
4857
|
+
throw new Error("Not connected to UseAI server");
|
|
4716
4858
|
}
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
executeToolCall,
|
|
4722
|
-
storePendingToolCall,
|
|
4723
|
-
approveAll,
|
|
4724
|
-
rejectAll
|
|
4725
|
-
};
|
|
4859
|
+
pendingMessagesRef.current.push({ message, options });
|
|
4860
|
+
await processMessageQueue();
|
|
4861
|
+
}, [connected, processMessageQueue]);
|
|
4862
|
+
return { sendMessage };
|
|
4726
4863
|
}
|
|
4727
4864
|
|
|
4728
4865
|
// src/providers/useAIProvider.tsx
|
|
@@ -4737,16 +4874,18 @@ var noOpContextValue = {
|
|
|
4737
4874
|
register: () => {
|
|
4738
4875
|
},
|
|
4739
4876
|
unregister: () => {
|
|
4740
|
-
}
|
|
4741
|
-
|
|
4742
|
-
prompts: {
|
|
4743
|
-
update: () => {
|
|
4877
|
+
},
|
|
4878
|
+
signalReady: () => {
|
|
4744
4879
|
},
|
|
4745
4880
|
registerWaiter: () => {
|
|
4746
4881
|
},
|
|
4747
4882
|
unregisterWaiter: () => {
|
|
4748
4883
|
}
|
|
4749
4884
|
},
|
|
4885
|
+
prompts: {
|
|
4886
|
+
update: () => {
|
|
4887
|
+
}
|
|
4888
|
+
},
|
|
4750
4889
|
chat: {
|
|
4751
4890
|
currentId: null,
|
|
4752
4891
|
create: async () => "",
|
|
@@ -4794,7 +4933,7 @@ function UseAIProvider({
|
|
|
4794
4933
|
CustomButton,
|
|
4795
4934
|
CustomChat,
|
|
4796
4935
|
chatRepository,
|
|
4797
|
-
|
|
4936
|
+
forwardedPropsProvider,
|
|
4798
4937
|
fileUploadConfig: fileUploadConfigProp,
|
|
4799
4938
|
commandRepository,
|
|
4800
4939
|
renderChat = true,
|
|
@@ -4808,87 +4947,41 @@ function UseAIProvider({
|
|
|
4808
4947
|
const strings = { ...defaultStrings, ...customStrings };
|
|
4809
4948
|
const [connected, setConnected] = useState13(false);
|
|
4810
4949
|
const [isChatOpen, setIsChatOpen] = useState13(false);
|
|
4811
|
-
const [loading, setLoading] = useState13(false);
|
|
4812
4950
|
const [messages, setMessages] = useState13([]);
|
|
4813
4951
|
const [fileProcessingState, setFileProcessingState] = useState13(null);
|
|
4814
|
-
const handleSetChatOpen =
|
|
4952
|
+
const handleSetChatOpen = useCallback12((open) => {
|
|
4815
4953
|
setIsChatOpen(open);
|
|
4816
4954
|
onOpenChange?.(open);
|
|
4817
4955
|
}, [onOpenChange]);
|
|
4818
|
-
const
|
|
4819
|
-
const
|
|
4820
|
-
const [executingTool, setExecutingTool] = useState13(null);
|
|
4821
|
-
const executingToolFallbackRef = useRef11(null);
|
|
4822
|
-
const clientRef = useRef11(null);
|
|
4823
|
-
const repositoryRef = useRef11(
|
|
4956
|
+
const clientRef = useRef12(null);
|
|
4957
|
+
const repositoryRef = useRef12(
|
|
4824
4958
|
chatRepository || new LocalStorageChatRepository()
|
|
4825
4959
|
);
|
|
4826
|
-
const
|
|
4827
|
-
const {
|
|
4828
|
-
registerTools,
|
|
4829
|
-
unregisterTools,
|
|
4830
|
-
isInvisible,
|
|
4831
|
-
aggregatedTools,
|
|
4832
|
-
hasTools,
|
|
4833
|
-
aggregatedToolsRef,
|
|
4834
|
-
toolOwnershipRef
|
|
4835
|
-
} = useToolRegistry();
|
|
4836
|
-
const {
|
|
4837
|
-
updatePrompt,
|
|
4838
|
-
registerWaiter,
|
|
4839
|
-
unregisterWaiter,
|
|
4840
|
-
getWaiter,
|
|
4841
|
-
aggregatedSuggestions,
|
|
4842
|
-
promptsRef
|
|
4843
|
-
} = usePromptState({
|
|
4960
|
+
const promptState = usePromptState({
|
|
4844
4961
|
systemPrompt,
|
|
4845
4962
|
clientRef,
|
|
4846
4963
|
connected
|
|
4847
4964
|
});
|
|
4848
|
-
const
|
|
4849
|
-
if (handleSendMessageRef.current) {
|
|
4850
|
-
await handleSendMessageRef.current(message, attachments);
|
|
4851
|
-
}
|
|
4852
|
-
}, []);
|
|
4853
|
-
const toolExecution = useToolExecution({
|
|
4965
|
+
const toolSystem = useToolSystem({
|
|
4854
4966
|
clientRef,
|
|
4855
|
-
|
|
4856
|
-
toolOwnershipRef,
|
|
4857
|
-
promptsRef,
|
|
4858
|
-
isInvisible,
|
|
4859
|
-
getWaiter
|
|
4967
|
+
buildState: promptState.buildStateFromPrompts
|
|
4860
4968
|
});
|
|
4861
4969
|
const chatManagement = useChatManagement({
|
|
4862
4970
|
repository: repositoryRef.current,
|
|
4863
4971
|
clientRef,
|
|
4864
4972
|
messages,
|
|
4865
4973
|
setMessages,
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4974
|
+
connected
|
|
4975
|
+
});
|
|
4976
|
+
const serverEvents = useServerEvents({
|
|
4977
|
+
toolSystem,
|
|
4978
|
+
saveAIResponse: chatManagement.saveAIResponse,
|
|
4979
|
+
strings
|
|
4871
4980
|
});
|
|
4872
|
-
const {
|
|
4873
|
-
currentChatId,
|
|
4874
|
-
pendingChatId,
|
|
4875
|
-
displayedChatId,
|
|
4876
|
-
createNewChat,
|
|
4877
|
-
loadChat,
|
|
4878
|
-
deleteChat,
|
|
4879
|
-
listChats,
|
|
4880
|
-
clearCurrentChat,
|
|
4881
|
-
activatePendingChat,
|
|
4882
|
-
saveUserMessage,
|
|
4883
|
-
saveAIResponse,
|
|
4884
|
-
sendMessage,
|
|
4885
|
-
getCurrentChat,
|
|
4886
|
-
updateMetadata
|
|
4887
|
-
} = chatManagement;
|
|
4888
4981
|
const feedback = useFeedback({
|
|
4889
4982
|
clientRef,
|
|
4890
4983
|
repository: repositoryRef.current,
|
|
4891
|
-
getDisplayedChatId: () => displayedChatId,
|
|
4984
|
+
getDisplayedChatId: () => chatManagement.displayedChatId,
|
|
4892
4985
|
setMessages
|
|
4893
4986
|
});
|
|
4894
4987
|
const {
|
|
@@ -4904,12 +4997,11 @@ function UseAIProvider({
|
|
|
4904
4997
|
renameCommand,
|
|
4905
4998
|
deleteCommand
|
|
4906
4999
|
} = useCommandManagement({ repository: commandRepository });
|
|
4907
|
-
|
|
5000
|
+
const handleServerEventRef = useRef12(serverEvents.handleServerEvent);
|
|
5001
|
+
handleServerEventRef.current = serverEvents.handleServerEvent;
|
|
5002
|
+
useEffect11(() => {
|
|
4908
5003
|
console.log("[UseAIProvider] Initializing client with serverUrl:", serverUrl);
|
|
4909
5004
|
const client = new UseAIClient(serverUrl);
|
|
4910
|
-
if (mcpHeadersProvider) {
|
|
4911
|
-
client.setMcpHeadersProvider(mcpHeadersProvider);
|
|
4912
|
-
}
|
|
4913
5005
|
const unsubscribeConnection = client.onConnectionStateChange((isConnected) => {
|
|
4914
5006
|
console.log("[UseAIProvider] Connection state changed:", isConnected);
|
|
4915
5007
|
setConnected(isConnected);
|
|
@@ -4917,64 +5009,7 @@ function UseAIProvider({
|
|
|
4917
5009
|
console.log("[UseAIProvider] Connecting...");
|
|
4918
5010
|
client.connect();
|
|
4919
5011
|
const unsubscribe = client.onEvent("globalChat", async (event) => {
|
|
4920
|
-
|
|
4921
|
-
const e = event;
|
|
4922
|
-
const tool = aggregatedToolsRef.current[e.toolCallName];
|
|
4923
|
-
const title = e.annotations?.title ?? tool?._options?.annotations?.title ?? null;
|
|
4924
|
-
if (!title) {
|
|
4925
|
-
const fallbacks = strings.toolExecution.fallbackMessages;
|
|
4926
|
-
executingToolFallbackRef.current = fallbacks[Math.floor(Math.random() * fallbacks.length)];
|
|
4927
|
-
}
|
|
4928
|
-
setExecutingTool({ toolCallId: e.toolCallId, title });
|
|
4929
|
-
} else if (event.type === EventType.TOOL_CALL_END) {
|
|
4930
|
-
const toolCallEnd = event;
|
|
4931
|
-
const toolCallId = toolCallEnd.toolCallId;
|
|
4932
|
-
setExecutingTool((prev) => prev?.toolCallId === toolCallId ? null : prev);
|
|
4933
|
-
const toolCallData = client["currentToolCalls"].get(toolCallId);
|
|
4934
|
-
if (!toolCallData) {
|
|
4935
|
-
console.error(`[Provider] Tool call ${toolCallId} not found`);
|
|
4936
|
-
return;
|
|
4937
|
-
}
|
|
4938
|
-
const name = toolCallData.name;
|
|
4939
|
-
const input = JSON.parse(toolCallData.args);
|
|
4940
|
-
const tool = aggregatedToolsRef.current[name];
|
|
4941
|
-
if (!tool) {
|
|
4942
|
-
console.log(`[Provider] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
|
|
4943
|
-
return;
|
|
4944
|
-
}
|
|
4945
|
-
if (tool._options?.annotations?.destructiveHint === true) {
|
|
4946
|
-
console.log(`[Provider] Tool "${name}" requires approval, deferring execution`);
|
|
4947
|
-
toolExecution.storePendingToolCall(toolCallId, name, input, toolCallData);
|
|
4948
|
-
return;
|
|
4949
|
-
}
|
|
4950
|
-
await toolExecution.executeToolCall(toolCallId, name, input);
|
|
4951
|
-
} else if (event.type === TOOL_APPROVAL_REQUEST) {
|
|
4952
|
-
const e = event;
|
|
4953
|
-
toolExecution.handleApprovalRequest(e);
|
|
4954
|
-
} else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
|
|
4955
|
-
const contentEvent = event;
|
|
4956
|
-
setStreamingText((prev) => prev + contentEvent.delta);
|
|
4957
|
-
} else if (event.type === EventType.TEXT_MESSAGE_END) {
|
|
4958
|
-
setStreamingText("");
|
|
4959
|
-
streamingChatIdRef.current = null;
|
|
4960
|
-
} else if (event.type === EventType.RUN_FINISHED) {
|
|
4961
|
-
const content = client.currentMessageContent;
|
|
4962
|
-
if (content) {
|
|
4963
|
-
const finishedEvent = event;
|
|
4964
|
-
const traceId = finishedEvent.runId;
|
|
4965
|
-
saveAIResponse(content, void 0, traceId);
|
|
4966
|
-
}
|
|
4967
|
-
setLoading(false);
|
|
4968
|
-
} else if (event.type === EventType.RUN_ERROR) {
|
|
4969
|
-
const errorEvent = event;
|
|
4970
|
-
const errorCode = errorEvent.message;
|
|
4971
|
-
console.error("[Provider] Run error:", errorCode);
|
|
4972
|
-
const userMessage = strings.errors[errorCode] || strings.errors[ErrorCode.UNKNOWN_ERROR];
|
|
4973
|
-
saveAIResponse(userMessage, "error");
|
|
4974
|
-
setStreamingText("");
|
|
4975
|
-
streamingChatIdRef.current = null;
|
|
4976
|
-
setLoading(false);
|
|
4977
|
-
}
|
|
5012
|
+
await handleServerEventRef.current(client, event);
|
|
4978
5013
|
});
|
|
4979
5014
|
clientRef.current = client;
|
|
4980
5015
|
return () => {
|
|
@@ -4983,18 +5018,11 @@ function UseAIProvider({
|
|
|
4983
5018
|
client.disconnect();
|
|
4984
5019
|
};
|
|
4985
5020
|
}, [serverUrl]);
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
if (!client) return;
|
|
4989
|
-
if (mcpHeadersProvider) {
|
|
4990
|
-
client.setMcpHeadersProvider(mcpHeadersProvider);
|
|
4991
|
-
}
|
|
4992
|
-
}, [mcpHeadersProvider]);
|
|
4993
|
-
const lastRegisteredToolsRef = useRef11("");
|
|
4994
|
-
useEffect10(() => {
|
|
5021
|
+
const lastRegisteredToolsRef = useRef12("");
|
|
5022
|
+
useEffect11(() => {
|
|
4995
5023
|
const client = clientRef.current;
|
|
4996
|
-
if (!client || !client.isConnected() || !hasTools) return;
|
|
4997
|
-
const toolKeys = Object.keys(aggregatedTools).sort().join(",");
|
|
5024
|
+
if (!client || !client.isConnected() || !toolSystem.hasTools) return;
|
|
5025
|
+
const toolKeys = Object.keys(toolSystem.aggregatedTools).sort().join(",");
|
|
4998
5026
|
if (toolKeys === lastRegisteredToolsRef.current) {
|
|
4999
5027
|
console.log("[Provider] Skipping re-registration, tools unchanged");
|
|
5000
5028
|
return;
|
|
@@ -5002,19 +5030,19 @@ function UseAIProvider({
|
|
|
5002
5030
|
lastRegisteredToolsRef.current = toolKeys;
|
|
5003
5031
|
console.log("[Provider] Registering tools:", toolKeys);
|
|
5004
5032
|
try {
|
|
5005
|
-
const toolDefinitions = convertToolsToDefinitions(aggregatedTools);
|
|
5033
|
+
const toolDefinitions = convertToolsToDefinitions(toolSystem.aggregatedTools);
|
|
5006
5034
|
console.log(`[Provider] Registering ${toolDefinitions.length} tools`);
|
|
5007
5035
|
client.registerTools(toolDefinitions);
|
|
5008
5036
|
} catch (err) {
|
|
5009
5037
|
console.error("Failed to register tools:", err);
|
|
5010
5038
|
}
|
|
5011
|
-
}, [hasTools, aggregatedTools, connected]);
|
|
5012
|
-
const handleSendMessage =
|
|
5039
|
+
}, [toolSystem.hasTools, toolSystem.aggregatedTools, connected]);
|
|
5040
|
+
const handleSendMessage = useCallback12(async (message, attachments, messageForwardedProps) => {
|
|
5013
5041
|
if (!clientRef.current) return;
|
|
5014
|
-
|
|
5015
|
-
const activatedChatId = activatePendingChat();
|
|
5016
|
-
const activeChatId = activatedChatId || currentChatId;
|
|
5017
|
-
streamingChatIdRef.current = activeChatId;
|
|
5042
|
+
serverEvents.clearStreamingText();
|
|
5043
|
+
const activatedChatId = chatManagement.activatePendingChat();
|
|
5044
|
+
const activeChatId = activatedChatId || chatManagement.currentChatId;
|
|
5045
|
+
serverEvents.streamingChatIdRef.current = activeChatId;
|
|
5018
5046
|
let persistedContent = message;
|
|
5019
5047
|
let multimodalContent;
|
|
5020
5048
|
if (attachments && attachments.length > 0) {
|
|
@@ -5034,12 +5062,12 @@ function UseAIProvider({
|
|
|
5034
5062
|
}
|
|
5035
5063
|
persistedContent = persistedParts;
|
|
5036
5064
|
if (activeChatId) {
|
|
5037
|
-
await saveUserMessage(activeChatId, persistedContent);
|
|
5065
|
+
await chatManagement.saveUserMessage(activeChatId, persistedContent);
|
|
5038
5066
|
}
|
|
5039
|
-
setLoading(true);
|
|
5067
|
+
serverEvents.setLoading(true);
|
|
5040
5068
|
try {
|
|
5041
5069
|
const fileContent = await processAttachments(attachments, {
|
|
5042
|
-
getCurrentChat,
|
|
5070
|
+
getCurrentChat: chatManagement.getCurrentChat,
|
|
5043
5071
|
backend: fileUploadConfig?.backend,
|
|
5044
5072
|
transformers: fileUploadConfig?.transformers,
|
|
5045
5073
|
onFileProgress: (_fileId, state) => {
|
|
@@ -5052,43 +5080,61 @@ function UseAIProvider({
|
|
|
5052
5080
|
}
|
|
5053
5081
|
multimodalContent.push(...fileContent);
|
|
5054
5082
|
} catch (error) {
|
|
5055
|
-
setLoading(false);
|
|
5083
|
+
serverEvents.setLoading(false);
|
|
5056
5084
|
throw error;
|
|
5057
5085
|
} finally {
|
|
5058
5086
|
setFileProcessingState(null);
|
|
5059
5087
|
}
|
|
5060
5088
|
} else {
|
|
5061
5089
|
if (activeChatId) {
|
|
5062
|
-
await saveUserMessage(activeChatId, persistedContent);
|
|
5090
|
+
await chatManagement.saveUserMessage(activeChatId, persistedContent);
|
|
5063
5091
|
}
|
|
5064
|
-
setLoading(true);
|
|
5092
|
+
serverEvents.setLoading(true);
|
|
5065
5093
|
}
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5094
|
+
const providerResult = forwardedPropsProvider ? forwardedPropsProvider() : {};
|
|
5095
|
+
const providerProps = providerResult instanceof Promise ? await providerResult : providerResult;
|
|
5096
|
+
const mergedForwardedProps = {
|
|
5097
|
+
...providerProps,
|
|
5098
|
+
...messageForwardedProps
|
|
5099
|
+
};
|
|
5100
|
+
await clientRef.current.sendPrompt(
|
|
5101
|
+
message,
|
|
5102
|
+
multimodalContent,
|
|
5103
|
+
Object.keys(mergedForwardedProps).length > 0 ? mergedForwardedProps : void 0
|
|
5104
|
+
);
|
|
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
|
+
});
|
|
5069
5114
|
const value = {
|
|
5070
5115
|
serverUrl,
|
|
5071
5116
|
connected,
|
|
5072
5117
|
client: clientRef.current,
|
|
5073
5118
|
tools: {
|
|
5074
|
-
register: registerTools,
|
|
5075
|
-
unregister: unregisterTools
|
|
5119
|
+
register: toolSystem.registerTools,
|
|
5120
|
+
unregister: toolSystem.unregisterTools,
|
|
5121
|
+
signalReady: toolSystem.signalReady,
|
|
5122
|
+
registerWaiter: toolSystem.registerWaiter,
|
|
5123
|
+
unregisterWaiter: toolSystem.unregisterWaiter
|
|
5076
5124
|
},
|
|
5077
5125
|
prompts: {
|
|
5078
|
-
update: updatePrompt
|
|
5079
|
-
registerWaiter,
|
|
5080
|
-
unregisterWaiter
|
|
5126
|
+
update: promptState.updatePrompt
|
|
5081
5127
|
},
|
|
5082
5128
|
chat: {
|
|
5083
|
-
currentId: currentChatId,
|
|
5084
|
-
create: createNewChat,
|
|
5085
|
-
load: loadChat,
|
|
5086
|
-
delete: deleteChat,
|
|
5087
|
-
list: listChats,
|
|
5088
|
-
clear: clearCurrentChat,
|
|
5089
|
-
sendMessage,
|
|
5090
|
-
get: getCurrentChat,
|
|
5091
|
-
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
|
|
5092
5138
|
},
|
|
5093
5139
|
agents: {
|
|
5094
5140
|
available: availableAgents,
|
|
@@ -5104,26 +5150,23 @@ function UseAIProvider({
|
|
|
5104
5150
|
delete: deleteCommand
|
|
5105
5151
|
}
|
|
5106
5152
|
};
|
|
5107
|
-
const effectiveStreamingText = streamingChatIdRef.current === displayedChatId ? streamingText : "";
|
|
5108
|
-
const executingToolDisplay = executingTool ? {
|
|
5109
|
-
displayText: executingTool.title ?? executingToolFallbackRef.current ?? strings.toolExecution.fallbackMessages[0]
|
|
5110
|
-
} : null;
|
|
5153
|
+
const effectiveStreamingText = serverEvents.streamingChatIdRef.current === chatManagement.displayedChatId ? serverEvents.streamingText : "";
|
|
5111
5154
|
const chatUIContextValue = {
|
|
5112
5155
|
connected,
|
|
5113
|
-
loading,
|
|
5156
|
+
loading: serverEvents.loading,
|
|
5114
5157
|
sendMessage: handleSendMessage,
|
|
5115
5158
|
messages,
|
|
5116
5159
|
streamingText: effectiveStreamingText,
|
|
5117
|
-
suggestions: aggregatedSuggestions,
|
|
5160
|
+
suggestions: promptState.aggregatedSuggestions,
|
|
5118
5161
|
fileUploadConfig,
|
|
5119
5162
|
fileProcessing: fileProcessingState,
|
|
5120
5163
|
history: {
|
|
5121
|
-
currentId: displayedChatId,
|
|
5122
|
-
create: createNewChat,
|
|
5123
|
-
load: loadChat,
|
|
5124
|
-
delete: deleteChat,
|
|
5125
|
-
list: listChats,
|
|
5126
|
-
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
|
|
5127
5170
|
},
|
|
5128
5171
|
agents: {
|
|
5129
5172
|
available: availableAgents,
|
|
@@ -5142,11 +5185,11 @@ function UseAIProvider({
|
|
|
5142
5185
|
setOpen: handleSetChatOpen
|
|
5143
5186
|
},
|
|
5144
5187
|
tools: {
|
|
5145
|
-
executing:
|
|
5188
|
+
executing: serverEvents.executingTool,
|
|
5146
5189
|
pending: {
|
|
5147
|
-
tools:
|
|
5148
|
-
approveAll:
|
|
5149
|
-
rejectAll:
|
|
5190
|
+
tools: toolSystem.pendingApprovals,
|
|
5191
|
+
approveAll: toolSystem.approveAll,
|
|
5192
|
+
rejectAll: toolSystem.rejectAll
|
|
5150
5193
|
}
|
|
5151
5194
|
},
|
|
5152
5195
|
feedback: {
|
|
@@ -5160,15 +5203,15 @@ function UseAIProvider({
|
|
|
5160
5203
|
const chatPanelProps = {
|
|
5161
5204
|
onSendMessage: handleSendMessage,
|
|
5162
5205
|
messages,
|
|
5163
|
-
loading,
|
|
5206
|
+
loading: serverEvents.loading,
|
|
5164
5207
|
connected,
|
|
5165
5208
|
streamingText: effectiveStreamingText,
|
|
5166
|
-
currentChatId: displayedChatId,
|
|
5167
|
-
onNewChat: createNewChat,
|
|
5168
|
-
onLoadChat: loadChat,
|
|
5169
|
-
onDeleteChat: deleteChat,
|
|
5170
|
-
onListChats: listChats,
|
|
5171
|
-
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,
|
|
5172
5215
|
availableAgents,
|
|
5173
5216
|
defaultAgent,
|
|
5174
5217
|
selectedAgent,
|
|
@@ -5179,12 +5222,12 @@ function UseAIProvider({
|
|
|
5179
5222
|
onSaveCommand: saveCommand,
|
|
5180
5223
|
onRenameCommand: renameCommand,
|
|
5181
5224
|
onDeleteCommand: deleteCommand,
|
|
5182
|
-
executingTool:
|
|
5225
|
+
executingTool: serverEvents.executingTool,
|
|
5183
5226
|
feedbackEnabled: feedback.enabled,
|
|
5184
5227
|
onFeedback: feedback.submitFeedback,
|
|
5185
|
-
pendingApprovals:
|
|
5186
|
-
onApproveToolCall:
|
|
5187
|
-
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
|
|
5188
5231
|
};
|
|
5189
5232
|
const renderDefaultChat = () => {
|
|
5190
5233
|
if (isUIDisabled) return null;
|
|
@@ -5205,9 +5248,9 @@ function UseAIProvider({
|
|
|
5205
5248
|
onClose: () => handleSetChatOpen(false),
|
|
5206
5249
|
onSendMessage: handleSendMessage,
|
|
5207
5250
|
messages,
|
|
5208
|
-
loading,
|
|
5251
|
+
loading: serverEvents.loading,
|
|
5209
5252
|
connected,
|
|
5210
|
-
suggestions: aggregatedSuggestions,
|
|
5253
|
+
suggestions: promptState.aggregatedSuggestions,
|
|
5211
5254
|
availableAgents,
|
|
5212
5255
|
defaultAgent,
|
|
5213
5256
|
selectedAgent,
|
|
@@ -5248,11 +5291,11 @@ function useAIContext() {
|
|
|
5248
5291
|
}
|
|
5249
5292
|
|
|
5250
5293
|
// src/hooks/useStableTools.ts
|
|
5251
|
-
import { useRef as
|
|
5294
|
+
import { useRef as useRef13 } from "react";
|
|
5252
5295
|
function useStableTools(tools) {
|
|
5253
|
-
const latestToolsRef =
|
|
5254
|
-
const stableToolsRef =
|
|
5255
|
-
const prevToolNamesRef =
|
|
5296
|
+
const latestToolsRef = useRef13({});
|
|
5297
|
+
const stableToolsRef = useRef13({});
|
|
5298
|
+
const prevToolNamesRef = useRef13("");
|
|
5256
5299
|
if (!tools) {
|
|
5257
5300
|
latestToolsRef.current = {};
|
|
5258
5301
|
return void 0;
|
|
@@ -5320,27 +5363,27 @@ function namespaceTools(tools, namespace) {
|
|
|
5320
5363
|
function useAI(options = {}) {
|
|
5321
5364
|
const { enabled = true } = options;
|
|
5322
5365
|
const { connected, tools, client, prompts } = useAIContext();
|
|
5323
|
-
const { register: registerTools, unregister: unregisterTools } = tools;
|
|
5324
|
-
const { update: updatePrompt
|
|
5366
|
+
const { register: registerTools, unregister: unregisterTools, signalReady, registerWaiter, unregisterWaiter } = tools;
|
|
5367
|
+
const { update: updatePrompt } = prompts;
|
|
5325
5368
|
const [response, setResponse] = useState14(null);
|
|
5326
5369
|
const [loading, setLoading] = useState14(false);
|
|
5327
5370
|
const [error, setError] = useState14(null);
|
|
5328
|
-
const hookId =
|
|
5329
|
-
const toolsRef =
|
|
5330
|
-
const componentRef =
|
|
5331
|
-
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([]);
|
|
5332
5375
|
const stableTools = useStableTools(options.tools);
|
|
5333
5376
|
const toolsKey = useMemo6(() => {
|
|
5334
5377
|
if (!options.tools) return "";
|
|
5335
5378
|
return Object.keys(options.tools).sort().join(",");
|
|
5336
5379
|
}, [options.tools]);
|
|
5337
5380
|
const memoizedSuggestions = useMemo6(() => options.suggestions, [options.suggestions]);
|
|
5338
|
-
|
|
5381
|
+
useEffect12(() => {
|
|
5339
5382
|
if (componentRef.current) {
|
|
5340
5383
|
componentRef.current.setAttribute("data-useai-context", "true");
|
|
5341
5384
|
}
|
|
5342
5385
|
}, []);
|
|
5343
|
-
const waitForPromptChange =
|
|
5386
|
+
const waitForPromptChange = useCallback13(() => {
|
|
5344
5387
|
return new Promise((resolve) => {
|
|
5345
5388
|
const timeoutMs = 100;
|
|
5346
5389
|
const timeoutId = setTimeout(() => {
|
|
@@ -5357,14 +5400,14 @@ function useAI(options = {}) {
|
|
|
5357
5400
|
promptChangeResolvers.current.push(resolveAndCleanup);
|
|
5358
5401
|
});
|
|
5359
5402
|
}, []);
|
|
5360
|
-
|
|
5403
|
+
useEffect12(() => {
|
|
5361
5404
|
if (!enabled || options.invisible) return;
|
|
5362
5405
|
registerWaiter(hookId.current, waitForPromptChange);
|
|
5363
5406
|
return () => {
|
|
5364
5407
|
unregisterWaiter(hookId.current);
|
|
5365
5408
|
};
|
|
5366
5409
|
}, [enabled, options.invisible, registerWaiter, unregisterWaiter, waitForPromptChange]);
|
|
5367
|
-
|
|
5410
|
+
useEffect12(() => {
|
|
5368
5411
|
if (!enabled) return;
|
|
5369
5412
|
updatePrompt(hookId.current, options.prompt, memoizedSuggestions);
|
|
5370
5413
|
if (promptChangeResolvers.current.length > 0) {
|
|
@@ -5372,29 +5415,30 @@ function useAI(options = {}) {
|
|
|
5372
5415
|
promptChangeResolvers.current = [];
|
|
5373
5416
|
}
|
|
5374
5417
|
}, [enabled, options.prompt, memoizedSuggestions, updatePrompt]);
|
|
5375
|
-
const updatePromptRef =
|
|
5418
|
+
const updatePromptRef = useRef14(updatePrompt);
|
|
5376
5419
|
updatePromptRef.current = updatePrompt;
|
|
5377
|
-
|
|
5420
|
+
useEffect12(() => {
|
|
5378
5421
|
const id = hookId.current;
|
|
5379
5422
|
return () => {
|
|
5380
5423
|
updatePromptRef.current(id, void 0, void 0);
|
|
5381
5424
|
};
|
|
5382
5425
|
}, []);
|
|
5383
|
-
|
|
5426
|
+
useLayoutEffect(() => {
|
|
5384
5427
|
if (!enabled) return;
|
|
5385
5428
|
if (stableTools) {
|
|
5386
5429
|
const componentId = options.id || componentRef.current?.id;
|
|
5387
5430
|
const toolsToRegister = componentId ? namespaceTools(stableTools, componentId) : stableTools;
|
|
5388
5431
|
registerTools(hookId.current, toolsToRegister, { invisible: options.invisible });
|
|
5389
5432
|
toolsRef.current = toolsToRegister;
|
|
5433
|
+
signalReady(hookId.current);
|
|
5390
5434
|
}
|
|
5391
5435
|
return () => {
|
|
5392
5436
|
if (stableTools) {
|
|
5393
5437
|
unregisterTools(hookId.current);
|
|
5394
5438
|
}
|
|
5395
5439
|
};
|
|
5396
|
-
}, [enabled, toolsKey, stableTools, options.id, options.invisible, registerTools, unregisterTools]);
|
|
5397
|
-
|
|
5440
|
+
}, [enabled, toolsKey, stableTools, options.id, options.invisible, registerTools, unregisterTools, signalReady]);
|
|
5441
|
+
useEffect12(() => {
|
|
5398
5442
|
if (!enabled || !client) return;
|
|
5399
5443
|
const unsubscribe = client.onEvent(hookId.current, (event) => {
|
|
5400
5444
|
handleAGUIEvent(event);
|
|
@@ -5403,9 +5447,9 @@ function useAI(options = {}) {
|
|
|
5403
5447
|
unsubscribe();
|
|
5404
5448
|
};
|
|
5405
5449
|
}, [enabled, client]);
|
|
5406
|
-
const handleAGUIEvent =
|
|
5450
|
+
const handleAGUIEvent = useCallback13(async (event) => {
|
|
5407
5451
|
switch (event.type) {
|
|
5408
|
-
case
|
|
5452
|
+
case EventType2.TEXT_MESSAGE_END: {
|
|
5409
5453
|
const content = client?.currentMessageContent;
|
|
5410
5454
|
if (content) {
|
|
5411
5455
|
setResponse(content);
|
|
@@ -5413,7 +5457,7 @@ function useAI(options = {}) {
|
|
|
5413
5457
|
}
|
|
5414
5458
|
break;
|
|
5415
5459
|
}
|
|
5416
|
-
case
|
|
5460
|
+
case EventType2.RUN_ERROR: {
|
|
5417
5461
|
const errorEvent = event;
|
|
5418
5462
|
const error2 = new Error(errorEvent.message);
|
|
5419
5463
|
setError(error2);
|
|
@@ -5423,7 +5467,7 @@ function useAI(options = {}) {
|
|
|
5423
5467
|
}
|
|
5424
5468
|
}
|
|
5425
5469
|
}, [client, options.onError]);
|
|
5426
|
-
const generate =
|
|
5470
|
+
const generate = useCallback13(async (prompt) => {
|
|
5427
5471
|
if (!enabled) {
|
|
5428
5472
|
const error2 = new Error("AI features are disabled");
|
|
5429
5473
|
setError(error2);
|
|
@@ -5459,7 +5503,7 @@ function useAI(options = {}) {
|
|
|
5459
5503
|
}
|
|
5460
5504
|
|
|
5461
5505
|
// src/useAIWorkflow.ts
|
|
5462
|
-
import { useState as useState15, useCallback as
|
|
5506
|
+
import { useState as useState15, useCallback as useCallback14, useRef as useRef15, useEffect as useEffect13 } from "react";
|
|
5463
5507
|
import { EventType as EventType3 } from "@meetsmore-oss/use-ai-core";
|
|
5464
5508
|
import { v4 as uuidv43 } from "uuid";
|
|
5465
5509
|
function useAIWorkflow(runner, workflowId) {
|
|
@@ -5467,9 +5511,9 @@ function useAIWorkflow(runner, workflowId) {
|
|
|
5467
5511
|
const [status, setStatus] = useState15("idle");
|
|
5468
5512
|
const [text, setText] = useState15(null);
|
|
5469
5513
|
const [error, setError] = useState15(null);
|
|
5470
|
-
const currentWorkflowRef =
|
|
5471
|
-
const eventListenerIdRef =
|
|
5472
|
-
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) => {
|
|
5473
5517
|
const currentWorkflow = currentWorkflowRef.current;
|
|
5474
5518
|
if (!currentWorkflow) return;
|
|
5475
5519
|
if (event.type === EventType3.RUN_STARTED) {
|
|
@@ -5554,14 +5598,14 @@ function useAIWorkflow(runner, workflowId) {
|
|
|
5554
5598
|
}
|
|
5555
5599
|
}
|
|
5556
5600
|
}, [client]);
|
|
5557
|
-
|
|
5601
|
+
useEffect13(() => {
|
|
5558
5602
|
if (!client) return;
|
|
5559
5603
|
const unsubscribe = client.onEvent(eventListenerIdRef.current, handleWorkflowEvent);
|
|
5560
5604
|
return () => {
|
|
5561
5605
|
unsubscribe();
|
|
5562
5606
|
};
|
|
5563
5607
|
}, [client, handleWorkflowEvent]);
|
|
5564
|
-
const trigger =
|
|
5608
|
+
const trigger = useCallback14(async (options) => {
|
|
5565
5609
|
if (!client?.isConnected()) {
|
|
5566
5610
|
const err = new Error("Not connected to server");
|
|
5567
5611
|
setError(err);
|
|
@@ -5652,12 +5696,14 @@ export {
|
|
|
5652
5696
|
useDropdownState,
|
|
5653
5697
|
useFeedback,
|
|
5654
5698
|
useFileUpload,
|
|
5699
|
+
useMessageQueue,
|
|
5655
5700
|
usePromptState,
|
|
5701
|
+
useServerEvents,
|
|
5656
5702
|
useSlashCommands,
|
|
5657
5703
|
useStableTools,
|
|
5658
5704
|
useStrings,
|
|
5659
5705
|
useTheme,
|
|
5660
|
-
|
|
5706
|
+
useToolSystem,
|
|
5661
5707
|
validateCommandName,
|
|
5662
5708
|
z2 as z
|
|
5663
5709
|
};
|