@automattic/agenttic-client 0.1.9 → 0.1.11
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 +53 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types/index.d.ts +6 -1
- package/dist/client/types/index.d.ts.map +1 -1
- package/dist/client/utils/core.d.ts +7 -1
- package/dist/client/utils/core.d.ts.map +1 -1
- package/dist/client/utils/index.d.ts +1 -1
- package/dist/client/utils/index.d.ts.map +1 -1
- package/dist/client/utils/internal/requests.d.ts +5 -2
- package/dist/client/utils/internal/requests.d.ts.map +1 -1
- package/dist/client/utils/internal/streaming.d.ts +63 -3
- package/dist/client/utils/internal/streaming.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +540 -98
- package/dist/message-actions/factories.d.ts.map +1 -1
- package/dist/message-actions/resolver.d.ts.map +1 -1
- package/dist/react/agentManager.d.ts.map +1 -1
- package/dist/react/useAgentChat.d.ts +8 -2
- package/dist/react/useAgentChat.d.ts.map +1 -1
- package/dist/utils/markdownParser.d.ts +2 -2
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -113,8 +113,8 @@ function createTextPart(text) {
|
|
|
113
113
|
text
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
|
-
function createSendMessageRequest(params, method = "message/send") {
|
|
117
|
-
|
|
116
|
+
function createSendMessageRequest(params, method = "message/send", tokenStreaming = false) {
|
|
117
|
+
const request = {
|
|
118
118
|
jsonrpc: "2.0",
|
|
119
119
|
id: createRequestId(),
|
|
120
120
|
method,
|
|
@@ -123,6 +123,10 @@ function createSendMessageRequest(params, method = "message/send") {
|
|
|
123
123
|
...params
|
|
124
124
|
}
|
|
125
125
|
};
|
|
126
|
+
if (tokenStreaming && method === "message/stream") {
|
|
127
|
+
request.tokenStreaming = true;
|
|
128
|
+
}
|
|
129
|
+
return request;
|
|
126
130
|
}
|
|
127
131
|
function extractTextFromMessage(message) {
|
|
128
132
|
if (!message || !message.parts || !Array.isArray(message.parts)) {
|
|
@@ -218,6 +222,9 @@ function createToolResultMessage(toolResults, historyDataParts = []) {
|
|
|
218
222
|
}
|
|
219
223
|
};
|
|
220
224
|
}
|
|
225
|
+
function createAbortController() {
|
|
226
|
+
return new AbortController();
|
|
227
|
+
}
|
|
221
228
|
|
|
222
229
|
// src/client/utils/internal/messages.ts
|
|
223
230
|
async function enhanceMessageWithTools(message, toolProvider) {
|
|
@@ -312,10 +319,14 @@ function parseStreamChunk(chunk, buffer = "") {
|
|
|
312
319
|
const nextBuffer = currentStreamData.substring(lastCompleteEventEnd);
|
|
313
320
|
return { events, nextBuffer };
|
|
314
321
|
}
|
|
315
|
-
async function* parseSSEStream(stream) {
|
|
322
|
+
async function* parseSSEStream(stream, options = {}) {
|
|
323
|
+
const { supportDeltas = false } = options;
|
|
316
324
|
const reader = stream.getReader();
|
|
317
325
|
const decoder = new TextDecoder();
|
|
318
326
|
let buffer = "";
|
|
327
|
+
const accumulator = new DeltaAccumulator();
|
|
328
|
+
let currentTaskId = null;
|
|
329
|
+
let lastStatus = null;
|
|
319
330
|
try {
|
|
320
331
|
while (true) {
|
|
321
332
|
const { done, value } = await reader.read();
|
|
@@ -325,13 +336,50 @@ async function* parseSSEStream(stream) {
|
|
|
325
336
|
const chunk = decoder.decode(value, { stream: true });
|
|
326
337
|
const { events, nextBuffer } = parseStreamChunk(chunk, buffer);
|
|
327
338
|
if (events && Array.isArray(events)) {
|
|
328
|
-
for (
|
|
339
|
+
for (let i = 0; i < events.length; i++) {
|
|
340
|
+
const event = events[i];
|
|
341
|
+
if (i > 0 && event.method === "message/delta" && typeof requestAnimationFrame !== "undefined") {
|
|
342
|
+
await new Promise((resolve) => {
|
|
343
|
+
requestAnimationFrame(() => resolve(void 0));
|
|
344
|
+
});
|
|
345
|
+
}
|
|
329
346
|
if (event.error) {
|
|
330
347
|
throw new Error(
|
|
331
348
|
`Streaming error: ${event.error.message}`
|
|
332
349
|
);
|
|
333
350
|
}
|
|
334
|
-
if (event.
|
|
351
|
+
if (supportDeltas && event.method === "message/delta" && event.params?.delta) {
|
|
352
|
+
const delta = event.params.delta;
|
|
353
|
+
try {
|
|
354
|
+
if (delta.deltaType === "content") {
|
|
355
|
+
accumulator.processContentDelta(
|
|
356
|
+
delta.content
|
|
357
|
+
);
|
|
358
|
+
if (!currentTaskId && event.params.id) {
|
|
359
|
+
currentTaskId = event.params.id;
|
|
360
|
+
}
|
|
361
|
+
if (currentTaskId) {
|
|
362
|
+
const currentMessage = accumulator.getCurrentMessage();
|
|
363
|
+
yield {
|
|
364
|
+
id: currentTaskId,
|
|
365
|
+
status: {
|
|
366
|
+
state: "working",
|
|
367
|
+
message: currentMessage
|
|
368
|
+
},
|
|
369
|
+
final: false,
|
|
370
|
+
text: accumulator.getTextContent()
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
} catch (error) {
|
|
375
|
+
logger("Failed to process delta: %o", error);
|
|
376
|
+
}
|
|
377
|
+
} else if (event.result && event.result.status) {
|
|
378
|
+
currentTaskId = event.result.id;
|
|
379
|
+
lastStatus = event.result.status;
|
|
380
|
+
if (accumulator.getTextContent() || accumulator.getCurrentMessage().parts.length > 0) {
|
|
381
|
+
accumulator.reset();
|
|
382
|
+
}
|
|
335
383
|
const update = {
|
|
336
384
|
id: event.result.id,
|
|
337
385
|
status: event.result.status,
|
|
@@ -344,6 +392,22 @@ async function* parseSSEStream(stream) {
|
|
|
344
392
|
)
|
|
345
393
|
};
|
|
346
394
|
yield update;
|
|
395
|
+
} else if (event.id && event.result) {
|
|
396
|
+
currentTaskId = event.result.id;
|
|
397
|
+
if (event.result.status) {
|
|
398
|
+
const update = {
|
|
399
|
+
id: event.result.id,
|
|
400
|
+
status: event.result.status,
|
|
401
|
+
final: event.result.status.state === "completed" || event.result.status.state === "failed" || event.result.status.state === "canceled",
|
|
402
|
+
text: extractTextFromMessage(
|
|
403
|
+
event.result.status?.message || {
|
|
404
|
+
role: "agent",
|
|
405
|
+
parts: []
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
};
|
|
409
|
+
yield update;
|
|
410
|
+
}
|
|
347
411
|
}
|
|
348
412
|
}
|
|
349
413
|
}
|
|
@@ -353,6 +417,103 @@ async function* parseSSEStream(stream) {
|
|
|
353
417
|
reader.releaseLock();
|
|
354
418
|
}
|
|
355
419
|
}
|
|
420
|
+
var DeltaAccumulator = class {
|
|
421
|
+
textContent = "";
|
|
422
|
+
toolCalls = /* @__PURE__ */ new Map();
|
|
423
|
+
/**
|
|
424
|
+
* Process a simple content delta (server's actual format)
|
|
425
|
+
* @param content - The text content to append
|
|
426
|
+
*/
|
|
427
|
+
processContentDelta(content) {
|
|
428
|
+
this.textContent += content;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Process a delta message and accumulate the content (original format)
|
|
432
|
+
* @param delta - The delta message to process
|
|
433
|
+
*/
|
|
434
|
+
processDelta(delta) {
|
|
435
|
+
switch (delta.type) {
|
|
436
|
+
case "content":
|
|
437
|
+
this.textContent += delta.content;
|
|
438
|
+
break;
|
|
439
|
+
case "tool_name":
|
|
440
|
+
if (!this.toolCalls.has(delta.toolCallIndex)) {
|
|
441
|
+
this.toolCalls.set(delta.toolCallIndex, {
|
|
442
|
+
toolCallId: delta.toolCallId,
|
|
443
|
+
toolName: "",
|
|
444
|
+
argumentFragments: []
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
const toolCall = this.toolCalls.get(delta.toolCallIndex);
|
|
448
|
+
toolCall.toolName += delta.content;
|
|
449
|
+
break;
|
|
450
|
+
case "tool_argument":
|
|
451
|
+
if (!this.toolCalls.has(delta.toolCallIndex)) {
|
|
452
|
+
this.toolCalls.set(delta.toolCallIndex, {
|
|
453
|
+
toolCallId: delta.toolCallId,
|
|
454
|
+
toolName: "",
|
|
455
|
+
argumentFragments: []
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
const call = this.toolCalls.get(delta.toolCallIndex);
|
|
459
|
+
call.argumentFragments.push(delta.content);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get the accumulated text content
|
|
465
|
+
*/
|
|
466
|
+
getTextContent() {
|
|
467
|
+
return this.textContent;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Get the current accumulated message
|
|
471
|
+
* @param role - The role for the message (default: 'agent')
|
|
472
|
+
*/
|
|
473
|
+
getCurrentMessage(role = "agent") {
|
|
474
|
+
const parts = [];
|
|
475
|
+
if (this.textContent) {
|
|
476
|
+
parts.push({
|
|
477
|
+
type: "text",
|
|
478
|
+
text: this.textContent
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
for (const [index, toolCall] of this.toolCalls) {
|
|
482
|
+
if (toolCall.toolName) {
|
|
483
|
+
const argumentsStr = toolCall.argumentFragments.join("");
|
|
484
|
+
let args = {};
|
|
485
|
+
if (argumentsStr) {
|
|
486
|
+
try {
|
|
487
|
+
args = JSON.parse(argumentsStr);
|
|
488
|
+
} catch {
|
|
489
|
+
args = { _raw: argumentsStr };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
parts.push({
|
|
493
|
+
type: "data",
|
|
494
|
+
data: {
|
|
495
|
+
toolCallId: toolCall.toolCallId,
|
|
496
|
+
toolId: toolCall.toolName,
|
|
497
|
+
arguments: args
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
role,
|
|
504
|
+
parts,
|
|
505
|
+
kind: "message",
|
|
506
|
+
messageId: generateMessageId()
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Reset the accumulator
|
|
511
|
+
*/
|
|
512
|
+
reset() {
|
|
513
|
+
this.textContent = "";
|
|
514
|
+
this.toolCalls.clear();
|
|
515
|
+
}
|
|
516
|
+
};
|
|
356
517
|
|
|
357
518
|
// src/client/utils/internal/errors.ts
|
|
358
519
|
function handleRequestError(error, timeoutId, operation = "request") {
|
|
@@ -417,6 +578,32 @@ async function getHeaders(authProvider, isStreaming = false) {
|
|
|
417
578
|
}
|
|
418
579
|
return baseHeaders;
|
|
419
580
|
}
|
|
581
|
+
function combineSignals(signal1, signal2) {
|
|
582
|
+
if (!signal2) {
|
|
583
|
+
return signal1;
|
|
584
|
+
}
|
|
585
|
+
const controller = new AbortController();
|
|
586
|
+
const handleAbort = (signal) => {
|
|
587
|
+
if (!controller.signal.aborted) {
|
|
588
|
+
controller.abort(signal.reason);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
if (signal1.aborted) {
|
|
592
|
+
controller.abort(signal1.reason);
|
|
593
|
+
} else {
|
|
594
|
+
signal1.addEventListener("abort", () => handleAbort(signal1), {
|
|
595
|
+
once: true
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
if (signal2.aborted) {
|
|
599
|
+
controller.abort(signal2.reason);
|
|
600
|
+
} else {
|
|
601
|
+
signal2.addEventListener("abort", () => handleAbort(signal2), {
|
|
602
|
+
once: true
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
return controller.signal;
|
|
606
|
+
}
|
|
420
607
|
function createFetchOptions(headers, body, signal) {
|
|
421
608
|
return {
|
|
422
609
|
method: "POST",
|
|
@@ -428,7 +615,7 @@ function createFetchOptions(headers, body, signal) {
|
|
|
428
615
|
async function prepareRequest(params, config, options, toolProvider, contextProvider, defaultSessionId) {
|
|
429
616
|
const { message, sessionId, taskId, metadata } = params;
|
|
430
617
|
const { agentId, agentUrl, authProvider, proxy } = config;
|
|
431
|
-
const { isStreaming = false } = options;
|
|
618
|
+
const { isStreaming = false, enableTokenStreaming = false } = options;
|
|
432
619
|
const effectiveSessionId = sessionId || defaultSessionId;
|
|
433
620
|
const fullAgentUrl = constructAgentUrl(agentUrl, agentId);
|
|
434
621
|
const enhancedMessage = await enhanceMessage(
|
|
@@ -443,7 +630,9 @@ async function prepareRequest(params, config, options, toolProvider, contextProv
|
|
|
443
630
|
message: enhancedMessage,
|
|
444
631
|
metadata
|
|
445
632
|
},
|
|
446
|
-
isStreaming ? "message/stream" : "message/send"
|
|
633
|
+
isStreaming ? "message/stream" : "message/send",
|
|
634
|
+
enableTokenStreaming && isStreaming
|
|
635
|
+
// Only enable token streaming if using SSE
|
|
447
636
|
);
|
|
448
637
|
const headers = await getHeaders(authProvider, isStreaming);
|
|
449
638
|
logRequest("POST", fullAgentUrl, headers, request);
|
|
@@ -455,24 +644,26 @@ async function prepareRequest(params, config, options, toolProvider, contextProv
|
|
|
455
644
|
fullAgentUrl
|
|
456
645
|
};
|
|
457
646
|
}
|
|
458
|
-
async function executeRequest(preparedRequest, config) {
|
|
647
|
+
async function executeRequest(preparedRequest, config, options = {}) {
|
|
459
648
|
const { request, headers, fullAgentUrl } = preparedRequest;
|
|
460
649
|
const { timeout } = config;
|
|
461
|
-
const {
|
|
650
|
+
const { abortSignal: externalSignal } = options;
|
|
651
|
+
const { timeoutId, controller: timeoutController } = createTimeoutHandler(
|
|
462
652
|
timeout,
|
|
463
653
|
"request"
|
|
464
654
|
);
|
|
655
|
+
const signal = externalSignal ? combineSignals(timeoutController.signal, externalSignal) : timeoutController.signal;
|
|
465
656
|
try {
|
|
466
|
-
const
|
|
657
|
+
const fetchOptions = createFetchOptions(
|
|
467
658
|
headers,
|
|
468
659
|
JSON.stringify(request),
|
|
469
|
-
|
|
660
|
+
signal
|
|
470
661
|
);
|
|
471
662
|
logger("Making request to %s with options: %O", fullAgentUrl, {
|
|
472
|
-
method:
|
|
473
|
-
headers:
|
|
663
|
+
method: fetchOptions.method,
|
|
664
|
+
headers: fetchOptions.headers
|
|
474
665
|
});
|
|
475
|
-
const response = await fetch(fullAgentUrl,
|
|
666
|
+
const response = await fetch(fullAgentUrl, fetchOptions);
|
|
476
667
|
clearTimeout(timeoutId);
|
|
477
668
|
validateHttpResponse(response, "request");
|
|
478
669
|
const data = await response.json();
|
|
@@ -490,21 +681,31 @@ async function executeRequest(preparedRequest, config) {
|
|
|
490
681
|
async function* executeStreamingRequest(preparedRequest, config, options) {
|
|
491
682
|
const { request, headers, fullAgentUrl } = preparedRequest;
|
|
492
683
|
const {} = config;
|
|
493
|
-
const {
|
|
684
|
+
const {
|
|
685
|
+
streamingTimeout = 6e4,
|
|
686
|
+
abortSignal: externalSignal,
|
|
687
|
+
enableTokenStreaming = false
|
|
688
|
+
} = options;
|
|
494
689
|
const { timeoutId, controller } = createTimeoutHandler(
|
|
495
690
|
streamingTimeout,
|
|
496
691
|
"streaming request"
|
|
497
692
|
);
|
|
693
|
+
const signal = externalSignal ? combineSignals(controller.signal, externalSignal) : controller.signal;
|
|
498
694
|
try {
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
JSON.stringify(request),
|
|
502
|
-
controller.signal
|
|
503
|
-
);
|
|
695
|
+
const requestBody = JSON.stringify(request);
|
|
696
|
+
const fetchOptions = createFetchOptions(headers, requestBody, signal);
|
|
504
697
|
const response = await fetch(fullAgentUrl, fetchOptions);
|
|
505
698
|
clearTimeout(timeoutId);
|
|
506
699
|
validateStreamingResponse(response, "streaming request");
|
|
507
|
-
|
|
700
|
+
if (!response.body) {
|
|
701
|
+
throw new Error(
|
|
702
|
+
"Response body is null - server may not support streaming"
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
const supportDeltas = enableTokenStreaming && request.tokenStreaming === true;
|
|
706
|
+
yield* parseSSEStream(response.body, {
|
|
707
|
+
supportDeltas
|
|
708
|
+
});
|
|
508
709
|
} catch (error) {
|
|
509
710
|
handleRequestError(error, timeoutId, "streaming request");
|
|
510
711
|
}
|
|
@@ -512,6 +713,7 @@ async function* executeStreamingRequest(preparedRequest, config, options) {
|
|
|
512
713
|
|
|
513
714
|
// src/client/index.ts
|
|
514
715
|
var DEFAULT_TIMEOUT = 12e4;
|
|
716
|
+
var toolResultPromises = /* @__PURE__ */ new Map();
|
|
515
717
|
async function hasMatchingToolCallbacks(toolProvider, message) {
|
|
516
718
|
if (!toolProvider || !message || !toolProvider.getAvailableTools) {
|
|
517
719
|
return false;
|
|
@@ -535,6 +737,32 @@ async function hasMatchingToolCallbacks(toolProvider, message) {
|
|
|
535
737
|
}
|
|
536
738
|
return false;
|
|
537
739
|
}
|
|
740
|
+
function clearToolResultPromises() {
|
|
741
|
+
toolResultPromises.clear();
|
|
742
|
+
}
|
|
743
|
+
function updateToolResultsWithResolvedPromises(toolResults) {
|
|
744
|
+
return toolResults.map((toolResult) => {
|
|
745
|
+
const toolCallId = toolResult.data.toolCallId;
|
|
746
|
+
const promiseEntry = toolResultPromises.get(toolCallId);
|
|
747
|
+
if (promiseEntry && promiseEntry.resolvedValue !== null) {
|
|
748
|
+
const resolvedValue = promiseEntry.resolvedValue;
|
|
749
|
+
if (resolvedValue.error) {
|
|
750
|
+
return createToolResultDataPart(
|
|
751
|
+
toolCallId,
|
|
752
|
+
toolResult.data.toolId,
|
|
753
|
+
void 0,
|
|
754
|
+
resolvedValue.error
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
return createToolResultDataPart(
|
|
758
|
+
toolCallId,
|
|
759
|
+
toolResult.data.toolId,
|
|
760
|
+
resolvedValue
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
return toolResult;
|
|
764
|
+
});
|
|
765
|
+
}
|
|
538
766
|
async function executeToolCallBatch(toolCalls, toolProvider, messageId) {
|
|
539
767
|
const results = [];
|
|
540
768
|
const agentMessages = [];
|
|
@@ -595,7 +823,7 @@ function conversationHistoryToDataParts(conversationHistory) {
|
|
|
595
823
|
}
|
|
596
824
|
return historyParts;
|
|
597
825
|
}
|
|
598
|
-
async function continueTask(taskId, message, requestConfig, toolProvider, contextProvider, sessionId) {
|
|
826
|
+
async function continueTask(taskId, message, requestConfig, toolProvider, contextProvider, sessionId, abortSignal) {
|
|
599
827
|
const continueParams = {
|
|
600
828
|
message,
|
|
601
829
|
taskId,
|
|
@@ -605,30 +833,37 @@ async function continueTask(taskId, message, requestConfig, toolProvider, contex
|
|
|
605
833
|
const preparedRequest = await prepareRequest(
|
|
606
834
|
continueParams,
|
|
607
835
|
requestConfig,
|
|
608
|
-
{ isStreaming: false },
|
|
836
|
+
{ isStreaming: false, abortSignal },
|
|
609
837
|
toolProvider,
|
|
610
838
|
contextProvider,
|
|
611
839
|
sessionId
|
|
612
840
|
);
|
|
613
|
-
return await executeRequest(preparedRequest, requestConfig
|
|
841
|
+
return await executeRequest(preparedRequest, requestConfig, {
|
|
842
|
+
abortSignal
|
|
843
|
+
});
|
|
614
844
|
}
|
|
615
|
-
async function continueTaskStreamed(taskId, message, requestConfig, toolProvider, contextProvider, sessionId) {
|
|
845
|
+
async function continueTaskStreamed(taskId, message, requestConfig, toolProvider, contextProvider, sessionId, abortSignal, requestOptions) {
|
|
616
846
|
const continueParams = {
|
|
617
847
|
message,
|
|
618
848
|
taskId,
|
|
619
849
|
sessionId: void 0
|
|
620
850
|
// Use task's session
|
|
621
851
|
};
|
|
852
|
+
const options = requestOptions || { isStreaming: true };
|
|
622
853
|
const preparedRequest = await prepareRequest(
|
|
623
854
|
continueParams,
|
|
624
855
|
requestConfig,
|
|
625
|
-
{
|
|
856
|
+
{
|
|
857
|
+
...options,
|
|
858
|
+
abortSignal
|
|
859
|
+
},
|
|
626
860
|
toolProvider,
|
|
627
861
|
contextProvider,
|
|
628
862
|
sessionId
|
|
629
863
|
);
|
|
630
864
|
const stream = executeStreamingRequest(preparedRequest, requestConfig, {
|
|
631
|
-
|
|
865
|
+
...options,
|
|
866
|
+
abortSignal
|
|
632
867
|
});
|
|
633
868
|
return processAgentResponseStream(
|
|
634
869
|
stream,
|
|
@@ -638,11 +873,14 @@ async function continueTaskStreamed(taskId, message, requestConfig, toolProvider
|
|
|
638
873
|
sessionId,
|
|
639
874
|
true,
|
|
640
875
|
// withHistory
|
|
641
|
-
[]
|
|
876
|
+
[],
|
|
642
877
|
// newConversationParts - empty for continueTask
|
|
878
|
+
abortSignal,
|
|
879
|
+
options
|
|
880
|
+
// Pass through the same request options
|
|
643
881
|
);
|
|
644
882
|
}
|
|
645
|
-
async function* processAgentResponseStream(stream, toolProvider, contextProvider, requestConfig, sessionId, withHistory = true, newConversationParts = []) {
|
|
883
|
+
async function* processAgentResponseStream(stream, toolProvider, contextProvider, requestConfig, sessionId, withHistory = true, newConversationParts = [], abortSignal, requestOptions) {
|
|
646
884
|
for await (const update of stream) {
|
|
647
885
|
yield update;
|
|
648
886
|
if (update.status.state === "running" && update.status.message && toolProvider && await hasMatchingToolCallbacks(
|
|
@@ -712,6 +950,28 @@ async function* processAgentResponseStream(stream, toolProvider, contextProvider
|
|
|
712
950
|
createAgentTextMessage(agentMessage)
|
|
713
951
|
);
|
|
714
952
|
}
|
|
953
|
+
if (result.result instanceof Promise) {
|
|
954
|
+
const promise = result.result;
|
|
955
|
+
const promiseEntry = {
|
|
956
|
+
promise,
|
|
957
|
+
resolvedValue: null
|
|
958
|
+
};
|
|
959
|
+
toolResultPromises.set(
|
|
960
|
+
toolCallId,
|
|
961
|
+
promiseEntry
|
|
962
|
+
);
|
|
963
|
+
promise.then((resolvedValue) => {
|
|
964
|
+
promiseEntry.resolvedValue = resolvedValue;
|
|
965
|
+
}).catch((error) => {
|
|
966
|
+
console.error(
|
|
967
|
+
`Promise rejected for tool call ${toolCallId}:`,
|
|
968
|
+
error
|
|
969
|
+
);
|
|
970
|
+
promiseEntry.resolvedValue = {
|
|
971
|
+
error: error instanceof Error ? error.message : String(error)
|
|
972
|
+
};
|
|
973
|
+
});
|
|
974
|
+
}
|
|
715
975
|
const toolResult = createToolResultDataPart(
|
|
716
976
|
toolCallId,
|
|
717
977
|
toolId,
|
|
@@ -752,7 +1012,9 @@ async function* processAgentResponseStream(stream, toolProvider, contextProvider
|
|
|
752
1012
|
requestConfig,
|
|
753
1013
|
toolProvider,
|
|
754
1014
|
contextProvider,
|
|
755
|
-
sessionId
|
|
1015
|
+
sessionId,
|
|
1016
|
+
abortSignal,
|
|
1017
|
+
requestOptions
|
|
756
1018
|
);
|
|
757
1019
|
let continuedTaskUpdate = null;
|
|
758
1020
|
for await (const streamUpdate of continuedTaskStream) {
|
|
@@ -837,7 +1099,9 @@ async function* processAgentResponseStream(stream, toolProvider, contextProvider
|
|
|
837
1099
|
requestConfig,
|
|
838
1100
|
toolProvider,
|
|
839
1101
|
contextProvider,
|
|
840
|
-
sessionId
|
|
1102
|
+
sessionId,
|
|
1103
|
+
abortSignal,
|
|
1104
|
+
requestOptions
|
|
841
1105
|
);
|
|
842
1106
|
let moreFinalTask = null;
|
|
843
1107
|
for await (const streamUpdate of moreTaskStream) {
|
|
@@ -930,7 +1194,8 @@ function createClient(config) {
|
|
|
930
1194
|
defaultSessionId,
|
|
931
1195
|
timeout = DEFAULT_TIMEOUT,
|
|
932
1196
|
toolProvider,
|
|
933
|
-
contextProvider
|
|
1197
|
+
contextProvider,
|
|
1198
|
+
enableStreaming = false
|
|
934
1199
|
} = config;
|
|
935
1200
|
const requestConfig = {
|
|
936
1201
|
agentId,
|
|
@@ -940,21 +1205,22 @@ function createClient(config) {
|
|
|
940
1205
|
};
|
|
941
1206
|
return {
|
|
942
1207
|
async sendMessage(params) {
|
|
943
|
-
const { withHistory = true } = params;
|
|
1208
|
+
const { withHistory = true, abortSignal } = params;
|
|
944
1209
|
const sessionId = params.sessionId || defaultSessionId || void 0;
|
|
945
1210
|
const newConversationParts = [];
|
|
946
1211
|
newConversationParts.push(params.message);
|
|
947
1212
|
const preparedRequest = await prepareRequest(
|
|
948
1213
|
params,
|
|
949
1214
|
requestConfig,
|
|
950
|
-
{ isStreaming: false },
|
|
1215
|
+
{ isStreaming: false, abortSignal },
|
|
951
1216
|
toolProvider,
|
|
952
1217
|
contextProvider,
|
|
953
1218
|
sessionId
|
|
954
1219
|
);
|
|
955
1220
|
let currentTask = await executeRequest(
|
|
956
1221
|
preparedRequest,
|
|
957
|
-
requestConfig
|
|
1222
|
+
requestConfig,
|
|
1223
|
+
{ abortSignal }
|
|
958
1224
|
);
|
|
959
1225
|
const allToolParts = [];
|
|
960
1226
|
const agentMessages = [];
|
|
@@ -1015,7 +1281,8 @@ function createClient(config) {
|
|
|
1015
1281
|
requestConfig,
|
|
1016
1282
|
toolProvider,
|
|
1017
1283
|
contextProvider,
|
|
1018
|
-
sessionId
|
|
1284
|
+
sessionId,
|
|
1285
|
+
abortSignal
|
|
1019
1286
|
);
|
|
1020
1287
|
} else {
|
|
1021
1288
|
break;
|
|
@@ -1061,14 +1328,26 @@ function createClient(config) {
|
|
|
1061
1328
|
};
|
|
1062
1329
|
},
|
|
1063
1330
|
async *sendMessageStream(params) {
|
|
1064
|
-
const {
|
|
1331
|
+
const {
|
|
1332
|
+
withHistory = true,
|
|
1333
|
+
abortSignal,
|
|
1334
|
+
enableStreaming: requestStreaming
|
|
1335
|
+
} = params;
|
|
1065
1336
|
const sessionId = params.sessionId || defaultSessionId || void 0;
|
|
1337
|
+
const useTokenStreaming = requestStreaming ?? enableStreaming;
|
|
1066
1338
|
const newConversationParts = [];
|
|
1067
1339
|
newConversationParts.push(params.message);
|
|
1068
1340
|
const preparedRequest = await prepareRequest(
|
|
1069
1341
|
params,
|
|
1070
1342
|
requestConfig,
|
|
1071
|
-
{
|
|
1343
|
+
{
|
|
1344
|
+
isStreaming: true,
|
|
1345
|
+
// Always use message/stream endpoint for SSE
|
|
1346
|
+
enableTokenStreaming: useTokenStreaming,
|
|
1347
|
+
// Optional token-by-token streaming
|
|
1348
|
+
streamingTimeout: timeout,
|
|
1349
|
+
abortSignal
|
|
1350
|
+
},
|
|
1072
1351
|
toolProvider,
|
|
1073
1352
|
contextProvider,
|
|
1074
1353
|
sessionId
|
|
@@ -1078,7 +1357,10 @@ function createClient(config) {
|
|
|
1078
1357
|
requestConfig,
|
|
1079
1358
|
{
|
|
1080
1359
|
isStreaming: true,
|
|
1081
|
-
|
|
1360
|
+
enableTokenStreaming: useTokenStreaming,
|
|
1361
|
+
// Token streaming is optional
|
|
1362
|
+
streamingTimeout: timeout,
|
|
1363
|
+
abortSignal
|
|
1082
1364
|
}
|
|
1083
1365
|
);
|
|
1084
1366
|
yield* processAgentResponseStream(
|
|
@@ -1088,7 +1370,13 @@ function createClient(config) {
|
|
|
1088
1370
|
requestConfig,
|
|
1089
1371
|
sessionId,
|
|
1090
1372
|
withHistory,
|
|
1091
|
-
newConversationParts
|
|
1373
|
+
newConversationParts,
|
|
1374
|
+
abortSignal,
|
|
1375
|
+
{
|
|
1376
|
+
isStreaming: true,
|
|
1377
|
+
enableTokenStreaming: useTokenStreaming,
|
|
1378
|
+
streamingTimeout: timeout
|
|
1379
|
+
}
|
|
1092
1380
|
);
|
|
1093
1381
|
},
|
|
1094
1382
|
async continueTask(taskId, userInput, sessionId) {
|
|
@@ -1378,6 +1666,31 @@ function extractToolResultsFromMessage(message) {
|
|
|
1378
1666
|
}
|
|
1379
1667
|
|
|
1380
1668
|
// src/react/agentManager.ts
|
|
1669
|
+
async function resolvePromisesInConversationHistory(conversationHistory) {
|
|
1670
|
+
const resolvedHistory = [];
|
|
1671
|
+
for (const message of conversationHistory) {
|
|
1672
|
+
if (message.parts && Array.isArray(message.parts)) {
|
|
1673
|
+
const hasToolResults = message.parts.some(
|
|
1674
|
+
(part) => part.type === "data" && "toolCallId" in part.data && "result" in part.data
|
|
1675
|
+
);
|
|
1676
|
+
if (hasToolResults) {
|
|
1677
|
+
const updatedParts = updateToolResultsWithResolvedPromises(
|
|
1678
|
+
message.parts
|
|
1679
|
+
);
|
|
1680
|
+
resolvedHistory.push({
|
|
1681
|
+
...message,
|
|
1682
|
+
parts: updatedParts
|
|
1683
|
+
});
|
|
1684
|
+
} else {
|
|
1685
|
+
resolvedHistory.push(message);
|
|
1686
|
+
}
|
|
1687
|
+
} else {
|
|
1688
|
+
resolvedHistory.push(message);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
clearToolResultPromises();
|
|
1692
|
+
return resolvedHistory;
|
|
1693
|
+
}
|
|
1381
1694
|
function createAgentManager() {
|
|
1382
1695
|
const agents = /* @__PURE__ */ new Map();
|
|
1383
1696
|
async function persistConversationHistory(key, messages) {
|
|
@@ -1506,9 +1819,20 @@ function createAgentManager() {
|
|
|
1506
1819
|
...managedAgent.conversationHistory
|
|
1507
1820
|
];
|
|
1508
1821
|
let currentToolCallIds = [];
|
|
1822
|
+
const resolvedConversationHistory = await resolvePromisesInConversationHistory(
|
|
1823
|
+
currentConversationHistory
|
|
1824
|
+
);
|
|
1825
|
+
managedAgent.conversationHistory = resolvedConversationHistory;
|
|
1826
|
+
currentConversationHistory = resolvedConversationHistory;
|
|
1827
|
+
if (withHistory) {
|
|
1828
|
+
await persistConversationHistory(
|
|
1829
|
+
key,
|
|
1830
|
+
resolvedConversationHistory
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1509
1833
|
const messageObj = options.message || createTextMessageWithHistory(
|
|
1510
1834
|
message,
|
|
1511
|
-
|
|
1835
|
+
resolvedConversationHistory
|
|
1512
1836
|
);
|
|
1513
1837
|
const userMessage = createTextMessage(message);
|
|
1514
1838
|
currentConversationHistory = [
|
|
@@ -1632,7 +1956,7 @@ function getAgentManager() {
|
|
|
1632
1956
|
}
|
|
1633
1957
|
|
|
1634
1958
|
// src/utils/createMessageRenderer.tsx
|
|
1635
|
-
import Markdown from "
|
|
1959
|
+
import Markdown from "streamdown";
|
|
1636
1960
|
|
|
1637
1961
|
// src/markdown-extensions/index.ts
|
|
1638
1962
|
import remarkGfm from "remark-gfm";
|
|
@@ -1699,30 +2023,40 @@ var createFeedbackActions = (config) => {
|
|
|
1699
2023
|
}
|
|
1700
2024
|
const feedbackState = feedbackByMessageId[message.id];
|
|
1701
2025
|
const actions = [];
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
2026
|
+
actions.push({
|
|
2027
|
+
id: "feedback-up",
|
|
2028
|
+
icon: config.icons.up,
|
|
2029
|
+
label: "Good response",
|
|
2030
|
+
onClick: async () => {
|
|
2031
|
+
if (feedbackState === "up") {
|
|
2032
|
+
delete feedbackByMessageId[message.id];
|
|
2033
|
+
} else {
|
|
1708
2034
|
await handleFeedback(message.id, "up");
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
2035
|
+
}
|
|
2036
|
+
notifyListeners();
|
|
2037
|
+
},
|
|
2038
|
+
tooltip: "This response was helpful",
|
|
2039
|
+
pressed: feedbackState === "up",
|
|
2040
|
+
disabled: feedbackState === "down"
|
|
2041
|
+
// Disable if other is selected
|
|
2042
|
+
});
|
|
2043
|
+
actions.push({
|
|
2044
|
+
id: "feedback-down",
|
|
2045
|
+
icon: config.icons.down,
|
|
2046
|
+
label: "Bad response",
|
|
2047
|
+
onClick: async () => {
|
|
2048
|
+
if (feedbackState === "down") {
|
|
2049
|
+
delete feedbackByMessageId[message.id];
|
|
2050
|
+
} else {
|
|
1720
2051
|
await handleFeedback(message.id, "down");
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
2052
|
+
}
|
|
2053
|
+
notifyListeners();
|
|
2054
|
+
},
|
|
2055
|
+
tooltip: "This response was not helpful",
|
|
2056
|
+
pressed: feedbackState === "down",
|
|
2057
|
+
disabled: feedbackState === "up"
|
|
2058
|
+
// Disable if other is selected
|
|
2059
|
+
});
|
|
1726
2060
|
return actions;
|
|
1727
2061
|
},
|
|
1728
2062
|
clearFeedback: (messageId) => {
|
|
@@ -1800,7 +2134,9 @@ function resolveActionsForMessage(message, registrations) {
|
|
|
1800
2134
|
icon: action.icon,
|
|
1801
2135
|
onClick: action.onClick,
|
|
1802
2136
|
tooltip: action.tooltip,
|
|
1803
|
-
disabled: action.disabled || false
|
|
2137
|
+
disabled: action.disabled || false,
|
|
2138
|
+
pressed: action.pressed,
|
|
2139
|
+
showLabel: action.showLabel
|
|
1804
2140
|
}));
|
|
1805
2141
|
return filteredActions;
|
|
1806
2142
|
}
|
|
@@ -1904,7 +2240,8 @@ function useAgentChat(config) {
|
|
|
1904
2240
|
error: isValidConfig ? null : "Invalid agent configuration",
|
|
1905
2241
|
suggestions: [],
|
|
1906
2242
|
markdownComponents: {},
|
|
1907
|
-
markdownExtensions: {}
|
|
2243
|
+
markdownExtensions: {},
|
|
2244
|
+
currentAbortController: null
|
|
1908
2245
|
});
|
|
1909
2246
|
const {
|
|
1910
2247
|
registerMessageActions,
|
|
@@ -1932,7 +2269,8 @@ function useAgentChat(config) {
|
|
|
1932
2269
|
sessionId: agentConfig.sessionId,
|
|
1933
2270
|
contextProvider: config.contextProvider || createNoOpContextProvider(),
|
|
1934
2271
|
toolProvider: config.toolProvider || createNoOpToolProvider(),
|
|
1935
|
-
authProvider: config.authProvider
|
|
2272
|
+
authProvider: config.authProvider,
|
|
2273
|
+
enableStreaming: config.enableStreaming
|
|
1936
2274
|
});
|
|
1937
2275
|
const clientHistory = agentManager.getConversationHistory(agentKey);
|
|
1938
2276
|
setState((prev) => {
|
|
@@ -1961,6 +2299,7 @@ function useAgentChat(config) {
|
|
|
1961
2299
|
config.contextProvider,
|
|
1962
2300
|
config.toolProvider,
|
|
1963
2301
|
config.authProvider,
|
|
2302
|
+
config.enableStreaming,
|
|
1964
2303
|
isValidConfig
|
|
1965
2304
|
]);
|
|
1966
2305
|
const onSubmit = useCallback3(
|
|
@@ -1979,51 +2318,143 @@ function useAgentChat(config) {
|
|
|
1979
2318
|
archived: false,
|
|
1980
2319
|
showIcon: false
|
|
1981
2320
|
};
|
|
2321
|
+
const abortController = new AbortController();
|
|
1982
2322
|
setState((prev) => ({
|
|
1983
2323
|
...prev,
|
|
1984
2324
|
uiMessages: [...prev.uiMessages, userMessage],
|
|
1985
2325
|
isProcessing: true,
|
|
1986
|
-
error: null
|
|
2326
|
+
error: null,
|
|
2327
|
+
currentAbortController: abortController
|
|
1987
2328
|
}));
|
|
1988
2329
|
try {
|
|
1989
|
-
let
|
|
2330
|
+
let streamingMessageId = null;
|
|
2331
|
+
let finalMessageAdded = false;
|
|
1990
2332
|
for await (const update of agentManager.sendMessageStream(
|
|
1991
2333
|
agentKey,
|
|
1992
|
-
message
|
|
2334
|
+
message,
|
|
2335
|
+
{
|
|
2336
|
+
abortSignal: abortController.signal
|
|
2337
|
+
}
|
|
1993
2338
|
)) {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2339
|
+
if (!update.final && update.text) {
|
|
2340
|
+
if (!streamingMessageId) {
|
|
2341
|
+
streamingMessageId = `agent-streaming-${Date.now()}`;
|
|
2342
|
+
const streamingMessage = {
|
|
2343
|
+
id: streamingMessageId,
|
|
2344
|
+
role: "agent",
|
|
2345
|
+
content: [
|
|
2346
|
+
{ type: "text", text: update.text }
|
|
2347
|
+
],
|
|
2348
|
+
timestamp: Date.now(),
|
|
2349
|
+
archived: false,
|
|
2350
|
+
showIcon: true,
|
|
2351
|
+
icon: "assistant"
|
|
2352
|
+
};
|
|
2353
|
+
setState((prev) => ({
|
|
2354
|
+
...prev,
|
|
2355
|
+
uiMessages: [
|
|
2356
|
+
...prev.uiMessages,
|
|
2357
|
+
streamingMessage
|
|
2358
|
+
]
|
|
2359
|
+
}));
|
|
2360
|
+
} else {
|
|
2361
|
+
setState((prev) => ({
|
|
2362
|
+
...prev,
|
|
2363
|
+
uiMessages: prev.uiMessages.map(
|
|
2364
|
+
(msg) => msg.id === streamingMessageId ? {
|
|
2365
|
+
...msg,
|
|
2366
|
+
content: [
|
|
2367
|
+
{
|
|
2368
|
+
type: "text",
|
|
2369
|
+
text: update.text
|
|
2370
|
+
}
|
|
2371
|
+
]
|
|
2372
|
+
} : msg
|
|
2373
|
+
)
|
|
2374
|
+
}));
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
if (update.final && update.status?.message && streamingMessageId) {
|
|
2378
|
+
finalMessageAdded = true;
|
|
2379
|
+
const currentStreamingId = streamingMessageId;
|
|
2380
|
+
const finalMessage = transformClientMessageToUI(
|
|
2381
|
+
update.status.message,
|
|
2001
2382
|
registrationsRef.current
|
|
2002
|
-
)
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2383
|
+
);
|
|
2384
|
+
if (finalMessage) {
|
|
2385
|
+
setState((prev) => {
|
|
2386
|
+
const updatedMessages = prev.uiMessages.map(
|
|
2387
|
+
(msg) => msg.id === currentStreamingId ? finalMessage : msg
|
|
2388
|
+
);
|
|
2389
|
+
const updatedClientHistory = agentManager.getConversationHistory(
|
|
2390
|
+
agentKey
|
|
2391
|
+
);
|
|
2392
|
+
return {
|
|
2393
|
+
...prev,
|
|
2394
|
+
clientMessages: updatedClientHistory,
|
|
2395
|
+
uiMessages: updatedMessages,
|
|
2396
|
+
isProcessing: false,
|
|
2397
|
+
currentAbortController: null
|
|
2398
|
+
};
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
streamingMessageId = null;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
if (!finalMessageAdded) {
|
|
2405
|
+
const updatedClientHistory = agentManager.getConversationHistory(agentKey);
|
|
2406
|
+
setState((prev) => {
|
|
2407
|
+
let filteredMessages = prev.uiMessages;
|
|
2408
|
+
if (streamingMessageId) {
|
|
2409
|
+
filteredMessages = prev.uiMessages.filter(
|
|
2410
|
+
(msg) => msg.id !== streamingMessageId
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
const transformedClientMessages = updatedClientHistory.map(
|
|
2414
|
+
(msg) => transformClientMessageToUI(
|
|
2415
|
+
msg,
|
|
2416
|
+
registrationsRef.current
|
|
2417
|
+
)
|
|
2418
|
+
).filter(
|
|
2419
|
+
(msg) => msg !== null
|
|
2420
|
+
);
|
|
2421
|
+
const clientMessageIds = new Set(
|
|
2422
|
+
updatedClientHistory.map((msg) => msg.messageId)
|
|
2423
|
+
);
|
|
2424
|
+
const uiOnlyMessages = filteredMessages.filter(
|
|
2425
|
+
(msg) => !clientMessageIds.has(msg.id) && msg.content[0]?.type === "component"
|
|
2426
|
+
);
|
|
2427
|
+
const mergedUIMessages = sortUIMessagesByTime([
|
|
2428
|
+
...transformedClientMessages,
|
|
2429
|
+
...uiOnlyMessages
|
|
2430
|
+
]);
|
|
2431
|
+
return {
|
|
2432
|
+
...prev,
|
|
2433
|
+
clientMessages: updatedClientHistory,
|
|
2434
|
+
uiMessages: mergedUIMessages,
|
|
2435
|
+
isProcessing: false,
|
|
2436
|
+
currentAbortController: null
|
|
2437
|
+
};
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2021
2440
|
} catch (error) {
|
|
2441
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2442
|
+
console.log("Request was aborted by user");
|
|
2443
|
+
setState((prev) => ({
|
|
2444
|
+
...prev,
|
|
2445
|
+
isProcessing: false,
|
|
2446
|
+
error: null,
|
|
2447
|
+
// Don't show error for user-initiated abort
|
|
2448
|
+
currentAbortController: null
|
|
2449
|
+
}));
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2022
2452
|
const errorMessage = error instanceof Error ? error.message : "Failed to send message";
|
|
2023
2453
|
setState((prev) => ({
|
|
2024
2454
|
...prev,
|
|
2025
2455
|
isProcessing: false,
|
|
2026
|
-
error: errorMessage
|
|
2456
|
+
error: errorMessage,
|
|
2457
|
+
currentAbortController: null
|
|
2027
2458
|
}));
|
|
2028
2459
|
throw error;
|
|
2029
2460
|
}
|
|
@@ -2142,6 +2573,14 @@ function useAgentChat(config) {
|
|
|
2142
2573
|
}),
|
|
2143
2574
|
[state.markdownComponents, state.markdownExtensions]
|
|
2144
2575
|
);
|
|
2576
|
+
const abortCurrentRequest = useCallback3(() => {
|
|
2577
|
+
setState((currentState) => {
|
|
2578
|
+
if (currentState.currentAbortController) {
|
|
2579
|
+
currentState.currentAbortController.abort();
|
|
2580
|
+
}
|
|
2581
|
+
return currentState;
|
|
2582
|
+
});
|
|
2583
|
+
}, []);
|
|
2145
2584
|
return {
|
|
2146
2585
|
// AgentUI props
|
|
2147
2586
|
messages: state.uiMessages,
|
|
@@ -2161,7 +2600,9 @@ function useAgentChat(config) {
|
|
|
2161
2600
|
clearAllMessageActions,
|
|
2162
2601
|
createFeedbackActions: createFeedbackActions2,
|
|
2163
2602
|
// Tool integration
|
|
2164
|
-
addMessage
|
|
2603
|
+
addMessage,
|
|
2604
|
+
// Abort control
|
|
2605
|
+
abortCurrentRequest
|
|
2165
2606
|
};
|
|
2166
2607
|
}
|
|
2167
2608
|
|
|
@@ -2266,6 +2707,7 @@ export {
|
|
|
2266
2707
|
BarChart,
|
|
2267
2708
|
ChartBlock,
|
|
2268
2709
|
LineChart,
|
|
2710
|
+
createAbortController,
|
|
2269
2711
|
createClient,
|
|
2270
2712
|
createFeedbackActions,
|
|
2271
2713
|
createJetpackAuthProvider,
|