@assistant-ui/react-google-adk 0.0.35 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/dist/AdkClient.d.ts +4 -0
- package/dist/AdkClient.d.ts.map +1 -1
- package/dist/AdkClient.js +12 -7
- package/dist/AdkClient.js.map +1 -1
- package/dist/AdkSessionAdapter.d.ts.map +1 -1
- package/dist/AdkSessionAdapter.js +7 -7
- package/dist/AdkSessionAdapter.js.map +1 -1
- package/dist/AdkThreadController.d.ts +15 -0
- package/dist/AdkThreadController.d.ts.map +1 -0
- package/dist/AdkThreadController.js +35 -0
- package/dist/AdkThreadController.js.map +1 -0
- package/dist/adkThreadState.d.ts +54 -0
- package/dist/adkThreadState.d.ts.map +1 -0
- package/dist/adkThreadState.js +93 -0
- package/dist/adkThreadState.js.map +1 -0
- package/dist/convertToAdkMessages.js +1 -1
- package/dist/convertToAdkMessages.js.map +1 -1
- package/dist/sdkIdentity.js +1 -1
- package/dist/server/createAdkApiRoute.d.ts +37 -6
- package/dist/server/createAdkApiRoute.d.ts.map +1 -1
- package/dist/server/createAdkApiRoute.js +55 -5
- package/dist/server/createAdkApiRoute.js.map +1 -1
- package/dist/server/parseAdkRequest.d.ts +4 -1
- package/dist/server/parseAdkRequest.d.ts.map +1 -1
- package/dist/server/parseAdkRequest.js +5 -1
- package/dist/server/parseAdkRequest.js.map +1 -1
- package/dist/useAdkMessages.d.ts +9 -7
- package/dist/useAdkMessages.d.ts.map +1 -1
- package/dist/useAdkMessages.js +55 -77
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts +7 -1
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +134 -56
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +5 -5
- package/src/AdkClient.test.ts +78 -2
- package/src/AdkClient.ts +24 -6
- package/src/AdkSessionAdapter.ts +1 -1
- package/src/AdkThreadController.test.ts +90 -0
- package/src/AdkThreadController.ts +45 -0
- package/src/adkThreadState.test.ts +207 -0
- package/src/adkThreadState.ts +124 -0
- package/src/convertToAdkMessages.test.ts +19 -0
- package/src/convertToAdkMessages.ts +1 -1
- package/src/hooks.test.tsx +1 -0
- package/src/server/createAdkApiRoute.controls.test.ts +66 -0
- package/src/server/createAdkApiRoute.test.ts +282 -0
- package/src/server/createAdkApiRoute.ts +119 -11
- package/src/server/parseAdkRequest.test.ts +11 -3
- package/src/server/parseAdkRequest.ts +7 -1
- package/src/useAdkMessages.test.ts +1 -0
- package/src/useAdkMessages.ts +61 -96
- package/src/useAdkRuntime.cancellation.test.tsx +4 -3
- package/src/useAdkRuntime.cloud-options.test.tsx +59 -0
- package/src/useAdkRuntime.refetch.test.tsx +548 -4
- package/src/useAdkRuntime.replacement.test.tsx +718 -1
- package/src/useAdkRuntime.ts +169 -73
- package/src/useAdkRuntimeApproval.test.tsx +87 -1
- package/dist/raceWithAbortSignal.d.ts +0 -2
- package/dist/raceWithAbortSignal.d.ts.map +0 -1
- package/dist/raceWithAbortSignal.js +0 -45
- package/dist/raceWithAbortSignal.js.map +0 -1
- package/src/raceWithAbortSignal.test.ts +0 -73
- package/src/raceWithAbortSignal.ts +0 -48
package/README.md
CHANGED
|
@@ -16,14 +16,24 @@ The recommended setup proxies through your own API route:
|
|
|
16
16
|
// app/api/adk/route.ts
|
|
17
17
|
import { createAdkApiRoute } from "@assistant-ui/react-google-adk/server";
|
|
18
18
|
import { runner } from "./agent";
|
|
19
|
+
import { requireUser } from "./auth"; // Your authentication helper
|
|
19
20
|
|
|
20
21
|
export const POST = createAdkApiRoute({
|
|
21
22
|
runner,
|
|
22
|
-
userId:
|
|
23
|
-
sessionId: (
|
|
23
|
+
userId: async (req) => (await requireUser(req)).id,
|
|
24
|
+
sessionId: (_req, clientSessionId) => {
|
|
25
|
+
if (!clientSessionId) throw new Error("Missing ADK session ID");
|
|
26
|
+
return clientSessionId;
|
|
27
|
+
},
|
|
24
28
|
});
|
|
25
29
|
```
|
|
26
30
|
|
|
31
|
+
`createAdkStream` sends its initialized thread ID to the route. Resolve
|
|
32
|
+
`userId` from authentication before accepting that identifier; a client-sent
|
|
33
|
+
session ID is not proof that the caller owns the session. The route creates a
|
|
34
|
+
missing ADK session before the first run when the runner exposes `appName` and
|
|
35
|
+
`sessionService`.
|
|
36
|
+
|
|
27
37
|
```tsx
|
|
28
38
|
// client component
|
|
29
39
|
import { useAdkRuntime, createAdkStream } from "@assistant-ui/react-google-adk";
|
package/dist/AdkClient.d.ts
CHANGED
|
@@ -23,6 +23,10 @@ export type CreateAdkStreamOptions = {
|
|
|
23
23
|
* Can be a static object or an async function for dynamic auth tokens.
|
|
24
24
|
*/
|
|
25
25
|
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>) | undefined;
|
|
26
|
+
/** Maximum UTF-16 code units accepted in one SSE line. Defaults to 16 MiB. */
|
|
27
|
+
maxStreamLineLength?: number | undefined;
|
|
28
|
+
/** Maximum UTF-16 code units retained across one SSE event. Defaults to 16 MiB. */
|
|
29
|
+
maxStreamEventLength?: number | undefined;
|
|
26
30
|
};
|
|
27
31
|
/**
|
|
28
32
|
* Creates an `AdkStreamCallback` that connects to an ADK endpoint.
|
package/dist/AdkClient.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkClient.d.ts","sourceRoot":"","sources":["../src/AdkClient.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAIV,iBAAiB,EAClB,mBAAgB;AAEjB,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B;;;OAGG;IACH,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"AdkClient.d.ts","sourceRoot":"","sources":["../src/AdkClient.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAIV,iBAAiB,EAClB,mBAAgB;AAEjB,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B;;;OAGG;IACH,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChE,SAAS,CAAC;IAEd,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzC,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,iBAAiB,CAuDnB"}
|
package/dist/AdkClient.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { contentToParts } from "./contentToParts.js";
|
|
2
2
|
import { parseAdkEventValue } from "./parseAdkEvent.js";
|
|
3
|
-
import { raceWithAbortSignal } from "./raceWithAbortSignal.js";
|
|
4
3
|
import { toAdkFunctionResponse } from "./toAdkFunctionResponse.js";
|
|
5
4
|
import { trimTrailingSlashes } from "./trimTrailingSlashes.js";
|
|
6
5
|
import { SSEEventDecoder } from "assistant-stream/utils";
|
|
6
|
+
import { raceWithAbortSignal } from "@assistant-ui/core/internal";
|
|
7
7
|
//#region src/AdkClient.ts
|
|
8
8
|
/**
|
|
9
9
|
* Creates an `AdkStreamCallback` that connects to an ADK endpoint.
|
|
@@ -43,7 +43,8 @@ function createAdkStream(options) {
|
|
|
43
43
|
};
|
|
44
44
|
} else {
|
|
45
45
|
url = options.api;
|
|
46
|
-
|
|
46
|
+
const { remoteId, externalId } = await config.initialize();
|
|
47
|
+
body = messagesToProxyBody(messages, config, externalId ?? remoteId);
|
|
47
48
|
}
|
|
48
49
|
const response = await fetch(url, {
|
|
49
50
|
method: "POST",
|
|
@@ -56,7 +57,7 @@ function createAdkStream(options) {
|
|
|
56
57
|
});
|
|
57
58
|
if (!response.ok) throw new Error(`ADK request failed: ${response.status} ${response.statusText}`);
|
|
58
59
|
validateEventStreamContentType(response);
|
|
59
|
-
yield* parseSSEResponse(response);
|
|
60
|
+
yield* parseSSEResponse(response, options);
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
function validateEventStreamContentType(response) {
|
|
@@ -111,8 +112,8 @@ function messagesToContent(messages) {
|
|
|
111
112
|
* Converts AdkMessage[] into the proxy request body format
|
|
112
113
|
* (compatible with `parseAdkRequest`).
|
|
113
114
|
*/
|
|
114
|
-
function messagesToProxyBody(messages, config) {
|
|
115
|
-
const body = {};
|
|
115
|
+
function messagesToProxyBody(messages, config, sessionId) {
|
|
116
|
+
const body = { sessionId };
|
|
116
117
|
if (config.runConfig != null) body.runConfig = config.runConfig;
|
|
117
118
|
if (config.checkpointId != null) body.checkpointId = config.checkpointId;
|
|
118
119
|
if (config.stateDelta != null) body.stateDelta = config.stateDelta;
|
|
@@ -144,13 +145,17 @@ function messagesToProxyBody(messages, config) {
|
|
|
144
145
|
body.parts = messagesToContent(messages).parts;
|
|
145
146
|
return body;
|
|
146
147
|
}
|
|
147
|
-
async function* parseSSEResponse(response) {
|
|
148
|
+
async function* parseSSEResponse(response, options) {
|
|
148
149
|
if (!response.body) throw new Error("Expected ADK stream response body, received no body");
|
|
149
150
|
const reader = response.body.getReader();
|
|
150
151
|
const decoder = new TextDecoder();
|
|
151
|
-
const sseDecoder = new SSEEventDecoder({ trailing: "dispatch" });
|
|
152
152
|
let shouldCancel = true;
|
|
153
153
|
try {
|
|
154
|
+
const sseDecoder = new SSEEventDecoder({
|
|
155
|
+
trailing: "dispatch",
|
|
156
|
+
maxLineLength: options.maxStreamLineLength,
|
|
157
|
+
maxEventLength: options.maxStreamEventLength
|
|
158
|
+
});
|
|
154
159
|
while (true) {
|
|
155
160
|
let result;
|
|
156
161
|
try {
|
package/dist/AdkClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkClient.js","names":[],"sources":["../src/AdkClient.ts"],"sourcesContent":["import { SSEEventDecoder } from \"assistant-stream/utils\";\nimport { contentToParts } from \"./contentToParts\";\nimport { parseAdkEventValue } from \"./parseAdkEvent\";\nimport { raceWithAbortSignal } from \"./raceWithAbortSignal\";\nimport { toAdkFunctionResponse } from \"./toAdkFunctionResponse\";\nimport { trimTrailingSlashes } from \"./trimTrailingSlashes\";\nimport type {\n AdkEvent,\n AdkEventPart,\n AdkMessage,\n AdkStreamCallback,\n} from \"./types\";\n\nexport type CreateAdkStreamOptions = {\n /**\n * URL to POST to. Either a proxy route (e.g. \"/api/adk\") or\n * an ADK server base URL (e.g. \"http://localhost:8000\").\n *\n * When `appName` and `userId` are provided, POSTs to `${api}/run_sse`\n * in ADK-native format. Otherwise POSTs directly to `api` in proxy format\n * (compatible with `parseAdkRequest`).\n */\n api: string;\n\n /**\n * ADK application name. When provided along with `userId`,\n * enables direct connection to an ADK server.\n */\n appName?: string | undefined;\n\n /**\n * ADK user ID. Required when `appName` is provided.\n */\n userId?: string | undefined;\n\n /**\n * Extra headers to send with every request.\n * Can be a static object or an async function for dynamic auth tokens.\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n};\n\n/**\n * Creates an `AdkStreamCallback` that connects to an ADK endpoint.\n *\n * @example Proxy mode (with a Next.js API route)\n * ```ts\n * const stream = createAdkStream({ api: \"/api/adk\" });\n * ```\n *\n * @example Direct mode (connecting to ADK server)\n * ```ts\n * const stream = createAdkStream({\n * api: \"http://localhost:8000\",\n * appName: \"my-app\",\n * userId: \"user-1\",\n * });\n * ```\n */\nexport function createAdkStream(\n options: CreateAdkStreamOptions,\n): AdkStreamCallback {\n if (options.appName === \"\") {\n throw new Error(\n 'createAdkStream direct mode requires a non-empty \"appName\".',\n );\n }\n\n const isDirect = options.appName != null;\n if (isDirect && (options.userId == null || options.userId === \"\")) {\n throw new Error(\n 'createAdkStream direct mode requires \"userId\" when \"appName\" is provided.',\n );\n }\n\n return async function* (messages, config) {\n const headers = await resolveHeaders(options.headers, config.abortSignal);\n\n let url: string;\n let body: unknown;\n\n if (isDirect) {\n // Direct mode: POST to ADK server's /run_sse\n url = `${trimTrailingSlashes(options.api)}/run_sse`;\n const { externalId } = await config.initialize();\n body = {\n appName: options.appName,\n userId: options.userId,\n sessionId: externalId,\n newMessage: messagesToContent(messages),\n streaming: true,\n ...(config.stateDelta != null && { stateDelta: config.stateDelta }),\n };\n } else {\n // Proxy mode: POST in parseAdkRequest-compatible format\n url = options.api;\n body = messagesToProxyBody(messages, config);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify(body),\n signal: config.abortSignal,\n });\n\n if (!response.ok) {\n throw new Error(\n `ADK request failed: ${response.status} ${response.statusText}`,\n );\n }\n\n validateEventStreamContentType(response);\n yield* parseSSEResponse(response);\n };\n}\n\n// ── Internal helpers ──\n\nfunction validateEventStreamContentType(response: Response): void {\n const contentType = response.headers.get(\"Content-Type\");\n const mediaType = contentType?.split(\";\", 1)[0]?.trim().toLowerCase();\n if (mediaType !== \"text/event-stream\") {\n const received = contentType\n ? `\"${contentType}\"`\n : \"no Content-Type header\";\n void response.body?.cancel().catch(() => undefined);\n throw new Error(\n `Expected ADK stream response Content-Type \"text/event-stream\", received ${received}`,\n );\n }\n}\n\nfunction parseAdkEvent(data: string): AdkEvent {\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n throw new Error(\"Invalid ADK stream event: expected valid JSON.\");\n }\n\n return parseAdkEventValue(value, \"Invalid ADK stream event\");\n}\n\nasync function resolveHeaders(\n headers:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined,\n signal?: AbortSignal,\n): Promise<Record<string, string>> {\n if (!headers) return {};\n if (typeof headers === \"function\") {\n return await raceWithAbortSignal(signal, headers);\n }\n return headers;\n}\n\n/**\n * Converts AdkMessage[] (new messages) into ADK Content format\n * for the direct `/run_sse` endpoint.\n */\nfunction messagesToContent(messages: AdkMessage[]): {\n role: string;\n parts: AdkEventPart[];\n} {\n const parts: AdkEventPart[] = [];\n\n for (const msg of messages) {\n if (msg.type === \"human\") {\n for (const part of contentToParts(msg.content)) {\n parts.push(part);\n }\n } else if (msg.type === \"tool\") {\n let response: unknown;\n try {\n response = JSON.parse(msg.content);\n } catch {\n response = msg.content;\n }\n parts.push({\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response: toAdkFunctionResponse(response, msg.status === \"error\"),\n },\n });\n }\n }\n\n if (parts.length === 0) {\n parts.push({ text: \"\" });\n }\n\n return { role: \"user\", parts };\n}\n\n/**\n * Converts AdkMessage[] into the proxy request body format\n * (compatible with `parseAdkRequest`).\n */\nfunction messagesToProxyBody(\n messages: AdkMessage[],\n config: {\n runConfig?: unknown;\n checkpointId?: string | undefined;\n stateDelta?: Record<string, unknown> | undefined;\n },\n): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n\n if (config.runConfig != null) body.runConfig = config.runConfig;\n if (config.checkpointId != null) body.checkpointId = config.checkpointId;\n if (config.stateDelta != null) body.stateDelta = config.stateDelta;\n\n // Check if there's a tool result\n const toolMsg = messages.find((m) => m.type === \"tool\");\n if (toolMsg && toolMsg.type === \"tool\") {\n // If there are also other messages (e.g. cancellations), send as parts\n if (messages.length > 1) {\n body.parts = messagesToContent(messages).parts;\n return body;\n }\n\n let result: unknown;\n try {\n result = JSON.parse(toolMsg.content);\n } catch {\n result = toolMsg.content;\n }\n body.type = \"tool-result\";\n body.toolCallId = toolMsg.tool_call_id;\n body.toolName = toolMsg.name;\n body.result = result;\n body.isError = toolMsg.status === \"error\";\n return body;\n }\n\n // Human message(s) - possibly with cancellation tool results prepended\n if (messages.length === 1 && messages[0]!.type === \"human\") {\n const msg = messages[0]!;\n if (typeof msg.content === \"string\") {\n body.message = msg.content;\n } else {\n body.parts = contentToParts(msg.content);\n }\n return body;\n }\n\n // Multiple messages (e.g. cancellations + human): send as parts array\n body.parts = messagesToContent(messages).parts;\n return body;\n}\n\nasync function* parseSSEResponse(response: Response): AsyncGenerator<AdkEvent> {\n if (!response.body) {\n throw new Error(\"Expected ADK stream response body, received no body\");\n }\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n const sseDecoder = new SSEEventDecoder({ trailing: \"dispatch\" });\n\n let shouldCancel = true;\n try {\n while (true) {\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch (error) {\n shouldCancel = false;\n throw error;\n }\n\n const { done, value } = result;\n if (done) {\n shouldCancel = false;\n for (const event of sseDecoder.push(decoder.decode())) {\n yield parseAdkEvent(event.data);\n }\n break;\n }\n\n for (const event of sseDecoder.push(\n decoder.decode(value, { stream: true }),\n )) {\n yield parseAdkEvent(event.data);\n }\n }\n\n const trailing = sseDecoder.flush();\n if (trailing !== null) yield parseAdkEvent(trailing.data);\n } finally {\n try {\n if (shouldCancel) await reader.cancel().catch(() => undefined);\n } finally {\n reader.releaseLock();\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdkClient.js","names":[],"sources":["../src/AdkClient.ts"],"sourcesContent":["import { SSEEventDecoder } from \"assistant-stream/utils\";\nimport { raceWithAbortSignal } from \"@assistant-ui/core/internal\";\nimport { contentToParts } from \"./contentToParts\";\nimport { parseAdkEventValue } from \"./parseAdkEvent\";\nimport { toAdkFunctionResponse } from \"./toAdkFunctionResponse\";\nimport { trimTrailingSlashes } from \"./trimTrailingSlashes\";\nimport type {\n AdkEvent,\n AdkEventPart,\n AdkMessage,\n AdkStreamCallback,\n} from \"./types\";\n\nexport type CreateAdkStreamOptions = {\n /**\n * URL to POST to. Either a proxy route (e.g. \"/api/adk\") or\n * an ADK server base URL (e.g. \"http://localhost:8000\").\n *\n * When `appName` and `userId` are provided, POSTs to `${api}/run_sse`\n * in ADK-native format. Otherwise POSTs directly to `api` in proxy format\n * (compatible with `parseAdkRequest`).\n */\n api: string;\n\n /**\n * ADK application name. When provided along with `userId`,\n * enables direct connection to an ADK server.\n */\n appName?: string | undefined;\n\n /**\n * ADK user ID. Required when `appName` is provided.\n */\n userId?: string | undefined;\n\n /**\n * Extra headers to send with every request.\n * Can be a static object or an async function for dynamic auth tokens.\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n\n /** Maximum UTF-16 code units accepted in one SSE line. Defaults to 16 MiB. */\n maxStreamLineLength?: number | undefined;\n\n /** Maximum UTF-16 code units retained across one SSE event. Defaults to 16 MiB. */\n maxStreamEventLength?: number | undefined;\n};\n\n/**\n * Creates an `AdkStreamCallback` that connects to an ADK endpoint.\n *\n * @example Proxy mode (with a Next.js API route)\n * ```ts\n * const stream = createAdkStream({ api: \"/api/adk\" });\n * ```\n *\n * @example Direct mode (connecting to ADK server)\n * ```ts\n * const stream = createAdkStream({\n * api: \"http://localhost:8000\",\n * appName: \"my-app\",\n * userId: \"user-1\",\n * });\n * ```\n */\nexport function createAdkStream(\n options: CreateAdkStreamOptions,\n): AdkStreamCallback {\n if (options.appName === \"\") {\n throw new Error(\n 'createAdkStream direct mode requires a non-empty \"appName\".',\n );\n }\n\n const isDirect = options.appName != null;\n if (isDirect && (options.userId == null || options.userId === \"\")) {\n throw new Error(\n 'createAdkStream direct mode requires \"userId\" when \"appName\" is provided.',\n );\n }\n\n return async function* (messages, config) {\n const headers = await resolveHeaders(options.headers, config.abortSignal);\n\n let url: string;\n let body: unknown;\n\n if (isDirect) {\n // Direct mode: POST to ADK server's /run_sse\n url = `${trimTrailingSlashes(options.api)}/run_sse`;\n const { externalId } = await config.initialize();\n body = {\n appName: options.appName,\n userId: options.userId,\n sessionId: externalId,\n newMessage: messagesToContent(messages),\n streaming: true,\n ...(config.stateDelta != null && { stateDelta: config.stateDelta }),\n };\n } else {\n // Proxy mode: POST in parseAdkRequest-compatible format\n url = options.api;\n const { remoteId, externalId } = await config.initialize();\n body = messagesToProxyBody(messages, config, externalId ?? remoteId);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify(body),\n signal: config.abortSignal,\n });\n\n if (!response.ok) {\n throw new Error(\n `ADK request failed: ${response.status} ${response.statusText}`,\n );\n }\n\n validateEventStreamContentType(response);\n yield* parseSSEResponse(response, options);\n };\n}\n\n// ── Internal helpers ──\n\nfunction validateEventStreamContentType(response: Response): void {\n const contentType = response.headers.get(\"Content-Type\");\n const mediaType = contentType?.split(\";\", 1)[0]?.trim().toLowerCase();\n if (mediaType !== \"text/event-stream\") {\n const received = contentType\n ? `\"${contentType}\"`\n : \"no Content-Type header\";\n void response.body?.cancel().catch(() => undefined);\n throw new Error(\n `Expected ADK stream response Content-Type \"text/event-stream\", received ${received}`,\n );\n }\n}\n\nfunction parseAdkEvent(data: string): AdkEvent {\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n throw new Error(\"Invalid ADK stream event: expected valid JSON.\");\n }\n\n return parseAdkEventValue(value, \"Invalid ADK stream event\");\n}\n\nasync function resolveHeaders(\n headers:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined,\n signal?: AbortSignal,\n): Promise<Record<string, string>> {\n if (!headers) return {};\n if (typeof headers === \"function\") {\n return await raceWithAbortSignal(signal, headers);\n }\n return headers;\n}\n\n/**\n * Converts AdkMessage[] (new messages) into ADK Content format\n * for the direct `/run_sse` endpoint.\n */\nfunction messagesToContent(messages: AdkMessage[]): {\n role: string;\n parts: AdkEventPart[];\n} {\n const parts: AdkEventPart[] = [];\n\n for (const msg of messages) {\n if (msg.type === \"human\") {\n for (const part of contentToParts(msg.content)) {\n parts.push(part);\n }\n } else if (msg.type === \"tool\") {\n let response: unknown;\n try {\n response = JSON.parse(msg.content);\n } catch {\n response = msg.content;\n }\n parts.push({\n functionResponse: {\n name: msg.name,\n id: msg.tool_call_id,\n response: toAdkFunctionResponse(response, msg.status === \"error\"),\n },\n });\n }\n }\n\n if (parts.length === 0) {\n parts.push({ text: \"\" });\n }\n\n return { role: \"user\", parts };\n}\n\n/**\n * Converts AdkMessage[] into the proxy request body format\n * (compatible with `parseAdkRequest`).\n */\nfunction messagesToProxyBody(\n messages: AdkMessage[],\n config: {\n runConfig?: unknown;\n checkpointId?: string | undefined;\n stateDelta?: Record<string, unknown> | undefined;\n },\n sessionId: string,\n): Record<string, unknown> {\n const body: Record<string, unknown> = { sessionId };\n\n if (config.runConfig != null) body.runConfig = config.runConfig;\n if (config.checkpointId != null) body.checkpointId = config.checkpointId;\n if (config.stateDelta != null) body.stateDelta = config.stateDelta;\n\n // Check if there's a tool result\n const toolMsg = messages.find((m) => m.type === \"tool\");\n if (toolMsg && toolMsg.type === \"tool\") {\n // If there are also other messages (e.g. cancellations), send as parts\n if (messages.length > 1) {\n body.parts = messagesToContent(messages).parts;\n return body;\n }\n\n let result: unknown;\n try {\n result = JSON.parse(toolMsg.content);\n } catch {\n result = toolMsg.content;\n }\n body.type = \"tool-result\";\n body.toolCallId = toolMsg.tool_call_id;\n body.toolName = toolMsg.name;\n body.result = result;\n body.isError = toolMsg.status === \"error\";\n return body;\n }\n\n // Human message(s) - possibly with cancellation tool results prepended\n if (messages.length === 1 && messages[0]!.type === \"human\") {\n const msg = messages[0]!;\n if (typeof msg.content === \"string\") {\n body.message = msg.content;\n } else {\n body.parts = contentToParts(msg.content);\n }\n return body;\n }\n\n // Multiple messages (e.g. cancellations + human): send as parts array\n body.parts = messagesToContent(messages).parts;\n return body;\n}\n\nasync function* parseSSEResponse(\n response: Response,\n options: Pick<\n CreateAdkStreamOptions,\n \"maxStreamLineLength\" | \"maxStreamEventLength\"\n >,\n): AsyncGenerator<AdkEvent> {\n if (!response.body) {\n throw new Error(\"Expected ADK stream response body, received no body\");\n }\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n let shouldCancel = true;\n try {\n const sseDecoder = new SSEEventDecoder({\n trailing: \"dispatch\",\n maxLineLength: options.maxStreamLineLength,\n maxEventLength: options.maxStreamEventLength,\n });\n while (true) {\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch (error) {\n shouldCancel = false;\n throw error;\n }\n\n const { done, value } = result;\n if (done) {\n shouldCancel = false;\n for (const event of sseDecoder.push(decoder.decode())) {\n yield parseAdkEvent(event.data);\n }\n break;\n }\n\n for (const event of sseDecoder.push(\n decoder.decode(value, { stream: true }),\n )) {\n yield parseAdkEvent(event.data);\n }\n }\n\n const trailing = sseDecoder.flush();\n if (trailing !== null) yield parseAdkEvent(trailing.data);\n } finally {\n try {\n if (shouldCancel) await reader.cancel().catch(() => undefined);\n } finally {\n reader.releaseLock();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkSessionAdapter.d.ts","sourceRoot":"","sources":["../src/AdkSessionAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EAGxB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"AdkSessionAdapter.d.ts","sourceRoot":"","sources":["../src/AdkSessionAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EAGxB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EAAc,iBAAiB,EAAE,mBAAgB;AAG7D,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChE,SAAS,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC5D,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IAC1E,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,uBAAuB,CAAC;IACjC,IAAI,EAAE,CACJ,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,KAC3C,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChC,SAAS,EAAE;QACT,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,IAAI,EAAE,CACJ,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC,eAAe,CAAC,CAAC;QAC9B,YAAY,EAAE,CACZ,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,KACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACvB,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACpE,CAAC;CACH,CAAC;AA+IF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,uBAAuB,CAiMzB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { parseAdkEventValue } from "./parseAdkEvent.js";
|
|
2
|
-
import { raceWithAbortSignal } from "./raceWithAbortSignal.js";
|
|
3
2
|
import { trimTrailingSlashes } from "./trimTrailingSlashes.js";
|
|
4
3
|
import { normalizeAdkPart } from "./normalizeAdkPart.js";
|
|
5
4
|
import { AdkEventAccumulator } from "./AdkEventAccumulator.js";
|
|
5
|
+
import { raceWithAbortSignal } from "@assistant-ui/core/internal";
|
|
6
6
|
//#region src/AdkSessionAdapter.ts
|
|
7
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
8
|
const isAdkSessionResponse = (value) => {
|
|
9
|
-
if (!isRecord(value)) return false;
|
|
9
|
+
if (!isRecord$1(value)) return false;
|
|
10
10
|
const id = value.id;
|
|
11
11
|
return typeof id === "string" && id.length > 0;
|
|
12
12
|
};
|
|
@@ -25,7 +25,7 @@ const parseAdkArtifactListResponse = (value) => {
|
|
|
25
25
|
if (!Array.isArray(value)) throw new Error("Invalid ADK artifact list response: expected an array of artifact names.");
|
|
26
26
|
return value.map((artifact, index) => {
|
|
27
27
|
if (typeof artifact === "string" && artifact.length > 0) return artifact;
|
|
28
|
-
if (isRecord(artifact)) {
|
|
28
|
+
if (isRecord$1(artifact)) {
|
|
29
29
|
const filename = artifact.filename;
|
|
30
30
|
if (typeof filename === "string" && filename.length > 0) return filename;
|
|
31
31
|
}
|
|
@@ -33,13 +33,13 @@ const parseAdkArtifactListResponse = (value) => {
|
|
|
33
33
|
});
|
|
34
34
|
};
|
|
35
35
|
const parseAdkArtifactResponse = (value) => {
|
|
36
|
-
if (!isRecord(value)) throw new Error("Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".");
|
|
36
|
+
if (!isRecord$1(value)) throw new Error("Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".");
|
|
37
37
|
const normalizedValue = normalizeAdkPart(value);
|
|
38
38
|
const { text, inlineData, fileData } = normalizedValue;
|
|
39
39
|
if (text === void 0 && inlineData === void 0 && fileData === void 0) throw new Error("Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".");
|
|
40
40
|
if (text !== void 0 && typeof text !== "string") throw new Error("Invalid ADK artifact load response: \"text\" must be a string when present.");
|
|
41
|
-
if (inlineData !== void 0 && (!isRecord(inlineData) || typeof inlineData.mimeType !== "string" || typeof inlineData.data !== "string")) throw new Error("Invalid ADK artifact load response: \"inlineData\" must contain string \"mimeType\" and \"data\" fields.");
|
|
42
|
-
if (fileData !== void 0 && (!isRecord(fileData) || typeof fileData.fileUri !== "string" || fileData.mimeType !== void 0 && typeof fileData.mimeType !== "string")) throw new Error("Invalid ADK artifact load response: \"fileData\" must contain a string \"fileUri\" and an optional string \"mimeType\" field.");
|
|
41
|
+
if (inlineData !== void 0 && (!isRecord$1(inlineData) || typeof inlineData.mimeType !== "string" || typeof inlineData.data !== "string")) throw new Error("Invalid ADK artifact load response: \"inlineData\" must contain string \"mimeType\" and \"data\" fields.");
|
|
42
|
+
if (fileData !== void 0 && (!isRecord$1(fileData) || typeof fileData.fileUri !== "string" || fileData.mimeType !== void 0 && typeof fileData.mimeType !== "string")) throw new Error("Invalid ADK artifact load response: \"fileData\" must contain a string \"fileUri\" and an optional string \"mimeType\" field.");
|
|
43
43
|
return normalizedValue;
|
|
44
44
|
};
|
|
45
45
|
const parseAdkArtifactVersionsResponse = (value) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkSessionAdapter.js","names":[],"sources":["../src/AdkSessionAdapter.ts"],"sourcesContent":["import type { AssistantStream, AssistantStreamChunk } from \"assistant-stream\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n} from \"@assistant-ui/core\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { normalizeAdkPart } from \"./normalizeAdkPart\";\nimport { parseAdkEventValue } from \"./parseAdkEvent\";\nimport type { AdkMessage, AdkThreadSnapshot } from \"./types\";\nimport { trimTrailingSlashes } from \"./trimTrailingSlashes\";\nimport { raceWithAbortSignal } from \"./raceWithAbortSignal\";\n\nexport type AdkSessionAdapterOptions = {\n /**\n * ADK server base URL (e.g. \"http://localhost:8000\").\n */\n apiUrl: string;\n\n /**\n * ADK application name.\n */\n appName: string;\n\n /**\n * ADK user ID.\n */\n userId: string;\n\n /**\n * Extra headers for API requests.\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n};\n\nexport type AdkArtifactData = {\n inlineData?: { mimeType: string; data: string } | undefined;\n fileData?: { fileUri: string; mimeType?: string | undefined } | undefined;\n text?: string | undefined;\n};\n\ntype AdkSessionAdapterResult = {\n adapter: RemoteThreadListAdapter;\n load: (\n sessionId: string,\n options?: { signal?: AbortSignal | undefined },\n ) => Promise<AdkThreadSnapshot>;\n artifacts: {\n list: (sessionId: string) => Promise<string[]>;\n load: (\n sessionId: string,\n artifactName: string,\n version?: number,\n ) => Promise<AdkArtifactData>;\n listVersions: (\n sessionId: string,\n artifactName: string,\n ) => Promise<number[]>;\n delete: (sessionId: string, artifactName: string) => Promise<void>;\n };\n};\n\ntype AdkSessionResponse = {\n id: string;\n events?: unknown;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isAdkSessionResponse = (value: unknown): value is AdkSessionResponse => {\n if (!isRecord(value)) return false;\n\n const id = value.id;\n return typeof id === \"string\" && id.length > 0;\n};\n\nconst parseAdkSessionResponse = (\n value: unknown,\n operation: \"create\" | \"fetch\" | \"load\",\n): AdkSessionResponse => {\n if (!isAdkSessionResponse(value)) {\n throw new Error(\n `Invalid ADK session ${operation} response: expected an object with a non-empty string \"id\".`,\n );\n }\n return value;\n};\n\nconst parseAdkSessionListResponse = (value: unknown): AdkSessionResponse[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK session list response: expected an array of sessions.\",\n );\n }\n\n return value.map((session, index) => {\n if (!isAdkSessionResponse(session)) {\n throw new Error(\n `Invalid ADK session list response: session at index ${index} must have a non-empty string \"id\".`,\n );\n }\n return session;\n });\n};\n\nconst parseAdkArtifactListResponse = (value: unknown): string[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK artifact list response: expected an array of artifact names.\",\n );\n }\n\n return value.map((artifact, index) => {\n if (typeof artifact === \"string\" && artifact.length > 0) {\n return artifact;\n }\n\n if (isRecord(artifact)) {\n const filename = artifact.filename;\n if (typeof filename === \"string\" && filename.length > 0) {\n return filename;\n }\n }\n\n throw new Error(\n `Invalid ADK artifact list response: artifact at index ${index} must be a non-empty string or an object with a non-empty string \"filename\".`,\n );\n });\n};\n\nconst parseAdkArtifactResponse = (value: unknown): AdkArtifactData => {\n if (!isRecord(value)) {\n throw new Error(\n 'Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".',\n );\n }\n\n const normalizedValue = normalizeAdkPart(value);\n const { text, inlineData, fileData } = normalizedValue;\n if (\n text === undefined &&\n inlineData === undefined &&\n fileData === undefined\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".',\n );\n }\n\n if (text !== undefined && typeof text !== \"string\") {\n throw new Error(\n 'Invalid ADK artifact load response: \"text\" must be a string when present.',\n );\n }\n\n if (\n inlineData !== undefined &&\n (!isRecord(inlineData) ||\n typeof inlineData.mimeType !== \"string\" ||\n typeof inlineData.data !== \"string\")\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: \"inlineData\" must contain string \"mimeType\" and \"data\" fields.',\n );\n }\n\n if (\n fileData !== undefined &&\n (!isRecord(fileData) ||\n typeof fileData.fileUri !== \"string\" ||\n (fileData.mimeType !== undefined &&\n typeof fileData.mimeType !== \"string\"))\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: \"fileData\" must contain a string \"fileUri\" and an optional string \"mimeType\" field.',\n );\n }\n\n return normalizedValue as AdkArtifactData;\n};\n\nconst parseAdkArtifactVersionsResponse = (value: unknown): number[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK artifact versions response: expected an array of version numbers.\",\n );\n }\n\n return value.map((version, index) => {\n if (\n typeof version !== \"number\" ||\n !Number.isInteger(version) ||\n version < 0\n ) {\n throw new Error(\n `Invalid ADK artifact versions response: version at index ${index} must be a non-negative integer.`,\n );\n }\n return version;\n });\n};\n\n/**\n * Creates a `RemoteThreadListAdapter` backed by ADK's session REST API,\n * plus a `load` function that reconstructs messages from session events.\n *\n * @example\n * ```ts\n * const { adapter, load } = createAdkSessionAdapter({\n * apiUrl: \"http://localhost:8000\",\n * appName: \"my-app\",\n * userId: \"user-1\",\n * });\n *\n * const runtime = useAdkRuntime({\n * stream: createAdkStream({ ... }),\n * sessionAdapter: adapter,\n * load,\n * });\n * ```\n */\nexport function createAdkSessionAdapter(\n options: AdkSessionAdapterOptions,\n): AdkSessionAdapterResult {\n const { apiUrl, appName, userId } = options;\n const normalizedApiUrl = trimTrailingSlashes(apiUrl);\n const baseUrl = `${normalizedApiUrl}/apps/${encodeURIComponent(appName)}/users/${encodeURIComponent(userId)}/sessions`;\n\n const getHeaders = async (\n signal?: AbortSignal,\n ): Promise<Record<string, string>> => {\n if (!options.headers) return {};\n if (typeof options.headers === \"function\") {\n return await raceWithAbortSignal(signal, options.headers);\n }\n return options.headers;\n };\n\n const adapter: RemoteThreadListAdapter = {\n async list(): Promise<RemoteThreadListResponse> {\n const headers = await getHeaders();\n const res = await fetch(baseUrl, { headers });\n if (!res.ok) {\n throw new Error(`Failed to list sessions: ${res.status}`);\n }\n const data = parseAdkSessionListResponse(await res.json());\n\n const threads: RemoteThreadMetadata[] = data.map((session) => ({\n status: \"regular\" as const,\n remoteId: session.id,\n externalId: session.id,\n title: undefined,\n }));\n\n return { threads };\n },\n\n async initialize(\n _threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const headers = await getHeaders();\n const res = await fetch(baseUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify({}),\n });\n if (!res.ok) {\n throw new Error(`Failed to create session: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"create\");\n return { remoteId: session.id, externalId: session.id };\n },\n\n async delete(remoteId: string): Promise<void> {\n const headers = await getHeaders();\n const res = await fetch(`${baseUrl}/${encodeURIComponent(remoteId)}`, {\n method: \"DELETE\",\n headers,\n });\n if (!res.ok && res.status !== 404) {\n throw new Error(`Failed to delete session: ${res.status}`);\n }\n },\n\n async rename(): Promise<void> {\n // ADK sessions don't support titles\n },\n\n async archive(): Promise<void> {\n // ADK sessions don't support archiving\n },\n\n async unarchive(): Promise<void> {\n // ADK sessions don't support archiving\n },\n\n generateTitle(): Promise<AssistantStream> {\n // Title generation not supported without assistant-cloud\n return Promise.resolve(\n new ReadableStream<AssistantStreamChunk>({\n start(controller) {\n controller.close();\n },\n }),\n );\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const headers = await getHeaders();\n const res = await fetch(`${baseUrl}/${encodeURIComponent(threadId)}`, {\n headers,\n });\n if (!res.ok) {\n throw new Error(`Session not found: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"fetch\");\n return {\n status: \"regular\",\n remoteId: session.id,\n externalId: session.id,\n title: undefined,\n };\n },\n };\n\n const load = async (\n sessionId: string,\n options?: { signal?: AbortSignal | undefined },\n ): Promise<AdkThreadSnapshot> => {\n const headers = await getHeaders(options?.signal);\n const res = await fetch(`${baseUrl}/${encodeURIComponent(sessionId)}`, {\n headers,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n if (!res.ok) {\n throw new Error(`Failed to load session: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"load\");\n\n if (session.events !== undefined && !Array.isArray(session.events)) {\n throw new Error(\n 'Invalid ADK session load response: expected \"events\" to be an array when present.',\n );\n }\n\n // Events carry ordered state and tool transitions, so partial replay can\n // produce a plausible but incorrect thread.\n const events = session.events?.map((event, index) =>\n parseAdkEventValue(event, `Invalid ADK session event at index ${index}`),\n );\n\n if (!events?.length) {\n return { messages: [] };\n }\n\n const accumulator = new AdkEventAccumulator();\n let messages: AdkMessage[] = [];\n for (const event of events) {\n messages = accumulator.processEvent(event);\n }\n // The per-turn state rides along, so a refetch can swap the thread over in\n // one commit instead of reconstructing it from the messages alone.\n return {\n messages,\n longRunningToolIds: accumulator.getLongRunningToolIds(),\n toolConfirmations: accumulator.getToolConfirmations(),\n authRequests: accumulator.getAuthRequests(),\n escalated: accumulator.isEscalated(),\n messageMetadata: accumulator.getMessageMetadata(),\n stateDelta: accumulator.getStateDelta(),\n artifactDelta: accumulator.getArtifactDelta(),\n agentInfo: accumulator.getAgentInfo(),\n };\n };\n\n const artifactBaseUrl = (sessionId: string) =>\n `${baseUrl}/${encodeURIComponent(sessionId)}/artifacts`;\n\n const artifacts: AdkSessionAdapterResult[\"artifacts\"] = {\n async list(sessionId) {\n const headers = await getHeaders();\n const res = await fetch(artifactBaseUrl(sessionId), { headers });\n if (!res.ok) throw new Error(`Failed to list artifacts: ${res.status}`);\n return parseAdkArtifactListResponse(await res.json());\n },\n\n async load(sessionId, artifactName, version?) {\n const headers = await getHeaders();\n let url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}`;\n if (version != null) url += `/versions/${version}`;\n const res = await fetch(url, { headers });\n if (!res.ok) throw new Error(`Failed to load artifact: ${res.status}`);\n return parseAdkArtifactResponse(await res.json());\n },\n\n async listVersions(sessionId, artifactName) {\n const headers = await getHeaders();\n const url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}/versions`;\n const res = await fetch(url, { headers });\n if (!res.ok) {\n throw new Error(`Failed to list artifact versions: ${res.status}`);\n }\n return parseAdkArtifactVersionsResponse(await res.json());\n },\n\n async delete(sessionId, artifactName) {\n const headers = await getHeaders();\n const url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}`;\n const res = await fetch(url, { method: \"DELETE\", headers });\n if (!res.ok && res.status !== 404) {\n throw new Error(`Failed to delete artifact: ${res.status}`);\n }\n },\n };\n\n return { adapter, load, artifacts };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdkSessionAdapter.js","names":["isRecord"],"sources":["../src/AdkSessionAdapter.ts"],"sourcesContent":["import type { AssistantStream, AssistantStreamChunk } from \"assistant-stream\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n} from \"@assistant-ui/core\";\nimport { raceWithAbortSignal } from \"@assistant-ui/core/internal\";\nimport { AdkEventAccumulator } from \"./AdkEventAccumulator\";\nimport { normalizeAdkPart } from \"./normalizeAdkPart\";\nimport { parseAdkEventValue } from \"./parseAdkEvent\";\nimport type { AdkMessage, AdkThreadSnapshot } from \"./types\";\nimport { trimTrailingSlashes } from \"./trimTrailingSlashes\";\n\nexport type AdkSessionAdapterOptions = {\n /**\n * ADK server base URL (e.g. \"http://localhost:8000\").\n */\n apiUrl: string;\n\n /**\n * ADK application name.\n */\n appName: string;\n\n /**\n * ADK user ID.\n */\n userId: string;\n\n /**\n * Extra headers for API requests.\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined;\n};\n\nexport type AdkArtifactData = {\n inlineData?: { mimeType: string; data: string } | undefined;\n fileData?: { fileUri: string; mimeType?: string | undefined } | undefined;\n text?: string | undefined;\n};\n\ntype AdkSessionAdapterResult = {\n adapter: RemoteThreadListAdapter;\n load: (\n sessionId: string,\n options?: { signal?: AbortSignal | undefined },\n ) => Promise<AdkThreadSnapshot>;\n artifacts: {\n list: (sessionId: string) => Promise<string[]>;\n load: (\n sessionId: string,\n artifactName: string,\n version?: number,\n ) => Promise<AdkArtifactData>;\n listVersions: (\n sessionId: string,\n artifactName: string,\n ) => Promise<number[]>;\n delete: (sessionId: string, artifactName: string) => Promise<void>;\n };\n};\n\ntype AdkSessionResponse = {\n id: string;\n events?: unknown;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isAdkSessionResponse = (value: unknown): value is AdkSessionResponse => {\n if (!isRecord(value)) return false;\n\n const id = value.id;\n return typeof id === \"string\" && id.length > 0;\n};\n\nconst parseAdkSessionResponse = (\n value: unknown,\n operation: \"create\" | \"fetch\" | \"load\",\n): AdkSessionResponse => {\n if (!isAdkSessionResponse(value)) {\n throw new Error(\n `Invalid ADK session ${operation} response: expected an object with a non-empty string \"id\".`,\n );\n }\n return value;\n};\n\nconst parseAdkSessionListResponse = (value: unknown): AdkSessionResponse[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK session list response: expected an array of sessions.\",\n );\n }\n\n return value.map((session, index) => {\n if (!isAdkSessionResponse(session)) {\n throw new Error(\n `Invalid ADK session list response: session at index ${index} must have a non-empty string \"id\".`,\n );\n }\n return session;\n });\n};\n\nconst parseAdkArtifactListResponse = (value: unknown): string[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK artifact list response: expected an array of artifact names.\",\n );\n }\n\n return value.map((artifact, index) => {\n if (typeof artifact === \"string\" && artifact.length > 0) {\n return artifact;\n }\n\n if (isRecord(artifact)) {\n const filename = artifact.filename;\n if (typeof filename === \"string\" && filename.length > 0) {\n return filename;\n }\n }\n\n throw new Error(\n `Invalid ADK artifact list response: artifact at index ${index} must be a non-empty string or an object with a non-empty string \"filename\".`,\n );\n });\n};\n\nconst parseAdkArtifactResponse = (value: unknown): AdkArtifactData => {\n if (!isRecord(value)) {\n throw new Error(\n 'Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".',\n );\n }\n\n const normalizedValue = normalizeAdkPart(value);\n const { text, inlineData, fileData } = normalizedValue;\n if (\n text === undefined &&\n inlineData === undefined &&\n fileData === undefined\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: expected an object containing \"text\", \"inlineData\", or \"fileData\".',\n );\n }\n\n if (text !== undefined && typeof text !== \"string\") {\n throw new Error(\n 'Invalid ADK artifact load response: \"text\" must be a string when present.',\n );\n }\n\n if (\n inlineData !== undefined &&\n (!isRecord(inlineData) ||\n typeof inlineData.mimeType !== \"string\" ||\n typeof inlineData.data !== \"string\")\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: \"inlineData\" must contain string \"mimeType\" and \"data\" fields.',\n );\n }\n\n if (\n fileData !== undefined &&\n (!isRecord(fileData) ||\n typeof fileData.fileUri !== \"string\" ||\n (fileData.mimeType !== undefined &&\n typeof fileData.mimeType !== \"string\"))\n ) {\n throw new Error(\n 'Invalid ADK artifact load response: \"fileData\" must contain a string \"fileUri\" and an optional string \"mimeType\" field.',\n );\n }\n\n return normalizedValue as AdkArtifactData;\n};\n\nconst parseAdkArtifactVersionsResponse = (value: unknown): number[] => {\n if (!Array.isArray(value)) {\n throw new Error(\n \"Invalid ADK artifact versions response: expected an array of version numbers.\",\n );\n }\n\n return value.map((version, index) => {\n if (\n typeof version !== \"number\" ||\n !Number.isInteger(version) ||\n version < 0\n ) {\n throw new Error(\n `Invalid ADK artifact versions response: version at index ${index} must be a non-negative integer.`,\n );\n }\n return version;\n });\n};\n\n/**\n * Creates a `RemoteThreadListAdapter` backed by ADK's session REST API,\n * plus a `load` function that reconstructs messages from session events.\n *\n * @example\n * ```ts\n * const { adapter, load } = createAdkSessionAdapter({\n * apiUrl: \"http://localhost:8000\",\n * appName: \"my-app\",\n * userId: \"user-1\",\n * });\n *\n * const runtime = useAdkRuntime({\n * stream: createAdkStream({ ... }),\n * sessionAdapter: adapter,\n * load,\n * });\n * ```\n */\nexport function createAdkSessionAdapter(\n options: AdkSessionAdapterOptions,\n): AdkSessionAdapterResult {\n const { apiUrl, appName, userId } = options;\n const normalizedApiUrl = trimTrailingSlashes(apiUrl);\n const baseUrl = `${normalizedApiUrl}/apps/${encodeURIComponent(appName)}/users/${encodeURIComponent(userId)}/sessions`;\n\n const getHeaders = async (\n signal?: AbortSignal,\n ): Promise<Record<string, string>> => {\n if (!options.headers) return {};\n if (typeof options.headers === \"function\") {\n return await raceWithAbortSignal(signal, options.headers);\n }\n return options.headers;\n };\n\n const adapter: RemoteThreadListAdapter = {\n async list(): Promise<RemoteThreadListResponse> {\n const headers = await getHeaders();\n const res = await fetch(baseUrl, { headers });\n if (!res.ok) {\n throw new Error(`Failed to list sessions: ${res.status}`);\n }\n const data = parseAdkSessionListResponse(await res.json());\n\n const threads: RemoteThreadMetadata[] = data.map((session) => ({\n status: \"regular\" as const,\n remoteId: session.id,\n externalId: session.id,\n title: undefined,\n }));\n\n return { threads };\n },\n\n async initialize(\n _threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const headers = await getHeaders();\n const res = await fetch(baseUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify({}),\n });\n if (!res.ok) {\n throw new Error(`Failed to create session: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"create\");\n return { remoteId: session.id, externalId: session.id };\n },\n\n async delete(remoteId: string): Promise<void> {\n const headers = await getHeaders();\n const res = await fetch(`${baseUrl}/${encodeURIComponent(remoteId)}`, {\n method: \"DELETE\",\n headers,\n });\n if (!res.ok && res.status !== 404) {\n throw new Error(`Failed to delete session: ${res.status}`);\n }\n },\n\n async rename(): Promise<void> {\n // ADK sessions don't support titles\n },\n\n async archive(): Promise<void> {\n // ADK sessions don't support archiving\n },\n\n async unarchive(): Promise<void> {\n // ADK sessions don't support archiving\n },\n\n generateTitle(): Promise<AssistantStream> {\n // Title generation not supported without assistant-cloud\n return Promise.resolve(\n new ReadableStream<AssistantStreamChunk>({\n start(controller) {\n controller.close();\n },\n }),\n );\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const headers = await getHeaders();\n const res = await fetch(`${baseUrl}/${encodeURIComponent(threadId)}`, {\n headers,\n });\n if (!res.ok) {\n throw new Error(`Session not found: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"fetch\");\n return {\n status: \"regular\",\n remoteId: session.id,\n externalId: session.id,\n title: undefined,\n };\n },\n };\n\n const load = async (\n sessionId: string,\n options?: { signal?: AbortSignal | undefined },\n ): Promise<AdkThreadSnapshot> => {\n const headers = await getHeaders(options?.signal);\n const res = await fetch(`${baseUrl}/${encodeURIComponent(sessionId)}`, {\n headers,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n if (!res.ok) {\n throw new Error(`Failed to load session: ${res.status}`);\n }\n const session = parseAdkSessionResponse(await res.json(), \"load\");\n\n if (session.events !== undefined && !Array.isArray(session.events)) {\n throw new Error(\n 'Invalid ADK session load response: expected \"events\" to be an array when present.',\n );\n }\n\n // Events carry ordered state and tool transitions, so partial replay can\n // produce a plausible but incorrect thread.\n const events = session.events?.map((event, index) =>\n parseAdkEventValue(event, `Invalid ADK session event at index ${index}`),\n );\n\n if (!events?.length) {\n return { messages: [] };\n }\n\n const accumulator = new AdkEventAccumulator();\n let messages: AdkMessage[] = [];\n for (const event of events) {\n messages = accumulator.processEvent(event);\n }\n // The per-turn state rides along, so a refetch can swap the thread over in\n // one commit instead of reconstructing it from the messages alone.\n return {\n messages,\n longRunningToolIds: accumulator.getLongRunningToolIds(),\n toolConfirmations: accumulator.getToolConfirmations(),\n authRequests: accumulator.getAuthRequests(),\n escalated: accumulator.isEscalated(),\n messageMetadata: accumulator.getMessageMetadata(),\n stateDelta: accumulator.getStateDelta(),\n artifactDelta: accumulator.getArtifactDelta(),\n agentInfo: accumulator.getAgentInfo(),\n };\n };\n\n const artifactBaseUrl = (sessionId: string) =>\n `${baseUrl}/${encodeURIComponent(sessionId)}/artifacts`;\n\n const artifacts: AdkSessionAdapterResult[\"artifacts\"] = {\n async list(sessionId) {\n const headers = await getHeaders();\n const res = await fetch(artifactBaseUrl(sessionId), { headers });\n if (!res.ok) throw new Error(`Failed to list artifacts: ${res.status}`);\n return parseAdkArtifactListResponse(await res.json());\n },\n\n async load(sessionId, artifactName, version?) {\n const headers = await getHeaders();\n let url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}`;\n if (version != null) url += `/versions/${version}`;\n const res = await fetch(url, { headers });\n if (!res.ok) throw new Error(`Failed to load artifact: ${res.status}`);\n return parseAdkArtifactResponse(await res.json());\n },\n\n async listVersions(sessionId, artifactName) {\n const headers = await getHeaders();\n const url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}/versions`;\n const res = await fetch(url, { headers });\n if (!res.ok) {\n throw new Error(`Failed to list artifact versions: ${res.status}`);\n }\n return parseAdkArtifactVersionsResponse(await res.json());\n },\n\n async delete(sessionId, artifactName) {\n const headers = await getHeaders();\n const url = `${artifactBaseUrl(sessionId)}/${encodeURIComponent(artifactName)}`;\n const res = await fetch(url, { method: \"DELETE\", headers });\n if (!res.ok && res.status !== 404) {\n throw new Error(`Failed to delete artifact: ${res.status}`);\n }\n },\n };\n\n return { adapter, load, artifacts };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AdkThreadAction } from "./adkThreadState.js";
|
|
2
|
+
import type { AdkMessage } from "./types.js";
|
|
3
|
+
export declare class AdkThreadController {
|
|
4
|
+
private state;
|
|
5
|
+
private readonly listeners;
|
|
6
|
+
getState: () => import("./adkThreadState.js").AdkThreadState;
|
|
7
|
+
getStagedMessageCount: () => number;
|
|
8
|
+
getStagedRun: (parentId: string | null, messages?: AdkMessage[]) => {
|
|
9
|
+
messages: AdkMessage[];
|
|
10
|
+
runConfig: import("@assistant-ui/core").RunConfig | undefined;
|
|
11
|
+
} | null;
|
|
12
|
+
subscribe: (listener: () => void) => () => boolean;
|
|
13
|
+
dispatch: (action: AdkThreadAction) => void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=AdkThreadController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdkThreadController.d.ts","sourceRoot":"","sources":["../src/AdkThreadController.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACrB,4BAAyB;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAgB;AAE1C,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IAE5C,QAAQ,qDAAoB;IAE5B,qBAAqB,eAAuC;IAE5D,YAAY,GACjB,UAAU,MAAM,GAAG,IAAI,EACvB,WAAU,UAAU,EAAwB;;;aAc5C;IAEK,SAAS,GAAI,UAAU,MAAM,IAAI,mBAGtC;IAEK,QAAQ,GAAI,QAAQ,eAAe,UAKxC;CACH"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createAdkThreadState, reduceAdkThreadState } from "./adkThreadState.js";
|
|
2
|
+
//#region src/AdkThreadController.ts
|
|
3
|
+
var AdkThreadController = class {
|
|
4
|
+
state = createAdkThreadState();
|
|
5
|
+
listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
getState = () => this.state;
|
|
7
|
+
getStagedMessageCount = () => this.state.stagedEntries.size;
|
|
8
|
+
getStagedRun = (parentId, messages = this.state.messages) => {
|
|
9
|
+
const entries = this.state.stagedEntries;
|
|
10
|
+
if (!parentId || !entries.has(parentId)) return null;
|
|
11
|
+
const staged = [];
|
|
12
|
+
for (const message of messages) {
|
|
13
|
+
if (message.id && entries.has(message.id)) staged.push(entries.get(message.id).message);
|
|
14
|
+
if (message.id === parentId) break;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
messages: staged,
|
|
18
|
+
runConfig: entries.get(parentId).runConfig
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
subscribe = (listener) => {
|
|
22
|
+
this.listeners.add(listener);
|
|
23
|
+
return () => this.listeners.delete(listener);
|
|
24
|
+
};
|
|
25
|
+
dispatch = (action) => {
|
|
26
|
+
const nextState = reduceAdkThreadState(this.state, action);
|
|
27
|
+
if (nextState === this.state) return;
|
|
28
|
+
this.state = nextState;
|
|
29
|
+
for (const listener of this.listeners) listener();
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { AdkThreadController };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=AdkThreadController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdkThreadController.js","names":[],"sources":["../src/AdkThreadController.ts"],"sourcesContent":["import {\n createAdkThreadState,\n reduceAdkThreadState,\n type AdkThreadAction,\n} from \"./adkThreadState\";\nimport type { AdkMessage } from \"./types\";\n\nexport class AdkThreadController {\n private state = createAdkThreadState();\n private readonly listeners = new Set<() => void>();\n\n public getState = () => this.state;\n\n public getStagedMessageCount = () => this.state.stagedEntries.size;\n\n public getStagedRun = (\n parentId: string | null,\n messages: AdkMessage[] = this.state.messages,\n ) => {\n const entries = this.state.stagedEntries;\n if (!parentId || !entries.has(parentId)) return null;\n\n const staged: AdkMessage[] = [];\n for (const message of messages) {\n if (message.id && entries.has(message.id)) {\n staged.push(entries.get(message.id)!.message);\n }\n if (message.id === parentId) break;\n }\n\n return { messages: staged, runConfig: entries.get(parentId)!.runConfig };\n };\n\n public subscribe = (listener: () => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n public dispatch = (action: AdkThreadAction) => {\n const nextState = reduceAdkThreadState(this.state, action);\n if (nextState === this.state) return;\n this.state = nextState;\n for (const listener of this.listeners) listener();\n };\n}\n"],"mappings":";;AAOA,IAAa,sBAAb,MAAiC;CAC/B,QAAgB,qBAAqB;CACrC,4BAA6B,IAAI,IAAgB;CAEjD,iBAAwB,KAAK;CAE7B,8BAAqC,KAAK,MAAM,cAAc;CAE9D,gBACE,UACA,WAAyB,KAAK,MAAM,aACjC;EACH,MAAM,UAAU,KAAK,MAAM;EAC3B,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,QAAQ,GAAG,OAAO;EAEhD,MAAM,SAAuB,CAAC;EAC9B,KAAK,MAAM,WAAW,UAAU;GAC9B,IAAI,QAAQ,MAAM,QAAQ,IAAI,QAAQ,EAAE,GACtC,OAAO,KAAK,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAE,OAAO;GAE9C,IAAI,QAAQ,OAAO,UAAU;EAC/B;EAEA,OAAO;GAAE,UAAU;GAAQ,WAAW,QAAQ,IAAI,QAAQ,CAAC,CAAE;EAAU;CACzE;CAEA,aAAoB,aAAyB;EAC3C,KAAK,UAAU,IAAI,QAAQ;EAC3B,aAAa,KAAK,UAAU,OAAO,QAAQ;CAC7C;CAEA,YAAmB,WAA4B;EAC7C,MAAM,YAAY,qBAAqB,KAAK,OAAO,MAAM;EACzD,IAAI,cAAc,KAAK,OAAO;EAC9B,KAAK,QAAQ;EACb,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS;CAClD;AACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AppendMessage } from "@assistant-ui/core";
|
|
2
|
+
import type { AdkAuthRequest, AdkMessage, AdkMessageMetadata, AdkThreadSnapshot, AdkToolConfirmation } from "./types.js";
|
|
3
|
+
export type AdkStagedEntry = {
|
|
4
|
+
message: AdkMessage & {
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
runConfig: AppendMessage["runConfig"];
|
|
8
|
+
};
|
|
9
|
+
export type AdkThreadState = {
|
|
10
|
+
messages: AdkMessage[];
|
|
11
|
+
stateDelta: Record<string, unknown>;
|
|
12
|
+
agentInfo: {
|
|
13
|
+
name?: string | undefined;
|
|
14
|
+
branch?: string | undefined;
|
|
15
|
+
};
|
|
16
|
+
longRunningToolIds: string[];
|
|
17
|
+
artifactDelta: Record<string, number>;
|
|
18
|
+
toolConfirmations: AdkToolConfirmation[];
|
|
19
|
+
authRequests: AdkAuthRequest[];
|
|
20
|
+
escalated: boolean;
|
|
21
|
+
messageMetadata: Map<string, AdkMessageMetadata>;
|
|
22
|
+
stagedEntries: ReadonlyMap<string, AdkStagedEntry>;
|
|
23
|
+
};
|
|
24
|
+
export type AdkThreadAction = {
|
|
25
|
+
type: "event.published";
|
|
26
|
+
state: Omit<AdkThreadState, "stagedEntries">;
|
|
27
|
+
} | {
|
|
28
|
+
type: "snapshot.applied";
|
|
29
|
+
snapshot: AdkThreadSnapshot;
|
|
30
|
+
} | {
|
|
31
|
+
type: "messages.replaced";
|
|
32
|
+
messages: AdkMessage[];
|
|
33
|
+
} | {
|
|
34
|
+
type: "messages.set";
|
|
35
|
+
messages: AdkMessage[];
|
|
36
|
+
} | {
|
|
37
|
+
type: "longRunningToolIds.set";
|
|
38
|
+
ids: string[];
|
|
39
|
+
} | {
|
|
40
|
+
type: "staged.stage";
|
|
41
|
+
entry: AdkStagedEntry;
|
|
42
|
+
} | {
|
|
43
|
+
type: "staged.unstage";
|
|
44
|
+
ids: readonly string[];
|
|
45
|
+
} | {
|
|
46
|
+
type: "run.started";
|
|
47
|
+
messages: AdkMessage[];
|
|
48
|
+
longRunningToolIds: string[];
|
|
49
|
+
toolConfirmations: AdkToolConfirmation[];
|
|
50
|
+
authRequests: AdkAuthRequest[];
|
|
51
|
+
};
|
|
52
|
+
export declare const createAdkThreadState: () => AdkThreadState;
|
|
53
|
+
export declare const reduceAdkThreadState: (state: AdkThreadState, action: AdkThreadAction) => AdkThreadState;
|
|
54
|
+
//# sourceMappingURL=adkThreadState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adkThreadState.d.ts","sourceRoot":"","sources":["../src/adkThreadState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACpB,mBAAgB;AAEjB,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,UAAU,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACtE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,iBAAiB,EAAE,mBAAmB,EAAE,CAAC;IACzC,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACjD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAClD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,mBAAmB,EAAE,CAAC;IACzC,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEN,eAAO,MAAM,oBAAoB,QAAO,cAWtC,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,cAAc,EACrB,QAAQ,eAAe,KACtB,cAgEF,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
//#region src/adkThreadState.ts
|
|
2
|
+
const createAdkThreadState = () => ({
|
|
3
|
+
messages: [],
|
|
4
|
+
stateDelta: {},
|
|
5
|
+
agentInfo: {},
|
|
6
|
+
longRunningToolIds: [],
|
|
7
|
+
artifactDelta: {},
|
|
8
|
+
toolConfirmations: [],
|
|
9
|
+
authRequests: [],
|
|
10
|
+
escalated: false,
|
|
11
|
+
messageMetadata: /* @__PURE__ */ new Map(),
|
|
12
|
+
stagedEntries: /* @__PURE__ */ new Map()
|
|
13
|
+
});
|
|
14
|
+
const reduceAdkThreadState = (state, action) => {
|
|
15
|
+
switch (action.type) {
|
|
16
|
+
case "event.published": {
|
|
17
|
+
const next = action.state;
|
|
18
|
+
return {
|
|
19
|
+
...state,
|
|
20
|
+
...next,
|
|
21
|
+
stateDelta: {
|
|
22
|
+
...state.stateDelta,
|
|
23
|
+
...next.stateDelta
|
|
24
|
+
},
|
|
25
|
+
artifactDelta: {
|
|
26
|
+
...state.artifactDelta,
|
|
27
|
+
...next.artifactDelta
|
|
28
|
+
},
|
|
29
|
+
messageMetadata: next.messageMetadata.size > 0 ? new Map([...state.messageMetadata, ...next.messageMetadata]) : state.messageMetadata
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
case "snapshot.applied": {
|
|
33
|
+
const snapshot = action.snapshot;
|
|
34
|
+
return {
|
|
35
|
+
...state,
|
|
36
|
+
messages: snapshot.messages,
|
|
37
|
+
stateDelta: snapshot.stateDelta ?? {},
|
|
38
|
+
agentInfo: snapshot.agentInfo ?? {},
|
|
39
|
+
longRunningToolIds: snapshot.longRunningToolIds ?? [],
|
|
40
|
+
artifactDelta: snapshot.artifactDelta ?? {},
|
|
41
|
+
toolConfirmations: snapshot.toolConfirmations ?? [],
|
|
42
|
+
authRequests: snapshot.authRequests ?? [],
|
|
43
|
+
escalated: snapshot.escalated ?? false,
|
|
44
|
+
messageMetadata: snapshot.messageMetadata ?? /* @__PURE__ */ new Map()
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
case "messages.replaced": return {
|
|
48
|
+
...state,
|
|
49
|
+
messages: action.messages,
|
|
50
|
+
longRunningToolIds: [],
|
|
51
|
+
toolConfirmations: [],
|
|
52
|
+
authRequests: [],
|
|
53
|
+
escalated: false,
|
|
54
|
+
messageMetadata: /* @__PURE__ */ new Map()
|
|
55
|
+
};
|
|
56
|
+
case "messages.set": return {
|
|
57
|
+
...state,
|
|
58
|
+
messages: action.messages
|
|
59
|
+
};
|
|
60
|
+
case "longRunningToolIds.set": return {
|
|
61
|
+
...state,
|
|
62
|
+
longRunningToolIds: action.ids
|
|
63
|
+
};
|
|
64
|
+
case "staged.stage": {
|
|
65
|
+
const stagedEntries = new Map(state.stagedEntries);
|
|
66
|
+
stagedEntries.set(action.entry.message.id, action.entry);
|
|
67
|
+
return {
|
|
68
|
+
...state,
|
|
69
|
+
stagedEntries
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
case "staged.unstage": {
|
|
73
|
+
if (!action.ids.some((id) => state.stagedEntries.has(id))) return state;
|
|
74
|
+
const stagedEntries = new Map(state.stagedEntries);
|
|
75
|
+
for (const id of action.ids) stagedEntries.delete(id);
|
|
76
|
+
return {
|
|
77
|
+
...state,
|
|
78
|
+
stagedEntries
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
case "run.started": return {
|
|
82
|
+
...state,
|
|
83
|
+
messages: action.messages,
|
|
84
|
+
longRunningToolIds: action.longRunningToolIds,
|
|
85
|
+
toolConfirmations: action.toolConfirmations,
|
|
86
|
+
authRequests: action.authRequests
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
//#endregion
|
|
91
|
+
export { createAdkThreadState, reduceAdkThreadState };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=adkThreadState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adkThreadState.js","names":[],"sources":["../src/adkThreadState.ts"],"sourcesContent":["import type { AppendMessage } from \"@assistant-ui/core\";\nimport type {\n AdkAuthRequest,\n AdkMessage,\n AdkMessageMetadata,\n AdkThreadSnapshot,\n AdkToolConfirmation,\n} from \"./types\";\n\nexport type AdkStagedEntry = {\n message: AdkMessage & { id: string };\n runConfig: AppendMessage[\"runConfig\"];\n};\n\nexport type AdkThreadState = {\n messages: AdkMessage[];\n stateDelta: Record<string, unknown>;\n agentInfo: { name?: string | undefined; branch?: string | undefined };\n longRunningToolIds: string[];\n artifactDelta: Record<string, number>;\n toolConfirmations: AdkToolConfirmation[];\n authRequests: AdkAuthRequest[];\n escalated: boolean;\n messageMetadata: Map<string, AdkMessageMetadata>;\n stagedEntries: ReadonlyMap<string, AdkStagedEntry>;\n};\n\nexport type AdkThreadAction =\n | { type: \"event.published\"; state: Omit<AdkThreadState, \"stagedEntries\"> }\n | { type: \"snapshot.applied\"; snapshot: AdkThreadSnapshot }\n | { type: \"messages.replaced\"; messages: AdkMessage[] }\n | { type: \"messages.set\"; messages: AdkMessage[] }\n | { type: \"longRunningToolIds.set\"; ids: string[] }\n | { type: \"staged.stage\"; entry: AdkStagedEntry }\n | { type: \"staged.unstage\"; ids: readonly string[] }\n | {\n type: \"run.started\";\n messages: AdkMessage[];\n longRunningToolIds: string[];\n toolConfirmations: AdkToolConfirmation[];\n authRequests: AdkAuthRequest[];\n };\n\nexport const createAdkThreadState = (): AdkThreadState => ({\n messages: [],\n stateDelta: {},\n agentInfo: {},\n longRunningToolIds: [],\n artifactDelta: {},\n toolConfirmations: [],\n authRequests: [],\n escalated: false,\n messageMetadata: new Map(),\n stagedEntries: new Map(),\n});\n\nexport const reduceAdkThreadState = (\n state: AdkThreadState,\n action: AdkThreadAction,\n): AdkThreadState => {\n switch (action.type) {\n case \"event.published\": {\n const next = action.state;\n return {\n ...state,\n ...next,\n stateDelta: { ...state.stateDelta, ...next.stateDelta },\n artifactDelta: { ...state.artifactDelta, ...next.artifactDelta },\n messageMetadata:\n next.messageMetadata.size > 0\n ? new Map([...state.messageMetadata, ...next.messageMetadata])\n : state.messageMetadata,\n };\n }\n case \"snapshot.applied\": {\n const snapshot = action.snapshot;\n return {\n ...state,\n messages: snapshot.messages,\n stateDelta: snapshot.stateDelta ?? {},\n agentInfo: snapshot.agentInfo ?? {},\n longRunningToolIds: snapshot.longRunningToolIds ?? [],\n artifactDelta: snapshot.artifactDelta ?? {},\n toolConfirmations: snapshot.toolConfirmations ?? [],\n authRequests: snapshot.authRequests ?? [],\n escalated: snapshot.escalated ?? false,\n messageMetadata: snapshot.messageMetadata ?? new Map(),\n };\n }\n case \"messages.replaced\":\n return {\n ...state,\n messages: action.messages,\n longRunningToolIds: [],\n toolConfirmations: [],\n authRequests: [],\n escalated: false,\n messageMetadata: new Map(),\n };\n case \"messages.set\":\n return { ...state, messages: action.messages };\n case \"longRunningToolIds.set\":\n return { ...state, longRunningToolIds: action.ids };\n case \"staged.stage\": {\n const stagedEntries = new Map(state.stagedEntries);\n stagedEntries.set(action.entry.message.id, action.entry);\n return { ...state, stagedEntries };\n }\n case \"staged.unstage\": {\n if (!action.ids.some((id) => state.stagedEntries.has(id))) return state;\n const stagedEntries = new Map(state.stagedEntries);\n for (const id of action.ids) stagedEntries.delete(id);\n return { ...state, stagedEntries };\n }\n case \"run.started\":\n return {\n ...state,\n messages: action.messages,\n longRunningToolIds: action.longRunningToolIds,\n toolConfirmations: action.toolConfirmations,\n authRequests: action.authRequests,\n };\n }\n};\n"],"mappings":";AA2CA,MAAa,8BAA8C;CACzD,UAAU,CAAC;CACX,YAAY,CAAC;CACb,WAAW,CAAC;CACZ,oBAAoB,CAAC;CACrB,eAAe,CAAC;CAChB,mBAAmB,CAAC;CACpB,cAAc,CAAC;CACf,WAAW;CACX,iCAAiB,IAAI,IAAI;CACzB,+BAAe,IAAI,IAAI;AACzB;AAEA,MAAa,wBACX,OACA,WACmB;CACnB,QAAQ,OAAO,MAAf;EACE,KAAK,mBAAmB;GACtB,MAAM,OAAO,OAAO;GACpB,OAAO;IACL,GAAG;IACH,GAAG;IACH,YAAY;KAAE,GAAG,MAAM;KAAY,GAAG,KAAK;IAAW;IACtD,eAAe;KAAE,GAAG,MAAM;KAAe,GAAG,KAAK;IAAc;IAC/D,iBACE,KAAK,gBAAgB,OAAO,IACxB,IAAI,IAAI,CAAC,GAAG,MAAM,iBAAiB,GAAG,KAAK,eAAe,CAAC,IAC3D,MAAM;GACd;EACF;EACA,KAAK,oBAAoB;GACvB,MAAM,WAAW,OAAO;GACxB,OAAO;IACL,GAAG;IACH,UAAU,SAAS;IACnB,YAAY,SAAS,cAAc,CAAC;IACpC,WAAW,SAAS,aAAa,CAAC;IAClC,oBAAoB,SAAS,sBAAsB,CAAC;IACpD,eAAe,SAAS,iBAAiB,CAAC;IAC1C,mBAAmB,SAAS,qBAAqB,CAAC;IAClD,cAAc,SAAS,gBAAgB,CAAC;IACxC,WAAW,SAAS,aAAa;IACjC,iBAAiB,SAAS,mCAAmB,IAAI,IAAI;GACvD;EACF;EACA,KAAK,qBACH,OAAO;GACL,GAAG;GACH,UAAU,OAAO;GACjB,oBAAoB,CAAC;GACrB,mBAAmB,CAAC;GACpB,cAAc,CAAC;GACf,WAAW;GACX,iCAAiB,IAAI,IAAI;EAC3B;EACF,KAAK,gBACH,OAAO;GAAE,GAAG;GAAO,UAAU,OAAO;EAAS;EAC/C,KAAK,0BACH,OAAO;GAAE,GAAG;GAAO,oBAAoB,OAAO;EAAI;EACpD,KAAK,gBAAgB;GACnB,MAAM,gBAAgB,IAAI,IAAI,MAAM,aAAa;GACjD,cAAc,IAAI,OAAO,MAAM,QAAQ,IAAI,OAAO,KAAK;GACvD,OAAO;IAAE,GAAG;IAAO;GAAc;EACnC;EACA,KAAK,kBAAkB;GACrB,IAAI,CAAC,OAAO,IAAI,MAAM,OAAO,MAAM,cAAc,IAAI,EAAE,CAAC,GAAG,OAAO;GAClE,MAAM,gBAAgB,IAAI,IAAI,MAAM,aAAa;GACjD,KAAK,MAAM,MAAM,OAAO,KAAK,cAAc,OAAO,EAAE;GACpD,OAAO;IAAE,GAAG;IAAO;GAAc;EACnC;EACA,KAAK,eACH,OAAO;GACL,GAAG;GACH,UAAU,OAAO;GACjB,oBAAoB,OAAO;GAC3B,mBAAmB,OAAO;GAC1B,cAAc,OAAO;EACvB;CACJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertToAdkMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertToAdkMessages.ts"],"sourcesContent":["import { isRecord } from \"@assistant-ui/core/internal\";\nimport {\n generateId,\n getExternalStoreMessages,\n type AppendMessage,\n type ThreadMessage,\n} from \"@assistant-ui/core\";\nimport {\n createToolCallCancellationStub,\n parseDataUrl,\n resolveFilePartSource,\n resolveImageMediaType,\n scanPendingToolCalls,\n} from \"@assistant-ui/core/internal\";\nimport type { AdkMessage } from \"./types\";\n\n/** Exported for unit tests. */\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content.map((part) => ({ part, contentType: undefined })),\n ...(msg.attachments?.flatMap((attachment) =>\n attachment.content.map((part) => ({\n part,\n contentType: attachment.contentType,\n })),\n ) ?? []),\n ];\n const content = allContent.flatMap(({ part, contentType }) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\": {\n const parsed = parseDataUrl(part.image);\n if (parsed) {\n return {\n type: \"image\" as const,\n mimeType: resolveImageMediaType(part.image, contentType),\n data: parsed.data,\n };\n }\n return { type: \"image_url\" as const, url: part.image };\n }\n case \"file\": {\n const source = resolveFilePartSource(part);\n if (source.kind === \"url\") {\n return {\n type: \"file_url\" as const,\n url: source.url,\n mimeType: part.mimeType,\n };\n }\n return {\n type: \"file\" as const,\n mimeType:
|
|
1
|
+
{"version":3,"file":"convertToAdkMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertToAdkMessages.ts"],"sourcesContent":["import { isRecord } from \"@assistant-ui/core/internal\";\nimport {\n generateId,\n getExternalStoreMessages,\n type AppendMessage,\n type ThreadMessage,\n} from \"@assistant-ui/core\";\nimport {\n createToolCallCancellationStub,\n parseDataUrl,\n resolveFilePartSource,\n resolveImageMediaType,\n scanPendingToolCalls,\n} from \"@assistant-ui/core/internal\";\nimport type { AdkMessage } from \"./types\";\n\n/** Exported for unit tests. */\nexport const getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content.map((part) => ({ part, contentType: undefined })),\n ...(msg.attachments?.flatMap((attachment) =>\n attachment.content.map((part) => ({\n part,\n contentType: attachment.contentType,\n })),\n ) ?? []),\n ];\n const content = allContent.flatMap(({ part, contentType }) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\": {\n const parsed = parseDataUrl(part.image);\n if (parsed) {\n return {\n type: \"image\" as const,\n mimeType: resolveImageMediaType(part.image, contentType),\n data: parsed.data,\n };\n }\n return { type: \"image_url\" as const, url: part.image };\n }\n case \"file\": {\n const source = resolveFilePartSource(part);\n if (source.kind === \"url\") {\n return {\n type: \"file_url\" as const,\n url: source.url,\n mimeType: part.mimeType,\n };\n }\n return {\n type: \"file\" as const,\n mimeType: source.mimeType,\n // Lands in Gemini `inlineData.data`, which takes bare base64, so a\n // data URL envelope is stripped rather than forwarded.\n data: source.data,\n ...(part.filename != null && { filename: part.filename }),\n };\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/** Exported for unit tests. */\nexport const getPendingToolCalls = (messages: AdkMessage[]) => {\n return scanPendingToolCalls(\n messages,\n (message) => {\n if (message.type === \"ai\") {\n return {\n toolCalls: (message.tool_calls ?? []).filter(isRecord),\n };\n }\n if (message.type === \"tool\") {\n return { toolCallId: message.tool_call_id };\n }\n return undefined;\n },\n (toolCall) => toolCall.id,\n );\n};\n\n/**\n * 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: generateId(),\n ...createToolCallCancellationStub(t),\n }) satisfies AdkMessage & { type: \"tool\" },\n );\n};\n\nexport const 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\nexport const toAdkUserMessage = (\n msg: AppendMessage,\n id = generateId(),\n): AdkMessage & { type: \"human\"; id: string } => ({\n id,\n type: \"human\",\n content: getMessageContent(msg),\n});\n"],"mappings":";;;;AAiBA,MAAa,qBAAqB,QAAuB;CAUvD,MAAM,UAAU,CARd,GAAG,IAAI,QAAQ,KAAK,UAAU;EAAE;EAAM,aAAa,KAAA;CAAU,EAAE,GAC/D,GAAI,IAAI,aAAa,SAAS,eAC5B,WAAW,QAAQ,KAAK,UAAU;EAChC;EACA,aAAa,WAAW;CAC1B,EAAE,CACJ,KAAK,CAAC,CAEiB,CAAC,CAAC,SAAS,EAAE,MAAM,kBAAkB;EAC5D,MAAM,OAAO,KAAK;EAClB,QAAQ,MAAR;GACE,KAAK,QACH,OAAO;IAAE,MAAM;IAAiB,MAAM,KAAK;GAAK;GAClD,KAAK,SAAS;IACZ,MAAM,SAAS,aAAa,KAAK,KAAK;IACtC,IAAI,QACF,OAAO;KACL,MAAM;KACN,UAAU,sBAAsB,KAAK,OAAO,WAAW;KACvD,MAAM,OAAO;IACf;IAEF,OAAO;KAAE,MAAM;KAAsB,KAAK,KAAK;IAAM;GACvD;GACA,KAAK,QAAQ;IACX,MAAM,SAAS,sBAAsB,IAAI;IACzC,IAAI,OAAO,SAAS,OAClB,OAAO;KACL,MAAM;KACN,KAAK,OAAO;KACZ,UAAU,KAAK;IACjB;IAEF,OAAO;KACL,MAAM;KACN,UAAU,OAAO;KAGjB,MAAM,OAAO;KACb,GAAI,KAAK,YAAY,QAAQ,EAAE,UAAU,KAAK,SAAS;IACzD;GACF;GACA,KAAK,SAAS;IACZ,MAAM,SAAS,aAAa,KAAK,MAAM,IAAI;IAC3C,OAAO;KACL,MAAM;KACN,UAAU,SAAS,KAAK,MAAM;KAC9B,MAAM,QAAQ,QAAQ,KAAK,MAAM;IACnC;GACF;GACA,KAAK,QACH,OAAO,CAAC;GAEV,KAAK,aACH,MAAM,IAAI,MAAM,sCAAsC;GAExD,SAEE,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,OAAO,qBACL,WACC,YAAY;EACX,IAAI,QAAQ,SAAS,MACnB,OAAO,EACL,YAAY,QAAQ,cAAc,CAAC,EAAA,CAAG,OAAO,QAAQ,EACvD;EAEF,IAAI,QAAQ,SAAS,QACnB,OAAO,EAAE,YAAY,QAAQ,aAAa;CAG9C,IACC,aAAa,SAAS,EACzB;AACF;;;;;;;;;;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,IAAI,WAAW;EACf,GAAG,+BAA+B,CAAC;CACrC,EACJ;AACJ;AAEA,MAAa,uBACX,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,MAAa,oBACX,KACA,KAAK,WAAW,OACgC;CAChD;CACA,MAAM;CACN,SAAS,kBAAkB,GAAG;AAChC"}
|