@copilotkit/runtime 1.62.1 → 1.62.2-canary.1783457132
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/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/v2/index.cjs +5 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/fetch-handler.cjs +27 -0
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +27 -0
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.cjs +10 -0
- package/dist/v2/runtime/core/fetch-router.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.mjs +10 -0
- package/dist/v2/runtime/core/fetch-router.mjs.map +1 -1
- package/dist/v2/runtime/core/hooks.cjs.map +1 -1
- package/dist/v2/runtime/core/hooks.d.cts +7 -0
- package/dist/v2/runtime/core/hooks.d.cts.map +1 -1
- package/dist/v2/runtime/core/hooks.d.mts +7 -0
- package/dist/v2/runtime/core/hooks.d.mts.map +1 -1
- package/dist/v2/runtime/core/hooks.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +5 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +21 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +21 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +5 -0
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +2 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +2 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/header-utils.cjs +169 -9
- package/dist/v2/runtime/handlers/header-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/header-utils.d.cts +54 -0
- package/dist/v2/runtime/handlers/header-utils.d.cts.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.d.mts +54 -0
- package/dist/v2/runtime/handlers/header-utils.d.mts.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.mjs +168 -9
- package/dist/v2/runtime/handlers/header-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/memories.cjs +209 -0
- package/dist/v2/runtime/handlers/intelligence/memories.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/memories.mjs +204 -0
- package/dist/v2/runtime/handlers/intelligence/memories.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +18 -5
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +18 -5
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs +2 -2
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs +3 -3
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +71 -2
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +112 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +112 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +71 -2
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.cjs +221 -37
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.cts +164 -3
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.mts +164 -3
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.mjs +218 -38
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
- package/dist/v2/runtime/runner/index.d.cts +1 -1
- package/dist/v2/runtime/runner/index.d.mts +1 -1
- package/dist/v2/runtime/runner/index.mjs +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
require("reflect-metadata");
|
|
2
|
+
const require_runtime = require('../../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_runtime$1 = require('../../core/runtime.cjs');
|
|
4
|
+
const require_client = require('../../intelligence-platform/client.cjs');
|
|
5
|
+
const require_json_response = require('../shared/json-response.cjs');
|
|
6
|
+
const require_resolve_intelligence_user = require('../shared/resolve-intelligence-user.cjs');
|
|
7
|
+
let _copilotkit_shared = require("@copilotkit/shared");
|
|
8
|
+
|
|
9
|
+
//#region src/v2/runtime/handlers/intelligence/memories.ts
|
|
10
|
+
const MISSING_INTELLIGENCE_MESSAGE = "Missing CopilotKitIntelligence configuration. Memory operations require a CopilotKitIntelligence instance to be provided in CopilotRuntime options.";
|
|
11
|
+
/** Allowed `kind` vocabulary the platform's memory endpoints accept. */
|
|
12
|
+
const MEMORY_KINDS = new Set([
|
|
13
|
+
"topical",
|
|
14
|
+
"episodic",
|
|
15
|
+
"operational"
|
|
16
|
+
]);
|
|
17
|
+
/** Allowed `scope` vocabulary the platform's memory endpoints accept. */
|
|
18
|
+
const MEMORY_SCOPES = new Set(["user", "project"]);
|
|
19
|
+
/**
|
|
20
|
+
* Maps a thrown error to a `Response`.
|
|
21
|
+
*
|
|
22
|
+
* For a {@link PlatformRequestError}, forward only client-actionable **4xx**
|
|
23
|
+
* statuses verbatim (e.g. 404 missing/wrong-scope memory, 409 conflict, 422
|
|
24
|
+
* unprocessable) so a `useMemories` consumer can branch on them — a flat 500
|
|
25
|
+
* would erase that distinction. A platform **5xx** (or any non-4xx / malformed
|
|
26
|
+
* status) means the runtime is healthy but its dependency failed, so it surfaces
|
|
27
|
+
* as `502 Bad Gateway` rather than echoing the upstream status as if the runtime
|
|
28
|
+
* itself broke — and this also avoids a `new Response(..., { status })`
|
|
29
|
+
* `RangeError` on an out-of-range status. Non-platform throws stay 500.
|
|
30
|
+
*/
|
|
31
|
+
function memoryErrorResponse(error, message) {
|
|
32
|
+
if (error instanceof require_client.PlatformRequestError) {
|
|
33
|
+
const { status } = error;
|
|
34
|
+
if (Number.isInteger(status) && status >= 400 && status <= 499) return require_json_response.errorResponse(message, status);
|
|
35
|
+
return require_json_response.errorResponse(message, 502);
|
|
36
|
+
}
|
|
37
|
+
return require_json_response.errorResponse(message, 500);
|
|
38
|
+
}
|
|
39
|
+
async function parseJsonBody(request) {
|
|
40
|
+
try {
|
|
41
|
+
return await request.json();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
_copilotkit_shared.logger.error({ err: error }, "Malformed JSON in memory request body");
|
|
44
|
+
return require_json_response.errorResponse("Invalid request body", 400);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Extracts and validates the create/supersede body fields the platform's
|
|
49
|
+
* memory endpoints require. Returns a `Response` (400) on invalid input.
|
|
50
|
+
*/
|
|
51
|
+
function parseMemoryBody(body) {
|
|
52
|
+
const { content, kind, scope, sourceThreadIds } = body;
|
|
53
|
+
if (typeof content !== "string" || typeof kind !== "string") return require_json_response.errorResponse("Memory requires string `content` and `kind`", 400);
|
|
54
|
+
if (!MEMORY_KINDS.has(kind)) return require_json_response.errorResponse("Memory `kind` must be one of: topical, episodic, operational", 400);
|
|
55
|
+
if (scope !== void 0 && typeof scope !== "string") return require_json_response.errorResponse("Memory `scope` must be a string when provided", 400);
|
|
56
|
+
if (typeof scope === "string" && !MEMORY_SCOPES.has(scope)) return require_json_response.errorResponse("Memory `scope` must be one of: user, project", 400);
|
|
57
|
+
if (sourceThreadIds !== void 0 && (!Array.isArray(sourceThreadIds) || !sourceThreadIds.every((id) => typeof id === "string"))) return require_json_response.errorResponse("Memory `sourceThreadIds` must be an array of strings when provided", 400);
|
|
58
|
+
return {
|
|
59
|
+
content,
|
|
60
|
+
kind,
|
|
61
|
+
...typeof scope === "string" ? { scope } : {},
|
|
62
|
+
...Array.isArray(sourceThreadIds) ? { sourceThreadIds } : {}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Lists the resolved user's long-term memories via the Intelligence platform.
|
|
67
|
+
*
|
|
68
|
+
* Mirrors {@link handleListThreads}: requires a `CopilotKitIntelligence`
|
|
69
|
+
* runtime, resolves the user with `identifyUser` (never trusting a
|
|
70
|
+
* client-supplied id), and proxies to the platform's `GET /api/memories`
|
|
71
|
+
* with the project API key + resolved user. The `?includeInvalidated=true`
|
|
72
|
+
* query is forwarded so callers can opt into retired rows. The response is
|
|
73
|
+
* the platform's `{ memories }` envelope, which the client memory store
|
|
74
|
+
* consumes directly.
|
|
75
|
+
*/
|
|
76
|
+
async function handleListMemories({ runtime, request }) {
|
|
77
|
+
if (require_runtime$1.isIntelligenceRuntime(runtime)) try {
|
|
78
|
+
const includeInvalidated = new URL(request.url).searchParams.get("includeInvalidated") === "true";
|
|
79
|
+
const user = await require_resolve_intelligence_user.resolveIntelligenceUser({
|
|
80
|
+
runtime,
|
|
81
|
+
request
|
|
82
|
+
});
|
|
83
|
+
if (require_json_response.isHandlerResponse(user)) return user;
|
|
84
|
+
const data = await runtime.intelligence.listMemories({
|
|
85
|
+
userId: user.id,
|
|
86
|
+
...includeInvalidated ? { includeInvalidated: true } : {}
|
|
87
|
+
});
|
|
88
|
+
if (data == null || typeof data !== "object" || !Array.isArray(data.memories)) {
|
|
89
|
+
_copilotkit_shared.logger.error({ data }, "listMemories: platform returned a response without a `memories` array");
|
|
90
|
+
return require_json_response.errorResponse("Memory platform returned an invalid list response", 502);
|
|
91
|
+
}
|
|
92
|
+
return Response.json(data);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
_copilotkit_shared.logger.error({ err: error }, "Error listing memories");
|
|
95
|
+
return memoryErrorResponse(error, "Failed to list memories");
|
|
96
|
+
}
|
|
97
|
+
return require_json_response.errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Mints memory-realtime join credentials (platform `POST
|
|
101
|
+
* /api/memories/subscribe`). Mirrors {@link handleSubscribeToThreads}: requires
|
|
102
|
+
* a `CopilotKitIntelligence` runtime and resolves the user with `identifyUser`
|
|
103
|
+
* (never a client-supplied id). Returns `{ joinToken, joinCode }` — memory needs
|
|
104
|
+
* the `joinCode` here (unlike threads, where it rides the thread-list response)
|
|
105
|
+
* because the client builds the `user_meta:memories:<joinCode>` channel topic
|
|
106
|
+
* from it.
|
|
107
|
+
*/
|
|
108
|
+
async function handleSubscribeToMemories({ runtime, request }) {
|
|
109
|
+
if (require_runtime$1.isIntelligenceRuntime(runtime)) try {
|
|
110
|
+
const user = await require_resolve_intelligence_user.resolveIntelligenceUser({
|
|
111
|
+
runtime,
|
|
112
|
+
request
|
|
113
|
+
});
|
|
114
|
+
if (require_json_response.isHandlerResponse(user)) return user;
|
|
115
|
+
const credentials = await runtime.intelligence.ɵsubscribeToMemories({ userId: user.id });
|
|
116
|
+
return Response.json({
|
|
117
|
+
joinToken: credentials.joinToken,
|
|
118
|
+
joinCode: credentials.joinCode
|
|
119
|
+
});
|
|
120
|
+
} catch (error) {
|
|
121
|
+
_copilotkit_shared.logger.error({ err: error }, "Error subscribing to memories");
|
|
122
|
+
return memoryErrorResponse(error, "Failed to subscribe to memories");
|
|
123
|
+
}
|
|
124
|
+
return require_json_response.errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Creates a memory for the resolved user (platform `POST /api/memories`).
|
|
128
|
+
* Identity comes from `identifyUser`, never the request body. Returns 201
|
|
129
|
+
* with the stored memory (the client store applies it server-authoritatively).
|
|
130
|
+
*/
|
|
131
|
+
async function handleCreateMemory({ runtime, request }) {
|
|
132
|
+
if (!require_runtime$1.isIntelligenceRuntime(runtime)) return require_json_response.errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
133
|
+
try {
|
|
134
|
+
const body = await parseJsonBody(request);
|
|
135
|
+
if (require_json_response.isHandlerResponse(body)) return body;
|
|
136
|
+
const fields = parseMemoryBody(body);
|
|
137
|
+
if (require_json_response.isHandlerResponse(fields)) return fields;
|
|
138
|
+
const user = await require_resolve_intelligence_user.resolveIntelligenceUser({
|
|
139
|
+
runtime,
|
|
140
|
+
request
|
|
141
|
+
});
|
|
142
|
+
if (require_json_response.isHandlerResponse(user)) return user;
|
|
143
|
+
const data = await runtime.intelligence.createMemory({
|
|
144
|
+
userId: user.id,
|
|
145
|
+
...fields
|
|
146
|
+
});
|
|
147
|
+
return Response.json(data, { status: 201 });
|
|
148
|
+
} catch (error) {
|
|
149
|
+
_copilotkit_shared.logger.error({ err: error }, "Error creating memory");
|
|
150
|
+
return memoryErrorResponse(error, "Failed to create memory");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Supersedes a memory (platform `PATCH /api/memories/:id`): retires `:id` and
|
|
155
|
+
* inserts the new content atomically; the response carries `retiredId`.
|
|
156
|
+
*/
|
|
157
|
+
async function handleUpdateMemory({ runtime, request, memoryId }) {
|
|
158
|
+
if (!require_runtime$1.isIntelligenceRuntime(runtime)) return require_json_response.errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
159
|
+
try {
|
|
160
|
+
const body = await parseJsonBody(request);
|
|
161
|
+
if (require_json_response.isHandlerResponse(body)) return body;
|
|
162
|
+
const fields = parseMemoryBody(body);
|
|
163
|
+
if (require_json_response.isHandlerResponse(fields)) return fields;
|
|
164
|
+
const user = await require_resolve_intelligence_user.resolveIntelligenceUser({
|
|
165
|
+
runtime,
|
|
166
|
+
request
|
|
167
|
+
});
|
|
168
|
+
if (require_json_response.isHandlerResponse(user)) return user;
|
|
169
|
+
const data = await runtime.intelligence.updateMemory({
|
|
170
|
+
userId: user.id,
|
|
171
|
+
id: memoryId,
|
|
172
|
+
...fields
|
|
173
|
+
});
|
|
174
|
+
return Response.json(data);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
_copilotkit_shared.logger.error({ err: error }, "Error updating memory");
|
|
177
|
+
return memoryErrorResponse(error, "Failed to update memory");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Retires (forgets) a memory (platform `DELETE /api/memories/:id`). Non-lossy
|
|
182
|
+
* on the platform side; returns 204.
|
|
183
|
+
*/
|
|
184
|
+
async function handleRemoveMemory({ runtime, request, memoryId }) {
|
|
185
|
+
if (!require_runtime$1.isIntelligenceRuntime(runtime)) return require_json_response.errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
186
|
+
try {
|
|
187
|
+
const user = await require_resolve_intelligence_user.resolveIntelligenceUser({
|
|
188
|
+
runtime,
|
|
189
|
+
request
|
|
190
|
+
});
|
|
191
|
+
if (require_json_response.isHandlerResponse(user)) return user;
|
|
192
|
+
await runtime.intelligence.removeMemory({
|
|
193
|
+
userId: user.id,
|
|
194
|
+
id: memoryId
|
|
195
|
+
});
|
|
196
|
+
return new Response(null, { status: 204 });
|
|
197
|
+
} catch (error) {
|
|
198
|
+
_copilotkit_shared.logger.error({ err: error }, "Error removing memory");
|
|
199
|
+
return memoryErrorResponse(error, "Failed to remove memory");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
exports.handleCreateMemory = handleCreateMemory;
|
|
205
|
+
exports.handleListMemories = handleListMemories;
|
|
206
|
+
exports.handleRemoveMemory = handleRemoveMemory;
|
|
207
|
+
exports.handleSubscribeToMemories = handleSubscribeToMemories;
|
|
208
|
+
exports.handleUpdateMemory = handleUpdateMemory;
|
|
209
|
+
//# sourceMappingURL=memories.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memories.cjs","names":["PlatformRequestError","errorResponse","isIntelligenceRuntime","resolveIntelligenceUser","isHandlerResponse"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/memories.ts"],"sourcesContent":["import type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { isIntelligenceRuntime } from \"../../core/runtime\";\nimport { logger } from \"@copilotkit/shared\";\nimport { errorResponse, isHandlerResponse } from \"../shared/json-response\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { PlatformRequestError } from \"../../intelligence-platform/client\";\n\ninterface MemoriesHandlerParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n}\n\ninterface MemoryMutationParams extends MemoriesHandlerParams {\n memoryId: string;\n}\n\nconst MISSING_INTELLIGENCE_MESSAGE =\n \"Missing CopilotKitIntelligence configuration. Memory operations require a CopilotKitIntelligence instance to be provided in CopilotRuntime options.\";\n\n/** Allowed `kind` vocabulary the platform's memory endpoints accept. */\nconst MEMORY_KINDS: ReadonlySet<string> = new Set([\n \"topical\",\n \"episodic\",\n \"operational\",\n]);\n/** Allowed `scope` vocabulary the platform's memory endpoints accept. */\nconst MEMORY_SCOPES: ReadonlySet<string> = new Set([\"user\", \"project\"]);\n\n/**\n * Maps a thrown error to a `Response`.\n *\n * For a {@link PlatformRequestError}, forward only client-actionable **4xx**\n * statuses verbatim (e.g. 404 missing/wrong-scope memory, 409 conflict, 422\n * unprocessable) so a `useMemories` consumer can branch on them — a flat 500\n * would erase that distinction. A platform **5xx** (or any non-4xx / malformed\n * status) means the runtime is healthy but its dependency failed, so it surfaces\n * as `502 Bad Gateway` rather than echoing the upstream status as if the runtime\n * itself broke — and this also avoids a `new Response(..., { status })`\n * `RangeError` on an out-of-range status. Non-platform throws stay 500.\n */\nfunction memoryErrorResponse(error: unknown, message: string): Response {\n if (error instanceof PlatformRequestError) {\n const { status } = error;\n if (Number.isInteger(status) && status >= 400 && status <= 499) {\n return errorResponse(message, status);\n }\n return errorResponse(message, 502);\n }\n return errorResponse(message, 500);\n}\n\nasync function parseJsonBody(\n request: Request,\n): Promise<Record<string, unknown> | Response> {\n try {\n return (await request.json()) as Record<string, unknown>;\n } catch (error) {\n logger.error({ err: error }, \"Malformed JSON in memory request body\");\n return errorResponse(\"Invalid request body\", 400);\n }\n}\n\n/**\n * Extracts and validates the create/supersede body fields the platform's\n * memory endpoints require. Returns a `Response` (400) on invalid input.\n */\nfunction parseMemoryBody(body: Record<string, unknown>):\n | {\n content: string;\n kind: string;\n scope?: string;\n sourceThreadIds?: string[];\n }\n | Response {\n const { content, kind, scope, sourceThreadIds } = body;\n if (typeof content !== \"string\" || typeof kind !== \"string\") {\n return errorResponse(\"Memory requires string `content` and `kind`\", 400);\n }\n // `kind` must be one of the platform's known kinds. Reject an out-of-vocabulary\n // value here rather than forwarding it for the platform to reject.\n if (!MEMORY_KINDS.has(kind)) {\n return errorResponse(\n \"Memory `kind` must be one of: topical, episodic, operational\",\n 400,\n );\n }\n // `scope` is optional: when omitted the platform applies its default\n // (`\"user\"`). Only reject a present-but-wrong-typed scope.\n if (scope !== undefined && typeof scope !== \"string\") {\n return errorResponse(\"Memory `scope` must be a string when provided\", 400);\n }\n // When `scope` is present, it must be one of the known scopes.\n if (typeof scope === \"string\" && !MEMORY_SCOPES.has(scope)) {\n return errorResponse(\"Memory `scope` must be one of: user, project\", 400);\n }\n // `sourceThreadIds` is optional, but when present it must be a string array.\n // Validate every element so non-string ids are not forwarded to the platform.\n if (\n sourceThreadIds !== undefined &&\n (!Array.isArray(sourceThreadIds) ||\n !sourceThreadIds.every((id) => typeof id === \"string\"))\n ) {\n return errorResponse(\n \"Memory `sourceThreadIds` must be an array of strings when provided\",\n 400,\n );\n }\n return {\n content,\n kind,\n ...(typeof scope === \"string\" ? { scope } : {}),\n ...(Array.isArray(sourceThreadIds)\n ? { sourceThreadIds: sourceThreadIds as string[] }\n : {}),\n // `sourceThreadIds` elements are validated as strings above; the cast is safe.\n };\n}\n\n/**\n * Lists the resolved user's long-term memories via the Intelligence platform.\n *\n * Mirrors {@link handleListThreads}: requires a `CopilotKitIntelligence`\n * runtime, resolves the user with `identifyUser` (never trusting a\n * client-supplied id), and proxies to the platform's `GET /api/memories`\n * with the project API key + resolved user. The `?includeInvalidated=true`\n * query is forwarded so callers can opt into retired rows. The response is\n * the platform's `{ memories }` envelope, which the client memory store\n * consumes directly.\n */\nexport async function handleListMemories({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (isIntelligenceRuntime(runtime)) {\n try {\n const url = new URL(request.url);\n const includeInvalidated =\n url.searchParams.get(\"includeInvalidated\") === \"true\";\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.listMemories({\n userId: user.id,\n ...(includeInvalidated ? { includeInvalidated: true } : {}),\n });\n\n // The client memory store consumes the `{ memories: [...] }` envelope\n // directly. Assert the shape before forwarding so a platform contract\n // violation surfaces as a clear 502 (the runtime is healthy but its\n // dependency returned the wrong shape) instead of a 200 the client will\n // choke on.\n if (\n data == null ||\n typeof data !== \"object\" ||\n !Array.isArray((data as { memories?: unknown }).memories)\n ) {\n logger.error(\n { data },\n \"listMemories: platform returned a response without a `memories` array\",\n );\n return errorResponse(\n \"Memory platform returned an invalid list response\",\n 502,\n );\n }\n\n return Response.json(data);\n } catch (error) {\n logger.error({ err: error }, \"Error listing memories\");\n return memoryErrorResponse(error, \"Failed to list memories\");\n }\n }\n\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n}\n\n/**\n * Mints memory-realtime join credentials (platform `POST\n * /api/memories/subscribe`). Mirrors {@link handleSubscribeToThreads}: requires\n * a `CopilotKitIntelligence` runtime and resolves the user with `identifyUser`\n * (never a client-supplied id). Returns `{ joinToken, joinCode }` — memory needs\n * the `joinCode` here (unlike threads, where it rides the thread-list response)\n * because the client builds the `user_meta:memories:<joinCode>` channel topic\n * from it.\n */\nexport async function handleSubscribeToMemories({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (isIntelligenceRuntime(runtime)) {\n try {\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const credentials = await runtime.intelligence.ɵsubscribeToMemories({\n userId: user.id,\n });\n\n return Response.json({\n joinToken: credentials.joinToken,\n joinCode: credentials.joinCode,\n });\n } catch (error) {\n logger.error({ err: error }, \"Error subscribing to memories\");\n return memoryErrorResponse(error, \"Failed to subscribe to memories\");\n }\n }\n\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n}\n\n/**\n * Creates a memory for the resolved user (platform `POST /api/memories`).\n * Identity comes from `identifyUser`, never the request body. Returns 201\n * with the stored memory (the client store applies it server-authoritatively).\n */\nexport async function handleCreateMemory({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const body = await parseJsonBody(request);\n if (isHandlerResponse(body)) return body;\n const fields = parseMemoryBody(body);\n if (isHandlerResponse(fields)) return fields;\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.createMemory({\n userId: user.id,\n ...fields,\n });\n return Response.json(data, { status: 201 });\n } catch (error) {\n logger.error({ err: error }, \"Error creating memory\");\n return memoryErrorResponse(error, \"Failed to create memory\");\n }\n}\n\n/**\n * Supersedes a memory (platform `PATCH /api/memories/:id`): retires `:id` and\n * inserts the new content atomically; the response carries `retiredId`.\n */\nexport async function handleUpdateMemory({\n runtime,\n request,\n memoryId,\n}: MemoryMutationParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const body = await parseJsonBody(request);\n if (isHandlerResponse(body)) return body;\n const fields = parseMemoryBody(body);\n if (isHandlerResponse(fields)) return fields;\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.updateMemory({\n userId: user.id,\n id: memoryId,\n ...fields,\n });\n return Response.json(data);\n } catch (error) {\n logger.error({ err: error }, \"Error updating memory\");\n return memoryErrorResponse(error, \"Failed to update memory\");\n }\n}\n\n/**\n * Retires (forgets) a memory (platform `DELETE /api/memories/:id`). Non-lossy\n * on the platform side; returns 204.\n */\nexport async function handleRemoveMemory({\n runtime,\n request,\n memoryId,\n}: MemoryMutationParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n await runtime.intelligence.removeMemory({ userId: user.id, id: memoryId });\n return new Response(null, { status: 204 });\n } catch (error) {\n logger.error({ err: error }, \"Error removing memory\");\n return memoryErrorResponse(error, \"Failed to remove memory\");\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { isIntelligenceRuntime } from "../../core/runtime.mjs";
|
|
3
|
+
import { PlatformRequestError } from "../../intelligence-platform/client.mjs";
|
|
4
|
+
import { errorResponse, isHandlerResponse } from "../shared/json-response.mjs";
|
|
5
|
+
import { resolveIntelligenceUser } from "../shared/resolve-intelligence-user.mjs";
|
|
6
|
+
import { logger } from "@copilotkit/shared";
|
|
7
|
+
|
|
8
|
+
//#region src/v2/runtime/handlers/intelligence/memories.ts
|
|
9
|
+
const MISSING_INTELLIGENCE_MESSAGE = "Missing CopilotKitIntelligence configuration. Memory operations require a CopilotKitIntelligence instance to be provided in CopilotRuntime options.";
|
|
10
|
+
/** Allowed `kind` vocabulary the platform's memory endpoints accept. */
|
|
11
|
+
const MEMORY_KINDS = new Set([
|
|
12
|
+
"topical",
|
|
13
|
+
"episodic",
|
|
14
|
+
"operational"
|
|
15
|
+
]);
|
|
16
|
+
/** Allowed `scope` vocabulary the platform's memory endpoints accept. */
|
|
17
|
+
const MEMORY_SCOPES = new Set(["user", "project"]);
|
|
18
|
+
/**
|
|
19
|
+
* Maps a thrown error to a `Response`.
|
|
20
|
+
*
|
|
21
|
+
* For a {@link PlatformRequestError}, forward only client-actionable **4xx**
|
|
22
|
+
* statuses verbatim (e.g. 404 missing/wrong-scope memory, 409 conflict, 422
|
|
23
|
+
* unprocessable) so a `useMemories` consumer can branch on them — a flat 500
|
|
24
|
+
* would erase that distinction. A platform **5xx** (or any non-4xx / malformed
|
|
25
|
+
* status) means the runtime is healthy but its dependency failed, so it surfaces
|
|
26
|
+
* as `502 Bad Gateway` rather than echoing the upstream status as if the runtime
|
|
27
|
+
* itself broke — and this also avoids a `new Response(..., { status })`
|
|
28
|
+
* `RangeError` on an out-of-range status. Non-platform throws stay 500.
|
|
29
|
+
*/
|
|
30
|
+
function memoryErrorResponse(error, message) {
|
|
31
|
+
if (error instanceof PlatformRequestError) {
|
|
32
|
+
const { status } = error;
|
|
33
|
+
if (Number.isInteger(status) && status >= 400 && status <= 499) return errorResponse(message, status);
|
|
34
|
+
return errorResponse(message, 502);
|
|
35
|
+
}
|
|
36
|
+
return errorResponse(message, 500);
|
|
37
|
+
}
|
|
38
|
+
async function parseJsonBody(request) {
|
|
39
|
+
try {
|
|
40
|
+
return await request.json();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
logger.error({ err: error }, "Malformed JSON in memory request body");
|
|
43
|
+
return errorResponse("Invalid request body", 400);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extracts and validates the create/supersede body fields the platform's
|
|
48
|
+
* memory endpoints require. Returns a `Response` (400) on invalid input.
|
|
49
|
+
*/
|
|
50
|
+
function parseMemoryBody(body) {
|
|
51
|
+
const { content, kind, scope, sourceThreadIds } = body;
|
|
52
|
+
if (typeof content !== "string" || typeof kind !== "string") return errorResponse("Memory requires string `content` and `kind`", 400);
|
|
53
|
+
if (!MEMORY_KINDS.has(kind)) return errorResponse("Memory `kind` must be one of: topical, episodic, operational", 400);
|
|
54
|
+
if (scope !== void 0 && typeof scope !== "string") return errorResponse("Memory `scope` must be a string when provided", 400);
|
|
55
|
+
if (typeof scope === "string" && !MEMORY_SCOPES.has(scope)) return errorResponse("Memory `scope` must be one of: user, project", 400);
|
|
56
|
+
if (sourceThreadIds !== void 0 && (!Array.isArray(sourceThreadIds) || !sourceThreadIds.every((id) => typeof id === "string"))) return errorResponse("Memory `sourceThreadIds` must be an array of strings when provided", 400);
|
|
57
|
+
return {
|
|
58
|
+
content,
|
|
59
|
+
kind,
|
|
60
|
+
...typeof scope === "string" ? { scope } : {},
|
|
61
|
+
...Array.isArray(sourceThreadIds) ? { sourceThreadIds } : {}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Lists the resolved user's long-term memories via the Intelligence platform.
|
|
66
|
+
*
|
|
67
|
+
* Mirrors {@link handleListThreads}: requires a `CopilotKitIntelligence`
|
|
68
|
+
* runtime, resolves the user with `identifyUser` (never trusting a
|
|
69
|
+
* client-supplied id), and proxies to the platform's `GET /api/memories`
|
|
70
|
+
* with the project API key + resolved user. The `?includeInvalidated=true`
|
|
71
|
+
* query is forwarded so callers can opt into retired rows. The response is
|
|
72
|
+
* the platform's `{ memories }` envelope, which the client memory store
|
|
73
|
+
* consumes directly.
|
|
74
|
+
*/
|
|
75
|
+
async function handleListMemories({ runtime, request }) {
|
|
76
|
+
if (isIntelligenceRuntime(runtime)) try {
|
|
77
|
+
const includeInvalidated = new URL(request.url).searchParams.get("includeInvalidated") === "true";
|
|
78
|
+
const user = await resolveIntelligenceUser({
|
|
79
|
+
runtime,
|
|
80
|
+
request
|
|
81
|
+
});
|
|
82
|
+
if (isHandlerResponse(user)) return user;
|
|
83
|
+
const data = await runtime.intelligence.listMemories({
|
|
84
|
+
userId: user.id,
|
|
85
|
+
...includeInvalidated ? { includeInvalidated: true } : {}
|
|
86
|
+
});
|
|
87
|
+
if (data == null || typeof data !== "object" || !Array.isArray(data.memories)) {
|
|
88
|
+
logger.error({ data }, "listMemories: platform returned a response without a `memories` array");
|
|
89
|
+
return errorResponse("Memory platform returned an invalid list response", 502);
|
|
90
|
+
}
|
|
91
|
+
return Response.json(data);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.error({ err: error }, "Error listing memories");
|
|
94
|
+
return memoryErrorResponse(error, "Failed to list memories");
|
|
95
|
+
}
|
|
96
|
+
return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Mints memory-realtime join credentials (platform `POST
|
|
100
|
+
* /api/memories/subscribe`). Mirrors {@link handleSubscribeToThreads}: requires
|
|
101
|
+
* a `CopilotKitIntelligence` runtime and resolves the user with `identifyUser`
|
|
102
|
+
* (never a client-supplied id). Returns `{ joinToken, joinCode }` — memory needs
|
|
103
|
+
* the `joinCode` here (unlike threads, where it rides the thread-list response)
|
|
104
|
+
* because the client builds the `user_meta:memories:<joinCode>` channel topic
|
|
105
|
+
* from it.
|
|
106
|
+
*/
|
|
107
|
+
async function handleSubscribeToMemories({ runtime, request }) {
|
|
108
|
+
if (isIntelligenceRuntime(runtime)) try {
|
|
109
|
+
const user = await resolveIntelligenceUser({
|
|
110
|
+
runtime,
|
|
111
|
+
request
|
|
112
|
+
});
|
|
113
|
+
if (isHandlerResponse(user)) return user;
|
|
114
|
+
const credentials = await runtime.intelligence.ɵsubscribeToMemories({ userId: user.id });
|
|
115
|
+
return Response.json({
|
|
116
|
+
joinToken: credentials.joinToken,
|
|
117
|
+
joinCode: credentials.joinCode
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logger.error({ err: error }, "Error subscribing to memories");
|
|
121
|
+
return memoryErrorResponse(error, "Failed to subscribe to memories");
|
|
122
|
+
}
|
|
123
|
+
return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Creates a memory for the resolved user (platform `POST /api/memories`).
|
|
127
|
+
* Identity comes from `identifyUser`, never the request body. Returns 201
|
|
128
|
+
* with the stored memory (the client store applies it server-authoritatively).
|
|
129
|
+
*/
|
|
130
|
+
async function handleCreateMemory({ runtime, request }) {
|
|
131
|
+
if (!isIntelligenceRuntime(runtime)) return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
132
|
+
try {
|
|
133
|
+
const body = await parseJsonBody(request);
|
|
134
|
+
if (isHandlerResponse(body)) return body;
|
|
135
|
+
const fields = parseMemoryBody(body);
|
|
136
|
+
if (isHandlerResponse(fields)) return fields;
|
|
137
|
+
const user = await resolveIntelligenceUser({
|
|
138
|
+
runtime,
|
|
139
|
+
request
|
|
140
|
+
});
|
|
141
|
+
if (isHandlerResponse(user)) return user;
|
|
142
|
+
const data = await runtime.intelligence.createMemory({
|
|
143
|
+
userId: user.id,
|
|
144
|
+
...fields
|
|
145
|
+
});
|
|
146
|
+
return Response.json(data, { status: 201 });
|
|
147
|
+
} catch (error) {
|
|
148
|
+
logger.error({ err: error }, "Error creating memory");
|
|
149
|
+
return memoryErrorResponse(error, "Failed to create memory");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Supersedes a memory (platform `PATCH /api/memories/:id`): retires `:id` and
|
|
154
|
+
* inserts the new content atomically; the response carries `retiredId`.
|
|
155
|
+
*/
|
|
156
|
+
async function handleUpdateMemory({ runtime, request, memoryId }) {
|
|
157
|
+
if (!isIntelligenceRuntime(runtime)) return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
158
|
+
try {
|
|
159
|
+
const body = await parseJsonBody(request);
|
|
160
|
+
if (isHandlerResponse(body)) return body;
|
|
161
|
+
const fields = parseMemoryBody(body);
|
|
162
|
+
if (isHandlerResponse(fields)) return fields;
|
|
163
|
+
const user = await resolveIntelligenceUser({
|
|
164
|
+
runtime,
|
|
165
|
+
request
|
|
166
|
+
});
|
|
167
|
+
if (isHandlerResponse(user)) return user;
|
|
168
|
+
const data = await runtime.intelligence.updateMemory({
|
|
169
|
+
userId: user.id,
|
|
170
|
+
id: memoryId,
|
|
171
|
+
...fields
|
|
172
|
+
});
|
|
173
|
+
return Response.json(data);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
logger.error({ err: error }, "Error updating memory");
|
|
176
|
+
return memoryErrorResponse(error, "Failed to update memory");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Retires (forgets) a memory (platform `DELETE /api/memories/:id`). Non-lossy
|
|
181
|
+
* on the platform side; returns 204.
|
|
182
|
+
*/
|
|
183
|
+
async function handleRemoveMemory({ runtime, request, memoryId }) {
|
|
184
|
+
if (!isIntelligenceRuntime(runtime)) return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);
|
|
185
|
+
try {
|
|
186
|
+
const user = await resolveIntelligenceUser({
|
|
187
|
+
runtime,
|
|
188
|
+
request
|
|
189
|
+
});
|
|
190
|
+
if (isHandlerResponse(user)) return user;
|
|
191
|
+
await runtime.intelligence.removeMemory({
|
|
192
|
+
userId: user.id,
|
|
193
|
+
id: memoryId
|
|
194
|
+
});
|
|
195
|
+
return new Response(null, { status: 204 });
|
|
196
|
+
} catch (error) {
|
|
197
|
+
logger.error({ err: error }, "Error removing memory");
|
|
198
|
+
return memoryErrorResponse(error, "Failed to remove memory");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
//#endregion
|
|
203
|
+
export { handleCreateMemory, handleListMemories, handleRemoveMemory, handleSubscribeToMemories, handleUpdateMemory };
|
|
204
|
+
//# sourceMappingURL=memories.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memories.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/intelligence/memories.ts"],"sourcesContent":["import type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { isIntelligenceRuntime } from \"../../core/runtime\";\nimport { logger } from \"@copilotkit/shared\";\nimport { errorResponse, isHandlerResponse } from \"../shared/json-response\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { PlatformRequestError } from \"../../intelligence-platform/client\";\n\ninterface MemoriesHandlerParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n}\n\ninterface MemoryMutationParams extends MemoriesHandlerParams {\n memoryId: string;\n}\n\nconst MISSING_INTELLIGENCE_MESSAGE =\n \"Missing CopilotKitIntelligence configuration. Memory operations require a CopilotKitIntelligence instance to be provided in CopilotRuntime options.\";\n\n/** Allowed `kind` vocabulary the platform's memory endpoints accept. */\nconst MEMORY_KINDS: ReadonlySet<string> = new Set([\n \"topical\",\n \"episodic\",\n \"operational\",\n]);\n/** Allowed `scope` vocabulary the platform's memory endpoints accept. */\nconst MEMORY_SCOPES: ReadonlySet<string> = new Set([\"user\", \"project\"]);\n\n/**\n * Maps a thrown error to a `Response`.\n *\n * For a {@link PlatformRequestError}, forward only client-actionable **4xx**\n * statuses verbatim (e.g. 404 missing/wrong-scope memory, 409 conflict, 422\n * unprocessable) so a `useMemories` consumer can branch on them — a flat 500\n * would erase that distinction. A platform **5xx** (or any non-4xx / malformed\n * status) means the runtime is healthy but its dependency failed, so it surfaces\n * as `502 Bad Gateway` rather than echoing the upstream status as if the runtime\n * itself broke — and this also avoids a `new Response(..., { status })`\n * `RangeError` on an out-of-range status. Non-platform throws stay 500.\n */\nfunction memoryErrorResponse(error: unknown, message: string): Response {\n if (error instanceof PlatformRequestError) {\n const { status } = error;\n if (Number.isInteger(status) && status >= 400 && status <= 499) {\n return errorResponse(message, status);\n }\n return errorResponse(message, 502);\n }\n return errorResponse(message, 500);\n}\n\nasync function parseJsonBody(\n request: Request,\n): Promise<Record<string, unknown> | Response> {\n try {\n return (await request.json()) as Record<string, unknown>;\n } catch (error) {\n logger.error({ err: error }, \"Malformed JSON in memory request body\");\n return errorResponse(\"Invalid request body\", 400);\n }\n}\n\n/**\n * Extracts and validates the create/supersede body fields the platform's\n * memory endpoints require. Returns a `Response` (400) on invalid input.\n */\nfunction parseMemoryBody(body: Record<string, unknown>):\n | {\n content: string;\n kind: string;\n scope?: string;\n sourceThreadIds?: string[];\n }\n | Response {\n const { content, kind, scope, sourceThreadIds } = body;\n if (typeof content !== \"string\" || typeof kind !== \"string\") {\n return errorResponse(\"Memory requires string `content` and `kind`\", 400);\n }\n // `kind` must be one of the platform's known kinds. Reject an out-of-vocabulary\n // value here rather than forwarding it for the platform to reject.\n if (!MEMORY_KINDS.has(kind)) {\n return errorResponse(\n \"Memory `kind` must be one of: topical, episodic, operational\",\n 400,\n );\n }\n // `scope` is optional: when omitted the platform applies its default\n // (`\"user\"`). Only reject a present-but-wrong-typed scope.\n if (scope !== undefined && typeof scope !== \"string\") {\n return errorResponse(\"Memory `scope` must be a string when provided\", 400);\n }\n // When `scope` is present, it must be one of the known scopes.\n if (typeof scope === \"string\" && !MEMORY_SCOPES.has(scope)) {\n return errorResponse(\"Memory `scope` must be one of: user, project\", 400);\n }\n // `sourceThreadIds` is optional, but when present it must be a string array.\n // Validate every element so non-string ids are not forwarded to the platform.\n if (\n sourceThreadIds !== undefined &&\n (!Array.isArray(sourceThreadIds) ||\n !sourceThreadIds.every((id) => typeof id === \"string\"))\n ) {\n return errorResponse(\n \"Memory `sourceThreadIds` must be an array of strings when provided\",\n 400,\n );\n }\n return {\n content,\n kind,\n ...(typeof scope === \"string\" ? { scope } : {}),\n ...(Array.isArray(sourceThreadIds)\n ? { sourceThreadIds: sourceThreadIds as string[] }\n : {}),\n // `sourceThreadIds` elements are validated as strings above; the cast is safe.\n };\n}\n\n/**\n * Lists the resolved user's long-term memories via the Intelligence platform.\n *\n * Mirrors {@link handleListThreads}: requires a `CopilotKitIntelligence`\n * runtime, resolves the user with `identifyUser` (never trusting a\n * client-supplied id), and proxies to the platform's `GET /api/memories`\n * with the project API key + resolved user. The `?includeInvalidated=true`\n * query is forwarded so callers can opt into retired rows. The response is\n * the platform's `{ memories }` envelope, which the client memory store\n * consumes directly.\n */\nexport async function handleListMemories({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (isIntelligenceRuntime(runtime)) {\n try {\n const url = new URL(request.url);\n const includeInvalidated =\n url.searchParams.get(\"includeInvalidated\") === \"true\";\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.listMemories({\n userId: user.id,\n ...(includeInvalidated ? { includeInvalidated: true } : {}),\n });\n\n // The client memory store consumes the `{ memories: [...] }` envelope\n // directly. Assert the shape before forwarding so a platform contract\n // violation surfaces as a clear 502 (the runtime is healthy but its\n // dependency returned the wrong shape) instead of a 200 the client will\n // choke on.\n if (\n data == null ||\n typeof data !== \"object\" ||\n !Array.isArray((data as { memories?: unknown }).memories)\n ) {\n logger.error(\n { data },\n \"listMemories: platform returned a response without a `memories` array\",\n );\n return errorResponse(\n \"Memory platform returned an invalid list response\",\n 502,\n );\n }\n\n return Response.json(data);\n } catch (error) {\n logger.error({ err: error }, \"Error listing memories\");\n return memoryErrorResponse(error, \"Failed to list memories\");\n }\n }\n\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n}\n\n/**\n * Mints memory-realtime join credentials (platform `POST\n * /api/memories/subscribe`). Mirrors {@link handleSubscribeToThreads}: requires\n * a `CopilotKitIntelligence` runtime and resolves the user with `identifyUser`\n * (never a client-supplied id). Returns `{ joinToken, joinCode }` — memory needs\n * the `joinCode` here (unlike threads, where it rides the thread-list response)\n * because the client builds the `user_meta:memories:<joinCode>` channel topic\n * from it.\n */\nexport async function handleSubscribeToMemories({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (isIntelligenceRuntime(runtime)) {\n try {\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const credentials = await runtime.intelligence.ɵsubscribeToMemories({\n userId: user.id,\n });\n\n return Response.json({\n joinToken: credentials.joinToken,\n joinCode: credentials.joinCode,\n });\n } catch (error) {\n logger.error({ err: error }, \"Error subscribing to memories\");\n return memoryErrorResponse(error, \"Failed to subscribe to memories\");\n }\n }\n\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n}\n\n/**\n * Creates a memory for the resolved user (platform `POST /api/memories`).\n * Identity comes from `identifyUser`, never the request body. Returns 201\n * with the stored memory (the client store applies it server-authoritatively).\n */\nexport async function handleCreateMemory({\n runtime,\n request,\n}: MemoriesHandlerParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const body = await parseJsonBody(request);\n if (isHandlerResponse(body)) return body;\n const fields = parseMemoryBody(body);\n if (isHandlerResponse(fields)) return fields;\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.createMemory({\n userId: user.id,\n ...fields,\n });\n return Response.json(data, { status: 201 });\n } catch (error) {\n logger.error({ err: error }, \"Error creating memory\");\n return memoryErrorResponse(error, \"Failed to create memory\");\n }\n}\n\n/**\n * Supersedes a memory (platform `PATCH /api/memories/:id`): retires `:id` and\n * inserts the new content atomically; the response carries `retiredId`.\n */\nexport async function handleUpdateMemory({\n runtime,\n request,\n memoryId,\n}: MemoryMutationParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const body = await parseJsonBody(request);\n if (isHandlerResponse(body)) return body;\n const fields = parseMemoryBody(body);\n if (isHandlerResponse(fields)) return fields;\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n const data = await runtime.intelligence.updateMemory({\n userId: user.id,\n id: memoryId,\n ...fields,\n });\n return Response.json(data);\n } catch (error) {\n logger.error({ err: error }, \"Error updating memory\");\n return memoryErrorResponse(error, \"Failed to update memory\");\n }\n}\n\n/**\n * Retires (forgets) a memory (platform `DELETE /api/memories/:id`). Non-lossy\n * on the platform side; returns 204.\n */\nexport async function handleRemoveMemory({\n runtime,\n request,\n memoryId,\n}: MemoryMutationParams): Promise<Response> {\n if (!isIntelligenceRuntime(runtime)) {\n return errorResponse(MISSING_INTELLIGENCE_MESSAGE, 422);\n }\n try {\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) return user;\n\n await runtime.intelligence.removeMemory({ userId: user.id, id: memoryId });\n return new Response(null, { status: 204 });\n } catch (error) {\n logger.error({ err: error }, \"Error removing memory\");\n return memoryErrorResponse(error, \"Failed to remove memory\");\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require("reflect-metadata");
|
|
2
2
|
const require_runtime = require('../../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_header_utils = require('../header-utils.cjs');
|
|
3
4
|
const require_runtime$1 = require('../../core/runtime.cjs');
|
|
4
5
|
const require_open_generative_ui_middleware = require('../../open-generative-ui-middleware.cjs');
|
|
5
6
|
const require_client = require('../../intelligence-platform/client.cjs');
|
|
6
|
-
const require_header_utils = require('../header-utils.cjs');
|
|
7
7
|
const require_resolve_intelligence_user = require('./resolve-intelligence-user.cjs');
|
|
8
8
|
let _copilotkit_shared = require("@copilotkit/shared");
|
|
9
9
|
let _ag_ui_client = require("@ag-ui/client");
|
|
@@ -12,6 +12,22 @@ let _ag_ui_mcp_apps_middleware = require("@ag-ui/mcp-apps-middleware");
|
|
|
12
12
|
let _ag_ui_mcp_middleware = require("@ag-ui/mcp-middleware");
|
|
13
13
|
|
|
14
14
|
//#region src/v2/runtime/handlers/shared/agent-utils.ts
|
|
15
|
+
/**
|
|
16
|
+
* Resolve `agentId` against the runtime's agents and return a per-request
|
|
17
|
+
* clone of the matching agent.
|
|
18
|
+
*
|
|
19
|
+
* Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)
|
|
20
|
+
* depend on it:
|
|
21
|
+
* - Returns a cloned `AbstractAgent` when the agent exists.
|
|
22
|
+
* - Returns a 404 `Response` (`{ error: "Agent not found", ... }`) when the
|
|
23
|
+
* agent is unknown. Callers MUST `instanceof Response`-check the result and
|
|
24
|
+
* return it directly; this doubles as the connect/run path's agent-existence
|
|
25
|
+
* guard, so skipping the check would let unknown agent ids slip through.
|
|
26
|
+
*
|
|
27
|
+
* The clone is what subsequent per-request mutation (middleware attach,
|
|
28
|
+
* `agent.headers` merge) operates on, leaving the shared agent registration
|
|
29
|
+
* untouched.
|
|
30
|
+
*/
|
|
15
31
|
async function cloneAgentForRequest(runtime, agentId, request) {
|
|
16
32
|
const agents = await require_runtime$1.resolveAgents(runtime.agents, request);
|
|
17
33
|
if (!agents[agentId]) return new Response(JSON.stringify({
|
|
@@ -47,10 +63,7 @@ function configureAgentForRequest(params) {
|
|
|
47
63
|
const targetAgents = typeof config === "object" ? config.agents : void 0;
|
|
48
64
|
if ((!targetAgents || targetAgents.includes(agentId)) && typeof agent.use === "function") agent.use(new require_open_generative_ui_middleware.OpenGenerativeUIMiddleware());
|
|
49
65
|
}
|
|
50
|
-
agent.headers =
|
|
51
|
-
...agent.headers,
|
|
52
|
-
...require_header_utils.extractForwardableHeaders(request)
|
|
53
|
-
};
|
|
66
|
+
agent.headers = require_header_utils.mergeForwardableHeaders(agent.headers, request, runtime.forwardHeadersPolicy ?? require_header_utils.resolveForwardHeadersPolicy(void 0));
|
|
54
67
|
}
|
|
55
68
|
/**
|
|
56
69
|
* Attach the Intelligence platform's MCP tools to the agent run when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","MCPAppsMiddleware","OpenGenerativeUIMiddleware","extractForwardableHeaders","isIntelligenceRuntime","resolveIntelligenceUser","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/client\";\nimport { A2UIMiddleware } from \"@ag-ui/a2ui-middleware\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport { OpenGenerativeUIMiddleware } from \"../../open-generative-ui-middleware\";\nimport { INTELLIGENCE_USER_ID_HEADER } from \"../../intelligence-platform/client\";\nimport { extractForwardableHeaders } from \"../header-utils\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n}): void {\n const { runtime, request, agentId, providerA2UIHasCatalog } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (runtime.mcpApps?.servers?.length) {\n const mcpServers = runtime.mcpApps.servers\n .filter((server) => !server.agentId || server.agentId === agentId)\n .map((server) => {\n const mcpServer = { ...server };\n delete mcpServer.agentId;\n return mcpServer;\n });\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n agent.headers = {\n ...agent.headers,\n ...extractForwardableHeaders(request),\n };\n}\n\n/**\n * Attach the Intelligence platform's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (\n !isIntelligenceRuntime(runtime) ||\n !runtime.intelligence?.ɵisEnterpriseLearningEnabled?.()\n ) {\n return;\n }\n\n // Enterprise learning is enabled, but this agent's framework can't take\n // middleware — surface it rather than silently shipping a run with none\n // of the tools the operator opted into.\n if (typeof agent.use !== \"function\") {\n logger.warn(\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\",\n );\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return;\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n },\n },\n ]),\n );\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return RunAgentInputSchema.parse(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = RunAgentInputSchema.parse(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","MCPAppsMiddleware","OpenGenerativeUIMiddleware","mergeForwardableHeaders","resolveForwardHeadersPolicy","isIntelligenceRuntime","resolveIntelligenceUser","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/client\";\nimport { A2UIMiddleware } from \"@ag-ui/a2ui-middleware\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport { OpenGenerativeUIMiddleware } from \"../../open-generative-ui-middleware\";\nimport { INTELLIGENCE_USER_ID_HEADER } from \"../../intelligence-platform/client\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\n/**\n * Resolve `agentId` against the runtime's agents and return a per-request\n * clone of the matching agent.\n *\n * Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)\n * depend on it:\n * - Returns a cloned `AbstractAgent` when the agent exists.\n * - Returns a 404 `Response` (`{ error: \"Agent not found\", ... }`) when the\n * agent is unknown. Callers MUST `instanceof Response`-check the result and\n * return it directly; this doubles as the connect/run path's agent-existence\n * guard, so skipping the check would let unknown agent ids slip through.\n *\n * The clone is what subsequent per-request mutation (middleware attach,\n * `agent.headers` merge) operates on, leaving the shared agent registration\n * untouched.\n */\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n}): void {\n const { runtime, request, agentId, providerA2UIHasCatalog } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (runtime.mcpApps?.servers?.length) {\n const mcpServers = runtime.mcpApps.servers\n .filter((server) => !server.agentId || server.agentId === agentId)\n .map((server) => {\n const mcpServer = { ...server };\n delete mcpServer.agentId;\n return mcpServer;\n });\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n // Forward eligible inbound headers onto the outgoing agent call under the\n // runtime's resolved forwarding policy (`authorization` / custom `x-*`, with\n // known infra/proxy/platform headers stripped by the default denylist —\n // #5712), but let headers the server explicitly configured on the agent WIN\n // on collision (case-insensitively): a server-set service-to-service token\n // (e.g. an IAM bearer) must never be silently overridden by a\n // browser/edge/platform-injected inbound header. See `mergeForwardableHeaders`\n // for the casing/duplicate-key rationale and `shouldForwardHeader` for breadth.\n agent.headers = mergeForwardableHeaders(\n agent.headers,\n request,\n // `forwardHeadersPolicy` is optional on the published `CopilotRuntimeLike`\n // interface (non-breaking minor release). Concrete runtimes always set it;\n // a policy-less external implementor falls back to the default resolved\n // policy (default-on denylist) so behavior stays identical and never derefs\n // undefined.\n runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(undefined),\n );\n}\n\n/**\n * Attach the Intelligence platform's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (\n !isIntelligenceRuntime(runtime) ||\n !runtime.intelligence?.ɵisEnterpriseLearningEnabled?.()\n ) {\n return;\n }\n\n // Enterprise learning is enabled, but this agent's framework can't take\n // middleware — surface it rather than silently shipping a run with none\n // of the tools the operator opted into.\n if (typeof agent.use !== \"function\") {\n logger.warn(\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\",\n );\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return;\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n },\n },\n ]),\n );\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return RunAgentInputSchema.parse(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = RunAgentInputSchema.parse(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
+
import { mergeForwardableHeaders, resolveForwardHeadersPolicy } from "../header-utils.mjs";
|
|
2
3
|
import { isA2UIEnabled, isIntelligenceRuntime, resolveAgents } from "../../core/runtime.mjs";
|
|
3
4
|
import { OpenGenerativeUIMiddleware } from "../../open-generative-ui-middleware.mjs";
|
|
4
5
|
import { INTELLIGENCE_USER_ID_HEADER } from "../../intelligence-platform/client.mjs";
|
|
5
|
-
import { extractForwardableHeaders } from "../header-utils.mjs";
|
|
6
6
|
import { resolveIntelligenceUser } from "./resolve-intelligence-user.mjs";
|
|
7
7
|
import { logger } from "@copilotkit/shared";
|
|
8
8
|
import { RunAgentInputSchema } from "@ag-ui/client";
|
|
@@ -11,6 +11,22 @@ import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
|
|
|
11
11
|
import { MCPMiddleware } from "@ag-ui/mcp-middleware";
|
|
12
12
|
|
|
13
13
|
//#region src/v2/runtime/handlers/shared/agent-utils.ts
|
|
14
|
+
/**
|
|
15
|
+
* Resolve `agentId` against the runtime's agents and return a per-request
|
|
16
|
+
* clone of the matching agent.
|
|
17
|
+
*
|
|
18
|
+
* Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)
|
|
19
|
+
* depend on it:
|
|
20
|
+
* - Returns a cloned `AbstractAgent` when the agent exists.
|
|
21
|
+
* - Returns a 404 `Response` (`{ error: "Agent not found", ... }`) when the
|
|
22
|
+
* agent is unknown. Callers MUST `instanceof Response`-check the result and
|
|
23
|
+
* return it directly; this doubles as the connect/run path's agent-existence
|
|
24
|
+
* guard, so skipping the check would let unknown agent ids slip through.
|
|
25
|
+
*
|
|
26
|
+
* The clone is what subsequent per-request mutation (middleware attach,
|
|
27
|
+
* `agent.headers` merge) operates on, leaving the shared agent registration
|
|
28
|
+
* untouched.
|
|
29
|
+
*/
|
|
14
30
|
async function cloneAgentForRequest(runtime, agentId, request) {
|
|
15
31
|
const agents = await resolveAgents(runtime.agents, request);
|
|
16
32
|
if (!agents[agentId]) return new Response(JSON.stringify({
|
|
@@ -46,10 +62,7 @@ function configureAgentForRequest(params) {
|
|
|
46
62
|
const targetAgents = typeof config === "object" ? config.agents : void 0;
|
|
47
63
|
if ((!targetAgents || targetAgents.includes(agentId)) && typeof agent.use === "function") agent.use(new OpenGenerativeUIMiddleware());
|
|
48
64
|
}
|
|
49
|
-
agent.headers =
|
|
50
|
-
...agent.headers,
|
|
51
|
-
...extractForwardableHeaders(request)
|
|
52
|
-
};
|
|
65
|
+
agent.headers = mergeForwardableHeaders(agent.headers, request, runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(void 0));
|
|
53
66
|
}
|
|
54
67
|
/**
|
|
55
68
|
* Attach the Intelligence platform's MCP tools to the agent run when
|