@assistant-ui/react-google-adk 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AdkClient.js +15 -2
- package/dist/AdkClient.js.map +1 -1
- package/dist/AdkEventAccumulator.d.ts +1 -0
- package/dist/AdkEventAccumulator.d.ts.map +1 -1
- package/dist/AdkEventAccumulator.js +20 -4
- package/dist/AdkEventAccumulator.js.map +1 -1
- package/dist/AdkSessionAdapter.d.ts +4 -4
- package/dist/AdkSessionAdapter.d.ts.map +1 -1
- package/dist/AdkSessionAdapter.js +16 -3
- package/dist/AdkSessionAdapter.js.map +1 -1
- package/dist/adkExtras.d.ts +1 -1
- package/dist/adkExtras.d.ts.map +1 -1
- package/dist/adkExtras.js +1 -1
- package/dist/adkExtras.js.map +1 -1
- package/dist/convertAdkMessages.d.ts.map +1 -1
- package/dist/convertAdkMessages.js +18 -11
- package/dist/convertAdkMessages.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +22 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/useAdkMessages.d.ts +2 -1
- package/dist/useAdkMessages.d.ts.map +1 -1
- package/dist/useAdkMessages.js +19 -1
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts +10 -4
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +79 -30
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +7 -4
- package/src/AdkClient.test.ts +55 -0
- package/src/AdkClient.ts +16 -2
- package/src/AdkEventAccumulator.test.ts +127 -0
- package/src/AdkEventAccumulator.ts +31 -5
- package/src/AdkSessionAdapter.test.ts +43 -0
- package/src/AdkSessionAdapter.ts +21 -4
- package/src/adkExtras.ts +1 -1
- package/src/convertAdkMessages.test.ts +113 -0
- package/src/convertAdkMessages.ts +24 -4
- package/src/index.ts +1 -0
- package/src/types.ts +21 -0
- package/src/useAdkMessages.ts +24 -1
- package/src/useAdkRuntime.refetch.test.tsx +336 -0
- package/src/useAdkRuntime.test.ts +222 -0
- package/src/useAdkRuntime.ts +139 -34
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdkAuthCredential, AdkAuthCredentialType, AdkAuthRequest, AdkEvent, AdkEventActions, AdkEventPart, AdkEventType, AdkMessage, AdkMessageContentPart, AdkMessageMetadata, AdkRunConfig, AdkSendMessageConfig, AdkStreamCallback, AdkStructuredEvent, AdkToolCall, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
1
|
+
import { AdkAuthCredential, AdkAuthCredentialType, AdkAuthRequest, AdkEvent, AdkEventActions, AdkEventPart, AdkEventType, AdkMessage, AdkMessageContentPart, AdkMessageMetadata, AdkRunConfig, AdkSendMessageConfig, AdkStreamCallback, AdkStructuredEvent, AdkThreadSnapshot, AdkToolCall, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
2
2
|
import { CreateAdkStreamOptions, createAdkStream } from "./AdkClient.js";
|
|
3
3
|
import { AdkEventAccumulator } from "./AdkEventAccumulator.js";
|
|
4
4
|
import { AdkArtifactData, AdkSessionAdapterOptions, createAdkSessionAdapter } from "./AdkSessionAdapter.js";
|
|
@@ -7,4 +7,4 @@ import { useAdkAgentInfo, useAdkAppState, useAdkArtifacts, useAdkAuthRequests, u
|
|
|
7
7
|
import { UseAdkRuntimeOptions, useAdkRuntime } from "./useAdkRuntime.js";
|
|
8
8
|
import { UseAdkMessagesOptions, useAdkMessages } from "./useAdkMessages.js";
|
|
9
9
|
import { toAdkStructuredEvents } from "./structuredEvents.js";
|
|
10
|
-
export { type AdkArtifactData, type AdkAuthCredential, type AdkAuthCredentialType, type AdkAuthRequest, type AdkEvent, AdkEventAccumulator, type AdkEventActions, type AdkEventPart, AdkEventType, type AdkMessage, type AdkMessageContentPart, type AdkMessageMetadata, type AdkRunConfig, type AdkSendMessageConfig, type AdkSessionAdapterOptions, type AdkStreamCallback, type AdkStructuredEvent, type AdkToolCall, type AdkToolConfirmation, type CreateAdkStreamOptions, type OnAdkAgentTransferCallback, type OnAdkCustomEventCallback, type OnAdkErrorCallback, type UseAdkMessagesOptions, type UseAdkRuntimeOptions, convertAdkMessage, createAdkSessionAdapter, createAdkStream, toAdkStructuredEvents, useAdkAgentInfo, useAdkAppState, useAdkArtifacts, useAdkAuthRequests, useAdkConfirmTool, useAdkEscalation, useAdkLongRunningToolIds, useAdkMessageMetadata, useAdkMessages, useAdkRuntime, useAdkSend, useAdkSessionState, useAdkSubmitAuth, useAdkSubmitInput, useAdkTempState, useAdkToolConfirmations, useAdkUserState };
|
|
10
|
+
export { type AdkArtifactData, type AdkAuthCredential, type AdkAuthCredentialType, type AdkAuthRequest, type AdkEvent, AdkEventAccumulator, type AdkEventActions, type AdkEventPart, AdkEventType, type AdkMessage, type AdkMessageContentPart, type AdkMessageMetadata, type AdkRunConfig, type AdkSendMessageConfig, type AdkSessionAdapterOptions, type AdkStreamCallback, type AdkStructuredEvent, type AdkThreadSnapshot, type AdkToolCall, type AdkToolConfirmation, type CreateAdkStreamOptions, type OnAdkAgentTransferCallback, type OnAdkCustomEventCallback, type OnAdkErrorCallback, type UseAdkMessagesOptions, type UseAdkRuntimeOptions, convertAdkMessage, createAdkSessionAdapter, createAdkStream, toAdkStructuredEvents, useAdkAgentInfo, useAdkAppState, useAdkArtifacts, useAdkAuthRequests, useAdkConfirmTool, useAdkEscalation, useAdkLongRunningToolIds, useAdkMessageMetadata, useAdkMessages, useAdkRuntime, useAdkSend, useAdkSessionState, useAdkSubmitAuth, useAdkSubmitInput, useAdkTempState, useAdkToolConfirmations, useAdkUserState };
|
package/dist/types.d.ts
CHANGED
|
@@ -275,6 +275,27 @@ type AdkRuntimeExtras = {
|
|
|
275
275
|
escalated: boolean;
|
|
276
276
|
messageMetadata: Map<string, AdkMessageMetadata>;
|
|
277
277
|
};
|
|
278
|
+
/**
|
|
279
|
+
* What a session load reconstructs. The messages are the whole thread; the
|
|
280
|
+
* rest is the per-turn state the events imply, which a caller that replays
|
|
281
|
+
* them through {@link AdkEventAccumulator} already has. Omitting a field
|
|
282
|
+
* clears it, since a snapshot that cannot describe the state is not evidence
|
|
283
|
+
* that the state survived.
|
|
284
|
+
*/
|
|
285
|
+
type AdkThreadSnapshot = {
|
|
286
|
+
messages: AdkMessage[];
|
|
287
|
+
longRunningToolIds?: string[] | undefined;
|
|
288
|
+
toolConfirmations?: AdkToolConfirmation[] | undefined;
|
|
289
|
+
authRequests?: AdkAuthRequest[] | undefined;
|
|
290
|
+
escalated?: boolean | undefined;
|
|
291
|
+
messageMetadata?: Map<string, AdkMessageMetadata> | undefined;
|
|
292
|
+
stateDelta?: Record<string, unknown> | undefined;
|
|
293
|
+
artifactDelta?: Record<string, number> | undefined;
|
|
294
|
+
agentInfo?: {
|
|
295
|
+
name?: string | undefined;
|
|
296
|
+
branch?: string | undefined;
|
|
297
|
+
} | undefined;
|
|
298
|
+
};
|
|
278
299
|
//#endregion
|
|
279
|
-
export { AdkAuthCredential, AdkAuthCredentialType, AdkAuthRequest, AdkEvent, AdkEventActions, AdkEventPart, AdkEventType, AdkMessage, AdkMessageContentPart, AdkMessageMetadata, AdkRunConfig, AdkRuntimeExtras, AdkSendMessageConfig, AdkStreamCallback, AdkStructuredEvent, AdkToolCall, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback };
|
|
300
|
+
export { AdkAuthCredential, AdkAuthCredentialType, AdkAuthRequest, AdkEvent, AdkEventActions, AdkEventPart, AdkEventType, AdkMessage, AdkMessageContentPart, AdkMessageMetadata, AdkRunConfig, AdkRuntimeExtras, AdkSendMessageConfig, AdkStreamCallback, AdkStructuredEvent, AdkThreadSnapshot, AdkToolCall, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback };
|
|
280
301
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAKY;EACV;EACA;EACA;IACE;IACA;IACA,MAAM;;EAER;IACE;IACA;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;;KAIQ;EACV,aAAa;EACb,gBAAgB;EAChB;EACA;EACA;EACA,uBAAuB;EACvB,6BAA6B;;KAGnB;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IAEM;IACA,QAAQ;;EAGd,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB;;KAKP;EACV;EACA;EACA,MAAM;EACN;;KAGU;EAEN;EACA;EACA,kBAAkB;;EAGlB;EACA;EACA,kBAAkB;EAClB,aAAa;EACb;EACA;EACA,SAAS;;EAGT;EACA;EACA;EACA;EACA;EACA;EACA;;KAGM;EACN;EAAc;;EACd;EAAmB;;EACnB;EAAe;EAAkB;;EACjC;EAAmB;;EAEnB;EACA;EACA;EACA;;EAGA;EACA;EACA;;EAEA;EAAc;EAAc;;EAC5B;EAAqB;EAAgB;;EACrC;EAAkB;;KAIZ;EACV;EACA;EACA,MAAM;EACN;EACA;EACA;;KAGU;KAOA;EACV,UAAU;EACV;EACA;EACA;IAEM;IACA;MACE;MACA;MACA;;;EAIR;IAEM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGN;;KAGU;EACV;EACA;;KAGU;EACV;EACA;EACA;;KAKU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;KAKU;;;;;;EAMV;EACA;EACA,aAAa;;cAKF;;;;;;;;;;;;KAaD;EACN;EAAiB;;EACjB;EAAiB;;EAEjB;EACA;IAAQ;IAAc;IAAa,MAAM;;;EAGzC;EACA;IAAU;IAAc;IAAa;;;EAErC;EAAmB;IAAQ;IAAc;;;EACzC;EAAqB;IAAU;IAAgB;;;EAC/C;EAAe;EAAoB;;EACnC;EAAkB;;EAElB;EACA,eAAe;;EAEf;;KAEM,qBACV,UAAU,cACV,QAAQ;EACN,aAAa;EACb,kBAAkB;IAChB;IACA;;MAGD,QAAQ,eAAe,aAAa,eAAe;KAI5C,sBAAsB,0BAA0B;KAEhD,4BACV,cACA,yBACU;KAEA,8BACV,2BACU;;KAGA;EACV,OAAO,UAAU,cAAc,QAAQ,yBAAyB;EAChE;IAAa;IAA2B;;EACxC,YAAY;EACZ,eAAe;EACf;EACA,mBAAmB;EACnB,cAAc;EACd;EACA,iBAAiB,YAAY"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAKY;EACV;EACA;EACA;IACE;IACA;IACA,MAAM;;EAER;IACE;IACA;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;EAEF;IACE;IACA;;;KAIQ;EACV,aAAa;EACb,gBAAgB;EAChB;EACA;EACA;EACA,uBAAuB;EACvB,6BAA6B;;KAGnB;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IAEM;IACA,QAAQ;;EAGd,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB;;KAKP;EACV;EACA;EACA,MAAM;EACN;;KAGU;EAEN;EACA;EACA,kBAAkB;;EAGlB;EACA;EACA,kBAAkB;EAClB,aAAa;EACb;EACA;EACA,SAAS;;EAGT;EACA;EACA;EACA;EACA;EACA;EACA;;KAGM;EACN;EAAc;;EACd;EAAmB;;EACnB;EAAe;EAAkB;;EACjC;EAAmB;;EAEnB;EACA;EACA;EACA;;EAGA;EACA;EACA;;EAEA;EAAc;EAAc;;EAC5B;EAAqB;EAAgB;;EACrC;EAAkB;;KAIZ;EACV;EACA;EACA,MAAM;EACN;EACA;EACA;;KAGU;KAOA;EACV,UAAU;EACV;EACA;EACA;IAEM;IACA;MACE;MACA;MACA;;;EAIR;IAEM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGN;;KAGU;EACV;EACA;;KAGU;EACV;EACA;EACA;;KAKU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;KAKU;;;;;;EAMV;EACA;EACA,aAAa;;cAKF;;;;;;;;;;;;KAaD;EACN;EAAiB;;EACjB;EAAiB;;EAEjB;EACA;IAAQ;IAAc;IAAa,MAAM;;;EAGzC;EACA;IAAU;IAAc;IAAa;;;EAErC;EAAmB;IAAQ;IAAc;;;EACzC;EAAqB;IAAU;IAAgB;;;EAC/C;EAAe;EAAoB;;EACnC;EAAkB;;EAElB;EACA,eAAe;;EAEf;;KAEM,qBACV,UAAU,cACV,QAAQ;EACN,aAAa;EACb,kBAAkB;IAChB;IACA;;MAGD,QAAQ,eAAe,aAAa,eAAe;KAI5C,sBAAsB,0BAA0B;KAEhD,4BACV,cACA,yBACU;KAEA,8BACV,2BACU;;KAGA;EACV,OAAO,UAAU,cAAc,QAAQ,yBAAyB;EAChE;IAAa;IAA2B;;EACxC,YAAY;EACZ,eAAe;EACf;EACA,mBAAmB;EACnB,cAAc;EACd;EACA,iBAAiB,YAAY;;;;;;;;;KAUnB;EACV,UAAU;EACV;EACA,oBAAoB;EACpB,eAAe;EACf;EACA,kBAAkB,YAAY;EAC9B,aAAa;EACb,gBAAgB;EAChB;IACM;IAA2B"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { MessageStatus } from \"@assistant-ui/core\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\n\n// ── ADK Event wire types (lightweight, no @google/adk dependency) ──\n\nexport type AdkEventPart = {\n text?: string;\n thought?: boolean;\n functionCall?: {\n name: string;\n id?: string;\n args: Record<string, unknown>;\n };\n functionResponse?: {\n name: string;\n id?: string;\n response: unknown;\n };\n executableCode?: {\n code: string;\n language?: string;\n };\n codeExecutionResult?: {\n output: string;\n outcome?: string;\n };\n inlineData?: {\n mimeType: string;\n data: string;\n };\n fileData?: {\n fileUri: string;\n mimeType?: string;\n };\n};\n\nexport type AdkEventActions = {\n stateDelta?: Record<string, unknown> | undefined;\n artifactDelta?: Record<string, number> | undefined;\n transferToAgent?: string | undefined;\n escalate?: boolean | undefined;\n skipSummarization?: boolean | undefined;\n requestedAuthConfigs?: Record<string, unknown> | undefined;\n requestedToolConfirmations?: Record<string, unknown> | undefined;\n};\n\nexport type AdkEvent = {\n id: string;\n invocationId?: string | undefined;\n author?: string | undefined;\n branch?: string | undefined;\n partial?: boolean | undefined;\n turnComplete?: boolean | undefined;\n interrupted?: boolean | undefined;\n finishReason?: string | undefined;\n timestamp?: number | undefined;\n content?:\n | {\n role?: string | undefined;\n parts?: AdkEventPart[] | undefined;\n }\n | undefined;\n actions?: AdkEventActions | undefined;\n longRunningToolIds?: string[] | undefined;\n errorCode?: string | undefined;\n errorMessage?: string | undefined;\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n customMetadata?: Record<string, unknown> | undefined;\n};\n\n// ── ADK Message types (accumulated from events) ──\n\nexport type AdkToolCall = {\n id: string;\n name: string;\n args: ReadonlyJSONObject;\n argsText?: string;\n};\n\nexport type AdkMessage =\n | {\n id: string;\n type: \"human\";\n content: string | AdkMessageContentPart[];\n }\n | {\n id: string;\n type: \"ai\";\n content: string | AdkMessageContentPart[];\n tool_calls?: AdkToolCall[] | undefined;\n author?: string | undefined;\n branch?: string | undefined;\n status?: MessageStatus | undefined;\n }\n | {\n id: string;\n type: \"tool\";\n content: string;\n tool_call_id: string;\n name: string;\n status?: \"success\" | \"error\" | undefined;\n artifact?: unknown;\n };\n\nexport type AdkMessageContentPart =\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"image\"; mimeType: string; data: string }\n | { type: \"image_url\"; url: string }\n | {\n type: \"file\";\n mimeType: string;\n data: string;\n filename?: string | undefined;\n }\n | {\n type: \"file_url\";\n url: string;\n mimeType?: string | undefined;\n }\n | { type: \"code\"; code: string; language: string }\n | { type: \"code_result\"; output: string; outcome: string }\n | { type: \"activity\"; message: string };\n\n// ── ADK-specific state types ──\n\nexport type AdkToolConfirmation = {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n hint: string;\n confirmed: boolean;\n payload?: unknown;\n};\n\nexport type AdkAuthCredentialType =\n | \"apiKey\"\n | \"http\"\n | \"oauth2\"\n | \"openIdConnect\"\n | \"serviceAccount\";\n\nexport type AdkAuthCredential = {\n authType: AdkAuthCredentialType;\n resourceRef?: string | undefined;\n apiKey?: string | undefined;\n http?:\n | {\n scheme: string;\n credentials: {\n username?: string;\n password?: string;\n token?: string;\n };\n }\n | undefined;\n oauth2?:\n | {\n clientId?: string;\n clientSecret?: string;\n authUri?: string;\n state?: string;\n redirectUri?: string;\n authResponseUri?: string;\n authCode?: string;\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n expiresIn?: number;\n }\n | undefined;\n serviceAccount?: unknown;\n};\n\nexport type AdkAuthRequest = {\n toolCallId: string;\n authConfig: unknown;\n};\n\nexport type AdkMessageMetadata = {\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n};\n\n// ── RunConfig ──\n\nexport type AdkRunConfig = {\n streamingMode?: \"none\" | \"sse\" | \"bidi\" | undefined;\n pauseOnToolCalls?: boolean | undefined;\n maxLlmCalls?: number | undefined;\n saveInputBlobsAsArtifacts?: boolean | undefined;\n supportCfc?: boolean | undefined;\n speechConfig?: unknown;\n responseModalities?: string[] | undefined;\n outputAudioTranscription?: unknown;\n inputAudioTranscription?: unknown;\n enableAffectiveDialog?: boolean | undefined;\n proactivity?: unknown;\n realtimeInputConfig?: unknown;\n};\n\n// ── Stream callback types ──\n\nexport type AdkSendMessageConfig = {\n /**\n * ADK RunConfig. Typed as `unknown` for compatibility with\n * assistant-ui core's RunConfig type. Use `AdkRunConfig` when\n * constructing configs manually for type safety.\n */\n runConfig?: unknown;\n checkpointId?: string | undefined;\n stateDelta?: Record<string, unknown> | undefined;\n};\n\n// ── Structured events ──\n\nexport const AdkEventType = {\n THOUGHT: \"thought\",\n CONTENT: \"content\",\n TOOL_CALL: \"tool_call\",\n TOOL_RESULT: \"tool_result\",\n CALL_CODE: \"call_code\",\n CODE_RESULT: \"code_result\",\n ERROR: \"error\",\n ACTIVITY: \"activity\",\n TOOL_CONFIRMATION: \"tool_confirmation\",\n FINISHED: \"finished\",\n} as const;\n\nexport type AdkStructuredEvent =\n | { type: \"thought\"; content: string }\n | { type: \"content\"; content: string }\n | {\n type: \"tool_call\";\n call: { name: string; id?: string; args: Record<string, unknown> };\n }\n | {\n type: \"tool_result\";\n result: { name: string; id?: string; response: unknown };\n }\n | { type: \"call_code\"; code: { code: string; language?: string } }\n | { type: \"code_result\"; result: { output: string; outcome?: string } }\n | { type: \"error\"; errorCode?: string; errorMessage?: string }\n | { type: \"activity\"; message: string }\n | {\n type: \"tool_confirmation\";\n confirmations: Record<string, unknown>;\n }\n | { type: \"finished\" };\n\nexport type AdkStreamCallback = (\n messages: AdkMessage[],\n config: AdkSendMessageConfig & {\n abortSignal: AbortSignal;\n initialize: () => Promise<{\n remoteId: string;\n externalId: string | undefined;\n }>;\n },\n) => Promise<AsyncGenerator<AdkEvent>> | AsyncGenerator<AdkEvent>;\n\n// ── Event handler callbacks ──\n\nexport type OnAdkErrorCallback = (error: unknown) => void | Promise<void>;\n\nexport type OnAdkCustomEventCallback = (\n type: string,\n data: unknown,\n) => void | Promise<void>;\n\nexport type OnAdkAgentTransferCallback = (\n toAgent: string,\n) => void | Promise<void>;\n\n/** Private state and actions `useAdkRuntime` exposes through `thread.extras`. */\nexport type AdkRuntimeExtras = {\n send: (messages: AdkMessage[], config: AdkSendMessageConfig) => Promise<void>;\n agentInfo: { name?: string | undefined; branch?: string | undefined };\n stateDelta: Record<string, unknown>;\n artifactDelta: Record<string, number>;\n longRunningToolIds: string[];\n toolConfirmations: AdkToolConfirmation[];\n authRequests: AdkAuthRequest[];\n escalated: boolean;\n messageMetadata: Map<string, AdkMessageMetadata>;\n};\n"],"mappings":";AA2NA,MAAa,eAAe;CAC1B,SAAS;CACT,SAAS;CACT,WAAW;CACX,aAAa;CACb,WAAW;CACX,aAAa;CACb,OAAO;CACP,UAAU;CACV,mBAAmB;CACnB,UAAU;AACZ"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { MessageStatus } from \"@assistant-ui/core\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\n\n// ── ADK Event wire types (lightweight, no @google/adk dependency) ──\n\nexport type AdkEventPart = {\n text?: string;\n thought?: boolean;\n functionCall?: {\n name: string;\n id?: string;\n args: Record<string, unknown>;\n };\n functionResponse?: {\n name: string;\n id?: string;\n response: unknown;\n };\n executableCode?: {\n code: string;\n language?: string;\n };\n codeExecutionResult?: {\n output: string;\n outcome?: string;\n };\n inlineData?: {\n mimeType: string;\n data: string;\n };\n fileData?: {\n fileUri: string;\n mimeType?: string;\n };\n};\n\nexport type AdkEventActions = {\n stateDelta?: Record<string, unknown> | undefined;\n artifactDelta?: Record<string, number> | undefined;\n transferToAgent?: string | undefined;\n escalate?: boolean | undefined;\n skipSummarization?: boolean | undefined;\n requestedAuthConfigs?: Record<string, unknown> | undefined;\n requestedToolConfirmations?: Record<string, unknown> | undefined;\n};\n\nexport type AdkEvent = {\n id: string;\n invocationId?: string | undefined;\n author?: string | undefined;\n branch?: string | undefined;\n partial?: boolean | undefined;\n turnComplete?: boolean | undefined;\n interrupted?: boolean | undefined;\n finishReason?: string | undefined;\n timestamp?: number | undefined;\n content?:\n | {\n role?: string | undefined;\n parts?: AdkEventPart[] | undefined;\n }\n | undefined;\n actions?: AdkEventActions | undefined;\n longRunningToolIds?: string[] | undefined;\n errorCode?: string | undefined;\n errorMessage?: string | undefined;\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n customMetadata?: Record<string, unknown> | undefined;\n};\n\n// ── ADK Message types (accumulated from events) ──\n\nexport type AdkToolCall = {\n id: string;\n name: string;\n args: ReadonlyJSONObject;\n argsText?: string;\n};\n\nexport type AdkMessage =\n | {\n id: string;\n type: \"human\";\n content: string | AdkMessageContentPart[];\n }\n | {\n id: string;\n type: \"ai\";\n content: string | AdkMessageContentPart[];\n tool_calls?: AdkToolCall[] | undefined;\n author?: string | undefined;\n branch?: string | undefined;\n status?: MessageStatus | undefined;\n }\n | {\n id: string;\n type: \"tool\";\n content: string;\n tool_call_id: string;\n name: string;\n status?: \"success\" | \"error\" | undefined;\n artifact?: unknown;\n };\n\nexport type AdkMessageContentPart =\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"image\"; mimeType: string; data: string }\n | { type: \"image_url\"; url: string }\n | {\n type: \"file\";\n mimeType: string;\n data: string;\n filename?: string | undefined;\n }\n | {\n type: \"file_url\";\n url: string;\n mimeType?: string | undefined;\n }\n | { type: \"code\"; code: string; language: string }\n | { type: \"code_result\"; output: string; outcome: string }\n | { type: \"activity\"; message: string };\n\n// ── ADK-specific state types ──\n\nexport type AdkToolConfirmation = {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n hint: string;\n confirmed: boolean;\n payload?: unknown;\n};\n\nexport type AdkAuthCredentialType =\n | \"apiKey\"\n | \"http\"\n | \"oauth2\"\n | \"openIdConnect\"\n | \"serviceAccount\";\n\nexport type AdkAuthCredential = {\n authType: AdkAuthCredentialType;\n resourceRef?: string | undefined;\n apiKey?: string | undefined;\n http?:\n | {\n scheme: string;\n credentials: {\n username?: string;\n password?: string;\n token?: string;\n };\n }\n | undefined;\n oauth2?:\n | {\n clientId?: string;\n clientSecret?: string;\n authUri?: string;\n state?: string;\n redirectUri?: string;\n authResponseUri?: string;\n authCode?: string;\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n expiresIn?: number;\n }\n | undefined;\n serviceAccount?: unknown;\n};\n\nexport type AdkAuthRequest = {\n toolCallId: string;\n authConfig: unknown;\n};\n\nexport type AdkMessageMetadata = {\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n};\n\n// ── RunConfig ──\n\nexport type AdkRunConfig = {\n streamingMode?: \"none\" | \"sse\" | \"bidi\" | undefined;\n pauseOnToolCalls?: boolean | undefined;\n maxLlmCalls?: number | undefined;\n saveInputBlobsAsArtifacts?: boolean | undefined;\n supportCfc?: boolean | undefined;\n speechConfig?: unknown;\n responseModalities?: string[] | undefined;\n outputAudioTranscription?: unknown;\n inputAudioTranscription?: unknown;\n enableAffectiveDialog?: boolean | undefined;\n proactivity?: unknown;\n realtimeInputConfig?: unknown;\n};\n\n// ── Stream callback types ──\n\nexport type AdkSendMessageConfig = {\n /**\n * ADK RunConfig. Typed as `unknown` for compatibility with\n * assistant-ui core's RunConfig type. Use `AdkRunConfig` when\n * constructing configs manually for type safety.\n */\n runConfig?: unknown;\n checkpointId?: string | undefined;\n stateDelta?: Record<string, unknown> | undefined;\n};\n\n// ── Structured events ──\n\nexport const AdkEventType = {\n THOUGHT: \"thought\",\n CONTENT: \"content\",\n TOOL_CALL: \"tool_call\",\n TOOL_RESULT: \"tool_result\",\n CALL_CODE: \"call_code\",\n CODE_RESULT: \"code_result\",\n ERROR: \"error\",\n ACTIVITY: \"activity\",\n TOOL_CONFIRMATION: \"tool_confirmation\",\n FINISHED: \"finished\",\n} as const;\n\nexport type AdkStructuredEvent =\n | { type: \"thought\"; content: string }\n | { type: \"content\"; content: string }\n | {\n type: \"tool_call\";\n call: { name: string; id?: string; args: Record<string, unknown> };\n }\n | {\n type: \"tool_result\";\n result: { name: string; id?: string; response: unknown };\n }\n | { type: \"call_code\"; code: { code: string; language?: string } }\n | { type: \"code_result\"; result: { output: string; outcome?: string } }\n | { type: \"error\"; errorCode?: string; errorMessage?: string }\n | { type: \"activity\"; message: string }\n | {\n type: \"tool_confirmation\";\n confirmations: Record<string, unknown>;\n }\n | { type: \"finished\" };\n\nexport type AdkStreamCallback = (\n messages: AdkMessage[],\n config: AdkSendMessageConfig & {\n abortSignal: AbortSignal;\n initialize: () => Promise<{\n remoteId: string;\n externalId: string | undefined;\n }>;\n },\n) => Promise<AsyncGenerator<AdkEvent>> | AsyncGenerator<AdkEvent>;\n\n// ── Event handler callbacks ──\n\nexport type OnAdkErrorCallback = (error: unknown) => void | Promise<void>;\n\nexport type OnAdkCustomEventCallback = (\n type: string,\n data: unknown,\n) => void | Promise<void>;\n\nexport type OnAdkAgentTransferCallback = (\n toAgent: string,\n) => void | Promise<void>;\n\n/** Private state and actions `useAdkRuntime` exposes through `thread.extras`. */\nexport type AdkRuntimeExtras = {\n send: (messages: AdkMessage[], config: AdkSendMessageConfig) => Promise<void>;\n agentInfo: { name?: string | undefined; branch?: string | undefined };\n stateDelta: Record<string, unknown>;\n artifactDelta: Record<string, number>;\n longRunningToolIds: string[];\n toolConfirmations: AdkToolConfirmation[];\n authRequests: AdkAuthRequest[];\n escalated: boolean;\n messageMetadata: Map<string, AdkMessageMetadata>;\n};\n\n/**\n * What a session load reconstructs. The messages are the whole thread; the\n * rest is the per-turn state the events imply, which a caller that replays\n * them through {@link AdkEventAccumulator} already has. Omitting a field\n * clears it, since a snapshot that cannot describe the state is not evidence\n * that the state survived.\n */\nexport type AdkThreadSnapshot = {\n messages: AdkMessage[];\n longRunningToolIds?: string[] | undefined;\n toolConfirmations?: AdkToolConfirmation[] | undefined;\n authRequests?: AdkAuthRequest[] | undefined;\n escalated?: boolean | undefined;\n messageMetadata?: Map<string, AdkMessageMetadata> | undefined;\n stateDelta?: Record<string, unknown> | undefined;\n artifactDelta?: Record<string, number> | undefined;\n agentInfo?:\n | { name?: string | undefined; branch?: string | undefined }\n | undefined;\n};\n"],"mappings":";AA2NA,MAAa,eAAe;CAC1B,SAAS;CACT,SAAS;CACT,WAAW;CACX,aAAa;CACb,WAAW;CACX,aAAa;CACb,OAAO;CACP,UAAU;CACV,mBAAmB;CACnB,UAAU;AACZ"}
|
package/dist/useAdkMessages.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdkAuthRequest, AdkMessage, AdkMessageMetadata, AdkSendMessageConfig, AdkStreamCallback, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
1
|
+
import { AdkAuthRequest, AdkMessage, AdkMessageMetadata, AdkSendMessageConfig, AdkStreamCallback, AdkThreadSnapshot, AdkToolConfirmation, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
2
2
|
//#region src/useAdkMessages.d.ts
|
|
3
3
|
type UseAdkMessagesOptions = {
|
|
4
4
|
stream: AdkStreamCallback;
|
|
@@ -25,6 +25,7 @@ declare const useAdkMessages: ({ stream, eventHandlers }: UseAdkMessagesOptions)
|
|
|
25
25
|
cancel: () => void;
|
|
26
26
|
setMessages: (msgs: AdkMessage[]) => void;
|
|
27
27
|
replaceMessages: (msgs: AdkMessage[]) => void;
|
|
28
|
+
applySnapshot: (snapshot: AdkThreadSnapshot) => void;
|
|
28
29
|
};
|
|
29
30
|
//#endregion
|
|
30
31
|
export { UseAdkMessagesOptions, useAdkMessages };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAdkMessages.d.ts","names":[],"sources":["../src/useAdkMessages.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"useAdkMessages.d.ts","names":[],"sources":["../src/useAdkMessages.ts"],"mappings":";;KAmBY;EACV,QAAQ;EACR;IACE,UAAU;IACV,gBAAgB;IAChB,kBAAkB;;;cAIT,mBAAkB,QAAA,iBAG5B;;;;IAIQ;IACE;;;;;;;;EA2EW,cAAA,aAAA,cAAY,QAAU,yBAAoB;;EAnDhB,cAAA,MAAA;EA+BvC,kBAAA,MAAA;EAnBI,gBAAA,UAAA"}
|
package/dist/useAdkMessages.js
CHANGED
|
@@ -27,6 +27,23 @@ const useAdkMessages = ({ stream, eventHandlers }) => {
|
|
|
27
27
|
messagesRef.current = msgs;
|
|
28
28
|
_setMessages(msgs);
|
|
29
29
|
}, []);
|
|
30
|
+
/**
|
|
31
|
+
* Swap the thread over to a loaded snapshot in one commit. Unlike
|
|
32
|
+
* {@link replaceMessages} this never passes through a cleared state, so a
|
|
33
|
+
* refetch that lands while a confirmation is on screen replaces it rather
|
|
34
|
+
* than blanking it first.
|
|
35
|
+
*/
|
|
36
|
+
const applySnapshot = useCallback((snapshot) => {
|
|
37
|
+
setMessagesImmediate(snapshot.messages);
|
|
38
|
+
setLongRunningToolIds(snapshot.longRunningToolIds ?? []);
|
|
39
|
+
setToolConfirmations(snapshot.toolConfirmations ?? []);
|
|
40
|
+
setAuthRequests(snapshot.authRequests ?? []);
|
|
41
|
+
setEscalated(snapshot.escalated ?? false);
|
|
42
|
+
setMessageMetadata(snapshot.messageMetadata ?? /* @__PURE__ */ new Map());
|
|
43
|
+
setStateDelta(snapshot.stateDelta ?? {});
|
|
44
|
+
setArtifactDelta(snapshot.artifactDelta ?? {});
|
|
45
|
+
setAgentInfo(snapshot.agentInfo ?? {});
|
|
46
|
+
}, [setMessagesImmediate]);
|
|
30
47
|
const replaceMessages = useCallback((msgs) => {
|
|
31
48
|
setMessagesImmediate(msgs);
|
|
32
49
|
setLongRunningToolIds([]);
|
|
@@ -111,7 +128,8 @@ const useAdkMessages = ({ stream, eventHandlers }) => {
|
|
|
111
128
|
if (abortControllerRef.current) abortControllerRef.current.abort();
|
|
112
129
|
}, []),
|
|
113
130
|
setMessages: setMessagesImmediate,
|
|
114
|
-
replaceMessages
|
|
131
|
+
replaceMessages,
|
|
132
|
+
applySnapshot
|
|
115
133
|
};
|
|
116
134
|
};
|
|
117
135
|
/** @internal — exported for unit tests. */
|
|
@@ -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 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\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 /**\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 [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 [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 applySnapshot,\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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"}
|
package/dist/useAdkRuntime.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdkMessage, AdkStreamCallback, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
1
|
+
import { AdkMessage, AdkStreamCallback, AdkThreadSnapshot, OnAdkAgentTransferCallback, OnAdkCustomEventCallback, OnAdkErrorCallback } from "./types.js";
|
|
2
2
|
import { AttachmentAdapter, DictationAdapter, ExternalStoreSharedOptions, FeedbackAdapter, RealtimeVoiceAdapter, RemoteThreadListAdapter, SpeechSynthesisAdapter } from "@assistant-ui/core";
|
|
3
3
|
import { AssistantCloud } from "assistant-cloud";
|
|
4
4
|
//#region src/useAdkRuntime.d.ts
|
|
@@ -16,9 +16,15 @@ type UseAdkRuntimeOptions = ExternalStoreSharedOptions & {
|
|
|
16
16
|
autoCancelPendingToolCalls?: boolean | undefined;
|
|
17
17
|
unstable_allowCancellation?: boolean | undefined;
|
|
18
18
|
getCheckpointId?: (threadId: string, parentMessages: AdkMessage[]) => Promise<string | null>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Loads a thread's stored state. Called when the thread opens, and again for
|
|
21
|
+
* `threads.reloadMainThread()`, which refetches in place rather than
|
|
22
|
+
* remounting the runtime; the signal aborts a load the runtime no longer
|
|
23
|
+
* needs.
|
|
24
|
+
*/
|
|
25
|
+
load?: (threadId: string, options?: {
|
|
26
|
+
signal?: AbortSignal | undefined;
|
|
27
|
+
}) => Promise<AdkThreadSnapshot>;
|
|
22
28
|
create?: () => Promise<{
|
|
23
29
|
externalId: string;
|
|
24
30
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAdkRuntime.d.ts","names":[],"sources":["../src/useAdkRuntime.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"useAdkRuntime.d.ts","names":[],"sources":["../src/useAdkRuntime.ts"],"mappings":";;;;KAsKY,uBAAuB;EACjC,QAAQ;;;;;;;;;EASR,qBAAqB;EACrB;EACA;EACA,mBACE,kBACA,gBAAgB,iBACb;;;;;;;EAOL,QACE,kBACA;IAAY,SAAS;QAClB,QAAQ;EACb,eAAe;IAAU;;EACzB,UAAU,qBAAqB;EAC/B;IAEM,cAAc;IACd,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,WAAW;;EAGjB;IAEM,UAAU;IACV,gBAAgB;IAChB,kBAAkB;;EAGxB,QAAQ;;;;;EAKR,iBAAiB;;cAmWN,kBAAiB,OAAA,gBAAA,QAAA,QAAA,UAAA,qBAAA,WAO3B,sDAAoB"}
|
package/dist/useAdkRuntime.js
CHANGED
|
@@ -2,14 +2,15 @@ import { adkExtras } from "./adkExtras.js";
|
|
|
2
2
|
import { convertAdkMessage } from "./convertAdkMessages.js";
|
|
3
3
|
import { useAdkMessages } from "./useAdkMessages.js";
|
|
4
4
|
import { v4 } from "uuid";
|
|
5
|
+
import { useCloudThreadListAdapter, useExternalMessageConverter, useExternalStoreRuntime, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
|
|
5
6
|
import { useAui } from "@assistant-ui/store";
|
|
6
|
-
import { useEffect, useRef, useState } from "react";
|
|
7
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
8
|
import { generateId, getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
8
|
-
import {
|
|
9
|
+
import { httpUrlPattern, parseDataUrl } from "@assistant-ui/core/internal";
|
|
9
10
|
//#region src/useAdkRuntime.ts
|
|
10
11
|
/** @internal — exported for unit tests. */
|
|
11
12
|
const getMessageContent = (msg) => {
|
|
12
|
-
const content = [...msg.content, ...msg.attachments?.flatMap((a) => a.content) ?? []].
|
|
13
|
+
const content = [...msg.content, ...msg.attachments?.flatMap((a) => a.content) ?? []].flatMap((part) => {
|
|
13
14
|
const type = part.type;
|
|
14
15
|
switch (type) {
|
|
15
16
|
case "text": return {
|
|
@@ -20,12 +21,27 @@ const getMessageContent = (msg) => {
|
|
|
20
21
|
type: "image_url",
|
|
21
22
|
url: part.image
|
|
22
23
|
};
|
|
23
|
-
case "file":
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
case "file":
|
|
25
|
+
if (part.sourceType === "url" || httpUrlPattern.test(part.data)) return {
|
|
26
|
+
type: "file_url",
|
|
27
|
+
url: part.data,
|
|
28
|
+
mimeType: part.mimeType
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
type: "file",
|
|
32
|
+
mimeType: part.mimeType,
|
|
33
|
+
data: parseDataUrl(part.data)?.data ?? part.data,
|
|
34
|
+
...part.filename != null && { filename: part.filename }
|
|
35
|
+
};
|
|
36
|
+
case "audio": {
|
|
37
|
+
const parsed = parseDataUrl(part.audio.data);
|
|
38
|
+
return {
|
|
39
|
+
type: "file",
|
|
40
|
+
mimeType: `audio/${part.audio.format}`,
|
|
41
|
+
data: parsed?.data ?? part.audio.data
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
case "data": return [];
|
|
29
45
|
case "tool-call": throw new Error("Tool call appends are not supported.");
|
|
30
46
|
default: throw new Error(`Unsupported append message part type: ${type}`);
|
|
31
47
|
}
|
|
@@ -78,14 +94,22 @@ const toAdkUserMessage = (msg, id = generateId()) => ({
|
|
|
78
94
|
const useAdkRuntimeImpl = (options) => {
|
|
79
95
|
const { autoCancelPendingToolCalls, adapters: { attachments, dictation, feedback, speech, voice } = {}, unstable_allowCancellation, stream, load, getCheckpointId, eventHandlers } = options;
|
|
80
96
|
const aui = useAui();
|
|
81
|
-
const { messages, stateDelta, agentInfo, longRunningToolIds, artifactDelta, toolConfirmations, authRequests, escalated, messageMetadata, sendMessage, cancel, setMessages, replaceMessages } = useAdkMessages({
|
|
97
|
+
const { messages, stateDelta, agentInfo, longRunningToolIds, artifactDelta, toolConfirmations, authRequests, escalated, messageMetadata, sendMessage, cancel, setMessages, replaceMessages, applySnapshot } = useAdkMessages({
|
|
82
98
|
stream,
|
|
83
99
|
...eventHandlers && { eventHandlers }
|
|
84
100
|
});
|
|
101
|
+
const loadRef = useRef(load);
|
|
102
|
+
loadRef.current = load;
|
|
103
|
+
const loadControllerRef = useRef(null);
|
|
104
|
+
const messagesRef = useRef(messages);
|
|
105
|
+
messagesRef.current = messages;
|
|
106
|
+
const [isLoadingThread, setIsLoadingThread] = useState(() => load !== void 0 && aui.threadListItem.getState().externalId != null);
|
|
85
107
|
const [isRunning, setIsRunning] = useState(false);
|
|
86
108
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
87
109
|
const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
|
|
88
110
|
const effectiveIsRunning = isRunning || hasExecutingTools;
|
|
111
|
+
const isRunningRef = useRef(effectiveIsRunning);
|
|
112
|
+
isRunningRef.current = effectiveIsRunning;
|
|
89
113
|
const handleSendMessage = async (msgs, config) => {
|
|
90
114
|
try {
|
|
91
115
|
setIsRunning(true);
|
|
@@ -129,9 +153,51 @@ const useAdkRuntimeImpl = (options) => {
|
|
|
129
153
|
adkMessagesRef.current = nextMessages;
|
|
130
154
|
setMessages(nextMessages);
|
|
131
155
|
};
|
|
132
|
-
const
|
|
156
|
+
const threadListItem = aui.threadListItem.source !== null ? aui.threadListItem : void 0;
|
|
157
|
+
const runLoad = useCallback((purpose = "initial") => {
|
|
158
|
+
const loadFn = loadRef.current;
|
|
159
|
+
if (!loadFn || !threadListItem) return Promise.resolve();
|
|
160
|
+
const externalId = threadListItem.getState().externalId;
|
|
161
|
+
if (externalId == null) return Promise.resolve();
|
|
162
|
+
if (purpose === "reload" && loadControllerRef.current?.purpose === "initial") return loadControllerRef.current.promise ?? Promise.resolve();
|
|
163
|
+
loadControllerRef.current?.controller.abort();
|
|
164
|
+
const controller = new AbortController();
|
|
165
|
+
const record = {
|
|
166
|
+
controller,
|
|
167
|
+
purpose
|
|
168
|
+
};
|
|
169
|
+
loadControllerRef.current = record;
|
|
170
|
+
const messagesAtLoadStart = messagesRef.current;
|
|
171
|
+
if (purpose === "initial") setIsLoadingThread(true);
|
|
172
|
+
const task = loadFn(externalId, { signal: controller.signal }).then((snapshot) => {
|
|
173
|
+
if (controller.signal.aborted) return;
|
|
174
|
+
if (purpose === "reload" && (isRunningRef.current || messagesRef.current !== messagesAtLoadStart)) return;
|
|
175
|
+
applySnapshot(snapshot);
|
|
176
|
+
}).catch((error) => {
|
|
177
|
+
if (controller.signal.aborted) return;
|
|
178
|
+
throw error;
|
|
179
|
+
}).finally(() => {
|
|
180
|
+
if (loadControllerRef.current?.controller === controller) loadControllerRef.current = null;
|
|
181
|
+
if (controller.signal.aborted) return;
|
|
182
|
+
setIsLoadingThread(false);
|
|
183
|
+
});
|
|
184
|
+
record.promise = task;
|
|
185
|
+
if (purpose === "reload") return task;
|
|
186
|
+
return task.catch((e) => {
|
|
187
|
+
console.warn("Failed to load ADK session:", e);
|
|
188
|
+
});
|
|
189
|
+
}, [threadListItem, applySnapshot]);
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
runLoad();
|
|
192
|
+
return () => {
|
|
193
|
+
loadControllerRef.current?.controller.abort();
|
|
194
|
+
setIsLoadingThread(false);
|
|
195
|
+
};
|
|
196
|
+
}, [runLoad]);
|
|
197
|
+
return useExternalStoreRuntime({
|
|
133
198
|
...pickExternalStoreSharedOptions(options),
|
|
134
199
|
isRunning: effectiveIsRunning,
|
|
200
|
+
isLoading: isLoadingThread,
|
|
135
201
|
messages: threadMessages,
|
|
136
202
|
unstable_enableToolInvocations: true,
|
|
137
203
|
setToolStatuses,
|
|
@@ -221,26 +287,9 @@ const useAdkRuntimeImpl = (options) => {
|
|
|
221
287
|
},
|
|
222
288
|
onCancel: unstable_allowCancellation ? async () => {
|
|
223
289
|
cancel();
|
|
224
|
-
} : void 0
|
|
290
|
+
} : void 0,
|
|
291
|
+
...load !== void 0 && { onRefetchThread: () => runLoad("reload") }
|
|
225
292
|
});
|
|
226
|
-
{
|
|
227
|
-
const loadRef = useRef(load);
|
|
228
|
-
useEffect(() => {
|
|
229
|
-
loadRef.current = load;
|
|
230
|
-
});
|
|
231
|
-
useEffect(() => {
|
|
232
|
-
const loadFn = loadRef.current;
|
|
233
|
-
if (!loadFn) return;
|
|
234
|
-
const externalId = aui.threadListItem.getState().externalId;
|
|
235
|
-
if (externalId == null) return;
|
|
236
|
-
loadFn(externalId).then(({ messages: msgs }) => {
|
|
237
|
-
replaceMessages(msgs);
|
|
238
|
-
}, (e) => {
|
|
239
|
-
console.warn("Failed to load ADK session:", e);
|
|
240
|
-
});
|
|
241
|
-
}, [aui, replaceMessages]);
|
|
242
|
-
}
|
|
243
|
-
return runtime;
|
|
244
293
|
};
|
|
245
294
|
const useAdkRuntime = ({ cloud, sessionAdapter, create, delete: deleteFn, onThreadIdChange, ...options }) => {
|
|
246
295
|
const aui = useAui();
|
|
@@ -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":";;;;;;;;;;AAsCA,MAAa,qBAAqB,QAAuB;CAKvD,MAAM,UAAU,CAHd,GAAG,IAAI,SACP,GAAI,IAAI,aAAa,SAAS,MAAM,EAAE,OAAO,KAAK,CAAC,CAE5B,CAAC,CAAC,KAAK,SAAS;EACvC,MAAM,OAAO,KAAK;EAClB,QAAQ,MAAR;GACE,KAAK,QACH,OAAO;IAAE,MAAM;IAAiB,MAAM,KAAK;GAAK;GAClD,KAAK,SACH,OAAO;IAAE,MAAM;IAAsB,KAAK,KAAK;GAAM;GACvD,KAAK,QACH,OAAO;IACL,MAAM;IACN,UAAU,KAAK;IACf,MAAM,KAAK;IACX,GAAI,KAAK,YAAY,QAAQ,EAAE,UAAU,KAAK,SAAS;GACzD;GAEF,KAAK,aACH,MAAM,IAAI,MAAM,sCAAsC;GAExD,SAOE,MAAM,IAAI,MACR,yCAAyCA,MAC3C;EAEJ;CACF,CAAC;CAED,IAAI,QAAQ,WAAW,KAAK,QAAQ,EAAE,EAAE,SAAS,QAC/C,OAAO,QAAQ,EAAE,CAAC,QAAQ;CAG5B,OAAO;AACT;;AAGA,MAAa,uBAAuB,aAA2B;CAC7D,MAAM,0BAAU,IAAI,IAA0C;CAC9D,KAAK,MAAM,OAAO,UAAU;EAC1B,IAAI,IAAI,SAAS,QAAQ,IAAI,YAC3B,KAAK,MAAM,MAAM,IAAI,YACnB,QAAQ,IAAI,GAAG,IAAI,EAAE;EAGzB,IAAI,IAAI,SAAS,QACf,QAAQ,OAAO,IAAI,YAAY;CAEnC;CACA,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC;AAC7B;;;;;;;;;;AAWA,MAAa,2BACX,UACA,uBACyC;CACzC,MAAM,iBAAiB,IAAI,IAAI,kBAAkB;CACjD,OAAO,oBAAoB,QAAQ,CAAC,CACjC,QAAQ,MAAM,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC,CAAC,CACxC,KACE,OACE;EACC,IAAIC,GAAO;EACX,MAAM;EACN,MAAM,EAAE;EACR,cAAc,EAAE;EAChB,SAAS,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;EAC3C,QAAQ;CACV,EACJ;AACJ;AAEA,MAAM,uBACJ,gBACA,aACiB;CACjB,IAAI,aAAa,MAAM,OAAO,CAAC;CAC/B,MAAM,cAAc,eAAe,WAAW,MAAM,EAAE,OAAO,QAAQ;CACrE,IAAI,gBAAgB,IAAI,OAAO,CAAC;CAChC,MAAM,YAA0B,CAAC;CACjC,KAAK,IAAI,IAAI,GAAG,KAAK,eAAe,IAAI,eAAe,QAAQ,KAC7D,UAAU,KAAK,GAAG,yBAAqC,eAAe,EAAG,CAAC;CAE5E,OAAO;AACT;AAEA,MAAM,oBACJ,KACA,KAAK,WAAW,OACgC;CAChD;CACA,MAAM;CACN,SAAS,kBAAkB,GAAG;AAChC;AA8CA,MAAM,qBAAqB,YAAkC;CAC3D,MAAM,EACJ,4BACA,UAAU,EAAE,aAAa,WAAW,UAAU,QAAQ,UAAU,CAAC,GACjE,4BACA,QACA,MACA,iBACA,kBACE;CACJ,MAAM,MAAM,OAAO;CACnB,MAAM,EACJ,UACA,YACA,WACA,oBACA,eACA,mBACA,cACA,WACA,iBACA,aACA,QACA,aACA,oBACE,eAAe;EACjB;EACA,GAAI,iBAAiB,EAAE,cAAc;CACvC,CAAC;CAED,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,cAAc,mBAAmB,SAEtC,CAAC,CAAC;CACJ,MAAM,oBAAoB,OAAO,OAAO,YAAY,CAAC,CAAC,MACnD,MAAM,GAAG,SAAS,WACrB;CACA,MAAM,qBAAqB,aAAa;CAExC,MAAM,oBAAoB,OACxB,MACA,WACG;EACH,IAAI;GACF,aAAa,IAAI;GACjB,MAAM,YAAY,MAAM,MAAM;EAChC,UAAU;GACR,aAAa,KAAK;EACpB;CACF;CAEA,MAAM,iBAAiB,4BAA4B;EACjD,UAAU;EACV;EACA,WAAW;CACb,CAAC;CAED,MAAM,oBAAoB,OAAO,cAAc;CAC/C,kBAAkB,UAAU;CAE5B,MAAM,iBAAiB,OAAO,QAAQ;CACtC,eAAe,UAAU;CAEzB,MAAM,oBAAoB,uBACxB,IAAI,IAMF,CACJ;CACA,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,CAAC;CAC9D,MAAM,oBAAoB,qBAAqB;CAE/C,MAAM,gBAAgB,aAA4B;EAChD,IAAI,CAAC,YAAY,CAAC,kBAAkB,QAAQ,IAAI,QAAQ,GAAG,OAAO;EAElE,MAAM,SAAuB,CAAC;EAC9B,KAAK,MAAM,WAAW,eAAe,SAAS;GAC5C,IAAI,QAAQ,MAAM,kBAAkB,QAAQ,IAAI,QAAQ,EAAE,GACxD,OAAO,KAAK,kBAAkB,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAE,OAAO;GAEhE,IAAI,QAAQ,OAAO,UAAU;EAC/B;EAEA,OAAO;GACL,UAAU;GACV,WAAW,kBAAkB,QAAQ,IAAI,QAAQ,CAAC,CAAE;EACtD;CACF;CAEA,MAAM,oBAAoB,QAAuB;EAC/C,MAAM,gBAAgB,iBAAiB,GAAG;EAC1C,kBAAkB,QAAQ,IAAI,cAAc,IAAI;GAC9C,SAAS;GACT,WAAW,IAAI;EACjB,CAAC;EACD,sBAAsB,kBAAkB,QAAQ,IAAI;EACpD,MAAM,eAAe,CAAC,GAAG,eAAe,SAAS,aAAa;EAC9D,eAAe,UAAU;EACzB,YAAY,YAAY;CAC1B;CAEA,MAAM,UAAU,wBAAwB;EACtC,GAAG,+BAA+B,OAAO;EACzC,WAAW;EACX,UAAU;EACV,gCAAgC;EAChC;EACA,UAAU;GAAE;GAAa;GAAW;GAAU;GAAQ;EAAM;EAC5D,QAAQ,UAAU,QAAQ;GACxB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,MAAM;EACR,CAAC;EACD,OAAO,OAAO,QAAQ;GACpB,IAAI,EAAE,IAAI,YAAY,IAAI,SAAS,SAAS;IAC1C,iBAAiB,GAAG;IACpB;GACF;GAEA,MAAM,gBACJ,+BAA+B,QAC3B,wBAAwB,UAAU,kBAAkB,IACpD,CAAC;GAEP,OAAO,kBACL,CACE,GAAG,eACH;IACE,IAAIA,GAAO;IACX,MAAM;IACN,SAAS,kBAAkB,GAAG;GAChC,CACF,GACA,EAAE,WAAW,IAAI,UAAU,CAC7B;EACF;EACA,QAAQ,kBACJ,OAAO,QAAQ;GACb,MAAM,YAAY,oBAChB,kBAAkB,SAClB,IAAI,QACN;GACA,gBAAgB,SAAS;GACzB,IAAI,EAAE,IAAI,YAAY,IAAI,SAAS,SAAS;IAC1C,MAAM,gBAAgB,iBAAiB,GAAG;IAC1C,kBAAkB,QAAQ,IAAI,cAAc,IAAI;KAC9C,SAAS;KACT,WAAW,IAAI;IACjB,CAAC;IACD,sBAAsB,kBAAkB,QAAQ,IAAI;IACpD,MAAM,eAAe,CAAC,GAAG,WAAW,aAAa;IACjD,eAAe,UAAU;IACzB,YAAY,YAAY;IACxB;GACF;GACA,MAAM,aAAa,IAAI,eAAe,SAAS,CAAC,CAAC;GACjD,MAAM,eAAe,aACjB,MAAM,gBAAgB,YAAY,SAAS,IAC3C;GACJ,OAAO,kBACL,CACE;IACE,IAAIA,GAAO;IACX,MAAM;IACN,SAAS,kBAAkB,GAAG;GAChC,CACF,GACA;IACE,WAAW,IAAI;IACf,GAAI,gBAAgB,EAAE,aAAa;GACrC,CACF;EACF,IACA,KAAA;EACJ,GAAI,mBAAmB,oBACnB,EACE,UAAU,OAAO,UAAU,WAAW;GACpC,MAAM,YAAY,aAAa,QAAQ;GACvC,IAAI,WAAW;IACb,KAAK,MAAM,WAAW,UAAU,UAC9B,kBAAkB,QAAQ,OAAO,QAAQ,EAAE;IAE7C,sBAAsB,kBAAkB,QAAQ,IAAI;IACpD,OAAO,kBAAkB,UAAU,UAAU,EAC3C,WAAW,OAAO,aAAa,UAAU,UAC3C,CAAC;GACH;GAEA,IAAI,CAAC,iBACH,MAAM,IAAI,MAAM,8CAA8C;GAEhE,MAAM,YAAY,oBAChB,kBAAkB,SAClB,QACF;GACA,gBAAgB,SAAS;GACzB,MAAM,aAAa,IAAI,eAAe,SAAS,CAAC,CAAC;GACjD,MAAM,eAAe,aACjB,MAAM,gBAAgB,YAAY,SAAS,IAC3C;GACJ,OAAO,kBAAkB,CAAC,GAAG;IAC3B,WAAW,OAAO;IAClB,GAAI,gBAAgB,EAAE,aAAa;GACrC,CAAC;EACH,EACF,IACA,CAAC;EACL,iBAAiB,OAAO,EACtB,YACA,UACA,QACA,SACA,eACI;GACJ,MAAM,kBACJ,CACE;IACE,IAAIA,GAAO;IACX,MAAM;IACN,MAAM;IACN,cAAc;IACd,SAAS,KAAK,UAAU,MAAM;IAC9B;IACA,QAAQ,UAAU,UAAU;GAC9B,CACF,GACA,CAAC,CACH;EACF;EACA,UAAU,6BACN,YAAY;GACV,OAAO;EACT,IACA,KAAA;CACN,CAAC;CAED;EACE,MAAM,UAAU,OAAO,IAAI;EAC3B,gBAAgB;GACd,QAAQ,UAAU;EACpB,CAAC;EAED,gBAAgB;GACd,MAAM,SAAS,QAAQ;GACvB,IAAI,CAAC,QAAQ;GAEb,MAAM,aAAa,IAAI,eAAe,SAAS,CAAC,CAAC;GACjD,IAAI,cAAc,MAAM;GAExB,OAAO,UAAU,CAAC,CAAC,MAChB,EAAE,UAAU,WAAW;IACtB,gBAAgB,IAAI;GACtB,IACC,MAAM;IACL,QAAQ,KAAK,+BAA+B,CAAC;GAC/C,CACF;EACF,GAAG,CAAC,KAAK,eAAe,CAAC;CAC3B;CAEA,OAAO;AACT;AAEA,MAAa,iBAAiB,EAC5B,OACA,gBACA,QACA,QAAQ,UACR,kBACA,GAAG,cACuB;CAC1B,MAAM,MAAM,OAAO;CACnB,MAAM,eAAe,0BAA0B;EAC7C;EACA,QAAQ,YAAY;GAClB,IAAI,QAAQ,OAAO,OAAO;GAC1B,IAAI,IAAI,eAAe,QAAQ,OAAO,IAAI,eAAe,WAAW;GACpE,OAAO,EAAE,YAAY,KAAA,EAAU;EACjC;EACA,QAAQ;CACV,CAAC;CAID,OAAO,2BAA2B;EAChC,aAAa,SAAS,cAAc;GAClC,OAAO,kBAAkB,OAAO;EAClC;EACA,SANc,kBAAkB;EAOhC,cAAc;EACd;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"useAdkRuntime.js","names":["_exhaustiveCheck","uuidv4"],"sources":["../src/useAdkRuntime.ts"],"sourcesContent":["import { useCallback, 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 { httpUrlPattern, parseDataUrl } 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 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 { 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.flatMap((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 if (part.sourceType === \"url\" || httpUrlPattern.test(part.data)) {\n return {\n type: \"file_url\" as const,\n url: part.data,\n mimeType: part.mimeType,\n };\n }\n return {\n type: \"file\" as const,\n mimeType: part.mimeType,\n // Lands in Gemini `inlineData.data`, which takes bare base64, so a\n // data URL envelope is stripped rather than forwarded.\n data: parseDataUrl(part.data)?.data ?? part.data,\n ...(part.filename != null && { filename: part.filename }),\n };\n case \"audio\": {\n const parsed = parseDataUrl(part.audio.data);\n return {\n type: \"file\" as const,\n mimeType: `audio/${part.audio.format}`,\n data: parsed?.data ?? part.audio.data,\n };\n }\n case \"data\":\n return [];\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default: {\n const _exhaustiveCheck: \"reasoning\" | \"source\" | \"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 /**\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 {\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 applySnapshot,\n } = useAdkMessages({\n stream,\n ...(eventHandlers && { eventHandlers }),\n });\n\n const loadRef = useRef(load);\n loadRef.current = load;\n const loadControllerRef = useRef<{\n controller: AbortController;\n purpose: \"initial\" | \"reload\";\n promise?: Promise<void> | undefined;\n } | null>(null);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\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 isRunningRef.current = effectiveIsRunning;\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 // 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 if (\n purpose === \"reload\" &&\n loadControllerRef.current?.purpose === \"initial\"\n )\n return loadControllerRef.current.promise ?? Promise.resolve();\n\n loadControllerRef.current?.controller.abort();\n const controller = new AbortController();\n const record: NonNullable<typeof loadControllerRef.current> = {\n controller,\n purpose,\n };\n loadControllerRef.current = record;\n\n const messagesAtLoadStart = messagesRef.current;\n if (purpose === \"initial\") setIsLoadingThread(true);\n\n const task = loadFn(externalId, { signal: controller.signal })\n .then((snapshot) => {\n if (controller.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 .catch((error: unknown) => {\n // Aborting a load the runtime no longer needs is not a failure.\n if (controller.signal.aborted) return;\n throw error;\n })\n .finally(() => {\n if (loadControllerRef.current?.controller === controller) {\n loadControllerRef.current = null;\n }\n if (controller.signal.aborted) return;\n setIsLoadingThread(false);\n });\n record.promise = task;\n\n // A refetch reports the failure to whoever awaited it; the initial load\n // has no caller to tell.\n if (purpose === \"reload\") return task;\n return task.catch((e: unknown) => {\n console.warn(\"Failed to load ADK session:\", e);\n });\n },\n [threadListItem, applySnapshot],\n );\n\n useEffect(() => {\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 loadControllerRef.current?.controller.abort();\n setIsLoadingThread(false);\n };\n }, [runLoad]);\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: effectiveIsRunning,\n isLoading: isLoadingThread,\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 ...(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 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.
|
|
3
|
+
"version": "0.0.21",
|
|
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.
|
|
38
|
-
"@assistant-ui/store": "^0.3.
|
|
37
|
+
"@assistant-ui/core": "^0.3.4",
|
|
38
|
+
"@assistant-ui/store": "^0.3.3",
|
|
39
39
|
"assistant-cloud": "*",
|
|
40
|
-
"assistant-stream": "^0.3.
|
|
40
|
+
"assistant-stream": "^0.3.32",
|
|
41
41
|
"uuid": "^14.0.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
@@ -54,8 +54,11 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
+
"@testing-library/dom": "^10.4.1",
|
|
58
|
+
"@testing-library/react": "^16.3.2",
|
|
57
59
|
"@types/react": "^19.2.17",
|
|
58
60
|
"@types/uuid": "^11.0.0",
|
|
61
|
+
"jsdom": "^29.1.1",
|
|
59
62
|
"react": "^19.2.8",
|
|
60
63
|
"vitest": "^4.1.10",
|
|
61
64
|
"@assistant-ui/x-buildutils": "0.0.20"
|
package/src/AdkClient.test.ts
CHANGED
|
@@ -630,6 +630,61 @@ describe("createAdkStream - SSE parsing", () => {
|
|
|
630
630
|
expect(collected).toHaveLength(1);
|
|
631
631
|
expect(collected[0]!.id).toBe("e1");
|
|
632
632
|
});
|
|
633
|
+
|
|
634
|
+
it("cancels the response body when iteration stops early", async () => {
|
|
635
|
+
const cancel = vi.fn();
|
|
636
|
+
const encoder = new TextEncoder();
|
|
637
|
+
const body = new ReadableStream<Uint8Array>({
|
|
638
|
+
start(controller) {
|
|
639
|
+
controller.enqueue(
|
|
640
|
+
encoder.encode(`data: ${JSON.stringify({ id: "e1" })}\n\n`),
|
|
641
|
+
);
|
|
642
|
+
},
|
|
643
|
+
cancel,
|
|
644
|
+
});
|
|
645
|
+
mockFetch.mockResolvedValueOnce(sseResponse(body));
|
|
646
|
+
|
|
647
|
+
const stream = createAdkStream({ api: "/api/adk" });
|
|
648
|
+
const gen = await stream(
|
|
649
|
+
[{ id: "m1", type: "human", content: "Hi" }],
|
|
650
|
+
makeConfig(),
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
for await (const _event of gen) {
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
expect(cancel).toHaveBeenCalledOnce();
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it("does not surface cancellation errors on early exit", async () => {
|
|
661
|
+
const encoder = new TextEncoder();
|
|
662
|
+
let controller!: ReadableStreamDefaultController<Uint8Array>;
|
|
663
|
+
const body = new ReadableStream<Uint8Array>({
|
|
664
|
+
start(streamController) {
|
|
665
|
+
controller = streamController;
|
|
666
|
+
controller.enqueue(
|
|
667
|
+
encoder.encode(`data: ${JSON.stringify({ id: "e1" })}\n\n`),
|
|
668
|
+
);
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
mockFetch.mockResolvedValueOnce(sseResponse(body));
|
|
672
|
+
|
|
673
|
+
const stream = createAdkStream({ api: "/api/adk" });
|
|
674
|
+
const gen = await stream(
|
|
675
|
+
[{ id: "m1", type: "human", content: "Hi" }],
|
|
676
|
+
makeConfig(),
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
const consume = async () => {
|
|
680
|
+
for await (const _event of gen) {
|
|
681
|
+
controller.error(new Error("stream failed"));
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
await expect(consume()).resolves.toBeUndefined();
|
|
687
|
+
});
|
|
633
688
|
});
|
|
634
689
|
|
|
635
690
|
// ── Error handling ──
|