@mastra/react 1.13.0-alpha.4 → 1.13.0-alpha.6

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.
@@ -0,0 +1,17 @@
1
+ import type { AggregateTracesArgs, AggregateTracesResponse } from '@mastra/client-js';
2
+ import type { UseQueryResult } from '@tanstack/react-query';
3
+ import type { MastraQueryOptions } from '../shared/query-options.js';
4
+ export interface UseTraceAggregateArgs<TData = AggregateTracesResponse> {
5
+ request: AggregateTracesArgs;
6
+ enabled?: boolean;
7
+ queryOptions?: MastraQueryOptions<AggregateTracesResponse, TData>;
8
+ }
9
+ /**
10
+ * Runs `aggregateTraces()` for `request`. Check `useTraceAggregateAvailable()` before enabling it.
11
+ *
12
+ * It doesn't poll: grouped requests over large tenants take seconds, so it refetches only when the
13
+ * request changes or the caller calls `refetch()`. The client already retries server errors, so
14
+ * React Query doesn't retry on top of it, and a rejected request (4xx) fails once.
15
+ */
16
+ export declare function useTraceAggregate<TData = AggregateTracesResponse>({ request, enabled, queryOptions, }: UseTraceAggregateArgs<TData>): UseQueryResult<TData, Error>;
17
+ //# sourceMappingURL=use-trace-aggregate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-trace-aggregate.d.ts","sourceRoot":"","sources":["../../../src/hooks/traces/use-trace-aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,WAAW,qBAAqB,CAAC,KAAK,GAAG,uBAAuB;IACpE,OAAO,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;CACnE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,GAAG,uBAAuB,EAAE,EACjE,OAAO,EACP,OAAc,EACd,YAAY,GACb,EAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAU7D"}
@@ -1,6 +1,8 @@
1
+ export type TraceColumnPreferencesScope = 'traces' | 'spans';
1
2
  /**
2
3
  * Storage key for the trace list column preferences, scoped to the Mastra server the client
3
- * talks to so each project keeps its own column layout.
4
+ * talks to so each project keeps its own column layout, and to the list (traces or spans)
5
+ * so each list keeps its own selection.
4
6
  */
5
- export declare function useTraceColumnPreferencesStorageKey(): string;
7
+ export declare function useTraceColumnPreferencesStorageKey(scope?: TraceColumnPreferencesScope): string;
6
8
  //# sourceMappingURL=use-trace-column-preferences-storage-key.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-trace-column-preferences-storage-key.d.ts","sourceRoot":"","sources":["../../../src/hooks/traces/use-trace-column-preferences-storage-key.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,mCAAmC,IAAI,MAAM,CAM5D"}
1
+ {"version":3,"file":"use-trace-column-preferences-storage-key.d.ts","sourceRoot":"","sources":["../../../src/hooks/traces/use-trace-column-preferences-storage-key.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,2BAA2B,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,GAAE,2BAAsC,GAAG,MAAM,CAMzG"}
@@ -373,6 +373,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
373
373
  const liveApprovalIds = (0, react.useRef)(/* @__PURE__ */ new Set());
374
374
  const liveRunId = (0, react.useRef)(void 0);
375
375
  const liveRunFinished = (0, react.useRef)(false);
376
+ const pendingRunStatuses = (0, react.useRef)(void 0);
376
377
  const [isAwaitingToolApproval, setIsAwaitingToolApproval] = (0, react.useState)(false);
377
378
  const baseClient = require_mastra_client_context.useMastraClient();
378
379
  const [isRunning, setIsRunning] = (0, react.useState)(false);
@@ -589,6 +590,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
589
590
  _threadSubscriptionPromiseRef.current = subscriptionAgent.subscribeToThread({
590
591
  resourceId,
591
592
  threadId,
593
+ withRunStatus: true,
592
594
  ...withInitialHistory ? { withInitialHistory } : {}
593
595
  }).then((response) => {
594
596
  const subscription = response;
@@ -600,7 +602,13 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
600
602
  subscription.processDataStream({ onChunk: (chunk) => {
601
603
  if (chunk.type === "thread-history") {
602
604
  if (_threadSubscriptionAbortRef.current === subscriptionAbort) {
603
- const { hasMore } = chunk.payload;
605
+ const { hasMore, activeRunId } = chunk.payload;
606
+ if (activeRunId && activeRunId !== liveRunId.current && (!liveRunId.current || liveRunFinished.current)) {
607
+ liveRunId.current = activeRunId;
608
+ liveRunFinished.current = false;
609
+ _currentRunId.current = activeRunId;
610
+ setIsRunning(pendingToolApprovalIdsRef.current.size === 0);
611
+ }
604
612
  setSubscriptionPagination(typeof hasMore === "boolean" ? {
605
613
  key: subscriptionKey,
606
614
  pagination: { hasMore }
@@ -619,6 +627,20 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
619
627
  });
620
628
  return;
621
629
  }
630
+ if (chunk.type === "thread-run-status") {
631
+ if (chunk.runId !== liveRunId.current) {
632
+ pendingRunStatuses.current?.set(chunk.runId, chunk);
633
+ return;
634
+ }
635
+ setIsRunning(false);
636
+ if (chunk.payload.status !== "suspended") {
637
+ liveRunFinished.current = true;
638
+ for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);
639
+ pendingToolApprovalIdsRef.current.clear();
640
+ setIsAwaitingToolApproval(false);
641
+ }
642
+ return;
643
+ }
622
644
  return processStreamChunk(chunk);
623
645
  } }).catch((error) => {
624
646
  if (!isAbortError(error)) {
@@ -855,6 +877,9 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
855
877
  clientTools: resolvedClientTools,
856
878
  clientToolsResolver
857
879
  };
880
+ const liveRunIdBeforeSend = liveRunId.current;
881
+ const earlyRunStatuses = /* @__PURE__ */ new Map();
882
+ pendingRunStatuses.current = earlyRunStatuses;
858
883
  try {
859
884
  const result = await agent.sendMessage({
860
885
  message: clientMessageId || metadata ? {
@@ -873,6 +898,23 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
873
898
  clientToolsResolver
874
899
  } }
875
900
  });
901
+ if (_streamAbortRef.current === internalAbort && liveRunId.current === liveRunIdBeforeSend && liveRunId.current !== result.runId) {
902
+ liveApprovalIds.current.clear();
903
+ liveRunId.current = result.runId;
904
+ liveRunFinished.current = false;
905
+ _currentRunId.current = result.runId;
906
+ setIsRunning(true);
907
+ const earlyStatus = earlyRunStatuses.get(result.runId);
908
+ if (earlyStatus) {
909
+ setIsRunning(false);
910
+ if (earlyStatus.payload.status !== "suspended") {
911
+ liveRunFinished.current = true;
912
+ for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);
913
+ pendingToolApprovalIdsRef.current.clear();
914
+ setIsAwaitingToolApproval(false);
915
+ }
916
+ }
917
+ }
876
918
  const echoedSignalId = result.signal && typeof result.signal === "object" && "id" in result.signal && typeof result.signal.id === "string" ? result.signal.id : resolvedSignalId;
877
919
  onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));
878
920
  if (pendingToolApprovalIdsRef.current.size > 0) setIsRunning(false);
@@ -902,6 +944,8 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
902
944
  throw signalError;
903
945
  }
904
946
  throw error;
947
+ } finally {
948
+ if (pendingRunStatuses.current === earlyRunStatuses) pendingRunStatuses.current = void 0;
905
949
  }
906
950
  if (_streamAbortRef.current === internalAbort) _streamAbortRef.current = null;
907
951
  };
@@ -1300,4 +1344,4 @@ Object.defineProperty(exports, "useChat", {
1300
1344
  }
1301
1345
  });
1302
1346
 
1303
- //# sourceMappingURL=hooks-D6LDSEcm.cjs.map
1347
+ //# sourceMappingURL=hooks-Czqwakn0.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-Czqwakn0.cjs","names":["encodeFilePartDataForStorage","exhaustiveCheck","isDataChunk","isRecord","CLIENT_MESSAGE_ID_KEY","isRecord","CLIENT_MESSAGE_ID_KEY","AIV5Adapter","useRef","useState","useMastraClient","convertSignalDataToBase64String","useCallback","accumulateChunk","MastraClient","uuid","accumulateNetworkChunk","finishStreamingAssistantMessage"],"sources":["../src/lib/mastra-db/fromCoreUserMessage.ts","../src/agent/extract-tasks.ts","../src/agent/extractRunIdFromMessages.ts","../src/agent/merge-history.ts","../src/agent/user-message.ts","../src/agent/hooks.ts"],"sourcesContent":["import type { MastraDBMessage, MastraMessagePart } from '@mastra/core/agent/message-list';\nimport type { CoreUserMessage } from '@mastra/core/llm';\nimport { encodeFilePartDataForStorage } from '../../agent/signal-data';\n\n/**\n * Convert a CoreUserMessage into a canonical `MastraDBMessage` (`format: 2`).\n *\n * Image and file inputs are emitted as the canonical V4 `file` part shape\n * (`{ type: 'file', mimeType, data }`) — the exact shape memory resolves on\n * reload (see `AIV4Adapter`), so optimistic-send and reload render identically.\n *\n * Handles all CoreUserMessage content types:\n * - String content → single text part\n * - Array content with text/image/file parts → corresponding `MastraMessagePart`s\n */\nconst coreUserMessageToParts = (coreUserMessage: CoreUserMessage): MastraMessagePart[] =>\n typeof coreUserMessage.content === 'string'\n ? [{ type: 'text' as const, text: coreUserMessage.content }]\n : coreUserMessage.content.map((part): MastraMessagePart => {\n switch (part.type) {\n case 'text': {\n return { type: 'text' as const, text: part.text };\n }\n case 'image': {\n const mimeType = part.mimeType ?? 'image/*';\n return {\n type: 'file' as const,\n mimeType,\n data: encodeFilePartDataForStorage(part.image, mimeType),\n };\n }\n case 'file': {\n return {\n type: 'file' as const,\n mimeType: part.mimeType,\n data: encodeFilePartDataForStorage(part.data, part.mimeType),\n ...(part.filename !== undefined ? { filename: part.filename } : {}),\n };\n }\n default: {\n const exhaustiveCheck: never = part;\n throw new Error(`Unhandled content part type: ${(exhaustiveCheck as { type: string }).type}`);\n }\n }\n });\n\nconst newUserMessage = (parts: MastraMessagePart[]): MastraDBMessage => ({\n id: `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,\n role: 'user',\n createdAt: new Date(),\n content: {\n format: 2,\n parts,\n },\n});\n\nexport const fromCoreUserMessageToMastraDBMessage = (coreUserMessage: CoreUserMessage): MastraDBMessage =>\n newUserMessage(coreUserMessageToParts(coreUserMessage));\n\n/**\n * Merge multiple `CoreUserMessage`s into a single canonical `MastraDBMessage`.\n *\n * A user turn that carries attachments arrives as several `CoreUserMessage`s\n * (one for the text, one per attachment). Flatten their parts for the optimistic\n * display. The send path must also submit a single multipart message: this\n * display conversion alone cannot combine separately persisted messages.\n */\nexport const fromCoreUserMessagesToMastraDBMessage = (coreUserMessages: CoreUserMessage[]): MastraDBMessage =>\n newUserMessage(coreUserMessages.flatMap(coreUserMessageToParts));\n","import type { MastraDBMessage } from '@mastra/core/agent/message-list';\nimport type { TaskItem } from '@mastra/core/signals';\nimport type { ChunkType, DataChunkType } from '@mastra/core/stream';\n\nexport const TASK_TOOL_NAMES = new Set(['task_write', 'task_update', 'task_complete', 'task_check']);\nconst TASK_SIGNAL_ID = 'tasks';\nconst TASK_TAG_NAMES = new Set(['current-task-list', 'task-list-update']);\nconst TASK_STATUSES = new Set(['pending', 'in_progress', 'completed']);\n\ntype DataChunk = Extract<ChunkType, DataChunkType>;\n\nconst isDataChunk = (chunk: ChunkType): chunk is DataChunk =>\n typeof chunk.type === 'string' && chunk.type.startsWith('data-');\n\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isTaskStatus = (value: unknown): value is TaskItem['status'] =>\n typeof value === 'string' && TASK_STATUSES.has(value);\n\nexport const isTaskItemArray = (value: unknown): value is TaskItem[] =>\n Array.isArray(value) &&\n value.every(\n item =>\n isRecord(item) &&\n typeof item.id === 'string' &&\n typeof item.content === 'string' &&\n isTaskStatus(item.status) &&\n typeof item.activeForm === 'string',\n );\n\nconst isTaskSignal = (value: unknown): boolean => {\n if (!isRecord(value)) return false;\n return value.id === TASK_SIGNAL_ID || (typeof value.tagName === 'string' && TASK_TAG_NAMES.has(value.tagName));\n};\n\nconst extractTasksFromSignalData = (data: unknown): TaskItem[] | undefined => {\n if (!isTaskSignal(data) || !isRecord(data)) return undefined;\n const metadata = data.metadata;\n if (!isRecord(metadata)) return undefined;\n const value = metadata.value;\n if (!isRecord(value)) return undefined;\n return isTaskItemArray(value.tasks) ? value.tasks : undefined;\n};\n\nconst parseTasksFromResult = (raw: unknown): TaskItem[] | undefined => {\n if (isRecord(raw) && isTaskItemArray(raw.tasks)) return raw.tasks;\n\n if (typeof raw !== 'string') return undefined;\n\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) && isTaskItemArray(parsed.tasks) ? parsed.tasks : undefined;\n } catch {\n return undefined;\n }\n};\n\nexport const extractTasksFromSignalChunk = (chunk: ChunkType): TaskItem[] | undefined => {\n if (!isDataChunk(chunk)) return undefined;\n return extractTasksFromSignalData(chunk.data);\n};\n\nexport const extractTasksFromToolResultChunk = (chunk: ChunkType): TaskItem[] | undefined => {\n if (chunk.type !== 'tool-result') return undefined;\n const payload = chunk.payload;\n if (!isRecord(payload) || typeof payload.toolName !== 'string' || !TASK_TOOL_NAMES.has(payload.toolName)) {\n return undefined;\n }\n return parseTasksFromResult(payload.result);\n};\n\nconst extractTasksFromToolInvocationPart = (part: unknown): TaskItem[] | undefined => {\n if (!isRecord(part) || part.type !== 'tool-invocation' || !isRecord(part.toolInvocation)) return undefined;\n const toolInvocation = part.toolInvocation;\n if (typeof toolInvocation.toolName !== 'string' || !TASK_TOOL_NAMES.has(toolInvocation.toolName)) return undefined;\n return parseTasksFromResult(toolInvocation.result);\n};\n\nconst extractTasksFromDataPart = (part: unknown): TaskItem[] | undefined => {\n if (!isRecord(part) || typeof part.type !== 'string' || !part.type.startsWith('data-')) return undefined;\n return extractTasksFromSignalData(part.data);\n};\n\nconst extractTasksFromSignalMessage = (message: MastraDBMessage): TaskItem[] | undefined => {\n if (message.role !== 'signal') return undefined;\n const metadata = message.content?.metadata;\n if (!isRecord(metadata)) return undefined;\n return extractTasksFromSignalData(metadata.signal);\n};\n\nexport const extractLatestTasksFromMessages = (messages: MastraDBMessage[]): TaskItem[] => {\n let latest: TaskItem[] | undefined;\n\n for (const message of messages) {\n for (const part of message.content?.parts ?? []) {\n const toolTasks = extractTasksFromToolInvocationPart(part);\n if (toolTasks !== undefined) latest = toolTasks;\n }\n\n const signalTasks = extractTasksFromSignalMessage(message);\n if (signalTasks !== undefined) latest = signalTasks;\n\n for (const part of message.content?.parts ?? []) {\n const dataTasks = extractTasksFromDataPart(part);\n if (dataTasks !== undefined) latest = dataTasks;\n }\n }\n\n return latest ?? [];\n};\n","import type { MastraDBMessage } from '@mastra/core/agent/message-list';\n\ntype RunIdMetadataEntry = { runId?: unknown };\ntype RunIdMetadataSource = Record<string, RunIdMetadataEntry>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object';\n\nconst runIdMetadataKeys = ['pendingToolApprovals', 'requireApprovalMetadata', 'suspendedTools'] as const;\n\nconst isRunIdMetadataSource = (value: unknown): value is RunIdMetadataSource =>\n isRecord(value) && Object.values(value).every(entry => isRecord(entry));\n\nconst getRunIdMetadataSources = (metadata: unknown): RunIdMetadataSource[] => {\n if (!isRecord(metadata)) return [];\n\n const sources: RunIdMetadataSource[] = [];\n for (const key of runIdMetadataKeys) {\n const source = metadata[key];\n if (isRunIdMetadataSource(source)) {\n sources.push(source);\n }\n }\n return sources;\n};\n\n/**\n * Scan initial DB-shape messages for any pending approvals, suspended tools, or\n * `requireApprovalMetadata` entries and return the first non-empty `runId`.\n *\n * Metadata is read off `message.content.metadata`, the canonical location for\n * MastraDBMessage UX hints.\n */\nexport const extractRunIdFromMessages = (messages: MastraDBMessage[]): string | undefined => {\n for (const message of messages) {\n for (const source of getRunIdMetadataSources(message.content?.metadata)) {\n for (const entry of Object.values(source)) {\n if (isRecord(entry) && typeof entry.runId === 'string' && entry.runId.length > 0) {\n return entry.runId;\n }\n }\n }\n }\n\n return undefined;\n};\n","import type { MastraDBMessage } from '@mastra/core/agent/message-list';\nimport { CLIENT_MESSAGE_ID_KEY } from '../lib/mastra-db';\nimport { isRecord } from './extract-tasks';\n\nconst liveClientMessageId = (message: MastraDBMessage): string | undefined => {\n const clientMessageId = message.content.metadata?.[CLIENT_MESSAGE_ID_KEY];\n return typeof clientMessageId === 'string' ? clientMessageId : undefined;\n};\n\n// A stored user signal keeps the sender's metadata under `metadata.signal.metadata`.\nconst storedClientMessageId = (message: MastraDBMessage): string | undefined => {\n const signal = message.content.metadata?.signal;\n const clientMessageId =\n isRecord(signal) && isRecord(signal.metadata) ? signal.metadata[CLIENT_MESSAGE_ID_KEY] : undefined;\n return typeof clientMessageId === 'string' ? clientMessageId : undefined;\n};\n\nexport const mergeHistoryIntoConversation = ({\n conversation,\n history,\n previousHistory,\n}: {\n conversation: MastraDBMessage[];\n history: MastraDBMessage[];\n previousHistory: MastraDBMessage[];\n}): MastraDBMessage[] => {\n const previousById = new Map(previousHistory.map(message => [message.id, message]));\n const live = conversation.filter(message => previousById.get(message.id) !== message);\n const liveById = new Map(live.map(message => [message.id, message]));\n const liveClientMessageIds = new Set(live.flatMap(message => liveClientMessageId(message) ?? []));\n const historyIds = new Set(history.map(message => message.id));\n const storedClientMessageIds = new Set(history.flatMap(message => storedClientMessageId(message) ?? []));\n\n const mergedHistory = history.map(message => {\n const liveCopy = liveById.get(message.id);\n if (liveCopy) return liveCopy;\n const clientMessageId = storedClientMessageId(message);\n if (!clientMessageId || !liveClientMessageIds.has(clientMessageId)) return message;\n // Rows key on the client id; keeping it stops the user row remounting mid-answer.\n return {\n ...message,\n content: {\n ...message.content,\n metadata: { ...message.content.metadata, [CLIENT_MESSAGE_ID_KEY]: clientMessageId },\n },\n };\n });\n const unstoredLive = live.filter(message => {\n const clientMessageId = liveClientMessageId(message);\n return !historyIds.has(message.id) && !(clientMessageId && storedClientMessageIds.has(clientMessageId));\n });\n\n return [...mergedHistory, ...unstoredLive];\n};\n","import type { CoreUserMessage } from '@mastra/core/llm';\n\ntype UserPart = Exclude<CoreUserMessage['content'], string>[number];\n\nconst messageParts = (message: CoreUserMessage): UserPart[] => {\n const parts: UserPart[] =\n typeof message.content === 'string' ? [{ type: 'text', text: message.content }] : message.content;\n const inheritedOptions = message.providerOptions ?? message.experimental_providerMetadata;\n if (!inheritedOptions) return parts;\n\n return parts.map(part => {\n const providerOptions = { ...inheritedOptions };\n for (const [provider, options] of Object.entries(\n part.providerOptions ?? part.experimental_providerMetadata ?? {},\n )) {\n providerOptions[provider] = { ...providerOptions[provider], ...options };\n }\n return { ...part, providerOptions };\n });\n};\n\n/** One send is one user message, with each attachment retained as a content part. */\nexport const createUserMessage = (text: string, attachments: CoreUserMessage[] = []): CoreUserMessage => ({\n role: 'user',\n content: [\n ...(text || attachments.length === 0 ? [{ type: 'text' as const, text }] : []),\n ...attachments.flatMap(messageParts),\n ],\n});\n","import { v4 as uuid } from '@lukeed/uuid';\nimport { MastraClient } from '@mastra/client-js';\nimport type { SendAgentSignalParams } from '@mastra/client-js';\nimport type { AIV5Type, MastraDBMessage, MastraToolInvocationPart } from '@mastra/core/agent/message-list';\nimport { AIV5Adapter } from '@mastra/core/agent/message-list';\nimport type { CoreUserMessage } from '@mastra/core/llm';\nimport type { TracingOptions } from '@mastra/core/observability';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { TaskItem } from '@mastra/core/signals';\nimport type { ChunkType, DataChunkType, NetworkChunkType, ThreadRunStatusChunk } from '@mastra/core/stream';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n accumulateChunk,\n accumulateNetworkChunk,\n CLIENT_MESSAGE_ID_KEY,\n finishStreamingAssistantMessage,\n fromCoreUserMessagesToMastraDBMessage,\n} from '../lib/mastra-db';\nimport type { MastraDBMessageMetadata } from '../lib/mastra-db';\nimport { useMastraClient } from '../mastra-client-context';\nimport {\n extractLatestTasksFromMessages,\n extractTasksFromSignalChunk,\n extractTasksFromToolResultChunk,\n} from './extract-tasks';\nimport { extractRunIdFromMessages } from './extractRunIdFromMessages';\nimport { mergeHistoryIntoConversation } from './merge-history';\nimport { convertSignalDataToBase64String } from './signal-data';\nimport type { ClientToolsInput, ClientToolsResolver, ModelSettings } from './types';\nimport { createUserMessage } from './user-message';\n\nconst extractPendingToolApprovalIdsFromMessages = (messages: MastraDBMessage[], runId?: string) => {\n const pendingToolApprovalIds = new Set<string>();\n\n for (const message of messages) {\n const metadata = message.content?.metadata as MastraDBMessageMetadata | undefined;\n if (!metadata) continue;\n\n const metadataSources = [\n metadata.pendingToolApprovals,\n metadata.requireApprovalMetadata,\n metadata.suspendedTools,\n ] as Array<Record<string, { toolCallId?: unknown; runId?: unknown }> | undefined>;\n\n for (const source of metadataSources) {\n if (!source || typeof source !== 'object') continue;\n\n for (const suspensionData of Object.values(source)) {\n if (runId && suspensionData?.runId !== runId) continue;\n const toolCallId = suspensionData?.toolCallId;\n if (typeof toolCallId === 'string' && toolCallId.length > 0) {\n pendingToolApprovalIds.add(toolCallId);\n }\n }\n }\n }\n\n return pendingToolApprovalIds;\n};\n\nconst toolCallHasOutput = (parts: MastraDBMessage['content']['parts'], toolCallId: string): boolean =>\n parts.some(part => {\n if (part.type !== 'tool-invocation') return false;\n const invocation = (part as MastraToolInvocationPart).toolInvocation;\n if (invocation.toolCallId !== toolCallId) return false;\n return invocation.state === 'result' || (invocation as { result?: unknown }).result != null;\n });\n\nconst filterUnresolvedApprovals = <T extends { toolCallId: string }>(\n entries: Record<string, T> | undefined,\n parts: MastraDBMessage['content']['parts'],\n): Record<string, T> | undefined => {\n if (!entries || typeof entries !== 'object') return undefined;\n const pending = Object.fromEntries(\n Object.entries(entries).filter(\n ([, approval]) =>\n approval &&\n typeof approval === 'object' &&\n typeof approval.toolCallId === 'string' &&\n !toolCallHasOutput(parts, approval.toolCallId),\n ),\n );\n return Object.keys(pending).length ? pending : undefined;\n};\n\n/**\n * Normalize persisted initial messages back into the stream-friendly shape the\n * UI renders from. Mirrors `main`'s `resolveInitialMessages`:\n *\n * - Converts persisted `pendingToolApprovals` (DB shape) into\n * `requireApprovalMetadata` (stream shape) so reloaded threads still render\n * approve/decline buttons, filtering out approvals whose tool already\n * produced output, and marks the message `mode: 'stream'`.\n * - Drops assistant completion messages flagged `suppressFeedback`, which are\n * persisted by the supervisor agent but must stay hidden on reload.\n */\nconst resolveInitialMessages = (messages: MastraDBMessage[]): MastraDBMessage[] =>\n messages\n .filter(message => {\n const metadata = message.content?.metadata as MastraDBMessageMetadata | undefined;\n if (metadata?.completionResult?.suppressFeedback || metadata?.isTaskCompleteResult?.suppressFeedback) {\n return false;\n }\n return true;\n })\n .map(message => {\n const metadata = message.content?.metadata as MastraDBMessageMetadata | undefined;\n\n // A persisted/refetched thread must never show a stuck \"sending\" bubble\n // and must never carry the optimistic correlation key: the pending status\n // and its `clientMessageId` are transient UI state. The `clientMessageId`\n // can survive into storage (it is sent to the server with the message), so\n // strip it on every reload regardless of pending status; the rendered row\n // key falls back to the stable server `id`.\n const normalizedMessage =\n metadata && (metadata.status === 'pending' || CLIENT_MESSAGE_ID_KEY in metadata)\n ? (() => {\n const { [CLIENT_MESSAGE_ID_KEY]: _omitClientMessageId, ...rest } = metadata;\n const { status: _omitStatus, ...restWithoutStatus } = rest;\n return {\n ...message,\n content: {\n ...message.content,\n metadata: metadata.status === 'pending' ? restWithoutStatus : rest,\n },\n };\n })()\n : message;\n\n const normalizedMetadata = normalizedMessage.content?.metadata as MastraDBMessageMetadata | undefined;\n if (\n !normalizedMetadata?.pendingToolApprovals &&\n !normalizedMetadata?.requireApprovalMetadata &&\n !normalizedMetadata?.suspendedTools\n ) {\n return normalizedMessage;\n }\n\n const { pendingToolApprovals, requireApprovalMetadata, suspendedTools, ...restMetadata } = normalizedMetadata;\n const parts = normalizedMessage.content.parts;\n const pending = filterUnresolvedApprovals(pendingToolApprovals, parts);\n const required = { ...filterUnresolvedApprovals(requireApprovalMetadata, parts), ...pending };\n const suspended = filterUnresolvedApprovals(suspendedTools, parts);\n\n return {\n ...normalizedMessage,\n content: {\n ...normalizedMessage.content,\n metadata: {\n ...restMetadata,\n ...(pendingToolApprovals ? { mode: 'stream' as const } : {}),\n ...(pending ? { pendingToolApprovals: pending } : {}),\n ...(Object.keys(required).length ? { requireApprovalMetadata: required } : {}),\n ...(suspended ? { suspendedTools: suspended } : {}),\n },\n },\n };\n });\n\ntype SignalContinuationOptions = {\n model?: string;\n maxSteps?: number;\n modelSettings?: {\n frequencyPenalty?: number;\n presencePenalty?: number;\n maxRetries?: number;\n maxOutputTokens?: number;\n temperature?: number;\n topK?: number;\n topP?: number;\n };\n instructions?: ModelSettings['instructions'];\n system?: ModelSettings['system'];\n providerOptions?: ModelSettings['providerOptions'];\n requireToolApproval?: boolean;\n tracingOptions?: TracingOptions;\n};\n\ntype ActiveContinuation = {\n model?: string;\n requestContext?: RequestContext;\n};\n\nexport interface MastraChatProps {\n agentId: string;\n resourceId?: string;\n threadId?: string;\n initialMessages?: MastraDBMessage[];\n /** Persistent request context used for tool approval/decline calls (e.g. agentVersionId). */\n requestContext?: RequestContext;\n /**\n * Client-side tool definitions. Forwarded once to `subscribeToThread` so\n * the client-js subscription drives the full client-tool execution loop\n * (execute, emit tool-result, continuation) without any logic in React.\n */\n clientTools?: ClientToolsInput;\n onSignalSent?: (signalId: string, preview: string) => void;\n onSignalEcho?: (signalId: string) => void;\n onThreadSignalsUnsupported?: () => void;\n /**\n * Use the agent-signals streaming path (sendSignal + subscribeToThread).\n * Defaults to `false`; set to `true` to opt into thread signals.\n */\n enableThreadSignals?: boolean;\n /** Override the legacy stream route for editor-owned hidden agents. */\n streamPath?: string;\n /**\n * Load stored thread messages through the thread subscription instead of\n * `initialMessages`. The subscription sends them as one `thread-history`\n * chunk and skips run parts already covered by it. Requires thread signals.\n */\n withInitialHistory?: boolean | { perPage?: number };\n}\n\ninterface SharedArgs {\n coreUserMessages: CoreUserMessage[];\n model?: string;\n requestContext?: RequestContext;\n threadId?: string;\n modelSettings?: ModelSettings;\n signal?: AbortSignal;\n tracingOptions?: TracingOptions;\n}\n\n/** JSON-serializable metadata attached to a user message sent through `useChat`. */\nexport type UserMessageMetadata = NonNullable<SendAgentSignalParams['signal']['metadata']>;\n\nexport type SendMessageArgs = {\n message: string;\n coreUserMessages?: CoreUserMessage[];\n /**\n * Custom metadata for the user message. It is merged into the optimistic\n * message's `content.metadata` and, on the thread-signals path, sent with the\n * outgoing message. Internal keys (`mode`, `status`, `clientMessageId`) take\n * precedence over user-supplied values.\n */\n metadata?: UserMessageMetadata;\n} & (\n | ({ mode: 'generate' } & Omit<GenerateArgs, 'coreUserMessages'>)\n | ({ mode: 'stream' } & Omit<StreamArgs, 'coreUserMessages'>)\n | ({ mode: 'network' } & Omit<NetworkArgs, 'coreUserMessages'>)\n | ({ mode?: undefined } & Omit<StreamArgs, 'coreUserMessages'>)\n);\n\nexport type GenerateArgs = SharedArgs & {\n onFinish?: (messages: MastraDBMessage[]) => Promise<void>;\n clientTools?: ClientToolsInput;\n clientToolsResolver?: ClientToolsResolver;\n};\n\nexport type StreamArgs = SharedArgs & {\n onChunk?: (chunk: ChunkType) => Promise<void>;\n clientTools?: ClientToolsInput;\n clientToolsResolver?: ClientToolsResolver;\n signalId?: string;\n /**\n * Client-generated correlation id stamped on the optimistic pending bubble\n * and the outgoing message metadata so the server echo can reconcile them.\n */\n clientMessageId?: string;\n /** Custom user-message metadata sent alongside the thread signal. */\n metadata?: UserMessageMetadata;\n};\n\nexport type NetworkArgs = SharedArgs & {\n onNetworkChunk?: (chunk: NetworkChunkType) => Promise<void>;\n};\n\nconst isObject = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null;\n\nconst getErrorName = (error: unknown) => (isObject(error) && typeof error.name === 'string' ? error.name : undefined);\n\nconst isAbortError = (error: unknown) => getErrorName(error) === 'AbortError';\n\nconst isThreadSignalUnsupportedError = (error: unknown) => {\n if (!isObject(error)) return false;\n\n const status = error.status;\n if (status === 404 || status === 405 || status === 501) {\n return true;\n }\n\n return (\n status === 400 &&\n typeof error.message === 'string' &&\n error.message.includes('No active agent run found for signal target')\n );\n};\n\ntype DataChunk = Extract<ChunkType, DataChunkType>;\n\nconst isDataChunk = (chunk: ChunkType): chunk is DataChunk =>\n typeof chunk.type === 'string' && chunk.type.startsWith('data-');\n\n/**\n * Convert AI-SDK v5 UIMessages returned by the server (generate mode) into\n * `MastraDBMessage[]`, stamping the supplied metadata onto each message's\n * `content.metadata`. Private helper — `useChat` never exposes the AI-SDK\n * shape to consumers.\n */\nconst dbFromServerUiMessages = (\n uiMessages: AIV5Type.UIMessage[],\n metadata: MastraDBMessageMetadata,\n): MastraDBMessage[] =>\n uiMessages.map(uiMsg => {\n const dbMsg = AIV5Adapter.fromUIMessage(uiMsg);\n return {\n ...dbMsg,\n content: {\n ...dbMsg.content,\n metadata: {\n ...(dbMsg.content.metadata ?? {}),\n ...metadata,\n },\n },\n };\n });\n\nexport const useChat = ({\n agentId,\n resourceId,\n threadId,\n initialMessages,\n requestContext: propsRequestContext,\n clientTools: hookClientTools,\n onSignalSent,\n onSignalEcho,\n onThreadSignalsUnsupported,\n enableThreadSignals = false,\n streamPath,\n withInitialHistory,\n}: MastraChatProps) => {\n const threadSignalsDisabled = enableThreadSignals === false;\n const _currentRunId = useRef<string | undefined>(undefined);\n const _onChunk = useRef<((chunk: ChunkType) => Promise<void>) | undefined>(undefined);\n const _networkRunId = useRef<string | undefined>(undefined);\n const _onNetworkChunk = useRef<((chunk: NetworkChunkType) => Promise<void>) | undefined>(undefined);\n const _activeContinuation = useRef<ActiveContinuation>({ requestContext: propsRequestContext });\n // Tracks the active stream (untilIdle) request so a subsequent stream() call\n // can abort the previous one. Without this, a still-open prior stream keeps\n // its background-task pubsub subscription alive and fans events into a second\n // concurrent UI consumer, producing duplicate bg-task events and duplicate\n // continuation turns on the server.\n const _streamAbortRef = useRef<AbortController | null>(null);\n const _threadSubscriptionAbortRef = useRef<AbortController | null>(null);\n const _threadSubscriptionRef = useRef<{ abort?: () => Promise<boolean> | boolean; unsubscribe?: () => void } | null>(\n null,\n );\n const _threadSubscriptionKeyRef = useRef<string | undefined>(undefined);\n const _threadSubscriptionPromiseRef = useRef<Promise<void> | null>(null);\n const _threadSignalsUnsupportedRef = useRef(false);\n const [messages, setMessages] = useState<MastraDBMessage[]>([]);\n const [tasks, setTasks] = useState<TaskItem[]>([]);\n const liveTasks = useRef<TaskItem[] | undefined>(undefined);\n const [toolCallApprovals, setToolCallApprovals] = useState<{\n [toolCallId: string]: { status: 'approved' | 'declined' };\n }>({});\n const [networkToolCallApprovals, setNetworkToolCallApprovals] = useState<{\n [toolName: string]: { status: 'approved' | 'declined' };\n }>({});\n const pendingToolApprovalIdsRef = useRef(new Set<string>());\n const liveApprovalIds = useRef(new Set<string>());\n const liveRunId = useRef<string | undefined>(undefined);\n const liveRunFinished = useRef(false);\n const pendingRunStatuses = useRef<Map<string, ThreadRunStatusChunk> | undefined>(undefined);\n const [isAwaitingToolApproval, setIsAwaitingToolApproval] = useState(false);\n\n const baseClient = useMastraClient();\n const [isRunning, setIsRunning] = useState(false);\n const [subscriptionHistory, setSubscriptionHistory] = useState<\n { key: string; messages: MastraDBMessage[] } | undefined\n >(undefined);\n // `hasMore` from the initial `thread-history` chunk, keyed by the subscription\n // that delivered it so a stale page never describes a different thread or config.\n const [subscriptionPagination, setSubscriptionPagination] = useState<\n { key: string; pagination: { hasMore: boolean } } | undefined\n >(undefined);\n const historyKey = `${agentId}:${resourceId ?? ''}:${threadId ?? ''}`;\n const historyConfigKey = !withInitialHistory\n ? ''\n : withInitialHistory === true\n ? 'history'\n : `history:${withInitialHistory.perPage ?? ''}`;\n const initialHistoryPagination: { hasMore: boolean } | undefined =\n withInitialHistory &&\n !threadSignalsDisabled &&\n threadId &&\n subscriptionPagination?.key ===\n `${agentId}:${resourceId || agentId}:${threadId}:${streamPath ?? ''}:${historyConfigKey}`\n ? subscriptionPagination.pagination\n : undefined;\n const hydratedMessages =\n withInitialHistory && subscriptionHistory?.key === historyKey ? subscriptionHistory.messages : initialMessages;\n\n const lastHydration = useRef<\n | {\n agentId: string;\n resourceId?: string;\n threadId?: string;\n initialMessages: MastraChatProps['initialMessages'];\n formattedMessages: MastraDBMessage[];\n }\n | undefined\n >(undefined);\n\n useEffect(() => {\n const previous = lastHydration.current;\n const sameThread =\n previous?.agentId === agentId && previous.resourceId === resourceId && previous.threadId === threadId;\n if (sameThread && previous.initialMessages === hydratedMessages) return;\n const formattedMessages = resolveInitialMessages(hydratedMessages ?? []);\n lastHydration.current = { agentId, resourceId, threadId, initialMessages: hydratedMessages, formattedMessages };\n\n if (sameThread) {\n setMessages(current =>\n mergeHistoryIntoConversation({\n conversation: current,\n history: formattedMessages,\n previousHistory: previous.formattedMessages,\n }),\n );\n setTasks(liveTasks.current ?? extractLatestTasksFromMessages(formattedMessages));\n // History may arrive before the live approval event, but must not undo\n // a live approval decision or terminal event, nor switch the active run.\n const historyRunId = extractRunIdFromMessages(formattedMessages);\n if (liveRunFinished.current) return;\n if (!liveRunId.current && isRunning && historyRunId !== _currentRunId.current) return;\n } else {\n liveTasks.current = undefined;\n liveApprovalIds.current.clear();\n liveRunId.current = undefined;\n liveRunFinished.current = false;\n if (previous) setIsRunning(false);\n setMessages(formattedMessages);\n setTasks(extractLatestTasksFromMessages(formattedMessages));\n }\n const pendingApprovals = extractPendingToolApprovalIdsFromMessages(formattedMessages, liveRunId.current);\n for (const toolCallId of liveApprovalIds.current) {\n if (pendingToolApprovalIdsRef.current.has(toolCallId)) pendingApprovals.add(toolCallId);\n else pendingApprovals.delete(toolCallId);\n }\n pendingToolApprovalIdsRef.current = pendingApprovals;\n setIsAwaitingToolApproval(pendingApprovals.size > 0);\n _currentRunId.current = liveRunId.current ?? extractRunIdFromMessages(formattedMessages);\n }, [agentId, resourceId, threadId, hydratedMessages, isRunning, isAwaitingToolApproval]);\n\n useEffect(() => {\n _activeContinuation.current = {\n ..._activeContinuation.current,\n requestContext: propsRequestContext,\n };\n }, [propsRequestContext]);\n\n type SignalContentPart =\n | { type: 'text'; text: string }\n | { type: 'file'; data: string; mediaType: string; filename?: string };\n type UserMessageSignalContents = string | SignalContentPart[];\n\n const normalizeSignalFileData = (data: string | URL | ArrayBuffer | Uint8Array) => {\n if (data instanceof URL) return data.toString();\n return convertSignalDataToBase64String(data);\n };\n\n const getSignalContents = (coreUserMessages: CoreUserMessage[]): UserMessageSignalContents => {\n const parts = coreUserMessages.reduce<SignalContentPart[]>((allParts, message) => {\n if (typeof message.content === 'string') {\n allParts.push({ type: 'text', text: message.content });\n return allParts;\n }\n\n for (const part of message.content) {\n if (part.type === 'text') {\n allParts.push({ type: 'text', text: part.text });\n } else if (part.type === 'file') {\n allParts.push({\n type: 'file',\n data: normalizeSignalFileData(part.data),\n mediaType: part.mimeType,\n ...(part.filename ? { filename: part.filename } : {}),\n });\n } else if (part.type === 'image') {\n allParts.push({\n type: 'file',\n data: normalizeSignalFileData(part.image),\n mediaType: part.mimeType ?? 'image/png',\n });\n }\n }\n\n return allParts;\n }, []);\n\n return parts.length === 1 && parts[0]?.type === 'text' ? parts[0].text : parts;\n };\n\n const markThreadSignalsUnsupported = useCallback(() => {\n _threadSignalsUnsupportedRef.current = true;\n onThreadSignalsUnsupported?.();\n }, [onThreadSignalsUnsupported]);\n\n const getSignalPreview = (coreUserMessages: CoreUserMessage[]) => {\n const preview = coreUserMessages\n .flatMap(message => {\n if (typeof message.content === 'string') {\n return [message.content];\n }\n\n return message.content.map(part => {\n if (part.type === 'text') return part.text;\n if (part.type === 'image') return 'Image';\n return part.filename ? `File: ${part.filename}` : 'File';\n });\n })\n .join(' ')\n .replace(/\\s+/g, ' ')\n .trim();\n\n return preview || 'Attachment';\n };\n\n const closeThreadSubscription = useCallback(() => {\n const subscription = _threadSubscriptionRef.current;\n if (subscription?.unsubscribe) {\n subscription.unsubscribe();\n } else {\n _threadSubscriptionAbortRef.current?.abort();\n }\n _threadSubscriptionRef.current = null;\n _threadSubscriptionAbortRef.current = null;\n _threadSubscriptionKeyRef.current = undefined;\n _threadSubscriptionPromiseRef.current = null;\n setSubscriptionPagination(undefined);\n }, []);\n\n const processStreamChunk = useCallback(\n async (chunk: ChunkType, onChunk?: (chunk: ChunkType) => Promise<void>) => {\n const isTerminal = chunk.type === 'finish' || chunk.type === 'abort' || chunk.type === 'error';\n // A delayed terminal event must not finish another run's message, clear\n // its approvals, or trigger its completion callback.\n if (isTerminal && liveRunId.current && chunk.runId !== liveRunId.current) return;\n const runId = 'runId' in chunk && typeof chunk.runId === 'string' ? chunk.runId : undefined;\n setMessages(prev => {\n const metadata = { mode: 'stream' as const, runId };\n const next = accumulateChunk({ chunk, conversation: prev, metadata });\n // A resumed response can already exist in history; explicit framing\n // establishes ownership even when the accumulator deduplicates it.\n if ((chunk.type === 'start' || chunk.type === 'step-start') && chunk.payload?.messageId && runId) {\n return next.map(message =>\n message.id === chunk.payload.messageId && message.role === 'assistant'\n ? { ...message, content: { ...message.content, metadata: { ...message.content.metadata, ...metadata } } }\n : message,\n );\n }\n return next;\n });\n\n const streamedTasks = extractTasksFromToolResultChunk(chunk) ?? extractTasksFromSignalChunk(chunk);\n if (streamedTasks !== undefined) {\n liveTasks.current = streamedTasks;\n setTasks(streamedTasks);\n }\n\n if (\n chunk.type === 'data-user-message' &&\n isDataChunk(chunk) &&\n (chunk.data?.type === 'user-message' || chunk.data?.type === 'user') &&\n typeof chunk.data?.id === 'string'\n ) {\n onSignalEcho?.(chunk.data.id);\n }\n\n if (chunk.type === 'start') {\n setIsRunning(true);\n if ('runId' in chunk && typeof chunk.runId === 'string') {\n if (liveRunId.current !== chunk.runId) liveApprovalIds.current.clear();\n liveRunFinished.current = false;\n liveRunId.current = chunk.runId;\n _currentRunId.current = chunk.runId;\n }\n }\n\n if (chunk.type === 'tool-call-approval' || chunk.type === 'tool-call-suspended') {\n const toolCallId = chunk.payload?.toolCallId;\n if (typeof toolCallId === 'string') {\n liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.add(toolCallId);\n setIsAwaitingToolApproval(true);\n }\n // Some runs (e.g. Inngest durable agents) emit no `start` chunk, so the\n // approval chunk is the only place the run ID reaches the client.\n if (runId) {\n if (!liveRunId.current || liveRunFinished.current) {\n liveRunId.current = runId;\n liveRunFinished.current = false;\n }\n if (liveRunId.current === runId) {\n _currentRunId.current = runId;\n }\n }\n setIsRunning(false);\n }\n\n if (chunk.type === 'tool-call-resumed') {\n const toolCallId = chunk.payload?.toolCallId;\n if (typeof toolCallId === 'string') {\n // Keep it as a live decision so stale hydrated history can't re-mark it pending.\n liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.delete(toolCallId);\n setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);\n }\n }\n\n if (isTerminal) {\n if (chunk.runId === liveRunId.current) liveRunFinished.current = true;\n for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.clear();\n setIsAwaitingToolApproval(false);\n setIsRunning(false);\n }\n\n void (onChunk ?? _onChunk.current)?.(chunk);\n },\n [onSignalEcho],\n );\n\n const ensureThreadSubscription = useCallback(\n async ({ threadId, resourceId }: { threadId: string; resourceId?: string }) => {\n const subscriptionKey = `${agentId}:${resourceId ?? ''}:${threadId}:${streamPath ?? ''}:${historyConfigKey}`;\n if (_threadSubscriptionKeyRef.current === subscriptionKey && _threadSubscriptionPromiseRef.current) {\n await _threadSubscriptionPromiseRef.current;\n return;\n }\n\n closeThreadSubscription();\n const subscriptionAbort = new AbortController();\n _threadSubscriptionAbortRef.current = subscriptionAbort;\n _threadSubscriptionKeyRef.current = subscriptionKey;\n\n // Release the cached subscription state, but only while this attempt\n // still owns it — a newer attempt cleans up after itself.\n const releaseSubscriptionRefs = () => {\n if (_threadSubscriptionAbortRef.current !== subscriptionAbort) return;\n _threadSubscriptionRef.current = null;\n _threadSubscriptionAbortRef.current = null;\n _threadSubscriptionKeyRef.current = undefined;\n _threadSubscriptionPromiseRef.current = null;\n setSubscriptionPagination(undefined);\n };\n\n const clientWithAbort = new MastraClient({\n ...baseClient!.options,\n abortSignal: subscriptionAbort.signal,\n });\n const subscriptionAgent = clientWithAbort.getAgent(agentId, undefined, { stream: streamPath });\n\n _threadSubscriptionPromiseRef.current = subscriptionAgent\n .subscribeToThread({\n resourceId,\n threadId,\n withRunStatus: true,\n ...(withInitialHistory ? { withInitialHistory } : {}),\n })\n .then(response => {\n const subscription = response;\n if (_threadSubscriptionAbortRef.current !== subscriptionAbort) {\n subscription.unsubscribe();\n return;\n }\n\n _threadSubscriptionRef.current = subscription;\n void subscription\n .processDataStream({\n onChunk: chunk => {\n if (chunk.type === 'thread-history') {\n if (_threadSubscriptionAbortRef.current === subscriptionAbort) {\n const { hasMore, activeRunId } = chunk.payload;\n if (\n activeRunId &&\n activeRunId !== liveRunId.current &&\n (!liveRunId.current || liveRunFinished.current)\n ) {\n liveRunId.current = activeRunId;\n liveRunFinished.current = false;\n _currentRunId.current = activeRunId;\n setIsRunning(pendingToolApprovalIdsRef.current.size === 0);\n }\n setSubscriptionPagination(\n typeof hasMore === 'boolean' ? { key: subscriptionKey, pagination: { hasMore } } : undefined,\n );\n }\n // Merge history into `messages` now, as a queued update, so the\n // live chunks right behind it accumulate onto the stored parts.\n const history = resolveInitialMessages(chunk.payload.messages);\n const previousHistory = lastHydration.current?.formattedMessages ?? [];\n setMessages(current =>\n mergeHistoryIntoConversation({ conversation: current, history, previousHistory }),\n );\n setSubscriptionHistory({\n key: `${agentId}:${resourceId ?? ''}:${threadId}`,\n messages: chunk.payload.messages,\n });\n return;\n }\n if (chunk.type === 'thread-run-status') {\n if (chunk.runId !== liveRunId.current) {\n pendingRunStatuses.current?.set(chunk.runId, chunk);\n return;\n }\n setIsRunning(false);\n if (chunk.payload.status !== 'suspended') {\n liveRunFinished.current = true;\n for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.clear();\n setIsAwaitingToolApproval(false);\n }\n return;\n }\n return processStreamChunk(chunk);\n },\n })\n .catch(error => {\n if (!isAbortError(error)) {\n console.error('[useChat] Thread subscription failed', error);\n setIsRunning(false);\n }\n })\n .finally(() => {\n if (_threadSubscriptionRef.current === subscription) {\n _threadSubscriptionRef.current = null;\n }\n releaseSubscriptionRefs();\n });\n })\n .catch(error => {\n // Release on every failure so the next call retries with a fresh\n // fetch instead of re-awaiting this rejected promise. Without this,\n // an aborted mount-time subscribe strands the channel and the reply\n // never arrives until reload (issue #18768).\n releaseSubscriptionRefs();\n\n if (isThreadSignalUnsupportedError(error)) {\n markThreadSignalsUnsupported();\n return;\n }\n if (!isAbortError(error)) {\n console.error('[useChat] Thread subscription failed', error);\n setIsRunning(false);\n }\n throw error;\n });\n\n await _threadSubscriptionPromiseRef.current;\n },\n [\n agentId,\n baseClient,\n closeThreadSubscription,\n historyConfigKey,\n markThreadSignalsUnsupported,\n processStreamChunk,\n streamPath,\n withInitialHistory,\n ],\n );\n\n useEffect(() => {\n _threadSignalsUnsupportedRef.current = false;\n return closeThreadSubscription;\n }, [agentId, resourceId, threadId, closeThreadSubscription]);\n\n useEffect(() => {\n if (!threadId || threadSignalsDisabled) {\n closeThreadSubscription();\n return;\n }\n\n void ensureThreadSubscription({ threadId, resourceId: resourceId || agentId }).catch(error => {\n if (!isAbortError(error)) {\n console.error('[useChat] Thread subscription failed', error);\n }\n });\n }, [agentId, closeThreadSubscription, ensureThreadSubscription, resourceId, threadId, threadSignalsDisabled]);\n\n const generate = async ({\n coreUserMessages,\n model,\n requestContext,\n threadId,\n modelSettings,\n signal,\n onFinish,\n tracingOptions,\n clientTools,\n clientToolsResolver,\n }: GenerateArgs) => {\n const {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxTokens,\n temperature,\n topK,\n topP,\n instructions,\n system,\n providerOptions,\n maxSteps,\n requireToolApproval,\n } = modelSettings || {};\n const resolvedRequestContext = requestContext ?? propsRequestContext;\n const resolvedClientTools = clientTools ?? hookClientTools;\n _activeContinuation.current = {\n model,\n requestContext: resolvedRequestContext,\n };\n setIsRunning(true);\n\n const clientWithAbort = new MastraClient({\n ...baseClient!.options,\n abortSignal: signal,\n });\n\n const agent = clientWithAbort.getAgent(agentId, undefined, { stream: streamPath });\n\n const runId = uuid();\n _currentRunId.current = runId;\n\n const response = await agent.generate(coreUserMessages, {\n model,\n runId,\n maxSteps,\n modelSettings: {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxOutputTokens: maxTokens,\n temperature,\n topK,\n topP,\n },\n instructions,\n system,\n requestContext: resolvedRequestContext,\n ...(threadId ? { memory: { thread: threadId, resource: resourceId || agentId } } : {}),\n providerOptions,\n tracingOptions,\n requireToolApproval,\n clientTools: resolvedClientTools,\n clientToolsResolver,\n });\n\n // Check if suspended for tool approval\n if (response.finishReason === 'suspended' && response.suspendPayload) {\n const { toolCallId, toolName, args } = response.suspendPayload;\n\n // Add uiMessages with requireApprovalMetadata so UI shows approval buttons\n if (response.response?.uiMessages) {\n const dbMessages = dbFromServerUiMessages(response.response.uiMessages, {\n mode: 'generate',\n requireApprovalMetadata: {\n [toolName]: { toolCallId, toolName, args },\n },\n });\n\n setMessages(prev => [...prev, ...dbMessages]);\n }\n\n // Set isRunning to false so approval buttons are enabled\n // The approval/decline functions will set isRunning to true when clicked\n setIsRunning(false);\n return;\n }\n\n setIsRunning(false);\n\n if (response && 'uiMessages' in response.response && response.response.uiMessages) {\n const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: 'generate' });\n void onFinish?.(dbMessages);\n setMessages(prev => [...prev, ...dbMessages]);\n }\n };\n\n const stream = async ({\n coreUserMessages,\n model,\n requestContext,\n threadId,\n onChunk,\n modelSettings,\n signal,\n tracingOptions,\n clientTools,\n clientToolsResolver,\n signalId,\n clientMessageId,\n metadata,\n }: StreamArgs) => {\n const {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxTokens,\n temperature,\n topK,\n topP,\n instructions,\n system,\n providerOptions,\n maxSteps,\n requireToolApproval,\n } = modelSettings || {};\n\n const resolvedRequestContext = requestContext ?? propsRequestContext;\n const resolvedClientTools = clientTools ?? hookClientTools;\n const signalContinuationOptions: SignalContinuationOptions = {\n model,\n maxSteps,\n modelSettings: {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxOutputTokens: maxTokens,\n temperature,\n topK,\n topP,\n },\n instructions,\n system,\n providerOptions,\n requireToolApproval,\n tracingOptions,\n };\n _activeContinuation.current = {\n model,\n requestContext: resolvedRequestContext,\n };\n setIsRunning(true);\n\n _streamAbortRef.current?.abort();\n const internalAbort = new AbortController();\n _streamAbortRef.current = internalAbort;\n\n if (signal) {\n if (signal.aborted) internalAbort.abort();\n else signal.addEventListener('abort', () => internalAbort.abort(), { once: true });\n }\n\n const clientWithAbort = new MastraClient({\n ...baseClient!.options,\n abortSignal: internalAbort.signal,\n });\n\n const agent = clientWithAbort.getAgent(agentId, undefined, { stream: streamPath });\n\n const streamWithLegacyRoute = async () => {\n const runId = uuid();\n _currentRunId.current = runId;\n const response = await agent.stream(coreUserMessages, {\n model,\n runId,\n maxSteps,\n untilIdle: true,\n modelSettings: {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxOutputTokens: maxTokens,\n temperature,\n topK,\n topP,\n },\n instructions,\n system,\n requestContext: resolvedRequestContext,\n ...(threadId ? { memory: { thread: threadId, resource: resourceId || agentId } } : {}),\n providerOptions,\n requireToolApproval,\n tracingOptions,\n clientTools: resolvedClientTools,\n clientToolsResolver,\n });\n\n _onChunk.current = onChunk;\n _currentRunId.current = runId;\n\n await response.processDataStream({\n onChunk: chunk => processStreamChunk(chunk, onChunk),\n });\n\n if (_streamAbortRef.current === internalAbort) {\n _streamAbortRef.current = null;\n }\n setIsRunning(false);\n };\n\n if (!threadId || _threadSignalsUnsupportedRef.current || threadSignalsDisabled) {\n await streamWithLegacyRoute();\n return;\n }\n\n _onChunk.current = onChunk;\n\n await ensureThreadSubscription({ threadId, resourceId: resourceId || agentId });\n\n if (_threadSignalsUnsupportedRef.current) {\n await streamWithLegacyRoute();\n return;\n }\n\n const resolvedSignalId = signalId ?? uuid();\n const messageContents = getSignalContents(coreUserMessages);\n // RequestContext serializes to a plain record via its toJSON(), but the class has no\n // index signature, so it isn't assignable to the generated `Record<string, unknown>` body type.\n const requestContextRecord = resolvedRequestContext as Record<string, unknown> | undefined;\n const streamOptions = {\n model,\n maxSteps,\n modelSettings: {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxOutputTokens: maxTokens,\n temperature,\n topK,\n topP,\n },\n instructions,\n system,\n requestContext: requestContextRecord,\n providerOptions: providerOptions as any,\n requireToolApproval,\n tracingOptions,\n clientTools: resolvedClientTools,\n clientToolsResolver,\n };\n\n const liveRunIdBeforeSend = liveRunId.current;\n // An outcome can reach SSE before the acceptance response supplies its run ID.\n const earlyRunStatuses = new Map<string, ThreadRunStatusChunk>();\n pendingRunStatuses.current = earlyRunStatuses;\n try {\n const result = await agent.sendMessage({\n message:\n clientMessageId || metadata\n ? {\n contents: messageContents,\n metadata: { ...metadata, ...(clientMessageId ? { [CLIENT_MESSAGE_ID_KEY]: clientMessageId } : {}) },\n }\n : messageContents,\n resourceId: resourceId || agentId,\n threadId,\n ifIdle: {\n streamOptions: {\n ...signalContinuationOptions,\n requestContext: requestContextRecord,\n clientTools: resolvedClientTools,\n clientToolsResolver,\n },\n },\n });\n // SSE may already have finished this run or moved on while the request was pending.\n if (\n _streamAbortRef.current === internalAbort &&\n liveRunId.current === liveRunIdBeforeSend &&\n liveRunId.current !== result.runId\n ) {\n liveApprovalIds.current.clear();\n liveRunId.current = result.runId;\n liveRunFinished.current = false;\n _currentRunId.current = result.runId;\n setIsRunning(true);\n const earlyStatus = earlyRunStatuses.get(result.runId);\n if (earlyStatus) {\n setIsRunning(false);\n if (earlyStatus.payload.status !== 'suspended') {\n liveRunFinished.current = true;\n for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.clear();\n setIsAwaitingToolApproval(false);\n }\n }\n }\n const echoedSignalId =\n result.signal &&\n typeof result.signal === 'object' &&\n 'id' in result.signal &&\n typeof result.signal.id === 'string'\n ? result.signal.id\n : resolvedSignalId;\n onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));\n if (pendingToolApprovalIdsRef.current.size > 0) {\n setIsRunning(false);\n }\n } catch (error) {\n if (isThreadSignalUnsupportedError(error)) {\n try {\n await agent.sendSignal({\n signal: {\n id: resolvedSignalId,\n type: 'user-message',\n contents: messageContents,\n ...(metadata ? { metadata } : {}),\n },\n resourceId: resourceId || agentId,\n threadId,\n ifIdle: { streamOptions },\n });\n onSignalSent?.(resolvedSignalId, getSignalPreview(coreUserMessages));\n return;\n } catch (signalError) {\n onSignalEcho?.(resolvedSignalId);\n if (isThreadSignalUnsupportedError(signalError)) {\n markThreadSignalsUnsupported();\n setMessages(prev => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);\n await streamWithLegacyRoute();\n return;\n }\n throw signalError;\n }\n }\n throw error;\n } finally {\n if (pendingRunStatuses.current === earlyRunStatuses) pendingRunStatuses.current = undefined;\n }\n\n if (_streamAbortRef.current === internalAbort) {\n _streamAbortRef.current = null;\n }\n };\n\n const network = async ({\n coreUserMessages,\n model,\n requestContext,\n threadId,\n onNetworkChunk,\n modelSettings,\n signal,\n tracingOptions,\n }: NetworkArgs) => {\n const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } =\n modelSettings || {};\n\n const resolvedRequestContext = requestContext ?? propsRequestContext;\n _activeContinuation.current = {\n model,\n requestContext: resolvedRequestContext,\n };\n setIsRunning(true);\n\n const clientWithAbort = new MastraClient({\n ...baseClient!.options,\n abortSignal: signal,\n });\n\n const agent = clientWithAbort.getAgent(agentId, undefined, { stream: streamPath });\n\n const runId = uuid();\n _currentRunId.current = runId;\n\n const response = await agent.network(coreUserMessages, {\n model,\n maxSteps,\n modelSettings: {\n frequencyPenalty,\n presencePenalty,\n maxRetries,\n maxOutputTokens: maxTokens,\n temperature,\n topK,\n topP,\n },\n runId,\n requestContext: resolvedRequestContext,\n ...(threadId ? { memory: { thread: threadId, resource: resourceId || agentId } } : {}),\n tracingOptions,\n });\n\n _onNetworkChunk.current = onNetworkChunk;\n _networkRunId.current = runId;\n\n // Accumulate network chunks into `messages` as `MastraDBMessage` (temporary\n // bridge until the next major), while still forwarding chunks to the\n // consumer for side-effects (OM, working memory, thread list, errors).\n await response.processDataStream({\n onChunk: async (chunk: NetworkChunkType) => {\n setMessages(prev =>\n accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: 'network', runId } }),\n );\n void onNetworkChunk?.(chunk);\n },\n });\n\n setMessages(prev => finishStreamingAssistantMessage(prev));\n setIsRunning(false);\n };\n\n const handleCancelRun = () => {\n const runId = _currentRunId.current;\n const agent = baseClient?.getAgent(agentId);\n const threadSubscription = _threadSubscriptionRef.current;\n const streamAbort = _streamAbortRef.current;\n const cancellationAbort = new AbortController();\n const timeout = setTimeout(\n () => cancellationAbort.abort(new Error('Agent run cancellation was not acknowledged')),\n 10_000,\n );\n // Stop execution explicitly: aborting the HTTP request only detaches a durable observer.\n const cancellation = (async () => {\n if (agent && runId) {\n while (true) {\n cancellationAbort.signal.throwIfAborted();\n const options = { signal: cancellationAbort.signal };\n const result = threadId\n ? await agent.abortThread({ threadId, resourceId: resourceId || agentId, expectedRunId: runId }, options)\n : await agent.abortRun(runId, options);\n if (result.aborted) return;\n // Stop can overtake stream registration. Keep the request alive until cancellation is applied.\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n await threadSubscription?.abort?.();\n })()\n .catch(error => {\n // Older servers and non-durable agents still stop when their HTTP request is aborted.\n if (isObject(error) && (error.status === 404 || error.status === 501)) return;\n throw error;\n })\n .finally(() => {\n clearTimeout(timeout);\n streamAbort?.abort();\n if (_streamAbortRef.current === streamAbort) _streamAbortRef.current = null;\n });\n void cancellation.catch(error => console.error('[useChat] Failed to abort agent run', error));\n closeThreadSubscription();\n setMessages(prev => finishStreamingAssistantMessage(prev));\n liveRunFinished.current = true;\n pendingToolApprovalIdsRef.current.clear();\n setIsAwaitingToolApproval(false);\n setIsRunning(false);\n _currentRunId.current = undefined;\n _onChunk.current = undefined;\n _networkRunId.current = undefined;\n _onNetworkChunk.current = undefined;\n _activeContinuation.current = {};\n return cancellation;\n };\n\n const approveToolCall = async (toolCallId: string, resumeData?: unknown) => {\n const onChunk = _onChunk.current;\n const currentRunId = _currentRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!currentRunId)\n return console.info('[approveToolCall] approveToolCall can only be called after a stream has started');\n\n setIsRunning(true);\n setToolCallApprovals(prev => ({ ...prev, [toolCallId]: { status: 'approved' } }));\n\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n if (_threadSubscriptionKeyRef.current && threadId) {\n try {\n await agent.sendToolApproval({\n resourceId: resourceId || agentId,\n threadId,\n toolCallId,\n approved: true,\n ...(continuation.model !== undefined ? { streamOptions: { model: continuation.model } } : {}),\n ...(resumeData !== undefined ? { resumeData } : {}),\n requestContext: continuation.requestContext,\n });\n liveRunId.current ??= currentRunId;\n liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.delete(toolCallId);\n setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);\n setIsRunning(false);\n } catch (error) {\n setToolCallApprovals(prev => {\n const next = { ...prev };\n delete next[toolCallId];\n return next;\n });\n setIsRunning(false);\n throw error;\n }\n return;\n }\n\n try {\n const response =\n resumeData !== undefined\n ? await agent.resumeStream(resumeData as Parameters<typeof agent.resumeStream>[0], {\n runId: currentRunId,\n toolCallId,\n ...continuation,\n })\n : await agent.approveToolCall({\n runId: currentRunId,\n toolCallId,\n ...continuation,\n });\n\n await response.processDataStream({\n onChunk: async (chunk: ChunkType) => {\n await processStreamChunk(chunk, onChunk);\n },\n });\n setIsRunning(false);\n } catch (error) {\n setToolCallApprovals(prev => {\n const next = { ...prev };\n delete next[toolCallId];\n return next;\n });\n setIsRunning(false);\n throw error;\n }\n };\n\n const declineToolCall = async (toolCallId: string) => {\n const onChunk = _onChunk.current;\n const currentRunId = _currentRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!currentRunId)\n return console.info('[declineToolCall] declineToolCall can only be called after a stream has started');\n\n setIsRunning(true);\n setToolCallApprovals(prev => ({ ...prev, [toolCallId]: { status: 'declined' } }));\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n if (_threadSubscriptionKeyRef.current && threadId) {\n try {\n await agent.sendToolApproval({\n resourceId: resourceId || agentId,\n threadId,\n toolCallId,\n approved: false,\n ...(continuation.model !== undefined ? { streamOptions: { model: continuation.model } } : {}),\n requestContext: continuation.requestContext,\n });\n liveRunId.current ??= currentRunId;\n liveApprovalIds.current.add(toolCallId);\n pendingToolApprovalIdsRef.current.delete(toolCallId);\n setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);\n setIsRunning(false);\n } catch (error) {\n setToolCallApprovals(prev => {\n const next = { ...prev };\n delete next[toolCallId];\n return next;\n });\n setIsRunning(false);\n throw error;\n }\n return;\n }\n\n const response = await agent.declineToolCall({\n runId: currentRunId,\n toolCallId,\n ...continuation,\n });\n\n await response.processDataStream({\n onChunk: async (chunk: ChunkType) => {\n await processStreamChunk(chunk, onChunk);\n },\n });\n setIsRunning(false);\n };\n\n const approveToolCallGenerate = async (toolCallId: string) => {\n const currentRunId = _currentRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!currentRunId)\n return console.info(\n '[approveToolCallGenerate] approveToolCallGenerate can only be called after a generate has started',\n );\n\n setIsRunning(true);\n setToolCallApprovals(prev => ({ ...prev, [toolCallId]: { status: 'approved' } }));\n\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n const response = await agent.approveToolCallGenerate({\n runId: currentRunId,\n toolCallId,\n ...continuation,\n });\n\n if (response && 'uiMessages' in response.response && response.response.uiMessages) {\n const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: 'generate' });\n setMessages(prev => [...prev, ...dbMessages]);\n }\n\n setIsRunning(false);\n };\n\n const declineToolCallGenerate = async (toolCallId: string) => {\n const currentRunId = _currentRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!currentRunId)\n return console.info(\n '[declineToolCallGenerate] declineToolCallGenerate can only be called after a generate has started',\n );\n\n setIsRunning(true);\n setToolCallApprovals(prev => ({ ...prev, [toolCallId]: { status: 'declined' } }));\n\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n const response = await agent.declineToolCallGenerate({\n runId: currentRunId,\n toolCallId,\n ...continuation,\n });\n\n if (response && 'uiMessages' in response.response && response.response.uiMessages) {\n const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: 'generate' });\n setMessages(prev => [...prev, ...dbMessages]);\n }\n\n setIsRunning(false);\n };\n\n const approveNetworkToolCall = async (toolName: string, runId?: string) => {\n const onNetworkChunk = _onNetworkChunk.current;\n const networkRunId = runId || _networkRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!networkRunId)\n return console.info(\n '[approveNetworkToolCall] approveNetworkToolCall can only be called after a network stream has started',\n );\n\n _currentRunId.current = networkRunId;\n setIsRunning(true);\n setNetworkToolCallApprovals(prev => ({\n ...prev,\n [runId ? `${runId}-${toolName}` : toolName]: { status: 'approved' },\n }));\n\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n const response = await agent.approveNetworkToolCall({\n runId: networkRunId,\n ...continuation,\n });\n\n await response.processDataStream({\n onChunk: async (chunk: NetworkChunkType) => {\n setMessages(prev =>\n accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: 'network', runId: networkRunId } }),\n );\n void onNetworkChunk?.(chunk);\n },\n });\n\n setMessages(prev => finishStreamingAssistantMessage(prev));\n setIsRunning(false);\n };\n\n const declineNetworkToolCall = async (toolName: string, runId?: string) => {\n const onNetworkChunk = _onNetworkChunk.current;\n const networkRunId = runId || _networkRunId.current;\n const continuation = _activeContinuation.current;\n\n if (!networkRunId)\n return console.info(\n '[declineNetworkToolCall] declineNetworkToolCall can only be called after a network stream has started',\n );\n\n _currentRunId.current = networkRunId;\n setIsRunning(true);\n setNetworkToolCallApprovals(prev => ({\n ...prev,\n [runId ? `${runId}-${toolName}` : toolName]: { status: 'declined' },\n }));\n\n const agent = baseClient.getAgent(agentId, undefined, { stream: streamPath });\n const response = await agent.declineNetworkToolCall({\n runId: networkRunId,\n ...continuation,\n });\n\n await response.processDataStream({\n onChunk: async (chunk: NetworkChunkType) => {\n setMessages(prev =>\n accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: 'network', runId: networkRunId } }),\n );\n void onNetworkChunk?.(chunk);\n },\n });\n\n setMessages(prev => finishStreamingAssistantMessage(prev));\n setIsRunning(false);\n };\n\n const sendMessage = async ({ mode = 'stream', metadata: userMetadata, ...args }: SendMessageArgs) => {\n if (!isRunning && !isAwaitingToolApproval) _currentRunId.current = undefined;\n const coreUserMessages = [createUserMessage(args.message, args.coreUserMessages)];\n\n // Use the same multipart message for the request and optimistic display.\n // Sending separate attachment messages would persist separate rows on reload.\n const coreDbUserMessage = fromCoreUserMessagesToMastraDBMessage(coreUserMessages);\n const dbUserMessage: MastraDBMessage = userMetadata\n ? {\n ...coreDbUserMessage,\n content: {\n ...coreDbUserMessage.content,\n metadata: { ...coreDbUserMessage.content.metadata, ...userMetadata },\n },\n }\n : coreDbUserMessage;\n const clientSetId =\n mode === 'stream' && args.threadId && !_threadSignalsUnsupportedRef.current && !threadSignalsDisabled\n ? `client-set-${uuid()}`\n : undefined;\n const signalId = clientSetId;\n const clientMessageId = clientSetId;\n\n if (signalId) {\n // Signal path: append the user turn optimistically as `pending` with a\n // visibly client-owned id. The server echo can replace the final message\n // id while the matching client id reconciles the pending bubble.\n const metadata: MastraDBMessageMetadata = {\n ...dbUserMessage.content.metadata,\n mode: 'stream',\n status: 'pending',\n [CLIENT_MESSAGE_ID_KEY]: clientMessageId,\n };\n const pendingMessage = { ...dbUserMessage, id: clientSetId, content: { ...dbUserMessage.content, metadata } };\n setMessages(s => [...s, pendingMessage]);\n } else {\n setMessages(s => [...s, dbUserMessage]);\n }\n\n try {\n if (mode === 'generate') {\n await generate({ ...args, coreUserMessages });\n } else if (mode === 'stream') {\n await stream({ ...args, coreUserMessages, signalId, clientMessageId, metadata: userMetadata });\n } else if (mode === 'network') {\n await network({ ...args, coreUserMessages });\n }\n } catch (error) {\n // A failed send (subscription setup, request, or stream) must not leave\n // the chat stranded in a \"running\" state until reload (issue #18768).\n setIsRunning(false);\n // Drop the optimistic bubble instead of leaving it pending until reload\n // (issue #26831). If the server did accept the turn before the response\n // was lost, the message can still reappear through the live subscription\n // echo or when the caller reloads thread history.\n if (signalId) {\n setMessages(s => s.filter(m => !(m.id === signalId && m.content.metadata?.status === 'pending')));\n }\n throw error;\n }\n };\n\n return {\n setMessages,\n sendMessage,\n isRunning,\n activeRunId: isRunning || isAwaitingToolApproval ? _currentRunId.current : undefined,\n isAwaitingToolApproval,\n messages,\n /**\n * Pagination of the initial `thread-history` page from `withInitialHistory`:\n * `hasMore: true` when older messages exist, `false` when the page reached the\n * start of the thread, and `undefined` while history is disabled, pending, or\n * the subscription for the current agent/resource/thread/config has ended.\n */\n initialHistoryPagination,\n tasks,\n approveToolCall,\n declineToolCall,\n approveToolCallGenerate,\n declineToolCallGenerate,\n cancelRun: handleCancelRun,\n toolCallApprovals,\n approveNetworkToolCall,\n declineNetworkToolCall,\n networkToolCallApprovals,\n };\n};\n"],"mappings":"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"}
@@ -373,6 +373,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
373
373
  const liveApprovalIds = useRef(/* @__PURE__ */ new Set());
374
374
  const liveRunId = useRef(void 0);
375
375
  const liveRunFinished = useRef(false);
376
+ const pendingRunStatuses = useRef(void 0);
376
377
  const [isAwaitingToolApproval, setIsAwaitingToolApproval] = useState(false);
377
378
  const baseClient = useMastraClient();
378
379
  const [isRunning, setIsRunning] = useState(false);
@@ -589,6 +590,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
589
590
  _threadSubscriptionPromiseRef.current = subscriptionAgent.subscribeToThread({
590
591
  resourceId,
591
592
  threadId,
593
+ withRunStatus: true,
592
594
  ...withInitialHistory ? { withInitialHistory } : {}
593
595
  }).then((response) => {
594
596
  const subscription = response;
@@ -600,7 +602,13 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
600
602
  subscription.processDataStream({ onChunk: (chunk) => {
601
603
  if (chunk.type === "thread-history") {
602
604
  if (_threadSubscriptionAbortRef.current === subscriptionAbort) {
603
- const { hasMore } = chunk.payload;
605
+ const { hasMore, activeRunId } = chunk.payload;
606
+ if (activeRunId && activeRunId !== liveRunId.current && (!liveRunId.current || liveRunFinished.current)) {
607
+ liveRunId.current = activeRunId;
608
+ liveRunFinished.current = false;
609
+ _currentRunId.current = activeRunId;
610
+ setIsRunning(pendingToolApprovalIdsRef.current.size === 0);
611
+ }
604
612
  setSubscriptionPagination(typeof hasMore === "boolean" ? {
605
613
  key: subscriptionKey,
606
614
  pagination: { hasMore }
@@ -619,6 +627,20 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
619
627
  });
620
628
  return;
621
629
  }
630
+ if (chunk.type === "thread-run-status") {
631
+ if (chunk.runId !== liveRunId.current) {
632
+ pendingRunStatuses.current?.set(chunk.runId, chunk);
633
+ return;
634
+ }
635
+ setIsRunning(false);
636
+ if (chunk.payload.status !== "suspended") {
637
+ liveRunFinished.current = true;
638
+ for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);
639
+ pendingToolApprovalIdsRef.current.clear();
640
+ setIsAwaitingToolApproval(false);
641
+ }
642
+ return;
643
+ }
622
644
  return processStreamChunk(chunk);
623
645
  } }).catch((error) => {
624
646
  if (!isAbortError(error)) {
@@ -855,6 +877,9 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
855
877
  clientTools: resolvedClientTools,
856
878
  clientToolsResolver
857
879
  };
880
+ const liveRunIdBeforeSend = liveRunId.current;
881
+ const earlyRunStatuses = /* @__PURE__ */ new Map();
882
+ pendingRunStatuses.current = earlyRunStatuses;
858
883
  try {
859
884
  const result = await agent.sendMessage({
860
885
  message: clientMessageId || metadata ? {
@@ -873,6 +898,23 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
873
898
  clientToolsResolver
874
899
  } }
875
900
  });
901
+ if (_streamAbortRef.current === internalAbort && liveRunId.current === liveRunIdBeforeSend && liveRunId.current !== result.runId) {
902
+ liveApprovalIds.current.clear();
903
+ liveRunId.current = result.runId;
904
+ liveRunFinished.current = false;
905
+ _currentRunId.current = result.runId;
906
+ setIsRunning(true);
907
+ const earlyStatus = earlyRunStatuses.get(result.runId);
908
+ if (earlyStatus) {
909
+ setIsRunning(false);
910
+ if (earlyStatus.payload.status !== "suspended") {
911
+ liveRunFinished.current = true;
912
+ for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);
913
+ pendingToolApprovalIdsRef.current.clear();
914
+ setIsAwaitingToolApproval(false);
915
+ }
916
+ }
917
+ }
876
918
  const echoedSignalId = result.signal && typeof result.signal === "object" && "id" in result.signal && typeof result.signal.id === "string" ? result.signal.id : resolvedSignalId;
877
919
  onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));
878
920
  if (pendingToolApprovalIdsRef.current.size > 0) setIsRunning(false);
@@ -902,6 +944,8 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
902
944
  throw signalError;
903
945
  }
904
946
  throw error;
947
+ } finally {
948
+ if (pendingRunStatuses.current === earlyRunStatuses) pendingRunStatuses.current = void 0;
905
949
  }
906
950
  if (_streamAbortRef.current === internalAbort) _streamAbortRef.current = null;
907
951
  };
@@ -1283,4 +1327,4 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
1283
1327
  };
1284
1328
  export { fromCoreUserMessageToMastraDBMessage as n, fromCoreUserMessagesToMastraDBMessage as r, useChat as t };
1285
1329
 
1286
- //# sourceMappingURL=hooks-CEikbhrN.js.map
1330
+ //# sourceMappingURL=hooks-MRtQ3GE8.js.map