@springbrand/chat-client 0.1.3-alpha.45 → 0.1.3-alpha.47
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/package.json +2 -2
- package/src/use-universal-agent-chat.ts +24 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@springbrand/chat-client",
|
|
3
|
-
"version": "0.1.3-alpha.
|
|
3
|
+
"version": "0.1.3-alpha.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@types/react-dom": "^19.2.5",
|
|
28
28
|
"react-dom": "^19.2.8",
|
|
29
29
|
"typescript": "^7.0.2",
|
|
30
|
-
"@springbrand/agent-runtime": "0.2.0-alpha.
|
|
30
|
+
"@springbrand/agent-runtime": "0.2.0-alpha.63"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"typecheck": "tsc --noEmit"
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type RuntimeConfigUpdateResult,
|
|
27
27
|
type RuntimeQueuedSubmission,
|
|
28
28
|
type RuntimeState,
|
|
29
|
+
type RuntimeTurnState,
|
|
29
30
|
} from "@springbrand/agent-runtime/contracts";
|
|
30
31
|
import { createSafeUIMessageAgentConnection } from "./ui-message-stream-guard";
|
|
31
32
|
import { CURRENT_INBOX_AGENT_PATH } from "./chat-sessions";
|
|
@@ -90,26 +91,6 @@ type ChatApproval = {
|
|
|
90
91
|
requestId: string;
|
|
91
92
|
};
|
|
92
93
|
|
|
93
|
-
type ChatQueuedSubmission = {
|
|
94
|
-
submissionId: string;
|
|
95
|
-
messageId: string;
|
|
96
|
-
preview: string;
|
|
97
|
-
position: number;
|
|
98
|
-
createdAt: number;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
type ChatTurn = {
|
|
102
|
-
activeSubmissionId?: string;
|
|
103
|
-
activeRequestId?: string;
|
|
104
|
-
activeMessageId?: string;
|
|
105
|
-
recoveryAttempt?: number;
|
|
106
|
-
recoveryMax?: number;
|
|
107
|
-
recoveryReason?: "no_meaningful_model_progress" | "transient_model_error";
|
|
108
|
-
steerable: boolean;
|
|
109
|
-
hasPendingSteer: boolean;
|
|
110
|
-
queued: ChatQueuedSubmission[];
|
|
111
|
-
};
|
|
112
|
-
|
|
113
94
|
export interface ChatRuntime {
|
|
114
95
|
messages: ChatMessage[];
|
|
115
96
|
status: ChatStatus;
|
|
@@ -177,7 +158,7 @@ export interface ChatRuntime {
|
|
|
177
158
|
isToolContinuation: boolean;
|
|
178
159
|
approvals: ChatApproval[] | undefined;
|
|
179
160
|
approvalsLoaded: boolean;
|
|
180
|
-
turn:
|
|
161
|
+
turn: RuntimeTurnState | undefined;
|
|
181
162
|
turnActive: boolean;
|
|
182
163
|
canSteer: boolean;
|
|
183
164
|
}
|
|
@@ -558,34 +539,46 @@ export function useUniversalAgentChat(): ChatRuntime {
|
|
|
558
539
|
: authoritativeStatus;
|
|
559
540
|
const messagesRef = useRef(messages);
|
|
560
541
|
messagesRef.current = messages;
|
|
561
|
-
|
|
542
|
+
// SDK callback identities can change without a new recovery request.
|
|
543
|
+
const replayActionsRef = useRef({ setMessages, clearError });
|
|
544
|
+
replayActionsRef.current = { setMessages, clearError };
|
|
562
545
|
useEffect(() => {
|
|
563
546
|
const activeMessageId = facetState?.turn?.activeMessageId;
|
|
564
547
|
if (
|
|
565
548
|
!activeMessageId ||
|
|
566
549
|
sdkStatus !== "error" ||
|
|
567
550
|
sdkIsRecovering ||
|
|
568
|
-
isServerStreaming
|
|
569
|
-
replayFallbackMessageIdRef.current === activeMessageId
|
|
551
|
+
isServerStreaming
|
|
570
552
|
) return;
|
|
571
553
|
const url = chatAgent.getHttpUrl();
|
|
572
554
|
if (!url) return;
|
|
573
|
-
|
|
555
|
+
const baseline = messagesRef.current;
|
|
556
|
+
let cancelled = false;
|
|
574
557
|
void loadInitialMessages(url, connection.credentials, "full")
|
|
575
558
|
.then((snapshot) => {
|
|
576
|
-
|
|
577
|
-
|
|
559
|
+
if (cancelled) return;
|
|
560
|
+
// The SDK protects its own snapshots while streaming. This HTTP
|
|
561
|
+
// fallback must also reject a response older than the current store.
|
|
562
|
+
const actions = replayActionsRef.current;
|
|
563
|
+
let applied = false;
|
|
564
|
+
actions.setMessages((current) => {
|
|
565
|
+
if (current !== baseline) return current;
|
|
566
|
+
applied = true;
|
|
567
|
+
return snapshot;
|
|
568
|
+
});
|
|
569
|
+
if (applied) actions.clearError();
|
|
578
570
|
})
|
|
579
571
|
.catch(() => undefined);
|
|
572
|
+
return () => {
|
|
573
|
+
cancelled = true;
|
|
574
|
+
};
|
|
580
575
|
}, [
|
|
581
576
|
chatAgent,
|
|
582
|
-
clearError,
|
|
583
577
|
connection.credentials,
|
|
584
578
|
facetState?.turn?.activeMessageId,
|
|
585
579
|
isServerStreaming,
|
|
586
580
|
sdkIsRecovering,
|
|
587
581
|
sdkStatus,
|
|
588
|
-
setMessages,
|
|
589
582
|
]);
|
|
590
583
|
const turnTimingRef = useRef<ChatTurnTiming | null>(null);
|
|
591
584
|
|
|
@@ -781,7 +774,7 @@ export function useUniversalAgentChat(): ChatRuntime {
|
|
|
781
774
|
markChatTurnPhase(turnTimingRef.current, "rpcReceipt");
|
|
782
775
|
}
|
|
783
776
|
if (receipt.kind === "rejected") {
|
|
784
|
-
|
|
777
|
+
rollback();
|
|
785
778
|
if (turnTimingRef.current?.messageId === message.id) {
|
|
786
779
|
turnTimingRef.current = null;
|
|
787
780
|
}
|
|
@@ -849,7 +842,7 @@ export function useUniversalAgentChat(): ChatRuntime {
|
|
|
849
842
|
}
|
|
850
843
|
return true;
|
|
851
844
|
} catch (cause) {
|
|
852
|
-
|
|
845
|
+
rollback();
|
|
853
846
|
if (turnTimingRef.current?.messageId === message.id) {
|
|
854
847
|
turnTimingRef.current = null;
|
|
855
848
|
}
|