@newfold/wp-module-ai-chat 1.0.1 → 1.0.2
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/build/index-rtl.css +1 -0
- package/build/index.asset.php +1 -0
- package/build/index.css +1 -0
- package/build/index.js +8 -0
- package/package.json +11 -9
- package/src/components/chat/ChatHeader.jsx +0 -63
- package/src/components/chat/ChatHistoryDropdown.jsx +0 -182
- package/src/components/chat/ChatHistoryList.jsx +0 -257
- package/src/components/chat/ChatInput.jsx +0 -157
- package/src/components/chat/ChatMessage.jsx +0 -157
- package/src/components/chat/ChatMessages.jsx +0 -137
- package/src/components/chat/WelcomeScreen.jsx +0 -115
- package/src/components/icons/CloseIcon.jsx +0 -27
- package/src/components/icons/SparklesOutlineIcon.jsx +0 -30
- package/src/components/icons/index.js +0 -5
- package/src/components/ui/AILogo.jsx +0 -47
- package/src/components/ui/BluBetaHeading.jsx +0 -18
- package/src/components/ui/ErrorAlert.jsx +0 -30
- package/src/components/ui/HeaderBar.jsx +0 -34
- package/src/components/ui/SuggestionButton.jsx +0 -28
- package/src/components/ui/ToolExecutionList.jsx +0 -264
- package/src/components/ui/TypingIndicator.jsx +0 -268
- package/src/constants/nfdAgents/input.js +0 -13
- package/src/constants/nfdAgents/storageKeys.js +0 -102
- package/src/constants/nfdAgents/typingStatus.js +0 -40
- package/src/constants/nfdAgents/websocket.js +0 -44
- package/src/hooks/useAIChat.js +0 -432
- package/src/hooks/useNfdAgentsWebSocket.js +0 -964
- package/src/index.js +0 -66
- package/src/services/mcpClient.js +0 -433
- package/src/services/openaiClient.js +0 -416
- package/src/styles/_branding.scss +0 -151
- package/src/styles/_history.scss +0 -180
- package/src/styles/_input.scss +0 -170
- package/src/styles/_messages.scss +0 -272
- package/src/styles/_mixins.scss +0 -21
- package/src/styles/_typing-indicator.scss +0 -162
- package/src/styles/_ui.scss +0 -173
- package/src/styles/_vars.scss +0 -103
- package/src/styles/_welcome.scss +0 -81
- package/src/styles/app.scss +0 -10
- package/src/utils/helpers.js +0 -75
- package/src/utils/markdownParser.js +0 -319
- package/src/utils/nfdAgents/archiveConversation.js +0 -82
- package/src/utils/nfdAgents/chatHistoryList.js +0 -130
- package/src/utils/nfdAgents/configFetcher.js +0 -137
- package/src/utils/nfdAgents/greeting.js +0 -55
- package/src/utils/nfdAgents/jwtUtils.js +0 -59
- package/src/utils/nfdAgents/messageHandler.js +0 -328
- package/src/utils/nfdAgents/storage.js +0 -112
- package/src/utils/nfdAgents/typingIndicatorToolDisplay.js +0 -180
- package/src/utils/nfdAgents/url.js +0 -101
- package/src/utils/restApi.js +0 -87
- package/src/utils/sanitizeHtml.js +0 -94
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NFD Agents WebSocket Configuration
|
|
3
|
-
*
|
|
4
|
-
* Constants for WebSocket connection, reconnection, typing indicator timeout,
|
|
5
|
-
* and JWT refresh. Storage key construction lives in storageKeys.js (getChatHistoryStorageKeys).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/** WebSocket close code: authentication failed (e.g. expired token). */
|
|
9
|
-
export const WS_CLOSE_AUTH_FAILED = 4000;
|
|
10
|
-
|
|
11
|
-
/** WebSocket close code: missing authentication token. */
|
|
12
|
-
export const WS_CLOSE_MISSING_TOKEN = 4001;
|
|
13
|
-
|
|
14
|
-
/** Buffer (ms) before JWT exp at which to proactively refresh (e.g. 5 min). */
|
|
15
|
-
const FIVE_MINUTES_MS = 5 * 60 * 1000;
|
|
16
|
-
|
|
17
|
-
/** Never schedule proactive refresh sooner than this (ms). */
|
|
18
|
-
const FIVE_MINUTES_MIN_DELAY_MS = 5 * 60 * 1000;
|
|
19
|
-
|
|
20
|
-
/** Don't schedule another proactive refresh sooner than this after the last one (ms). */
|
|
21
|
-
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
22
|
-
|
|
23
|
-
/** Don't clear config + reset attempts on 4000/4001 more than once per this window (ms). */
|
|
24
|
-
const AUTH_REFRESH_COOLDOWN_MS = 3 * 60 * 1000;
|
|
25
|
-
|
|
26
|
-
/** Consider token expired if exp is within this many ms from now (pre-connect check). */
|
|
27
|
-
const JWT_EXPIRED_BUFFER_MS = 60 * 1000;
|
|
28
|
-
|
|
29
|
-
/** When proactive refresh fires during an in-flight reply, reschedule after this many ms. */
|
|
30
|
-
const JWT_PROACTIVE_REFRESH_DEFER_MS = 30 * 1000;
|
|
31
|
-
|
|
32
|
-
export const NFD_AGENTS_WEBSOCKET = {
|
|
33
|
-
MAX_RECONNECT_ATTEMPTS: 5,
|
|
34
|
-
RECONNECT_DELAY: 1000, // Base delay between reconnect attempts (ms)
|
|
35
|
-
TYPING_TIMEOUT: 60000, // Hide typing indicator if no response within this time (ms)
|
|
36
|
-
WS_CLOSE_AUTH_FAILED,
|
|
37
|
-
WS_CLOSE_MISSING_TOKEN,
|
|
38
|
-
JWT_REFRESH_BUFFER_MS: FIVE_MINUTES_MS,
|
|
39
|
-
JWT_REFRESH_MIN_DELAY_MS: FIVE_MINUTES_MIN_DELAY_MS,
|
|
40
|
-
JWT_PROACTIVE_REFRESH_COOLDOWN_MS: ONE_HOUR_MS,
|
|
41
|
-
AUTH_REFRESH_COOLDOWN_MS,
|
|
42
|
-
JWT_EXPIRED_BUFFER_MS,
|
|
43
|
-
JWT_PROACTIVE_REFRESH_DEFER_MS,
|
|
44
|
-
};
|
package/src/hooks/useAIChat.js
DELETED
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WordPress dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { useState, useCallback, useRef, useEffect } from "@wordpress/element";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Internal dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { generateSessionId } from "../utils/helpers";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Chat status enumeration
|
|
13
|
-
*/
|
|
14
|
-
export const CHAT_STATUS = {
|
|
15
|
-
IDLE: "idle",
|
|
16
|
-
RECEIVED: "received",
|
|
17
|
-
GENERATING: "generating",
|
|
18
|
-
TOOL_CALL: "tool_call",
|
|
19
|
-
SUMMARIZING: "summarizing",
|
|
20
|
-
COMPLETED: "completed",
|
|
21
|
-
FAILED: "failed",
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Default system prompt
|
|
26
|
-
*/
|
|
27
|
-
const DEFAULT_SYSTEM_PROMPT = `You are a helpful AI assistant. Be concise and helpful in your responses.`;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* useAIChat Hook
|
|
31
|
-
*
|
|
32
|
-
* A configurable React hook for managing AI chat conversations.
|
|
33
|
-
* Provides extension points for tool handling and message processing.
|
|
34
|
-
*
|
|
35
|
-
* @param {Object} options - Hook configuration options
|
|
36
|
-
* @param {Object} options.mcpClient - MCP client instance for tool execution
|
|
37
|
-
* @param {Object} options.openaiClient - OpenAI client instance for chat completions
|
|
38
|
-
* @param {string} options.systemPrompt - System prompt for the AI
|
|
39
|
-
* @param {Function} options.onToolCall - Callback before tool execution (can intercept)
|
|
40
|
-
* @param {Function} options.onToolResult - Callback after tool execution (for glue code)
|
|
41
|
-
* @param {Function} options.onMessageComplete - Callback when a message is complete
|
|
42
|
-
* @param {Function} options.onError - Callback for errors
|
|
43
|
-
* @param {boolean} options.autoInitialize - Auto-initialize MCP client (default: true)
|
|
44
|
-
* @return {Object} Chat state and controls
|
|
45
|
-
*/
|
|
46
|
-
export const useAIChat = ({
|
|
47
|
-
mcpClient = null,
|
|
48
|
-
openaiClient = null,
|
|
49
|
-
systemPrompt = DEFAULT_SYSTEM_PROMPT,
|
|
50
|
-
onToolCall = null,
|
|
51
|
-
onToolResult = null,
|
|
52
|
-
onMessageComplete = null,
|
|
53
|
-
onError = null,
|
|
54
|
-
autoInitialize = true,
|
|
55
|
-
} = {}) => {
|
|
56
|
-
// Chat state
|
|
57
|
-
const [messages, setMessages] = useState([]);
|
|
58
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
59
|
-
const [error, setError] = useState(null);
|
|
60
|
-
const [status, setStatus] = useState(CHAT_STATUS.IDLE);
|
|
61
|
-
const [sessionId, setSessionId] = useState(() => generateSessionId());
|
|
62
|
-
|
|
63
|
-
// Tool execution state
|
|
64
|
-
const [activeToolCall, setActiveToolCall] = useState(null);
|
|
65
|
-
const [executedTools, setExecutedTools] = useState([]);
|
|
66
|
-
const [pendingTools, setPendingTools] = useState([]);
|
|
67
|
-
const [toolProgress, setToolProgress] = useState(null);
|
|
68
|
-
|
|
69
|
-
// MCP state
|
|
70
|
-
const [mcpConnected, setMcpConnected] = useState(false);
|
|
71
|
-
const [mcpTools, setMcpTools] = useState([]);
|
|
72
|
-
|
|
73
|
-
// Refs
|
|
74
|
-
const isProcessingRef = useRef(false);
|
|
75
|
-
const abortControllerRef = useRef(null);
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Initialize MCP client
|
|
79
|
-
*/
|
|
80
|
-
const initializeMCP = useCallback(async () => {
|
|
81
|
-
if (!mcpClient) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
if (!mcpClient.isConnected()) {
|
|
87
|
-
await mcpClient.connect();
|
|
88
|
-
}
|
|
89
|
-
await mcpClient.initialize();
|
|
90
|
-
setMcpTools(mcpClient.getTools());
|
|
91
|
-
setMcpConnected(true);
|
|
92
|
-
return true;
|
|
93
|
-
} catch (err) {
|
|
94
|
-
// eslint-disable-next-line no-console
|
|
95
|
-
console.error("Failed to initialize MCP:", err);
|
|
96
|
-
setError(`Failed to initialize MCP: ${err.message}`);
|
|
97
|
-
onError?.(err);
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}, [mcpClient, onError]);
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Auto-initialize MCP on mount
|
|
104
|
-
*/
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (autoInitialize && mcpClient) {
|
|
107
|
-
initializeMCP();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Copy ref to variable for cleanup function
|
|
111
|
-
const abortController = abortControllerRef.current;
|
|
112
|
-
|
|
113
|
-
return () => {
|
|
114
|
-
if (abortController) {
|
|
115
|
-
abortController.abort();
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
}, [autoInitialize, mcpClient, initializeMCP]);
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Create a new message object
|
|
122
|
-
*/
|
|
123
|
-
const createMessage = useCallback((role, content, extras = {}) => {
|
|
124
|
-
return {
|
|
125
|
-
id: `${role}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
126
|
-
role,
|
|
127
|
-
type: role,
|
|
128
|
-
content,
|
|
129
|
-
timestamp: new Date(),
|
|
130
|
-
...extras,
|
|
131
|
-
};
|
|
132
|
-
}, []);
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Execute a single tool call
|
|
136
|
-
*
|
|
137
|
-
* The onToolCall callback can return an object with { intercepted: true, result: {...} }
|
|
138
|
-
* to handle the tool call locally instead of calling MCP.
|
|
139
|
-
*/
|
|
140
|
-
const executeTool = useCallback(
|
|
141
|
-
async (toolCall) => {
|
|
142
|
-
if (!mcpClient) {
|
|
143
|
-
throw new Error("MCP client not available");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const { name, arguments: args } = toolCall;
|
|
147
|
-
|
|
148
|
-
// Call onToolCall - it can optionally intercept and return a result
|
|
149
|
-
if (onToolCall) {
|
|
150
|
-
const interceptResult = await onToolCall(toolCall);
|
|
151
|
-
|
|
152
|
-
// If the callback intercepted the call, use its result
|
|
153
|
-
if (interceptResult && interceptResult.intercepted) {
|
|
154
|
-
const result = interceptResult.result || {
|
|
155
|
-
content: [],
|
|
156
|
-
isError: false,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Notify after execution (for glue code to react to changes)
|
|
160
|
-
if (onToolResult) {
|
|
161
|
-
await onToolResult(toolCall, result);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
id: toolCall.id,
|
|
166
|
-
name,
|
|
167
|
-
result,
|
|
168
|
-
isError: result.isError || false,
|
|
169
|
-
hasChanges: result.hasChanges || false,
|
|
170
|
-
undoData: interceptResult.undoData,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
const result = await mcpClient.callTool(name, args);
|
|
177
|
-
|
|
178
|
-
// Notify after execution (for glue code to react to changes)
|
|
179
|
-
if (onToolResult) {
|
|
180
|
-
await onToolResult(toolCall, result);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
id: toolCall.id,
|
|
185
|
-
name,
|
|
186
|
-
result,
|
|
187
|
-
isError: result.isError || false,
|
|
188
|
-
};
|
|
189
|
-
} catch (err) {
|
|
190
|
-
return {
|
|
191
|
-
id: toolCall.id,
|
|
192
|
-
name,
|
|
193
|
-
error: err.message,
|
|
194
|
-
isError: true,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
[mcpClient, onToolCall, onToolResult]
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Execute all tool calls
|
|
203
|
-
*/
|
|
204
|
-
const executeToolCalls = useCallback(
|
|
205
|
-
async (toolCalls) => {
|
|
206
|
-
const results = [];
|
|
207
|
-
setPendingTools(toolCalls.slice(1));
|
|
208
|
-
|
|
209
|
-
for (let i = 0; i < toolCalls.length; i++) {
|
|
210
|
-
const toolCall = toolCalls[i];
|
|
211
|
-
|
|
212
|
-
setActiveToolCall({
|
|
213
|
-
...toolCall,
|
|
214
|
-
index: i + 1,
|
|
215
|
-
total: toolCalls.length,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
const result = await executeTool(toolCall);
|
|
219
|
-
results.push(result);
|
|
220
|
-
|
|
221
|
-
setExecutedTools((prev) => [...prev, { ...toolCall, ...result }]);
|
|
222
|
-
setPendingTools(toolCalls.slice(i + 2));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
setActiveToolCall(null);
|
|
226
|
-
setPendingTools([]);
|
|
227
|
-
return results;
|
|
228
|
-
},
|
|
229
|
-
[executeTool]
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Send a message and get AI response
|
|
234
|
-
*/
|
|
235
|
-
const sendMessage = useCallback(
|
|
236
|
-
async (userMessage) => {
|
|
237
|
-
if (!openaiClient) {
|
|
238
|
-
setError("OpenAI client not configured");
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (isProcessingRef.current) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
isProcessingRef.current = true;
|
|
247
|
-
setIsLoading(true);
|
|
248
|
-
setError(null);
|
|
249
|
-
setStatus(CHAT_STATUS.RECEIVED);
|
|
250
|
-
setExecutedTools([]);
|
|
251
|
-
|
|
252
|
-
// Add user message
|
|
253
|
-
const userMsg = createMessage("user", userMessage);
|
|
254
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
// Build conversation history
|
|
258
|
-
const conversationHistory = [
|
|
259
|
-
{ role: "system", content: systemPrompt },
|
|
260
|
-
...messages.map((msg) => ({
|
|
261
|
-
role: msg.role === "user" ? "user" : "assistant",
|
|
262
|
-
content: msg.content,
|
|
263
|
-
toolCalls: msg.toolCalls,
|
|
264
|
-
toolResults: msg.toolResults,
|
|
265
|
-
})),
|
|
266
|
-
{ role: "user", content: userMessage },
|
|
267
|
-
];
|
|
268
|
-
|
|
269
|
-
// Get tools in OpenAI format
|
|
270
|
-
const tools = mcpConnected && mcpClient ? mcpClient.getToolsForOpenAI() : [];
|
|
271
|
-
|
|
272
|
-
setStatus(CHAT_STATUS.GENERATING);
|
|
273
|
-
|
|
274
|
-
let response = null;
|
|
275
|
-
let allToolResults = [];
|
|
276
|
-
|
|
277
|
-
// Streaming completion
|
|
278
|
-
await openaiClient.createStreamingCompletion(
|
|
279
|
-
{
|
|
280
|
-
messages: openaiClient.convertMessagesToOpenAI(conversationHistory),
|
|
281
|
-
tools: tools.length > 0 ? tools : undefined,
|
|
282
|
-
tool_choice: tools.length > 0 ? "auto" : undefined,
|
|
283
|
-
},
|
|
284
|
-
// onChunk - streaming content updates could be added here
|
|
285
|
-
() => {},
|
|
286
|
-
// onComplete
|
|
287
|
-
async (fullMessage, toolCalls) => {
|
|
288
|
-
if (toolCalls && toolCalls.length > 0) {
|
|
289
|
-
setStatus(CHAT_STATUS.TOOL_CALL);
|
|
290
|
-
|
|
291
|
-
// Execute tool calls
|
|
292
|
-
const toolResults = await executeToolCalls(toolCalls);
|
|
293
|
-
allToolResults = toolResults;
|
|
294
|
-
|
|
295
|
-
// Continue conversation with tool results
|
|
296
|
-
setStatus(CHAT_STATUS.SUMMARIZING);
|
|
297
|
-
|
|
298
|
-
const followUpHistory = [
|
|
299
|
-
...conversationHistory,
|
|
300
|
-
{
|
|
301
|
-
role: "assistant",
|
|
302
|
-
content: fullMessage || null,
|
|
303
|
-
toolCalls,
|
|
304
|
-
toolResults: toolResults.map((r) => ({
|
|
305
|
-
id: r.id,
|
|
306
|
-
result: r.result,
|
|
307
|
-
error: r.error,
|
|
308
|
-
})),
|
|
309
|
-
},
|
|
310
|
-
];
|
|
311
|
-
|
|
312
|
-
// Get follow-up response
|
|
313
|
-
const followUp = await openaiClient.createChatCompletion({
|
|
314
|
-
messages: openaiClient.convertMessagesToOpenAI(followUpHistory),
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
response = followUp.choices?.[0]?.message?.content || "";
|
|
318
|
-
} else {
|
|
319
|
-
response = fullMessage;
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
// onError
|
|
323
|
-
(err) => {
|
|
324
|
-
throw err;
|
|
325
|
-
}
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
// Add assistant message
|
|
329
|
-
if (response) {
|
|
330
|
-
const assistantMsg = createMessage("assistant", response, {
|
|
331
|
-
toolCalls: allToolResults.length > 0 ? allToolResults : undefined,
|
|
332
|
-
executedTools: allToolResults.length > 0 ? allToolResults : undefined,
|
|
333
|
-
});
|
|
334
|
-
setMessages((prev) => [...prev, assistantMsg]);
|
|
335
|
-
onMessageComplete?.(assistantMsg);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
setStatus(CHAT_STATUS.COMPLETED);
|
|
339
|
-
} catch (err) {
|
|
340
|
-
// eslint-disable-next-line no-console
|
|
341
|
-
console.error("Chat error:", err);
|
|
342
|
-
setError(err.message);
|
|
343
|
-
setStatus(CHAT_STATUS.FAILED);
|
|
344
|
-
onError?.(err);
|
|
345
|
-
} finally {
|
|
346
|
-
isProcessingRef.current = false;
|
|
347
|
-
setIsLoading(false);
|
|
348
|
-
setActiveToolCall(null);
|
|
349
|
-
setExecutedTools([]);
|
|
350
|
-
setPendingTools([]);
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
[
|
|
354
|
-
openaiClient,
|
|
355
|
-
mcpClient,
|
|
356
|
-
mcpConnected,
|
|
357
|
-
messages,
|
|
358
|
-
systemPrompt,
|
|
359
|
-
createMessage,
|
|
360
|
-
executeToolCalls,
|
|
361
|
-
onMessageComplete,
|
|
362
|
-
onError,
|
|
363
|
-
]
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Stop the current request
|
|
368
|
-
*/
|
|
369
|
-
const stopRequest = useCallback(() => {
|
|
370
|
-
if (abortControllerRef.current) {
|
|
371
|
-
abortControllerRef.current.abort();
|
|
372
|
-
}
|
|
373
|
-
isProcessingRef.current = false;
|
|
374
|
-
setIsLoading(false);
|
|
375
|
-
setStatus(CHAT_STATUS.IDLE);
|
|
376
|
-
setActiveToolCall(null);
|
|
377
|
-
}, []);
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Clear conversation history
|
|
381
|
-
*/
|
|
382
|
-
const clearMessages = useCallback(() => {
|
|
383
|
-
setMessages([]);
|
|
384
|
-
setError(null);
|
|
385
|
-
setStatus(CHAT_STATUS.IDLE);
|
|
386
|
-
setSessionId(generateSessionId());
|
|
387
|
-
}, []);
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Add a message programmatically
|
|
391
|
-
*/
|
|
392
|
-
const addMessage = useCallback(
|
|
393
|
-
(role, content, extras = {}) => {
|
|
394
|
-
const msg = createMessage(role, content, extras);
|
|
395
|
-
setMessages((prev) => [...prev, msg]);
|
|
396
|
-
return msg;
|
|
397
|
-
},
|
|
398
|
-
[createMessage]
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
return {
|
|
402
|
-
// State
|
|
403
|
-
messages,
|
|
404
|
-
isLoading,
|
|
405
|
-
error,
|
|
406
|
-
status,
|
|
407
|
-
sessionId,
|
|
408
|
-
|
|
409
|
-
// Tool execution state
|
|
410
|
-
activeToolCall,
|
|
411
|
-
executedTools,
|
|
412
|
-
pendingTools,
|
|
413
|
-
toolProgress,
|
|
414
|
-
|
|
415
|
-
// MCP state
|
|
416
|
-
mcpConnected,
|
|
417
|
-
mcpTools,
|
|
418
|
-
|
|
419
|
-
// Actions
|
|
420
|
-
sendMessage,
|
|
421
|
-
stopRequest,
|
|
422
|
-
clearMessages,
|
|
423
|
-
addMessage,
|
|
424
|
-
initializeMCP,
|
|
425
|
-
|
|
426
|
-
// Setters for advanced usage
|
|
427
|
-
setError,
|
|
428
|
-
setToolProgress,
|
|
429
|
-
};
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
export default useAIChat;
|