@assistant-ui/react-google-adk 0.0.21 → 0.0.22
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adkEventStream.d.ts","names":[],"sources":["../../src/server/adkEventStream.ts"],"mappings":";;;;KAKK;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ,MAAM;;EAEhB,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB;;KAyEP;EACV,WAAW;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"adkEventStream.d.ts","names":[],"sources":["../../src/server/adkEventStream.ts"],"mappings":";;;;KAKK;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ,MAAM;;EAEhB,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB;;KAyEP;EACV,WAAW;;;;;;;;;;;;cA4BA,iBACX,QAAQ,eAAe,+BACvB,UAAU,0BACT"}
|
|
@@ -48,6 +48,16 @@ const convertSdkEvent = (event) => {
|
|
|
48
48
|
if (event.customMetadata != null) result.customMetadata = event.customMetadata;
|
|
49
49
|
return result;
|
|
50
50
|
};
|
|
51
|
+
const reportCallbackError = (error) => {
|
|
52
|
+
console.error("[react-google-adk] onError callback threw an error", error);
|
|
53
|
+
};
|
|
54
|
+
const notifyError = (callback, error) => {
|
|
55
|
+
try {
|
|
56
|
+
Promise.resolve(callback?.(error)).catch(reportCallbackError);
|
|
57
|
+
} catch (callbackError) {
|
|
58
|
+
reportCallbackError(callbackError);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
51
61
|
/**
|
|
52
62
|
* Converts an AsyncGenerator of ADK SDK Events into an SSE Response.
|
|
53
63
|
*
|
|
@@ -72,7 +82,7 @@ const adkEventStream = (events, options) => {
|
|
|
72
82
|
}
|
|
73
83
|
} catch (e) {
|
|
74
84
|
if (!cancelled) {
|
|
75
|
-
options?.onError
|
|
85
|
+
notifyError(options?.onError, e);
|
|
76
86
|
const errorEvent = {
|
|
77
87
|
id: "",
|
|
78
88
|
errorCode: "STREAM_ERROR",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adkEventStream.js","names":[],"sources":["../../src/server/adkEventStream.ts"],"sourcesContent":["import type { AdkEvent, AdkEventActions, AdkEventPart } from \"../types\";\n\n/**\n * The ADK SDK Event type. Intentionally loose to avoid requiring @google/adk.\n */\ntype AdkSdkEvent = {\n id?: string;\n invocationId?: string;\n author?: string;\n branch?: string;\n partial?: boolean;\n turnComplete?: boolean;\n interrupted?: boolean;\n finishReason?: string;\n timestamp?: number;\n content?: {\n role?: string;\n parts?: Array<Record<string, unknown>>;\n };\n actions?: Record<string, unknown>;\n longRunningToolIds?: string[];\n errorCode?: string;\n errorMessage?: string;\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n customMetadata?: Record<string, unknown>;\n};\n\nconst convertSdkPart = (part: Record<string, unknown>): AdkEventPart => {\n const result: Record<string, unknown> = {};\n if (\"text\" in part && typeof part.text === \"string\") result.text = part.text;\n if (\"thought\" in part && typeof part.thought === \"boolean\")\n result.thought = part.thought;\n if (\"functionCall\" in part && part.functionCall)\n result.functionCall = part.functionCall;\n if (\"functionResponse\" in part && part.functionResponse)\n result.functionResponse = part.functionResponse;\n if (\"executableCode\" in part && part.executableCode)\n result.executableCode = part.executableCode;\n if (\"codeExecutionResult\" in part && part.codeExecutionResult)\n result.codeExecutionResult = part.codeExecutionResult;\n if (\"inlineData\" in part && part.inlineData)\n result.inlineData = part.inlineData;\n if (\"fileData\" in part && part.fileData) result.fileData = part.fileData;\n return result as AdkEventPart;\n};\n\nconst convertSdkActions = (\n actions: Record<string, unknown>,\n): AdkEventActions => {\n const result: Record<string, unknown> = {};\n if (actions.stateDelta != null) result.stateDelta = actions.stateDelta;\n if (actions.artifactDelta != null)\n result.artifactDelta = actions.artifactDelta;\n if (actions.transferToAgent != null)\n result.transferToAgent = actions.transferToAgent;\n if (actions.escalate != null) result.escalate = actions.escalate;\n if (actions.skipSummarization != null)\n result.skipSummarization = actions.skipSummarization;\n if (actions.requestedAuthConfigs != null)\n result.requestedAuthConfigs = actions.requestedAuthConfigs;\n if (actions.requestedToolConfirmations != null)\n result.requestedToolConfirmations = actions.requestedToolConfirmations;\n return result as AdkEventActions;\n};\n\nconst convertSdkEvent = (event: AdkSdkEvent): AdkEvent => {\n const result: Record<string, unknown> = { id: event.id ?? \"\" };\n if (event.invocationId != null) result.invocationId = event.invocationId;\n if (event.author != null) result.author = event.author;\n if (event.branch != null) result.branch = event.branch;\n if (event.partial != null) result.partial = event.partial;\n if (event.turnComplete != null) result.turnComplete = event.turnComplete;\n if (event.interrupted != null) result.interrupted = event.interrupted;\n if (event.finishReason != null) result.finishReason = event.finishReason;\n if (event.timestamp != null) result.timestamp = event.timestamp;\n if (event.content) {\n const content: Record<string, unknown> = {};\n if (event.content.role != null) content.role = event.content.role;\n if (event.content.parts)\n content.parts = event.content.parts.map(convertSdkPart);\n result.content = content;\n }\n if (event.actions) result.actions = convertSdkActions(event.actions);\n if (event.longRunningToolIds)\n result.longRunningToolIds = event.longRunningToolIds;\n if (event.errorCode != null) result.errorCode = event.errorCode;\n if (event.errorMessage != null) result.errorMessage = event.errorMessage;\n if (event.groundingMetadata != null)\n result.groundingMetadata = event.groundingMetadata;\n if (event.citationMetadata != null)\n result.citationMetadata = event.citationMetadata;\n if (event.usageMetadata != null) result.usageMetadata = event.usageMetadata;\n if (event.customMetadata != null)\n result.customMetadata = event.customMetadata;\n return result as AdkEvent;\n};\n\nexport type AdkEventStreamOptions = {\n onError?: (error: unknown) => void;\n};\n\n/**\n * Converts an AsyncGenerator of ADK SDK Events into an SSE Response.\n *\n * @example\n * ```ts\n * import { adkEventStream } from '@assistant-ui/react-google-adk/server';\n * const events = runner.runAsync({ userId, sessionId, newMessage });\n * return adkEventStream(events);\n * ```\n */\nexport const adkEventStream = (\n events: AsyncGenerator<AdkSdkEvent, void, undefined>,\n options?: AdkEventStreamOptions,\n): Response => {\n const encoder = new TextEncoder();\n let cancelled = false;\n const stream = new ReadableStream({\n async start(controller) {\n // Initial SSE comment to keep connection alive through proxies\n controller.enqueue(encoder.encode(\":ok\\n\\n\"));\n try {\n for await (const event of events) {\n if (cancelled) break;\n const wireEvent = convertSdkEvent(event);\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify(wireEvent)}\\n\\n`),\n );\n }\n } catch (e) {\n if (!cancelled) {\n options?.onError
|
|
1
|
+
{"version":3,"file":"adkEventStream.js","names":[],"sources":["../../src/server/adkEventStream.ts"],"sourcesContent":["import type { AdkEvent, AdkEventActions, AdkEventPart } from \"../types\";\n\n/**\n * The ADK SDK Event type. Intentionally loose to avoid requiring @google/adk.\n */\ntype AdkSdkEvent = {\n id?: string;\n invocationId?: string;\n author?: string;\n branch?: string;\n partial?: boolean;\n turnComplete?: boolean;\n interrupted?: boolean;\n finishReason?: string;\n timestamp?: number;\n content?: {\n role?: string;\n parts?: Array<Record<string, unknown>>;\n };\n actions?: Record<string, unknown>;\n longRunningToolIds?: string[];\n errorCode?: string;\n errorMessage?: string;\n groundingMetadata?: unknown;\n citationMetadata?: unknown;\n usageMetadata?: unknown;\n customMetadata?: Record<string, unknown>;\n};\n\nconst convertSdkPart = (part: Record<string, unknown>): AdkEventPart => {\n const result: Record<string, unknown> = {};\n if (\"text\" in part && typeof part.text === \"string\") result.text = part.text;\n if (\"thought\" in part && typeof part.thought === \"boolean\")\n result.thought = part.thought;\n if (\"functionCall\" in part && part.functionCall)\n result.functionCall = part.functionCall;\n if (\"functionResponse\" in part && part.functionResponse)\n result.functionResponse = part.functionResponse;\n if (\"executableCode\" in part && part.executableCode)\n result.executableCode = part.executableCode;\n if (\"codeExecutionResult\" in part && part.codeExecutionResult)\n result.codeExecutionResult = part.codeExecutionResult;\n if (\"inlineData\" in part && part.inlineData)\n result.inlineData = part.inlineData;\n if (\"fileData\" in part && part.fileData) result.fileData = part.fileData;\n return result as AdkEventPart;\n};\n\nconst convertSdkActions = (\n actions: Record<string, unknown>,\n): AdkEventActions => {\n const result: Record<string, unknown> = {};\n if (actions.stateDelta != null) result.stateDelta = actions.stateDelta;\n if (actions.artifactDelta != null)\n result.artifactDelta = actions.artifactDelta;\n if (actions.transferToAgent != null)\n result.transferToAgent = actions.transferToAgent;\n if (actions.escalate != null) result.escalate = actions.escalate;\n if (actions.skipSummarization != null)\n result.skipSummarization = actions.skipSummarization;\n if (actions.requestedAuthConfigs != null)\n result.requestedAuthConfigs = actions.requestedAuthConfigs;\n if (actions.requestedToolConfirmations != null)\n result.requestedToolConfirmations = actions.requestedToolConfirmations;\n return result as AdkEventActions;\n};\n\nconst convertSdkEvent = (event: AdkSdkEvent): AdkEvent => {\n const result: Record<string, unknown> = { id: event.id ?? \"\" };\n if (event.invocationId != null) result.invocationId = event.invocationId;\n if (event.author != null) result.author = event.author;\n if (event.branch != null) result.branch = event.branch;\n if (event.partial != null) result.partial = event.partial;\n if (event.turnComplete != null) result.turnComplete = event.turnComplete;\n if (event.interrupted != null) result.interrupted = event.interrupted;\n if (event.finishReason != null) result.finishReason = event.finishReason;\n if (event.timestamp != null) result.timestamp = event.timestamp;\n if (event.content) {\n const content: Record<string, unknown> = {};\n if (event.content.role != null) content.role = event.content.role;\n if (event.content.parts)\n content.parts = event.content.parts.map(convertSdkPart);\n result.content = content;\n }\n if (event.actions) result.actions = convertSdkActions(event.actions);\n if (event.longRunningToolIds)\n result.longRunningToolIds = event.longRunningToolIds;\n if (event.errorCode != null) result.errorCode = event.errorCode;\n if (event.errorMessage != null) result.errorMessage = event.errorMessage;\n if (event.groundingMetadata != null)\n result.groundingMetadata = event.groundingMetadata;\n if (event.citationMetadata != null)\n result.citationMetadata = event.citationMetadata;\n if (event.usageMetadata != null) result.usageMetadata = event.usageMetadata;\n if (event.customMetadata != null)\n result.customMetadata = event.customMetadata;\n return result as AdkEvent;\n};\n\nexport type AdkEventStreamOptions = {\n onError?: (error: unknown) => void;\n};\n\nconst reportCallbackError = (error: unknown) => {\n console.error(\"[react-google-adk] onError callback threw an error\", error);\n};\n\nconst notifyError = (\n callback: AdkEventStreamOptions[\"onError\"],\n error: unknown,\n) => {\n try {\n void Promise.resolve(callback?.(error)).catch(reportCallbackError);\n } catch (callbackError) {\n reportCallbackError(callbackError);\n }\n};\n\n/**\n * Converts an AsyncGenerator of ADK SDK Events into an SSE Response.\n *\n * @example\n * ```ts\n * import { adkEventStream } from '@assistant-ui/react-google-adk/server';\n * const events = runner.runAsync({ userId, sessionId, newMessage });\n * return adkEventStream(events);\n * ```\n */\nexport const adkEventStream = (\n events: AsyncGenerator<AdkSdkEvent, void, undefined>,\n options?: AdkEventStreamOptions,\n): Response => {\n const encoder = new TextEncoder();\n let cancelled = false;\n const stream = new ReadableStream({\n async start(controller) {\n // Initial SSE comment to keep connection alive through proxies\n controller.enqueue(encoder.encode(\":ok\\n\\n\"));\n try {\n for await (const event of events) {\n if (cancelled) break;\n const wireEvent = convertSdkEvent(event);\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify(wireEvent)}\\n\\n`),\n );\n }\n } catch (e) {\n if (!cancelled) {\n notifyError(options?.onError, e);\n const errorEvent: AdkEvent = {\n id: \"\",\n errorCode: \"STREAM_ERROR\",\n errorMessage:\n e instanceof Error ? e.message : \"Unknown stream error\",\n };\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify(errorEvent)}\\n\\n`),\n );\n }\n } finally {\n controller.close();\n }\n },\n async cancel() {\n cancelled = true;\n await events.return?.(undefined as any);\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n },\n });\n};\n"],"mappings":";AA6BA,MAAM,kBAAkB,SAAgD;CACtE,MAAM,SAAkC,CAAC;CACzC,IAAI,UAAU,QAAQ,OAAO,KAAK,SAAS,UAAU,OAAO,OAAO,KAAK;CACxE,IAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,WAC/C,OAAO,UAAU,KAAK;CACxB,IAAI,kBAAkB,QAAQ,KAAK,cACjC,OAAO,eAAe,KAAK;CAC7B,IAAI,sBAAsB,QAAQ,KAAK,kBACrC,OAAO,mBAAmB,KAAK;CACjC,IAAI,oBAAoB,QAAQ,KAAK,gBACnC,OAAO,iBAAiB,KAAK;CAC/B,IAAI,yBAAyB,QAAQ,KAAK,qBACxC,OAAO,sBAAsB,KAAK;CACpC,IAAI,gBAAgB,QAAQ,KAAK,YAC/B,OAAO,aAAa,KAAK;CAC3B,IAAI,cAAc,QAAQ,KAAK,UAAU,OAAO,WAAW,KAAK;CAChE,OAAO;AACT;AAEA,MAAM,qBACJ,YACoB;CACpB,MAAM,SAAkC,CAAC;CACzC,IAAI,QAAQ,cAAc,MAAM,OAAO,aAAa,QAAQ;CAC5D,IAAI,QAAQ,iBAAiB,MAC3B,OAAO,gBAAgB,QAAQ;CACjC,IAAI,QAAQ,mBAAmB,MAC7B,OAAO,kBAAkB,QAAQ;CACnC,IAAI,QAAQ,YAAY,MAAM,OAAO,WAAW,QAAQ;CACxD,IAAI,QAAQ,qBAAqB,MAC/B,OAAO,oBAAoB,QAAQ;CACrC,IAAI,QAAQ,wBAAwB,MAClC,OAAO,uBAAuB,QAAQ;CACxC,IAAI,QAAQ,8BAA8B,MACxC,OAAO,6BAA6B,QAAQ;CAC9C,OAAO;AACT;AAEA,MAAM,mBAAmB,UAAiC;CACxD,MAAM,SAAkC,EAAE,IAAI,MAAM,MAAM,GAAG;CAC7D,IAAI,MAAM,gBAAgB,MAAM,OAAO,eAAe,MAAM;CAC5D,IAAI,MAAM,UAAU,MAAM,OAAO,SAAS,MAAM;CAChD,IAAI,MAAM,UAAU,MAAM,OAAO,SAAS,MAAM;CAChD,IAAI,MAAM,WAAW,MAAM,OAAO,UAAU,MAAM;CAClD,IAAI,MAAM,gBAAgB,MAAM,OAAO,eAAe,MAAM;CAC5D,IAAI,MAAM,eAAe,MAAM,OAAO,cAAc,MAAM;CAC1D,IAAI,MAAM,gBAAgB,MAAM,OAAO,eAAe,MAAM;CAC5D,IAAI,MAAM,aAAa,MAAM,OAAO,YAAY,MAAM;CACtD,IAAI,MAAM,SAAS;EACjB,MAAM,UAAmC,CAAC;EAC1C,IAAI,MAAM,QAAQ,QAAQ,MAAM,QAAQ,OAAO,MAAM,QAAQ;EAC7D,IAAI,MAAM,QAAQ,OAChB,QAAQ,QAAQ,MAAM,QAAQ,MAAM,IAAI,cAAc;EACxD,OAAO,UAAU;CACnB;CACA,IAAI,MAAM,SAAS,OAAO,UAAU,kBAAkB,MAAM,OAAO;CACnE,IAAI,MAAM,oBACR,OAAO,qBAAqB,MAAM;CACpC,IAAI,MAAM,aAAa,MAAM,OAAO,YAAY,MAAM;CACtD,IAAI,MAAM,gBAAgB,MAAM,OAAO,eAAe,MAAM;CAC5D,IAAI,MAAM,qBAAqB,MAC7B,OAAO,oBAAoB,MAAM;CACnC,IAAI,MAAM,oBAAoB,MAC5B,OAAO,mBAAmB,MAAM;CAClC,IAAI,MAAM,iBAAiB,MAAM,OAAO,gBAAgB,MAAM;CAC9D,IAAI,MAAM,kBAAkB,MAC1B,OAAO,iBAAiB,MAAM;CAChC,OAAO;AACT;AAMA,MAAM,uBAAuB,UAAmB;CAC9C,QAAQ,MAAM,sDAAsD,KAAK;AAC3E;AAEA,MAAM,eACJ,UACA,UACG;CACH,IAAI;EACF,QAAa,QAAQ,WAAW,KAAK,CAAC,CAAC,CAAC,MAAM,mBAAmB;CACnE,SAAS,eAAe;EACtB,oBAAoB,aAAa;CACnC;AACF;;;;;;;;;;;AAYA,MAAa,kBACX,QACA,YACa;CACb,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,YAAY;CAChB,MAAM,SAAS,IAAI,eAAe;EAChC,MAAM,MAAM,YAAY;GAEtB,WAAW,QAAQ,QAAQ,OAAO,SAAS,CAAC;GAC5C,IAAI;IACF,WAAW,MAAM,SAAS,QAAQ;KAChC,IAAI,WAAW;KACf,MAAM,YAAY,gBAAgB,KAAK;KACvC,WAAW,QACT,QAAQ,OAAO,SAAS,KAAK,UAAU,SAAS,EAAE,KAAK,CACzD;IACF;GACF,SAAS,GAAG;IACV,IAAI,CAAC,WAAW;KACd,YAAY,SAAS,SAAS,CAAC;KAC/B,MAAM,aAAuB;MAC3B,IAAI;MACJ,WAAW;MACX,cACE,aAAa,QAAQ,EAAE,UAAU;KACrC;KACA,WAAW,QACT,QAAQ,OAAO,SAAS,KAAK,UAAU,UAAU,EAAE,KAAK,CAC1D;IACF;GACF,UAAU;IACR,WAAW,MAAM;GACnB;EACF;EACA,MAAM,SAAS;GACb,YAAY;GACZ,MAAM,OAAO,SAAS,KAAA,CAAgB;EACxC;CACF,CAAC;CAED,OAAO,IAAI,SAAS,QAAQ,EAC1B,SAAS;EACP,gBAAgB;EAChB,iBAAiB;CACnB,EACF,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-google-adk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "Google ADK adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"google-adk",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
],
|
|
35
35
|
"sideEffects": false,
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@assistant-ui/core": "^0.3.
|
|
38
|
-
"@assistant-ui/store": "^0.3.
|
|
37
|
+
"@assistant-ui/core": "^0.3.6",
|
|
38
|
+
"@assistant-ui/store": "^0.3.4",
|
|
39
39
|
"assistant-cloud": "*",
|
|
40
|
-
"assistant-stream": "^0.3.
|
|
40
|
+
"assistant-stream": "^0.3.34",
|
|
41
41
|
"uuid": "^14.0.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"jsdom": "^29.1.1",
|
|
62
62
|
"react": "^19.2.8",
|
|
63
63
|
"vitest": "^4.1.10",
|
|
64
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
64
|
+
"@assistant-ui/x-buildutils": "0.0.21"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public",
|
|
@@ -73,4 +73,42 @@ describe("adkEventStream", () => {
|
|
|
73
73
|
await readSSE(response);
|
|
74
74
|
expect(onError).toHaveBeenCalledTimes(1);
|
|
75
75
|
});
|
|
76
|
+
|
|
77
|
+
it.each([
|
|
78
|
+
[
|
|
79
|
+
"throws",
|
|
80
|
+
() => {
|
|
81
|
+
throw new Error("callback failed");
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"rejects",
|
|
86
|
+
async () => {
|
|
87
|
+
throw new Error("callback failed");
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
])(
|
|
91
|
+
"still emits the stream error when onError %s",
|
|
92
|
+
async (_behavior, onError) => {
|
|
93
|
+
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
94
|
+
async function* throwingGen() {
|
|
95
|
+
throw new Error("stream failed");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const response = adkEventStream(throwingGen() as any, { onError });
|
|
100
|
+
const text = await readSSE(response);
|
|
101
|
+
await vi.waitFor(() => expect(errorSpy).toHaveBeenCalledTimes(1));
|
|
102
|
+
|
|
103
|
+
const lines = text.split("\n\n").filter((l) => l.startsWith("data: "));
|
|
104
|
+
expect(lines).toHaveLength(1);
|
|
105
|
+
expect(JSON.parse(lines[0]!.slice(6))).toMatchObject({
|
|
106
|
+
errorCode: "STREAM_ERROR",
|
|
107
|
+
errorMessage: "stream failed",
|
|
108
|
+
});
|
|
109
|
+
} finally {
|
|
110
|
+
errorSpy.mockRestore();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
);
|
|
76
114
|
});
|
|
@@ -101,6 +101,21 @@ export type AdkEventStreamOptions = {
|
|
|
101
101
|
onError?: (error: unknown) => void;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
const reportCallbackError = (error: unknown) => {
|
|
105
|
+
console.error("[react-google-adk] onError callback threw an error", error);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const notifyError = (
|
|
109
|
+
callback: AdkEventStreamOptions["onError"],
|
|
110
|
+
error: unknown,
|
|
111
|
+
) => {
|
|
112
|
+
try {
|
|
113
|
+
void Promise.resolve(callback?.(error)).catch(reportCallbackError);
|
|
114
|
+
} catch (callbackError) {
|
|
115
|
+
reportCallbackError(callbackError);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
104
119
|
/**
|
|
105
120
|
* Converts an AsyncGenerator of ADK SDK Events into an SSE Response.
|
|
106
121
|
*
|
|
@@ -131,7 +146,7 @@ export const adkEventStream = (
|
|
|
131
146
|
}
|
|
132
147
|
} catch (e) {
|
|
133
148
|
if (!cancelled) {
|
|
134
|
-
options?.onError
|
|
149
|
+
notifyError(options?.onError, e);
|
|
135
150
|
const errorEvent: AdkEvent = {
|
|
136
151
|
id: "",
|
|
137
152
|
errorCode: "STREAM_ERROR",
|