@assistant-ui/react-google-adk 0.0.10 → 0.0.11
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 +15 -128
- package/dist/AdkClient.d.ts +30 -26
- package/dist/AdkClient.d.ts.map +1 -1
- package/dist/AdkClient.js +131 -165
- package/dist/AdkClient.js.map +1 -1
- package/dist/AdkEventAccumulator.d.ts +43 -39
- package/dist/AdkEventAccumulator.d.ts.map +1 -1
- package/dist/AdkEventAccumulator.js +446 -531
- package/dist/AdkEventAccumulator.js.map +1 -1
- package/dist/AdkSessionAdapter.d.ts +40 -37
- package/dist/AdkSessionAdapter.d.ts.map +1 -1
- package/dist/AdkSessionAdapter.js +134 -155
- package/dist/AdkSessionAdapter.js.map +1 -1
- package/dist/contentToParts.d.ts +6 -2
- package/dist/contentToParts.d.ts.map +1 -1
- package/dist/contentToParts.js +37 -34
- package/dist/contentToParts.js.map +1 -1
- package/dist/convertAdkMessages.d.ts +7 -3
- package/dist/convertAdkMessages.d.ts.map +1 -1
- package/dist/convertAdkMessages.js +93 -86
- package/dist/convertAdkMessages.js.map +1 -1
- package/dist/hooks.d.ts +38 -34
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +132 -155
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +10 -11
- package/dist/index.js +10 -10
- package/dist/server/adkEventStream.d.ts +27 -25
- package/dist/server/adkEventStream.d.ts.map +1 -1
- package/dist/server/adkEventStream.js +91 -126
- package/dist/server/adkEventStream.js.map +1 -1
- package/dist/server/createAdkApiRoute.d.ts +26 -23
- package/dist/server/createAdkApiRoute.d.ts.map +1 -1
- package/dist/server/createAdkApiRoute.js +34 -37
- package/dist/server/createAdkApiRoute.js.map +1 -1
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +4 -4
- package/dist/server/parseAdkRequest.d.ts +21 -18
- package/dist/server/parseAdkRequest.d.ts.map +1 -1
- package/dist/server/parseAdkRequest.js +80 -88
- package/dist/server/parseAdkRequest.js.map +1 -1
- package/dist/structuredEvents.d.ts +6 -2
- package/dist/structuredEvents.d.ts.map +1 -1
- package/dist/structuredEvents.js +70 -75
- package/dist/structuredEvents.js.map +1 -1
- package/dist/types.d.ts +231 -227
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -12
- package/dist/types.js.map +1 -1
- package/dist/useAdkMessages.d.ts +32 -25
- package/dist/useAdkMessages.d.ts.map +1 -1
- package/dist/useAdkMessages.js +155 -182
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts +43 -34
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +219 -273
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +8 -8
- package/src/useAdkRuntime.ts +6 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@assistant-ui/react-google-adk`
|
|
2
2
|
|
|
3
|
-
Google ADK (Agent Development Kit)
|
|
4
|
-
|
|
5
|
-
Connects Google ADK JS agents to assistant-ui's React runtime with streaming, tool calls, multi-agent support, tool confirmations, auth flows, and session state management.
|
|
3
|
+
[Google ADK](https://github.com/google/adk-js) (Agent Development Kit) integration for `@assistant-ui/react`. Connects ADK JS agents to the assistant-ui runtime with streaming, tool calls, multi-agent support, tool confirmations, auth flows, and session-state management.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
|
-
```
|
|
10
|
-
npm install @assistant-ui/react @assistant-ui/react-google-adk
|
|
7
|
+
```bash
|
|
8
|
+
npm install @assistant-ui/react @assistant-ui/react-google-adk @google/adk
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
### Proxy Mode (with a Next.js API Route)
|
|
11
|
+
## Usage
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
The recommended setup proxies through your own API route:
|
|
18
14
|
|
|
19
|
-
```
|
|
15
|
+
```ts
|
|
16
|
+
// app/api/adk/route.ts
|
|
20
17
|
import { createAdkApiRoute } from "@assistant-ui/react-google-adk/server";
|
|
21
18
|
import { runner } from "./agent";
|
|
22
19
|
|
|
23
20
|
export const POST = createAdkApiRoute({
|
|
24
21
|
runner,
|
|
25
22
|
userId: "default-user",
|
|
26
|
-
sessionId: (req) =>
|
|
27
|
-
new URL(req.url).searchParams.get("sessionId") ?? "default",
|
|
23
|
+
sessionId: (req) => new URL(req.url).searchParams.get("sessionId") ?? "default",
|
|
28
24
|
});
|
|
29
25
|
```
|
|
30
26
|
|
|
31
|
-
**Client:**
|
|
32
|
-
|
|
33
27
|
```tsx
|
|
28
|
+
// client component
|
|
34
29
|
import { useAdkRuntime, createAdkStream } from "@assistant-ui/react-google-adk";
|
|
35
30
|
|
|
36
31
|
const runtime = useAdkRuntime({
|
|
@@ -38,119 +33,11 @@ const runtime = useAdkRuntime({
|
|
|
38
33
|
});
|
|
39
34
|
```
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import {
|
|
45
|
-
useAdkRuntime,
|
|
46
|
-
createAdkStream,
|
|
47
|
-
createAdkSessionAdapter,
|
|
48
|
-
} from "@assistant-ui/react-google-adk";
|
|
49
|
-
|
|
50
|
-
const { adapter, load } = createAdkSessionAdapter({
|
|
51
|
-
apiUrl: "http://localhost:8000",
|
|
52
|
-
appName: "my-app",
|
|
53
|
-
userId: "user-1",
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const runtime = useAdkRuntime({
|
|
57
|
-
stream: createAdkStream({
|
|
58
|
-
api: "http://localhost:8000",
|
|
59
|
-
appName: "my-app",
|
|
60
|
-
userId: "user-1",
|
|
61
|
-
}),
|
|
62
|
-
sessionAdapter: adapter,
|
|
63
|
-
load,
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## API Reference
|
|
68
|
-
|
|
69
|
-
### Client Exports
|
|
70
|
-
|
|
71
|
-
#### `createAdkStream(options)`
|
|
72
|
-
|
|
73
|
-
Creates an `AdkStreamCallback` that connects to an ADK endpoint via SSE.
|
|
74
|
-
|
|
75
|
-
| Option | Type | Description |
|
|
76
|
-
|--------|------|-------------|
|
|
77
|
-
| `api` | `string` | URL to POST to (proxy route or ADK server base URL) |
|
|
78
|
-
| `appName` | `string?` | ADK app name (enables direct mode when set) |
|
|
79
|
-
| `userId` | `string?` | ADK user ID (required with `appName`) |
|
|
80
|
-
| `headers` | `Record<string, string> \| (() => ...)` | Static or dynamic request headers |
|
|
81
|
-
|
|
82
|
-
#### `createAdkSessionAdapter(options)`
|
|
83
|
-
|
|
84
|
-
Creates a `RemoteThreadListAdapter` backed by ADK's session REST API.
|
|
85
|
-
|
|
86
|
-
Returns `{ adapter, load }` where `load` reconstructs messages from session events.
|
|
87
|
-
|
|
88
|
-
| Option | Type | Description |
|
|
89
|
-
|--------|------|-------------|
|
|
90
|
-
| `apiUrl` | `string` | ADK server base URL |
|
|
91
|
-
| `appName` | `string` | ADK app name |
|
|
92
|
-
| `userId` | `string` | ADK user ID |
|
|
93
|
-
| `headers` | `Record<string, string> \| (() => ...)` | Static or dynamic request headers |
|
|
94
|
-
|
|
95
|
-
#### `useAdkRuntime(options)`
|
|
96
|
-
|
|
97
|
-
Main hook that creates a full `AssistantRuntime`.
|
|
98
|
-
|
|
99
|
-
| Option | Type | Description |
|
|
100
|
-
|--------|------|-------------|
|
|
101
|
-
| `stream` | `AdkStreamCallback` | Stream callback (use `createAdkStream`) |
|
|
102
|
-
| `sessionAdapter` | `RemoteThreadListAdapter?` | Alternative to `cloud` for thread persistence |
|
|
103
|
-
| `cloud` | `AssistantCloud?` | Cloud adapter for thread persistence |
|
|
104
|
-
| `load` | `(threadId: string) => Promise<{messages}>` | Load thread history |
|
|
105
|
-
| `autoCancelPendingToolCalls` | `boolean?` | Auto-cancel pending tools on new message (default: true) |
|
|
106
|
-
| `unstable_allowCancellation` | `boolean?` | Enable stream cancellation |
|
|
107
|
-
| `getCheckpointId` | `(threadId, messages) => Promise<string?>` | Enable edit/reload |
|
|
108
|
-
| `adapters` | `{attachments?, speech?, feedback?}` | Optional adapters |
|
|
109
|
-
| `eventHandlers` | `{onError?, onCustomEvent?, onAgentTransfer?}` | Event callbacks |
|
|
110
|
-
|
|
111
|
-
### Hooks
|
|
112
|
-
|
|
113
|
-
| Hook | Description |
|
|
114
|
-
|------|-------------|
|
|
115
|
-
| `useAdkAgentInfo()` | Current agent name and branch path |
|
|
116
|
-
| `useAdkSessionState()` | Accumulated session state delta |
|
|
117
|
-
| `useAdkSend()` | Send raw ADK messages |
|
|
118
|
-
| `useAdkLongRunningToolIds()` | Pending tool IDs awaiting input |
|
|
119
|
-
| `useAdkToolConfirmations()` | Tool confirmation requests |
|
|
120
|
-
| `useAdkAuthRequests()` | Auth credential requests |
|
|
121
|
-
| `useAdkArtifacts()` | Artifact delta (filename → version) |
|
|
122
|
-
| `useAdkEscalation()` | Escalation flag |
|
|
123
|
-
| `useAdkMessageMetadata()` | Per-message grounding/citation/usage |
|
|
124
|
-
|
|
125
|
-
### Server Exports (`/server`)
|
|
126
|
-
|
|
127
|
-
#### `createAdkApiRoute(options)`
|
|
128
|
-
|
|
129
|
-
One-liner API route handler combining request parsing and SSE streaming.
|
|
130
|
-
|
|
131
|
-
| Option | Type | Description |
|
|
132
|
-
|--------|------|-------------|
|
|
133
|
-
| `runner` | `AdkRunner` | ADK Runner instance |
|
|
134
|
-
| `userId` | `string \| (req) => string` | Static or dynamic user ID |
|
|
135
|
-
| `sessionId` | `string \| (req) => string` | Static or dynamic session ID |
|
|
136
|
-
| `onError` | `(error) => void` | Error handler |
|
|
137
|
-
|
|
138
|
-
#### `adkEventStream(events, options?)`
|
|
139
|
-
|
|
140
|
-
Converts an ADK event async generator into an SSE `Response`.
|
|
141
|
-
|
|
142
|
-
#### `parseAdkRequest(request)`
|
|
143
|
-
|
|
144
|
-
Parses an incoming HTTP request into a structured ADK request.
|
|
145
|
-
|
|
146
|
-
#### `toAdkContent(parsed)`
|
|
147
|
-
|
|
148
|
-
Converts a parsed request into a Google GenAI `Content` object.
|
|
149
|
-
|
|
150
|
-
## Documentation
|
|
36
|
+
Or connect directly to an ADK server with `createAdkSessionAdapter`; see the docs for the full setup and option reference.
|
|
151
37
|
|
|
152
|
-
See
|
|
38
|
+
## See also
|
|
153
39
|
|
|
154
|
-
|
|
40
|
+
- `@assistant-ui/react-langgraph` for LangGraph SDK agents.
|
|
41
|
+
- `@assistant-ui/react-ag-ui` for the AG-UI protocol.
|
|
155
42
|
|
|
156
|
-
|
|
43
|
+
Full reference for client hooks (`useAdkAgentInfo`, `useAdkSessionState`, `useAdkToolConfirmations`, `useAdkAuthRequests`, etc.), server exports, and direct mode at [assistant-ui.com/docs/runtimes/google-adk](https://www.assistant-ui.com/docs/runtimes/google-adk).
|
package/dist/AdkClient.d.ts
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
import { AdkStreamCallback } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/AdkClient.d.ts
|
|
4
|
+
type CreateAdkStreamOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* URL to POST to. Either a proxy route (e.g. "/api/adk") or
|
|
7
|
+
* an ADK server base URL (e.g. "http://localhost:8000").
|
|
8
|
+
*
|
|
9
|
+
* When `appName` and `userId` are provided, POSTs to `${api}/run_sse`
|
|
10
|
+
* in ADK-native format. Otherwise POSTs directly to `api` in proxy format
|
|
11
|
+
* (compatible with `parseAdkRequest`).
|
|
12
|
+
*/
|
|
13
|
+
api: string;
|
|
14
|
+
/**
|
|
15
|
+
* ADK application name. When provided along with `userId`,
|
|
16
|
+
* enables direct connection to an ADK server.
|
|
17
|
+
*/
|
|
18
|
+
appName?: string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* ADK user ID. Required when `appName` is provided.
|
|
21
|
+
*/
|
|
22
|
+
userId?: string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Extra headers to send with every request.
|
|
25
|
+
* Can be a static object or an async function for dynamic auth tokens.
|
|
26
|
+
*/
|
|
27
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>) | undefined;
|
|
26
28
|
};
|
|
27
29
|
/**
|
|
28
30
|
* Creates an `AdkStreamCallback` that connects to an ADK endpoint.
|
|
@@ -41,5 +43,7 @@ export type CreateAdkStreamOptions = {
|
|
|
41
43
|
* });
|
|
42
44
|
* ```
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
declare function createAdkStream(options: CreateAdkStreamOptions): AdkStreamCallback;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { CreateAdkStreamOptions, createAdkStream };
|
|
45
49
|
//# sourceMappingURL=AdkClient.d.ts.map
|
package/dist/AdkClient.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkClient.d.ts","
|
|
1
|
+
{"version":3,"file":"AdkClient.d.ts","names":[],"sources":["../src/AdkClient.ts"],"mappings":";;;KAQY,sBAAA;;AAAZ;;;;;;;EASE,GAAA;EAmB2C;;;;EAb3C,OAAA;EAYI;;;EAPJ,MAAA;EAQkD;AAAA;AAqBpD;;EAvBE,OAAA,GACI,MAAA,0BACO,MAAA,mBAAyB,OAAA,CAAQ,MAAA;AAAA;;;;;AAuB1B;;;;;;;;;;;;;iBAFJ,eAAA,CACd,OAAA,EAAS,sBAAA,GACR,iBAAiB"}
|
package/dist/AdkClient.js
CHANGED
|
@@ -1,179 +1,145 @@
|
|
|
1
1
|
import { contentToParts } from "./contentToParts.js";
|
|
2
|
+
//#region src/AdkClient.ts
|
|
2
3
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
yield* parseSSEResponse(response);
|
|
53
|
-
};
|
|
4
|
+
* Creates an `AdkStreamCallback` that connects to an ADK endpoint.
|
|
5
|
+
*
|
|
6
|
+
* @example Proxy mode (with a Next.js API route)
|
|
7
|
+
* ```ts
|
|
8
|
+
* const stream = createAdkStream({ api: "/api/adk" });
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* @example Direct mode (connecting to ADK server)
|
|
12
|
+
* ```ts
|
|
13
|
+
* const stream = createAdkStream({
|
|
14
|
+
* api: "http://localhost:8000",
|
|
15
|
+
* appName: "my-app",
|
|
16
|
+
* userId: "user-1",
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function createAdkStream(options) {
|
|
21
|
+
const isDirect = options.appName != null;
|
|
22
|
+
return async function* (messages, config) {
|
|
23
|
+
const headers = await resolveHeaders(options.headers);
|
|
24
|
+
let url;
|
|
25
|
+
let body;
|
|
26
|
+
if (isDirect) {
|
|
27
|
+
url = `${options.api}/run_sse`;
|
|
28
|
+
const { externalId } = await config.initialize();
|
|
29
|
+
body = {
|
|
30
|
+
appName: options.appName,
|
|
31
|
+
userId: options.userId,
|
|
32
|
+
sessionId: externalId,
|
|
33
|
+
newMessage: messagesToContent(messages),
|
|
34
|
+
streaming: true,
|
|
35
|
+
...config.stateDelta != null && { stateDelta: config.stateDelta }
|
|
36
|
+
};
|
|
37
|
+
} else {
|
|
38
|
+
url = options.api;
|
|
39
|
+
body = messagesToProxyBody(messages, config);
|
|
40
|
+
}
|
|
41
|
+
const response = await fetch(url, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
...headers
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify(body),
|
|
48
|
+
signal: config.abortSignal
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) throw new Error(`ADK request failed: ${response.status} ${response.statusText}`);
|
|
51
|
+
yield* parseSSEResponse(response);
|
|
52
|
+
};
|
|
54
53
|
}
|
|
55
|
-
// ── Internal helpers ──
|
|
56
54
|
async function resolveHeaders(headers) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return await headers();
|
|
61
|
-
return headers;
|
|
55
|
+
if (!headers) return {};
|
|
56
|
+
if (typeof headers === "function") return await headers();
|
|
57
|
+
return headers;
|
|
62
58
|
}
|
|
63
59
|
/**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
* Converts AdkMessage[] (new messages) into ADK Content format
|
|
61
|
+
* for the direct `/run_sse` endpoint.
|
|
62
|
+
*/
|
|
67
63
|
function messagesToContent(messages) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (parts.length === 0) {
|
|
93
|
-
parts.push({ text: "" });
|
|
94
|
-
}
|
|
95
|
-
return { role: "user", parts };
|
|
64
|
+
const parts = [];
|
|
65
|
+
for (const msg of messages) if (msg.type === "human") for (const part of contentToParts(msg.content)) parts.push(part);
|
|
66
|
+
else if (msg.type === "tool") {
|
|
67
|
+
let response;
|
|
68
|
+
try {
|
|
69
|
+
response = JSON.parse(msg.content);
|
|
70
|
+
} catch {
|
|
71
|
+
response = msg.content;
|
|
72
|
+
}
|
|
73
|
+
parts.push({ functionResponse: {
|
|
74
|
+
name: msg.name,
|
|
75
|
+
id: msg.tool_call_id,
|
|
76
|
+
response
|
|
77
|
+
} });
|
|
78
|
+
}
|
|
79
|
+
if (parts.length === 0) parts.push({ text: "" });
|
|
80
|
+
return {
|
|
81
|
+
role: "user",
|
|
82
|
+
parts
|
|
83
|
+
};
|
|
96
84
|
}
|
|
97
85
|
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
* Converts AdkMessage[] into the proxy request body format
|
|
87
|
+
* (compatible with `parseAdkRequest`).
|
|
88
|
+
*/
|
|
101
89
|
function messagesToProxyBody(messages, config) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const msg = messages[0];
|
|
134
|
-
if (typeof msg.content === "string") {
|
|
135
|
-
body.message = msg.content;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
body.parts = contentToParts(msg.content);
|
|
139
|
-
}
|
|
140
|
-
return body;
|
|
141
|
-
}
|
|
142
|
-
// Multiple messages (e.g. cancellations + human): send as parts array
|
|
143
|
-
body.parts = messagesToContent(messages).parts;
|
|
144
|
-
return body;
|
|
90
|
+
const body = {};
|
|
91
|
+
if (config.runConfig != null) body.runConfig = config.runConfig;
|
|
92
|
+
if (config.checkpointId != null) body.checkpointId = config.checkpointId;
|
|
93
|
+
if (config.stateDelta != null) body.stateDelta = config.stateDelta;
|
|
94
|
+
const toolMsg = messages.find((m) => m.type === "tool");
|
|
95
|
+
if (toolMsg && toolMsg.type === "tool") {
|
|
96
|
+
if (messages.length > 1) {
|
|
97
|
+
body.parts = messagesToContent(messages).parts;
|
|
98
|
+
return body;
|
|
99
|
+
}
|
|
100
|
+
let result;
|
|
101
|
+
try {
|
|
102
|
+
result = JSON.parse(toolMsg.content);
|
|
103
|
+
} catch {
|
|
104
|
+
result = toolMsg.content;
|
|
105
|
+
}
|
|
106
|
+
body.type = "tool-result";
|
|
107
|
+
body.toolCallId = toolMsg.tool_call_id;
|
|
108
|
+
body.toolName = toolMsg.name;
|
|
109
|
+
body.result = result;
|
|
110
|
+
body.isError = toolMsg.status === "error";
|
|
111
|
+
return body;
|
|
112
|
+
}
|
|
113
|
+
if (messages.length === 1 && messages[0].type === "human") {
|
|
114
|
+
const msg = messages[0];
|
|
115
|
+
if (typeof msg.content === "string") body.message = msg.content;
|
|
116
|
+
else body.parts = contentToParts(msg.content);
|
|
117
|
+
return body;
|
|
118
|
+
}
|
|
119
|
+
body.parts = messagesToContent(messages).parts;
|
|
120
|
+
return body;
|
|
145
121
|
}
|
|
146
122
|
async function* parseSSEResponse(response) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
// Handle remaining buffer
|
|
167
|
-
if (buffer.trim()) {
|
|
168
|
-
for (const line of buffer.split("\n")) {
|
|
169
|
-
if (line.startsWith("data: ")) {
|
|
170
|
-
yield JSON.parse(line.slice(6));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
finally {
|
|
176
|
-
reader.releaseLock();
|
|
177
|
-
}
|
|
123
|
+
const reader = response.body.getReader();
|
|
124
|
+
const decoder = new TextDecoder();
|
|
125
|
+
let buffer = "";
|
|
126
|
+
try {
|
|
127
|
+
while (true) {
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done) break;
|
|
130
|
+
buffer += decoder.decode(value, { stream: true });
|
|
131
|
+
const parts = buffer.split("\n\n");
|
|
132
|
+
buffer = parts.pop() ?? "";
|
|
133
|
+
for (const part of parts) for (const line of part.split("\n")) if (line.startsWith("data: ")) yield JSON.parse(line.slice(6));
|
|
134
|
+
}
|
|
135
|
+
if (buffer.trim()) {
|
|
136
|
+
for (const line of buffer.split("\n")) if (line.startsWith("data: ")) yield JSON.parse(line.slice(6));
|
|
137
|
+
}
|
|
138
|
+
} finally {
|
|
139
|
+
reader.releaseLock();
|
|
140
|
+
}
|
|
178
141
|
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { createAdkStream };
|
|
144
|
+
|
|
179
145
|
//# sourceMappingURL=AdkClient.js.map
|
package/dist/AdkClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdkClient.js","
|
|
1
|
+
{"version":3,"file":"AdkClient.js","names":[],"sources":["../src/AdkClient.ts"],"sourcesContent":["import { contentToParts } from \"./contentToParts\";\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 const isDirect = options.appName != null;\n\n return async function* (messages, config) {\n const headers = await resolveHeaders(options.headers);\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 = `${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 yield* parseSSEResponse(response);\n };\n}\n\n// ── Internal helpers ──\n\nasync function resolveHeaders(\n headers:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>)\n | undefined,\n): Promise<Record<string, string>> {\n if (!headers) return {};\n if (typeof headers === \"function\") return await headers();\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,\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 const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop() ?? \"\";\n\n for (const part of parts) {\n for (const line of part.split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n yield JSON.parse(line.slice(6)) as AdkEvent;\n }\n }\n }\n }\n\n // Handle remaining buffer\n if (buffer.trim()) {\n for (const line of buffer.split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n yield JSON.parse(line.slice(6)) as AdkEvent;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":"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"}
|