@copilotkit/runtime 1.56.5-canary.1777972218 → 1.57.0
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/agent/index.cjs +8 -41
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +27 -54
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +27 -54
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +10 -43
- package/dist/agent/index.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/v2/index.cjs +0 -2
- package/dist/v2/index.d.cts +5 -6
- package/dist/v2/index.d.mts +5 -6
- package/dist/v2/index.mjs +1 -2
- package/dist/v2/runtime/core/runtime.d.cts +0 -1
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +0 -1
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +0 -4
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +0 -4
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -3
- package/dist/v2/runtime/index.d.cts.map +1 -1
- package/dist/v2/runtime/index.d.mts +1 -3
- package/dist/v2/runtime/index.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +0 -53
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +0 -41
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +0 -41
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +0 -53
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/package.json +2 -2
- package/src/agent/__tests__/mcp-clients.test.ts +25 -11
- package/src/agent/__tests__/mcp-servers-integration.test.ts +1 -485
- package/src/agent/index.ts +62 -139
- package/src/v2/runtime/handlers/intelligence/run.ts +0 -9
- package/src/v2/runtime/handlers/shared/agent-utils.ts +0 -1
- package/src/v2/runtime/index.ts +0 -5
- package/src/v2/runtime/intelligence-platform/client.ts +0 -68
- package/dist/agent/mcp-transport.cjs +0 -94
- package/dist/agent/mcp-transport.cjs.map +0 -1
- package/dist/agent/mcp-transport.d.cts +0 -51
- package/dist/agent/mcp-transport.d.cts.map +0 -1
- package/dist/agent/mcp-transport.d.mts +0 -52
- package/dist/agent/mcp-transport.d.mts.map +0 -1
- package/dist/agent/mcp-transport.mjs +0 -92
- package/dist/agent/mcp-transport.mjs.map +0 -1
- package/dist/v2/runtime/intelligence-platform/index.d.cts +0 -2
- package/dist/v2/runtime/intelligence-platform/index.d.mts +0 -2
- package/src/agent/mcp-transport.ts +0 -190
- package/src/v2/runtime/intelligence-platform/__tests__/intelligence-mcp-helper.test.ts +0 -190
package/src/agent/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
AbstractAgent,
|
|
2
3
|
BaseEvent,
|
|
3
4
|
RunAgentInput,
|
|
5
|
+
EventType,
|
|
4
6
|
Message,
|
|
5
7
|
ReasoningEndEvent,
|
|
6
8
|
ReasoningMessageContentEvent,
|
|
@@ -18,9 +20,9 @@ import type {
|
|
|
18
20
|
StateSnapshotEvent,
|
|
19
21
|
StateDeltaEvent,
|
|
20
22
|
} from "@ag-ui/client";
|
|
21
|
-
import { AbstractAgent, EventType } from "@ag-ui/client";
|
|
22
23
|
import type { AgentCapabilities } from "@ag-ui/core";
|
|
23
|
-
import
|
|
24
|
+
import {
|
|
25
|
+
streamText,
|
|
24
26
|
LanguageModel,
|
|
25
27
|
ModelMessage,
|
|
26
28
|
AssistantModelMessage,
|
|
@@ -32,31 +34,29 @@ import type {
|
|
|
32
34
|
TextPart,
|
|
33
35
|
ImagePart,
|
|
34
36
|
FilePart,
|
|
37
|
+
tool as createVercelAISDKTool,
|
|
35
38
|
ToolChoice,
|
|
36
39
|
ToolSet,
|
|
40
|
+
stepCountIs,
|
|
37
41
|
} from "ai";
|
|
38
|
-
import {
|
|
39
|
-
import { createMCPClient } from "@ai-sdk/mcp";
|
|
40
|
-
import type { MCPClient } from "@ai-sdk/mcp";
|
|
42
|
+
import { experimental_createMCPClient as createMCPClient } from "@ai-sdk/mcp";
|
|
41
43
|
import { Observable } from "rxjs";
|
|
42
44
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
43
45
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
44
46
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
45
47
|
import { createVertex } from "@ai-sdk/google-vertex";
|
|
46
|
-
import {
|
|
48
|
+
import { safeParseToolArgs } from "@copilotkit/shared";
|
|
47
49
|
import { z } from "zod";
|
|
48
50
|
import type { StandardSchemaV1, InferSchemaOutput } from "@copilotkit/shared";
|
|
49
51
|
import { schemaToJsonSchema } from "@copilotkit/shared";
|
|
50
52
|
import { jsonSchema as aiJsonSchema } from "ai";
|
|
51
53
|
import { convertAISDKStream } from "./converters/aisdk";
|
|
52
54
|
import { convertTanStackStream } from "./converters/tanstack";
|
|
53
|
-
import type { StreamableHTTPClientTransportOptions } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
54
55
|
import {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} from "./mcp-transport";
|
|
56
|
+
StreamableHTTPClientTransport,
|
|
57
|
+
StreamableHTTPClientTransportOptions,
|
|
58
|
+
} from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
59
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
60
60
|
import { randomUUID } from "@copilotkit/shared";
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -113,114 +113,58 @@ export type BuiltInAgentModel =
|
|
|
113
113
|
*/
|
|
114
114
|
export type ModelSpecifier = string | LanguageModel;
|
|
115
115
|
|
|
116
|
-
// MCPRequestContext and MCPHeaderResolverError now live in mcp-transport.ts.
|
|
117
|
-
// Re-export so existing imports of these symbols from agent/index continue to
|
|
118
|
-
// work.
|
|
119
|
-
export { MCPHeaderResolverError, type MCPRequestContext };
|
|
120
|
-
|
|
121
116
|
/**
|
|
122
|
-
* MCP Client configuration for HTTP transport
|
|
117
|
+
* MCP Client configuration for HTTP transport
|
|
123
118
|
*/
|
|
124
119
|
export interface MCPClientConfigHTTP {
|
|
125
|
-
/** Type of MCP client */
|
|
126
|
-
type: "http";
|
|
127
|
-
/** URL of the MCP server */
|
|
128
|
-
url: string;
|
|
129
120
|
/**
|
|
130
|
-
*
|
|
131
|
-
* `StreamableHTTPClientTransport`. Pre-existing escape hatch for advanced
|
|
132
|
-
* use cases (custom `fetch`, `requestInit`, OAuth `authProvider`, etc.).
|
|
121
|
+
* Type of MCP client
|
|
133
122
|
*/
|
|
134
|
-
|
|
123
|
+
type: "http";
|
|
135
124
|
/**
|
|
136
|
-
*
|
|
137
|
-
* For per-call values, use {@link MCPClientConfigHTTP.getHeaders} instead.
|
|
125
|
+
* URL of the MCP server
|
|
138
126
|
*/
|
|
139
|
-
|
|
127
|
+
url: string;
|
|
140
128
|
/**
|
|
141
|
-
*
|
|
142
|
-
* this server (initialize, tools/list, tools/call, SSE reconnects). The
|
|
143
|
-
* returned headers are merged on top of `headers` and any
|
|
144
|
-
* `options.requestInit.headers`, so a resolver can override either.
|
|
145
|
-
*
|
|
146
|
-
* Throwing from the resolver causes the agent run to emit `RUN_ERROR`
|
|
147
|
-
* carrying a {@link MCPHeaderResolverError}.
|
|
129
|
+
* Optional transport options for HTTP client
|
|
148
130
|
*/
|
|
149
|
-
|
|
150
|
-
ctx: MCPRequestContext,
|
|
151
|
-
) => Record<string, string> | Promise<Record<string, string>>;
|
|
152
|
-
/** If true, the server is skipped at run-start when `agent.user` is unset. */
|
|
153
|
-
requiresUser?: boolean;
|
|
131
|
+
options?: StreamableHTTPClientTransportOptions;
|
|
154
132
|
}
|
|
155
133
|
|
|
156
134
|
/**
|
|
157
|
-
* MCP Client configuration for SSE transport
|
|
135
|
+
* MCP Client configuration for SSE transport
|
|
158
136
|
*/
|
|
159
137
|
export interface MCPClientConfigSSE {
|
|
160
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Type of MCP client
|
|
140
|
+
*/
|
|
161
141
|
type: "sse";
|
|
162
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* URL of the MCP server
|
|
144
|
+
*/
|
|
163
145
|
url: string;
|
|
164
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Optional HTTP headers (e.g., for authentication)
|
|
148
|
+
*/
|
|
165
149
|
headers?: Record<string, string>;
|
|
166
150
|
}
|
|
167
151
|
|
|
168
152
|
/**
|
|
169
|
-
* MCP Client configuration
|
|
153
|
+
* MCP Client configuration
|
|
170
154
|
*/
|
|
171
155
|
export type MCPClientConfig = MCPClientConfigHTTP | MCPClientConfigSSE;
|
|
172
156
|
|
|
173
157
|
/**
|
|
174
|
-
* A user-managed MCP client that provides tools to the agent.
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* for tests/caching layers.
|
|
178
|
-
*
|
|
179
|
-
* Unlike `mcpServers`, the agent does NOT create or close these clients. The
|
|
180
|
-
* user controls the full lifecycle.
|
|
181
|
-
*/
|
|
182
|
-
export type MCPClientProvider = Pick<MCPClient, "tools">;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Open an MCP client for the given server config.
|
|
158
|
+
* A user-managed MCP client that provides tools to the agent.
|
|
159
|
+
* The user is responsible for creating, configuring, and closing the client.
|
|
160
|
+
* Compatible with the return type of @ai-sdk/mcp's createMCPClient().
|
|
186
161
|
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* resolution).
|
|
190
|
-
* - SSE goes through `@ai-sdk/mcp`'s `createMCPClient`, whose built-in
|
|
191
|
-
* `SseMCPTransport` correctly applies static `headers` on every outbound
|
|
192
|
-
* request.
|
|
162
|
+
* Unlike mcpServers, the agent does NOT create or close these clients.
|
|
163
|
+
* This allows persistent connections, custom auth, and tool caching.
|
|
193
164
|
*/
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
requestHeaders: Record<string, string>;
|
|
198
|
-
input: RunAgentInput;
|
|
199
|
-
user?: MCPRuntimeUser;
|
|
200
|
-
},
|
|
201
|
-
): Promise<MCPClient> {
|
|
202
|
-
if (config.type === "http") {
|
|
203
|
-
const transport = new CopilotKitMCPTransport({
|
|
204
|
-
url: config.url,
|
|
205
|
-
headers: config.headers,
|
|
206
|
-
getHeaders: config.getHeaders,
|
|
207
|
-
options: config.options,
|
|
208
|
-
requestHeaders: context.requestHeaders,
|
|
209
|
-
input: context.input,
|
|
210
|
-
user: context.user,
|
|
211
|
-
});
|
|
212
|
-
return createMCPClient({ transport });
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// SSE: hand to Vercel's transport. Static `headers` are applied via the
|
|
216
|
-
// SseMCPTransport's common-header pipeline.
|
|
217
|
-
return createMCPClient({
|
|
218
|
-
transport: {
|
|
219
|
-
type: "sse",
|
|
220
|
-
url: config.url,
|
|
221
|
-
headers: config.headers,
|
|
222
|
-
},
|
|
223
|
-
});
|
|
165
|
+
export interface MCPClientProvider {
|
|
166
|
+
/** Return tools to be merged into the agent's tool set. */
|
|
167
|
+
tools(): Promise<ToolSet>;
|
|
224
168
|
}
|
|
225
169
|
|
|
226
170
|
/**
|
|
@@ -907,21 +851,6 @@ function isFactoryConfig(
|
|
|
907
851
|
|
|
908
852
|
export class BuiltInAgent extends AbstractAgent {
|
|
909
853
|
private abortController?: AbortController;
|
|
910
|
-
/**
|
|
911
|
-
* Headers populated per-request by the runtime's
|
|
912
|
-
* `extractForwardableHeaders` (the incoming request's `Authorization` +
|
|
913
|
-
* every `x-*` header, lower-cased). Available to MCP header resolvers via
|
|
914
|
-
* {@link MCPRequestContext.requestHeaders}; kept here as a plain field so
|
|
915
|
-
* the runtime's `configureAgentForRequest` feature-detect activates.
|
|
916
|
-
*/
|
|
917
|
-
public headers: Record<string, string> = {};
|
|
918
|
-
/**
|
|
919
|
-
* End-user identity for the current request, populated by the runtime by
|
|
920
|
-
* invoking `identifyUser(request)` (Intelligence mode). Surfaced to MCP
|
|
921
|
-
* header resolvers via {@link MCPRequestContext.user}; remains undefined
|
|
922
|
-
* for runs that aren't going through a runtime with `identifyUser` set.
|
|
923
|
-
*/
|
|
924
|
-
public user?: { id: string; name: string };
|
|
925
854
|
|
|
926
855
|
constructor(private config: BuiltInAgentConfiguration) {
|
|
927
856
|
super();
|
|
@@ -1175,7 +1104,7 @@ export class BuiltInAgent extends AbstractAgent {
|
|
|
1175
1104
|
}
|
|
1176
1105
|
|
|
1177
1106
|
// Set up MCP clients if configured and process the stream
|
|
1178
|
-
const mcpClients:
|
|
1107
|
+
const mcpClients: Array<{ close: () => Promise<void> }> = [];
|
|
1179
1108
|
|
|
1180
1109
|
(async () => {
|
|
1181
1110
|
let terminalEventEmitted = false;
|
|
@@ -1260,39 +1189,33 @@ export class BuiltInAgent extends AbstractAgent {
|
|
|
1260
1189
|
|
|
1261
1190
|
// Initialize MCP clients and get their tools
|
|
1262
1191
|
if (this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
1263
|
-
// Snapshot the agent's per-run state (forwarded headers + user)
|
|
1264
|
-
// once at run-start. Resolvers see this immutable snapshot for the
|
|
1265
|
-
// lifetime of the run, including any reconnections fired after the
|
|
1266
|
-
// initial run completes.
|
|
1267
|
-
const requestHeaders: Record<string, string> = { ...this.headers };
|
|
1268
|
-
const user = this.user ? { ...this.user } : undefined;
|
|
1269
|
-
|
|
1270
1192
|
for (const serverConfig of this.config.mcpServers) {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1193
|
+
let transport;
|
|
1194
|
+
|
|
1195
|
+
if (serverConfig.type === "http") {
|
|
1196
|
+
const url = new URL(serverConfig.url);
|
|
1197
|
+
transport = new StreamableHTTPClientTransport(
|
|
1198
|
+
url,
|
|
1199
|
+
serverConfig.options,
|
|
1200
|
+
);
|
|
1201
|
+
} else if (serverConfig.type === "sse") {
|
|
1202
|
+
transport = new SSEClientTransport(
|
|
1203
|
+
new URL(serverConfig.url),
|
|
1204
|
+
serverConfig.headers,
|
|
1279
1205
|
);
|
|
1280
|
-
continue;
|
|
1281
1206
|
}
|
|
1282
1207
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
user,
|
|
1287
|
-
});
|
|
1288
|
-
mcpClients.push(mcpClient);
|
|
1208
|
+
if (transport) {
|
|
1209
|
+
const mcpClient = await createMCPClient({ transport });
|
|
1210
|
+
mcpClients.push(mcpClient);
|
|
1289
1211
|
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1212
|
+
// Get tools from this MCP server and merge with existing tools
|
|
1213
|
+
const mcpTools = await mcpClient.tools();
|
|
1214
|
+
streamTextParams.tools = {
|
|
1215
|
+
...streamTextParams.tools,
|
|
1216
|
+
...mcpTools,
|
|
1217
|
+
} as ToolSet;
|
|
1218
|
+
}
|
|
1296
1219
|
}
|
|
1297
1220
|
}
|
|
1298
1221
|
|
|
@@ -80,15 +80,6 @@ export async function handleIntelligenceRun({
|
|
|
80
80
|
}
|
|
81
81
|
const userId = user.id;
|
|
82
82
|
|
|
83
|
-
// Surface the resolved user on the agent so MCP header resolvers (and any
|
|
84
|
-
// other per-run consumer) can read it via context. Snapshotted by the
|
|
85
|
-
// BuiltInAgent at run-start; runs that don't go through this Intelligence
|
|
86
|
-
// path leave `agent.user` undefined.
|
|
87
|
-
(agent as unknown as { user?: { id: string; name: string } }).user = {
|
|
88
|
-
id: user.id,
|
|
89
|
-
name: user.name,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
83
|
try {
|
|
93
84
|
const { thread, created } = await runtime.intelligence.getOrCreateThread({
|
|
94
85
|
threadId: input.threadId,
|
|
@@ -13,7 +13,6 @@ import { logger } from "@copilotkit/shared";
|
|
|
13
13
|
type MiddlewareCapableAgent = AbstractAgent & {
|
|
14
14
|
use?: (middleware: unknown) => void;
|
|
15
15
|
headers?: Record<string, string>;
|
|
16
|
-
user?: { id: string; name: string };
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
export interface RunAgentParameters {
|
package/src/v2/runtime/index.ts
CHANGED
|
@@ -19,11 +19,6 @@ export {
|
|
|
19
19
|
type UpdateThreadRequest,
|
|
20
20
|
} from "./intelligence-platform";
|
|
21
21
|
|
|
22
|
-
// Re-export `@ai-sdk/mcp` stable types so consumers don't need to depend on
|
|
23
|
-
// it directly to type their MCP wiring. `MCPClient` is the value users pass
|
|
24
|
-
// into `mcpClients`; `MCPTransport` is the contract for custom transports.
|
|
25
|
-
export type { MCPClient, MCPTransport } from "@ai-sdk/mcp";
|
|
26
|
-
|
|
27
22
|
// Export framework-agnostic fetch handler
|
|
28
23
|
export { createCopilotRuntimeHandler } from "./core/fetch-handler";
|
|
29
24
|
export type {
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import { logger } from "@copilotkit/shared";
|
|
2
|
-
import type { MCPClientConfigHTTP } from "../../../agent";
|
|
3
|
-
|
|
4
|
-
// Header name carrying the per-call end-user identity that the CopilotKit
|
|
5
|
-
// Intelligence `/mcp` endpoint requires. Encapsulated inside the helper so
|
|
6
|
-
// users of `intelligence.toMCPServer()` never need to know the wire-level
|
|
7
|
-
// header name — they configure `identifyUser` once on the runtime and the
|
|
8
|
-
// helper does the rest.
|
|
9
|
-
const INTELLIGENCE_USER_ID_HEADER = "x-cpki-user-id";
|
|
10
2
|
|
|
11
3
|
/**
|
|
12
4
|
* Error thrown when an Intelligence platform HTTP request returns a non-2xx
|
|
@@ -382,66 +374,6 @@ export class CopilotKitIntelligence {
|
|
|
382
374
|
return this.#apiKey;
|
|
383
375
|
}
|
|
384
376
|
|
|
385
|
-
/**
|
|
386
|
-
* Build an MCP-server config pre-wired for this Intelligence platform
|
|
387
|
-
* connection. Drop the result into a `BuiltInAgent`'s `mcpServers` to give
|
|
388
|
-
* the agent access to Intel's bash + thread tools with both auth axes
|
|
389
|
-
* correctly populated:
|
|
390
|
-
*
|
|
391
|
-
* - `Authorization: Bearer <apiKey>` is stamped on every outbound request
|
|
392
|
-
* from this Intelligence client's project key.
|
|
393
|
-
* - `X-Cpki-User-Id` is read fresh per call from the agent's resolved user,
|
|
394
|
-
* which is populated by the runtime's `identifyUser` callback. The
|
|
395
|
-
* helper does not surface the header name to user code.
|
|
396
|
-
*
|
|
397
|
-
* @example
|
|
398
|
-
* ```ts
|
|
399
|
-
* const intelligence = new CopilotKitIntelligence({
|
|
400
|
-
* apiUrl: "https://api.copilotkit.ai",
|
|
401
|
-
* wsUrl: "wss://api.copilotkit.ai",
|
|
402
|
-
* apiKey: process.env.INTELLIGENCE_API_KEY!,
|
|
403
|
-
* });
|
|
404
|
-
*
|
|
405
|
-
* const runtime = new CopilotRuntime({
|
|
406
|
-
* intelligence,
|
|
407
|
-
* identifyUser: (request) => resolveUserFromSession(request),
|
|
408
|
-
* agents: {
|
|
409
|
-
* myAgent: new BuiltInAgent({
|
|
410
|
-
* model: "openai/gpt-4o",
|
|
411
|
-
* mcpServers: [intelligence.toMCPServer()],
|
|
412
|
-
* }),
|
|
413
|
-
* },
|
|
414
|
-
* });
|
|
415
|
-
* ```
|
|
416
|
-
*
|
|
417
|
-
* The resolver throws if no user is present — typically the runtime is
|
|
418
|
-
* misconfigured (no `identifyUser`) or `identifyUser` returned an invalid
|
|
419
|
-
* id. Silent fallthrough to an empty user-id would collapse every browser
|
|
420
|
-
* session for this project into one shared bash sandbox, which is the
|
|
421
|
-
* very isolation guarantee the per-call header exists to enforce.
|
|
422
|
-
*/
|
|
423
|
-
toMCPServer(): MCPClientConfigHTTP {
|
|
424
|
-
const apiKey = this.#apiKey;
|
|
425
|
-
const url = `${this.#apiUrl}/mcp`;
|
|
426
|
-
return {
|
|
427
|
-
type: "http",
|
|
428
|
-
url,
|
|
429
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
430
|
-
requiresUser: true,
|
|
431
|
-
getHeaders: ({ user }) => {
|
|
432
|
-
const userId = user?.id?.trim();
|
|
433
|
-
if (!userId) {
|
|
434
|
-
throw new Error(
|
|
435
|
-
"CopilotKitIntelligence.toMCPServer(): no user resolved for this run. " +
|
|
436
|
-
"Configure `identifyUser` on the CopilotRuntime so the agent " +
|
|
437
|
-
"knows which end-user each MCP call is on behalf of.",
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
return { [INTELLIGENCE_USER_ID_HEADER]: userId };
|
|
441
|
-
},
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
377
|
async #request<T>(method: string, path: string, body?: unknown): Promise<T> {
|
|
446
378
|
const url = `${this.#apiUrl}${path}`;
|
|
447
379
|
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
require("reflect-metadata");
|
|
2
|
-
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
-
let _modelcontextprotocol_sdk_client_streamableHttp_js = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
4
|
-
|
|
5
|
-
//#region src/agent/mcp-transport.ts
|
|
6
|
-
/**
|
|
7
|
-
* Thrown when an MCP {@link MCPClientConfigHTTP.getHeaders} resolver throws.
|
|
8
|
-
* Wraps the underlying error so `RUN_ERROR` carries clear attribution instead
|
|
9
|
-
* of a generic transport failure. The original error is preserved on the
|
|
10
|
-
* standard ES2022 `Error.cause` chain.
|
|
11
|
-
*/
|
|
12
|
-
var MCPHeaderResolverError = class extends Error {
|
|
13
|
-
constructor(message, cause) {
|
|
14
|
-
super(message, { cause });
|
|
15
|
-
this.name = "MCPHeaderResolverError";
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* MCP transport for CopilotKit's BuiltInAgent that adds per-call header
|
|
20
|
-
* resolution on top of the standard Streamable HTTP transport.
|
|
21
|
-
*
|
|
22
|
-
* Implements `@ai-sdk/mcp`'s {@link MCPTransport} interface so it can be
|
|
23
|
-
* passed straight to `createMCPClient({ transport })`. Internally delegates
|
|
24
|
-
* to `@modelcontextprotocol/sdk`'s `StreamableHTTPClientTransport` with a
|
|
25
|
-
* wrapped `fetch` that runs the static-header + per-call resolver pipeline
|
|
26
|
-
* before each outbound request.
|
|
27
|
-
*/
|
|
28
|
-
var CopilotKitMCPTransport = class {
|
|
29
|
-
constructor(options) {
|
|
30
|
-
const transportOptions = {
|
|
31
|
-
...options.options,
|
|
32
|
-
fetch: buildWrappedFetch(options)
|
|
33
|
-
};
|
|
34
|
-
this.inner = new _modelcontextprotocol_sdk_client_streamableHttp_js.StreamableHTTPClientTransport(new URL(options.url), transportOptions);
|
|
35
|
-
}
|
|
36
|
-
get onclose() {
|
|
37
|
-
return this.inner.onclose;
|
|
38
|
-
}
|
|
39
|
-
set onclose(handler) {
|
|
40
|
-
this.inner.onclose = handler;
|
|
41
|
-
}
|
|
42
|
-
get onerror() {
|
|
43
|
-
return this.inner.onerror;
|
|
44
|
-
}
|
|
45
|
-
set onerror(handler) {
|
|
46
|
-
this.inner.onerror = handler;
|
|
47
|
-
}
|
|
48
|
-
get onmessage() {
|
|
49
|
-
return this.inner.onmessage;
|
|
50
|
-
}
|
|
51
|
-
set onmessage(handler) {
|
|
52
|
-
this.inner.onmessage = handler;
|
|
53
|
-
}
|
|
54
|
-
start() {
|
|
55
|
-
return this.inner.start();
|
|
56
|
-
}
|
|
57
|
-
send(message) {
|
|
58
|
-
return this.inner.send(message);
|
|
59
|
-
}
|
|
60
|
-
close() {
|
|
61
|
-
return this.inner.close();
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
function buildWrappedFetch(options) {
|
|
65
|
-
const { headers: staticHeaders, getHeaders, requestHeaders, input, url: mcpServerUrl, user, options: transportOptions } = options;
|
|
66
|
-
const baseFetch = transportOptions?.fetch ?? globalThis.fetch;
|
|
67
|
-
return async (fetchUrl, init) => {
|
|
68
|
-
const merged = new Headers(init?.headers);
|
|
69
|
-
if (staticHeaders) for (const [key, value] of Object.entries(staticHeaders)) merged.set(key, value);
|
|
70
|
-
if (getHeaders) {
|
|
71
|
-
let resolved;
|
|
72
|
-
try {
|
|
73
|
-
resolved = await getHeaders({
|
|
74
|
-
requestHeaders,
|
|
75
|
-
input,
|
|
76
|
-
mcpServerUrl,
|
|
77
|
-
user
|
|
78
|
-
});
|
|
79
|
-
} catch (err) {
|
|
80
|
-
throw new MCPHeaderResolverError(`MCP header resolver for ${mcpServerUrl} threw: ${err instanceof Error ? err.message : String(err)}`, err);
|
|
81
|
-
}
|
|
82
|
-
for (const [key, value] of Object.entries(resolved)) merged.set(key, value);
|
|
83
|
-
}
|
|
84
|
-
return baseFetch(fetchUrl, {
|
|
85
|
-
...init,
|
|
86
|
-
headers: merged
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
//#endregion
|
|
92
|
-
exports.CopilotKitMCPTransport = CopilotKitMCPTransport;
|
|
93
|
-
exports.MCPHeaderResolverError = MCPHeaderResolverError;
|
|
94
|
-
//# sourceMappingURL=mcp-transport.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-transport.cjs","names":["StreamableHTTPClientTransport"],"sources":["../../src/agent/mcp-transport.ts"],"sourcesContent":["import type { RunAgentInput } from \"@ag-ui/client\";\nimport type { JSONRPCMessage, MCPTransport } from \"@ai-sdk/mcp\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { StreamableHTTPClientTransportOptions } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { FetchLike } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\n/**\n * The end-user identity resolved by the runtime's `identifyUser` callback for\n * the current request. Surfaced on {@link MCPRequestContext} so MCP header\n * resolvers can read it without re-doing auth work.\n */\nexport interface MCPRuntimeUser {\n id: string;\n name: string;\n}\n\n/**\n * Context handed to {@link MCPClientConfigHTTP.getHeaders} on every outbound\n * MCP HTTP request. The resolver is invoked fresh per request — initialize,\n * tools/list, tools/call, and reconnects — so values it depends on are never\n * cached across calls.\n */\nexport interface MCPRequestContext {\n /**\n * Headers forwarded onto the agent for this run. Populated by the runtime's\n * `extractForwardableHeaders` (`authorization` + every `x-*` header from the\n * incoming HTTP request). Keys are lower-cased.\n */\n requestHeaders: Record<string, string>;\n /** The {@link RunAgentInput} the agent is currently running. */\n input: RunAgentInput;\n /** URL of the MCP server this request is going to. */\n mcpServerUrl: string;\n /**\n * The end-user identity for this run, resolved by the runtime's\n * `identifyUser` callback (only populated when the agent is run via a\n * `CopilotRuntime` configured with `identifyUser`). Snapshotted at\n * run-start.\n */\n user?: MCPRuntimeUser;\n}\n\n/**\n * Thrown when an MCP {@link MCPClientConfigHTTP.getHeaders} resolver throws.\n * Wraps the underlying error so `RUN_ERROR` carries clear attribution instead\n * of a generic transport failure. The original error is preserved on the\n * standard ES2022 `Error.cause` chain.\n */\nexport class MCPHeaderResolverError extends Error {\n constructor(message: string, cause: unknown) {\n super(message, { cause });\n this.name = \"MCPHeaderResolverError\";\n }\n}\n\nexport interface CopilotKitMCPTransportOptions {\n /** URL of the MCP server. */\n url: string;\n /** Static HTTP headers, merged into every outbound request. */\n headers?: Record<string, string>;\n /**\n * Per-call header resolver. Invoked on **every** outbound HTTP request to\n * this server (initialize, tools/list, tools/call, reconnects). Returned\n * headers are merged on top of `headers`, so a resolver can override either.\n */\n getHeaders?: (\n ctx: MCPRequestContext,\n ) => Record<string, string> | Promise<Record<string, string>>;\n /**\n * Pre-existing escape hatch: low-level options for the underlying\n * `StreamableHTTPClientTransport`. Forwarded as-is, except `fetch` is\n * wrapped so static `headers` and `getHeaders` resolution still apply.\n */\n options?: StreamableHTTPClientTransportOptions;\n /** Snapshot of the agent's per-run forwarded headers, captured at run-start. */\n requestHeaders: Record<string, string>;\n /** RunAgentInput for the current run, exposed to the resolver via context. */\n input: RunAgentInput;\n /** Per-run end-user identity from the runtime's `identifyUser`, if set. */\n user?: MCPRuntimeUser;\n}\n\n/**\n * MCP transport for CopilotKit's BuiltInAgent that adds per-call header\n * resolution on top of the standard Streamable HTTP transport.\n *\n * Implements `@ai-sdk/mcp`'s {@link MCPTransport} interface so it can be\n * passed straight to `createMCPClient({ transport })`. Internally delegates\n * to `@modelcontextprotocol/sdk`'s `StreamableHTTPClientTransport` with a\n * wrapped `fetch` that runs the static-header + per-call resolver pipeline\n * before each outbound request.\n */\nexport class CopilotKitMCPTransport implements MCPTransport {\n private readonly inner: StreamableHTTPClientTransport;\n\n constructor(options: CopilotKitMCPTransportOptions) {\n const transportOptions: StreamableHTTPClientTransportOptions = {\n ...options.options,\n fetch: buildWrappedFetch(options),\n };\n this.inner = new StreamableHTTPClientTransport(\n new URL(options.url),\n transportOptions,\n );\n }\n\n get onclose(): (() => void) | undefined {\n return this.inner.onclose;\n }\n set onclose(handler: (() => void) | undefined) {\n this.inner.onclose = handler;\n }\n\n get onerror(): ((error: Error) => void) | undefined {\n return this.inner.onerror;\n }\n set onerror(handler: ((error: Error) => void) | undefined) {\n this.inner.onerror = handler;\n }\n\n get onmessage(): ((message: JSONRPCMessage) => void) | undefined {\n return this.inner.onmessage as\n | ((message: JSONRPCMessage) => void)\n | undefined;\n }\n set onmessage(handler: ((message: JSONRPCMessage) => void) | undefined) {\n this.inner.onmessage = handler as\n | ((message: JSONRPCMessage) => void)\n | undefined;\n }\n\n start(): Promise<void> {\n return this.inner.start();\n }\n\n send(message: JSONRPCMessage): Promise<void> {\n return this.inner.send(message as Parameters<typeof this.inner.send>[0]);\n }\n\n close(): Promise<void> {\n return this.inner.close();\n }\n}\n\nfunction buildWrappedFetch(options: CopilotKitMCPTransportOptions): FetchLike {\n const {\n headers: staticHeaders,\n getHeaders,\n requestHeaders,\n input,\n url: mcpServerUrl,\n user,\n options: transportOptions,\n } = options;\n const baseFetch: FetchLike = transportOptions?.fetch ?? globalThis.fetch;\n\n return async (fetchUrl, init) => {\n // SDK passes a Headers instance via init.headers — start fresh from it so\n // we don't mutate the SDK's object, then layer headers on top via .set()\n // (last write wins).\n const merged = new Headers(init?.headers);\n if (staticHeaders) {\n for (const [key, value] of Object.entries(staticHeaders)) {\n merged.set(key, value);\n }\n }\n if (getHeaders) {\n let resolved: Record<string, string>;\n try {\n resolved = await getHeaders({\n requestHeaders,\n input,\n mcpServerUrl,\n user,\n });\n } catch (err) {\n throw new MCPHeaderResolverError(\n `MCP header resolver for ${mcpServerUrl} threw: ${\n err instanceof Error ? err.message : String(err)\n }`,\n err,\n );\n }\n for (const [key, value] of Object.entries(resolved)) {\n merged.set(key, value);\n }\n }\n return baseFetch(fetchUrl, { ...init, headers: merged });\n };\n}\n"],"mappings":";;;;;;;;;;;AAgDA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,SAAiB,OAAgB;AAC3C,QAAM,SAAS,EAAE,OAAO,CAAC;AACzB,OAAK,OAAO;;;;;;;;;;;;;AAyChB,IAAa,yBAAb,MAA4D;CAG1D,YAAY,SAAwC;EAClD,MAAM,mBAAyD;GAC7D,GAAG,QAAQ;GACX,OAAO,kBAAkB,QAAQ;GAClC;AACD,OAAK,QAAQ,IAAIA,iFACf,IAAI,IAAI,QAAQ,IAAI,EACpB,iBACD;;CAGH,IAAI,UAAoC;AACtC,SAAO,KAAK,MAAM;;CAEpB,IAAI,QAAQ,SAAmC;AAC7C,OAAK,MAAM,UAAU;;CAGvB,IAAI,UAAgD;AAClD,SAAO,KAAK,MAAM;;CAEpB,IAAI,QAAQ,SAA+C;AACzD,OAAK,MAAM,UAAU;;CAGvB,IAAI,YAA6D;AAC/D,SAAO,KAAK,MAAM;;CAIpB,IAAI,UAAU,SAA0D;AACtE,OAAK,MAAM,YAAY;;CAKzB,QAAuB;AACrB,SAAO,KAAK,MAAM,OAAO;;CAG3B,KAAK,SAAwC;AAC3C,SAAO,KAAK,MAAM,KAAK,QAAiD;;CAG1E,QAAuB;AACrB,SAAO,KAAK,MAAM,OAAO;;;AAI7B,SAAS,kBAAkB,SAAmD;CAC5E,MAAM,EACJ,SAAS,eACT,YACA,gBACA,OACA,KAAK,cACL,MACA,SAAS,qBACP;CACJ,MAAM,YAAuB,kBAAkB,SAAS,WAAW;AAEnE,QAAO,OAAO,UAAU,SAAS;EAI/B,MAAM,SAAS,IAAI,QAAQ,MAAM,QAAQ;AACzC,MAAI,cACF,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,cAAc,CACtD,QAAO,IAAI,KAAK,MAAM;AAG1B,MAAI,YAAY;GACd,IAAI;AACJ,OAAI;AACF,eAAW,MAAM,WAAW;KAC1B;KACA;KACA;KACA;KACD,CAAC;YACK,KAAK;AACZ,UAAM,IAAI,uBACR,2BAA2B,aAAa,UACtC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IAElD,IACD;;AAEH,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,CACjD,QAAO,IAAI,KAAK,MAAM;;AAG1B,SAAO,UAAU,UAAU;GAAE,GAAG;GAAM,SAAS;GAAQ,CAAC"}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { RunAgentInput } from "@ag-ui/client";
|
|
3
|
-
import { StreamableHTTPClientTransportOptions } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
-
|
|
5
|
-
//#region src/agent/mcp-transport.d.ts
|
|
6
|
-
/**
|
|
7
|
-
* The end-user identity resolved by the runtime's `identifyUser` callback for
|
|
8
|
-
* the current request. Surfaced on {@link MCPRequestContext} so MCP header
|
|
9
|
-
* resolvers can read it without re-doing auth work.
|
|
10
|
-
*/
|
|
11
|
-
interface MCPRuntimeUser {
|
|
12
|
-
id: string;
|
|
13
|
-
name: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Context handed to {@link MCPClientConfigHTTP.getHeaders} on every outbound
|
|
17
|
-
* MCP HTTP request. The resolver is invoked fresh per request — initialize,
|
|
18
|
-
* tools/list, tools/call, and reconnects — so values it depends on are never
|
|
19
|
-
* cached across calls.
|
|
20
|
-
*/
|
|
21
|
-
interface MCPRequestContext {
|
|
22
|
-
/**
|
|
23
|
-
* Headers forwarded onto the agent for this run. Populated by the runtime's
|
|
24
|
-
* `extractForwardableHeaders` (`authorization` + every `x-*` header from the
|
|
25
|
-
* incoming HTTP request). Keys are lower-cased.
|
|
26
|
-
*/
|
|
27
|
-
requestHeaders: Record<string, string>;
|
|
28
|
-
/** The {@link RunAgentInput} the agent is currently running. */
|
|
29
|
-
input: RunAgentInput;
|
|
30
|
-
/** URL of the MCP server this request is going to. */
|
|
31
|
-
mcpServerUrl: string;
|
|
32
|
-
/**
|
|
33
|
-
* The end-user identity for this run, resolved by the runtime's
|
|
34
|
-
* `identifyUser` callback (only populated when the agent is run via a
|
|
35
|
-
* `CopilotRuntime` configured with `identifyUser`). Snapshotted at
|
|
36
|
-
* run-start.
|
|
37
|
-
*/
|
|
38
|
-
user?: MCPRuntimeUser;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Thrown when an MCP {@link MCPClientConfigHTTP.getHeaders} resolver throws.
|
|
42
|
-
* Wraps the underlying error so `RUN_ERROR` carries clear attribution instead
|
|
43
|
-
* of a generic transport failure. The original error is preserved on the
|
|
44
|
-
* standard ES2022 `Error.cause` chain.
|
|
45
|
-
*/
|
|
46
|
-
declare class MCPHeaderResolverError extends Error {
|
|
47
|
-
constructor(message: string, cause: unknown);
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
|
-
export { MCPHeaderResolverError, MCPRequestContext };
|
|
51
|
-
//# sourceMappingURL=mcp-transport.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-transport.d.cts","names":[],"sources":["../../src/agent/mcp-transport.ts"],"mappings":";;;;;;AAWA;;;;UAAiB,cAAA;EACf,EAAA;EACA,IAAA;AAAA;;;;;;;UASe,iBAAA;EAQf;;;;;EAFA,cAAA,EAAgB,MAAA;EAWK;EATrB,KAAA,EAAO,aAAA;EAkB2B;EAhBlC,YAAA;EAgB+C;;;;;;EAT/C,IAAA,GAAO,cAAA;AAAA;;;;;;;cASI,sBAAA,SAA+B,KAAA;cAC9B,OAAA,UAAiB,KAAA;AAAA"}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
|
-
import { RunAgentInput } from "@ag-ui/client";
|
|
3
|
-
import "@ai-sdk/mcp";
|
|
4
|
-
import { StreamableHTTPClientTransportOptions } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
-
|
|
6
|
-
//#region src/agent/mcp-transport.d.ts
|
|
7
|
-
/**
|
|
8
|
-
* The end-user identity resolved by the runtime's `identifyUser` callback for
|
|
9
|
-
* the current request. Surfaced on {@link MCPRequestContext} so MCP header
|
|
10
|
-
* resolvers can read it without re-doing auth work.
|
|
11
|
-
*/
|
|
12
|
-
interface MCPRuntimeUser {
|
|
13
|
-
id: string;
|
|
14
|
-
name: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Context handed to {@link MCPClientConfigHTTP.getHeaders} on every outbound
|
|
18
|
-
* MCP HTTP request. The resolver is invoked fresh per request — initialize,
|
|
19
|
-
* tools/list, tools/call, and reconnects — so values it depends on are never
|
|
20
|
-
* cached across calls.
|
|
21
|
-
*/
|
|
22
|
-
interface MCPRequestContext {
|
|
23
|
-
/**
|
|
24
|
-
* Headers forwarded onto the agent for this run. Populated by the runtime's
|
|
25
|
-
* `extractForwardableHeaders` (`authorization` + every `x-*` header from the
|
|
26
|
-
* incoming HTTP request). Keys are lower-cased.
|
|
27
|
-
*/
|
|
28
|
-
requestHeaders: Record<string, string>;
|
|
29
|
-
/** The {@link RunAgentInput} the agent is currently running. */
|
|
30
|
-
input: RunAgentInput;
|
|
31
|
-
/** URL of the MCP server this request is going to. */
|
|
32
|
-
mcpServerUrl: string;
|
|
33
|
-
/**
|
|
34
|
-
* The end-user identity for this run, resolved by the runtime's
|
|
35
|
-
* `identifyUser` callback (only populated when the agent is run via a
|
|
36
|
-
* `CopilotRuntime` configured with `identifyUser`). Snapshotted at
|
|
37
|
-
* run-start.
|
|
38
|
-
*/
|
|
39
|
-
user?: MCPRuntimeUser;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Thrown when an MCP {@link MCPClientConfigHTTP.getHeaders} resolver throws.
|
|
43
|
-
* Wraps the underlying error so `RUN_ERROR` carries clear attribution instead
|
|
44
|
-
* of a generic transport failure. The original error is preserved on the
|
|
45
|
-
* standard ES2022 `Error.cause` chain.
|
|
46
|
-
*/
|
|
47
|
-
declare class MCPHeaderResolverError extends Error {
|
|
48
|
-
constructor(message: string, cause: unknown);
|
|
49
|
-
}
|
|
50
|
-
//#endregion
|
|
51
|
-
export { MCPHeaderResolverError, MCPRequestContext };
|
|
52
|
-
//# sourceMappingURL=mcp-transport.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-transport.d.mts","names":[],"sources":["../../src/agent/mcp-transport.ts"],"mappings":";;;;;;;;AAWA;;;UAAiB,cAAA;EACf,EAAA;EACA,IAAA;AAAA;;;;;;;UASe,iBAAA;EAMC;;;;;EAAhB,cAAA,EAAgB,MAAA;EAWK;EATrB,KAAA,EAAO,aAAA;EAkBI;EAhBX,YAAA;;;;;;;EAOA,IAAA,GAAO,cAAA;AAAA;;;;;;;cASI,sBAAA,SAA+B,KAAA;cAC9B,OAAA,UAAiB,KAAA;AAAA"}
|