@assistant-ui/react-google-adk 0.0.35 → 0.0.36

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.
Files changed (65) hide show
  1. package/README.md +12 -2
  2. package/dist/AdkClient.d.ts +4 -0
  3. package/dist/AdkClient.d.ts.map +1 -1
  4. package/dist/AdkClient.js +12 -7
  5. package/dist/AdkClient.js.map +1 -1
  6. package/dist/AdkSessionAdapter.d.ts.map +1 -1
  7. package/dist/AdkSessionAdapter.js +7 -7
  8. package/dist/AdkSessionAdapter.js.map +1 -1
  9. package/dist/AdkThreadController.d.ts +15 -0
  10. package/dist/AdkThreadController.d.ts.map +1 -0
  11. package/dist/AdkThreadController.js +35 -0
  12. package/dist/AdkThreadController.js.map +1 -0
  13. package/dist/adkThreadState.d.ts +54 -0
  14. package/dist/adkThreadState.d.ts.map +1 -0
  15. package/dist/adkThreadState.js +93 -0
  16. package/dist/adkThreadState.js.map +1 -0
  17. package/dist/convertToAdkMessages.js +1 -1
  18. package/dist/convertToAdkMessages.js.map +1 -1
  19. package/dist/sdkIdentity.js +1 -1
  20. package/dist/server/createAdkApiRoute.d.ts +37 -6
  21. package/dist/server/createAdkApiRoute.d.ts.map +1 -1
  22. package/dist/server/createAdkApiRoute.js +55 -5
  23. package/dist/server/createAdkApiRoute.js.map +1 -1
  24. package/dist/server/parseAdkRequest.d.ts +4 -1
  25. package/dist/server/parseAdkRequest.d.ts.map +1 -1
  26. package/dist/server/parseAdkRequest.js +5 -1
  27. package/dist/server/parseAdkRequest.js.map +1 -1
  28. package/dist/useAdkMessages.d.ts +9 -7
  29. package/dist/useAdkMessages.d.ts.map +1 -1
  30. package/dist/useAdkMessages.js +55 -77
  31. package/dist/useAdkMessages.js.map +1 -1
  32. package/dist/useAdkRuntime.d.ts +7 -1
  33. package/dist/useAdkRuntime.d.ts.map +1 -1
  34. package/dist/useAdkRuntime.js +134 -56
  35. package/dist/useAdkRuntime.js.map +1 -1
  36. package/package.json +5 -5
  37. package/src/AdkClient.test.ts +78 -2
  38. package/src/AdkClient.ts +24 -6
  39. package/src/AdkSessionAdapter.ts +1 -1
  40. package/src/AdkThreadController.test.ts +90 -0
  41. package/src/AdkThreadController.ts +45 -0
  42. package/src/adkThreadState.test.ts +207 -0
  43. package/src/adkThreadState.ts +124 -0
  44. package/src/convertToAdkMessages.test.ts +19 -0
  45. package/src/convertToAdkMessages.ts +1 -1
  46. package/src/hooks.test.tsx +1 -0
  47. package/src/server/createAdkApiRoute.controls.test.ts +66 -0
  48. package/src/server/createAdkApiRoute.test.ts +282 -0
  49. package/src/server/createAdkApiRoute.ts +119 -11
  50. package/src/server/parseAdkRequest.test.ts +11 -3
  51. package/src/server/parseAdkRequest.ts +7 -1
  52. package/src/useAdkMessages.test.ts +1 -0
  53. package/src/useAdkMessages.ts +61 -96
  54. package/src/useAdkRuntime.cancellation.test.tsx +4 -3
  55. package/src/useAdkRuntime.cloud-options.test.tsx +59 -0
  56. package/src/useAdkRuntime.refetch.test.tsx +548 -4
  57. package/src/useAdkRuntime.replacement.test.tsx +718 -1
  58. package/src/useAdkRuntime.ts +169 -73
  59. package/src/useAdkRuntimeApproval.test.tsx +87 -1
  60. package/dist/raceWithAbortSignal.d.ts +0 -2
  61. package/dist/raceWithAbortSignal.d.ts.map +0 -1
  62. package/dist/raceWithAbortSignal.js +0 -45
  63. package/dist/raceWithAbortSignal.js.map +0 -1
  64. package/src/raceWithAbortSignal.test.ts +0 -73
  65. package/src/raceWithAbortSignal.ts +0 -48
@@ -1 +1 @@
1
- {"version":3,"file":"useAdkMessages.js","names":[],"sources":["../src/useAdkMessages.ts"],"sourcesContent":["import { isRecord } from \"@assistant-ui/core/internal\";\nimport {\n useState,\n useCallback,\n useInsertionEffect,\n useRef,\n useMemo,\n} from \"react\";\nimport { generateId } from \"@assistant-ui/core\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n abortableIterable,\n invokeUserCallback,\n openAbortableIterable,\n} from \"@assistant-ui/core/internal\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { contentToParts } from \"./contentToParts\";\nimport { toAdkFunctionResponse } from \"./toAdkFunctionResponse\";\nimport type {\n AdkEvent,\n AdkMessage,\n AdkMessageMetadata,\n AdkSendMessageConfig,\n AdkStreamCallback,\n AdkToolConfirmation,\n AdkAuthRequest,\n AdkThreadSnapshot,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\n\nexport type UseAdkMessagesOptions = {\n stream: AdkStreamCallback;\n eventHandlers?: {\n onError?: OnAdkErrorCallback;\n onCustomEvent?: OnAdkCustomEventCallback;\n onAgentTransfer?: OnAdkAgentTransferCallback;\n };\n};\n\ntype UseAdkMessagesInternalOptions = UseAdkMessagesOptions & {\n onMessages?: (messages: AdkMessage[], runConfig: unknown) => void;\n};\n\ntype AdkRuntimeCallbackName = \"onError\" | \"onCustomEvent\" | \"onAgentTransfer\";\n\nconst invokeAdkRuntimeCallback = <TArgs extends readonly unknown[]>(\n name: AdkRuntimeCallbackName,\n callback: ((...args: TArgs) => unknown) | undefined,\n ...args: TArgs\n): void => {\n void invokeUserCallback(\"react-google-adk\", name, callback, ...args);\n};\n\nconst useAdkMessagesInternal = ({\n stream,\n eventHandlers,\n onMessages,\n}: UseAdkMessagesInternalOptions) => {\n const [messages, _setMessages] = useState<AdkMessage[]>([]);\n const [stateDelta, setStateDelta] = useState<Record<string, unknown>>({});\n const [agentInfo, setAgentInfo] = useState<{\n name?: string | undefined;\n branch?: string | undefined;\n }>({});\n const [longRunningToolIds, _setLongRunningToolIds] = useState<string[]>([]);\n const [artifactDelta, setArtifactDelta] = useState<Record<string, number>>(\n {},\n );\n const [toolConfirmations, setToolConfirmations] = useState<\n AdkToolConfirmation[]\n >([]);\n const [authRequests, setAuthRequests] = useState<AdkAuthRequest[]>([]);\n const [escalated, setEscalated] = useState(false);\n const [messageMetadata, setMessageMetadata] = useState<\n Map<string, AdkMessageMetadata>\n >(new Map());\n // setMessagesImmediate and setLongRunningToolIds are the only writers of their state and publish these refs with it, so neither ref trails a commit.\n const messagesRef = useRef(messages);\n const longRunningToolIdsRef = useRef(longRunningToolIds);\n const stateDeltaRef = useRef(stateDelta);\n useInsertionEffect(() => {\n stateDeltaRef.current = stateDelta;\n }, [stateDelta]);\n const artifactDeltaRef = useRef(artifactDelta);\n useInsertionEffect(() => {\n artifactDeltaRef.current = artifactDelta;\n }, [artifactDelta]);\n const messageMetadataRef = useRef(messageMetadata);\n useInsertionEffect(() => {\n messageMetadataRef.current = messageMetadata;\n }, [messageMetadata]);\n\n const setMessagesImmediate = useCallback((msgs: AdkMessage[]) => {\n messagesRef.current = msgs;\n _setMessages(msgs);\n }, []);\n const setLongRunningToolIds = useCallback((ids: string[]) => {\n longRunningToolIdsRef.current = ids;\n _setLongRunningToolIds(ids);\n }, []);\n\n /**\n * Swap the thread over to a loaded snapshot in one commit. Unlike\n * {@link replaceMessages} this never passes through a cleared state, so a\n * refetch that lands while a confirmation is on screen replaces it rather\n * than blanking it first.\n */\n const applySnapshot = useCallback(\n (snapshot: AdkThreadSnapshot) => {\n setMessagesImmediate(snapshot.messages);\n setLongRunningToolIds(snapshot.longRunningToolIds ?? []);\n setToolConfirmations(snapshot.toolConfirmations ?? []);\n setAuthRequests(snapshot.authRequests ?? []);\n setEscalated(snapshot.escalated ?? false);\n setMessageMetadata(snapshot.messageMetadata ?? new Map());\n setStateDelta(snapshot.stateDelta ?? {});\n setArtifactDelta(snapshot.artifactDelta ?? {});\n setAgentInfo(snapshot.agentInfo ?? {});\n },\n [setLongRunningToolIds, setMessagesImmediate],\n );\n\n // Replace the message list AND reset derived per-turn HITL state.\n // Used by truncation paths (edit, reload) so that stale interrupt\n // markers and per-message metadata from the removed messages don't leak\n // into the next turn.\n const replaceMessages = useCallback(\n (msgs: AdkMessage[]) => {\n setMessagesImmediate(msgs);\n setLongRunningToolIds([]);\n setToolConfirmations([]);\n setAuthRequests([]);\n setEscalated(false);\n setMessageMetadata(new Map());\n },\n [setLongRunningToolIds, setMessagesImmediate],\n );\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const { onError, onCustomEvent, onAgentTransfer } = useMemo(\n () => eventHandlers ?? {},\n [eventHandlers],\n );\n\n const aui = useAui();\n const sendMessage = useCallback(\n async (newMessages: AdkMessage[], config: AdkSendMessageConfig) => {\n const newMessagesWithId = newMessages.map((m) =>\n m.id ? m : { ...m, id: generateId() },\n ) as AdkMessage[];\n\n // A staged message is already in the thread under its own id, and the\n // merged event below re-emits the whole batch under the first one. Seeding\n // with the originals would leave every later staged id beside the merged\n // copy of itself.\n const resentIds = new Set(newMessagesWithId.map((m) => m.id));\n // The optimistic event for a tool-only batch carries no author, so the accumulator cannot settle the calls this send answers.\n const answeredToolCallIds = new Set(\n newMessagesWithId.flatMap((m) =>\n m.type === \"tool\" ? [m.tool_call_id] : [],\n ),\n );\n const accumulator = new AdkEventAccumulator(\n messagesRef.current.filter((m) => !resentIds.has(m.id)),\n longRunningToolIdsRef.current.filter(\n (id) => !answeredToolCallIds.has(id),\n ),\n );\n for (const event of messagesToEvents(newMessagesWithId)) {\n accumulator.processEvent(event);\n }\n const initialMessages = accumulator.getMessages();\n const initialMessageIds = new Set(initialMessages.map((m) => m.id));\n const initialLongRunningToolIds = accumulator.getLongRunningToolIds();\n setMessagesImmediate(initialMessages);\n setLongRunningToolIds(initialLongRunningToolIds);\n setToolConfirmations(accumulator.getToolConfirmations());\n setAuthRequests(accumulator.getAuthRequests());\n let lastTransferToAgent: string | undefined;\n\n // Google ADK replaces active runs, while React LangGraph queues sends.\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n try {\n const response = await openAbortableIterable(\n stream(newMessagesWithId, {\n ...config,\n abortSignal: abortController.signal,\n initialize: async () => {\n return await aui.threadListItem.initialize();\n },\n }),\n abortController.signal,\n );\n if (!response) return;\n\n for await (const event of abortableIterable(\n response,\n abortController.signal,\n )) {\n if (\n abortController.signal.aborted ||\n abortControllerRef.current !== abortController\n ) {\n break;\n }\n const updatedMessages = accumulator.processEvent(event);\n // Each event part can append at most one message, and a function call\n // stays on the current assistant message until a later part finalizes\n // it, so every message touched by this event is within this tail.\n const affectedMessageCount = Math.max(\n event.content?.parts?.length ?? 0,\n 1,\n );\n const affectedMessages = updatedMessages.slice(-affectedMessageCount);\n if (affectedMessages.length > 0) {\n onMessages?.(affectedMessages, config.runConfig);\n }\n setMessagesImmediate(updatedMessages);\n setStateDelta({\n ...stateDeltaRef.current,\n ...accumulator.getStateDelta(),\n });\n setAgentInfo(accumulator.getAgentInfo());\n setLongRunningToolIds(accumulator.getLongRunningToolIds());\n setArtifactDelta({\n ...artifactDeltaRef.current,\n ...accumulator.getArtifactDelta(),\n });\n setToolConfirmations(accumulator.getToolConfirmations());\n setAuthRequests(accumulator.getAuthRequests());\n setEscalated(accumulator.isEscalated());\n {\n const newMeta = accumulator.getMessageMetadata();\n if (newMeta.size > 0) {\n setMessageMetadata(\n new Map([...messageMetadataRef.current, ...newMeta]),\n );\n }\n }\n\n const transfer = accumulator.getLastTransferToAgent();\n if (transfer && transfer !== lastTransferToAgent) {\n lastTransferToAgent = transfer;\n invokeAdkRuntimeCallback(\n \"onAgentTransfer\",\n onAgentTransfer,\n transfer,\n );\n }\n\n // Fire custom event callback for events with customMetadata\n if (event.customMetadata && onCustomEvent) {\n for (const [key, value] of Object.entries(event.customMetadata)) {\n invokeAdkRuntimeCallback(\n \"onCustomEvent\",\n onCustomEvent,\n key,\n value,\n );\n }\n }\n\n if (event.errorCode || event.errorMessage) {\n invokeAdkRuntimeCallback(\n \"onError\",\n onError,\n event.errorMessage ?? event.errorCode,\n );\n }\n }\n } catch (error) {\n if (\n !abortController.signal.aborted &&\n abortControllerRef.current === abortController &&\n !(error instanceof Error && error.name === \"AbortError\")\n ) {\n throw error;\n }\n } finally {\n if (abortControllerRef.current === abortController) {\n if (abortController.signal.aborted) {\n setLongRunningToolIds(\n accumulator\n .getLongRunningToolIds()\n .filter((id) => initialLongRunningToolIds.includes(id)),\n );\n const updatedMessages = messagesRef.current;\n const lastAssistantMessage = updatedMessages.findLast(\n (m) => m.type === \"ai\",\n );\n if (\n lastAssistantMessage &&\n !initialMessageIds.has(lastAssistantMessage.id) &&\n !lastAssistantMessage.status\n ) {\n setMessagesImmediate(\n updatedMessages.map((m) =>\n m === lastAssistantMessage\n ? {\n ...lastAssistantMessage,\n status: { type: \"incomplete\", reason: \"cancelled\" },\n }\n : m,\n ),\n );\n }\n }\n abortControllerRef.current = null;\n }\n }\n },\n [\n aui,\n setMessagesImmediate,\n setLongRunningToolIds,\n stream,\n onError,\n onCustomEvent,\n onAgentTransfer,\n onMessages,\n ],\n );\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n }, []);\n\n useReplaySafeEffect(() => cancel, []);\n\n return {\n messages,\n stateDelta,\n agentInfo,\n longRunningToolIds,\n artifactDelta,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n sendMessage,\n cancel,\n setMessages: setMessagesImmediate,\n replaceMessages,\n applySnapshot,\n };\n};\n\nexport const useAdkMessages = ({\n stream,\n eventHandlers,\n}: UseAdkMessagesOptions) =>\n useAdkMessagesInternal({\n stream,\n ...(eventHandlers !== undefined && { eventHandlers }),\n });\n\nexport { useAdkMessagesInternal };\n\n/**\n * Transport sends every human and tool message of one `send` call as a single\n * ADK `Content`, and ADK parses that event's function responses before running\n * any tool, so the batch runs whole or not at all. The optimistic projection\n * has to sit on the same boundary, so a run of those messages becomes one\n * synthetic event whose parts come from the same per-message conversion.\n *\n * The transport drops `ai` messages from that `Content`, so one interleaved\n * between two replies does not split the batch on the wire and must not split\n * it here either. It still becomes its own event, placed after the merged one,\n * so the optimistic projection keeps the assistant turn.\n *\n * @internal — exported for unit tests.\n */\nexport const messagesToEvents = (messages: AdkMessage[]): AdkEvent[] => {\n // A reload sends no messages at all, and the empty user content the transport\n // puts on the wire for it is not part of the optimistic view: projecting one\n // would put an empty user bubble above every regenerated turn.\n if (messages.length === 0) return [];\n\n const events: AdkEvent[] = [];\n const run: AdkMessage[] = [];\n let runIndex = 0;\n\n for (const msg of messages) {\n if (msg.type === \"ai\") {\n events.push(messageToEvent(msg));\n } else {\n if (run.length === 0) runIndex = events.length;\n run.push(msg);\n }\n }\n\n const parts = run.flatMap((m) => messageToEvent(m).content?.parts ?? []);\n const human = run.find((m) => m.type === \"human\");\n\n // A batch that contributes no part still reaches the wire: the transport\n // sends an empty user `Content`, which a reload replays as an empty human\n // message. Emitting it here keeps the optimistic view equal to that replay.\n if (parts.length === 0) parts.push({ text: \"\" });\n\n const event: AdkEvent = { id: (human ?? run[0])?.id ?? generateId() };\n if (human || run.length === 0) event.author = \"user\";\n event.content = { role: \"user\", parts };\n events.splice(run.length > 0 ? runIndex : events.length, 0, event);\n\n return events;\n};\n\n/** @internal — exported for unit tests. */\nexport const messageToEvent = (msg: AdkMessage): AdkEvent => {\n if (msg.type === \"human\") {\n return {\n id: msg.id ?? generateId(),\n author: \"user\",\n content: { role: \"user\", parts: contentToParts(msg.content) },\n };\n }\n\n if (msg.type === \"tool\") {\n let response: unknown;\n try {\n response = JSON.parse(msg.content);\n } catch {\n response = msg.content;\n }\n return {\n id: msg.id ?? generateId(),\n content: {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response: toAdkFunctionResponse(response, msg.status === \"error\"),\n },\n },\n ],\n },\n };\n }\n\n const result: AdkEvent = { id: msg.id ?? generateId() };\n if (msg.author != null) result.author = msg.author;\n result.content = {\n role: \"model\",\n parts: [\n ...contentToParts(msg.content),\n ...(msg.tool_calls ?? []).filter(isRecord).map((tc) => ({\n functionCall: { name: tc.name, id: tc.id, args: { ...tc.args } },\n })),\n ],\n };\n return result;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useAdkMessages.js","names":[],"sources":["../src/useAdkMessages.ts"],"sourcesContent":["import { isRecord } from \"@assistant-ui/core/internal\";\nimport {\n useState,\n useCallback,\n useRef,\n useMemo,\n useSyncExternalStore,\n} from \"react\";\nimport { generateId } from \"@assistant-ui/core\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n abortableIterable,\n invokeUserCallback,\n openAbortableIterable,\n} from \"@assistant-ui/core/internal\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { AdkThreadController } from \"./AdkThreadController\";\nimport { contentToParts } from \"./contentToParts\";\nimport { toAdkFunctionResponse } from \"./toAdkFunctionResponse\";\nimport type {\n AdkEvent,\n AdkMessage,\n AdkSendMessageConfig,\n AdkStreamCallback,\n AdkThreadSnapshot,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\n\nexport type UseAdkMessagesOptions = {\n stream: AdkStreamCallback;\n eventHandlers?: {\n onError?: OnAdkErrorCallback;\n onCustomEvent?: OnAdkCustomEventCallback;\n onAgentTransfer?: OnAdkAgentTransferCallback;\n };\n};\n\ntype UseAdkMessagesInternalOptions = UseAdkMessagesOptions & {\n onMessages?: (messages: AdkMessage[], runConfig: unknown) => void;\n};\n\ntype AdkRuntimeCallbackName = \"onError\" | \"onCustomEvent\" | \"onAgentTransfer\";\n\nconst invokeAdkRuntimeCallback = <TArgs extends readonly unknown[]>(\n name: AdkRuntimeCallbackName,\n callback: ((...args: TArgs) => unknown) | undefined,\n ...args: TArgs\n): void => {\n void invokeUserCallback(\"react-google-adk\", name, callback, ...args);\n};\n\nconst useAdkMessagesInternal = ({\n stream,\n eventHandlers,\n onMessages,\n}: UseAdkMessagesInternalOptions) => {\n const [controller] = useState(() => new AdkThreadController());\n const {\n messages,\n stateDelta,\n agentInfo,\n longRunningToolIds,\n artifactDelta,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n } = useSyncExternalStore(\n controller.subscribe,\n controller.getState,\n controller.getState,\n );\n\n const setMessagesImmediate = useCallback(\n (msgs: AdkMessage[]) => {\n controller.dispatch({ type: \"messages.set\", messages: msgs });\n },\n [controller],\n );\n /**\n * Swap the thread over to a loaded snapshot in one commit. Unlike\n * {@link replaceMessages} this never passes through a cleared state, so a\n * refetch that lands while a confirmation is on screen replaces it rather\n * than blanking it first.\n */\n const applySnapshot = useCallback(\n (snapshot: AdkThreadSnapshot) => {\n controller.dispatch({ type: \"snapshot.applied\", snapshot });\n },\n [controller],\n );\n\n // Replace the message list AND reset derived per-turn HITL state.\n // Used by truncation paths (edit, reload) so that stale interrupt\n // markers and per-message metadata from the removed messages don't leak\n // into the next turn.\n const replaceMessages = useCallback(\n (msgs: AdkMessage[]) => {\n controller.dispatch({ type: \"messages.replaced\", messages: msgs });\n },\n [controller],\n );\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const { onError, onCustomEvent, onAgentTransfer } = useMemo(\n () => eventHandlers ?? {},\n [eventHandlers],\n );\n\n const aui = useAui();\n const sendMessage = useCallback(\n async (newMessages: AdkMessage[], config: AdkSendMessageConfig) => {\n const newMessagesWithId = newMessages.map((m) =>\n m.id ? m : { ...m, id: generateId() },\n ) as AdkMessage[];\n\n // A staged message is already in the thread under its own id, and the\n // merged event below re-emits the whole batch under the first one. Seeding\n // with the originals would leave every later staged id beside the merged\n // copy of itself.\n const resentIds = new Set(newMessagesWithId.map((m) => m.id));\n // The optimistic event for a tool-only batch carries no author, so the accumulator cannot settle the calls this send answers.\n const answeredToolCallIds = new Set(\n newMessagesWithId.flatMap((m) =>\n m.type === \"tool\" ? [m.tool_call_id] : [],\n ),\n );\n const currentState = controller.getState();\n const accumulator = new AdkEventAccumulator(\n currentState.messages.filter((m) => !resentIds.has(m.id)),\n currentState.longRunningToolIds.filter(\n (id) => !answeredToolCallIds.has(id),\n ),\n );\n for (const event of messagesToEvents(newMessagesWithId)) {\n accumulator.processEvent(event);\n }\n const initialMessages = accumulator.getMessages();\n const initialMessageIds = new Set(initialMessages.map((m) => m.id));\n const initialLongRunningToolIds = accumulator.getLongRunningToolIds();\n controller.dispatch({\n type: \"run.started\",\n messages: initialMessages,\n longRunningToolIds: initialLongRunningToolIds,\n toolConfirmations: accumulator.getToolConfirmations(),\n authRequests: accumulator.getAuthRequests(),\n });\n let lastTransferToAgent: string | undefined;\n\n // Google ADK replaces active runs, while React LangGraph queues sends.\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n try {\n const response = await openAbortableIterable(\n stream(newMessagesWithId, {\n ...config,\n abortSignal: abortController.signal,\n initialize: async () => {\n return await aui.threadListItem.initialize();\n },\n }),\n abortController.signal,\n );\n if (!response) return;\n\n for await (const event of abortableIterable(\n response,\n abortController.signal,\n )) {\n if (\n abortController.signal.aborted ||\n abortControllerRef.current !== abortController\n ) {\n break;\n }\n const updatedMessages = accumulator.processEvent(event);\n // Each event part can append at most one message, and a function call\n // stays on the current assistant message until a later part finalizes\n // it, so every message touched by this event is within this tail.\n const affectedMessageCount = Math.max(\n event.content?.parts?.length ?? 0,\n 1,\n );\n const affectedMessages = updatedMessages.slice(-affectedMessageCount);\n if (affectedMessages.length > 0) {\n onMessages?.(affectedMessages, config.runConfig);\n }\n controller.dispatch({\n type: \"event.published\",\n state: {\n messages: updatedMessages,\n stateDelta: accumulator.getStateDelta(),\n agentInfo: accumulator.getAgentInfo(),\n longRunningToolIds: accumulator.getLongRunningToolIds(),\n artifactDelta: accumulator.getArtifactDelta(),\n toolConfirmations: accumulator.getToolConfirmations(),\n authRequests: accumulator.getAuthRequests(),\n escalated: accumulator.isEscalated(),\n messageMetadata: accumulator.getMessageMetadata(),\n },\n });\n\n const transfer = accumulator.getLastTransferToAgent();\n if (transfer && transfer !== lastTransferToAgent) {\n lastTransferToAgent = transfer;\n invokeAdkRuntimeCallback(\n \"onAgentTransfer\",\n onAgentTransfer,\n transfer,\n );\n }\n\n // Fire custom event callback for events with customMetadata\n if (event.customMetadata && onCustomEvent) {\n for (const [key, value] of Object.entries(event.customMetadata)) {\n invokeAdkRuntimeCallback(\n \"onCustomEvent\",\n onCustomEvent,\n key,\n value,\n );\n }\n }\n\n if (event.errorCode || event.errorMessage) {\n invokeAdkRuntimeCallback(\n \"onError\",\n onError,\n event.errorMessage ?? event.errorCode,\n );\n }\n }\n } catch (error) {\n if (\n !abortController.signal.aborted &&\n abortControllerRef.current === abortController &&\n !(error instanceof Error && error.name === \"AbortError\")\n ) {\n throw error;\n }\n } finally {\n if (abortControllerRef.current === abortController) {\n if (abortController.signal.aborted) {\n controller.dispatch({\n type: \"longRunningToolIds.set\",\n ids: accumulator\n .getLongRunningToolIds()\n .filter((id) => initialLongRunningToolIds.includes(id)),\n });\n const updatedMessages = controller.getState().messages;\n const lastAssistantMessage = updatedMessages.findLast(\n (m) => m.type === \"ai\",\n );\n if (\n lastAssistantMessage &&\n !initialMessageIds.has(lastAssistantMessage.id) &&\n !lastAssistantMessage.status\n ) {\n setMessagesImmediate(\n updatedMessages.map((m) =>\n m === lastAssistantMessage\n ? {\n ...lastAssistantMessage,\n status: { type: \"incomplete\", reason: \"cancelled\" },\n }\n : m,\n ),\n );\n }\n }\n abortControllerRef.current = null;\n }\n }\n },\n [\n aui,\n controller,\n setMessagesImmediate,\n stream,\n onError,\n onCustomEvent,\n onAgentTransfer,\n onMessages,\n ],\n );\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n }, []);\n\n useReplaySafeEffect(() => cancel, []);\n\n return {\n controller,\n messages,\n stateDelta,\n agentInfo,\n longRunningToolIds,\n artifactDelta,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n sendMessage,\n cancel,\n setMessages: setMessagesImmediate,\n replaceMessages,\n applySnapshot,\n };\n};\n\nexport const useAdkMessages = ({\n stream,\n eventHandlers,\n}: UseAdkMessagesOptions) => {\n const { controller: _controller, ...result } = useAdkMessagesInternal({\n stream,\n ...(eventHandlers !== undefined && { eventHandlers }),\n });\n return result;\n};\n\nexport { useAdkMessagesInternal };\n\n/**\n * Transport sends every human and tool message of one `send` call as a single\n * ADK `Content`, and ADK parses that event's function responses before running\n * any tool, so the batch runs whole or not at all. The optimistic projection\n * has to sit on the same boundary, so a run of those messages becomes one\n * synthetic event whose parts come from the same per-message conversion.\n *\n * The transport drops `ai` messages from that `Content`, so one interleaved\n * between two replies does not split the batch on the wire and must not split\n * it here either. It still becomes its own event, placed after the merged one,\n * so the optimistic projection keeps the assistant turn.\n *\n * @internal — exported for unit tests.\n */\nexport const messagesToEvents = (messages: AdkMessage[]): AdkEvent[] => {\n // A reload sends no messages at all, and the empty user content the transport\n // puts on the wire for it is not part of the optimistic view: projecting one\n // would put an empty user bubble above every regenerated turn.\n if (messages.length === 0) return [];\n\n const events: AdkEvent[] = [];\n const run: AdkMessage[] = [];\n let runIndex = 0;\n\n for (const msg of messages) {\n if (msg.type === \"ai\") {\n events.push(messageToEvent(msg));\n } else {\n if (run.length === 0) runIndex = events.length;\n run.push(msg);\n }\n }\n\n const parts = run.flatMap((m) => messageToEvent(m).content?.parts ?? []);\n const human = run.find((m) => m.type === \"human\");\n\n // A batch that contributes no part still reaches the wire: the transport\n // sends an empty user `Content`, which a reload replays as an empty human\n // message. Emitting it here keeps the optimistic view equal to that replay.\n if (parts.length === 0) parts.push({ text: \"\" });\n\n const event: AdkEvent = { id: (human ?? run[0])?.id ?? generateId() };\n if (human || run.length === 0) event.author = \"user\";\n event.content = { role: \"user\", parts };\n events.splice(run.length > 0 ? runIndex : events.length, 0, event);\n\n return events;\n};\n\n/** @internal — exported for unit tests. */\nexport const messageToEvent = (msg: AdkMessage): AdkEvent => {\n if (msg.type === \"human\") {\n return {\n id: msg.id ?? generateId(),\n author: \"user\",\n content: { role: \"user\", parts: contentToParts(msg.content) },\n };\n }\n\n if (msg.type === \"tool\") {\n let response: unknown;\n try {\n response = JSON.parse(msg.content);\n } catch {\n response = msg.content;\n }\n return {\n id: msg.id ?? generateId(),\n content: {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response: toAdkFunctionResponse(response, msg.status === \"error\"),\n },\n },\n ],\n },\n };\n }\n\n const result: AdkEvent = { id: msg.id ?? generateId() };\n if (msg.author != null) result.author = msg.author;\n result.content = {\n role: \"model\",\n parts: [\n ...contentToParts(msg.content),\n ...(msg.tool_calls ?? []).filter(isRecord).map((tc) => ({\n functionCall: { name: tc.name, id: tc.id, args: { ...tc.args } },\n })),\n ],\n };\n return result;\n};\n"],"mappings":"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"}
@@ -14,6 +14,7 @@ export type UseAdkRuntimeOptions = ExternalStoreSharedOptions & {
14
14
  */
15
15
  onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;
16
16
  autoCancelPendingToolCalls?: boolean | undefined;
17
+ /** @deprecated Experimental since 2025-01-03. Not scheduled for removal; the API may change in any release. */
17
18
  unstable_allowCancellation?: boolean | undefined;
18
19
  getCheckpointId?: (threadId: string, parentMessages: AdkMessage[]) => Promise<string | null>;
19
20
  /**
@@ -42,11 +43,16 @@ export type UseAdkRuntimeOptions = ExternalStoreSharedOptions & {
42
43
  onAgentTransfer?: OnAdkAgentTransferCallback;
43
44
  } | undefined;
44
45
  cloud?: AssistantCloud | undefined;
46
+ /**
47
+ * Stable identity for the account or workspace owning Cloud runtime state.
48
+ * Provide it from the first render and change it when that scope changes.
49
+ */
50
+ scopeId?: string | undefined;
45
51
  /**
46
52
  * A `RemoteThreadListAdapter` to use instead of the cloud adapter.
47
53
  * Use with `createAdkSessionAdapter` for ADK session-backed persistence.
48
54
  */
49
55
  sessionAdapter?: RemoteThreadListAdapter | undefined;
50
56
  };
51
- export declare const useAdkRuntime: ({ cloud, sessionAdapter, create, delete: deleteFn, onThreadIdChange, ...options }: UseAdkRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
57
+ export declare const useAdkRuntime: ({ cloud, scopeId, sessionAdapter, create, delete: deleteFn, onThreadIdChange, ...options }: UseAdkRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
52
58
  //# sourceMappingURL=useAdkRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAdkRuntime.d.ts","sourceRoot":"","sources":["../src/useAdkRuntime.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAK5B,MAAM,oBAAoB,CAAC;AAc5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAEjB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC3B,mBAAgB;AAmBjB,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG;IAC9D,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxE,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,UAAU,EAAE,KACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,CACL,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,KAC3C,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAChC,SAAS,CAAC,EAAE,gBAAgB,CAAC;QAC7B,KAAK,CAAC,EAAE,oBAAoB,CAAC;QAC7B,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,GACD,SAAS,CAAC;IACd,aAAa,CAAC,EACV;QACE,OAAO,CAAC,EAAE,kBAAkB,CAAC;QAC7B,aAAa,CAAC,EAAE,wBAAwB,CAAC;QACzC,eAAe,CAAC,EAAE,0BAA0B,CAAC;KAC9C,GACD,SAAS,CAAC;IACd,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;CACtD,CAAC;AAkdF,eAAO,MAAM,aAAa,GAAI,mFAO3B,oBAAoB,kDAsBtB,CAAC"}
1
+ {"version":3,"file":"useAdkRuntime.d.ts","sourceRoot":"","sources":["../src/useAdkRuntime.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAK5B,MAAM,oBAAoB,CAAC;AAgB5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAEjB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC3B,mBAAgB;AAmBjB,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG;IAC9D,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxE,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,+GAA+G;IAC/G,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,UAAU,EAAE,KACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,CACL,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,KAC3C,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAChC,SAAS,CAAC,EAAE,gBAAgB,CAAC;QAC7B,KAAK,CAAC,EAAE,oBAAoB,CAAC;QAC7B,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,GACD,SAAS,CAAC;IACd,aAAa,CAAC,EACV;QACE,OAAO,CAAC,EAAE,kBAAkB,CAAC;QAC7B,aAAa,CAAC,EAAE,wBAAwB,CAAC;QACzC,eAAe,CAAC,EAAE,0BAA0B,CAAC;KAC9C,GACD,SAAS,CAAC;IACd,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;OAGG;IACH,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;CACtD,CAAC;AAuiBF,eAAO,MAAM,aAAa,GAAI,4FAQ3B,oBAAoB,kDAuBtB,CAAC"}
@@ -4,12 +4,12 @@ import { convertAdkMessage, createAdkMessageConverter } from "./convertAdkMessag
4
4
  import { getMessageContent, getPendingCancellations, toAdkUserMessage, truncateAdkMessages } from "./convertToAdkMessages.js";
5
5
  import { useAdkMessagesInternal } from "./useAdkMessages.js";
6
6
  import { ADK_SDK } from "./sdkIdentity.js";
7
- import { createAbortableThreadLoad, createCloudThreadListAdapterCreateFallback, isRecord } from "@assistant-ui/core/internal";
7
+ import { RunLeases, createAbortableThreadLoad, createCloudThreadListAdapterCreateFallback, isRecord } from "@assistant-ui/core/internal";
8
8
  import { generateId, pickExternalStoreSharedOptions } from "@assistant-ui/core";
9
9
  import { useCloudThreadListAdapter, useExternalMessageConverter, useExternalStoreRuntime, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
10
10
  import { useAui } from "@assistant-ui/store";
11
11
  import { useReplaySafeEffect } from "@assistant-ui/store/internal";
12
- import { useCallback, useInsertionEffect, useMemo, useRef, useState } from "react";
12
+ import { useCallback, useInsertionEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
13
13
  //#region src/useAdkRuntime.ts
14
14
  const useAdkRuntimeImpl = (options) => {
15
15
  const { autoCancelPendingToolCalls, adapters: { attachments, dictation, feedback, speech, voice } = {}, unstable_allowCancellation, stream, load, getCheckpointId, eventHandlers } = options;
@@ -51,7 +51,7 @@ const useAdkRuntimeImpl = (options) => {
51
51
  const getToolRunConfig = useCallback((toolCallId) => {
52
52
  return runConfigByToolCallIdRef.current.get(toolCallId);
53
53
  }, []);
54
- const { messages, stateDelta, agentInfo, longRunningToolIds, artifactDelta, toolConfirmations, authRequests, escalated, messageMetadata, sendMessage, cancel, setMessages, replaceMessages: replaceAdkMessages, applySnapshot: applyAdkSnapshot } = useAdkMessagesInternal({
54
+ const { controller, messages, stateDelta, agentInfo, longRunningToolIds, artifactDelta, toolConfirmations, authRequests, escalated, messageMetadata, sendMessage, cancel, setMessages, replaceMessages: replaceAdkMessages, applySnapshot: applyAdkSnapshot } = useAdkMessagesInternal({
55
55
  stream,
56
56
  ...eventHandlers && { eventHandlers },
57
57
  onMessages: rememberMessageOwnership
@@ -61,6 +61,15 @@ const useAdkRuntimeImpl = (options) => {
61
61
  loadRef.current = load;
62
62
  }, [load]);
63
63
  const [loadController] = useState(createAbortableThreadLoad);
64
+ const initialLoadRef = useRef(null);
65
+ const waitForInitialLoad = () => {
66
+ const load = initialLoadRef.current;
67
+ if (!load) return void 0;
68
+ return load.promise.then(() => ({
69
+ active: load.active && (!threadListItem || aui.threads.getState().mainThreadId === threadListItem.getState().id),
70
+ snapshot: load.snapshot
71
+ }));
72
+ };
64
73
  const messagesRef = useRef(messages);
65
74
  useInsertionEffect(() => {
66
75
  messagesRef.current = messages;
@@ -82,20 +91,29 @@ const useAdkRuntimeImpl = (options) => {
82
91
  useInsertionEffect(() => {
83
92
  isRunningRef.current = effectiveIsRunning;
84
93
  }, [effectiveIsRunning]);
85
- const runGenerationRef = useRef(0);
86
- const handleSendMessage = async (msgs, config) => {
87
- const continuationConfig = msgs.length > 0 && msgs.every((msg) => msg.type === "tool") && config.runConfig === void 0 ? {
88
- ...config,
89
- runConfig: getToolRunConfig(msgs[0].tool_call_id)
90
- } : config;
91
- const generation = ++runGenerationRef.current;
94
+ const [runLeases] = useState(() => new RunLeases());
95
+ const reloadLookupRef = useRef(null);
96
+ const runExclusive = async (run) => {
97
+ const lease = runLeases.begin();
92
98
  try {
93
99
  setIsRunning(true);
94
- await sendMessage(msgs, continuationConfig);
100
+ await run(lease.isCurrent);
95
101
  } finally {
96
- if (runGenerationRef.current === generation) setIsRunning(false);
102
+ if (lease.isCurrent()) setIsRunning(false);
97
103
  }
98
104
  };
105
+ const handleSendMessage = (msgs, config) => {
106
+ const continuationConfig = msgs.length > 0 && msgs.every((msg) => msg.type === "tool") && config.runConfig === void 0 ? {
107
+ ...config,
108
+ runConfig: getToolRunConfig(msgs[0].tool_call_id)
109
+ } : config;
110
+ return runExclusive(() => sendMessage(msgs, continuationConfig));
111
+ };
112
+ const stopRun = () => {
113
+ runLeases.invalidate();
114
+ setIsRunning(false);
115
+ cancel();
116
+ };
99
117
  const { approvals: toolApprovals, key: toolApprovalsKey } = projectAdkToolApprovals(messages);
100
118
  const toolApprovalsRef = useRef(toolApprovals);
101
119
  toolApprovalsRef.current = toolApprovals;
@@ -118,29 +136,17 @@ const useAdkRuntimeImpl = (options) => {
118
136
  useInsertionEffect(() => {
119
137
  adkMessagesRef.current = messages;
120
138
  }, [messages]);
121
- const stagedMessagesRef = useRef(/* @__PURE__ */ new Map());
122
- const [stagedMessageCount, setStagedMessageCount] = useState(0);
123
- const hasStagedMessages = stagedMessageCount > 0;
124
- const getStagedRun = (parentId) => {
125
- if (!parentId || !stagedMessagesRef.current.has(parentId)) return null;
126
- const staged = [];
127
- for (const message of adkMessagesRef.current) {
128
- if (message.id && stagedMessagesRef.current.has(message.id)) staged.push(stagedMessagesRef.current.get(message.id).message);
129
- if (message.id === parentId) break;
130
- }
131
- return {
132
- messages: staged,
133
- runConfig: stagedMessagesRef.current.get(parentId).runConfig
134
- };
135
- };
139
+ const hasStagedMessages = useSyncExternalStore(controller.subscribe, controller.getStagedMessageCount, controller.getStagedMessageCount) > 0;
136
140
  const stageUserMessage = (msg) => {
137
141
  const stagedMessage = toAdkUserMessage(msg);
138
- stagedMessagesRef.current.set(stagedMessage.id, {
139
- message: stagedMessage,
140
- runConfig: msg.runConfig
142
+ controller.dispatch({
143
+ type: "staged.stage",
144
+ entry: {
145
+ message: stagedMessage,
146
+ runConfig: msg.runConfig
147
+ }
141
148
  });
142
- setStagedMessageCount(stagedMessagesRef.current.size);
143
- const nextMessages = [...adkMessagesRef.current, stagedMessage];
149
+ const nextMessages = [...controller.getState().messages, stagedMessage];
144
150
  adkMessagesRef.current = nextMessages;
145
151
  setMessages(nextMessages);
146
152
  };
@@ -158,7 +164,12 @@ const useAdkRuntimeImpl = (options) => {
158
164
  const snapshot = await loadFn(externalId, { signal });
159
165
  if (signal.aborted) return;
160
166
  if (purpose === "reload" && (isRunningRef.current || messagesRef.current !== messagesAtLoadStart)) return;
167
+ reloadLookupRef.current = null;
161
168
  applySnapshot(snapshot);
169
+ messagesRef.current = snapshot.messages;
170
+ adkMessagesRef.current = snapshot.messages;
171
+ longRunningToolIdsRef.current = snapshot.longRunningToolIds ?? [];
172
+ if (purpose === "initial" && initialLoadRef.current) initialLoadRef.current.snapshot = snapshot;
162
173
  },
163
174
  onSettled: () => {
164
175
  setIsLoadingThread(false);
@@ -173,9 +184,24 @@ const useAdkRuntimeImpl = (options) => {
173
184
  applySnapshot
174
185
  ]);
175
186
  useReplaySafeEffect(() => {
176
- runLoad();
187
+ let release;
188
+ const barrier = {
189
+ promise: new Promise((resolve) => {
190
+ release = resolve;
191
+ }),
192
+ active: true,
193
+ snapshot: void 0
194
+ };
195
+ initialLoadRef.current = barrier;
196
+ const settle = () => {
197
+ if (initialLoadRef.current === barrier) initialLoadRef.current = null;
198
+ release();
199
+ };
200
+ runLoad().then(settle, settle);
177
201
  return () => {
202
+ barrier.active = false;
178
203
  loadController.abort();
204
+ settle();
179
205
  setIsLoadingThread(false);
180
206
  };
181
207
  }, [threadListItem]);
@@ -203,14 +229,20 @@ const useAdkRuntimeImpl = (options) => {
203
229
  authRequests,
204
230
  escalated,
205
231
  messageMetadata,
206
- send: handleSendMessage
232
+ send: (messages, config) => {
233
+ const initialLoad = waitForInitialLoad();
234
+ if (!initialLoad) return handleSendMessage(messages, config);
235
+ return initialLoad.then(({ active }) => active ? handleSendMessage(messages, config) : void 0);
236
+ }
207
237
  }),
208
238
  onNew: async (msg) => {
239
+ const initialLoad = await waitForInitialLoad();
240
+ if (initialLoad && !initialLoad.active) return;
209
241
  if (!(msg.startRun ?? msg.role === "user")) {
210
242
  stageUserMessage(msg);
211
243
  return;
212
244
  }
213
- const cancellations = autoCancelPendingToolCalls !== false ? getPendingCancellations(messages, longRunningToolIds) : [];
245
+ const cancellations = autoCancelPendingToolCalls !== false ? getPendingCancellations(initialLoad?.snapshot?.messages ?? messagesRef.current, initialLoad?.snapshot?.longRunningToolIds ?? longRunningToolIdsRef.current) : [];
214
246
  return handleSendMessage([...cancellations, {
215
247
  id: generateId(),
216
248
  type: "human",
@@ -218,49 +250,89 @@ const useAdkRuntimeImpl = (options) => {
218
250
  }], { runConfig: msg.runConfig });
219
251
  },
220
252
  onEdit: getCheckpointId ? async (msg) => {
253
+ const initialLoad = waitForInitialLoad();
254
+ if (initialLoad && !(await initialLoad).active) return;
255
+ stopRun();
221
256
  const truncated = truncateAdkMessages(threadMessagesRef.current, msg.parentId);
222
257
  replaceMessages(truncated);
223
258
  if (!(msg.startRun ?? msg.role === "user")) {
224
259
  const stagedMessage = toAdkUserMessage(msg);
225
- stagedMessagesRef.current.set(stagedMessage.id, {
226
- message: stagedMessage,
227
- runConfig: msg.runConfig
260
+ controller.dispatch({
261
+ type: "staged.stage",
262
+ entry: {
263
+ message: stagedMessage,
264
+ runConfig: msg.runConfig
265
+ }
228
266
  });
229
- setStagedMessageCount(stagedMessagesRef.current.size);
230
267
  const nextMessages = [...truncated, stagedMessage];
231
268
  adkMessagesRef.current = nextMessages;
232
269
  setMessages(nextMessages);
233
270
  return;
234
271
  }
272
+ const editedMessage = toAdkUserMessage(msg);
273
+ setMessages([...truncated, editedMessage]);
235
274
  const externalId = aui.threadListItem.getState().externalId;
236
- const checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
237
- return handleSendMessage([{
238
- id: generateId(),
239
- type: "human",
240
- content: getMessageContent(msg)
241
- }], {
242
- runConfig: msg.runConfig,
243
- ...checkpointId && { checkpointId }
275
+ return runExclusive(async (isCurrent) => {
276
+ const checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
277
+ if (!isCurrent()) return;
278
+ await sendMessage([editedMessage], {
279
+ runConfig: msg.runConfig,
280
+ ...checkpointId && { checkpointId }
281
+ });
244
282
  });
245
283
  } : void 0,
246
284
  ...getCheckpointId || hasStagedMessages ? { onReload: async (parentId, config) => {
247
- const stagedRun = getStagedRun(parentId);
285
+ const initialLoad = waitForInitialLoad();
286
+ if (initialLoad && !(await initialLoad).active) return;
287
+ const stagedRun = controller.getStagedRun(parentId);
248
288
  if (stagedRun) {
249
- for (const message of stagedRun.messages) stagedMessagesRef.current.delete(message.id);
250
- setStagedMessageCount(stagedMessagesRef.current.size);
289
+ controller.dispatch({
290
+ type: "staged.unstage",
291
+ ids: stagedRun.messages.map((message) => message.id)
292
+ });
251
293
  return handleSendMessage(stagedRun.messages, { runConfig: config.runConfig ?? stagedRun.runConfig });
252
294
  }
253
295
  if (!getCheckpointId) throw new Error("Runtime does not support reloading messages.");
296
+ stopRun();
297
+ const beforeReload = {
298
+ messages: adkMessagesRef.current,
299
+ longRunningToolIds,
300
+ toolConfirmations,
301
+ authRequests,
302
+ escalated,
303
+ messageMetadata,
304
+ stateDelta,
305
+ artifactDelta,
306
+ agentInfo
307
+ };
254
308
  const truncated = truncateAdkMessages(threadMessagesRef.current, parentId);
255
309
  replaceMessages(truncated);
256
310
  const externalId = aui.threadListItem.getState().externalId;
257
- const checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
258
- return handleSendMessage([], {
259
- runConfig: config.runConfig,
260
- ...checkpointId && { checkpointId }
311
+ return runExclusive(async (isCurrent) => {
312
+ const lookup = {
313
+ lease: runLeases.current(),
314
+ beforeReload
315
+ };
316
+ reloadLookupRef.current = lookup;
317
+ let checkpointId;
318
+ try {
319
+ checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
320
+ } catch (error) {
321
+ if (isCurrent() && reloadLookupRef.current === lookup) applySnapshot(beforeReload);
322
+ throw error;
323
+ } finally {
324
+ if (reloadLookupRef.current === lookup) reloadLookupRef.current = null;
325
+ }
326
+ if (!isCurrent()) return;
327
+ await sendMessage([], {
328
+ runConfig: config.runConfig,
329
+ ...checkpointId && { checkpointId }
330
+ });
261
331
  });
262
332
  } } : {},
263
333
  onAddToolResult: async ({ toolCallId, toolName, result, isError, artifact }) => {
334
+ const initialLoad = waitForInitialLoad();
335
+ if (initialLoad && !(await initialLoad).active) return;
264
336
  await handleSendMessage([{
265
337
  id: generateId(),
266
338
  type: "tool",
@@ -272,19 +344,25 @@ const useAdkRuntimeImpl = (options) => {
272
344
  }], {});
273
345
  },
274
346
  onRespondToToolApproval: async (options) => {
347
+ const initialLoad = waitForInitialLoad();
348
+ if (initialLoad && !(await initialLoad).active) return;
275
349
  await handleSendMessage([toAdkToolConfirmationReply(options, projectAdkToolApprovals(adkMessagesRef.current).approvals)], {});
276
350
  },
277
351
  onCancel: unstable_allowCancellation ? async () => {
278
- cancel();
352
+ const lookup = reloadLookupRef.current;
353
+ const beforeReload = lookup?.lease.isCurrent() ? lookup.beforeReload : void 0;
354
+ stopRun();
355
+ if (beforeReload) applySnapshot(beforeReload);
279
356
  } : void 0,
280
357
  ...load !== void 0 && { onRefetchThread: () => runLoad("reload") }
281
358
  });
282
359
  };
283
- const useAdkRuntime = ({ cloud, sessionAdapter, create, delete: deleteFn, onThreadIdChange, ...options }) => {
360
+ const useAdkRuntime = ({ cloud, scopeId, sessionAdapter, create, delete: deleteFn, onThreadIdChange, ...options }) => {
284
361
  const aui = useAui();
285
362
  const cloudAdapter = useCloudThreadListAdapter({
286
363
  sdk: ADK_SDK,
287
364
  cloud,
365
+ scopeId,
288
366
  create: createCloudThreadListAdapterCreateFallback(create, aui.threadListItem),
289
367
  delete: deleteFn
290
368
  });
@@ -1 +1 @@
1
- {"version":3,"file":"useAdkRuntime.js","names":[],"sources":["../src/useAdkRuntime.ts"],"sourcesContent":["import {\n useCallback,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n pickExternalStoreSharedOptions,\n type AttachmentAdapter,\n type DictationAdapter,\n type ExternalStoreSharedOptions,\n type FeedbackAdapter,\n type RealtimeVoiceAdapter,\n type SpeechSynthesisAdapter,\n type AppendMessage,\n type ToolCallMessagePart,\n type ToolExecutionStatus,\n generateId,\n} from \"@assistant-ui/core\";\nimport {\n createAbortableThreadLoad,\n createCloudThreadListAdapterCreateFallback,\n isRecord,\n} from \"@assistant-ui/core/internal\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"@assistant-ui/core\";\nimport type {\n AdkMessage,\n AdkThreadSnapshot,\n AdkSendMessageConfig,\n AdkStreamCallback,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\nimport { useAdkMessagesInternal } from \"./useAdkMessages\";\nimport {\n convertAdkMessage,\n createAdkMessageConverter,\n} from \"./convertAdkMessages\";\nimport {\n getMessageContent,\n getPendingCancellations,\n toAdkUserMessage,\n truncateAdkMessages,\n} from \"./convertToAdkMessages\";\nimport {\n projectAdkToolApprovals,\n toAdkToolConfirmationReply,\n} from \"./adkToolApproval\";\nimport { adkExtras } from \"./adkExtras\";\nimport { ADK_SDK } from \"./sdkIdentity\";\n\nexport type UseAdkRuntimeOptions = ExternalStoreSharedOptions & {\n stream: AdkStreamCallback;\n /**\n * Called whenever the active thread's canonical (remote) ID changes, so the\n * value can be treated as a managed/controlled variable (e.g. synced to a URL\n * query param). Only the settled remote ID is emitted: while a freshly created\n * thread is still optimistic the value is `undefined`, and the real ID is\n * emitted once the thread is initialized; the transient local ID is never\n * surfaced.\n */\n onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;\n autoCancelPendingToolCalls?: boolean | undefined;\n unstable_allowCancellation?: boolean | undefined;\n getCheckpointId?: (\n threadId: string,\n parentMessages: AdkMessage[],\n ) => Promise<string | null>;\n /**\n * Loads a thread's stored state. Called when the thread opens, and again for\n * `threads.reloadMainThread()`, which refetches in place rather than\n * remounting the runtime; the signal aborts a load the runtime no longer\n * needs.\n */\n load?: (\n threadId: string,\n options?: { signal?: AbortSignal | undefined },\n ) => Promise<AdkThreadSnapshot>;\n create?: () => Promise<{ externalId: string }>;\n delete?: (threadId: string) => Promise<void>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n dictation?: DictationAdapter;\n voice?: RealtimeVoiceAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n eventHandlers?:\n | {\n onError?: OnAdkErrorCallback;\n onCustomEvent?: OnAdkCustomEventCallback;\n onAgentTransfer?: OnAdkAgentTransferCallback;\n }\n | undefined;\n cloud?: AssistantCloud | undefined;\n /**\n * A `RemoteThreadListAdapter` to use instead of the cloud adapter.\n * Use with `createAdkSessionAdapter` for ADK session-backed persistence.\n */\n sessionAdapter?: RemoteThreadListAdapter | undefined;\n};\n\nconst useAdkRuntimeImpl = (options: UseAdkRuntimeOptions) => {\n const {\n autoCancelPendingToolCalls,\n adapters: { attachments, dictation, feedback, speech, voice } = {},\n unstable_allowCancellation,\n stream,\n load,\n getCheckpointId,\n eventHandlers,\n } = options;\n const aui = useAui();\n const runConfigByToolCallIdRef = useRef(new Map<string, unknown>());\n\n const rememberMessageOwnership = useCallback(\n (newMessages: AdkMessage[], runConfig: unknown) => {\n const toolOwnership = runConfigByToolCallIdRef.current;\n for (const message of newMessages) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n if (!toolOwnership.has(toolCall.id)) {\n toolOwnership.set(toolCall.id, runConfig);\n }\n }\n }\n },\n [],\n );\n\n const seedMessageOwnership = useCallback((history: AdkMessage[]) => {\n const currentOwnership = runConfigByToolCallIdRef.current;\n const nextOwnership = new Map<string, unknown>();\n for (const message of history) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n // Loaded ids must remain present even without a local owner because\n // streamed event windows use has() to avoid attributing them later.\n nextOwnership.set(\n toolCall.id,\n currentOwnership.has(toolCall.id)\n ? currentOwnership.get(toolCall.id)\n : undefined,\n );\n }\n }\n runConfigByToolCallIdRef.current = nextOwnership;\n }, []);\n\n const pruneMessageOwnership = useCallback((history: AdkMessage[]) => {\n const toolCallIds = new Set<string>();\n for (const message of history) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n toolCallIds.add(toolCall.id);\n }\n }\n for (const id of runConfigByToolCallIdRef.current.keys()) {\n if (!toolCallIds.has(id)) runConfigByToolCallIdRef.current.delete(id);\n }\n }, []);\n\n const getToolRunConfig = useCallback((toolCallId: string) => {\n return runConfigByToolCallIdRef.current.get(toolCallId);\n }, []);\n\n const {\n messages,\n stateDelta,\n agentInfo,\n longRunningToolIds,\n artifactDelta,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n sendMessage,\n cancel,\n setMessages,\n replaceMessages: replaceAdkMessages,\n applySnapshot: applyAdkSnapshot,\n } = useAdkMessagesInternal({\n stream,\n ...(eventHandlers && { eventHandlers }),\n onMessages: rememberMessageOwnership,\n });\n\n const loadRef = useRef(load);\n useInsertionEffect(() => {\n loadRef.current = load;\n }, [load]);\n const [loadController] = useState(createAbortableThreadLoad);\n const messagesRef = useRef(messages);\n useInsertionEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n const applySnapshot = useCallback(\n (snapshot: AdkThreadSnapshot) => {\n seedMessageOwnership(snapshot.messages);\n applyAdkSnapshot(snapshot);\n },\n [applyAdkSnapshot, seedMessageOwnership],\n );\n const replaceMessages = useCallback(\n (nextMessages: AdkMessage[]) => {\n pruneMessageOwnership(nextMessages);\n replaceAdkMessages(nextMessages);\n },\n [pruneMessageOwnership, replaceAdkMessages],\n );\n const [isLoadingThread, setIsLoadingThread] = useState(\n () =>\n load !== undefined && aui.threadListItem.getState().externalId != null,\n );\n\n const [isRunning, setIsRunning] = useState(false);\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const effectiveIsRunning = isRunning || hasExecutingTools;\n const isRunningRef = useRef(effectiveIsRunning);\n useInsertionEffect(() => {\n isRunningRef.current = effectiveIsRunning;\n }, [effectiveIsRunning]);\n const runGenerationRef = useRef(0);\n\n const handleSendMessage = async (\n msgs: AdkMessage[],\n config: AdkSendMessageConfig,\n ) => {\n const isToolContinuation =\n msgs.length > 0 && msgs.every((msg) => msg.type === \"tool\");\n const continuationConfig =\n isToolContinuation && config.runConfig === undefined\n ? {\n ...config,\n runConfig: getToolRunConfig(msgs[0]!.tool_call_id),\n }\n : config;\n\n const generation = ++runGenerationRef.current;\n try {\n setIsRunning(true);\n await sendMessage(msgs, continuationConfig);\n } finally {\n if (runGenerationRef.current === generation) setIsRunning(false);\n }\n };\n\n const { approvals: toolApprovals, key: toolApprovalsKey } =\n projectAdkToolApprovals(messages);\n // The messageConverter memo below reads this during render, where the ref\n // must carry the same render's approvals; a commit-scoped write would feed\n // the memo the previous commit's approvals whenever the key changes. No\n // callback reads it — approval replies project from the committed messages.\n const toolApprovalsRef = useRef(toolApprovals);\n toolApprovalsRef.current = toolApprovals;\n\n const longRunningToolIdsRef = useRef(longRunningToolIds);\n useInsertionEffect(() => {\n longRunningToolIdsRef.current = longRunningToolIds;\n }, [longRunningToolIds]);\n // ADK resolves every call it did not mark long-running itself, and yields\n // that call to the client one or more events before its own response, so\n // only a long-running call is the client's to execute.\n const isClientToolCall = useCallback(\n (toolCall: ToolCallMessagePart) =>\n longRunningToolIdsRef.current.includes(toolCall.toolCallId),\n [],\n );\n\n const messageConverter = useMemo(\n () =>\n toolApprovalsKey === \"\"\n ? convertAdkMessage\n : createAdkMessageConverter(toolApprovalsRef.current),\n [toolApprovalsKey],\n );\n\n const threadMessages = useExternalMessageConverter({\n callback: messageConverter,\n messages,\n isRunning: effectiveIsRunning,\n });\n\n const threadMessagesRef = useRef(threadMessages);\n useInsertionEffect(() => {\n threadMessagesRef.current = threadMessages;\n }, [threadMessages]);\n\n // Staging assigns adkMessagesRef.current directly, so the effect must key on\n // the committed messages alone; a dep-less publication would clobber the\n // optimistic value on any unrelated commit.\n const adkMessagesRef = useRef(messages);\n useInsertionEffect(() => {\n adkMessagesRef.current = messages;\n }, [messages]);\n\n const stagedMessagesRef = useRef(\n new Map<\n string,\n {\n message: AdkMessage & { id: string };\n runConfig: AppendMessage[\"runConfig\"];\n }\n >(),\n );\n const [stagedMessageCount, setStagedMessageCount] = useState(0);\n const hasStagedMessages = stagedMessageCount > 0;\n\n const getStagedRun = (parentId: string | null) => {\n if (!parentId || !stagedMessagesRef.current.has(parentId)) return null;\n\n const staged: AdkMessage[] = [];\n for (const message of adkMessagesRef.current) {\n if (message.id && stagedMessagesRef.current.has(message.id)) {\n staged.push(stagedMessagesRef.current.get(message.id)!.message);\n }\n if (message.id === parentId) break;\n }\n\n return {\n messages: staged,\n runConfig: stagedMessagesRef.current.get(parentId)!.runConfig,\n };\n };\n\n const stageUserMessage = (msg: AppendMessage) => {\n const stagedMessage = toAdkUserMessage(msg);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: msg.runConfig,\n });\n setStagedMessageCount(stagedMessagesRef.current.size);\n const nextMessages = [...adkMessagesRef.current, stagedMessage];\n adkMessagesRef.current = nextMessages;\n setMessages(nextMessages);\n };\n\n // The scoped client, not `aui` itself: useAui returns a render-bound\n // instance, so depending on it would re-run the load on every render.\n const threadListItem =\n aui.threadListItem.source !== null ? aui.threadListItem : undefined;\n\n const runLoad = useCallback(\n (purpose: \"initial\" | \"reload\" = \"initial\") => {\n const loadFn = loadRef.current;\n if (!loadFn || !threadListItem) return Promise.resolve();\n\n const externalId = threadListItem.getState().externalId;\n if (externalId == null) return Promise.resolve();\n\n // The initial load is already fetching what a refetch would ask for, and\n // taking it over strands the thread's history if the refetch then fails.\n // Aborting a load the runtime no longer needs is not a failure.\n // A refetch reports the failure to whoever awaited it; the initial load\n // has no caller to tell.\n return loadController.run({\n purpose,\n load: async (signal) => {\n const messagesAtLoadStart = messagesRef.current;\n if (purpose === \"initial\") setIsLoadingThread(true);\n\n const snapshot = await loadFn(externalId, { signal });\n if (signal.aborted) return;\n // A snapshot the session assembled before a run cannot speak for what\n // that run has since produced, and an ADK id cannot correlate a\n // message sent optimistically with the one the session stored for it,\n // so there is nothing here that could merge the two. A refetch that\n // raced a run therefore defers to the run, whether the run started\n // during the load or was already streaming when it began.\n if (\n purpose === \"reload\" &&\n (isRunningRef.current ||\n messagesRef.current !== messagesAtLoadStart)\n )\n return;\n applySnapshot(snapshot);\n },\n onSettled: () => {\n setIsLoadingThread(false);\n },\n onInitialError: (error) => {\n console.warn(\"Failed to load ADK session:\", error);\n },\n });\n },\n [threadListItem, loadController, applySnapshot],\n );\n\n useReplaySafeEffect(() => {\n runLoad();\n return () => {\n // Whatever is current, not this effect's own controller: a refetch swaps\n // the ref, and one in flight at unmount must be aborted too.\n loadController.abort();\n setIsLoadingThread(false);\n };\n }, [threadListItem]);\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning,\n isLoading: isLoadingThread,\n messages: threadMessages,\n unstable_enableToolInvocations: true,\n unstable_isClientToolCall: isClientToolCall,\n setToolStatuses,\n adapters: { attachments, dictation, feedback, speech, voice },\n extras: adkExtras.provide({\n agentInfo,\n stateDelta,\n artifactDelta,\n longRunningToolIds,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n send: handleSendMessage,\n }),\n onNew: async (msg) => {\n if (!(msg.startRun ?? msg.role === \"user\")) {\n stageUserMessage(msg);\n return;\n }\n\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingCancellations(messages, longRunningToolIds)\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n id: generateId(),\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n { runConfig: msg.runConfig },\n );\n },\n onEdit: getCheckpointId\n ? async (msg) => {\n const truncated = truncateAdkMessages(\n threadMessagesRef.current,\n msg.parentId,\n );\n replaceMessages(truncated);\n if (!(msg.startRun ?? msg.role === \"user\")) {\n const stagedMessage = toAdkUserMessage(msg);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: msg.runConfig,\n });\n setStagedMessageCount(stagedMessagesRef.current.size);\n const nextMessages = [...truncated, stagedMessage];\n adkMessagesRef.current = nextMessages;\n setMessages(nextMessages);\n return;\n }\n const externalId = aui.threadListItem.getState().externalId;\n const checkpointId = externalId\n ? await getCheckpointId(externalId, truncated)\n : null;\n return handleSendMessage(\n [\n {\n id: generateId(),\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n {\n runConfig: msg.runConfig,\n ...(checkpointId && { checkpointId }),\n },\n );\n }\n : undefined,\n ...(getCheckpointId || hasStagedMessages\n ? {\n onReload: async (parentId, config) => {\n const stagedRun = getStagedRun(parentId);\n if (stagedRun) {\n for (const message of stagedRun.messages) {\n stagedMessagesRef.current.delete(message.id);\n }\n setStagedMessageCount(stagedMessagesRef.current.size);\n return handleSendMessage(stagedRun.messages, {\n runConfig: config.runConfig ?? stagedRun.runConfig,\n });\n }\n\n if (!getCheckpointId)\n throw new Error(\"Runtime does not support reloading messages.\");\n\n const truncated = truncateAdkMessages(\n threadMessagesRef.current,\n parentId,\n );\n replaceMessages(truncated);\n const externalId = aui.threadListItem.getState().externalId;\n const checkpointId = externalId\n ? await getCheckpointId(externalId, truncated)\n : null;\n return handleSendMessage([], {\n runConfig: config.runConfig,\n ...(checkpointId && { checkpointId }),\n });\n },\n }\n : {}),\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n await handleSendMessage(\n [\n {\n id: generateId(),\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n {},\n );\n },\n onRespondToToolApproval: async (options) => {\n await handleSendMessage(\n [\n toAdkToolConfirmationReply(\n options,\n projectAdkToolApprovals(adkMessagesRef.current).approvals,\n ),\n ],\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n ...(load !== undefined && {\n onRefetchThread: () => runLoad(\"reload\"),\n }),\n });\n\n return runtime;\n};\n\nexport const useAdkRuntime = ({\n cloud,\n sessionAdapter,\n create,\n delete: deleteFn,\n onThreadIdChange,\n ...options\n}: UseAdkRuntimeOptions) => {\n const aui = useAui();\n const cloudAdapter = useCloudThreadListAdapter({\n sdk: ADK_SDK,\n cloud,\n create: createCloudThreadListAdapterCreateFallback(\n create,\n aui.threadListItem,\n ),\n delete: deleteFn,\n });\n\n const adapter = sessionAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useAdkRuntimeImpl(options);\n },\n adapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useAdkRuntime.js","names":[],"sources":["../src/useAdkRuntime.ts"],"sourcesContent":["import {\n useCallback,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport {\n pickExternalStoreSharedOptions,\n type AttachmentAdapter,\n type DictationAdapter,\n type ExternalStoreSharedOptions,\n type FeedbackAdapter,\n type RealtimeVoiceAdapter,\n type SpeechSynthesisAdapter,\n type AppendMessage,\n type ToolCallMessagePart,\n type ToolExecutionStatus,\n generateId,\n} from \"@assistant-ui/core\";\nimport {\n createAbortableThreadLoad,\n createCloudThreadListAdapterCreateFallback,\n isRecord,\n RunLeases,\n type RunLease,\n} from \"@assistant-ui/core/internal\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"@assistant-ui/core\";\nimport type {\n AdkMessage,\n AdkThreadSnapshot,\n AdkSendMessageConfig,\n AdkStreamCallback,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\nimport { useAdkMessagesInternal } from \"./useAdkMessages\";\nimport {\n convertAdkMessage,\n createAdkMessageConverter,\n} from \"./convertAdkMessages\";\nimport {\n getMessageContent,\n getPendingCancellations,\n toAdkUserMessage,\n truncateAdkMessages,\n} from \"./convertToAdkMessages\";\nimport {\n projectAdkToolApprovals,\n toAdkToolConfirmationReply,\n} from \"./adkToolApproval\";\nimport { adkExtras } from \"./adkExtras\";\nimport { ADK_SDK } from \"./sdkIdentity\";\n\nexport type UseAdkRuntimeOptions = ExternalStoreSharedOptions & {\n stream: AdkStreamCallback;\n /**\n * Called whenever the active thread's canonical (remote) ID changes, so the\n * value can be treated as a managed/controlled variable (e.g. synced to a URL\n * query param). Only the settled remote ID is emitted: while a freshly created\n * thread is still optimistic the value is `undefined`, and the real ID is\n * emitted once the thread is initialized; the transient local ID is never\n * surfaced.\n */\n onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;\n autoCancelPendingToolCalls?: boolean | undefined;\n /** @deprecated Experimental since 2025-01-03. Not scheduled for removal; the API may change in any release. */\n unstable_allowCancellation?: boolean | undefined;\n getCheckpointId?: (\n threadId: string,\n parentMessages: AdkMessage[],\n ) => Promise<string | null>;\n /**\n * Loads a thread's stored state. Called when the thread opens, and again for\n * `threads.reloadMainThread()`, which refetches in place rather than\n * remounting the runtime; the signal aborts a load the runtime no longer\n * needs.\n */\n load?: (\n threadId: string,\n options?: { signal?: AbortSignal | undefined },\n ) => Promise<AdkThreadSnapshot>;\n create?: () => Promise<{ externalId: string }>;\n delete?: (threadId: string) => Promise<void>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n dictation?: DictationAdapter;\n voice?: RealtimeVoiceAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n eventHandlers?:\n | {\n onError?: OnAdkErrorCallback;\n onCustomEvent?: OnAdkCustomEventCallback;\n onAgentTransfer?: OnAdkAgentTransferCallback;\n }\n | undefined;\n cloud?: AssistantCloud | undefined;\n /**\n * Stable identity for the account or workspace owning Cloud runtime state.\n * Provide it from the first render and change it when that scope changes.\n */\n scopeId?: string | undefined;\n /**\n * A `RemoteThreadListAdapter` to use instead of the cloud adapter.\n * Use with `createAdkSessionAdapter` for ADK session-backed persistence.\n */\n sessionAdapter?: RemoteThreadListAdapter | undefined;\n};\n\nconst useAdkRuntimeImpl = (options: UseAdkRuntimeOptions) => {\n const {\n autoCancelPendingToolCalls,\n adapters: { attachments, dictation, feedback, speech, voice } = {},\n unstable_allowCancellation,\n stream,\n load,\n getCheckpointId,\n eventHandlers,\n } = options;\n const aui = useAui();\n const runConfigByToolCallIdRef = useRef(new Map<string, unknown>());\n\n const rememberMessageOwnership = useCallback(\n (newMessages: AdkMessage[], runConfig: unknown) => {\n const toolOwnership = runConfigByToolCallIdRef.current;\n for (const message of newMessages) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n if (!toolOwnership.has(toolCall.id)) {\n toolOwnership.set(toolCall.id, runConfig);\n }\n }\n }\n },\n [],\n );\n\n const seedMessageOwnership = useCallback((history: AdkMessage[]) => {\n const currentOwnership = runConfigByToolCallIdRef.current;\n const nextOwnership = new Map<string, unknown>();\n for (const message of history) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n // Loaded ids must remain present even without a local owner because\n // streamed event windows use has() to avoid attributing them later.\n nextOwnership.set(\n toolCall.id,\n currentOwnership.has(toolCall.id)\n ? currentOwnership.get(toolCall.id)\n : undefined,\n );\n }\n }\n runConfigByToolCallIdRef.current = nextOwnership;\n }, []);\n\n const pruneMessageOwnership = useCallback((history: AdkMessage[]) => {\n const toolCallIds = new Set<string>();\n for (const message of history) {\n if (message.type !== \"ai\") continue;\n for (const toolCall of message.tool_calls ?? []) {\n if (!isRecord(toolCall)) continue;\n toolCallIds.add(toolCall.id);\n }\n }\n for (const id of runConfigByToolCallIdRef.current.keys()) {\n if (!toolCallIds.has(id)) runConfigByToolCallIdRef.current.delete(id);\n }\n }, []);\n\n const getToolRunConfig = useCallback((toolCallId: string) => {\n return runConfigByToolCallIdRef.current.get(toolCallId);\n }, []);\n\n const {\n controller,\n messages,\n stateDelta,\n agentInfo,\n longRunningToolIds,\n artifactDelta,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n sendMessage,\n cancel,\n setMessages,\n replaceMessages: replaceAdkMessages,\n applySnapshot: applyAdkSnapshot,\n } = useAdkMessagesInternal({\n stream,\n ...(eventHandlers && { eventHandlers }),\n onMessages: rememberMessageOwnership,\n });\n\n const loadRef = useRef(load);\n useInsertionEffect(() => {\n loadRef.current = load;\n }, [load]);\n const [loadController] = useState(createAbortableThreadLoad);\n const initialLoadRef = useRef<{\n promise: Promise<void>;\n active: boolean;\n snapshot: AdkThreadSnapshot | undefined;\n } | null>(null);\n const waitForInitialLoad = () => {\n const load = initialLoadRef.current;\n if (!load) return undefined;\n return load.promise.then(() => ({\n active:\n load.active &&\n (!threadListItem ||\n aui.threads.getState().mainThreadId === threadListItem.getState().id),\n snapshot: load.snapshot,\n }));\n };\n const messagesRef = useRef(messages);\n useInsertionEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n const applySnapshot = useCallback(\n (snapshot: AdkThreadSnapshot) => {\n seedMessageOwnership(snapshot.messages);\n applyAdkSnapshot(snapshot);\n },\n [applyAdkSnapshot, seedMessageOwnership],\n );\n const replaceMessages = useCallback(\n (nextMessages: AdkMessage[]) => {\n pruneMessageOwnership(nextMessages);\n replaceAdkMessages(nextMessages);\n },\n [pruneMessageOwnership, replaceAdkMessages],\n );\n const [isLoadingThread, setIsLoadingThread] = useState(\n () =>\n load !== undefined && aui.threadListItem.getState().externalId != null,\n );\n\n const [isRunning, setIsRunning] = useState(false);\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const effectiveIsRunning = isRunning || hasExecutingTools;\n const isRunningRef = useRef(effectiveIsRunning);\n useInsertionEffect(() => {\n isRunningRef.current = effectiveIsRunning;\n }, [effectiveIsRunning]);\n const [runLeases] = useState(() => new RunLeases());\n const reloadLookupRef = useRef<{\n lease: RunLease;\n beforeReload: AdkThreadSnapshot;\n } | null>(null);\n\n const runExclusive = async (\n run: (isCurrent: () => boolean) => Promise<void>,\n ) => {\n const lease = runLeases.begin();\n try {\n setIsRunning(true);\n await run(lease.isCurrent);\n } finally {\n if (lease.isCurrent()) setIsRunning(false);\n }\n };\n\n const handleSendMessage = (\n msgs: AdkMessage[],\n config: AdkSendMessageConfig,\n ) => {\n const isToolContinuation =\n msgs.length > 0 && msgs.every((msg) => msg.type === \"tool\");\n const continuationConfig =\n isToolContinuation && config.runConfig === undefined\n ? {\n ...config,\n runConfig: getToolRunConfig(msgs[0]!.tool_call_id),\n }\n : config;\n\n return runExclusive(() => sendMessage(msgs, continuationConfig));\n };\n\n const stopRun = () => {\n runLeases.invalidate();\n setIsRunning(false);\n cancel();\n };\n\n const { approvals: toolApprovals, key: toolApprovalsKey } =\n projectAdkToolApprovals(messages);\n // The messageConverter memo below reads this during render, where the ref\n // must carry the same render's approvals; a commit-scoped write would feed\n // the memo the previous commit's approvals whenever the key changes. No\n // callback reads it — approval replies project from the committed messages.\n const toolApprovalsRef = useRef(toolApprovals);\n toolApprovalsRef.current = toolApprovals;\n\n const longRunningToolIdsRef = useRef(longRunningToolIds);\n useInsertionEffect(() => {\n longRunningToolIdsRef.current = longRunningToolIds;\n }, [longRunningToolIds]);\n // ADK resolves every call it did not mark long-running itself, and yields\n // that call to the client one or more events before its own response, so\n // only a long-running call is the client's to execute.\n const isClientToolCall = useCallback(\n (toolCall: ToolCallMessagePart) =>\n longRunningToolIdsRef.current.includes(toolCall.toolCallId),\n [],\n );\n\n const messageConverter = useMemo(\n () =>\n toolApprovalsKey === \"\"\n ? convertAdkMessage\n : createAdkMessageConverter(toolApprovalsRef.current),\n [toolApprovalsKey],\n );\n\n const threadMessages = useExternalMessageConverter({\n callback: messageConverter,\n messages,\n isRunning: effectiveIsRunning,\n });\n\n const threadMessagesRef = useRef(threadMessages);\n useInsertionEffect(() => {\n threadMessagesRef.current = threadMessages;\n }, [threadMessages]);\n\n // Staging assigns adkMessagesRef.current directly, so the effect must key on\n // the committed messages alone; a dep-less publication would clobber the\n // optimistic value on any unrelated commit.\n const adkMessagesRef = useRef(messages);\n useInsertionEffect(() => {\n adkMessagesRef.current = messages;\n }, [messages]);\n\n const stagedMessageCount = useSyncExternalStore(\n controller.subscribe,\n controller.getStagedMessageCount,\n controller.getStagedMessageCount,\n );\n const hasStagedMessages = stagedMessageCount > 0;\n\n const stageUserMessage = (msg: AppendMessage) => {\n const stagedMessage = toAdkUserMessage(msg);\n controller.dispatch({\n type: \"staged.stage\",\n entry: { message: stagedMessage, runConfig: msg.runConfig },\n });\n const nextMessages = [...controller.getState().messages, stagedMessage];\n adkMessagesRef.current = nextMessages;\n setMessages(nextMessages);\n };\n\n // The scoped client, not `aui` itself: useAui returns a render-bound\n // instance, so depending on it would re-run the load on every render.\n const threadListItem =\n aui.threadListItem.source !== null ? aui.threadListItem : undefined;\n\n const runLoad = useCallback(\n (purpose: \"initial\" | \"reload\" = \"initial\") => {\n const loadFn = loadRef.current;\n if (!loadFn || !threadListItem) return Promise.resolve();\n\n const externalId = threadListItem.getState().externalId;\n if (externalId == null) return Promise.resolve();\n\n // The initial load is already fetching what a refetch would ask for, and\n // taking it over strands the thread's history if the refetch then fails.\n // Aborting a load the runtime no longer needs is not a failure.\n // A refetch reports the failure to whoever awaited it; the initial load\n // has no caller to tell.\n return loadController.run({\n purpose,\n load: async (signal) => {\n const messagesAtLoadStart = messagesRef.current;\n if (purpose === \"initial\") setIsLoadingThread(true);\n\n const snapshot = await loadFn(externalId, { signal });\n if (signal.aborted) return;\n // A snapshot the session assembled before a run cannot speak for what\n // that run has since produced, and an ADK id cannot correlate a\n // message sent optimistically with the one the session stored for it,\n // so there is nothing here that could merge the two. A refetch that\n // raced a run therefore defers to the run, whether the run started\n // during the load or was already streaming when it began.\n if (\n purpose === \"reload\" &&\n (isRunningRef.current ||\n messagesRef.current !== messagesAtLoadStart)\n )\n return;\n reloadLookupRef.current = null;\n applySnapshot(snapshot);\n messagesRef.current = snapshot.messages;\n adkMessagesRef.current = snapshot.messages;\n longRunningToolIdsRef.current = snapshot.longRunningToolIds ?? [];\n if (purpose === \"initial\" && initialLoadRef.current) {\n initialLoadRef.current.snapshot = snapshot;\n }\n },\n onSettled: () => {\n setIsLoadingThread(false);\n },\n onInitialError: (error) => {\n console.warn(\"Failed to load ADK session:\", error);\n },\n });\n },\n [threadListItem, loadController, applySnapshot],\n );\n\n useReplaySafeEffect(() => {\n let release!: () => void;\n const barrier = {\n promise: new Promise<void>((resolve) => {\n release = resolve;\n }),\n active: true,\n snapshot: undefined as AdkThreadSnapshot | undefined,\n };\n initialLoadRef.current = barrier;\n const settle = () => {\n if (initialLoadRef.current === barrier) initialLoadRef.current = null;\n release();\n };\n void runLoad().then(settle, settle);\n return () => {\n barrier.active = false;\n // Whatever is current, not this effect's own controller: a refetch swaps\n // the ref, and one in flight at unmount must be aborted too.\n loadController.abort();\n settle();\n setIsLoadingThread(false);\n };\n }, [threadListItem]);\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning,\n isLoading: isLoadingThread,\n messages: threadMessages,\n unstable_enableToolInvocations: true,\n unstable_isClientToolCall: isClientToolCall,\n setToolStatuses,\n adapters: { attachments, dictation, feedback, speech, voice },\n extras: adkExtras.provide({\n agentInfo,\n stateDelta,\n artifactDelta,\n longRunningToolIds,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n send: (messages, config) => {\n const initialLoad = waitForInitialLoad();\n if (!initialLoad) return handleSendMessage(messages, config);\n return initialLoad.then(({ active }) =>\n active ? handleSendMessage(messages, config) : undefined,\n );\n },\n }),\n onNew: async (msg) => {\n const initialLoad = await waitForInitialLoad();\n if (initialLoad && !initialLoad.active) return;\n if (!(msg.startRun ?? msg.role === \"user\")) {\n stageUserMessage(msg);\n return;\n }\n\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingCancellations(\n initialLoad?.snapshot?.messages ?? messagesRef.current,\n initialLoad?.snapshot?.longRunningToolIds ??\n longRunningToolIdsRef.current,\n )\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n id: generateId(),\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n { runConfig: msg.runConfig },\n );\n },\n onEdit: getCheckpointId\n ? async (msg) => {\n const initialLoad = waitForInitialLoad();\n if (initialLoad && !(await initialLoad).active) return;\n stopRun();\n const truncated = truncateAdkMessages(\n threadMessagesRef.current,\n msg.parentId,\n );\n replaceMessages(truncated);\n if (!(msg.startRun ?? msg.role === \"user\")) {\n const stagedMessage = toAdkUserMessage(msg);\n controller.dispatch({\n type: \"staged.stage\",\n entry: { message: stagedMessage, runConfig: msg.runConfig },\n });\n const nextMessages = [...truncated, stagedMessage];\n adkMessagesRef.current = nextMessages;\n setMessages(nextMessages);\n return;\n }\n const editedMessage = toAdkUserMessage(msg);\n setMessages([...truncated, editedMessage]);\n const externalId = aui.threadListItem.getState().externalId;\n return runExclusive(async (isCurrent) => {\n const checkpointId = externalId\n ? await getCheckpointId(externalId, truncated)\n : null;\n if (!isCurrent()) return;\n await sendMessage([editedMessage], {\n runConfig: msg.runConfig,\n ...(checkpointId && { checkpointId }),\n });\n });\n }\n : undefined,\n ...(getCheckpointId || hasStagedMessages\n ? {\n onReload: async (parentId, config) => {\n const initialLoad = waitForInitialLoad();\n if (initialLoad && !(await initialLoad).active) return;\n const stagedRun = controller.getStagedRun(parentId);\n if (stagedRun) {\n controller.dispatch({\n type: \"staged.unstage\",\n ids: stagedRun.messages.map((message) => message.id!),\n });\n return handleSendMessage(stagedRun.messages, {\n runConfig: config.runConfig ?? stagedRun.runConfig,\n });\n }\n\n if (!getCheckpointId)\n throw new Error(\"Runtime does not support reloading messages.\");\n\n stopRun();\n const beforeReload: AdkThreadSnapshot = {\n messages: adkMessagesRef.current,\n longRunningToolIds,\n toolConfirmations,\n authRequests,\n escalated,\n messageMetadata,\n stateDelta,\n artifactDelta,\n agentInfo,\n };\n const truncated = truncateAdkMessages(\n threadMessagesRef.current,\n parentId,\n );\n replaceMessages(truncated);\n const externalId = aui.threadListItem.getState().externalId;\n return runExclusive(async (isCurrent) => {\n const lookup = {\n lease: runLeases.current(),\n beforeReload,\n };\n reloadLookupRef.current = lookup;\n let checkpointId: string | null;\n try {\n checkpointId = externalId\n ? await getCheckpointId(externalId, truncated)\n : null;\n } catch (error) {\n if (isCurrent() && reloadLookupRef.current === lookup)\n applySnapshot(beforeReload);\n throw error;\n } finally {\n if (reloadLookupRef.current === lookup)\n reloadLookupRef.current = null;\n }\n if (!isCurrent()) return;\n await sendMessage([], {\n runConfig: config.runConfig,\n ...(checkpointId && { checkpointId }),\n });\n });\n },\n }\n : {}),\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n const initialLoad = waitForInitialLoad();\n if (initialLoad && !(await initialLoad).active) return;\n await handleSendMessage(\n [\n {\n id: generateId(),\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n {},\n );\n },\n onRespondToToolApproval: async (options) => {\n const initialLoad = waitForInitialLoad();\n if (initialLoad && !(await initialLoad).active) return;\n await handleSendMessage(\n [\n toAdkToolConfirmationReply(\n options,\n projectAdkToolApprovals(adkMessagesRef.current).approvals,\n ),\n ],\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n const lookup = reloadLookupRef.current;\n const beforeReload = lookup?.lease.isCurrent()\n ? lookup.beforeReload\n : undefined;\n stopRun();\n // A reload stopped before it sent leaves the ADK session holding the\n // turn it removed, so the thread shows that turn again.\n if (beforeReload) applySnapshot(beforeReload);\n }\n : undefined,\n ...(load !== undefined && {\n onRefetchThread: () => runLoad(\"reload\"),\n }),\n });\n\n return runtime;\n};\n\nexport const useAdkRuntime = ({\n cloud,\n scopeId,\n sessionAdapter,\n create,\n delete: deleteFn,\n onThreadIdChange,\n ...options\n}: UseAdkRuntimeOptions) => {\n const aui = useAui();\n const cloudAdapter = useCloudThreadListAdapter({\n sdk: ADK_SDK,\n cloud,\n scopeId,\n create: createCloudThreadListAdapterCreateFallback(\n create,\n aui.threadListItem,\n ),\n delete: deleteFn,\n });\n\n const adapter = sessionAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useAdkRuntimeImpl(options);\n },\n adapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-google-adk",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "description": "Google ADK adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "google-adk",
@@ -34,10 +34,10 @@
34
34
  ],
35
35
  "sideEffects": false,
36
36
  "dependencies": {
37
- "@assistant-ui/core": "^0.3.24",
38
- "@assistant-ui/store": "^0.3.17",
37
+ "@assistant-ui/core": "^0.3.25",
38
+ "@assistant-ui/store": "^0.3.18",
39
39
  "assistant-cloud": "*",
40
- "assistant-stream": "^0.3.48"
40
+ "assistant-stream": "^0.3.49"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@google/adk": ">=0.5.0",
@@ -58,7 +58,7 @@
58
58
  "@testing-library/dom": "^10.4.2",
59
59
  "@testing-library/react": "^16.3.3",
60
60
  "@types/react": "^19.3.0",
61
- "jsdom": "^30.0.1",
61
+ "jsdom": "^30.1.2",
62
62
  "react": "^19.3.0",
63
63
  "vitest": "^5.0.3"
64
64
  },