@assistant-ui/react-google-adk 0.0.18 → 0.0.19

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.
@@ -63,7 +63,7 @@ const useAdkMessages = ({ stream, eventHandlers }) => {
63
63
  ...config,
64
64
  abortSignal: abortController.signal,
65
65
  initialize: async () => {
66
- return await aui.threadListItem().initialize();
66
+ return await aui.threadListItem.initialize();
67
67
  }
68
68
  });
69
69
  for await (const event of response) {
@@ -1 +1 @@
1
- {"version":3,"file":"useAdkMessages.js","names":["uuidv4"],"sources":["../src/useAdkMessages.ts"],"sourcesContent":["import { useState, useCallback, useRef, useMemo } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { contentToParts } from \"./contentToParts\";\nimport type {\n AdkEvent,\n AdkMessage,\n AdkMessageMetadata,\n AdkSendMessageConfig,\n AdkStreamCallback,\n AdkToolConfirmation,\n AdkAuthRequest,\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\nexport const useAdkMessages = ({\n stream,\n eventHandlers,\n}: UseAdkMessagesOptions) => {\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 const lastTransferToAgentRef = useRef<string | undefined>(undefined);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const stateDeltaRef = useRef(stateDelta);\n stateDeltaRef.current = stateDelta;\n const artifactDeltaRef = useRef(artifactDelta);\n artifactDeltaRef.current = artifactDelta;\n const messageMetadataRef = useRef(messageMetadata);\n messageMetadataRef.current = messageMetadata;\n\n const setMessagesImmediate = useCallback((msgs: AdkMessage[]) => {\n messagesRef.current = msgs;\n _setMessages(msgs);\n }, []);\n\n // Replace the message list AND reset derived per-turn HITL state.\n // Used by truncation paths (edit, reload, load) 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 [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: uuidv4() },\n ) as AdkMessage[];\n\n const accumulator = new AdkEventAccumulator(messagesRef.current);\n for (const msg of newMessagesWithId) {\n accumulator.processEvent(messageToEvent(msg));\n }\n setMessagesImmediate(accumulator.getMessages());\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n try {\n const response = await stream(newMessagesWithId, {\n ...config,\n abortSignal: abortController.signal,\n initialize: async () => {\n return await aui.threadListItem().initialize();\n },\n });\n\n for await (const event of response) {\n const updatedMessages = accumulator.processEvent(event);\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 !== lastTransferToAgentRef.current) {\n lastTransferToAgentRef.current = transfer;\n onAgentTransfer?.(transfer);\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 onCustomEvent(key, value);\n }\n }\n\n if (event.errorCode || event.errorMessage) {\n onError?.(event.errorMessage ?? event.errorCode);\n }\n }\n } catch (error) {\n if (\n !abortController.signal.aborted &&\n !(error instanceof Error && error.name === \"AbortError\")\n ) {\n throw error;\n }\n } finally {\n if (abortControllerRef.current === abortController) {\n abortControllerRef.current = null;\n }\n }\n },\n [\n aui,\n setMessagesImmediate,\n stream,\n onError,\n onCustomEvent,\n onAgentTransfer,\n ],\n );\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n }, []);\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 };\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 ?? uuidv4(),\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 ?? uuidv4(),\n content: {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response,\n },\n },\n ],\n },\n };\n }\n\n const result: AdkEvent = { id: msg.id ?? uuidv4() };\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?.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":["uuidv4"],"sources":["../src/useAdkMessages.ts"],"sourcesContent":["import { useState, useCallback, useRef, useMemo } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { contentToParts } from \"./contentToParts\";\nimport type {\n AdkEvent,\n AdkMessage,\n AdkMessageMetadata,\n AdkSendMessageConfig,\n AdkStreamCallback,\n AdkToolConfirmation,\n AdkAuthRequest,\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\nexport const useAdkMessages = ({\n stream,\n eventHandlers,\n}: UseAdkMessagesOptions) => {\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 const lastTransferToAgentRef = useRef<string | undefined>(undefined);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const stateDeltaRef = useRef(stateDelta);\n stateDeltaRef.current = stateDelta;\n const artifactDeltaRef = useRef(artifactDelta);\n artifactDeltaRef.current = artifactDelta;\n const messageMetadataRef = useRef(messageMetadata);\n messageMetadataRef.current = messageMetadata;\n\n const setMessagesImmediate = useCallback((msgs: AdkMessage[]) => {\n messagesRef.current = msgs;\n _setMessages(msgs);\n }, []);\n\n // Replace the message list AND reset derived per-turn HITL state.\n // Used by truncation paths (edit, reload, load) 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 [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: uuidv4() },\n ) as AdkMessage[];\n\n const accumulator = new AdkEventAccumulator(messagesRef.current);\n for (const msg of newMessagesWithId) {\n accumulator.processEvent(messageToEvent(msg));\n }\n setMessagesImmediate(accumulator.getMessages());\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n try {\n const response = await stream(newMessagesWithId, {\n ...config,\n abortSignal: abortController.signal,\n initialize: async () => {\n return await aui.threadListItem.initialize();\n },\n });\n\n for await (const event of response) {\n const updatedMessages = accumulator.processEvent(event);\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 !== lastTransferToAgentRef.current) {\n lastTransferToAgentRef.current = transfer;\n onAgentTransfer?.(transfer);\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 onCustomEvent(key, value);\n }\n }\n\n if (event.errorCode || event.errorMessage) {\n onError?.(event.errorMessage ?? event.errorCode);\n }\n }\n } catch (error) {\n if (\n !abortController.signal.aborted &&\n !(error instanceof Error && error.name === \"AbortError\")\n ) {\n throw error;\n }\n } finally {\n if (abortControllerRef.current === abortController) {\n abortControllerRef.current = null;\n }\n }\n },\n [\n aui,\n setMessagesImmediate,\n stream,\n onError,\n onCustomEvent,\n onAgentTransfer,\n ],\n );\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n }, []);\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 };\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 ?? uuidv4(),\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 ?? uuidv4(),\n content: {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response,\n },\n },\n ],\n },\n };\n }\n\n const result: AdkEvent = { id: msg.id ?? uuidv4() };\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?.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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"}
@@ -180,7 +180,7 @@ const useAdkRuntimeImpl = (options) => {
180
180
  setMessages(nextMessages);
181
181
  return;
182
182
  }
183
- const externalId = aui.threadListItem().getState().externalId;
183
+ const externalId = aui.threadListItem.getState().externalId;
184
184
  const checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
185
185
  return handleSendMessage([{
186
186
  id: v4(),
@@ -201,7 +201,7 @@ const useAdkRuntimeImpl = (options) => {
201
201
  if (!getCheckpointId) throw new Error("Runtime does not support reloading messages.");
202
202
  const truncated = truncateAdkMessages(threadMessagesRef.current, parentId);
203
203
  replaceMessages(truncated);
204
- const externalId = aui.threadListItem().getState().externalId;
204
+ const externalId = aui.threadListItem.getState().externalId;
205
205
  const checkpointId = externalId ? await getCheckpointId(externalId, truncated) : null;
206
206
  return handleSendMessage([], {
207
207
  runConfig: config.runConfig,
@@ -231,7 +231,7 @@ const useAdkRuntimeImpl = (options) => {
231
231
  useEffect(() => {
232
232
  const loadFn = loadRef.current;
233
233
  if (!loadFn) return;
234
- const externalId = aui.threadListItem().getState().externalId;
234
+ const externalId = aui.threadListItem.getState().externalId;
235
235
  if (externalId == null) return;
236
236
  loadFn(externalId).then(({ messages: msgs }) => {
237
237
  replaceMessages(msgs);
@@ -248,7 +248,7 @@ const useAdkRuntime = ({ cloud, sessionAdapter, create, delete: deleteFn, onThre
248
248
  cloud,
249
249
  create: async () => {
250
250
  if (create) return create();
251
- if (aui.threadListItem.source) return aui.threadListItem().initialize();
251
+ if (aui.threadListItem.source) return aui.threadListItem.initialize();
252
252
  return { externalId: void 0 };
253
253
  },
254
254
  delete: deleteFn
@@ -1 +1 @@
1
- {"version":3,"file":"useAdkRuntime.js","names":["_exhaustiveCheck","uuidv4"],"sources":["../src/useAdkRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n getExternalStoreMessages,\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 ThreadMessage,\n type ToolExecutionStatus,\n generateId,\n} from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"@assistant-ui/core\";\nimport type {\n AdkMessage,\n AdkSendMessageConfig,\n AdkStreamCallback,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\nimport { useAdkMessages } from \"./useAdkMessages\";\nimport { convertAdkMessage } from \"./convertAdkMessages\";\nimport { adkExtras } from \"./adkExtras\";\nimport { v4 as uuidv4 } from \"uuid\";\n\n/** @internal — exported for unit tests. */\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, url: part.image };\n case \"file\":\n return {\n type: \"file\" as const,\n mimeType: part.mimeType,\n data: part.data,\n ...(part.filename != null && { filename: part.filename }),\n };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default: {\n const _exhaustiveCheck:\n | \"reasoning\"\n | \"source\"\n | \"audio\"\n | \"data\"\n | \"generative-ui\" = type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\n/** @internal — exported for unit tests. */\nexport const getPendingToolCalls = (messages: AdkMessage[]) => {\n const pending = new Map<string, { id: string; name: string }>();\n for (const msg of messages) {\n if (msg.type === \"ai\" && msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n pending.set(tc.id, tc);\n }\n }\n if (msg.type === \"tool\") {\n pending.delete(msg.tool_call_id);\n }\n }\n return [...pending.values()];\n};\n\n/**\n * @internal — exported for unit tests.\n *\n * Returns `{cancelled: true}` tool responses for pending tool calls when the\n * user sends a new turn, EXCEPT for HITL interrupts marked via\n * `long_running_tool_ids` (`adk_request_input`, `adk_request_confirmation`,\n * `adk_request_credential`). Those must be answered through a dedicated tool\n * UI + submit helper, not auto-cancelled.\n */\nexport const getPendingCancellations = (\n messages: AdkMessage[],\n longRunningToolIds: readonly string[],\n): Array<AdkMessage & { type: \"tool\" }> => {\n const longRunningSet = new Set(longRunningToolIds);\n return getPendingToolCalls(messages)\n .filter((t) => !longRunningSet.has(t.id))\n .map(\n (t) =>\n ({\n id: uuidv4(),\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies AdkMessage & { type: \"tool\" },\n );\n};\n\nconst truncateAdkMessages = (\n threadMessages: readonly ThreadMessage[],\n parentId: string | null,\n): AdkMessage[] => {\n if (parentId === null) return [];\n const parentIndex = threadMessages.findIndex((m) => m.id === parentId);\n if (parentIndex === -1) return [];\n const truncated: AdkMessage[] = [];\n for (let i = 0; i <= parentIndex && i < threadMessages.length; i++) {\n truncated.push(...getExternalStoreMessages<AdkMessage>(threadMessages[i]!));\n }\n return truncated;\n};\n\nconst toAdkUserMessage = (\n msg: AppendMessage,\n id = generateId(),\n): AdkMessage & { type: \"human\"; id: string } => ({\n id,\n type: \"human\",\n content: getMessageContent(msg),\n});\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 load?: (threadId: string) => Promise<{ messages: AdkMessage[] }>;\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 {\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,\n } = useAdkMessages({\n stream,\n ...(eventHandlers && { eventHandlers }),\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\n const handleSendMessage = async (\n msgs: AdkMessage[],\n config: AdkSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(msgs, config);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertAdkMessage,\n messages,\n isRunning: effectiveIsRunning,\n });\n\n const threadMessagesRef = useRef(threadMessages);\n threadMessagesRef.current = threadMessages;\n\n const adkMessagesRef = useRef(messages);\n adkMessagesRef.current = 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 const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: effectiveIsRunning,\n messages: threadMessages,\n unstable_enableToolInvocations: true,\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: uuidv4(),\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: uuidv4(),\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: uuidv4(),\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 onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n\n {\n const loadRef = useRef(load);\n useEffect(() => {\n loadRef.current = load;\n });\n\n useEffect(() => {\n const loadFn = loadRef.current;\n if (!loadFn) return;\n\n const externalId = aui.threadListItem().getState().externalId;\n if (externalId == null) return;\n\n loadFn(externalId).then(\n ({ messages: msgs }) => {\n replaceMessages(msgs);\n },\n (e) => {\n console.warn(\"Failed to load ADK session:\", e);\n },\n );\n }, [aui, replaceMessages]);\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 cloud,\n create: async () => {\n if (create) return create();\n if (aui.threadListItem.source) return aui.threadListItem().initialize();\n return { externalId: undefined };\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":["_exhaustiveCheck","uuidv4"],"sources":["../src/useAdkRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n getExternalStoreMessages,\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 ThreadMessage,\n type ToolExecutionStatus,\n generateId,\n} from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"@assistant-ui/core\";\nimport type {\n AdkMessage,\n AdkSendMessageConfig,\n AdkStreamCallback,\n OnAdkErrorCallback,\n OnAdkCustomEventCallback,\n OnAdkAgentTransferCallback,\n} from \"./types\";\nimport { useAdkMessages } from \"./useAdkMessages\";\nimport { convertAdkMessage } from \"./convertAdkMessages\";\nimport { adkExtras } from \"./adkExtras\";\nimport { v4 as uuidv4 } from \"uuid\";\n\n/** @internal — exported for unit tests. */\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, url: part.image };\n case \"file\":\n return {\n type: \"file\" as const,\n mimeType: part.mimeType,\n data: part.data,\n ...(part.filename != null && { filename: part.filename }),\n };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default: {\n const _exhaustiveCheck:\n | \"reasoning\"\n | \"source\"\n | \"audio\"\n | \"data\"\n | \"generative-ui\" = type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\n/** @internal — exported for unit tests. */\nexport const getPendingToolCalls = (messages: AdkMessage[]) => {\n const pending = new Map<string, { id: string; name: string }>();\n for (const msg of messages) {\n if (msg.type === \"ai\" && msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n pending.set(tc.id, tc);\n }\n }\n if (msg.type === \"tool\") {\n pending.delete(msg.tool_call_id);\n }\n }\n return [...pending.values()];\n};\n\n/**\n * @internal — exported for unit tests.\n *\n * Returns `{cancelled: true}` tool responses for pending tool calls when the\n * user sends a new turn, EXCEPT for HITL interrupts marked via\n * `long_running_tool_ids` (`adk_request_input`, `adk_request_confirmation`,\n * `adk_request_credential`). Those must be answered through a dedicated tool\n * UI + submit helper, not auto-cancelled.\n */\nexport const getPendingCancellations = (\n messages: AdkMessage[],\n longRunningToolIds: readonly string[],\n): Array<AdkMessage & { type: \"tool\" }> => {\n const longRunningSet = new Set(longRunningToolIds);\n return getPendingToolCalls(messages)\n .filter((t) => !longRunningSet.has(t.id))\n .map(\n (t) =>\n ({\n id: uuidv4(),\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies AdkMessage & { type: \"tool\" },\n );\n};\n\nconst truncateAdkMessages = (\n threadMessages: readonly ThreadMessage[],\n parentId: string | null,\n): AdkMessage[] => {\n if (parentId === null) return [];\n const parentIndex = threadMessages.findIndex((m) => m.id === parentId);\n if (parentIndex === -1) return [];\n const truncated: AdkMessage[] = [];\n for (let i = 0; i <= parentIndex && i < threadMessages.length; i++) {\n truncated.push(...getExternalStoreMessages<AdkMessage>(threadMessages[i]!));\n }\n return truncated;\n};\n\nconst toAdkUserMessage = (\n msg: AppendMessage,\n id = generateId(),\n): AdkMessage & { type: \"human\"; id: string } => ({\n id,\n type: \"human\",\n content: getMessageContent(msg),\n});\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 load?: (threadId: string) => Promise<{ messages: AdkMessage[] }>;\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 {\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,\n } = useAdkMessages({\n stream,\n ...(eventHandlers && { eventHandlers }),\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\n const handleSendMessage = async (\n msgs: AdkMessage[],\n config: AdkSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(msgs, config);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertAdkMessage,\n messages,\n isRunning: effectiveIsRunning,\n });\n\n const threadMessagesRef = useRef(threadMessages);\n threadMessagesRef.current = threadMessages;\n\n const adkMessagesRef = useRef(messages);\n adkMessagesRef.current = 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 const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: effectiveIsRunning,\n messages: threadMessages,\n unstable_enableToolInvocations: true,\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: uuidv4(),\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: uuidv4(),\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: uuidv4(),\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 onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n\n {\n const loadRef = useRef(load);\n useEffect(() => {\n loadRef.current = load;\n });\n\n useEffect(() => {\n const loadFn = loadRef.current;\n if (!loadFn) return;\n\n const externalId = aui.threadListItem.getState().externalId;\n if (externalId == null) return;\n\n loadFn(externalId).then(\n ({ messages: msgs }) => {\n replaceMessages(msgs);\n },\n (e) => {\n console.warn(\"Failed to load ADK session:\", e);\n },\n );\n }, [aui, replaceMessages]);\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 cloud,\n create: async () => {\n if (create) return create();\n if (aui.threadListItem.source) return aui.threadListItem.initialize();\n return { externalId: undefined };\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.18",
3
+ "version": "0.0.19",
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.2.22",
38
- "@assistant-ui/store": "^0.2.21",
37
+ "@assistant-ui/core": "^0.3.0",
38
+ "@assistant-ui/store": "^0.3.0",
39
39
  "assistant-cloud": "*",
40
- "assistant-stream": "^0.3.27",
40
+ "assistant-stream": "^0.3.29",
41
41
  "uuid": "^14.0.1"
42
42
  },
43
43
  "peerDependencies": {
@@ -58,7 +58,7 @@
58
58
  "@types/uuid": "^11.0.0",
59
59
  "react": "^19.2.8",
60
60
  "vitest": "^4.1.10",
61
- "@assistant-ui/x-buildutils": "0.0.19"
61
+ "@assistant-ui/x-buildutils": "0.0.20"
62
62
  },
63
63
  "publishConfig": {
64
64
  "access": "public",
@@ -723,28 +723,6 @@ describe("createAdkStream - headers", () => {
723
723
  expect(headers["Content-Type"]).toBe("application/json");
724
724
  });
725
725
 
726
- it("resolves dynamic headers from a function", async () => {
727
- mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
728
-
729
- const stream = createAdkStream({
730
- api: "/api/adk",
731
- headers: () => ({ "X-Custom": "dynamic" }),
732
- });
733
- const gen = await stream(
734
- [{ id: "m1", type: "human", content: "Hi" }],
735
- makeConfig(),
736
- );
737
- for await (const _ of gen) {
738
- /* noop */
739
- }
740
-
741
- const headers = mockFetch.mock.calls[0]![1]?.headers as Record<
742
- string,
743
- string
744
- >;
745
- expect(headers["X-Custom"]).toBe("dynamic");
746
- });
747
-
748
726
  it("resolves async dynamic headers", async () => {
749
727
  mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
750
728
 
@@ -452,13 +452,6 @@ describe("AdkEventAccumulator - HITL requires-action", () => {
452
452
  expect(aiMsg.status).toBeUndefined();
453
453
  });
454
454
 
455
- it("matches tool call id to the longRunningToolIds entry", () => {
456
- const acc = new AdkEventAccumulator();
457
- const msgs = acc.processEvent(makeHitlEvent("tc-1"));
458
- const aiMsg = msgs[0] as AdkMessage & { type: "ai" };
459
- expect(aiMsg.tool_calls![0]!.id).toBe("tc-1");
460
- });
461
-
462
455
  it("stays pending across a subsequent bookkeeping event", () => {
463
456
  const acc = new AdkEventAccumulator();
464
457
  acc.processEvent(makeHitlEvent("tc-1", { author: "WorkflowA" }));
@@ -480,35 +473,6 @@ describe("AdkEventAccumulator - HITL requires-action", () => {
480
473
  expect(aiMsg!.status).toBeUndefined();
481
474
  });
482
475
 
483
- it("assigns manual complete status on non-HITL final event", () => {
484
- const acc = new AdkEventAccumulator();
485
- const msgs = acc.processEvent(
486
- makeEvent({
487
- author: "agent",
488
- content: { role: "model", parts: [{ text: "Done." }] },
489
- }),
490
- );
491
-
492
- expect(msgs[0]).toMatchObject({
493
- status: { type: "complete", reason: "stop" },
494
- });
495
- });
496
-
497
- it("assigns manual complete status on skipSummarization final event", () => {
498
- const acc = new AdkEventAccumulator();
499
- const msgs = acc.processEvent(
500
- makeEvent({
501
- author: "agent",
502
- actions: { skipSummarization: true },
503
- content: { role: "model", parts: [{ text: "skipped" }] },
504
- }),
505
- );
506
-
507
- expect(msgs[0]).toMatchObject({
508
- status: { type: "complete", reason: "stop" },
509
- });
510
- });
511
-
512
476
  it("prioritizes skipSummarization over longRunningToolIds", () => {
513
477
  const acc = new AdkEventAccumulator();
514
478
  const msgs = acc.processEvent(
@@ -224,20 +224,10 @@ describe("createAdkSessionAdapter - delete", () => {
224
224
  // ── adapter.rename / archive / unarchive ──
225
225
 
226
226
  describe("createAdkSessionAdapter - no-op methods", () => {
227
- it("rename resolves without error", async () => {
227
+ it("rename/archive/unarchive resolve without hitting the network", async () => {
228
228
  const { adapter } = createAdkSessionAdapter(baseOptions);
229
229
  await expect(adapter.rename("s1", "New Title")).resolves.toBeUndefined();
230
- expect(mockFetch).not.toHaveBeenCalled();
231
- });
232
-
233
- it("archive resolves without error", async () => {
234
- const { adapter } = createAdkSessionAdapter(baseOptions);
235
230
  await expect(adapter.archive("s1")).resolves.toBeUndefined();
236
- expect(mockFetch).not.toHaveBeenCalled();
237
- });
238
-
239
- it("unarchive resolves without error", async () => {
240
- const { adapter } = createAdkSessionAdapter(baseOptions);
241
231
  await expect(adapter.unarchive("s1")).resolves.toBeUndefined();
242
232
  expect(mockFetch).not.toHaveBeenCalled();
243
233
  });
@@ -106,7 +106,7 @@ export const useAdkMessages = ({
106
106
  ...config,
107
107
  abortSignal: abortController.signal,
108
108
  initialize: async () => {
109
- return await aui.threadListItem().initialize();
109
+ return await aui.threadListItem.initialize();
110
110
  },
111
111
  });
112
112
 
@@ -356,7 +356,7 @@ const useAdkRuntimeImpl = (options: UseAdkRuntimeOptions) => {
356
356
  setMessages(nextMessages);
357
357
  return;
358
358
  }
359
- const externalId = aui.threadListItem().getState().externalId;
359
+ const externalId = aui.threadListItem.getState().externalId;
360
360
  const checkpointId = externalId
361
361
  ? await getCheckpointId(externalId, truncated)
362
362
  : null;
@@ -397,7 +397,7 @@ const useAdkRuntimeImpl = (options: UseAdkRuntimeOptions) => {
397
397
  parentId,
398
398
  );
399
399
  replaceMessages(truncated);
400
- const externalId = aui.threadListItem().getState().externalId;
400
+ const externalId = aui.threadListItem.getState().externalId;
401
401
  const checkpointId = externalId
402
402
  ? await getCheckpointId(externalId, truncated)
403
403
  : null;
@@ -447,7 +447,7 @@ const useAdkRuntimeImpl = (options: UseAdkRuntimeOptions) => {
447
447
  const loadFn = loadRef.current;
448
448
  if (!loadFn) return;
449
449
 
450
- const externalId = aui.threadListItem().getState().externalId;
450
+ const externalId = aui.threadListItem.getState().externalId;
451
451
  if (externalId == null) return;
452
452
 
453
453
  loadFn(externalId).then(
@@ -477,7 +477,7 @@ export const useAdkRuntime = ({
477
477
  cloud,
478
478
  create: async () => {
479
479
  if (create) return create();
480
- if (aui.threadListItem.source) return aui.threadListItem().initialize();
480
+ if (aui.threadListItem.source) return aui.threadListItem.initialize();
481
481
  return { externalId: undefined };
482
482
  },
483
483
  delete: deleteFn,
@@ -1,370 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- // ── Module mocks ──
4
-
5
- vi.mock("./parseAdkRequest", () => ({
6
- parseAdkRequest: vi.fn(),
7
- toAdkContent: vi.fn(),
8
- }));
9
-
10
- vi.mock("./adkEventStream", () => ({
11
- adkEventStream: vi.fn(),
12
- }));
13
-
14
- import { createAdkApiRoute } from "./createAdkApiRoute";
15
- import { parseAdkRequest, toAdkContent } from "./parseAdkRequest";
16
- import { adkEventStream } from "./adkEventStream";
17
-
18
- const mockParseAdkRequest = vi.mocked(parseAdkRequest);
19
- const mockToAdkContent = vi.mocked(toAdkContent);
20
- const mockAdkEventStream = vi.mocked(adkEventStream);
21
-
22
- const makeRequest = (body: unknown = { message: "Hello" }) =>
23
- new Request("http://localhost/api/adk", {
24
- method: "POST",
25
- headers: { "Content-Type": "application/json" },
26
- body: JSON.stringify(body),
27
- });
28
-
29
- const makeRunner = () => ({
30
- runAsync: vi.fn().mockReturnValue(
31
- (async function* () {
32
- yield { id: "e1" };
33
- })(),
34
- ),
35
- });
36
-
37
- beforeEach(() => {
38
- vi.clearAllMocks();
39
- mockParseAdkRequest.mockResolvedValue({
40
- type: "message",
41
- text: "Hello",
42
- config: {},
43
- });
44
- mockToAdkContent.mockReturnValue({
45
- role: "user",
46
- parts: [{ text: "Hello" }],
47
- });
48
- mockAdkEventStream.mockReturnValue(new Response("stream", { status: 200 }));
49
- });
50
-
51
- // ── Basic flow ──
52
-
53
- describe("createAdkApiRoute - basic flow", () => {
54
- it("calls parseAdkRequest with the request", async () => {
55
- const runner = makeRunner();
56
- const handler = createAdkApiRoute({
57
- runner,
58
- userId: "user-1",
59
- sessionId: "session-1",
60
- });
61
-
62
- const req = makeRequest();
63
- await handler(req);
64
-
65
- expect(mockParseAdkRequest).toHaveBeenCalledOnce();
66
- expect(mockParseAdkRequest).toHaveBeenCalledWith(req);
67
- });
68
-
69
- it("calls toAdkContent with the parsed request", async () => {
70
- const parsed = { type: "message" as const, text: "Hi", config: {} };
71
- mockParseAdkRequest.mockResolvedValue(parsed);
72
-
73
- const runner = makeRunner();
74
- const handler = createAdkApiRoute({
75
- runner,
76
- userId: "user-1",
77
- sessionId: "session-1",
78
- });
79
-
80
- await handler(makeRequest());
81
-
82
- expect(mockToAdkContent).toHaveBeenCalledOnce();
83
- expect(mockToAdkContent).toHaveBeenCalledWith(parsed);
84
- });
85
-
86
- it("calls runner.runAsync with the correct arguments", async () => {
87
- const newMessage = { role: "user", parts: [{ text: "Hi" }] };
88
- mockToAdkContent.mockReturnValue(newMessage);
89
-
90
- const runner = makeRunner();
91
- const handler = createAdkApiRoute({
92
- runner,
93
- userId: "user-1",
94
- sessionId: "session-1",
95
- });
96
-
97
- await handler(makeRequest());
98
-
99
- expect(runner.runAsync).toHaveBeenCalledOnce();
100
- expect(runner.runAsync).toHaveBeenCalledWith({
101
- userId: "user-1",
102
- sessionId: "session-1",
103
- newMessage,
104
- });
105
- });
106
-
107
- it("passes runner.runAsync result to adkEventStream and returns its response", async () => {
108
- const runner = makeRunner();
109
- const expectedResponse = new Response("ok", { status: 200 });
110
- mockAdkEventStream.mockReturnValue(expectedResponse);
111
-
112
- const handler = createAdkApiRoute({
113
- runner,
114
- userId: "user-1",
115
- sessionId: "session-1",
116
- });
117
-
118
- const result = await handler(makeRequest());
119
-
120
- expect(mockAdkEventStream).toHaveBeenCalledOnce();
121
- expect(result).toBe(expectedResponse);
122
- });
123
- });
124
-
125
- // ── userId and sessionId as functions ──
126
-
127
- describe("createAdkApiRoute - dynamic userId/sessionId", () => {
128
- it("resolves userId from a function", async () => {
129
- const runner = makeRunner();
130
- const handler = createAdkApiRoute({
131
- runner,
132
- userId: (req) => new URL(req.url).searchParams.get("user") ?? "default",
133
- sessionId: "session-1",
134
- });
135
-
136
- const req = new Request("http://localhost/api/adk?user=alice", {
137
- method: "POST",
138
- headers: { "Content-Type": "application/json" },
139
- body: JSON.stringify({ message: "Hi" }),
140
- });
141
- await handler(req);
142
-
143
- expect(runner.runAsync).toHaveBeenCalledWith(
144
- expect.objectContaining({ userId: "alice" }),
145
- );
146
- });
147
-
148
- it("resolves sessionId from a function", async () => {
149
- const runner = makeRunner();
150
- const handler = createAdkApiRoute({
151
- runner,
152
- userId: "user-1",
153
- sessionId: (req) =>
154
- new URL(req.url).searchParams.get("session") ?? "default",
155
- });
156
-
157
- const req = new Request("http://localhost/api/adk?session=s42", {
158
- method: "POST",
159
- headers: { "Content-Type": "application/json" },
160
- body: JSON.stringify({ message: "Hi" }),
161
- });
162
- await handler(req);
163
-
164
- expect(runner.runAsync).toHaveBeenCalledWith(
165
- expect.objectContaining({ sessionId: "s42" }),
166
- );
167
- });
168
-
169
- it("resolves async userId function", async () => {
170
- const runner = makeRunner();
171
- const handler = createAdkApiRoute({
172
- runner,
173
- userId: async () => "async-user",
174
- sessionId: "session-1",
175
- });
176
-
177
- await handler(makeRequest());
178
-
179
- expect(runner.runAsync).toHaveBeenCalledWith(
180
- expect.objectContaining({ userId: "async-user" }),
181
- );
182
- });
183
-
184
- it("resolves async sessionId function", async () => {
185
- const runner = makeRunner();
186
- const handler = createAdkApiRoute({
187
- runner,
188
- userId: "user-1",
189
- sessionId: async () => "async-session",
190
- });
191
-
192
- await handler(makeRequest());
193
-
194
- expect(runner.runAsync).toHaveBeenCalledWith(
195
- expect.objectContaining({ sessionId: "async-session" }),
196
- );
197
- });
198
- });
199
-
200
- // ── stateDelta passthrough ──
201
-
202
- describe("createAdkApiRoute - stateDelta", () => {
203
- it("passes stateDelta to runner.runAsync when present", async () => {
204
- mockParseAdkRequest.mockResolvedValue({
205
- type: "message",
206
- text: "Hello",
207
- config: {},
208
- stateDelta: { count: 1 },
209
- });
210
-
211
- const runner = makeRunner();
212
- const handler = createAdkApiRoute({
213
- runner,
214
- userId: "user-1",
215
- sessionId: "session-1",
216
- });
217
-
218
- await handler(makeRequest());
219
-
220
- expect(runner.runAsync).toHaveBeenCalledWith(
221
- expect.objectContaining({ stateDelta: { count: 1 } }),
222
- );
223
- });
224
-
225
- it("does not include stateDelta when it is null/undefined", async () => {
226
- mockParseAdkRequest.mockResolvedValue({
227
- type: "message",
228
- text: "Hello",
229
- config: {},
230
- });
231
-
232
- const runner = makeRunner();
233
- const handler = createAdkApiRoute({
234
- runner,
235
- userId: "user-1",
236
- sessionId: "session-1",
237
- });
238
-
239
- await handler(makeRequest());
240
-
241
- const callArgs = runner.runAsync.mock.calls[0]![0];
242
- expect(callArgs).not.toHaveProperty("stateDelta");
243
- });
244
- });
245
-
246
- // ── runConfig passthrough ──
247
-
248
- describe("createAdkApiRoute - runConfig", () => {
249
- it("passes runConfig to runner.runAsync when present", async () => {
250
- mockParseAdkRequest.mockResolvedValue({
251
- type: "message",
252
- text: "Hello",
253
- config: { runConfig: { temperature: 0.5 } },
254
- });
255
-
256
- const runner = makeRunner();
257
- const handler = createAdkApiRoute({
258
- runner,
259
- userId: "user-1",
260
- sessionId: "session-1",
261
- });
262
-
263
- await handler(makeRequest());
264
-
265
- expect(runner.runAsync).toHaveBeenCalledWith(
266
- expect.objectContaining({ runConfig: { temperature: 0.5 } }),
267
- );
268
- });
269
-
270
- it("does not include runConfig when it is null/undefined", async () => {
271
- mockParseAdkRequest.mockResolvedValue({
272
- type: "message",
273
- text: "Hello",
274
- config: {},
275
- });
276
-
277
- const runner = makeRunner();
278
- const handler = createAdkApiRoute({
279
- runner,
280
- userId: "user-1",
281
- sessionId: "session-1",
282
- });
283
-
284
- await handler(makeRequest());
285
-
286
- const callArgs = runner.runAsync.mock.calls[0]![0];
287
- expect(callArgs).not.toHaveProperty("runConfig");
288
- });
289
- });
290
-
291
- // ── onError passthrough ──
292
-
293
- describe("createAdkApiRoute - onError", () => {
294
- it("passes onError to adkEventStream", async () => {
295
- const onError = vi.fn();
296
- const runner = makeRunner();
297
- const handler = createAdkApiRoute({
298
- runner,
299
- userId: "user-1",
300
- sessionId: "session-1",
301
- onError,
302
- });
303
-
304
- await handler(makeRequest());
305
-
306
- expect(mockAdkEventStream).toHaveBeenCalledWith(expect.anything(), {
307
- onError,
308
- });
309
- });
310
-
311
- it("does not pass onError when not provided", async () => {
312
- const runner = makeRunner();
313
- const handler = createAdkApiRoute({
314
- runner,
315
- userId: "user-1",
316
- sessionId: "session-1",
317
- });
318
-
319
- await handler(makeRequest());
320
-
321
- expect(mockAdkEventStream).toHaveBeenCalledWith(
322
- expect.anything(),
323
- undefined,
324
- );
325
- });
326
- });
327
-
328
- // ── tool-result flow ──
329
-
330
- describe("createAdkApiRoute - tool-result flow", () => {
331
- it("handles tool-result requests", async () => {
332
- const toolParsed = {
333
- type: "tool-result" as const,
334
- toolCallId: "tc-1",
335
- toolName: "search",
336
- result: { found: true },
337
- isError: false,
338
- config: {},
339
- };
340
- mockParseAdkRequest.mockResolvedValue(toolParsed);
341
- mockToAdkContent.mockReturnValue({
342
- role: "user",
343
- parts: [
344
- {
345
- functionResponse: {
346
- name: "search",
347
- id: "tc-1",
348
- response: { found: true },
349
- },
350
- },
351
- ],
352
- });
353
-
354
- const runner = makeRunner();
355
- const handler = createAdkApiRoute({
356
- runner,
357
- userId: "user-1",
358
- sessionId: "session-1",
359
- });
360
-
361
- await handler(makeRequest());
362
-
363
- expect(mockToAdkContent).toHaveBeenCalledWith(toolParsed);
364
- expect(runner.runAsync).toHaveBeenCalledOnce();
365
- const callArgs = runner.runAsync.mock.calls[0]![0];
366
- expect(callArgs.newMessage.parts[0]).toMatchObject({
367
- functionResponse: { name: "search", id: "tc-1" },
368
- });
369
- });
370
- });