@springbrand/chat-client 0.1.3-alpha.40 → 0.1.3-alpha.41

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/chat-client",
3
- "version": "0.1.3-alpha.40",
3
+ "version": "0.1.3-alpha.41",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -13,6 +13,7 @@
13
13
  ".": "./src/index.ts"
14
14
  },
15
15
  "peerDependencies": {
16
+ "@cloudflare/ai-chat": "^0.11.0",
16
17
  "agents": "^0.22.0",
17
18
  "ai": "^7.0.0",
18
19
  "react": "^19.0.0"
@@ -21,11 +22,12 @@
21
22
  "nanoid": "^5.1.16"
22
23
  },
23
24
  "devDependencies": {
24
- "@types/react": "^19.2.17",
25
- "@types/react-dom": "^19.2.3",
26
- "react-dom": "^19.2.7",
25
+ "@cloudflare/ai-chat": "0.11.0",
26
+ "@types/react": "^19.2.18",
27
+ "@types/react-dom": "^19.2.5",
28
+ "react-dom": "^19.2.8",
27
29
  "typescript": "^7.0.2",
28
- "@springbrand/agent-runtime": "0.2.0-alpha.51"
30
+ "@springbrand/agent-runtime": "0.2.0-alpha.53"
29
31
  },
30
32
  "scripts": {
31
33
  "typecheck": "tsc --noEmit"
@@ -15,7 +15,7 @@ import type { ChatStatus, FileUIPart, UIMessage } from "ai";
15
15
  import type { AgentToolRunState } from "agents";
16
16
  import type { AgentConnectionError } from "agents/client";
17
17
  import { MessageType } from "agents/chat";
18
- import { getAgentMessages, useAgentChat } from "agents/chat/react";
18
+ import { getAgentMessages, useAgentChat } from "@cloudflare/ai-chat/react";
19
19
  import { useAgent, useAgentToolEvents } from "agents/react";
20
20
  import {
21
21
  type ApprovalDecision,
@@ -95,6 +95,7 @@ type ChatQueuedSubmission = {
95
95
  type ChatTurn = {
96
96
  activeSubmissionId?: string;
97
97
  activeRequestId?: string;
98
+ activeMessageId?: string;
98
99
  recoveryAttempt?: number;
99
100
  recoveryMax?: number;
100
101
  recoveryReason?: "no_meaningful_model_progress" | "transient_model_error";
@@ -382,10 +383,12 @@ function queuedPreview(message: ChatMessage): string {
382
383
  function loadInitialMessages(
383
384
  url: string | undefined,
384
385
  credentials: RequestCredentials | undefined,
386
+ view: "hydration" | "full" = "hydration",
385
387
  ): Promise<ChatMessage[]> {
386
388
  if (!url) return Promise.resolve([]);
387
389
  const messagesUrl = new URL(url);
388
390
  messagesUrl.pathname = `${messagesUrl.pathname.replace(/\/$/, "")}/get-messages`;
391
+ if (view === "hydration") messagesUrl.searchParams.set("view", "hydration");
389
392
  return getAgentMessages({
390
393
  url: messagesUrl.toString(),
391
394
  ...(credentials === undefined ? {} : { credentials }),
@@ -449,7 +452,6 @@ export function useUniversalAgentChat(): ChatRuntime {
449
452
  ? {}
450
453
  : { credentials: connection.credentials }),
451
454
  syncMessagesToServer: false,
452
- throttle: 16,
453
455
  });
454
456
  // The SDK keeps its advisory recovery flag until terminal settlement; a
455
457
  // live server stream proves the recovered Turn is executing again.
@@ -481,14 +483,15 @@ export function useUniversalAgentChat(): ChatRuntime {
481
483
  const runtimeErrorMessage = runtimeError instanceof Error
482
484
  ? runtimeError.message
483
485
  : runtimeError;
484
- const presentationError = latestTurnStatus === "error" &&
485
- latestMessage?.metadata?.error === runtimeErrorMessage
486
+ const presentationError = isServerStreaming || isRecovering ||
487
+ (latestTurnStatus === "error" && latestMessage?.metadata?.error === runtimeErrorMessage)
486
488
  ? undefined
487
489
  : runtimeError;
488
490
  // RPC admissions bypass useChat's request lifecycle. Project the durable
489
491
  // Turn here so presentation stays correct without a second send path.
490
- const authoritativeStatus =
491
- normalizedSdkStatus === "ready" &&
492
+ const authoritativeStatus = isServerStreaming
493
+ ? "streaming"
494
+ : normalizedSdkStatus === "ready" &&
492
495
  !isRecovering &&
493
496
  approvals?.length === 0 &&
494
497
  authoritativeTurn?.activeSubmissionId
@@ -506,6 +509,35 @@ export function useUniversalAgentChat(): ChatRuntime {
506
509
  : authoritativeStatus;
507
510
  const messagesRef = useRef(messages);
508
511
  messagesRef.current = messages;
512
+ const replayFallbackMessageIdRef = useRef<string | undefined>(undefined);
513
+ useEffect(() => {
514
+ const activeMessageId = facetState?.turn?.activeMessageId;
515
+ if (
516
+ !activeMessageId ||
517
+ sdkStatus !== "error" ||
518
+ sdkIsRecovering ||
519
+ isServerStreaming ||
520
+ replayFallbackMessageIdRef.current === activeMessageId
521
+ ) return;
522
+ const url = chatAgent.getHttpUrl();
523
+ if (!url) return;
524
+ replayFallbackMessageIdRef.current = activeMessageId;
525
+ void loadInitialMessages(url, connection.credentials, "full")
526
+ .then((snapshot) => {
527
+ setMessages(snapshot);
528
+ clearError();
529
+ })
530
+ .catch(() => undefined);
531
+ }, [
532
+ chatAgent,
533
+ clearError,
534
+ connection.credentials,
535
+ facetState?.turn?.activeMessageId,
536
+ isServerStreaming,
537
+ sdkIsRecovering,
538
+ sdkStatus,
539
+ setMessages,
540
+ ]);
509
541
  const turnTimingRef = useRef<ChatTurnTiming | null>(null);
510
542
 
511
543
  useEffect(() => {