@agents24/chat-react 0.2.0 → 0.3.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 +4 -3
- package/dist/controller-hitl.d.ts +22 -0
- package/dist/controller-options.d.ts +15 -0
- package/dist/controller-thread-events.d.ts +7 -0
- package/dist/controller.d.ts +4 -16
- package/dist/index.cjs +217 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +205 -118
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +36 -18
- package/dist/ui/agent-response-timeline.d.ts +3 -3
- package/dist/ui/index.cjs +169 -156
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +169 -156
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -86,7 +86,7 @@ __export(index_exports, {
|
|
|
86
86
|
module.exports = __toCommonJS(index_exports);
|
|
87
87
|
|
|
88
88
|
// src/controller.ts
|
|
89
|
-
var
|
|
89
|
+
var import_react4 = require("react");
|
|
90
90
|
|
|
91
91
|
// src/controller-actions.ts
|
|
92
92
|
var import_react = require("react");
|
|
@@ -160,6 +160,47 @@ function useControllerMessageActions(input) {
|
|
|
160
160
|
return { handleCopy, handleDislike, handleLike, handleRetry, startNewThread, upsertLiveVoiceMessage };
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
// src/controller-hitl.ts
|
|
164
|
+
var import_react2 = require("react");
|
|
165
|
+
function useControllerHitl({
|
|
166
|
+
messages,
|
|
167
|
+
transport,
|
|
168
|
+
activeRunId,
|
|
169
|
+
activeRunIdRef,
|
|
170
|
+
activeThreadIdRef,
|
|
171
|
+
runStream
|
|
172
|
+
}) {
|
|
173
|
+
const [isResolvingHitl, setIsResolvingHitl] = (0, import_react2.useState)(false);
|
|
174
|
+
const pendingHitl = (0, import_react2.useMemo)(() => {
|
|
175
|
+
for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
|
|
176
|
+
const parts = messages[messageIndex]?.parts || [];
|
|
177
|
+
for (let partIndex = parts.length - 1; partIndex >= 0; partIndex -= 1) {
|
|
178
|
+
const part = parts[partIndex];
|
|
179
|
+
if (part?.kind === "hitl" && part.status === "pending") return part;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}, [messages]);
|
|
184
|
+
const resumeHitl = (0, import_react2.useCallback)(async (input) => {
|
|
185
|
+
if (!transport.resumeHitl) throw new Error("HITL resume is not configured.");
|
|
186
|
+
const runId = input.runId || activeRunIdRef.current || activeRunId;
|
|
187
|
+
if (!runId) throw new Error("No paused run is available to resume.");
|
|
188
|
+
setIsResolvingHitl(true);
|
|
189
|
+
try {
|
|
190
|
+
const result = await transport.resumeHitl({ ...input, runId });
|
|
191
|
+
const threadId = result.thread_id || activeThreadIdRef.current;
|
|
192
|
+
if (threadId) await runStream({ mode: "attach", runId: result.run_id || runId, threadId });
|
|
193
|
+
return result;
|
|
194
|
+
} finally {
|
|
195
|
+
setIsResolvingHitl(false);
|
|
196
|
+
}
|
|
197
|
+
}, [activeRunId, activeRunIdRef, activeThreadIdRef, runStream, transport]);
|
|
198
|
+
return { pendingHitl, isResolvingHitl, resumeHitl };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/controller-thread-events.ts
|
|
202
|
+
var import_react3 = require("react");
|
|
203
|
+
|
|
163
204
|
// src/context-window.ts
|
|
164
205
|
var SOURCE_PRIORITY = {
|
|
165
206
|
unknown: 0,
|
|
@@ -444,13 +485,34 @@ var partsFromResponseBlocks = (blocks, fallbackText) => {
|
|
|
444
485
|
}
|
|
445
486
|
if (block.kind === "hitl_request") {
|
|
446
487
|
const hitl = asRecord(block.hitl) || block;
|
|
488
|
+
if (hitl.schema_version !== "agents24.hitl.interrupt.v2") {
|
|
489
|
+
throw new Error("Invalid V2 HITL response block.");
|
|
490
|
+
}
|
|
491
|
+
const interruptId = optionalString(block.interruptId) || optionalString(hitl.interrupt_id);
|
|
492
|
+
const hitlKind = optionalString(block.hitlKind) || optionalString(hitl.kind);
|
|
493
|
+
const status = optionalString(block.status) || optionalString(hitl.status) || "pending";
|
|
494
|
+
const allowedActions = Array.isArray(hitl.allowed_actions) ? hitl.allowed_actions.filter((value) => ["approve", "reject", "connect", "skip"].includes(String(value))) : [];
|
|
495
|
+
if (!interruptId || allowedActions.length === 0 || !["tool_review", "mcp_auth", "user_approval", "app_data_permission"].includes(String(hitlKind))) {
|
|
496
|
+
throw new Error("Invalid V2 HITL response block.");
|
|
497
|
+
}
|
|
498
|
+
const resolution = asRecord(block.resolution);
|
|
447
499
|
parts.push({
|
|
448
500
|
id,
|
|
449
501
|
type: "hitl",
|
|
450
502
|
kind: "hitl",
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
503
|
+
interruptId,
|
|
504
|
+
hitlKind,
|
|
505
|
+
message: optionalString(hitl.message) || optionalString(block.text) || "Input is required to continue.",
|
|
506
|
+
allowedActions,
|
|
507
|
+
status,
|
|
508
|
+
presentation: asRecord(hitl.presentation) || {},
|
|
509
|
+
resolution: resolution ? {
|
|
510
|
+
action: ["approve", "reject", "connect", "skip"].includes(String(resolution.action)) ? String(resolution.action) : null,
|
|
511
|
+
outcome: optionalString(resolution.outcome),
|
|
512
|
+
reason: optionalString(resolution.reason),
|
|
513
|
+
resolvedAt: optionalString(resolution.resolved_at),
|
|
514
|
+
resolver: asRecord(resolution.resolver)
|
|
515
|
+
} : null,
|
|
454
516
|
raw: block
|
|
455
517
|
});
|
|
456
518
|
return;
|
|
@@ -690,6 +752,47 @@ var applyThreadSummaryEvent = (currentThreads, event) => {
|
|
|
690
752
|
return sortByActivity(next);
|
|
691
753
|
};
|
|
692
754
|
|
|
755
|
+
// src/controller-thread-events.ts
|
|
756
|
+
function useControllerThreadEvents({
|
|
757
|
+
transport,
|
|
758
|
+
storage,
|
|
759
|
+
refresh,
|
|
760
|
+
setThreads
|
|
761
|
+
}) {
|
|
762
|
+
const cursorRef = (0, import_react3.useRef)(null);
|
|
763
|
+
(0, import_react3.useEffect)(() => {
|
|
764
|
+
if (!transport.subscribeThreadEvents) return;
|
|
765
|
+
let cancelled = false;
|
|
766
|
+
let retryTimeout = null;
|
|
767
|
+
let controller = null;
|
|
768
|
+
const connect = () => {
|
|
769
|
+
if (cancelled) return;
|
|
770
|
+
controller = new AbortController();
|
|
771
|
+
transport.subscribeThreadEvents?.(
|
|
772
|
+
{ cursor: cursorRef.current, signal: controller.signal },
|
|
773
|
+
async (event) => {
|
|
774
|
+
if (typeof event.cursor === "number") cursorRef.current = event.cursor;
|
|
775
|
+
if (event.event === "snapshot_required") {
|
|
776
|
+
await refresh().catch(() => void 0);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
storage.setThreads(applyThreadSummaryEvent(storage.listThreads(), event));
|
|
780
|
+
setThreads(storage.listThreads());
|
|
781
|
+
}
|
|
782
|
+
).catch((error) => {
|
|
783
|
+
if (cancelled || isAbortError(error)) return;
|
|
784
|
+
retryTimeout = setTimeout(connect, 1500);
|
|
785
|
+
});
|
|
786
|
+
};
|
|
787
|
+
connect();
|
|
788
|
+
return () => {
|
|
789
|
+
cancelled = true;
|
|
790
|
+
if (retryTimeout) clearTimeout(retryTimeout);
|
|
791
|
+
controller?.abort();
|
|
792
|
+
};
|
|
793
|
+
}, [refresh, setThreads, storage, transport]);
|
|
794
|
+
}
|
|
795
|
+
|
|
693
796
|
// src/message-lifecycle.ts
|
|
694
797
|
function findStableAssistantMessageIndex(messages, input) {
|
|
695
798
|
return messages.findIndex(
|
|
@@ -728,83 +831,83 @@ function upsertStableAssistantMessage(messages, input) {
|
|
|
728
831
|
}
|
|
729
832
|
|
|
730
833
|
// src/controller.ts
|
|
731
|
-
function useAgents24ChatController({
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
834
|
+
function useAgents24ChatController(options) {
|
|
835
|
+
const {
|
|
836
|
+
transport,
|
|
837
|
+
storage,
|
|
838
|
+
activeThreadId: controlledActiveThreadId,
|
|
839
|
+
pageSize = DEFAULT_THREAD_PAGE_SIZE,
|
|
840
|
+
storageKey,
|
|
841
|
+
createId = createChatId,
|
|
842
|
+
onActiveThreadIdChange,
|
|
843
|
+
onSourceClick,
|
|
844
|
+
onStreamErrorMessage,
|
|
845
|
+
onRuntimeEvent,
|
|
846
|
+
onThreadDetailLoaded
|
|
847
|
+
} = options;
|
|
744
848
|
const activeThreadId = controlledActiveThreadId ?? storage.getActiveThreadId?.() ?? null;
|
|
745
849
|
const initialCached = activeThreadId ? storage.getThread(activeThreadId) : void 0;
|
|
746
|
-
const [messages, setMessages] = (0,
|
|
747
|
-
const [isLoading, setIsLoading] = (0,
|
|
748
|
-
const [isLoadingHistory, setIsLoadingHistory] = (0,
|
|
749
|
-
const [isLoadingOlder, setIsLoadingOlder] = (0,
|
|
750
|
-
const [hasOlderTurns, setHasOlderTurns] = (0,
|
|
751
|
-
const [streamingContent, setStreamingContent] = (0,
|
|
752
|
-
const [streamingMessageId, setStreamingMessageId] = (0,
|
|
753
|
-
const [contextStatus, setContextStatus] = (0,
|
|
754
|
-
const [currentReasoning, setCurrentReasoning] = (0,
|
|
755
|
-
const [liked, setLiked] = (0,
|
|
756
|
-
const [disliked, setDisliked] = (0,
|
|
757
|
-
const [copiedMessageId, setCopiedMessageId] = (0,
|
|
758
|
-
const [lastThinkingDurationMs, setLastThinkingDurationMs] = (0,
|
|
759
|
-
const [threads, setThreads] = (0,
|
|
760
|
-
const [isRefreshingThreads, setIsRefreshingThreads] = (0,
|
|
761
|
-
const [isSelectingThread, setIsSelectingThread] = (0,
|
|
762
|
-
const [activeRunId, setActiveRunId] = (0,
|
|
763
|
-
const textareaRef = (0,
|
|
764
|
-
const activeThreadIdRef = (0,
|
|
765
|
-
const messagesRef = (0,
|
|
766
|
-
const nextBeforeTurnIndexRef = (0,
|
|
767
|
-
const hasOlderTurnsRef = (0,
|
|
768
|
-
const isLoadingOlderRef = (0,
|
|
769
|
-
const loadedThreadIdRef = (0,
|
|
770
|
-
const requestSeqRef = (0,
|
|
771
|
-
const isLoadingHistoryRef = (0,
|
|
772
|
-
const activeRunIdRef = (0,
|
|
773
|
-
const reattachedRunIdRef = (0,
|
|
774
|
-
const abortControllerRef = (0,
|
|
775
|
-
const [lifecycleAbortController] = (0,
|
|
776
|
-
const streamingContentRef = (0,
|
|
777
|
-
const streamingMessageIdRef = (0,
|
|
778
|
-
const reasoningRef = (0,
|
|
779
|
-
const liveVoiceIdsRef = (0,
|
|
780
|
-
const refreshSeqRef = (0,
|
|
781
|
-
const
|
|
782
|
-
const setActiveRunIdValue = (0, import_react2.useCallback)((runId) => {
|
|
850
|
+
const [messages, setMessages] = (0, import_react4.useState)(() => initialCached?.messages || []);
|
|
851
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
852
|
+
const [isLoadingHistory, setIsLoadingHistory] = (0, import_react4.useState)(() => Boolean(activeThreadId) && !initialCached?.messages?.length);
|
|
853
|
+
const [isLoadingOlder, setIsLoadingOlder] = (0, import_react4.useState)(false);
|
|
854
|
+
const [hasOlderTurns, setHasOlderTurns] = (0, import_react4.useState)(Boolean(initialCached?.hasOlderTurns));
|
|
855
|
+
const [streamingContent, setStreamingContent] = (0, import_react4.useState)("");
|
|
856
|
+
const [streamingMessageId, setStreamingMessageId] = (0, import_react4.useState)(null);
|
|
857
|
+
const [contextStatus, setContextStatus] = (0, import_react4.useState)(null);
|
|
858
|
+
const [currentReasoning, setCurrentReasoning] = (0, import_react4.useState)([]);
|
|
859
|
+
const [liked, setLiked] = (0, import_react4.useState)({});
|
|
860
|
+
const [disliked, setDisliked] = (0, import_react4.useState)({});
|
|
861
|
+
const [copiedMessageId, setCopiedMessageId] = (0, import_react4.useState)(null);
|
|
862
|
+
const [lastThinkingDurationMs, setLastThinkingDurationMs] = (0, import_react4.useState)(null);
|
|
863
|
+
const [threads, setThreads] = (0, import_react4.useState)(() => storage.listThreads());
|
|
864
|
+
const [isRefreshingThreads, setIsRefreshingThreads] = (0, import_react4.useState)(false);
|
|
865
|
+
const [isSelectingThread, setIsSelectingThread] = (0, import_react4.useState)(false);
|
|
866
|
+
const [activeRunId, setActiveRunId] = (0, import_react4.useState)(null);
|
|
867
|
+
const textareaRef = (0, import_react4.useRef)(null);
|
|
868
|
+
const activeThreadIdRef = (0, import_react4.useRef)(activeThreadId);
|
|
869
|
+
const messagesRef = (0, import_react4.useRef)(messages);
|
|
870
|
+
const nextBeforeTurnIndexRef = (0, import_react4.useRef)(initialCached?.nextBeforeTurnIndex ?? null);
|
|
871
|
+
const hasOlderTurnsRef = (0, import_react4.useRef)(Boolean(initialCached?.hasOlderTurns));
|
|
872
|
+
const isLoadingOlderRef = (0, import_react4.useRef)(false);
|
|
873
|
+
const loadedThreadIdRef = (0, import_react4.useRef)(initialCached?.messages?.length ? activeThreadId : null);
|
|
874
|
+
const requestSeqRef = (0, import_react4.useRef)(0);
|
|
875
|
+
const isLoadingHistoryRef = (0, import_react4.useRef)(isLoadingHistory);
|
|
876
|
+
const activeRunIdRef = (0, import_react4.useRef)(null);
|
|
877
|
+
const reattachedRunIdRef = (0, import_react4.useRef)(null);
|
|
878
|
+
const abortControllerRef = (0, import_react4.useRef)(null);
|
|
879
|
+
const [lifecycleAbortController] = (0, import_react4.useState)(() => new AbortController());
|
|
880
|
+
const streamingContentRef = (0, import_react4.useRef)("");
|
|
881
|
+
const streamingMessageIdRef = (0, import_react4.useRef)(null);
|
|
882
|
+
const reasoningRef = (0, import_react4.useRef)([]);
|
|
883
|
+
const liveVoiceIdsRef = (0, import_react4.useRef)({});
|
|
884
|
+
const refreshSeqRef = (0, import_react4.useRef)(0);
|
|
885
|
+
const setActiveRunIdValue = (0, import_react4.useCallback)((runId) => {
|
|
783
886
|
activeRunIdRef.current = runId;
|
|
784
887
|
setActiveRunId(runId);
|
|
785
888
|
}, []);
|
|
786
|
-
const syncThreadsFromStorage = (0,
|
|
889
|
+
const syncThreadsFromStorage = (0, import_react4.useCallback)(() => {
|
|
787
890
|
setThreads(storage.listThreads());
|
|
788
891
|
}, [storage]);
|
|
789
|
-
const upsertStoredThread = (0,
|
|
892
|
+
const upsertStoredThread = (0, import_react4.useCallback)(
|
|
790
893
|
(thread) => {
|
|
791
894
|
storage.upsertThread(thread);
|
|
792
895
|
syncThreadsFromStorage();
|
|
793
896
|
},
|
|
794
897
|
[storage, syncThreadsFromStorage]
|
|
795
898
|
);
|
|
796
|
-
(0,
|
|
899
|
+
(0, import_react4.useEffect)(() => {
|
|
797
900
|
messagesRef.current = messages;
|
|
798
901
|
}, [messages]);
|
|
799
|
-
const persistThread = (0,
|
|
800
|
-
(threadId, nextMessages, paging,
|
|
902
|
+
const persistThread = (0, import_react4.useCallback)(
|
|
903
|
+
(threadId, nextMessages, paging, options2) => {
|
|
801
904
|
const existing = storage.getThread(threadId);
|
|
802
905
|
const firstUser = nextMessages.find((message) => message.role === "user");
|
|
803
906
|
upsertStoredThread({
|
|
804
907
|
...existing || {},
|
|
805
908
|
id: threadId,
|
|
806
909
|
title: existing?.title || (firstUser ? titleFromMessage(firstUser.content, firstUser.attachments || []) : "New chat"),
|
|
807
|
-
updated_at:
|
|
910
|
+
updated_at: options2?.updatedAt || (options2?.touch ? (/* @__PURE__ */ new Date()).toISOString() : existing?.updated_at) || (/* @__PURE__ */ new Date()).toISOString(),
|
|
808
911
|
messages: nextMessages,
|
|
809
912
|
isHydrated: true,
|
|
810
913
|
hasOlderTurns: paging?.hasOlderTurns ?? hasOlderTurnsRef.current,
|
|
@@ -813,7 +916,7 @@ function useAgents24ChatController({
|
|
|
813
916
|
},
|
|
814
917
|
[storage, upsertStoredThread]
|
|
815
918
|
);
|
|
816
|
-
const markThreadRunStatus = (0,
|
|
919
|
+
const markThreadRunStatus = (0, import_react4.useCallback)(
|
|
817
920
|
(threadId, runId, status, lastEventSeq) => {
|
|
818
921
|
const existing = storage.getThread(threadId);
|
|
819
922
|
if (!existing || !runId) return;
|
|
@@ -843,7 +946,7 @@ function useAgents24ChatController({
|
|
|
843
946
|
},
|
|
844
947
|
[storage, upsertStoredThread]
|
|
845
948
|
);
|
|
846
|
-
const refresh = (0,
|
|
949
|
+
const refresh = (0, import_react4.useCallback)(async () => {
|
|
847
950
|
const seq = ++refreshSeqRef.current;
|
|
848
951
|
setIsRefreshingThreads(true);
|
|
849
952
|
try {
|
|
@@ -857,7 +960,7 @@ function useAgents24ChatController({
|
|
|
857
960
|
if (!lifecycleAbortController.signal.aborted && seq === refreshSeqRef.current) setIsRefreshingThreads(false);
|
|
858
961
|
}
|
|
859
962
|
}, [lifecycleAbortController, storage, transport]);
|
|
860
|
-
const applyThreadId = (0,
|
|
963
|
+
const applyThreadId = (0, import_react4.useCallback)(
|
|
861
964
|
(threadId, baseMessages) => {
|
|
862
965
|
if (!threadId || activeThreadIdRef.current === threadId) return;
|
|
863
966
|
activeThreadIdRef.current = threadId;
|
|
@@ -871,15 +974,15 @@ function useAgents24ChatController({
|
|
|
871
974
|
streamingContentRef.current = value;
|
|
872
975
|
setStreamingContent(value);
|
|
873
976
|
};
|
|
874
|
-
const setLoadingHistory = (0,
|
|
977
|
+
const setLoadingHistory = (0, import_react4.useCallback)((value) => {
|
|
875
978
|
isLoadingHistoryRef.current = value;
|
|
876
979
|
setIsLoadingHistory(value);
|
|
877
980
|
}, []);
|
|
878
|
-
const setReasoningSteps = (0,
|
|
981
|
+
const setReasoningSteps = (0, import_react4.useCallback)((value) => {
|
|
879
982
|
reasoningRef.current = value || [];
|
|
880
983
|
setCurrentReasoning(value || []);
|
|
881
984
|
}, []);
|
|
882
|
-
const detachActiveStream = (0,
|
|
985
|
+
const detachActiveStream = (0, import_react4.useCallback)(() => {
|
|
883
986
|
const controller = abortControllerRef.current;
|
|
884
987
|
abortControllerRef.current = null;
|
|
885
988
|
abortDetachedStream(controller);
|
|
@@ -893,7 +996,7 @@ function useAgents24ChatController({
|
|
|
893
996
|
setStreamingContent("");
|
|
894
997
|
setCurrentReasoning([]);
|
|
895
998
|
}, [setActiveRunIdValue]);
|
|
896
|
-
const clearMissingThread = (0,
|
|
999
|
+
const clearMissingThread = (0, import_react4.useCallback)(
|
|
897
1000
|
(threadId) => {
|
|
898
1001
|
storage.deleteThread?.(threadId);
|
|
899
1002
|
syncThreadsFromStorage();
|
|
@@ -915,7 +1018,7 @@ function useAgents24ChatController({
|
|
|
915
1018
|
},
|
|
916
1019
|
[detachActiveStream, onActiveThreadIdChange, setLoadingHistory, storage, syncThreadsFromStorage]
|
|
917
1020
|
);
|
|
918
|
-
const setLiveAssistantMessage = (0,
|
|
1021
|
+
const setLiveAssistantMessage = (0, import_react4.useCallback)(
|
|
919
1022
|
(input) => {
|
|
920
1023
|
setMessages((prev) => {
|
|
921
1024
|
const next = upsertStableAssistantMessage(prev, {
|
|
@@ -947,7 +1050,7 @@ function useAgents24ChatController({
|
|
|
947
1050
|
},
|
|
948
1051
|
[]
|
|
949
1052
|
);
|
|
950
|
-
const finalizeAssistantMessage = (0,
|
|
1053
|
+
const finalizeAssistantMessage = (0, import_react4.useCallback)(
|
|
951
1054
|
(input) => {
|
|
952
1055
|
const content = input.error || input.assistantText.trim();
|
|
953
1056
|
if (!content) return input.baseMessages;
|
|
@@ -1001,7 +1104,7 @@ function useAgents24ChatController({
|
|
|
1001
1104
|
},
|
|
1002
1105
|
[createId, persistThread, storage, upsertStoredThread]
|
|
1003
1106
|
);
|
|
1004
|
-
const loadThread = (0,
|
|
1107
|
+
const loadThread = (0, import_react4.useCallback)(
|
|
1005
1108
|
async (threadId) => {
|
|
1006
1109
|
const seq = ++requestSeqRef.current;
|
|
1007
1110
|
setLoadingHistory(true);
|
|
@@ -1046,7 +1149,7 @@ function useAgents24ChatController({
|
|
|
1046
1149
|
},
|
|
1047
1150
|
[clearMissingThread, lifecycleAbortController, onThreadDetailLoaded, pageSize, setLoadingHistory, transport, upsertStoredThread]
|
|
1048
1151
|
);
|
|
1049
|
-
const loadOlderTurns = (0,
|
|
1152
|
+
const loadOlderTurns = (0, import_react4.useCallback)(async () => {
|
|
1050
1153
|
const threadId = activeThreadIdRef.current;
|
|
1051
1154
|
const beforeTurnIndex = nextBeforeTurnIndexRef.current;
|
|
1052
1155
|
if (!threadId || beforeTurnIndex === null || isLoadingOlderRef.current) return;
|
|
@@ -1082,7 +1185,7 @@ function useAgents24ChatController({
|
|
|
1082
1185
|
isLoadingOlderRef.current = false;
|
|
1083
1186
|
}
|
|
1084
1187
|
}, [clearMissingThread, lifecycleAbortController, pageSize, persistThread, transport]);
|
|
1085
|
-
const handleStreamEvent = (0,
|
|
1188
|
+
const handleStreamEvent = (0, import_react4.useCallback)(
|
|
1086
1189
|
(input) => {
|
|
1087
1190
|
const { mode, event, assistantMessageId, startedAt, streamThreadIdRef, baseMessages } = input;
|
|
1088
1191
|
const payload = event.payload || {};
|
|
@@ -1143,7 +1246,7 @@ function useAgents24ChatController({
|
|
|
1143
1246
|
},
|
|
1144
1247
|
[applyThreadId, finalizeAssistantMessage, markThreadRunStatus, onRuntimeEvent, onStreamErrorMessage, setActiveRunIdValue, setLiveAssistantMessage, setReasoningSteps]
|
|
1145
1248
|
);
|
|
1146
|
-
const runStream = (0,
|
|
1249
|
+
const runStream = (0, import_react4.useCallback)(
|
|
1147
1250
|
async (input) => {
|
|
1148
1251
|
const startedAt = Date.now();
|
|
1149
1252
|
const controller = new AbortController();
|
|
@@ -1266,18 +1369,26 @@ function useAgents24ChatController({
|
|
|
1266
1369
|
},
|
|
1267
1370
|
[createId, finalizeAssistantMessage, handleStreamEvent, onStreamErrorMessage, persistThread, refresh, setActiveRunIdValue, setReasoningSteps, transport]
|
|
1268
1371
|
);
|
|
1269
|
-
const handleSubmit = (0,
|
|
1372
|
+
const handleSubmit = (0, import_react4.useCallback)(
|
|
1270
1373
|
async (message) => {
|
|
1271
1374
|
if (!message.text.trim() && !(message.files || []).length) return;
|
|
1272
1375
|
await runStream({ mode: "submit", message });
|
|
1273
1376
|
},
|
|
1274
1377
|
[runStream]
|
|
1275
1378
|
);
|
|
1276
|
-
const attachRun = (0,
|
|
1379
|
+
const attachRun = (0, import_react4.useCallback)(async (runId, threadId) => {
|
|
1277
1380
|
const resolvedThreadId = threadId ?? activeThreadIdRef.current;
|
|
1278
1381
|
if (runId && resolvedThreadId) await runStream({ mode: "attach", runId, threadId: resolvedThreadId });
|
|
1279
1382
|
}, [runStream]);
|
|
1280
|
-
const
|
|
1383
|
+
const { pendingHitl, isResolvingHitl, resumeHitl } = useControllerHitl({
|
|
1384
|
+
messages,
|
|
1385
|
+
transport,
|
|
1386
|
+
activeRunId,
|
|
1387
|
+
activeRunIdRef,
|
|
1388
|
+
activeThreadIdRef,
|
|
1389
|
+
runStream
|
|
1390
|
+
});
|
|
1391
|
+
const handleStop = (0, import_react4.useCallback)(() => {
|
|
1281
1392
|
const runId = activeRunIdRef.current;
|
|
1282
1393
|
const partial = streamingContentRef.current;
|
|
1283
1394
|
const liveMessageId = streamingMessageIdRef.current;
|
|
@@ -1301,56 +1412,25 @@ function useAgents24ChatController({
|
|
|
1301
1412
|
});
|
|
1302
1413
|
}
|
|
1303
1414
|
}, [finalizeAssistantMessage, lastThinkingDurationMs, setActiveRunIdValue, setReasoningSteps, transport]);
|
|
1304
|
-
(0,
|
|
1415
|
+
(0, import_react4.useEffect)(() => {
|
|
1305
1416
|
refresh().catch((error) => {
|
|
1306
1417
|
if (!isAbortError(error) && !lifecycleAbortController.signal.aborted) {
|
|
1307
1418
|
setThreads(storage.listThreads());
|
|
1308
1419
|
}
|
|
1309
1420
|
});
|
|
1310
1421
|
}, [lifecycleAbortController, refresh, storage]);
|
|
1311
|
-
(0,
|
|
1422
|
+
(0, import_react4.useEffect)(() => {
|
|
1312
1423
|
return () => {
|
|
1313
1424
|
lifecycleAbortController.abort();
|
|
1314
1425
|
abortDetachedStream(abortControllerRef.current);
|
|
1315
1426
|
abortControllerRef.current = null;
|
|
1316
1427
|
};
|
|
1317
1428
|
}, [lifecycleAbortController]);
|
|
1318
|
-
(
|
|
1319
|
-
|
|
1320
|
-
let cancelled = false;
|
|
1321
|
-
let retryTimeout = null;
|
|
1322
|
-
let controller = null;
|
|
1323
|
-
const connect = () => {
|
|
1324
|
-
if (cancelled) return;
|
|
1325
|
-
controller = new AbortController();
|
|
1326
|
-
transport.subscribeThreadEvents?.(
|
|
1327
|
-
{ cursor: threadEventsCursorRef.current, signal: controller.signal },
|
|
1328
|
-
async (event) => {
|
|
1329
|
-
if (typeof event.cursor === "number") threadEventsCursorRef.current = event.cursor;
|
|
1330
|
-
if (event.event === "snapshot_required") {
|
|
1331
|
-
await refresh().catch(() => void 0);
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
const next = applyThreadSummaryEvent(storage.listThreads(), event);
|
|
1335
|
-
storage.setThreads(next);
|
|
1336
|
-
setThreads(storage.listThreads());
|
|
1337
|
-
}
|
|
1338
|
-
).catch((error) => {
|
|
1339
|
-
if (cancelled || isAbortError(error)) return;
|
|
1340
|
-
retryTimeout = setTimeout(connect, 1500);
|
|
1341
|
-
});
|
|
1342
|
-
};
|
|
1343
|
-
connect();
|
|
1344
|
-
return () => {
|
|
1345
|
-
cancelled = true;
|
|
1346
|
-
if (retryTimeout) clearTimeout(retryTimeout);
|
|
1347
|
-
controller?.abort();
|
|
1348
|
-
};
|
|
1349
|
-
}, [refresh, storage, transport]);
|
|
1350
|
-
(0, import_react2.useEffect)(() => {
|
|
1429
|
+
useControllerThreadEvents({ transport, storage, refresh, setThreads });
|
|
1430
|
+
(0, import_react4.useEffect)(() => {
|
|
1351
1431
|
syncThreadsFromStorage();
|
|
1352
1432
|
}, [storageKey, syncThreadsFromStorage]);
|
|
1353
|
-
(0,
|
|
1433
|
+
(0, import_react4.useEffect)(() => {
|
|
1354
1434
|
const previous = activeThreadIdRef.current;
|
|
1355
1435
|
activeThreadIdRef.current = activeThreadId;
|
|
1356
1436
|
if (activeThreadId && previous === activeThreadId && (activeRunIdRef.current || streamingMessageIdRef.current)) {
|
|
@@ -1394,14 +1474,14 @@ function useAgents24ChatController({
|
|
|
1394
1474
|
}
|
|
1395
1475
|
void loadThread(activeThreadId).catch(() => setLoadingHistory(false));
|
|
1396
1476
|
}, [activeThreadId, detachActiveStream, loadThread, setLoadingHistory, storage]);
|
|
1397
|
-
(0,
|
|
1477
|
+
(0, import_react4.useEffect)(() => {
|
|
1398
1478
|
const threadId = activeThreadId;
|
|
1399
1479
|
if (!threadId || isLoadingHistory || loadedThreadIdRef.current !== threadId || activeRunIdRef.current) return;
|
|
1400
1480
|
const runId = autoAttachRunIdFromThread(storage.getThread(threadId));
|
|
1401
1481
|
if (!runId || reattachedRunIdRef.current === runId) return;
|
|
1402
1482
|
void runStream({ mode: "attach", threadId, runId });
|
|
1403
1483
|
}, [activeThreadId, isLoadingHistory, runStream, storage, storageKey]);
|
|
1404
|
-
(0,
|
|
1484
|
+
(0, import_react4.useEffect)(() => {
|
|
1405
1485
|
const threadId = activeThreadId;
|
|
1406
1486
|
if (!threadId || isLoadingHistoryRef.current || activeRunIdRef.current || streamingMessageIdRef.current) {
|
|
1407
1487
|
return;
|
|
@@ -1442,7 +1522,7 @@ function useAgents24ChatController({
|
|
|
1442
1522
|
setMessages,
|
|
1443
1523
|
storage
|
|
1444
1524
|
});
|
|
1445
|
-
const loadThreadById = (0,
|
|
1525
|
+
const loadThreadById = (0, import_react4.useCallback)(
|
|
1446
1526
|
async (threadId) => {
|
|
1447
1527
|
if (!threadId) return;
|
|
1448
1528
|
setIsSelectingThread(true);
|
|
@@ -1461,7 +1541,7 @@ function useAgents24ChatController({
|
|
|
1461
1541
|
[detachActiveStream, loadThread, onActiveThreadIdChange, storage]
|
|
1462
1542
|
);
|
|
1463
1543
|
const activeThread = activeThreadId ? storage.getThread(activeThreadId) || threads.find((thread) => thread.id === activeThreadId) || null : null;
|
|
1464
|
-
return (0,
|
|
1544
|
+
return (0, import_react4.useMemo)(() => ({
|
|
1465
1545
|
threads,
|
|
1466
1546
|
activeThreadId,
|
|
1467
1547
|
activeThread,
|
|
@@ -1481,8 +1561,11 @@ function useAgents24ChatController({
|
|
|
1481
1561
|
copiedMessageId,
|
|
1482
1562
|
lastThinkingDurationMs,
|
|
1483
1563
|
activeRunId,
|
|
1564
|
+
pendingHitl,
|
|
1565
|
+
isResolvingHitl,
|
|
1484
1566
|
handleSubmit,
|
|
1485
1567
|
attachRun,
|
|
1568
|
+
resumeHitl,
|
|
1486
1569
|
handleStop,
|
|
1487
1570
|
handleCopy,
|
|
1488
1571
|
handleLike,
|
|
@@ -1521,8 +1604,11 @@ function useAgents24ChatController({
|
|
|
1521
1604
|
loadThreadById,
|
|
1522
1605
|
loadOlderTurns,
|
|
1523
1606
|
messages,
|
|
1607
|
+
isResolvingHitl,
|
|
1524
1608
|
onSourceClick,
|
|
1609
|
+
pendingHitl,
|
|
1525
1610
|
refresh,
|
|
1611
|
+
resumeHitl,
|
|
1526
1612
|
streamingContent,
|
|
1527
1613
|
streamingMessageId,
|
|
1528
1614
|
startNewThread,
|
|
@@ -1992,7 +2078,7 @@ var consumeSseResponse = async (response, onEvent, options = {}) => {
|
|
|
1992
2078
|
};
|
|
1993
2079
|
|
|
1994
2080
|
// src/streaming-text.ts
|
|
1995
|
-
var
|
|
2081
|
+
var import_react5 = require("react");
|
|
1996
2082
|
var DEFAULT_COMPLETED_TEXT_CACHE_SIZE = 200;
|
|
1997
2083
|
var defaultCompletedTextCache = /* @__PURE__ */ new Map();
|
|
1998
2084
|
var defaultStreamingTextCache = {
|
|
@@ -2020,24 +2106,24 @@ function useStreamingText({
|
|
|
2020
2106
|
maxCatchupChars = 20
|
|
2021
2107
|
}) {
|
|
2022
2108
|
const cacheAdapter = cache === false ? null : cache;
|
|
2023
|
-
const [displayedText, setDisplayedText] = (0,
|
|
2109
|
+
const [displayedText, setDisplayedText] = (0, import_react5.useState)(() => {
|
|
2024
2110
|
const cachedText = cacheAdapter?.get(id);
|
|
2025
2111
|
return isStreaming && cachedText !== text ? "" : text;
|
|
2026
2112
|
});
|
|
2027
|
-
const targetRef = (0,
|
|
2028
|
-
const displayedRef = (0,
|
|
2029
|
-
const rafRef = (0,
|
|
2030
|
-
const lastFrameAtRef = (0,
|
|
2031
|
-
const idRef = (0,
|
|
2032
|
-
const shouldAnimateRef = (0,
|
|
2033
|
-
(0,
|
|
2113
|
+
const targetRef = (0, import_react5.useRef)(text);
|
|
2114
|
+
const displayedRef = (0, import_react5.useRef)(displayedText);
|
|
2115
|
+
const rafRef = (0, import_react5.useRef)(null);
|
|
2116
|
+
const lastFrameAtRef = (0, import_react5.useRef)(null);
|
|
2117
|
+
const idRef = (0, import_react5.useRef)(id);
|
|
2118
|
+
const shouldAnimateRef = (0, import_react5.useRef)(isStreaming);
|
|
2119
|
+
(0, import_react5.useEffect)(() => {
|
|
2034
2120
|
if (isStreaming || !text) return;
|
|
2035
2121
|
cacheAdapter?.set(id, text);
|
|
2036
2122
|
}, [cacheAdapter, id, isStreaming, text]);
|
|
2037
|
-
(0,
|
|
2123
|
+
(0, import_react5.useEffect)(() => {
|
|
2038
2124
|
targetRef.current = text;
|
|
2039
2125
|
}, [text]);
|
|
2040
|
-
(0,
|
|
2126
|
+
(0, import_react5.useEffect)(() => {
|
|
2041
2127
|
if (idRef.current === id) return;
|
|
2042
2128
|
idRef.current = id;
|
|
2043
2129
|
const cachedText = cacheAdapter?.get(id);
|
|
@@ -2051,7 +2137,7 @@ function useStreamingText({
|
|
|
2051
2137
|
}
|
|
2052
2138
|
lastFrameAtRef.current = null;
|
|
2053
2139
|
}, [cacheAdapter, id, isStreaming, text]);
|
|
2054
|
-
(0,
|
|
2140
|
+
(0, import_react5.useEffect)(() => {
|
|
2055
2141
|
if (typeof window === "undefined") {
|
|
2056
2142
|
displayedRef.current = text;
|
|
2057
2143
|
setDisplayedText(text);
|
|
@@ -2229,9 +2315,10 @@ var createFetchChatTransport = ({
|
|
|
2229
2315
|
method: "POST",
|
|
2230
2316
|
headers: jsonHeaders(await loadHeaders()),
|
|
2231
2317
|
body: JSON.stringify({
|
|
2232
|
-
schema_version: "agents24.hitl.resume.
|
|
2318
|
+
schema_version: "agents24.hitl.resume.v2",
|
|
2233
2319
|
interrupt_id: input.interruptId,
|
|
2234
|
-
|
|
2320
|
+
action: input.action,
|
|
2321
|
+
comment: input.comment,
|
|
2235
2322
|
client: input.client
|
|
2236
2323
|
})
|
|
2237
2324
|
});
|