@assistant-ui/react-google-adk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/dist/AdkClient.d.ts +45 -0
  4. package/dist/AdkClient.d.ts.map +1 -0
  5. package/dist/AdkClient.js +204 -0
  6. package/dist/AdkClient.js.map +1 -0
  7. package/dist/AdkEventAccumulator.d.ts +45 -0
  8. package/dist/AdkEventAccumulator.d.ts.map +1 -0
  9. package/dist/AdkEventAccumulator.js +508 -0
  10. package/dist/AdkEventAccumulator.js.map +1 -0
  11. package/dist/AdkSessionAdapter.d.ts +61 -0
  12. package/dist/AdkSessionAdapter.d.ts.map +1 -0
  13. package/dist/AdkSessionAdapter.js +159 -0
  14. package/dist/AdkSessionAdapter.js.map +1 -0
  15. package/dist/convertAdkMessages.d.ts +4 -0
  16. package/dist/convertAdkMessages.d.ts.map +1 -0
  17. package/dist/convertAdkMessages.js +75 -0
  18. package/dist/convertAdkMessages.js.map +1 -0
  19. package/dist/hooks.d.ts +50 -0
  20. package/dist/hooks.d.ts.map +1 -0
  21. package/dist/hooks.js +173 -0
  22. package/dist/hooks.js.map +1 -0
  23. package/dist/index.d.ts +11 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +10 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/server/adkEventStream.d.ts +42 -0
  28. package/dist/server/adkEventStream.d.ts.map +1 -0
  29. package/dist/server/adkEventStream.js +135 -0
  30. package/dist/server/adkEventStream.js.map +1 -0
  31. package/dist/server/createAdkApiRoute.d.ts +47 -0
  32. package/dist/server/createAdkApiRoute.d.ts.map +1 -0
  33. package/dist/server/createAdkApiRoute.js +41 -0
  34. package/dist/server/createAdkApiRoute.js.map +1 -0
  35. package/dist/server/index.d.ts +4 -0
  36. package/dist/server/index.d.ts.map +1 -0
  37. package/dist/server/index.js +4 -0
  38. package/dist/server/index.js.map +1 -0
  39. package/dist/server/parseAdkRequest.d.ts +56 -0
  40. package/dist/server/parseAdkRequest.d.ts.map +1 -0
  41. package/dist/server/parseAdkRequest.js +93 -0
  42. package/dist/server/parseAdkRequest.js.map +1 -0
  43. package/dist/structuredEvents.d.ts +7 -0
  44. package/dist/structuredEvents.d.ts.map +1 -0
  45. package/dist/structuredEvents.js +79 -0
  46. package/dist/structuredEvents.js.map +1 -0
  47. package/dist/types.d.ts +253 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +14 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/useAdkMessages.d.ts +28 -0
  52. package/dist/useAdkMessages.d.ts.map +1 -0
  53. package/dist/useAdkMessages.js +198 -0
  54. package/dist/useAdkMessages.js.map +1 -0
  55. package/dist/useAdkRuntime.d.ts +36 -0
  56. package/dist/useAdkRuntime.d.ts.map +1 -0
  57. package/dist/useAdkRuntime.js +252 -0
  58. package/dist/useAdkRuntime.js.map +1 -0
  59. package/package.json +83 -0
  60. package/server/package.json +4 -0
  61. package/src/AdkClient.test.ts +662 -0
  62. package/src/AdkClient.ts +274 -0
  63. package/src/AdkEventAccumulator.test.ts +591 -0
  64. package/src/AdkEventAccumulator.ts +602 -0
  65. package/src/AdkSessionAdapter.test.ts +362 -0
  66. package/src/AdkSessionAdapter.ts +245 -0
  67. package/src/convertAdkMessages.test.ts +209 -0
  68. package/src/convertAdkMessages.ts +93 -0
  69. package/src/hooks.ts +217 -0
  70. package/src/index.ts +66 -0
  71. package/src/server/adkEventStream.test.ts +78 -0
  72. package/src/server/adkEventStream.ts +161 -0
  73. package/src/server/createAdkApiRoute.test.ts +370 -0
  74. package/src/server/createAdkApiRoute.ts +86 -0
  75. package/src/server/index.ts +6 -0
  76. package/src/server/parseAdkRequest.test.ts +152 -0
  77. package/src/server/parseAdkRequest.ts +122 -0
  78. package/src/structuredEvents.ts +81 -0
  79. package/src/types.ts +265 -0
  80. package/src/useAdkMessages.ts +259 -0
  81. package/src/useAdkRuntime.ts +398 -0
@@ -0,0 +1,152 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { parseAdkRequest, toAdkContent } from "./parseAdkRequest";
3
+
4
+ const makeRequest = (body: unknown) =>
5
+ new Request("http://localhost", {
6
+ method: "POST",
7
+ headers: { "Content-Type": "application/json" },
8
+ body: JSON.stringify(body),
9
+ });
10
+
11
+ describe("parseAdkRequest", () => {
12
+ it("parses a simple message request", async () => {
13
+ const result = await parseAdkRequest(makeRequest({ message: "Hello" }));
14
+ expect(result).toMatchObject({ type: "message", text: "Hello" });
15
+ });
16
+
17
+ it("parses a message request with runConfig and checkpointId", async () => {
18
+ const result = await parseAdkRequest(
19
+ makeRequest({
20
+ message: "Hello",
21
+ runConfig: { temperature: 0.5 },
22
+ checkpointId: "cp-123",
23
+ }),
24
+ );
25
+ expect(result.config).toMatchObject({
26
+ runConfig: { temperature: 0.5 },
27
+ checkpointId: "cp-123",
28
+ });
29
+ });
30
+
31
+ it("parses a message request with stateDelta", async () => {
32
+ const result = await parseAdkRequest(
33
+ makeRequest({ message: "Hello", stateDelta: { count: 1 } }),
34
+ );
35
+ expect(result).toMatchObject({ stateDelta: { count: 1 } });
36
+ });
37
+
38
+ it("parses a message request with parts (multimodal)", async () => {
39
+ const result = await parseAdkRequest(
40
+ makeRequest({
41
+ message: "Look at this",
42
+ parts: [
43
+ { text: "Look" },
44
+ { inlineData: { mimeType: "image/png", data: "abc" } },
45
+ ],
46
+ }),
47
+ );
48
+ if (result.type !== "message") throw new Error("Expected message type");
49
+ expect(result.parts).toHaveLength(2);
50
+ });
51
+
52
+ it("parses a tool-result request", async () => {
53
+ const result = await parseAdkRequest(
54
+ makeRequest({
55
+ type: "tool-result",
56
+ toolCallId: "tc-1",
57
+ toolName: "search",
58
+ result: { data: "found" },
59
+ isError: false,
60
+ }),
61
+ );
62
+ expect(result).toMatchObject({
63
+ type: "tool-result",
64
+ toolCallId: "tc-1",
65
+ toolName: "search",
66
+ result: { data: "found" },
67
+ isError: false,
68
+ });
69
+ });
70
+
71
+ it("defaults isError to false when missing", async () => {
72
+ const result = await parseAdkRequest(
73
+ makeRequest({
74
+ type: "tool-result",
75
+ toolCallId: "tc-1",
76
+ result: {},
77
+ }),
78
+ );
79
+ if (result.type !== "tool-result") throw new Error("Expected tool-result");
80
+ expect(result.isError).toBe(false);
81
+ });
82
+
83
+ it("throws on invalid JSON", async () => {
84
+ const req = new Request("http://localhost", {
85
+ method: "POST",
86
+ body: "not json",
87
+ });
88
+ await expect(parseAdkRequest(req)).rejects.toThrow();
89
+ });
90
+
91
+ it("throws on non-object body", async () => {
92
+ await expect(parseAdkRequest(makeRequest([1, 2, 3]))).rejects.toThrow(
93
+ "Request body must be a JSON object",
94
+ );
95
+ });
96
+ });
97
+
98
+ describe("toAdkContent", () => {
99
+ it("converts a text message to user content with text part", () => {
100
+ const content = toAdkContent({
101
+ type: "message",
102
+ text: "Hello",
103
+ config: {},
104
+ });
105
+ expect(content).toEqual({
106
+ role: "user",
107
+ parts: [{ text: "Hello" }],
108
+ });
109
+ });
110
+
111
+ it("converts a multimodal message using raw parts", () => {
112
+ const content = toAdkContent({
113
+ type: "message",
114
+ text: "",
115
+ parts: [
116
+ { text: "Look" },
117
+ { inlineData: { mimeType: "image/png", data: "abc" } },
118
+ ],
119
+ config: {},
120
+ });
121
+ expect(content).toEqual({
122
+ role: "user",
123
+ parts: [
124
+ { text: "Look" },
125
+ { inlineData: { mimeType: "image/png", data: "abc" } },
126
+ ],
127
+ });
128
+ });
129
+
130
+ it("converts a tool-result to user content with functionResponse part", () => {
131
+ const content = toAdkContent({
132
+ type: "tool-result",
133
+ toolCallId: "tc-1",
134
+ toolName: "search",
135
+ result: { found: true },
136
+ isError: false,
137
+ config: {},
138
+ });
139
+ expect(content).toEqual({
140
+ role: "user",
141
+ parts: [
142
+ {
143
+ functionResponse: {
144
+ name: "search",
145
+ id: "tc-1",
146
+ response: { found: true },
147
+ },
148
+ },
149
+ ],
150
+ });
151
+ });
152
+ });
@@ -0,0 +1,122 @@
1
+ import type { AdkSendMessageConfig } from "../types";
2
+
3
+ type ParsedAdkRequest =
4
+ | {
5
+ type: "message";
6
+ text: string;
7
+ parts?: Array<Record<string, unknown>> | undefined;
8
+ config: AdkSendMessageConfig;
9
+ stateDelta?: Record<string, unknown> | undefined;
10
+ }
11
+ | {
12
+ type: "tool-result";
13
+ toolCallId: string;
14
+ toolName: string;
15
+ result: unknown;
16
+ isError: boolean;
17
+ config: AdkSendMessageConfig;
18
+ stateDelta?: Record<string, unknown> | undefined;
19
+ };
20
+
21
+ /**
22
+ * Parses an incoming HTTP request into a structured ADK request.
23
+ *
24
+ * Supports two request shapes:
25
+ *
26
+ * 1. User message:
27
+ * ```json
28
+ * { "message": "Hello", "runConfig": {}, "stateDelta": {} }
29
+ * ```
30
+ *
31
+ * 2. Tool result:
32
+ * ```json
33
+ * {
34
+ * "type": "tool-result",
35
+ * "toolCallId": "call_123",
36
+ * "toolName": "search",
37
+ * "result": { ... },
38
+ * "isError": false
39
+ * }
40
+ * ```
41
+ */
42
+ export const parseAdkRequest = async (
43
+ request: Request,
44
+ ): Promise<ParsedAdkRequest> => {
45
+ let body: Record<string, unknown>;
46
+ try {
47
+ body = (await request.json()) as Record<string, unknown>;
48
+ } catch {
49
+ throw new Error("Invalid JSON in request body");
50
+ }
51
+
52
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
53
+ throw new Error("Request body must be a JSON object");
54
+ }
55
+
56
+ const config: AdkSendMessageConfig = {};
57
+ if (body.runConfig !== undefined) config.runConfig = body.runConfig;
58
+ if (body.checkpointId !== undefined)
59
+ config.checkpointId = body.checkpointId as string;
60
+
61
+ const stateDelta = body.stateDelta as Record<string, unknown> | undefined;
62
+
63
+ if (body.type === "tool-result") {
64
+ return {
65
+ type: "tool-result",
66
+ toolCallId: (body.toolCallId as string) ?? "",
67
+ toolName: (body.toolName as string) ?? "",
68
+ result: body.result,
69
+ isError: (body.isError as boolean) ?? false,
70
+ config,
71
+ ...(stateDelta != null && { stateDelta }),
72
+ };
73
+ }
74
+
75
+ return {
76
+ type: "message",
77
+ text: (body.message as string) ?? "",
78
+ ...(body.parts != null && {
79
+ parts: body.parts as Array<Record<string, unknown>>,
80
+ }),
81
+ config,
82
+ ...(stateDelta != null && { stateDelta }),
83
+ };
84
+ };
85
+
86
+ /**
87
+ * Converts a parsed ADK request into a Google GenAI Content object
88
+ * suitable for `Runner.runAsync({ newMessage })`.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const parsed = await parseAdkRequest(req);
93
+ * const newMessage = toAdkContent(parsed);
94
+ * const events = runner.runAsync({ userId, sessionId, newMessage, stateDelta: parsed.stateDelta });
95
+ * return adkEventStream(events);
96
+ * ```
97
+ */
98
+ export const toAdkContent = (
99
+ parsed: ParsedAdkRequest,
100
+ ): { role: string; parts: Array<Record<string, unknown>> } => {
101
+ if (parsed.type === "tool-result") {
102
+ return {
103
+ role: "user",
104
+ parts: [
105
+ {
106
+ functionResponse: {
107
+ name: parsed.toolName,
108
+ id: parsed.toolCallId,
109
+ response: parsed.result,
110
+ },
111
+ },
112
+ ],
113
+ };
114
+ }
115
+
116
+ // If raw parts are provided (multimodal), use them directly
117
+ if (parsed.parts?.length) {
118
+ return { role: "user", parts: parsed.parts };
119
+ }
120
+
121
+ return { role: "user", parts: [{ text: parsed.text }] };
122
+ };
@@ -0,0 +1,81 @@
1
+ import type { AdkEvent, AdkStructuredEvent } from "./types";
2
+ import { isFinalResponse } from "./AdkEventAccumulator";
3
+
4
+ /**
5
+ * Converts a raw `AdkEvent` into an array of structured, typed events.
6
+ * Useful for building custom event renderers.
7
+ */
8
+ export function toAdkStructuredEvents(event: AdkEvent): AdkStructuredEvent[] {
9
+ const result: AdkStructuredEvent[] = [];
10
+
11
+ if (event.errorCode || event.errorMessage) {
12
+ const err: AdkStructuredEvent & { type: "error" } = { type: "error" };
13
+ if (event.errorCode != null) err.errorCode = event.errorCode;
14
+ if (event.errorMessage != null) err.errorMessage = event.errorMessage;
15
+ result.push(err);
16
+ }
17
+
18
+ const parts = event.content?.parts;
19
+ if (parts) {
20
+ for (const part of parts) {
21
+ if (part.text != null) {
22
+ if (part.thought) {
23
+ result.push({ type: "thought", content: part.text });
24
+ } else {
25
+ result.push({ type: "content", content: part.text });
26
+ }
27
+ }
28
+ if (part.functionCall) {
29
+ const call: AdkStructuredEvent & { type: "tool_call" } = {
30
+ type: "tool_call",
31
+ call: { name: part.functionCall.name, args: part.functionCall.args },
32
+ };
33
+ if (part.functionCall.id != null) call.call.id = part.functionCall.id;
34
+ result.push(call);
35
+ }
36
+ if (part.functionResponse) {
37
+ const tr: AdkStructuredEvent & { type: "tool_result" } = {
38
+ type: "tool_result",
39
+ result: {
40
+ name: part.functionResponse.name,
41
+ response: part.functionResponse.response,
42
+ },
43
+ };
44
+ if (part.functionResponse.id != null)
45
+ tr.result.id = part.functionResponse.id;
46
+ result.push(tr);
47
+ }
48
+ if (part.executableCode) {
49
+ const ce: AdkStructuredEvent & { type: "call_code" } = {
50
+ type: "call_code",
51
+ code: { code: part.executableCode.code },
52
+ };
53
+ if (part.executableCode.language != null)
54
+ ce.code.language = part.executableCode.language;
55
+ result.push(ce);
56
+ }
57
+ if (part.codeExecutionResult) {
58
+ const cr: AdkStructuredEvent & { type: "code_result" } = {
59
+ type: "code_result",
60
+ result: { output: part.codeExecutionResult.output },
61
+ };
62
+ if (part.codeExecutionResult.outcome != null)
63
+ cr.result.outcome = part.codeExecutionResult.outcome;
64
+ result.push(cr);
65
+ }
66
+ }
67
+ }
68
+
69
+ if (event.actions?.requestedToolConfirmations) {
70
+ result.push({
71
+ type: "tool_confirmation",
72
+ confirmations: event.actions.requestedToolConfirmations,
73
+ });
74
+ }
75
+
76
+ if (isFinalResponse(event) && result.length === 0) {
77
+ result.push({ type: "finished" });
78
+ }
79
+
80
+ return result;
81
+ }
package/src/types.ts ADDED
@@ -0,0 +1,265 @@
1
+ import type { MessageStatus } from "@assistant-ui/core";
2
+ import type { ReadonlyJSONObject } from "assistant-stream/utils";
3
+
4
+ // ── ADK Event wire types (lightweight, no @google/adk dependency) ──
5
+
6
+ export type AdkEventPart = {
7
+ text?: string;
8
+ thought?: boolean;
9
+ functionCall?: {
10
+ name: string;
11
+ id?: string;
12
+ args: Record<string, unknown>;
13
+ };
14
+ functionResponse?: {
15
+ name: string;
16
+ id?: string;
17
+ response: unknown;
18
+ };
19
+ executableCode?: {
20
+ code: string;
21
+ language?: string;
22
+ };
23
+ codeExecutionResult?: {
24
+ output: string;
25
+ outcome?: string;
26
+ };
27
+ inlineData?: {
28
+ mimeType: string;
29
+ data: string;
30
+ };
31
+ fileData?: {
32
+ fileUri: string;
33
+ mimeType?: string;
34
+ };
35
+ };
36
+
37
+ export type AdkEventActions = {
38
+ stateDelta?: Record<string, unknown> | undefined;
39
+ artifactDelta?: Record<string, number> | undefined;
40
+ transferToAgent?: string | undefined;
41
+ escalate?: boolean | undefined;
42
+ skipSummarization?: boolean | undefined;
43
+ requestedAuthConfigs?: Record<string, unknown> | undefined;
44
+ requestedToolConfirmations?: Record<string, unknown> | undefined;
45
+ };
46
+
47
+ export type AdkEvent = {
48
+ id: string;
49
+ invocationId?: string | undefined;
50
+ author?: string | undefined;
51
+ branch?: string | undefined;
52
+ partial?: boolean | undefined;
53
+ turnComplete?: boolean | undefined;
54
+ interrupted?: boolean | undefined;
55
+ finishReason?: string | undefined;
56
+ timestamp?: number | undefined;
57
+ content?:
58
+ | {
59
+ role?: string | undefined;
60
+ parts?: AdkEventPart[] | undefined;
61
+ }
62
+ | undefined;
63
+ actions?: AdkEventActions | undefined;
64
+ longRunningToolIds?: string[] | undefined;
65
+ errorCode?: string | undefined;
66
+ errorMessage?: string | undefined;
67
+ groundingMetadata?: unknown;
68
+ citationMetadata?: unknown;
69
+ usageMetadata?: unknown;
70
+ customMetadata?: Record<string, unknown> | undefined;
71
+ };
72
+
73
+ // ── ADK Message types (accumulated from events) ──
74
+
75
+ export type AdkToolCall = {
76
+ id: string;
77
+ name: string;
78
+ args: ReadonlyJSONObject;
79
+ argsText?: string;
80
+ };
81
+
82
+ export type AdkMessage =
83
+ | {
84
+ id: string;
85
+ type: "human";
86
+ content: string | AdkMessageContentPart[];
87
+ }
88
+ | {
89
+ id: string;
90
+ type: "ai";
91
+ content: string | AdkMessageContentPart[];
92
+ tool_calls?: AdkToolCall[] | undefined;
93
+ author?: string | undefined;
94
+ branch?: string | undefined;
95
+ status?: MessageStatus | undefined;
96
+ }
97
+ | {
98
+ id: string;
99
+ type: "tool";
100
+ content: string;
101
+ tool_call_id: string;
102
+ name: string;
103
+ status?: "success" | "error" | undefined;
104
+ artifact?: unknown;
105
+ };
106
+
107
+ export type AdkMessageContentPart =
108
+ | { type: "text"; text: string }
109
+ | { type: "reasoning"; text: string }
110
+ | { type: "image"; mimeType: string; data: string }
111
+ | { type: "image_url"; url: string }
112
+ | { type: "code"; code: string; language: string }
113
+ | { type: "code_result"; output: string; outcome: string }
114
+ | { type: "activity"; message: string };
115
+
116
+ // ── ADK-specific state types ──
117
+
118
+ export type AdkToolConfirmation = {
119
+ toolCallId: string;
120
+ toolName: string;
121
+ args: Record<string, unknown>;
122
+ hint: string;
123
+ confirmed: boolean;
124
+ payload?: unknown;
125
+ };
126
+
127
+ export type AdkAuthCredentialType =
128
+ | "apiKey"
129
+ | "http"
130
+ | "oauth2"
131
+ | "openIdConnect"
132
+ | "serviceAccount";
133
+
134
+ export type AdkAuthCredential = {
135
+ authType: AdkAuthCredentialType;
136
+ resourceRef?: string | undefined;
137
+ apiKey?: string | undefined;
138
+ http?:
139
+ | {
140
+ scheme: string;
141
+ credentials: {
142
+ username?: string;
143
+ password?: string;
144
+ token?: string;
145
+ };
146
+ }
147
+ | undefined;
148
+ oauth2?:
149
+ | {
150
+ clientId?: string;
151
+ clientSecret?: string;
152
+ authUri?: string;
153
+ state?: string;
154
+ redirectUri?: string;
155
+ authResponseUri?: string;
156
+ authCode?: string;
157
+ accessToken?: string;
158
+ refreshToken?: string;
159
+ expiresAt?: number;
160
+ expiresIn?: number;
161
+ }
162
+ | undefined;
163
+ serviceAccount?: unknown;
164
+ };
165
+
166
+ export type AdkAuthRequest = {
167
+ toolCallId: string;
168
+ authConfig: unknown;
169
+ };
170
+
171
+ export type AdkMessageMetadata = {
172
+ groundingMetadata?: unknown;
173
+ citationMetadata?: unknown;
174
+ usageMetadata?: unknown;
175
+ };
176
+
177
+ // ── RunConfig ──
178
+
179
+ export type AdkRunConfig = {
180
+ streamingMode?: "none" | "sse" | "bidi" | undefined;
181
+ pauseOnToolCalls?: boolean | undefined;
182
+ maxLlmCalls?: number | undefined;
183
+ saveInputBlobsAsArtifacts?: boolean | undefined;
184
+ supportCfc?: boolean | undefined;
185
+ speechConfig?: unknown;
186
+ responseModalities?: string[] | undefined;
187
+ outputAudioTranscription?: unknown;
188
+ inputAudioTranscription?: unknown;
189
+ enableAffectiveDialog?: boolean | undefined;
190
+ proactivity?: unknown;
191
+ realtimeInputConfig?: unknown;
192
+ };
193
+
194
+ // ── Stream callback types ──
195
+
196
+ export type AdkSendMessageConfig = {
197
+ /**
198
+ * ADK RunConfig. Typed as `unknown` for compatibility with
199
+ * assistant-ui core's RunConfig type. Use `AdkRunConfig` when
200
+ * constructing configs manually for type safety.
201
+ */
202
+ runConfig?: unknown;
203
+ checkpointId?: string | undefined;
204
+ stateDelta?: Record<string, unknown> | undefined;
205
+ };
206
+
207
+ // ── Structured events ──
208
+
209
+ export const AdkEventType = {
210
+ THOUGHT: "thought",
211
+ CONTENT: "content",
212
+ TOOL_CALL: "tool_call",
213
+ TOOL_RESULT: "tool_result",
214
+ CALL_CODE: "call_code",
215
+ CODE_RESULT: "code_result",
216
+ ERROR: "error",
217
+ ACTIVITY: "activity",
218
+ TOOL_CONFIRMATION: "tool_confirmation",
219
+ FINISHED: "finished",
220
+ } as const;
221
+
222
+ export type AdkStructuredEvent =
223
+ | { type: "thought"; content: string }
224
+ | { type: "content"; content: string }
225
+ | {
226
+ type: "tool_call";
227
+ call: { name: string; id?: string; args: Record<string, unknown> };
228
+ }
229
+ | {
230
+ type: "tool_result";
231
+ result: { name: string; id?: string; response: unknown };
232
+ }
233
+ | { type: "call_code"; code: { code: string; language?: string } }
234
+ | { type: "code_result"; result: { output: string; outcome?: string } }
235
+ | { type: "error"; errorCode?: string; errorMessage?: string }
236
+ | { type: "activity"; message: string }
237
+ | {
238
+ type: "tool_confirmation";
239
+ confirmations: Record<string, unknown>;
240
+ }
241
+ | { type: "finished" };
242
+
243
+ export type AdkStreamCallback = (
244
+ messages: AdkMessage[],
245
+ config: AdkSendMessageConfig & {
246
+ abortSignal: AbortSignal;
247
+ initialize: () => Promise<{
248
+ remoteId: string;
249
+ externalId: string | undefined;
250
+ }>;
251
+ },
252
+ ) => Promise<AsyncGenerator<AdkEvent>> | AsyncGenerator<AdkEvent>;
253
+
254
+ // ── Event handler callbacks ──
255
+
256
+ export type OnAdkErrorCallback = (error: unknown) => void | Promise<void>;
257
+
258
+ export type OnAdkCustomEventCallback = (
259
+ type: string,
260
+ data: unknown,
261
+ ) => void | Promise<void>;
262
+
263
+ export type OnAdkAgentTransferCallback = (
264
+ toAgent: string,
265
+ ) => void | Promise<void>;