@assistant-ui/react-google-adk 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AdkClient.d.ts +2 -3
- package/dist/AdkClient.d.ts.map +1 -1
- package/dist/AdkClient.js +2 -1
- package/dist/AdkClient.js.map +1 -1
- package/dist/AdkEventAccumulator.d.ts +4 -6
- package/dist/AdkEventAccumulator.d.ts.map +1 -1
- package/dist/AdkEventAccumulator.js +80 -95
- package/dist/AdkEventAccumulator.js.map +1 -1
- package/dist/AdkSessionAdapter.d.ts +7 -4
- package/dist/AdkSessionAdapter.d.ts.map +1 -1
- package/dist/AdkSessionAdapter.js +7 -4
- package/dist/AdkSessionAdapter.js.map +1 -1
- package/dist/adkExtras.d.ts +1 -2
- package/dist/adkExtras.d.ts.map +1 -1
- package/dist/adkToolApproval.d.ts +6 -7
- package/dist/adkToolApproval.d.ts.map +1 -1
- package/dist/adkToolApproval.js +1 -3
- package/dist/adkToolApproval.js.map +1 -1
- package/dist/contentToParts.d.ts +1 -2
- package/dist/contentToParts.d.ts.map +1 -1
- package/dist/convertAdkMessages.d.ts +2 -3
- package/dist/convertAdkMessages.d.ts.map +1 -1
- package/dist/convertToAdkMessages.d.ts +15 -7
- package/dist/convertToAdkMessages.d.ts.map +1 -1
- package/dist/convertToAdkMessages.js +20 -6
- package/dist/convertToAdkMessages.js.map +1 -1
- package/dist/hooks.d.ts +15 -16
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +1 -1
- package/dist/normalizeAdkPart.d.ts +4 -0
- package/dist/normalizeAdkPart.d.ts.map +1 -0
- package/dist/normalizeAdkPart.js +31 -0
- package/dist/normalizeAdkPart.js.map +1 -0
- package/dist/parseAdkEvent.d.ts +1 -2
- package/dist/parseAdkEvent.d.ts.map +1 -1
- package/dist/sdkIdentity.d.ts +5 -0
- package/dist/sdkIdentity.d.ts.map +1 -0
- package/dist/sdkIdentity.js +9 -0
- package/dist/sdkIdentity.js.map +1 -0
- package/dist/server/adkEventStream.d.ts +2 -3
- package/dist/server/adkEventStream.d.ts.map +1 -1
- package/dist/server/createAdkApiRoute.d.ts +2 -3
- package/dist/server/createAdkApiRoute.d.ts.map +1 -1
- package/dist/server/parseAdkRequest.d.ts +2 -3
- package/dist/server/parseAdkRequest.d.ts.map +1 -1
- package/dist/server/parseAdkRequest.js +2 -1
- package/dist/server/parseAdkRequest.js.map +1 -1
- package/dist/structuredEvents.d.ts +1 -2
- package/dist/structuredEvents.d.ts.map +1 -1
- package/dist/structuredEvents.js +1 -1
- package/dist/structuredEvents.js.map +1 -1
- package/dist/toAdkFunctionResponse.d.ts +5 -0
- package/dist/toAdkFunctionResponse.d.ts.map +1 -0
- package/dist/toAdkFunctionResponse.js +11 -0
- package/dist/toAdkFunctionResponse.js.map +1 -0
- package/dist/trimTrailingSlashes.d.ts +1 -2
- package/dist/trimTrailingSlashes.d.ts.map +1 -1
- package/dist/types.d.ts +22 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/useAdkMessages.d.ts +2 -3
- package/dist/useAdkMessages.d.ts.map +1 -1
- package/dist/useAdkMessages.js +16 -5
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts +2 -3
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +3 -1
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +10 -9
- package/src/AdkClient.test.ts +139 -2
- package/src/AdkClient.ts +2 -1
- package/src/AdkEventAccumulator.test.ts +588 -11
- package/src/AdkEventAccumulator.ts +85 -130
- package/src/AdkSessionAdapter.test.ts +355 -1
- package/src/AdkSessionAdapter.ts +24 -5
- package/src/adkToolApproval.test.ts +0 -4
- package/src/adkToolApproval.ts +1 -3
- package/src/convertToAdkMessages.test.ts +70 -0
- package/src/convertToAdkMessages.ts +19 -4
- package/src/normalizeAdkPart.ts +35 -0
- package/src/sdkIdentity.ts +9 -0
- package/src/server/parseAdkRequest.test.ts +63 -0
- package/src/server/parseAdkRequest.ts +2 -1
- package/src/structuredEvents.test.ts +69 -0
- package/src/structuredEvents.ts +4 -1
- package/src/toAdkFunctionResponse.test.ts +46 -0
- package/src/toAdkFunctionResponse.ts +18 -0
- package/src/types.ts +1 -1
- package/src/useAdkMessages.test.ts +249 -2
- package/src/useAdkMessages.ts +24 -6
- package/src/useAdkRuntime.replacement.test.tsx +11 -7
- package/src/useAdkRuntime.ts +2 -0
- package/src/useAdkRuntimeApproval.test.tsx +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateId } from "@assistant-ui/core";
|
|
2
|
+
import { isRecord } from "@assistant-ui/core/internal";
|
|
2
3
|
import type { MessageStatus } from "@assistant-ui/core";
|
|
3
4
|
import type {
|
|
4
5
|
AdkEvent,
|
|
@@ -11,6 +12,9 @@ import type {
|
|
|
11
12
|
AdkMessageMetadata,
|
|
12
13
|
} from "./types";
|
|
13
14
|
import type { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
15
|
+
import { normalizeAdkPart } from "./normalizeAdkPart";
|
|
16
|
+
import { projectAdkToolApprovals } from "./adkToolApproval";
|
|
17
|
+
import { isAdkFunctionError } from "./toAdkFunctionResponse";
|
|
14
18
|
|
|
15
19
|
type InProgressMessage = AdkMessage & { type: "ai" };
|
|
16
20
|
|
|
@@ -97,41 +101,27 @@ const finishReasonToStatus = (
|
|
|
97
101
|
return { type: "complete", reason: "stop" };
|
|
98
102
|
};
|
|
99
103
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
): AdkMessageContentPart =>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
mimeType
|
|
104
|
+
const mediaToContentPart = ({
|
|
105
|
+
inlineData,
|
|
106
|
+
fileData,
|
|
107
|
+
}: Record<string, unknown>): AdkMessageContentPart | undefined => {
|
|
108
|
+
if (isRecord(inlineData)) {
|
|
109
|
+
const { mimeType, data } = inlineData;
|
|
110
|
+
if (typeof mimeType !== "string" || typeof data !== "string") return;
|
|
111
|
+
return mimeType.startsWith("image/")
|
|
112
|
+
? { type: "image", mimeType, data }
|
|
113
|
+
: { type: "file", mimeType, data };
|
|
114
|
+
}
|
|
115
|
+
if (!isRecord(fileData)) return;
|
|
116
|
+
const { fileUri, mimeType } = fileData;
|
|
117
|
+
if (typeof fileUri !== "string") return;
|
|
118
|
+
return typeof mimeType !== "string" || mimeType.startsWith("image/")
|
|
113
119
|
? { type: "image_url", url: fileUri }
|
|
114
120
|
: { type: "file_url", url: fileUri, mimeType };
|
|
121
|
+
};
|
|
115
122
|
|
|
116
123
|
// ── Snake_case normalization ──
|
|
117
124
|
|
|
118
|
-
const normalizeEventPart = (part: AdkEventPart): AdkEventPart => {
|
|
119
|
-
const p = part as Record<string, unknown>;
|
|
120
|
-
const result: Record<string, unknown> = { ...p };
|
|
121
|
-
if ("function_call" in p && !("functionCall" in p))
|
|
122
|
-
result.functionCall = p.function_call;
|
|
123
|
-
if ("function_response" in p && !("functionResponse" in p))
|
|
124
|
-
result.functionResponse = p.function_response;
|
|
125
|
-
if ("inline_data" in p && !("inlineData" in p))
|
|
126
|
-
result.inlineData = p.inline_data;
|
|
127
|
-
if ("file_data" in p && !("fileData" in p)) result.fileData = p.file_data;
|
|
128
|
-
if ("executable_code" in p && !("executableCode" in p))
|
|
129
|
-
result.executableCode = p.executable_code;
|
|
130
|
-
if ("code_execution_result" in p && !("codeExecutionResult" in p))
|
|
131
|
-
result.codeExecutionResult = p.code_execution_result;
|
|
132
|
-
return result as AdkEventPart;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
125
|
const normalizeEvent = (event: AdkEvent): AdkEvent => {
|
|
136
126
|
const e = event as Record<string, unknown>;
|
|
137
127
|
const result: Record<string, unknown> = { ...e };
|
|
@@ -178,8 +168,8 @@ const normalizeEvent = (event: AdkEvent): AdkEvent => {
|
|
|
178
168
|
|
|
179
169
|
if (result.content && (result.content as Record<string, unknown>).parts) {
|
|
180
170
|
const content = result.content as Record<string, unknown>;
|
|
181
|
-
const parts = content.parts as
|
|
182
|
-
result.content = { ...content, parts: parts.map(
|
|
171
|
+
const parts = content.parts as Record<string, unknown>[];
|
|
172
|
+
result.content = { ...content, parts: parts.map(normalizeAdkPart) };
|
|
183
173
|
}
|
|
184
174
|
|
|
185
175
|
return result as AdkEvent;
|
|
@@ -203,19 +193,23 @@ export class AdkEventAccumulator {
|
|
|
203
193
|
} = {};
|
|
204
194
|
private lastTransferToAgent: string | undefined;
|
|
205
195
|
private pendingLongRunningToolIds = new Set<string>();
|
|
206
|
-
private toolConfirmations: AdkToolConfirmation[] = [];
|
|
207
|
-
private authRequests: AdkAuthRequest[] = [];
|
|
208
196
|
private escalated = false;
|
|
209
197
|
private messageMetadataMap = new Map<string, AdkMessageMetadata>();
|
|
210
198
|
// How many assistant messages each event has opened, so a replay of that
|
|
211
199
|
// event opens them with the same ids.
|
|
212
200
|
private aiMessageOrdinals = new Map<string, number>();
|
|
213
|
-
constructor(
|
|
201
|
+
constructor(
|
|
202
|
+
initialMessages?: AdkMessage[],
|
|
203
|
+
initialLongRunningToolIds?: readonly string[],
|
|
204
|
+
) {
|
|
214
205
|
if (initialMessages) {
|
|
215
206
|
for (const msg of initialMessages) {
|
|
216
207
|
this.messagesMap.set(msg.id, msg);
|
|
217
208
|
}
|
|
218
209
|
}
|
|
210
|
+
if (initialLongRunningToolIds) {
|
|
211
|
+
this.pendingLongRunningToolIds = new Set(initialLongRunningToolIds);
|
|
212
|
+
}
|
|
219
213
|
}
|
|
220
214
|
|
|
221
215
|
processEvent(rawEvent: AdkEvent): AdkMessage[] {
|
|
@@ -250,32 +244,6 @@ export class AdkEventAccumulator {
|
|
|
250
244
|
}
|
|
251
245
|
}
|
|
252
246
|
|
|
253
|
-
// Track tool confirmations from actions
|
|
254
|
-
if (event.actions?.requestedToolConfirmations) {
|
|
255
|
-
for (const [tcId, conf] of Object.entries(
|
|
256
|
-
event.actions.requestedToolConfirmations,
|
|
257
|
-
)) {
|
|
258
|
-
const c = conf as Record<string, unknown>;
|
|
259
|
-
this.toolConfirmations.push({
|
|
260
|
-
toolCallId: tcId,
|
|
261
|
-
toolName: "",
|
|
262
|
-
args: {},
|
|
263
|
-
hint: (c.hint as string) ?? "",
|
|
264
|
-
confirmed: false,
|
|
265
|
-
payload: c.payload,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Track auth requests from actions
|
|
271
|
-
if (event.actions?.requestedAuthConfigs) {
|
|
272
|
-
for (const [tcId, authConf] of Object.entries(
|
|
273
|
-
event.actions.requestedAuthConfigs,
|
|
274
|
-
)) {
|
|
275
|
-
this.authRequests.push({ toolCallId: tcId, authConfig: authConf });
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
247
|
// Track agent info
|
|
280
248
|
if (event.author && event.author !== "user") {
|
|
281
249
|
this.lastAgentInfo = {
|
|
@@ -338,14 +306,9 @@ export class AdkEventAccumulator {
|
|
|
338
306
|
for (const [index, part] of parts.entries()) {
|
|
339
307
|
if (part.text != null && !part.thought) {
|
|
340
308
|
humanParts.push({ type: "text", text: part.text });
|
|
341
|
-
} else if (part.inlineData) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
);
|
|
345
|
-
} else if (part.fileData) {
|
|
346
|
-
humanParts.push(
|
|
347
|
-
fileDataToPart(part.fileData.fileUri, part.fileData.mimeType),
|
|
348
|
-
);
|
|
309
|
+
} else if (part.inlineData || part.fileData) {
|
|
310
|
+
const mediaPart = mediaToContentPart(part);
|
|
311
|
+
if (mediaPart) humanParts.push(mediaPart);
|
|
349
312
|
} else if (part.functionResponse?.id) {
|
|
350
313
|
// ADK records tool confirmation and other client-supplied tool
|
|
351
314
|
// results as user-authored function responses, and its request
|
|
@@ -359,8 +322,12 @@ export class AdkEventAccumulator {
|
|
|
359
322
|
tool_call_id: part.functionResponse.id,
|
|
360
323
|
name: part.functionResponse.name,
|
|
361
324
|
content: JSON.stringify(part.functionResponse.response),
|
|
362
|
-
status:
|
|
325
|
+
status: isAdkFunctionError(part.functionResponse.response)
|
|
326
|
+
? "error"
|
|
327
|
+
: "success",
|
|
363
328
|
});
|
|
329
|
+
// Only a user-authored response settles a long-running call; the response ADK authors for one is the tool's interim result.
|
|
330
|
+
this.pendingLongRunningToolIds.delete(part.functionResponse.id);
|
|
364
331
|
}
|
|
365
332
|
}
|
|
366
333
|
// The replies answer the preceding assistant turn, so they are emitted
|
|
@@ -435,45 +402,6 @@ export class AdkEventAccumulator {
|
|
|
435
402
|
event: AdkEvent,
|
|
436
403
|
partIndex: number,
|
|
437
404
|
): void {
|
|
438
|
-
// Detect special ADK function calls
|
|
439
|
-
if (part.functionCall && !event.partial) {
|
|
440
|
-
const name = part.functionCall.name;
|
|
441
|
-
|
|
442
|
-
// Tool confirmation request
|
|
443
|
-
if (name === ADK_REQUEST_CONFIRMATION) {
|
|
444
|
-
const callArgs = part.functionCall.args;
|
|
445
|
-
// ADK JS: args keys are "originalFunctionCall" and "toolConfirmation"
|
|
446
|
-
// ADK Python: args keys are "original_function_call" and "tool_confirmation"
|
|
447
|
-
const original =
|
|
448
|
-
(callArgs.originalFunctionCall as Record<string, unknown>) ??
|
|
449
|
-
(callArgs.original_function_call as Record<string, unknown>);
|
|
450
|
-
const conf =
|
|
451
|
-
(callArgs.toolConfirmation as Record<string, unknown>) ??
|
|
452
|
-
(callArgs.tool_confirmation as Record<string, unknown>);
|
|
453
|
-
this.toolConfirmations.push({
|
|
454
|
-
toolCallId: part.functionCall.id ?? "",
|
|
455
|
-
toolName: (original?.name as string) ?? "",
|
|
456
|
-
args: (original?.args as Record<string, unknown>) ?? {},
|
|
457
|
-
hint: (conf?.hint as string) ?? "",
|
|
458
|
-
confirmed: false,
|
|
459
|
-
payload: conf?.payload,
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Auth credential request
|
|
464
|
-
if (name === ADK_REQUEST_CREDENTIAL) {
|
|
465
|
-
const credArgs = part.functionCall.args;
|
|
466
|
-
// ADK JS: args keys are "function_call_id" and "auth_config"
|
|
467
|
-
const originalToolCallId =
|
|
468
|
-
(credArgs.function_call_id as string) ?? part.functionCall.id ?? "";
|
|
469
|
-
const authConfig = credArgs.auth_config ?? credArgs;
|
|
470
|
-
this.authRequests.push({
|
|
471
|
-
toolCallId: originalToolCallId,
|
|
472
|
-
authConfig,
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
405
|
// Text with thought=true → reasoning (accumulated)
|
|
478
406
|
if (part.text != null && part.thought) {
|
|
479
407
|
const msg = this.getOrCreateAiMessage(event);
|
|
@@ -513,8 +441,8 @@ export class AdkEventAccumulator {
|
|
|
513
441
|
const toolCall: AdkToolCall = {
|
|
514
442
|
id: part.functionCall.id ?? generateId(),
|
|
515
443
|
name: part.functionCall.name,
|
|
516
|
-
args: part.functionCall.args as ReadonlyJSONObject,
|
|
517
|
-
argsText: JSON.stringify(part.functionCall.args),
|
|
444
|
+
args: (part.functionCall.args ?? {}) as ReadonlyJSONObject,
|
|
445
|
+
argsText: JSON.stringify(part.functionCall.args ?? {}),
|
|
518
446
|
};
|
|
519
447
|
const existing = [...(msg.tool_calls ?? [])];
|
|
520
448
|
const idx = existing.findIndex((tc) => tc.id === toolCall.id);
|
|
@@ -541,7 +469,9 @@ export class AdkEventAccumulator {
|
|
|
541
469
|
tool_call_id: part.functionResponse.id ?? "",
|
|
542
470
|
name: part.functionResponse.name,
|
|
543
471
|
content: JSON.stringify(part.functionResponse.response),
|
|
544
|
-
status:
|
|
472
|
+
status: isAdkFunctionError(part.functionResponse.response)
|
|
473
|
+
? "error"
|
|
474
|
+
: "success",
|
|
545
475
|
};
|
|
546
476
|
this.messagesMap.set(toolMsg.id, toolMsg);
|
|
547
477
|
return;
|
|
@@ -569,22 +499,10 @@ export class AdkEventAccumulator {
|
|
|
569
499
|
return;
|
|
570
500
|
}
|
|
571
501
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
inlineDataToPart(part.inlineData.mimeType, part.inlineData.data),
|
|
577
|
-
);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (part.fileData) {
|
|
582
|
-
const msg = this.getOrCreateAiMessage(event);
|
|
583
|
-
this.appendContent(
|
|
584
|
-
msg,
|
|
585
|
-
fileDataToPart(part.fileData.fileUri, part.fileData.mimeType),
|
|
586
|
-
);
|
|
587
|
-
}
|
|
502
|
+
const mediaPart = mediaToContentPart(part);
|
|
503
|
+
if (!mediaPart) return;
|
|
504
|
+
const msg = this.getOrCreateAiMessage(event);
|
|
505
|
+
this.appendContent(msg, mediaPart);
|
|
588
506
|
}
|
|
589
507
|
|
|
590
508
|
private trackMessageMetadata(event: AdkEvent): void {
|
|
@@ -679,6 +597,18 @@ export class AdkEventAccumulator {
|
|
|
679
597
|
this.currentMessageId = null;
|
|
680
598
|
}
|
|
681
599
|
|
|
600
|
+
// ADK resumes a confirmation or credential request only on a reply that quotes its synthetic call's id, so those calls are the whole record; requestedToolConfirmations and requestedAuthConfigs key the gated call instead, which no reply answers.
|
|
601
|
+
private getRequestCalls(name: string): AdkToolCall[] {
|
|
602
|
+
const calls = new Map<string, AdkToolCall>();
|
|
603
|
+
for (const msg of this.messagesMap.values()) {
|
|
604
|
+
if (msg.type !== "ai") continue;
|
|
605
|
+
for (const call of msg.tool_calls ?? []) {
|
|
606
|
+
if (call.name === name && !calls.has(call.id)) calls.set(call.id, call);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return [...calls.values()];
|
|
610
|
+
}
|
|
611
|
+
|
|
682
612
|
getMessages(): AdkMessage[] {
|
|
683
613
|
return [...this.messagesMap.values()];
|
|
684
614
|
}
|
|
@@ -704,11 +634,36 @@ export class AdkEventAccumulator {
|
|
|
704
634
|
}
|
|
705
635
|
|
|
706
636
|
getToolConfirmations(): AdkToolConfirmation[] {
|
|
707
|
-
|
|
637
|
+
const { approvals } = projectAdkToolApprovals(this.getMessages());
|
|
638
|
+
return this.getRequestCalls(ADK_REQUEST_CONFIRMATION)
|
|
639
|
+
.filter(({ id }) => approvals.get(id)?.approved === undefined)
|
|
640
|
+
.map(({ id, args = {} }) => {
|
|
641
|
+
const original = (args.originalFunctionCall ??
|
|
642
|
+
args.original_function_call) as Record<string, unknown> | undefined;
|
|
643
|
+
const confirmation = (args.toolConfirmation ??
|
|
644
|
+
args.tool_confirmation) as Record<string, unknown> | undefined;
|
|
645
|
+
return {
|
|
646
|
+
toolCallId: id,
|
|
647
|
+
toolName: (original?.name as string) ?? "",
|
|
648
|
+
args: (original?.args as Record<string, unknown>) ?? {},
|
|
649
|
+
hint: (confirmation?.hint as string) ?? "",
|
|
650
|
+
confirmed: false,
|
|
651
|
+
payload: confirmation?.payload,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
708
654
|
}
|
|
709
655
|
|
|
710
656
|
getAuthRequests(): AdkAuthRequest[] {
|
|
711
|
-
|
|
657
|
+
const answered = new Set<string>();
|
|
658
|
+
for (const msg of this.messagesMap.values()) {
|
|
659
|
+
if (msg.type === "tool") answered.add(msg.tool_call_id);
|
|
660
|
+
}
|
|
661
|
+
return this.getRequestCalls(ADK_REQUEST_CREDENTIAL)
|
|
662
|
+
.filter(({ id }) => !answered.has(id))
|
|
663
|
+
.map(({ id, args = {} }) => ({
|
|
664
|
+
toolCallId: id,
|
|
665
|
+
authConfig: args.auth_config ?? args.authConfig,
|
|
666
|
+
}));
|
|
712
667
|
}
|
|
713
668
|
|
|
714
669
|
isEscalated(): boolean {
|