@automattic/agenttic-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +409 -0
- package/dist/MockSalesGraph-ORPXGMCD.js +7 -0
- package/dist/chunk-LAB4XYXR.js +688 -0
- package/dist/chunk-ZDG7Y2LU.js +39 -0
- package/dist/client/index.d.ts +44 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2137 -0
- package/dist/message-actions/factories.d.ts.map +1 -0
- package/dist/message-actions/index.d.ts.map +1 -0
- package/dist/message-actions/resolver.d.ts.map +1 -0
- package/dist/message-actions/useMessageActions.d.ts.map +1 -0
- package/dist/mocks/index.js +288 -0
- package/dist/react/agentManager.d.ts.map +1 -0
- package/dist/react/useAgentChat.d.ts.map +1 -0
- package/package.json +74 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BarChart,
|
|
3
|
+
ChartBlock,
|
|
4
|
+
LineChart,
|
|
5
|
+
createChartBlock
|
|
6
|
+
} from "./chunk-LAB4XYXR.js";
|
|
7
|
+
|
|
8
|
+
// src/react/useClientContext.ts
|
|
9
|
+
import { useMemo } from "@wordpress/element";
|
|
10
|
+
|
|
11
|
+
// src/client/utils/logger.ts
|
|
12
|
+
var logger = (message, ...args) => {
|
|
13
|
+
if (isDebugEnabled()) {
|
|
14
|
+
console.log(`[agenttic-client] ${message}`, ...args);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function isDebugEnabled() {
|
|
18
|
+
return typeof globalThis !== "undefined" && "window" in globalThis && globalThis.window?.DEBUG === "agenttic-client";
|
|
19
|
+
}
|
|
20
|
+
function formatObject(obj) {
|
|
21
|
+
return JSON.stringify(obj, null, 2);
|
|
22
|
+
}
|
|
23
|
+
function log(message, ...args) {
|
|
24
|
+
console.log(`[agenttic-client] ${message}`, ...args);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/react/useClientContext.ts
|
|
28
|
+
function useClientContext(getClientContextCallback) {
|
|
29
|
+
const contextProvider = useMemo(() => {
|
|
30
|
+
if (!getClientContextCallback) {
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
const provider = {
|
|
34
|
+
getClientContext: () => {
|
|
35
|
+
try {
|
|
36
|
+
const context = getClientContextCallback();
|
|
37
|
+
return context || {};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
logger("Error getting client context: %O", error);
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return provider;
|
|
45
|
+
}, [getClientContextCallback]);
|
|
46
|
+
return contextProvider;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/react/useClientTools.ts
|
|
50
|
+
import { useCallback, useMemo as useMemo2 } from "@wordpress/element";
|
|
51
|
+
function useClientTools(getClientTools, executeTool) {
|
|
52
|
+
const stableGetAvailableTools = useCallback(async () => {
|
|
53
|
+
if (!getClientTools) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return await getClientTools();
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger("Error getting available tools: %O", error);
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}, [getClientTools]);
|
|
63
|
+
const stableExecuteTool = useCallback(
|
|
64
|
+
async (toolId, args) => {
|
|
65
|
+
if (!executeTool) {
|
|
66
|
+
throw new Error("No executeTool callback provided");
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return await executeTool(toolId, args);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
logger("Error executing tool %s: %O", toolId, error);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
[executeTool]
|
|
76
|
+
);
|
|
77
|
+
const toolProvider = useMemo2(() => {
|
|
78
|
+
if (!getClientTools) {
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
getAvailableTools: stableGetAvailableTools,
|
|
83
|
+
executeTool: stableExecuteTool
|
|
84
|
+
};
|
|
85
|
+
}, [stableGetAvailableTools, stableExecuteTool, getClientTools]);
|
|
86
|
+
return toolProvider;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/react/useAgentChat.ts
|
|
90
|
+
import { useCallback as useCallback3, useEffect, useMemo as useMemo3, useRef, useState as useState2 } from "react";
|
|
91
|
+
|
|
92
|
+
// src/client/utils/core.ts
|
|
93
|
+
function generateRandomId() {
|
|
94
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
95
|
+
let result = "";
|
|
96
|
+
for (let i = 0; i < 8; i++) {
|
|
97
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
function generateMessageId() {
|
|
102
|
+
return generateRandomId();
|
|
103
|
+
}
|
|
104
|
+
function createRequestId() {
|
|
105
|
+
return `req-${generateRandomId()}`;
|
|
106
|
+
}
|
|
107
|
+
function createTaskId() {
|
|
108
|
+
return `task-${generateRandomId()}`;
|
|
109
|
+
}
|
|
110
|
+
function createTextPart(text) {
|
|
111
|
+
return {
|
|
112
|
+
type: "text",
|
|
113
|
+
text
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createSendMessageRequest(params, method = "message/send") {
|
|
117
|
+
return {
|
|
118
|
+
jsonrpc: "2.0",
|
|
119
|
+
id: createRequestId(),
|
|
120
|
+
method,
|
|
121
|
+
params: {
|
|
122
|
+
id: params.id || createTaskId(),
|
|
123
|
+
...params
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function extractTextFromMessage(message) {
|
|
128
|
+
if (!message || !message.parts || !Array.isArray(message.parts)) {
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
return message.parts.filter((part) => part.type === "text").map((part) => part.text).join(" ");
|
|
132
|
+
}
|
|
133
|
+
function createToolDataPart(tool) {
|
|
134
|
+
return {
|
|
135
|
+
type: "data",
|
|
136
|
+
data: {
|
|
137
|
+
toolId: tool.id,
|
|
138
|
+
toolName: tool.name,
|
|
139
|
+
description: tool.description,
|
|
140
|
+
inputSchema: tool.input_schema
|
|
141
|
+
},
|
|
142
|
+
metadata: {}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function extractToolCallsFromMessage(message) {
|
|
146
|
+
if (!message || !message.parts || !Array.isArray(message.parts)) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
return message.parts.filter(
|
|
150
|
+
(part) => part.type === "data" && "toolCallId" in part.data && "toolId" in part.data && "arguments" in part.data
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
function createToolResultDataPart(toolCallId, toolId, result, error) {
|
|
154
|
+
return {
|
|
155
|
+
type: "data",
|
|
156
|
+
data: {
|
|
157
|
+
toolCallId,
|
|
158
|
+
toolId,
|
|
159
|
+
result
|
|
160
|
+
},
|
|
161
|
+
metadata: error ? { error } : void 0
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function createContextDataPart(clientContext) {
|
|
165
|
+
return {
|
|
166
|
+
type: "data",
|
|
167
|
+
data: {
|
|
168
|
+
clientContext
|
|
169
|
+
},
|
|
170
|
+
metadata: {}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function createTextMessage(text) {
|
|
174
|
+
return {
|
|
175
|
+
role: "user",
|
|
176
|
+
parts: [createTextPart(text)],
|
|
177
|
+
kind: "message",
|
|
178
|
+
messageId: generateMessageId(),
|
|
179
|
+
metadata: {
|
|
180
|
+
timestamp: Date.now()
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function createAgentTextMessage(text) {
|
|
185
|
+
return {
|
|
186
|
+
role: "agent",
|
|
187
|
+
parts: [createTextPart(text)],
|
|
188
|
+
kind: "message",
|
|
189
|
+
messageId: generateMessageId(),
|
|
190
|
+
metadata: {
|
|
191
|
+
timestamp: Date.now()
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function processToolExecutionResult(executionResult) {
|
|
196
|
+
if (executionResult && typeof executionResult === "object" && "result" in executionResult) {
|
|
197
|
+
return {
|
|
198
|
+
result: executionResult.result,
|
|
199
|
+
returnToAgent: executionResult.returnToAgent !== false,
|
|
200
|
+
// Default to true
|
|
201
|
+
agentMessage: executionResult.agentMessage
|
|
202
|
+
// Pass through agentMessage if present
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
result: executionResult,
|
|
207
|
+
returnToAgent: true
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function createToolResultMessage(toolResults, historyDataParts = []) {
|
|
211
|
+
return {
|
|
212
|
+
role: "user",
|
|
213
|
+
kind: "message",
|
|
214
|
+
parts: [...historyDataParts, ...toolResults],
|
|
215
|
+
messageId: generateMessageId(),
|
|
216
|
+
metadata: {
|
|
217
|
+
timestamp: Date.now()
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/client/utils/internal/messages.ts
|
|
223
|
+
async function enhanceMessageWithTools(message, toolProvider) {
|
|
224
|
+
if (!toolProvider) {
|
|
225
|
+
return message;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const tools = await toolProvider.getAvailableTools();
|
|
229
|
+
if (tools.length === 0) {
|
|
230
|
+
return message;
|
|
231
|
+
}
|
|
232
|
+
const toolParts = tools.map(createToolDataPart);
|
|
233
|
+
return {
|
|
234
|
+
...message,
|
|
235
|
+
parts: [...message.parts, ...toolParts]
|
|
236
|
+
};
|
|
237
|
+
} catch (error) {
|
|
238
|
+
logger("Warning: Failed to get tools: %s", error);
|
|
239
|
+
return message;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function enhanceMessageWithContext(message, contextProvider) {
|
|
243
|
+
if (!contextProvider) {
|
|
244
|
+
return message;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const clientContext = contextProvider.getClientContext();
|
|
248
|
+
if (!clientContext || Object.keys(clientContext).length === 0) {
|
|
249
|
+
return message;
|
|
250
|
+
}
|
|
251
|
+
const contextPart = createContextDataPart(clientContext);
|
|
252
|
+
return {
|
|
253
|
+
...message,
|
|
254
|
+
parts: [...message.parts, contextPart]
|
|
255
|
+
};
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logger("Warning: Failed to get context: %s", error);
|
|
258
|
+
return message;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function enhanceMessage(message, toolProvider, contextProvider) {
|
|
262
|
+
let enhancedMessage = await enhanceMessageWithTools(
|
|
263
|
+
message,
|
|
264
|
+
toolProvider
|
|
265
|
+
);
|
|
266
|
+
enhancedMessage = enhanceMessageWithContext(
|
|
267
|
+
enhancedMessage,
|
|
268
|
+
contextProvider
|
|
269
|
+
);
|
|
270
|
+
const { metadata, ...messageForAgent } = enhancedMessage;
|
|
271
|
+
return messageForAgent;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/client/utils/internal/streaming.ts
|
|
275
|
+
function parseStreamChunk(chunk, buffer = "") {
|
|
276
|
+
const events = [];
|
|
277
|
+
const currentStreamData = buffer + chunk;
|
|
278
|
+
let eventPayload = "";
|
|
279
|
+
let lastCompleteEventEnd = 0;
|
|
280
|
+
let searchStartIndex = 0;
|
|
281
|
+
while (searchStartIndex < currentStreamData.length) {
|
|
282
|
+
const newlineIndex = currentStreamData.indexOf(
|
|
283
|
+
"\n",
|
|
284
|
+
searchStartIndex
|
|
285
|
+
);
|
|
286
|
+
const line = newlineIndex === -1 ? currentStreamData.substring(searchStartIndex) : currentStreamData.substring(searchStartIndex, newlineIndex);
|
|
287
|
+
if (line.startsWith("data:")) {
|
|
288
|
+
if (eventPayload !== "") {
|
|
289
|
+
eventPayload += "\n";
|
|
290
|
+
}
|
|
291
|
+
eventPayload += line.substring(
|
|
292
|
+
line.startsWith("data: ") ? 6 : 5
|
|
293
|
+
);
|
|
294
|
+
} else if (line.trim() === "") {
|
|
295
|
+
if (eventPayload) {
|
|
296
|
+
try {
|
|
297
|
+
events.push(JSON.parse(eventPayload));
|
|
298
|
+
lastCompleteEventEnd = newlineIndex === -1 ? currentStreamData.length : newlineIndex + 1;
|
|
299
|
+
} catch (e) {
|
|
300
|
+
logger("Failed to parse SSE event: %o", e);
|
|
301
|
+
logger("Problematic payload: %s", eventPayload);
|
|
302
|
+
}
|
|
303
|
+
eventPayload = "";
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (newlineIndex === -1) {
|
|
307
|
+
searchStartIndex = currentStreamData.length;
|
|
308
|
+
} else {
|
|
309
|
+
searchStartIndex = newlineIndex + 1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const nextBuffer = currentStreamData.substring(lastCompleteEventEnd);
|
|
313
|
+
return { events, nextBuffer };
|
|
314
|
+
}
|
|
315
|
+
async function* parseSSEStream(stream) {
|
|
316
|
+
const reader = stream.getReader();
|
|
317
|
+
const decoder = new TextDecoder();
|
|
318
|
+
let buffer = "";
|
|
319
|
+
try {
|
|
320
|
+
while (true) {
|
|
321
|
+
const { done, value } = await reader.read();
|
|
322
|
+
if (done) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
326
|
+
const { events, nextBuffer } = parseStreamChunk(chunk, buffer);
|
|
327
|
+
if (events && Array.isArray(events)) {
|
|
328
|
+
for (const event of events) {
|
|
329
|
+
if (event.error) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
`Streaming error: ${event.error.message}`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
if (event.result && event.result.status) {
|
|
335
|
+
const update = {
|
|
336
|
+
id: event.result.id,
|
|
337
|
+
status: event.result.status,
|
|
338
|
+
final: event.result.status.state === "completed" || event.result.status.state === "failed" || event.result.status.state === "canceled",
|
|
339
|
+
text: extractTextFromMessage(
|
|
340
|
+
event.result.status?.message || {
|
|
341
|
+
role: "agent",
|
|
342
|
+
parts: []
|
|
343
|
+
}
|
|
344
|
+
)
|
|
345
|
+
};
|
|
346
|
+
yield update;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
buffer = nextBuffer;
|
|
351
|
+
}
|
|
352
|
+
} finally {
|
|
353
|
+
reader.releaseLock();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/client/utils/internal/errors.ts
|
|
358
|
+
function handleRequestError(error, timeoutId, operation = "request") {
|
|
359
|
+
clearTimeout(timeoutId);
|
|
360
|
+
logger("%s failed with error: %O", operation, error);
|
|
361
|
+
if (error instanceof Error) {
|
|
362
|
+
logger("Error message: %s", error.message);
|
|
363
|
+
logger("Error stack: %s", error.stack);
|
|
364
|
+
}
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
function validateHttpResponse(response, operation = "request") {
|
|
368
|
+
if (!response.ok) {
|
|
369
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function validateJsonRpcResponse(data, operation = "request") {
|
|
373
|
+
if (data.error) {
|
|
374
|
+
throw new Error(`A2A ${operation} error: ${data.error.message}`);
|
|
375
|
+
}
|
|
376
|
+
if (!data.result) {
|
|
377
|
+
throw new Error(`No result in ${operation} response`);
|
|
378
|
+
}
|
|
379
|
+
return data.result;
|
|
380
|
+
}
|
|
381
|
+
function validateStreamingResponse(response, operation = "streaming request") {
|
|
382
|
+
validateHttpResponse(response, operation);
|
|
383
|
+
if (!response.body) {
|
|
384
|
+
throw new Error(`No response body for ${operation}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function createTimeoutHandler(timeout, operation = "request") {
|
|
388
|
+
const controller = new AbortController();
|
|
389
|
+
const timeoutId = setTimeout(
|
|
390
|
+
() => controller.abort(),
|
|
391
|
+
timeout
|
|
392
|
+
);
|
|
393
|
+
return { timeoutId, controller };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/client/utils/internal/requests.ts
|
|
397
|
+
function constructAgentUrl(agentUrl, agentId) {
|
|
398
|
+
return `${agentUrl}/${agentId}`;
|
|
399
|
+
}
|
|
400
|
+
function logRequest(method, url, headers, body) {
|
|
401
|
+
logger("Request: %s %s", method, url);
|
|
402
|
+
logger("Headers: %o", headers);
|
|
403
|
+
if (body) {
|
|
404
|
+
logger("Body: %s", formatObject(body));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async function getHeaders(authProvider, isStreaming = false) {
|
|
408
|
+
const baseHeaders = {
|
|
409
|
+
"Content-Type": "application/json"
|
|
410
|
+
};
|
|
411
|
+
if (isStreaming) {
|
|
412
|
+
baseHeaders.Accept = "text/event-stream";
|
|
413
|
+
}
|
|
414
|
+
if (authProvider) {
|
|
415
|
+
const authHeaders = await authProvider();
|
|
416
|
+
return { ...baseHeaders, ...authHeaders };
|
|
417
|
+
}
|
|
418
|
+
return baseHeaders;
|
|
419
|
+
}
|
|
420
|
+
function createFetchOptions(headers, body, signal) {
|
|
421
|
+
return {
|
|
422
|
+
method: "POST",
|
|
423
|
+
headers,
|
|
424
|
+
body,
|
|
425
|
+
signal
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
async function prepareRequest(params, config, options, toolProvider, contextProvider, defaultSessionId) {
|
|
429
|
+
const { message, sessionId, taskId, metadata } = params;
|
|
430
|
+
const { agentId, agentUrl, authProvider, proxy } = config;
|
|
431
|
+
const { isStreaming = false } = options;
|
|
432
|
+
const effectiveSessionId = sessionId || defaultSessionId;
|
|
433
|
+
const fullAgentUrl = constructAgentUrl(agentUrl, agentId);
|
|
434
|
+
const enhancedMessage = await enhanceMessage(
|
|
435
|
+
message,
|
|
436
|
+
toolProvider,
|
|
437
|
+
contextProvider
|
|
438
|
+
);
|
|
439
|
+
const request = createSendMessageRequest(
|
|
440
|
+
{
|
|
441
|
+
id: taskId,
|
|
442
|
+
sessionId: effectiveSessionId,
|
|
443
|
+
message: enhancedMessage,
|
|
444
|
+
metadata
|
|
445
|
+
},
|
|
446
|
+
isStreaming ? "message/stream" : "message/send"
|
|
447
|
+
);
|
|
448
|
+
const headers = await getHeaders(authProvider, isStreaming);
|
|
449
|
+
logRequest("POST", fullAgentUrl, headers, request);
|
|
450
|
+
return {
|
|
451
|
+
request,
|
|
452
|
+
headers,
|
|
453
|
+
enhancedMessage,
|
|
454
|
+
effectiveSessionId,
|
|
455
|
+
fullAgentUrl
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
async function executeRequest(preparedRequest, config) {
|
|
459
|
+
const { request, headers, fullAgentUrl } = preparedRequest;
|
|
460
|
+
const { timeout } = config;
|
|
461
|
+
const { timeoutId, controller } = createTimeoutHandler(
|
|
462
|
+
timeout,
|
|
463
|
+
"request"
|
|
464
|
+
);
|
|
465
|
+
try {
|
|
466
|
+
const options = createFetchOptions(
|
|
467
|
+
headers,
|
|
468
|
+
JSON.stringify(request),
|
|
469
|
+
controller.signal
|
|
470
|
+
);
|
|
471
|
+
logger("Making request to %s with options: %O", fullAgentUrl, {
|
|
472
|
+
method: options.method,
|
|
473
|
+
headers: options.headers
|
|
474
|
+
});
|
|
475
|
+
const response = await fetch(fullAgentUrl, options);
|
|
476
|
+
clearTimeout(timeoutId);
|
|
477
|
+
validateHttpResponse(response, "request");
|
|
478
|
+
const data = await response.json();
|
|
479
|
+
logger(
|
|
480
|
+
"Response from %s: %d %O",
|
|
481
|
+
fullAgentUrl,
|
|
482
|
+
response.status,
|
|
483
|
+
formatObject(data)
|
|
484
|
+
);
|
|
485
|
+
return validateJsonRpcResponse(data, "request");
|
|
486
|
+
} catch (error) {
|
|
487
|
+
handleRequestError(error, timeoutId, "request");
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function* executeStreamingRequest(preparedRequest, config, options) {
|
|
491
|
+
const { request, headers, fullAgentUrl } = preparedRequest;
|
|
492
|
+
const {} = config;
|
|
493
|
+
const { streamingTimeout = 6e4 } = options;
|
|
494
|
+
const { timeoutId, controller } = createTimeoutHandler(
|
|
495
|
+
streamingTimeout,
|
|
496
|
+
"streaming request"
|
|
497
|
+
);
|
|
498
|
+
try {
|
|
499
|
+
const fetchOptions = createFetchOptions(
|
|
500
|
+
headers,
|
|
501
|
+
JSON.stringify(request),
|
|
502
|
+
controller.signal
|
|
503
|
+
);
|
|
504
|
+
const response = await fetch(fullAgentUrl, fetchOptions);
|
|
505
|
+
clearTimeout(timeoutId);
|
|
506
|
+
validateStreamingResponse(response, "streaming request");
|
|
507
|
+
yield* parseSSEStream(response.body);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
handleRequestError(error, timeoutId, "streaming request");
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/client/index.ts
|
|
514
|
+
var DEFAULT_TIMEOUT = 12e4;
|
|
515
|
+
async function executeToolCallBatch(toolCalls, toolProvider, messageId) {
|
|
516
|
+
const results = [];
|
|
517
|
+
const agentMessages = [];
|
|
518
|
+
let shouldReturnToAgent = false;
|
|
519
|
+
for (const toolCall of toolCalls) {
|
|
520
|
+
const { toolCallId, toolId, arguments: args } = toolCall.data;
|
|
521
|
+
try {
|
|
522
|
+
const executionResult = await toolProvider.executeTool(
|
|
523
|
+
toolId,
|
|
524
|
+
args,
|
|
525
|
+
messageId,
|
|
526
|
+
toolCallId
|
|
527
|
+
);
|
|
528
|
+
const { result, returnToAgent, agentMessage } = processToolExecutionResult(executionResult);
|
|
529
|
+
if (returnToAgent) {
|
|
530
|
+
shouldReturnToAgent = true;
|
|
531
|
+
}
|
|
532
|
+
if (agentMessage) {
|
|
533
|
+
agentMessages.push(createAgentTextMessage(agentMessage));
|
|
534
|
+
}
|
|
535
|
+
results.push(
|
|
536
|
+
createToolResultDataPart(
|
|
537
|
+
toolCallId,
|
|
538
|
+
toolId,
|
|
539
|
+
result
|
|
540
|
+
)
|
|
541
|
+
);
|
|
542
|
+
} catch (error) {
|
|
543
|
+
shouldReturnToAgent = true;
|
|
544
|
+
results.push(
|
|
545
|
+
createToolResultDataPart(
|
|
546
|
+
toolCallId,
|
|
547
|
+
toolId,
|
|
548
|
+
void 0,
|
|
549
|
+
error instanceof Error ? error.message : String(error)
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return { results, shouldReturnToAgent, agentMessages };
|
|
555
|
+
}
|
|
556
|
+
function conversationHistoryToDataParts(conversationHistory) {
|
|
557
|
+
const historyParts = [];
|
|
558
|
+
for (const message of conversationHistory) {
|
|
559
|
+
for (const part of message.parts) {
|
|
560
|
+
if (part.type === "text") {
|
|
561
|
+
historyParts.push({
|
|
562
|
+
type: "data",
|
|
563
|
+
data: {
|
|
564
|
+
role: message.role,
|
|
565
|
+
text: part.text
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
} else if (part.type === "data") {
|
|
569
|
+
historyParts.push(part);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return historyParts;
|
|
574
|
+
}
|
|
575
|
+
async function continueTask(taskId, message, requestConfig, toolProvider, contextProvider, sessionId) {
|
|
576
|
+
const continueParams = {
|
|
577
|
+
message,
|
|
578
|
+
taskId,
|
|
579
|
+
sessionId: void 0
|
|
580
|
+
// Use task's session
|
|
581
|
+
};
|
|
582
|
+
const preparedRequest = await prepareRequest(
|
|
583
|
+
continueParams,
|
|
584
|
+
requestConfig,
|
|
585
|
+
{ isStreaming: false },
|
|
586
|
+
toolProvider,
|
|
587
|
+
contextProvider,
|
|
588
|
+
sessionId
|
|
589
|
+
);
|
|
590
|
+
return await executeRequest(preparedRequest, requestConfig);
|
|
591
|
+
}
|
|
592
|
+
async function continueTaskStreamed(taskId, message, requestConfig, toolProvider, contextProvider, sessionId) {
|
|
593
|
+
const continueParams = {
|
|
594
|
+
message,
|
|
595
|
+
taskId,
|
|
596
|
+
sessionId: void 0
|
|
597
|
+
// Use task's session
|
|
598
|
+
};
|
|
599
|
+
const preparedRequest = await prepareRequest(
|
|
600
|
+
continueParams,
|
|
601
|
+
requestConfig,
|
|
602
|
+
{ isStreaming: true },
|
|
603
|
+
toolProvider,
|
|
604
|
+
contextProvider,
|
|
605
|
+
sessionId
|
|
606
|
+
);
|
|
607
|
+
const stream = executeStreamingRequest(preparedRequest, requestConfig, {
|
|
608
|
+
isStreaming: true
|
|
609
|
+
});
|
|
610
|
+
return processAgentResponseStream(
|
|
611
|
+
stream,
|
|
612
|
+
toolProvider,
|
|
613
|
+
contextProvider,
|
|
614
|
+
requestConfig,
|
|
615
|
+
sessionId,
|
|
616
|
+
true,
|
|
617
|
+
// withHistory
|
|
618
|
+
[]
|
|
619
|
+
// newConversationParts - empty for continueTask
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
async function* processAgentResponseStream(stream, toolProvider, contextProvider, requestConfig, sessionId, withHistory = true, newConversationParts = []) {
|
|
623
|
+
for await (const update of stream) {
|
|
624
|
+
yield update;
|
|
625
|
+
if (update.status.state === "input-required" && update.status.message && toolProvider) {
|
|
626
|
+
const toolCalls = extractToolCallsFromMessage(
|
|
627
|
+
update.status.message
|
|
628
|
+
);
|
|
629
|
+
if (toolCalls.length > 0) {
|
|
630
|
+
const toolResults = [];
|
|
631
|
+
let shouldReturnToAgent = false;
|
|
632
|
+
const toolParts = [];
|
|
633
|
+
const agentMessages = [];
|
|
634
|
+
for (const toolCall of toolCalls) {
|
|
635
|
+
const {
|
|
636
|
+
toolCallId,
|
|
637
|
+
toolId,
|
|
638
|
+
arguments: args
|
|
639
|
+
} = toolCall.data;
|
|
640
|
+
try {
|
|
641
|
+
const executionResult = await toolProvider.executeTool(
|
|
642
|
+
toolId,
|
|
643
|
+
args,
|
|
644
|
+
update.status?.message?.messageId,
|
|
645
|
+
toolCallId
|
|
646
|
+
);
|
|
647
|
+
const { result, returnToAgent, agentMessage } = processToolExecutionResult(executionResult);
|
|
648
|
+
if (returnToAgent) {
|
|
649
|
+
shouldReturnToAgent = true;
|
|
650
|
+
}
|
|
651
|
+
if (agentMessage) {
|
|
652
|
+
agentMessages.push(
|
|
653
|
+
createAgentTextMessage(agentMessage)
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
const toolResult = createToolResultDataPart(
|
|
657
|
+
toolCallId,
|
|
658
|
+
toolId,
|
|
659
|
+
result
|
|
660
|
+
);
|
|
661
|
+
toolResults.push(toolResult);
|
|
662
|
+
toolParts.push(toolResult);
|
|
663
|
+
} catch (error) {
|
|
664
|
+
const toolResult = createToolResultDataPart(
|
|
665
|
+
toolCallId,
|
|
666
|
+
toolId,
|
|
667
|
+
void 0,
|
|
668
|
+
error instanceof Error ? error.message : String(error)
|
|
669
|
+
);
|
|
670
|
+
toolResults.push(toolResult);
|
|
671
|
+
toolParts.push(toolResult);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
newConversationParts.push(update.status.message);
|
|
675
|
+
if (shouldReturnToAgent) {
|
|
676
|
+
const historyDataParts = conversationHistoryToDataParts(newConversationParts);
|
|
677
|
+
const toolResultMessage = createToolResultMessage(
|
|
678
|
+
toolResults,
|
|
679
|
+
historyDataParts
|
|
680
|
+
);
|
|
681
|
+
yield {
|
|
682
|
+
id: update.id,
|
|
683
|
+
status: {
|
|
684
|
+
state: "working",
|
|
685
|
+
message: toolResultMessage
|
|
686
|
+
},
|
|
687
|
+
final: false,
|
|
688
|
+
text: ""
|
|
689
|
+
};
|
|
690
|
+
const continuedTaskStream = await continueTaskStreamed(
|
|
691
|
+
update.id,
|
|
692
|
+
toolResultMessage,
|
|
693
|
+
requestConfig,
|
|
694
|
+
toolProvider,
|
|
695
|
+
contextProvider,
|
|
696
|
+
sessionId
|
|
697
|
+
);
|
|
698
|
+
let continuedTaskUpdate = null;
|
|
699
|
+
for await (const streamUpdate of continuedTaskStream) {
|
|
700
|
+
if (!streamUpdate.final) {
|
|
701
|
+
yield streamUpdate;
|
|
702
|
+
} else {
|
|
703
|
+
continuedTaskUpdate = streamUpdate;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (!continuedTaskUpdate) {
|
|
707
|
+
throw new Error(
|
|
708
|
+
"Continue task stream ended without final result"
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
let continuedToolCalls = continuedTaskUpdate.status?.message ? extractToolCallsFromMessage(
|
|
712
|
+
continuedTaskUpdate.status.message
|
|
713
|
+
) : [];
|
|
714
|
+
if (toolResults.length > 0) {
|
|
715
|
+
newConversationParts.push({
|
|
716
|
+
role: "agent",
|
|
717
|
+
kind: "message",
|
|
718
|
+
parts: toolResults,
|
|
719
|
+
messageId: generateMessageId()
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
let finalTask = continuedTaskUpdate;
|
|
723
|
+
if (continuedToolCalls.length > 0) {
|
|
724
|
+
yield {
|
|
725
|
+
...continuedTaskUpdate,
|
|
726
|
+
final: false,
|
|
727
|
+
text: extractTextFromMessage(
|
|
728
|
+
continuedTaskUpdate.status?.message || {
|
|
729
|
+
role: "agent",
|
|
730
|
+
kind: "message",
|
|
731
|
+
parts: [],
|
|
732
|
+
messageId: generateMessageId()
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
};
|
|
736
|
+
while (continuedToolCalls.length > 0) {
|
|
737
|
+
if (finalTask.status?.message) {
|
|
738
|
+
newConversationParts.push(
|
|
739
|
+
finalTask.status.message
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
const {
|
|
743
|
+
results: moreResults,
|
|
744
|
+
shouldReturnToAgent: moreShouldReturn
|
|
745
|
+
} = await executeToolCallBatch(
|
|
746
|
+
continuedToolCalls,
|
|
747
|
+
toolProvider,
|
|
748
|
+
finalTask.status?.message?.messageId
|
|
749
|
+
);
|
|
750
|
+
if (moreResults.length > 0) {
|
|
751
|
+
yield {
|
|
752
|
+
id: finalTask.id,
|
|
753
|
+
status: {
|
|
754
|
+
state: "working",
|
|
755
|
+
message: {
|
|
756
|
+
role: "agent",
|
|
757
|
+
kind: "message",
|
|
758
|
+
parts: moreResults,
|
|
759
|
+
messageId: generateMessageId()
|
|
760
|
+
}
|
|
761
|
+
// Simple message with just the results
|
|
762
|
+
},
|
|
763
|
+
final: false,
|
|
764
|
+
text: ""
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
if (moreShouldReturn) {
|
|
768
|
+
const moreHistoryDataParts = withHistory ? conversationHistoryToDataParts(
|
|
769
|
+
newConversationParts
|
|
770
|
+
) : [];
|
|
771
|
+
const moreResultMessage = createToolResultMessage(
|
|
772
|
+
moreResults,
|
|
773
|
+
moreHistoryDataParts
|
|
774
|
+
);
|
|
775
|
+
const moreTaskStream = await continueTaskStreamed(
|
|
776
|
+
finalTask.id,
|
|
777
|
+
moreResultMessage,
|
|
778
|
+
requestConfig,
|
|
779
|
+
toolProvider,
|
|
780
|
+
contextProvider,
|
|
781
|
+
sessionId
|
|
782
|
+
);
|
|
783
|
+
let moreFinalTask = null;
|
|
784
|
+
for await (const streamUpdate of moreTaskStream) {
|
|
785
|
+
if (!streamUpdate.final) {
|
|
786
|
+
yield streamUpdate;
|
|
787
|
+
} else {
|
|
788
|
+
moreFinalTask = streamUpdate;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (!moreFinalTask) {
|
|
792
|
+
throw new Error(
|
|
793
|
+
"Continue task stream ended without final result"
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
finalTask = moreFinalTask;
|
|
797
|
+
continuedToolCalls = finalTask.status?.message ? extractToolCallsFromMessage(
|
|
798
|
+
finalTask.status.message
|
|
799
|
+
) : [];
|
|
800
|
+
if (continuedToolCalls.length > 0) {
|
|
801
|
+
yield {
|
|
802
|
+
id: finalTask.id,
|
|
803
|
+
status: finalTask.status,
|
|
804
|
+
final: false,
|
|
805
|
+
text: extractTextFromMessage(
|
|
806
|
+
finalTask.status?.message || {
|
|
807
|
+
role: "agent",
|
|
808
|
+
kind: "message",
|
|
809
|
+
parts: [],
|
|
810
|
+
messageId: generateMessageId()
|
|
811
|
+
}
|
|
812
|
+
)
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
} else {
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
yield {
|
|
821
|
+
...finalTask,
|
|
822
|
+
final: true,
|
|
823
|
+
text: extractTextFromMessage(
|
|
824
|
+
finalTask.status?.message || {
|
|
825
|
+
role: "agent",
|
|
826
|
+
kind: "message",
|
|
827
|
+
parts: [],
|
|
828
|
+
messageId: generateMessageId()
|
|
829
|
+
}
|
|
830
|
+
)
|
|
831
|
+
};
|
|
832
|
+
} else {
|
|
833
|
+
const enhancedMessage = {
|
|
834
|
+
...update.status.message,
|
|
835
|
+
parts: toolParts
|
|
836
|
+
};
|
|
837
|
+
const enhancedUpdate = {
|
|
838
|
+
...update,
|
|
839
|
+
status: {
|
|
840
|
+
...update.status,
|
|
841
|
+
message: enhancedMessage
|
|
842
|
+
},
|
|
843
|
+
final: agentMessages.length === 0,
|
|
844
|
+
// Only final if no agent messages to follow
|
|
845
|
+
text: extractTextFromMessage(enhancedMessage)
|
|
846
|
+
};
|
|
847
|
+
yield enhancedUpdate;
|
|
848
|
+
if (agentMessages.length > 0) {
|
|
849
|
+
const combinedAgentText = agentMessages.map((msg) => extractTextFromMessage(msg)).join(" ");
|
|
850
|
+
const finalAgentMessage = createAgentTextMessage(combinedAgentText);
|
|
851
|
+
yield {
|
|
852
|
+
id: enhancedUpdate.id,
|
|
853
|
+
status: {
|
|
854
|
+
state: "completed",
|
|
855
|
+
message: finalAgentMessage
|
|
856
|
+
},
|
|
857
|
+
final: true,
|
|
858
|
+
text: combinedAgentText
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
function createClient(config) {
|
|
867
|
+
const {
|
|
868
|
+
agentId,
|
|
869
|
+
agentUrl,
|
|
870
|
+
authProvider,
|
|
871
|
+
defaultSessionId,
|
|
872
|
+
timeout = DEFAULT_TIMEOUT,
|
|
873
|
+
toolProvider,
|
|
874
|
+
contextProvider
|
|
875
|
+
} = config;
|
|
876
|
+
const requestConfig = {
|
|
877
|
+
agentId,
|
|
878
|
+
agentUrl,
|
|
879
|
+
authProvider,
|
|
880
|
+
timeout
|
|
881
|
+
};
|
|
882
|
+
return {
|
|
883
|
+
async sendMessage(params) {
|
|
884
|
+
const { withHistory = true } = params;
|
|
885
|
+
const sessionId = params.sessionId || defaultSessionId || void 0;
|
|
886
|
+
const newConversationParts = [];
|
|
887
|
+
newConversationParts.push(params.message);
|
|
888
|
+
const preparedRequest = await prepareRequest(
|
|
889
|
+
params,
|
|
890
|
+
requestConfig,
|
|
891
|
+
{ isStreaming: false },
|
|
892
|
+
toolProvider,
|
|
893
|
+
contextProvider,
|
|
894
|
+
sessionId
|
|
895
|
+
);
|
|
896
|
+
let currentTask = await executeRequest(
|
|
897
|
+
preparedRequest,
|
|
898
|
+
requestConfig
|
|
899
|
+
);
|
|
900
|
+
const allToolParts = [];
|
|
901
|
+
const agentMessages = [];
|
|
902
|
+
while (currentTask.status.message && toolProvider) {
|
|
903
|
+
const toolCalls = extractToolCallsFromMessage(
|
|
904
|
+
currentTask.status.message
|
|
905
|
+
);
|
|
906
|
+
if (toolCalls.length === 0) {
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
allToolParts.push(...toolCalls);
|
|
910
|
+
const toolResults = [];
|
|
911
|
+
let shouldReturnToAgent = false;
|
|
912
|
+
for (const toolCall of toolCalls) {
|
|
913
|
+
const {
|
|
914
|
+
toolCallId,
|
|
915
|
+
toolId,
|
|
916
|
+
arguments: args
|
|
917
|
+
} = toolCall.data;
|
|
918
|
+
try {
|
|
919
|
+
const executionResult = await toolProvider.executeTool(
|
|
920
|
+
toolId,
|
|
921
|
+
args
|
|
922
|
+
);
|
|
923
|
+
const { result, returnToAgent, agentMessage } = processToolExecutionResult(executionResult);
|
|
924
|
+
if (returnToAgent) {
|
|
925
|
+
shouldReturnToAgent = true;
|
|
926
|
+
}
|
|
927
|
+
if (agentMessage) {
|
|
928
|
+
agentMessages.push(
|
|
929
|
+
createAgentTextMessage(agentMessage)
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
const toolResult = createToolResultDataPart(
|
|
933
|
+
toolCallId,
|
|
934
|
+
toolId,
|
|
935
|
+
result
|
|
936
|
+
);
|
|
937
|
+
toolResults.push(toolResult);
|
|
938
|
+
allToolParts.push(toolResult);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
const toolResult = createToolResultDataPart(
|
|
941
|
+
toolCallId,
|
|
942
|
+
toolId,
|
|
943
|
+
void 0,
|
|
944
|
+
error instanceof Error ? error.message : String(error)
|
|
945
|
+
);
|
|
946
|
+
toolResults.push(toolResult);
|
|
947
|
+
allToolParts.push(toolResult);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
newConversationParts.push(currentTask.status.message);
|
|
951
|
+
if (shouldReturnToAgent) {
|
|
952
|
+
const toolResultMessage = createToolResultMessage(toolResults);
|
|
953
|
+
currentTask = await continueTask(
|
|
954
|
+
currentTask.id,
|
|
955
|
+
toolResultMessage,
|
|
956
|
+
requestConfig,
|
|
957
|
+
toolProvider,
|
|
958
|
+
contextProvider,
|
|
959
|
+
sessionId
|
|
960
|
+
);
|
|
961
|
+
} else {
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (allToolParts.length > 0) {
|
|
966
|
+
if (currentTask.status?.message) {
|
|
967
|
+
const enhancedMessage = {
|
|
968
|
+
...currentTask.status.message,
|
|
969
|
+
parts: allToolParts
|
|
970
|
+
};
|
|
971
|
+
currentTask = {
|
|
972
|
+
...currentTask,
|
|
973
|
+
status: {
|
|
974
|
+
...currentTask.status,
|
|
975
|
+
message: enhancedMessage
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (agentMessages.length > 0) {
|
|
981
|
+
const combinedAgentText = agentMessages.map((msg) => extractTextFromMessage(msg)).join(" ");
|
|
982
|
+
const finalAgentMessage = createAgentTextMessage(combinedAgentText);
|
|
983
|
+
return {
|
|
984
|
+
...currentTask,
|
|
985
|
+
// Keep the enhanced message with tool results
|
|
986
|
+
// The agent message will be handled separately by the caller
|
|
987
|
+
text: combinedAgentText,
|
|
988
|
+
agentMessage: finalAgentMessage
|
|
989
|
+
// Add this for the caller to handle
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
return {
|
|
993
|
+
...currentTask,
|
|
994
|
+
text: extractTextFromMessage(
|
|
995
|
+
currentTask.status?.message || {
|
|
996
|
+
role: "agent",
|
|
997
|
+
kind: "message",
|
|
998
|
+
parts: [],
|
|
999
|
+
messageId: generateMessageId()
|
|
1000
|
+
}
|
|
1001
|
+
)
|
|
1002
|
+
};
|
|
1003
|
+
},
|
|
1004
|
+
async *sendMessageStream(params) {
|
|
1005
|
+
const { withHistory = true } = params;
|
|
1006
|
+
const sessionId = params.sessionId || defaultSessionId || void 0;
|
|
1007
|
+
const newConversationParts = [];
|
|
1008
|
+
newConversationParts.push(params.message);
|
|
1009
|
+
const preparedRequest = await prepareRequest(
|
|
1010
|
+
params,
|
|
1011
|
+
requestConfig,
|
|
1012
|
+
{ isStreaming: true, streamingTimeout: timeout },
|
|
1013
|
+
toolProvider,
|
|
1014
|
+
contextProvider,
|
|
1015
|
+
sessionId
|
|
1016
|
+
);
|
|
1017
|
+
const stream = executeStreamingRequest(
|
|
1018
|
+
preparedRequest,
|
|
1019
|
+
requestConfig,
|
|
1020
|
+
{
|
|
1021
|
+
isStreaming: true,
|
|
1022
|
+
streamingTimeout: timeout
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
yield* processAgentResponseStream(
|
|
1026
|
+
stream,
|
|
1027
|
+
toolProvider,
|
|
1028
|
+
contextProvider,
|
|
1029
|
+
requestConfig,
|
|
1030
|
+
sessionId,
|
|
1031
|
+
withHistory,
|
|
1032
|
+
newConversationParts
|
|
1033
|
+
);
|
|
1034
|
+
},
|
|
1035
|
+
async continueTask(taskId, userInput, sessionId) {
|
|
1036
|
+
const userMessage = createTextMessage(userInput);
|
|
1037
|
+
const continuedTask = await continueTask(
|
|
1038
|
+
taskId,
|
|
1039
|
+
userMessage,
|
|
1040
|
+
requestConfig,
|
|
1041
|
+
toolProvider,
|
|
1042
|
+
contextProvider,
|
|
1043
|
+
sessionId
|
|
1044
|
+
);
|
|
1045
|
+
let currentTask = continuedTask;
|
|
1046
|
+
while (currentTask.status.state === "input-required" && currentTask.status.message && toolProvider) {
|
|
1047
|
+
const toolCalls = extractToolCallsFromMessage(
|
|
1048
|
+
currentTask.status.message
|
|
1049
|
+
);
|
|
1050
|
+
if (toolCalls.length === 0) {
|
|
1051
|
+
break;
|
|
1052
|
+
}
|
|
1053
|
+
const { results: toolResults, shouldReturnToAgent } = await executeToolCallBatch(toolCalls, toolProvider);
|
|
1054
|
+
if (shouldReturnToAgent) {
|
|
1055
|
+
const toolResultMessage = createToolResultMessage(toolResults);
|
|
1056
|
+
currentTask = await continueTask(
|
|
1057
|
+
currentTask.id,
|
|
1058
|
+
toolResultMessage,
|
|
1059
|
+
requestConfig,
|
|
1060
|
+
toolProvider,
|
|
1061
|
+
contextProvider,
|
|
1062
|
+
sessionId
|
|
1063
|
+
);
|
|
1064
|
+
} else {
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return {
|
|
1069
|
+
...currentTask,
|
|
1070
|
+
text: extractTextFromMessage(
|
|
1071
|
+
currentTask.status?.message || {
|
|
1072
|
+
role: "agent",
|
|
1073
|
+
kind: "message",
|
|
1074
|
+
parts: [],
|
|
1075
|
+
messageId: generateMessageId()
|
|
1076
|
+
}
|
|
1077
|
+
)
|
|
1078
|
+
};
|
|
1079
|
+
},
|
|
1080
|
+
async getTask(taskId) {
|
|
1081
|
+
throw new Error("getTask not implemented yet");
|
|
1082
|
+
},
|
|
1083
|
+
async cancelTask(taskId) {
|
|
1084
|
+
throw new Error("cancelTask not implemented yet");
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// src/react/conversationStorage.ts
|
|
1090
|
+
var STORAGE_KEY = "a8c_agenttic_conversation_history";
|
|
1091
|
+
function extractStorableContent(message) {
|
|
1092
|
+
const textParts = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
1093
|
+
const toolCalls = message.parts.filter(
|
|
1094
|
+
(part) => part.type === "data" && "toolCallId" in part.data && "arguments" in part.data
|
|
1095
|
+
).map((part) => ({
|
|
1096
|
+
toolCallId: part.data.toolCallId,
|
|
1097
|
+
toolId: part.data.toolId,
|
|
1098
|
+
arguments: part.data.arguments
|
|
1099
|
+
}));
|
|
1100
|
+
const toolResults = message.parts.filter(
|
|
1101
|
+
(part) => part.type === "data" && "toolCallId" in part.data && "result" in part.data
|
|
1102
|
+
).map((part) => ({
|
|
1103
|
+
toolCallId: part.data.toolCallId,
|
|
1104
|
+
result: part.data.result,
|
|
1105
|
+
error: part.data.error
|
|
1106
|
+
}));
|
|
1107
|
+
const hasToolInteractions = toolCalls.length > 0 || toolResults.length > 0;
|
|
1108
|
+
const storageRole = hasToolInteractions ? "agent" : message.role;
|
|
1109
|
+
const timestamp = message.metadata?.timestamp ?? Date.now();
|
|
1110
|
+
return {
|
|
1111
|
+
role: storageRole,
|
|
1112
|
+
content: textParts || "(No text content)",
|
|
1113
|
+
timestamp,
|
|
1114
|
+
...toolCalls.length > 0 && { toolCalls },
|
|
1115
|
+
...toolResults.length > 0 && { toolResults }
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
function restoreMessage(stored) {
|
|
1119
|
+
const parts = [];
|
|
1120
|
+
if (stored.content && stored.content !== "(No text content)") {
|
|
1121
|
+
parts.push({
|
|
1122
|
+
type: "text",
|
|
1123
|
+
text: stored.content
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
if (stored.toolCalls) {
|
|
1127
|
+
for (const toolCall of stored.toolCalls) {
|
|
1128
|
+
parts.push({
|
|
1129
|
+
type: "data",
|
|
1130
|
+
data: {
|
|
1131
|
+
toolCallId: toolCall.toolCallId,
|
|
1132
|
+
toolId: toolCall.toolId,
|
|
1133
|
+
arguments: toolCall.arguments
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (stored.toolResults) {
|
|
1139
|
+
for (const toolResult of stored.toolResults) {
|
|
1140
|
+
parts.push({
|
|
1141
|
+
type: "data",
|
|
1142
|
+
data: {
|
|
1143
|
+
toolCallId: toolResult.toolCallId,
|
|
1144
|
+
result: toolResult.result,
|
|
1145
|
+
...toolResult.error && { error: toolResult.error }
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return {
|
|
1151
|
+
role: stored.role,
|
|
1152
|
+
kind: "message",
|
|
1153
|
+
parts,
|
|
1154
|
+
messageId: generateMessageId(),
|
|
1155
|
+
metadata: {
|
|
1156
|
+
timestamp: stored.timestamp
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
var conversationCache = /* @__PURE__ */ new Map();
|
|
1161
|
+
var maxCacheSize = 50;
|
|
1162
|
+
async function storeConversation(sessionId, messages, conversationStorageKey) {
|
|
1163
|
+
const currentStorageKey = conversationStorageKey || sessionId;
|
|
1164
|
+
conversationCache.set(currentStorageKey, [...messages]);
|
|
1165
|
+
if (conversationCache.size > maxCacheSize) {
|
|
1166
|
+
const firstKey = conversationCache.keys().next().value;
|
|
1167
|
+
if (firstKey) {
|
|
1168
|
+
conversationCache.delete(firstKey);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (typeof sessionStorage === "undefined") {
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
try {
|
|
1175
|
+
const stored = {
|
|
1176
|
+
storageKey: currentStorageKey,
|
|
1177
|
+
messages: messages.map(extractStorableContent),
|
|
1178
|
+
lastUpdated: Date.now()
|
|
1179
|
+
};
|
|
1180
|
+
sessionStorage.setItem(
|
|
1181
|
+
`${STORAGE_KEY}_${currentStorageKey}`,
|
|
1182
|
+
JSON.stringify(stored)
|
|
1183
|
+
);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
logger(
|
|
1186
|
+
"Failed to store conversation in sessionStorage for key %s: %O",
|
|
1187
|
+
currentStorageKey,
|
|
1188
|
+
error
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
async function loadConversation(sessionId, conversationStorageKey) {
|
|
1193
|
+
const currentStorageKey = conversationStorageKey || sessionId;
|
|
1194
|
+
if (conversationCache.has(currentStorageKey)) {
|
|
1195
|
+
return [...conversationCache.get(currentStorageKey)];
|
|
1196
|
+
}
|
|
1197
|
+
if (typeof sessionStorage === "undefined") {
|
|
1198
|
+
return [];
|
|
1199
|
+
}
|
|
1200
|
+
try {
|
|
1201
|
+
const stored = sessionStorage.getItem(
|
|
1202
|
+
`${STORAGE_KEY}_${currentStorageKey}`
|
|
1203
|
+
);
|
|
1204
|
+
if (stored) {
|
|
1205
|
+
const conversation = JSON.parse(stored);
|
|
1206
|
+
const messages = conversation.messages.map(restoreMessage);
|
|
1207
|
+
conversationCache.set(currentStorageKey, messages);
|
|
1208
|
+
return [...messages];
|
|
1209
|
+
}
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
logger(
|
|
1212
|
+
"Failed to load conversation from sessionStorage for key %s: %O",
|
|
1213
|
+
currentStorageKey,
|
|
1214
|
+
error
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
return [];
|
|
1218
|
+
}
|
|
1219
|
+
async function clearConversation(sessionId, conversationStorageKey) {
|
|
1220
|
+
const currentStorageKey = conversationStorageKey || sessionId;
|
|
1221
|
+
conversationCache.delete(currentStorageKey);
|
|
1222
|
+
if (typeof sessionStorage === "undefined") {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
try {
|
|
1226
|
+
sessionStorage.removeItem(`${STORAGE_KEY}_${currentStorageKey}`);
|
|
1227
|
+
} catch (error) {
|
|
1228
|
+
logger(
|
|
1229
|
+
"Failed to clear conversation from sessionStorage for key %s: %O",
|
|
1230
|
+
currentStorageKey,
|
|
1231
|
+
error
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// src/react/conversationUtils.ts
|
|
1237
|
+
function extractNewContentFromMessage(message) {
|
|
1238
|
+
const newParts = message.parts.filter((part) => {
|
|
1239
|
+
if (part.type === "text") {
|
|
1240
|
+
return true;
|
|
1241
|
+
}
|
|
1242
|
+
if (part.type === "data") {
|
|
1243
|
+
if ("role" in part.data && "text" in part.data) {
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
if ("toolCallId" in part.data && "arguments" in part.data) {
|
|
1247
|
+
return true;
|
|
1248
|
+
}
|
|
1249
|
+
if ("toolCallId" in part.data && "result" in part.data) {
|
|
1250
|
+
return true;
|
|
1251
|
+
}
|
|
1252
|
+
return false;
|
|
1253
|
+
}
|
|
1254
|
+
return true;
|
|
1255
|
+
});
|
|
1256
|
+
return {
|
|
1257
|
+
...message,
|
|
1258
|
+
parts: newParts,
|
|
1259
|
+
// Preserve metadata if it exists, otherwise add timestamp
|
|
1260
|
+
metadata: message.metadata || {
|
|
1261
|
+
timestamp: Date.now()
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function conversationMessagesToDataParts(conversationMessages) {
|
|
1266
|
+
const historyParts = [];
|
|
1267
|
+
for (const message of conversationMessages) {
|
|
1268
|
+
for (const part of message.parts) {
|
|
1269
|
+
if (part.type === "text") {
|
|
1270
|
+
historyParts.push({
|
|
1271
|
+
type: "data",
|
|
1272
|
+
data: {
|
|
1273
|
+
role: message.role,
|
|
1274
|
+
text: part.text
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
} else if (part.type === "data") {
|
|
1278
|
+
if ("role" in part.data && "text" in part.data) {
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
if ("toolCallId" in part.data && "arguments" in part.data) {
|
|
1282
|
+
historyParts.push(part);
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
if ("toolCallId" in part.data && "result" in part.data) {
|
|
1286
|
+
historyParts.push(part);
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
return historyParts;
|
|
1293
|
+
}
|
|
1294
|
+
function createTextMessageWithHistory(text, conversationMessages = []) {
|
|
1295
|
+
const historyParts = conversationMessagesToDataParts(conversationMessages);
|
|
1296
|
+
return {
|
|
1297
|
+
role: "user",
|
|
1298
|
+
parts: [
|
|
1299
|
+
...historyParts,
|
|
1300
|
+
{
|
|
1301
|
+
type: "text",
|
|
1302
|
+
text
|
|
1303
|
+
}
|
|
1304
|
+
],
|
|
1305
|
+
kind: "message",
|
|
1306
|
+
messageId: generateMessageId(),
|
|
1307
|
+
metadata: {
|
|
1308
|
+
timestamp: Date.now()
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
function extractToolResultsFromMessage(message) {
|
|
1313
|
+
if (!message?.parts) {
|
|
1314
|
+
return [];
|
|
1315
|
+
}
|
|
1316
|
+
return message.parts.filter(
|
|
1317
|
+
(part) => part.type === "data" && "toolCallId" in part.data && "result" in part.data
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// src/react/agentManager.ts
|
|
1322
|
+
function createAgentManager() {
|
|
1323
|
+
const agents = /* @__PURE__ */ new Map();
|
|
1324
|
+
async function persistConversationHistory(key, messages) {
|
|
1325
|
+
const agent = agents.get(key);
|
|
1326
|
+
if (agent?.sessionId) {
|
|
1327
|
+
try {
|
|
1328
|
+
await storeConversation(
|
|
1329
|
+
agent.sessionId,
|
|
1330
|
+
messages,
|
|
1331
|
+
agent.conversationStorageKey
|
|
1332
|
+
);
|
|
1333
|
+
} catch (error) {
|
|
1334
|
+
log(
|
|
1335
|
+
`Failed to persist conversation history for agent ${key}:`,
|
|
1336
|
+
error
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return {
|
|
1342
|
+
async createAgent(key, config) {
|
|
1343
|
+
if (agents.has(key)) {
|
|
1344
|
+
return agents.get(key).client;
|
|
1345
|
+
}
|
|
1346
|
+
const client = createClient(config);
|
|
1347
|
+
const sessionId = config.sessionId || null;
|
|
1348
|
+
const conversationStorageKey = config.conversationStorageKey;
|
|
1349
|
+
let conversationHistory = [];
|
|
1350
|
+
if (sessionId) {
|
|
1351
|
+
try {
|
|
1352
|
+
conversationHistory = await loadConversation(
|
|
1353
|
+
sessionId,
|
|
1354
|
+
conversationStorageKey
|
|
1355
|
+
);
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
log(
|
|
1358
|
+
`Failed to load conversation history for agent ${key} with session ${sessionId}:`,
|
|
1359
|
+
error
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
const managedAgent = {
|
|
1364
|
+
client,
|
|
1365
|
+
sessionId,
|
|
1366
|
+
conversationStorageKey,
|
|
1367
|
+
conversationHistory
|
|
1368
|
+
};
|
|
1369
|
+
agents.set(key, managedAgent);
|
|
1370
|
+
return client;
|
|
1371
|
+
},
|
|
1372
|
+
getAgent(key) {
|
|
1373
|
+
const agent = agents.get(key);
|
|
1374
|
+
return agent?.client || null;
|
|
1375
|
+
},
|
|
1376
|
+
hasAgent(key) {
|
|
1377
|
+
return agents.has(key);
|
|
1378
|
+
},
|
|
1379
|
+
removeAgent(key) {
|
|
1380
|
+
return agents.delete(key);
|
|
1381
|
+
},
|
|
1382
|
+
async sendMessage(key, message, options = {}) {
|
|
1383
|
+
const managedAgent = agents.get(key);
|
|
1384
|
+
if (!managedAgent) {
|
|
1385
|
+
throw new Error(`Agent with key "${key}" not found`);
|
|
1386
|
+
}
|
|
1387
|
+
const { withHistory = true, ...otherOptions } = options;
|
|
1388
|
+
const { client, conversationHistory } = managedAgent;
|
|
1389
|
+
const messageObj = options.message || createTextMessageWithHistory(message, conversationHistory);
|
|
1390
|
+
const task = await client.sendMessage({
|
|
1391
|
+
message: messageObj,
|
|
1392
|
+
withHistory,
|
|
1393
|
+
...otherOptions
|
|
1394
|
+
});
|
|
1395
|
+
let completeAgentMessage = null;
|
|
1396
|
+
if (task.status?.message) {
|
|
1397
|
+
const toolParts = task.status.message.parts.filter(
|
|
1398
|
+
(part) => part.type === "data" && "toolCallId" in part.data && ("arguments" in part.data || "result" in part.data)
|
|
1399
|
+
);
|
|
1400
|
+
const textParts = task.status.message.parts.filter(
|
|
1401
|
+
(part) => part.type === "text"
|
|
1402
|
+
);
|
|
1403
|
+
completeAgentMessage = {
|
|
1404
|
+
role: "agent",
|
|
1405
|
+
kind: "message",
|
|
1406
|
+
parts: [...toolParts, ...textParts],
|
|
1407
|
+
messageId: generateMessageId(),
|
|
1408
|
+
metadata: {
|
|
1409
|
+
timestamp: Date.now()
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
const newConversationHistory = [
|
|
1414
|
+
...conversationHistory,
|
|
1415
|
+
// Store only the new content from the user message (without history parts)
|
|
1416
|
+
createTextMessage(message),
|
|
1417
|
+
// Add complete agent response with tool calls/results if present
|
|
1418
|
+
...completeAgentMessage ? [extractNewContentFromMessage(completeAgentMessage)] : []
|
|
1419
|
+
];
|
|
1420
|
+
let finalConversationHistory = newConversationHistory;
|
|
1421
|
+
if (task.agentMessage) {
|
|
1422
|
+
const separateAgentMessage = extractNewContentFromMessage(
|
|
1423
|
+
task.agentMessage
|
|
1424
|
+
);
|
|
1425
|
+
finalConversationHistory = [
|
|
1426
|
+
...newConversationHistory,
|
|
1427
|
+
separateAgentMessage
|
|
1428
|
+
];
|
|
1429
|
+
}
|
|
1430
|
+
managedAgent.conversationHistory = finalConversationHistory;
|
|
1431
|
+
if (withHistory) {
|
|
1432
|
+
await persistConversationHistory(
|
|
1433
|
+
key,
|
|
1434
|
+
finalConversationHistory
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
return task;
|
|
1438
|
+
},
|
|
1439
|
+
async *sendMessageStream(key, message, options = {}) {
|
|
1440
|
+
const managedAgent = agents.get(key);
|
|
1441
|
+
if (!managedAgent) {
|
|
1442
|
+
throw new Error(`Agent with key "${key}" not found`);
|
|
1443
|
+
}
|
|
1444
|
+
const { withHistory = true, ...otherOptions } = options;
|
|
1445
|
+
const { client } = managedAgent;
|
|
1446
|
+
let currentConversationHistory = [
|
|
1447
|
+
...managedAgent.conversationHistory
|
|
1448
|
+
];
|
|
1449
|
+
let currentToolCallIds = [];
|
|
1450
|
+
const messageObj = options.message || createTextMessageWithHistory(
|
|
1451
|
+
message,
|
|
1452
|
+
currentConversationHistory
|
|
1453
|
+
);
|
|
1454
|
+
const userMessage = createTextMessage(message);
|
|
1455
|
+
currentConversationHistory = [
|
|
1456
|
+
...currentConversationHistory,
|
|
1457
|
+
userMessage
|
|
1458
|
+
];
|
|
1459
|
+
managedAgent.conversationHistory = currentConversationHistory;
|
|
1460
|
+
if (withHistory) {
|
|
1461
|
+
await persistConversationHistory(
|
|
1462
|
+
key,
|
|
1463
|
+
currentConversationHistory
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
for await (const update of client.sendMessageStream({
|
|
1467
|
+
message: messageObj,
|
|
1468
|
+
withHistory,
|
|
1469
|
+
...otherOptions
|
|
1470
|
+
})) {
|
|
1471
|
+
if (update.status?.state === "input-required" && update.status?.message) {
|
|
1472
|
+
const toolCalls = extractToolCallsFromMessage(
|
|
1473
|
+
update.status.message
|
|
1474
|
+
);
|
|
1475
|
+
currentToolCallIds = toolCalls.map(
|
|
1476
|
+
(call) => call.data.toolCallId
|
|
1477
|
+
);
|
|
1478
|
+
const toolMessage = extractNewContentFromMessage(
|
|
1479
|
+
update.status.message
|
|
1480
|
+
);
|
|
1481
|
+
currentConversationHistory = [
|
|
1482
|
+
...currentConversationHistory,
|
|
1483
|
+
toolMessage
|
|
1484
|
+
];
|
|
1485
|
+
managedAgent.conversationHistory = currentConversationHistory;
|
|
1486
|
+
if (withHistory) {
|
|
1487
|
+
await persistConversationHistory(
|
|
1488
|
+
key,
|
|
1489
|
+
currentConversationHistory
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
if (update.status?.state === "working" && update.status?.message && !update.final) {
|
|
1494
|
+
const allToolResults = extractToolResultsFromMessage(
|
|
1495
|
+
update.status.message
|
|
1496
|
+
);
|
|
1497
|
+
const currentToolResults = allToolResults.filter(
|
|
1498
|
+
(result) => currentToolCallIds.includes(
|
|
1499
|
+
result.data.toolCallId
|
|
1500
|
+
)
|
|
1501
|
+
);
|
|
1502
|
+
if (currentToolResults.length > 0) {
|
|
1503
|
+
const toolResultMessage = {
|
|
1504
|
+
role: "agent",
|
|
1505
|
+
kind: "message",
|
|
1506
|
+
parts: currentToolResults,
|
|
1507
|
+
messageId: generateMessageId()
|
|
1508
|
+
};
|
|
1509
|
+
currentConversationHistory = [
|
|
1510
|
+
...currentConversationHistory,
|
|
1511
|
+
extractNewContentFromMessage(toolResultMessage)
|
|
1512
|
+
];
|
|
1513
|
+
managedAgent.conversationHistory = currentConversationHistory;
|
|
1514
|
+
if (withHistory) {
|
|
1515
|
+
await persistConversationHistory(
|
|
1516
|
+
key,
|
|
1517
|
+
currentConversationHistory
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
if (update.final && update.status?.state !== "input-required") {
|
|
1523
|
+
currentToolCallIds = [];
|
|
1524
|
+
let finalAgentMessage = null;
|
|
1525
|
+
if (update.status?.message) {
|
|
1526
|
+
finalAgentMessage = extractNewContentFromMessage(
|
|
1527
|
+
update.status.message
|
|
1528
|
+
);
|
|
1529
|
+
currentConversationHistory = [
|
|
1530
|
+
...currentConversationHistory,
|
|
1531
|
+
finalAgentMessage
|
|
1532
|
+
];
|
|
1533
|
+
managedAgent.conversationHistory = currentConversationHistory;
|
|
1534
|
+
if (withHistory) {
|
|
1535
|
+
await persistConversationHistory(
|
|
1536
|
+
key,
|
|
1537
|
+
currentConversationHistory
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
yield update;
|
|
1543
|
+
}
|
|
1544
|
+
},
|
|
1545
|
+
async resetConversation(key) {
|
|
1546
|
+
const managedAgent = agents.get(key);
|
|
1547
|
+
if (!managedAgent) {
|
|
1548
|
+
throw new Error(`Agent with key "${key}" not found`);
|
|
1549
|
+
}
|
|
1550
|
+
managedAgent.conversationHistory = [];
|
|
1551
|
+
if (managedAgent.sessionId) {
|
|
1552
|
+
await clearConversation(
|
|
1553
|
+
managedAgent.sessionId,
|
|
1554
|
+
managedAgent.conversationStorageKey
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
},
|
|
1558
|
+
getConversationHistory(key) {
|
|
1559
|
+
const managedAgent = agents.get(key);
|
|
1560
|
+
if (!managedAgent) {
|
|
1561
|
+
throw new Error(`Agent with key "${key}" not found`);
|
|
1562
|
+
}
|
|
1563
|
+
return [...managedAgent.conversationHistory];
|
|
1564
|
+
},
|
|
1565
|
+
clear() {
|
|
1566
|
+
agents.clear();
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
var globalAgentManager = createAgentManager();
|
|
1571
|
+
function getAgentManager() {
|
|
1572
|
+
return globalAgentManager;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// src/utils/createMessageRenderer.tsx
|
|
1576
|
+
import Markdown from "react-markdown";
|
|
1577
|
+
|
|
1578
|
+
// src/markdown-extensions/index.ts
|
|
1579
|
+
import remarkGfm from "remark-gfm";
|
|
1580
|
+
function processMarkdownExtensions(extensions) {
|
|
1581
|
+
const components = {};
|
|
1582
|
+
const remarkPlugins = [];
|
|
1583
|
+
if (extensions?.charts?.enabled) {
|
|
1584
|
+
components.code = createChartBlock(extensions.charts.config);
|
|
1585
|
+
}
|
|
1586
|
+
if (extensions?.gfm?.enabled) {
|
|
1587
|
+
remarkPlugins.push(remarkGfm);
|
|
1588
|
+
}
|
|
1589
|
+
return { components, remarkPlugins };
|
|
1590
|
+
}
|
|
1591
|
+
function mergeMarkdownComponents(extensionComponents, userComponents = {}) {
|
|
1592
|
+
return {
|
|
1593
|
+
...extensionComponents,
|
|
1594
|
+
...userComponents
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
// src/utils/createMessageRenderer.tsx
|
|
1599
|
+
import { jsx } from "react/jsx-runtime";
|
|
1600
|
+
function createMessageRenderer(options = {}) {
|
|
1601
|
+
const { components = {}, extensions = {}, remarkPlugins = [] } = options;
|
|
1602
|
+
const processed = processMarkdownExtensions(extensions);
|
|
1603
|
+
const finalComponents = mergeMarkdownComponents(
|
|
1604
|
+
processed.components,
|
|
1605
|
+
components
|
|
1606
|
+
);
|
|
1607
|
+
const finalPlugins = [...processed.remarkPlugins, ...remarkPlugins];
|
|
1608
|
+
return function MessageRenderer({ children }) {
|
|
1609
|
+
return /* @__PURE__ */ jsx(
|
|
1610
|
+
Markdown,
|
|
1611
|
+
{
|
|
1612
|
+
components: finalComponents,
|
|
1613
|
+
remarkPlugins: finalPlugins,
|
|
1614
|
+
children
|
|
1615
|
+
}
|
|
1616
|
+
);
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// src/message-actions/useMessageActions.ts
|
|
1621
|
+
import { useCallback as useCallback2, useState } from "react";
|
|
1622
|
+
|
|
1623
|
+
// src/message-actions/factories.tsx
|
|
1624
|
+
var createFeedbackActions = (config) => {
|
|
1625
|
+
const baseCondition = config.condition || (() => true);
|
|
1626
|
+
const feedbackByMessageId = {};
|
|
1627
|
+
const changeListeners = [];
|
|
1628
|
+
const notifyListeners = () => {
|
|
1629
|
+
changeListeners.forEach((listener) => listener());
|
|
1630
|
+
};
|
|
1631
|
+
const handleFeedback = async (messageId, feedback) => {
|
|
1632
|
+
feedbackByMessageId[messageId] = feedback;
|
|
1633
|
+
await config.onFeedback(messageId, feedback);
|
|
1634
|
+
notifyListeners();
|
|
1635
|
+
};
|
|
1636
|
+
return {
|
|
1637
|
+
getActionsForMessage: (message) => {
|
|
1638
|
+
if (!baseCondition(message)) {
|
|
1639
|
+
return [];
|
|
1640
|
+
}
|
|
1641
|
+
const feedbackState = feedbackByMessageId[message.id];
|
|
1642
|
+
const actions = [];
|
|
1643
|
+
if (feedbackState !== "down") {
|
|
1644
|
+
actions.push({
|
|
1645
|
+
id: "feedback-up",
|
|
1646
|
+
icon: config.icons.up,
|
|
1647
|
+
label: "Good response",
|
|
1648
|
+
onClick: async () => {
|
|
1649
|
+
await handleFeedback(message.id, "up");
|
|
1650
|
+
},
|
|
1651
|
+
tooltip: "This response was helpful",
|
|
1652
|
+
disabled: feedbackState === "up"
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
if (feedbackState !== "up") {
|
|
1656
|
+
actions.push({
|
|
1657
|
+
id: "feedback-down",
|
|
1658
|
+
icon: config.icons.down,
|
|
1659
|
+
label: "Bad response",
|
|
1660
|
+
onClick: async () => {
|
|
1661
|
+
await handleFeedback(message.id, "down");
|
|
1662
|
+
},
|
|
1663
|
+
tooltip: "This response was not helpful",
|
|
1664
|
+
disabled: feedbackState === "down"
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
return actions;
|
|
1668
|
+
},
|
|
1669
|
+
clearFeedback: (messageId) => {
|
|
1670
|
+
delete feedbackByMessageId[messageId];
|
|
1671
|
+
notifyListeners();
|
|
1672
|
+
},
|
|
1673
|
+
clearAllFeedback: () => {
|
|
1674
|
+
Object.keys(feedbackByMessageId).forEach((key) => {
|
|
1675
|
+
delete feedbackByMessageId[key];
|
|
1676
|
+
});
|
|
1677
|
+
notifyListeners();
|
|
1678
|
+
},
|
|
1679
|
+
onChange: (listener) => {
|
|
1680
|
+
changeListeners.push(listener);
|
|
1681
|
+
},
|
|
1682
|
+
offChange: (listener) => {
|
|
1683
|
+
const index = changeListeners.indexOf(listener);
|
|
1684
|
+
if (index > -1) {
|
|
1685
|
+
changeListeners.splice(index, 1);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
};
|
|
1690
|
+
|
|
1691
|
+
// src/message-actions/useMessageActions.ts
|
|
1692
|
+
function useMessageActions() {
|
|
1693
|
+
const [registrations, setRegistrations] = useState([]);
|
|
1694
|
+
const registerMessageActions = useCallback2(
|
|
1695
|
+
(registration) => {
|
|
1696
|
+
setRegistrations((prev) => {
|
|
1697
|
+
const existingIndex = prev.findIndex(
|
|
1698
|
+
(r) => r.id === registration.id
|
|
1699
|
+
);
|
|
1700
|
+
if (existingIndex >= 0) {
|
|
1701
|
+
const updated = [...prev];
|
|
1702
|
+
updated[existingIndex] = registration;
|
|
1703
|
+
return updated;
|
|
1704
|
+
}
|
|
1705
|
+
return [...prev, registration];
|
|
1706
|
+
});
|
|
1707
|
+
},
|
|
1708
|
+
[]
|
|
1709
|
+
);
|
|
1710
|
+
const unregisterMessageActions = useCallback2((id) => {
|
|
1711
|
+
setRegistrations((prev) => prev.filter((r) => r.id !== id));
|
|
1712
|
+
}, []);
|
|
1713
|
+
const clearAllMessageActions = useCallback2(() => {
|
|
1714
|
+
setRegistrations([]);
|
|
1715
|
+
}, []);
|
|
1716
|
+
return {
|
|
1717
|
+
registerMessageActions,
|
|
1718
|
+
unregisterMessageActions,
|
|
1719
|
+
clearAllMessageActions,
|
|
1720
|
+
createFeedbackActions,
|
|
1721
|
+
registrations
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// src/message-actions/resolver.ts
|
|
1726
|
+
function resolveActionsForMessage(message, registrations) {
|
|
1727
|
+
const allActions = registrations.flatMap((reg) => {
|
|
1728
|
+
if (typeof reg.actions === "function") {
|
|
1729
|
+
return reg.actions(message);
|
|
1730
|
+
}
|
|
1731
|
+
return reg.actions;
|
|
1732
|
+
});
|
|
1733
|
+
const filteredActions = allActions.filter((action) => {
|
|
1734
|
+
if (action.condition && !action.condition(message)) {
|
|
1735
|
+
return false;
|
|
1736
|
+
}
|
|
1737
|
+
return true;
|
|
1738
|
+
}).map((action) => ({
|
|
1739
|
+
id: action.id,
|
|
1740
|
+
label: action.label,
|
|
1741
|
+
icon: action.icon,
|
|
1742
|
+
onClick: action.onClick,
|
|
1743
|
+
tooltip: action.tooltip,
|
|
1744
|
+
disabled: action.disabled || false
|
|
1745
|
+
}));
|
|
1746
|
+
return filteredActions;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// src/react/useAgentChat.ts
|
|
1750
|
+
var sortUIMessagesByTime = (messages) => {
|
|
1751
|
+
return [...messages].sort((a, b) => a.timestamp - b.timestamp);
|
|
1752
|
+
};
|
|
1753
|
+
var transformClientMessageToUI = (clientMessage, messageActionsRegistrations = []) => {
|
|
1754
|
+
const hasToolContent = clientMessage.parts.some((part) => {
|
|
1755
|
+
if (part.type === "data") {
|
|
1756
|
+
const data = part.data;
|
|
1757
|
+
return data.toolCallId || data.toolId || data.result;
|
|
1758
|
+
}
|
|
1759
|
+
return false;
|
|
1760
|
+
});
|
|
1761
|
+
if (hasToolContent) {
|
|
1762
|
+
return null;
|
|
1763
|
+
}
|
|
1764
|
+
const content = clientMessage.parts.map((part) => {
|
|
1765
|
+
if (part.type === "text") {
|
|
1766
|
+
return {
|
|
1767
|
+
type: "text",
|
|
1768
|
+
text: part.text
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
if (part.type === "file") {
|
|
1772
|
+
return {
|
|
1773
|
+
type: "image_url",
|
|
1774
|
+
image_url: part.file.uri || `data:${part.file.mimeType};base64,${part.file.bytes}`
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
if (part.type === "data") {
|
|
1778
|
+
const data = part.data;
|
|
1779
|
+
if (data.component && data.componentProps) {
|
|
1780
|
+
return {
|
|
1781
|
+
type: "component",
|
|
1782
|
+
component: data.component,
|
|
1783
|
+
componentProps: data.componentProps
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
return {
|
|
1787
|
+
type: "text",
|
|
1788
|
+
text: JSON.stringify(data)
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
return {
|
|
1792
|
+
type: "text",
|
|
1793
|
+
text: "[Unsupported content]"
|
|
1794
|
+
};
|
|
1795
|
+
});
|
|
1796
|
+
const timestamp = clientMessage.metadata?.timestamp ?? Date.now();
|
|
1797
|
+
const uiMessage = {
|
|
1798
|
+
id: clientMessage.messageId,
|
|
1799
|
+
role: clientMessage.role === "agent" ? "agent" : "user",
|
|
1800
|
+
content,
|
|
1801
|
+
timestamp,
|
|
1802
|
+
archived: false,
|
|
1803
|
+
showIcon: clientMessage.role === "agent",
|
|
1804
|
+
icon: clientMessage.role === "agent" ? "assistant" : void 0
|
|
1805
|
+
};
|
|
1806
|
+
if (clientMessage.role === "agent" && messageActionsRegistrations.length > 0) {
|
|
1807
|
+
const resolvedActions = resolveActionsForMessage(
|
|
1808
|
+
uiMessage,
|
|
1809
|
+
messageActionsRegistrations
|
|
1810
|
+
);
|
|
1811
|
+
if (resolvedActions.length > 0) {
|
|
1812
|
+
uiMessage.actions = resolvedActions;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return uiMessage;
|
|
1816
|
+
};
|
|
1817
|
+
var createNoOpContextProvider = () => ({
|
|
1818
|
+
getClientContext: () => ({})
|
|
1819
|
+
});
|
|
1820
|
+
var createNoOpToolProvider = () => ({
|
|
1821
|
+
getAvailableTools: async () => [],
|
|
1822
|
+
executeTool: async () => ({
|
|
1823
|
+
success: true,
|
|
1824
|
+
result: "No tools available"
|
|
1825
|
+
})
|
|
1826
|
+
});
|
|
1827
|
+
var validateAgentConfig = (config) => {
|
|
1828
|
+
const required = ["agentId", "agentUrl", "sessionId"];
|
|
1829
|
+
return required.every((key) => {
|
|
1830
|
+
const value = config[key];
|
|
1831
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1832
|
+
});
|
|
1833
|
+
};
|
|
1834
|
+
function useAgentChat(config) {
|
|
1835
|
+
const agentConfig = {
|
|
1836
|
+
agentId: config.agentId,
|
|
1837
|
+
agentUrl: config.agentUrl,
|
|
1838
|
+
sessionId: config.sessionId
|
|
1839
|
+
};
|
|
1840
|
+
const isValidConfig = validateAgentConfig(agentConfig);
|
|
1841
|
+
const [state, setState] = useState2({
|
|
1842
|
+
clientMessages: [],
|
|
1843
|
+
uiMessages: [],
|
|
1844
|
+
isProcessing: false,
|
|
1845
|
+
error: isValidConfig ? null : "Invalid agent configuration",
|
|
1846
|
+
suggestions: [],
|
|
1847
|
+
markdownComponents: {},
|
|
1848
|
+
markdownExtensions: {}
|
|
1849
|
+
});
|
|
1850
|
+
const {
|
|
1851
|
+
registerMessageActions,
|
|
1852
|
+
unregisterMessageActions,
|
|
1853
|
+
clearAllMessageActions,
|
|
1854
|
+
createFeedbackActions: createFeedbackActions2,
|
|
1855
|
+
registrations
|
|
1856
|
+
} = useMessageActions();
|
|
1857
|
+
const registrationsRef = useRef(registrations);
|
|
1858
|
+
useEffect(() => {
|
|
1859
|
+
registrationsRef.current = registrations;
|
|
1860
|
+
}, [registrations]);
|
|
1861
|
+
useEffect(() => {
|
|
1862
|
+
if (!isValidConfig) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
const initializeAgent = async () => {
|
|
1866
|
+
if (agentConfig.sessionId) {
|
|
1867
|
+
const agentManager = getAgentManager();
|
|
1868
|
+
const agentKey = `${agentConfig.agentId}-${agentConfig.sessionId}`;
|
|
1869
|
+
if (!agentManager.hasAgent(agentKey)) {
|
|
1870
|
+
await agentManager.createAgent(agentKey, {
|
|
1871
|
+
agentId: agentConfig.agentId,
|
|
1872
|
+
agentUrl: agentConfig.agentUrl,
|
|
1873
|
+
sessionId: agentConfig.sessionId,
|
|
1874
|
+
contextProvider: config.contextProvider || createNoOpContextProvider(),
|
|
1875
|
+
toolProvider: config.toolProvider || createNoOpToolProvider(),
|
|
1876
|
+
authProvider: config.authProvider
|
|
1877
|
+
});
|
|
1878
|
+
const clientHistory = agentManager.getConversationHistory(agentKey);
|
|
1879
|
+
setState((prev) => {
|
|
1880
|
+
const uiHistory = clientHistory.map(
|
|
1881
|
+
(msg) => transformClientMessageToUI(
|
|
1882
|
+
msg,
|
|
1883
|
+
registrationsRef.current
|
|
1884
|
+
)
|
|
1885
|
+
).filter(
|
|
1886
|
+
(msg) => msg !== null
|
|
1887
|
+
);
|
|
1888
|
+
return {
|
|
1889
|
+
...prev,
|
|
1890
|
+
clientMessages: clientHistory,
|
|
1891
|
+
uiMessages: uiHistory
|
|
1892
|
+
};
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
initializeAgent();
|
|
1898
|
+
}, [
|
|
1899
|
+
agentConfig.sessionId,
|
|
1900
|
+
agentConfig.agentId,
|
|
1901
|
+
agentConfig.agentUrl,
|
|
1902
|
+
config.contextProvider,
|
|
1903
|
+
config.toolProvider,
|
|
1904
|
+
config.authProvider,
|
|
1905
|
+
isValidConfig
|
|
1906
|
+
]);
|
|
1907
|
+
const onSubmit = useCallback3(
|
|
1908
|
+
async (message) => {
|
|
1909
|
+
if (!isValidConfig) {
|
|
1910
|
+
throw new Error("Invalid agent configuration");
|
|
1911
|
+
}
|
|
1912
|
+
const agentManager = getAgentManager();
|
|
1913
|
+
const agentKey = `${agentConfig.agentId}-${agentConfig.sessionId}`;
|
|
1914
|
+
const messageTimestamp = Date.now();
|
|
1915
|
+
const userMessage = {
|
|
1916
|
+
id: `user-${messageTimestamp}`,
|
|
1917
|
+
role: "user",
|
|
1918
|
+
content: [{ type: "text", text: message }],
|
|
1919
|
+
timestamp: messageTimestamp,
|
|
1920
|
+
archived: false,
|
|
1921
|
+
showIcon: false
|
|
1922
|
+
};
|
|
1923
|
+
setState((prev) => ({
|
|
1924
|
+
...prev,
|
|
1925
|
+
uiMessages: [...prev.uiMessages, userMessage],
|
|
1926
|
+
isProcessing: true,
|
|
1927
|
+
error: null
|
|
1928
|
+
}));
|
|
1929
|
+
try {
|
|
1930
|
+
let lastUpdate = null;
|
|
1931
|
+
for await (const update of agentManager.sendMessageStream(
|
|
1932
|
+
agentKey,
|
|
1933
|
+
message
|
|
1934
|
+
)) {
|
|
1935
|
+
lastUpdate = update;
|
|
1936
|
+
}
|
|
1937
|
+
const updatedClientHistory = agentManager.getConversationHistory(agentKey);
|
|
1938
|
+
setState((prev) => {
|
|
1939
|
+
const transformedClientMessages = updatedClientHistory.map(
|
|
1940
|
+
(msg) => transformClientMessageToUI(
|
|
1941
|
+
msg,
|
|
1942
|
+
registrationsRef.current
|
|
1943
|
+
)
|
|
1944
|
+
).filter((msg) => msg !== null);
|
|
1945
|
+
const clientMessageIds = new Set(
|
|
1946
|
+
updatedClientHistory.map((msg) => msg.messageId)
|
|
1947
|
+
);
|
|
1948
|
+
const uiOnlyMessages = prev.uiMessages.filter(
|
|
1949
|
+
(msg) => !clientMessageIds.has(msg.id) && msg.content[0]?.type === "component"
|
|
1950
|
+
);
|
|
1951
|
+
const mergedUIMessages = sortUIMessagesByTime([
|
|
1952
|
+
...transformedClientMessages,
|
|
1953
|
+
...uiOnlyMessages
|
|
1954
|
+
]);
|
|
1955
|
+
return {
|
|
1956
|
+
...prev,
|
|
1957
|
+
clientMessages: updatedClientHistory,
|
|
1958
|
+
uiMessages: mergedUIMessages,
|
|
1959
|
+
isProcessing: false
|
|
1960
|
+
};
|
|
1961
|
+
});
|
|
1962
|
+
} catch (error) {
|
|
1963
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to send message";
|
|
1964
|
+
setState((prev) => ({
|
|
1965
|
+
...prev,
|
|
1966
|
+
isProcessing: false,
|
|
1967
|
+
error: errorMessage
|
|
1968
|
+
}));
|
|
1969
|
+
throw error;
|
|
1970
|
+
}
|
|
1971
|
+
},
|
|
1972
|
+
[agentConfig.agentId, agentConfig.sessionId, isValidConfig]
|
|
1973
|
+
);
|
|
1974
|
+
const addMessage = useCallback3((message) => {
|
|
1975
|
+
setState((prev) => ({
|
|
1976
|
+
...prev,
|
|
1977
|
+
uiMessages: sortUIMessagesByTime([...prev.uiMessages, message])
|
|
1978
|
+
}));
|
|
1979
|
+
}, []);
|
|
1980
|
+
const registerSuggestions = useCallback3((suggestions) => {
|
|
1981
|
+
setState((prev) => ({
|
|
1982
|
+
...prev,
|
|
1983
|
+
suggestions
|
|
1984
|
+
}));
|
|
1985
|
+
}, []);
|
|
1986
|
+
const clearSuggestions = useCallback3(() => {
|
|
1987
|
+
setState((prev) => ({
|
|
1988
|
+
...prev,
|
|
1989
|
+
suggestions: []
|
|
1990
|
+
}));
|
|
1991
|
+
}, []);
|
|
1992
|
+
const registerMarkdownComponents = useCallback3(
|
|
1993
|
+
(components) => {
|
|
1994
|
+
setState((prev) => {
|
|
1995
|
+
const updatedComponents = {
|
|
1996
|
+
...prev.markdownComponents,
|
|
1997
|
+
...components
|
|
1998
|
+
};
|
|
1999
|
+
const updatedUIMessages = prev.clientMessages.map(
|
|
2000
|
+
(msg) => transformClientMessageToUI(
|
|
2001
|
+
msg,
|
|
2002
|
+
registrationsRef.current
|
|
2003
|
+
)
|
|
2004
|
+
).filter((msg) => msg !== null);
|
|
2005
|
+
const clientMessageIds = new Set(
|
|
2006
|
+
prev.clientMessages.map((msg) => msg.messageId)
|
|
2007
|
+
);
|
|
2008
|
+
const uiOnlyMessages = prev.uiMessages.filter(
|
|
2009
|
+
(msg) => !clientMessageIds.has(msg.id) && msg.content[0]?.type === "component"
|
|
2010
|
+
);
|
|
2011
|
+
const mergedUIMessages = sortUIMessagesByTime([
|
|
2012
|
+
...updatedUIMessages,
|
|
2013
|
+
...uiOnlyMessages
|
|
2014
|
+
]);
|
|
2015
|
+
return {
|
|
2016
|
+
...prev,
|
|
2017
|
+
markdownComponents: updatedComponents,
|
|
2018
|
+
uiMessages: mergedUIMessages
|
|
2019
|
+
};
|
|
2020
|
+
});
|
|
2021
|
+
},
|
|
2022
|
+
[]
|
|
2023
|
+
);
|
|
2024
|
+
const registerMarkdownExtensions = useCallback3(
|
|
2025
|
+
(extensions) => {
|
|
2026
|
+
setState((prev) => {
|
|
2027
|
+
const updatedExtensions = {
|
|
2028
|
+
...prev.markdownExtensions,
|
|
2029
|
+
...extensions
|
|
2030
|
+
};
|
|
2031
|
+
const updatedUIMessages = prev.clientMessages.map(
|
|
2032
|
+
(msg) => transformClientMessageToUI(
|
|
2033
|
+
msg,
|
|
2034
|
+
registrationsRef.current
|
|
2035
|
+
)
|
|
2036
|
+
).filter((msg) => msg !== null);
|
|
2037
|
+
const clientMessageIds = new Set(
|
|
2038
|
+
prev.clientMessages.map((msg) => msg.messageId)
|
|
2039
|
+
);
|
|
2040
|
+
const uiOnlyMessages = prev.uiMessages.filter(
|
|
2041
|
+
(msg) => !clientMessageIds.has(msg.id) && msg.content[0]?.type === "component"
|
|
2042
|
+
);
|
|
2043
|
+
const mergedUIMessages = sortUIMessagesByTime([
|
|
2044
|
+
...updatedUIMessages,
|
|
2045
|
+
...uiOnlyMessages
|
|
2046
|
+
]);
|
|
2047
|
+
return {
|
|
2048
|
+
...prev,
|
|
2049
|
+
markdownExtensions: updatedExtensions,
|
|
2050
|
+
uiMessages: mergedUIMessages
|
|
2051
|
+
};
|
|
2052
|
+
});
|
|
2053
|
+
},
|
|
2054
|
+
[]
|
|
2055
|
+
);
|
|
2056
|
+
useEffect(() => {
|
|
2057
|
+
setState((prev) => {
|
|
2058
|
+
if (prev.clientMessages.length === 0) {
|
|
2059
|
+
return prev;
|
|
2060
|
+
}
|
|
2061
|
+
const updatedUIMessages = prev.clientMessages.map(
|
|
2062
|
+
(msg) => transformClientMessageToUI(msg, registrationsRef.current)
|
|
2063
|
+
).filter((msg) => msg !== null);
|
|
2064
|
+
const clientMessageIds = new Set(
|
|
2065
|
+
prev.clientMessages.map((msg) => msg.messageId)
|
|
2066
|
+
);
|
|
2067
|
+
const uiOnlyMessages = prev.uiMessages.filter(
|
|
2068
|
+
(msg) => !clientMessageIds.has(msg.id) && msg.content[0]?.type === "component"
|
|
2069
|
+
);
|
|
2070
|
+
return {
|
|
2071
|
+
...prev,
|
|
2072
|
+
uiMessages: sortUIMessagesByTime([
|
|
2073
|
+
...updatedUIMessages,
|
|
2074
|
+
...uiOnlyMessages
|
|
2075
|
+
])
|
|
2076
|
+
};
|
|
2077
|
+
});
|
|
2078
|
+
}, [registrations]);
|
|
2079
|
+
const messageRenderer = useMemo3(
|
|
2080
|
+
() => createMessageRenderer({
|
|
2081
|
+
components: state.markdownComponents,
|
|
2082
|
+
extensions: state.markdownExtensions
|
|
2083
|
+
}),
|
|
2084
|
+
[state.markdownComponents, state.markdownExtensions]
|
|
2085
|
+
);
|
|
2086
|
+
return {
|
|
2087
|
+
// AgentUI props
|
|
2088
|
+
messages: state.uiMessages,
|
|
2089
|
+
isProcessing: state.isProcessing,
|
|
2090
|
+
error: state.error,
|
|
2091
|
+
onSubmit,
|
|
2092
|
+
suggestions: state.suggestions,
|
|
2093
|
+
messageRenderer,
|
|
2094
|
+
// UI management methods
|
|
2095
|
+
registerSuggestions,
|
|
2096
|
+
clearSuggestions,
|
|
2097
|
+
registerMarkdownComponents,
|
|
2098
|
+
registerMarkdownExtensions,
|
|
2099
|
+
// Message actions methods
|
|
2100
|
+
registerMessageActions,
|
|
2101
|
+
unregisterMessageActions,
|
|
2102
|
+
clearAllMessageActions,
|
|
2103
|
+
createFeedbackActions: createFeedbackActions2,
|
|
2104
|
+
// Tool integration
|
|
2105
|
+
addMessage
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// src/client/types/index.ts
|
|
2110
|
+
var A2AErrorCodes = /* @__PURE__ */ ((A2AErrorCodes2) => {
|
|
2111
|
+
A2AErrorCodes2[A2AErrorCodes2["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
|
|
2112
|
+
A2AErrorCodes2[A2AErrorCodes2["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
|
|
2113
|
+
A2AErrorCodes2[A2AErrorCodes2["METHOD_NOT_FOUND"] = -32601] = "METHOD_NOT_FOUND";
|
|
2114
|
+
A2AErrorCodes2[A2AErrorCodes2["INVALID_PARAMS"] = -32602] = "INVALID_PARAMS";
|
|
2115
|
+
A2AErrorCodes2[A2AErrorCodes2["INTERNAL_ERROR"] = -32603] = "INTERNAL_ERROR";
|
|
2116
|
+
A2AErrorCodes2[A2AErrorCodes2["SERVER_ERROR"] = -32e3] = "SERVER_ERROR";
|
|
2117
|
+
return A2AErrorCodes2;
|
|
2118
|
+
})(A2AErrorCodes || {});
|
|
2119
|
+
export {
|
|
2120
|
+
A2AErrorCodes,
|
|
2121
|
+
BarChart,
|
|
2122
|
+
ChartBlock,
|
|
2123
|
+
LineChart,
|
|
2124
|
+
createClient,
|
|
2125
|
+
createFeedbackActions,
|
|
2126
|
+
createMessageRenderer,
|
|
2127
|
+
createRequestId,
|
|
2128
|
+
createTaskId,
|
|
2129
|
+
createTextMessage,
|
|
2130
|
+
extractTextFromMessage,
|
|
2131
|
+
extractToolCallsFromMessage,
|
|
2132
|
+
getAgentManager,
|
|
2133
|
+
useAgentChat,
|
|
2134
|
+
useClientContext,
|
|
2135
|
+
useClientTools,
|
|
2136
|
+
useMessageActions
|
|
2137
|
+
};
|