@copilotkit/runtime 1.80.0 → 1.82.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/_virtual/_rolldown/runtime.mjs +15 -1
- package/dist/agent/index.cjs +10 -7
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +1 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +10 -7
- package/dist/agent/index.mjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +17 -2
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +2 -2
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +2 -2
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +18 -3
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/runtime/legacy-service-adapter-agent.cjs +360 -0
- package/dist/lib/runtime/legacy-service-adapter-agent.cjs.map +1 -0
- package/dist/lib/runtime/legacy-service-adapter-agent.mjs +359 -0
- package/dist/lib/runtime/legacy-service-adapter-agent.mjs.map +1 -0
- package/dist/lib/runtime/telemetry-agent-runner.cjs +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.cjs.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.cts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.mts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs.map +1 -1
- package/dist/lib/telemetry-client.cjs +12 -1
- package/dist/lib/telemetry-client.cjs.map +1 -1
- package/dist/lib/telemetry-client.mjs +12 -1
- package/dist/lib/telemetry-client.mjs.map +1 -1
- package/dist/package.cjs +2 -2
- package/dist/package.mjs +2 -2
- package/dist/service-adapters/events.cjs +91 -0
- package/dist/service-adapters/events.cjs.map +1 -1
- package/dist/service-adapters/events.d.cts +6 -1
- package/dist/service-adapters/events.d.cts.map +1 -1
- package/dist/service-adapters/events.d.mts +6 -1
- package/dist/service-adapters/events.d.mts.map +1 -1
- package/dist/service-adapters/events.mjs +90 -1
- package/dist/service-adapters/events.mjs.map +1 -1
- package/dist/service-adapters/langchain/langchain-adapter.cjs +1 -1
- package/dist/service-adapters/langchain/langchain-adapter.cjs.map +1 -1
- package/dist/service-adapters/langchain/langchain-adapter.d.cts.map +1 -1
- package/dist/service-adapters/langchain/langchain-adapter.d.mts.map +1 -1
- package/dist/service-adapters/langchain/langchain-adapter.mjs +2 -2
- package/dist/service-adapters/langchain/langchain-adapter.mjs.map +1 -1
- package/dist/service-adapters/langchain/utils.cjs +53 -15
- package/dist/service-adapters/langchain/utils.cjs.map +1 -1
- package/dist/service-adapters/langchain/utils.mjs +53 -16
- package/dist/service-adapters/langchain/utils.mjs.map +1 -1
- package/dist/v2/index.cjs +5 -0
- package/dist/v2/index.d.cts +5 -2
- package/dist/v2/index.d.mts +5 -2
- package/dist/v2/index.mjs +4 -2
- package/dist/v2/runtime/core/channel-manager.cjs +1 -0
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +1 -0
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.cjs +1 -1
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/package-info.cjs +1 -1
- package/dist/v2/runtime/core/package-info.mjs +1 -1
- package/dist/v2/runtime/core/runtime.cjs +5 -1
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +15 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +15 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +5 -1
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/endpoints/express.cjs +2 -2
- package/dist/v2/runtime/endpoints/express.cjs.map +1 -1
- package/dist/v2/runtime/endpoints/express.mjs +2 -2
- package/dist/v2/runtime/endpoints/express.mjs.map +1 -1
- package/dist/v2/runtime/endpoints/node-fetch-handler.cjs +51 -1
- package/dist/v2/runtime/endpoints/node-fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/endpoints/node-fetch-handler.d.cts.map +1 -1
- package/dist/v2/runtime/endpoints/node-fetch-handler.d.mts.map +1 -1
- package/dist/v2/runtime/endpoints/node-fetch-handler.mjs +52 -2
- package/dist/v2/runtime/endpoints/node-fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.cjs +394 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.cjs.map +1 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.cts +21 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.cts.map +1 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.mts +21 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.mts.map +1 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.mjs +393 -0
- package/dist/v2/runtime/generative-ui/generative-ui-middleware.mjs.map +1 -0
- package/dist/v2/runtime/generative-ui/index.d.cts +3 -0
- package/dist/v2/runtime/generative-ui/index.d.mts +3 -0
- package/dist/v2/runtime/generative-ui/surface-writer.cjs +86 -0
- package/dist/v2/runtime/generative-ui/surface-writer.cjs.map +1 -0
- package/dist/v2/runtime/generative-ui/surface-writer.d.cts +33 -0
- package/dist/v2/runtime/generative-ui/surface-writer.d.cts.map +1 -0
- package/dist/v2/runtime/generative-ui/surface-writer.d.mts +33 -0
- package/dist/v2/runtime/generative-ui/surface-writer.d.mts.map +1 -0
- package/dist/v2/runtime/generative-ui/surface-writer.mjs +85 -0
- package/dist/v2/runtime/generative-ui/surface-writer.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs +8 -3
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +5 -1
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +7 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +7 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs +2 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs +3 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +5 -1
- package/dist/v2/runtime/index.d.cts.map +1 -1
- package/dist/v2/runtime/index.d.mts +5 -1
- package/dist/v2/runtime/index.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +85 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +24 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +24 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +85 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/experimental.d.cts +27 -0
- package/dist/v2/runtime/intelligence-platform/experimental.d.cts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/experimental.d.mts +27 -0
- package/dist/v2/runtime/intelligence-platform/experimental.d.mts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/index.d.cts +2 -1
- package/dist/v2/runtime/intelligence-platform/index.d.mts +2 -1
- package/dist/v2/runtime/intelligence-platform/learning-management.cjs +204 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.cjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.d.cts +112 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.d.cts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.d.mts +112 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.d.mts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.mjs +194 -0
- package/dist/v2/runtime/intelligence-platform/learning-management.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs +0 -82
- package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs.map +0 -1
- package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs +0 -81
- package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs.map +0 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/v2/runtime/intelligence-platform/learning-management.ts
|
|
5
|
+
/** Wire contracts for the project-key Learning API; keep aligned with Intelligence. */
|
|
6
|
+
const learningContainerIdSchema = z.string().min(1).max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
|
|
7
|
+
const learningContainerSchema = z.object({
|
|
8
|
+
id: learningContainerIdSchema,
|
|
9
|
+
name: z.string().min(1),
|
|
10
|
+
projectId: z.number().int().positive(),
|
|
11
|
+
promptContext: z.string().nullable(),
|
|
12
|
+
createdAt: z.string().datetime({ offset: true }),
|
|
13
|
+
updatedAt: z.string().datetime({ offset: true })
|
|
14
|
+
});
|
|
15
|
+
const learningContainerPageSchema = z.object({
|
|
16
|
+
containers: z.array(learningContainerSchema).max(500),
|
|
17
|
+
nextCursor: z.string().min(1).nullable()
|
|
18
|
+
});
|
|
19
|
+
/** Validates a stable identifier before constructing a request path. */
|
|
20
|
+
function learningContainerPath(containerId) {
|
|
21
|
+
return `/api/v1/learning/containers/${encodeURIComponent(learningContainerIdSchema.parse(containerId))}`;
|
|
22
|
+
}
|
|
23
|
+
/** Reads a bounded JSON response while the request's signal governs stream cancellation. */
|
|
24
|
+
async function readLearningJson(response, limit = 16 * 1024 * 1024, signal) {
|
|
25
|
+
if (!response.body) throw new Error("Missing Learning response body");
|
|
26
|
+
const reader = response.body.getReader();
|
|
27
|
+
const abort = () => {
|
|
28
|
+
reader.cancel(signal?.reason).catch(() => void 0);
|
|
29
|
+
};
|
|
30
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
31
|
+
if (signal?.aborted) abort();
|
|
32
|
+
const decoder = new TextDecoder();
|
|
33
|
+
let text = "";
|
|
34
|
+
let bytes = 0;
|
|
35
|
+
try {
|
|
36
|
+
while (true) {
|
|
37
|
+
signal?.throwIfAborted();
|
|
38
|
+
const next = await reader.read();
|
|
39
|
+
signal?.throwIfAborted();
|
|
40
|
+
if (next.done) break;
|
|
41
|
+
bytes += next.value.byteLength;
|
|
42
|
+
if (bytes > limit) {
|
|
43
|
+
await reader.cancel();
|
|
44
|
+
throw new Error("Learning response exceeds its size limit");
|
|
45
|
+
}
|
|
46
|
+
text += decoder.decode(next.value, { stream: true });
|
|
47
|
+
}
|
|
48
|
+
return JSON.parse(text + decoder.decode());
|
|
49
|
+
} finally {
|
|
50
|
+
signal?.removeEventListener("abort", abort);
|
|
51
|
+
reader.releaseLock();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const learningSha256Schema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
55
|
+
const learningUuidSchema = z.string().uuid();
|
|
56
|
+
const learningDateTimeSchema = z.string().datetime({ offset: true });
|
|
57
|
+
/** One immutable file in a proposed Skill candidate bundle. */
|
|
58
|
+
const learningSkillBundleFileSchema = z.object({
|
|
59
|
+
content: z.string(),
|
|
60
|
+
path: z.string().min(1).refine((path) => !path.startsWith("/") && !path.split("/").some((segment) => segment === ".."), "Bundle paths must be relative and may not traverse parent directories."),
|
|
61
|
+
sha256: learningSha256Schema
|
|
62
|
+
});
|
|
63
|
+
/** Complete Skill files attached to one review candidate. */
|
|
64
|
+
const learningSkillBundleSchema = z.object({
|
|
65
|
+
files: z.array(learningSkillBundleFileSchema).min(1),
|
|
66
|
+
schemaVersion: z.literal(1)
|
|
67
|
+
}).superRefine(({ files }, context) => {
|
|
68
|
+
const paths = /* @__PURE__ */ new Set();
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
if (paths.has(file.path)) context.addIssue({
|
|
71
|
+
code: "custom",
|
|
72
|
+
message: `Duplicate bundle path: ${file.path}`,
|
|
73
|
+
path: ["files"]
|
|
74
|
+
});
|
|
75
|
+
paths.add(file.path);
|
|
76
|
+
}
|
|
77
|
+
if (!paths.has("SKILL.md")) context.addIssue({
|
|
78
|
+
code: "custom",
|
|
79
|
+
message: "A Skill bundle must contain SKILL.md.",
|
|
80
|
+
path: ["files"]
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
/** Review state and summary returned for one proposed Skill change. */
|
|
84
|
+
const learningCandidateSchema = z.object({
|
|
85
|
+
bundleSha256: learningSha256Schema,
|
|
86
|
+
createdAt: learningDateTimeSchema,
|
|
87
|
+
description: z.string().min(1),
|
|
88
|
+
id: learningUuidSchema,
|
|
89
|
+
operation: z.enum([
|
|
90
|
+
"add",
|
|
91
|
+
"update",
|
|
92
|
+
"remove"
|
|
93
|
+
]),
|
|
94
|
+
publishedRegistryRevision: z.number().int().positive().nullable(),
|
|
95
|
+
publishedSkillId: learningUuidSchema.nullable(),
|
|
96
|
+
reason: z.string().min(1),
|
|
97
|
+
registryBaseRevision: z.number().int().nonnegative(),
|
|
98
|
+
reviewedAt: learningDateTimeSchema.nullable(),
|
|
99
|
+
runId: learningUuidSchema,
|
|
100
|
+
status: z.enum([
|
|
101
|
+
"pending_review",
|
|
102
|
+
"approved",
|
|
103
|
+
"rejected"
|
|
104
|
+
]),
|
|
105
|
+
subjectSha256: learningSha256Schema,
|
|
106
|
+
targetSkillId: learningUuidSchema.nullable(),
|
|
107
|
+
targetSkillRevision: z.number().int().positive().nullable(),
|
|
108
|
+
title: z.string().min(1)
|
|
109
|
+
});
|
|
110
|
+
/** Full proposed Skill change, including evidence and every bundle file. */
|
|
111
|
+
const learningCandidateDetailSchema = learningCandidateSchema.extend({
|
|
112
|
+
bundle: learningSkillBundleSchema,
|
|
113
|
+
supportingInsights: z.array(z.object({
|
|
114
|
+
alias: z.string().min(1),
|
|
115
|
+
id: learningUuidSchema,
|
|
116
|
+
impact: z.string().min(1),
|
|
117
|
+
statement: z.string().min(1)
|
|
118
|
+
}))
|
|
119
|
+
});
|
|
120
|
+
/** Result returned after a human or agent reviews a Skill candidate. */
|
|
121
|
+
const learningCandidateReviewSchema = z.object({
|
|
122
|
+
candidateId: learningUuidSchema,
|
|
123
|
+
operation: z.enum([
|
|
124
|
+
"add",
|
|
125
|
+
"update",
|
|
126
|
+
"remove"
|
|
127
|
+
]),
|
|
128
|
+
publishedRegistryRevision: z.number().int().positive().nullable(),
|
|
129
|
+
publishedSkillId: learningUuidSchema.nullable(),
|
|
130
|
+
status: z.enum(["approved", "rejected"])
|
|
131
|
+
});
|
|
132
|
+
const learningRunSchema = z.object({
|
|
133
|
+
id: z.string().uuid(),
|
|
134
|
+
learningContainerId: learningContainerIdSchema,
|
|
135
|
+
projectId: z.number().int().positive(),
|
|
136
|
+
status: z.enum([
|
|
137
|
+
"queued",
|
|
138
|
+
"freezing",
|
|
139
|
+
"batching",
|
|
140
|
+
"reducing",
|
|
141
|
+
"finalizing",
|
|
142
|
+
"succeeded",
|
|
143
|
+
"failed"
|
|
144
|
+
]),
|
|
145
|
+
triggerSource: z.enum(["automatic", "manual"]),
|
|
146
|
+
attemptCount: z.number().int().nonnegative(),
|
|
147
|
+
candidateCount: z.number().int().nonnegative().nullable(),
|
|
148
|
+
insightCount: z.number().int().nonnegative().nullable(),
|
|
149
|
+
evidenceThreadCount: z.number().int().nonnegative().nullable().optional(),
|
|
150
|
+
createdAt: learningDateTimeSchema,
|
|
151
|
+
updatedAt: learningDateTimeSchema,
|
|
152
|
+
startedAt: learningDateTimeSchema.nullable(),
|
|
153
|
+
completedAt: learningDateTimeSchema.nullable(),
|
|
154
|
+
failureCode: z.string().nullable(),
|
|
155
|
+
kubernetesJobName: z.string().nullable()
|
|
156
|
+
});
|
|
157
|
+
const unavailableSchema = z.enum(["snapshot-missing", "snapshot-unreadable"]).nullable();
|
|
158
|
+
const learningInsightEvidenceSchema = z.union([z.object({
|
|
159
|
+
cited: z.array(z.object({
|
|
160
|
+
id: z.string(),
|
|
161
|
+
content: z.string(),
|
|
162
|
+
role: z.enum([
|
|
163
|
+
"assistant",
|
|
164
|
+
"tool",
|
|
165
|
+
"user"
|
|
166
|
+
])
|
|
167
|
+
})),
|
|
168
|
+
messageCount: z.number().int().nonnegative(),
|
|
169
|
+
threadId: z.string(),
|
|
170
|
+
threadName: z.string().nullable(),
|
|
171
|
+
threadPresent: z.boolean(),
|
|
172
|
+
unavailable: unavailableSchema
|
|
173
|
+
}), z.object({
|
|
174
|
+
kind: z.literal("trajectory"),
|
|
175
|
+
trajectoryId: z.string().uuid(),
|
|
176
|
+
trajectoryPresent: z.boolean(),
|
|
177
|
+
eventCount: z.number().int().nonnegative(),
|
|
178
|
+
events: z.array(z.object({
|
|
179
|
+
seq: z.number().int().nonnegative(),
|
|
180
|
+
name: z.string(),
|
|
181
|
+
offsetMs: z.number(),
|
|
182
|
+
value: z.unknown(),
|
|
183
|
+
eventId: z.string().nullable()
|
|
184
|
+
})),
|
|
185
|
+
unavailable: unavailableSchema
|
|
186
|
+
})]);
|
|
187
|
+
/** Validates object IDs independently from container IDs; neither may alter the path. */
|
|
188
|
+
function learningObjectId(id) {
|
|
189
|
+
return z.string().uuid().parse(id);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
export { learningCandidateDetailSchema, learningCandidateReviewSchema, learningCandidateSchema, learningContainerPageSchema, learningContainerPath, learningContainerSchema, learningInsightEvidenceSchema, learningObjectId, learningRunSchema, readLearningJson };
|
|
194
|
+
//# sourceMappingURL=learning-management.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning-management.mjs","names":[],"sources":["../../../../src/v2/runtime/intelligence-platform/learning-management.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** Wire contracts for the project-key Learning API; keep aligned with Intelligence. */\nexport const learningContainerIdSchema = z\n .string()\n .min(1)\n .max(64)\n .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);\nexport const learningContainerSchema = z.object({\n id: learningContainerIdSchema,\n name: z.string().min(1),\n projectId: z.number().int().positive(),\n promptContext: z.string().nullable(),\n createdAt: z.string().datetime({ offset: true }),\n updatedAt: z.string().datetime({ offset: true }),\n});\nexport const learningContainerPageSchema = z.object({\n containers: z.array(learningContainerSchema).max(500),\n nextCursor: z.string().min(1).nullable(),\n});\n/** Explicit wire types preserve required/null fields in declarations emitted with strictNullChecks disabled. */\nexport interface LearningContainer {\n id: string;\n name: string;\n projectId: number;\n promptContext: string | null;\n createdAt: string;\n updatedAt: string;\n}\nexport interface LearningContainerPage {\n containers: LearningContainer[];\n nextCursor: string | null;\n}\nexport interface LearningRequestOptions {\n readonly signal?: AbortSignal;\n}\nexport interface LearningContainerRequest extends LearningRequestOptions {\n readonly containerId: string;\n}\n\n/** Validates a stable identifier before constructing a request path. */\nexport function learningContainerPath(containerId: string): string {\n return `/api/v1/learning/containers/${encodeURIComponent(learningContainerIdSchema.parse(containerId))}`;\n}\n\n/** Reads a bounded JSON response while the request's signal governs stream cancellation. */\nexport async function readLearningJson(\n response: Response,\n limit = 16 * 1024 * 1024,\n signal?: AbortSignal,\n): Promise<unknown> {\n if (!response.body) throw new Error(\"Missing Learning response body\");\n const reader = response.body.getReader();\n const abort = () => {\n void reader.cancel(signal?.reason).catch(() => undefined);\n };\n signal?.addEventListener(\"abort\", abort, { once: true });\n if (signal?.aborted) abort();\n const decoder = new TextDecoder();\n let text = \"\";\n let bytes = 0;\n try {\n while (true) {\n signal?.throwIfAborted();\n const next = await reader.read();\n signal?.throwIfAborted();\n if (next.done) break;\n bytes += next.value.byteLength;\n if (bytes > limit) {\n await reader.cancel();\n throw new Error(\"Learning response exceeds its size limit\");\n }\n text += decoder.decode(next.value, { stream: true });\n }\n return JSON.parse(text + decoder.decode());\n } finally {\n signal?.removeEventListener(\"abort\", abort);\n reader.releaseLock();\n }\n}\n\nconst learningSha256Schema = z.string().regex(/^[a-f0-9]{64}$/u);\nconst learningUuidSchema = z.string().uuid();\nconst learningDateTimeSchema = z.string().datetime({ offset: true });\n\n/** One immutable file in a proposed Skill candidate bundle. */\nexport const learningSkillBundleFileSchema = z.object({\n content: z.string(),\n path: z\n .string()\n .min(1)\n .refine(\n (path) =>\n !path.startsWith(\"/\") &&\n !path.split(\"/\").some((segment) => segment === \"..\"),\n \"Bundle paths must be relative and may not traverse parent directories.\",\n ),\n sha256: learningSha256Schema,\n});\n\n/** Complete Skill files attached to one review candidate. */\nexport const learningSkillBundleSchema = z\n .object({\n files: z.array(learningSkillBundleFileSchema).min(1),\n schemaVersion: z.literal(1),\n })\n\n .superRefine(({ files }, context) => {\n const paths = new Set<string>();\n for (const file of files) {\n if (paths.has(file.path)) {\n context.addIssue({\n code: \"custom\",\n message: `Duplicate bundle path: ${file.path}`,\n path: [\"files\"],\n });\n }\n paths.add(file.path);\n }\n if (!paths.has(\"SKILL.md\")) {\n context.addIssue({\n code: \"custom\",\n message: \"A Skill bundle must contain SKILL.md.\",\n path: [\"files\"],\n });\n }\n });\n\n/** Review state and summary returned for one proposed Skill change. */\nexport const learningCandidateSchema = z.object({\n bundleSha256: learningSha256Schema,\n createdAt: learningDateTimeSchema,\n description: z.string().min(1),\n id: learningUuidSchema,\n operation: z.enum([\"add\", \"update\", \"remove\"]),\n publishedRegistryRevision: z.number().int().positive().nullable(),\n publishedSkillId: learningUuidSchema.nullable(),\n reason: z.string().min(1),\n registryBaseRevision: z.number().int().nonnegative(),\n reviewedAt: learningDateTimeSchema.nullable(),\n runId: learningUuidSchema,\n status: z.enum([\"pending_review\", \"approved\", \"rejected\"]),\n subjectSha256: learningSha256Schema,\n targetSkillId: learningUuidSchema.nullable(),\n targetSkillRevision: z.number().int().positive().nullable(),\n title: z.string().min(1),\n});\n\n/** Full proposed Skill change, including evidence and every bundle file. */\nexport const learningCandidateDetailSchema = learningCandidateSchema.extend({\n bundle: learningSkillBundleSchema,\n supportingInsights: z.array(\n z.object({\n alias: z.string().min(1),\n id: learningUuidSchema,\n impact: z.string().min(1),\n statement: z.string().min(1),\n }),\n ),\n});\n\n/** Result returned after a human or agent reviews a Skill candidate. */\nexport const learningCandidateReviewSchema = z.object({\n candidateId: learningUuidSchema,\n operation: z.enum([\"add\", \"update\", \"remove\"]),\n publishedRegistryRevision: z.number().int().positive().nullable(),\n publishedSkillId: learningUuidSchema.nullable(),\n status: z.enum([\"approved\", \"rejected\"]),\n});\n\nexport interface LearningCandidate {\n id: string;\n bundleSha256: string;\n createdAt: string;\n description: string;\n operation: \"add\" | \"update\" | \"remove\";\n publishedRegistryRevision: number | null;\n publishedSkillId: string | null;\n reason: string;\n registryBaseRevision: number;\n reviewedAt: string | null;\n runId: string;\n status: \"pending_review\" | \"approved\" | \"rejected\";\n subjectSha256: string;\n targetSkillId: string | null;\n targetSkillRevision: number | null;\n title: string;\n}\nexport interface LearningCandidateDetail extends LearningCandidate {\n bundle: {\n schemaVersion: 1;\n files: Array<{ path: string; content: string; sha256: string }>;\n };\n supportingInsights: Array<{\n alias: string;\n id: string;\n impact: string;\n statement: string;\n }>;\n}\nexport interface LearningCandidateReview {\n candidateId: string;\n operation: \"add\" | \"update\" | \"remove\";\n publishedRegistryRevision: number | null;\n publishedSkillId: string | null;\n status: \"approved\" | \"rejected\";\n}\nexport interface LearningCandidateRequest extends LearningContainerRequest {\n readonly candidateId: string;\n}\n\nexport const learningRunSchema = z.object({\n id: z.string().uuid(),\n learningContainerId: learningContainerIdSchema,\n projectId: z.number().int().positive(),\n status: z.enum([\n \"queued\",\n \"freezing\",\n \"batching\",\n \"reducing\",\n \"finalizing\",\n \"succeeded\",\n \"failed\",\n ]),\n triggerSource: z.enum([\"automatic\", \"manual\"]),\n attemptCount: z.number().int().nonnegative(),\n candidateCount: z.number().int().nonnegative().nullable(),\n insightCount: z.number().int().nonnegative().nullable(),\n evidenceThreadCount: z.number().int().nonnegative().nullable().optional(),\n createdAt: learningDateTimeSchema,\n updatedAt: learningDateTimeSchema,\n startedAt: learningDateTimeSchema.nullable(),\n completedAt: learningDateTimeSchema.nullable(),\n failureCode: z.string().nullable(),\n kubernetesJobName: z.string().nullable(),\n});\nexport interface LearningRun {\n id: string;\n learningContainerId: string;\n projectId: number;\n status:\n | \"queued\"\n | \"freezing\"\n | \"batching\"\n | \"reducing\"\n | \"finalizing\"\n | \"succeeded\"\n | \"failed\";\n triggerSource: \"automatic\" | \"manual\";\n attemptCount: number;\n candidateCount: number | null;\n insightCount: number | null;\n evidenceThreadCount?: number | null;\n createdAt: string;\n updatedAt: string;\n startedAt: string | null;\n completedAt: string | null;\n failureCode: string | null;\n kubernetesJobName: string | null;\n}\nconst unavailableSchema = z\n .enum([\"snapshot-missing\", \"snapshot-unreadable\"])\n .nullable();\nexport const learningInsightEvidenceSchema = z.union([\n z.object({\n cited: z.array(\n z.object({\n id: z.string(),\n content: z.string(),\n role: z.enum([\"assistant\", \"tool\", \"user\"]),\n }),\n ),\n messageCount: z.number().int().nonnegative(),\n threadId: z.string(),\n threadName: z.string().nullable(),\n threadPresent: z.boolean(),\n unavailable: unavailableSchema,\n }),\n z.object({\n kind: z.literal(\"trajectory\"),\n trajectoryId: z.string().uuid(),\n trajectoryPresent: z.boolean(),\n eventCount: z.number().int().nonnegative(),\n events: z.array(\n z.object({\n seq: z.number().int().nonnegative(),\n name: z.string(),\n offsetMs: z.number(),\n value: z.unknown(),\n eventId: z.string().nullable(),\n }),\n ),\n unavailable: unavailableSchema,\n }),\n]);\nexport type LearningInsightEvidence =\n | {\n cited: Array<{\n id: string;\n content: string;\n role: \"assistant\" | \"tool\" | \"user\";\n }>;\n messageCount: number;\n threadId: string;\n threadName: string | null;\n threadPresent: boolean;\n unavailable: \"snapshot-missing\" | \"snapshot-unreadable\" | null;\n }\n | {\n kind: \"trajectory\";\n trajectoryId: string;\n trajectoryPresent: boolean;\n eventCount: number;\n events: Array<{\n seq: number;\n name: string;\n offsetMs: number;\n value?: unknown;\n eventId: string | null;\n }>;\n unavailable: \"snapshot-missing\" | \"snapshot-unreadable\" | null;\n };\n\n/** Validates object IDs independently from container IDs; neither may alter the path. */\nexport function learningObjectId(id: string): string {\n return z.string().uuid().parse(id);\n}\n"],"mappings":"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"}
|
|
@@ -59,7 +59,7 @@ var TelemetryClient = class {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
async captureWithIdentity(event, properties, identity) {
|
|
62
|
-
if (this.telemetryDisabled) return;
|
|
62
|
+
if (this.telemetryDisabled || isTelemetryDisabled()) return;
|
|
63
63
|
if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;
|
|
64
64
|
await _copilotkit_shared.lambdaClient.send({
|
|
65
65
|
event,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.cjs","names":["lambdaClient","TELEMETRY_EMITTER_V2","TELEMETRY_SURFACE_V2","RUNTIME_PACKAGE_NAME","RUNTIME_PACKAGE_VERSION"],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"sourcesContent":["import type { AnalyticsEvents } from \"./events\";\nimport {\n lambdaClient,\n parseAndWarnTelemetryId,\n computeSamplingMeta,\n TELEMETRY_EMITTER_V2,\n TELEMETRY_SURFACE_V2,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_PACKAGE_NAME,\n RUNTIME_PACKAGE_VERSION,\n} from \"../core/package-info\";\nimport { firstNonBlankTelemetryId } from \"./telemetry-identity\";\n\n/** Transport identity and sampling authority resolved for one runtime. */\nexport interface TelemetryIdentity {\n telemetryId?: string;\n licenseToken?: string;\n}\n\n/** Capture-only telemetry client bound to one runtime identity. */\nexport interface TelemetryCapture {\n capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void>;\n}\n\ninterface ResolvedTelemetryIdentity {\n telemetryId: string | null;\n licenseToken: string | null;\n licenseTelemetryId: string | null;\n}\n\nexport function isTelemetryDisabled(): boolean {\n return (\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"true\" ||\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"1\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK ===\n \"true\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK === \"1\"\n );\n}\n\nexport class TelemetryClient {\n private telemetryDisabled: boolean = false;\n // Opt-down for anonymous events, defaulting to 1: the sink is ours, so a\n // real count beats one extrapolated from a fraction of the population.\n // It stays configurable because it is the cross-SDK lever for reducing or\n // stopping anonymous volume — the Go, Python, Ruby, and .NET runtimes all\n // expose it, and the cross-language conformance suite drives it to 0 to\n // assert silence. Identified callers bypass it.\n private sampleRate: number = 1;\n // EIP / Intelligence license token (Ed25519-signed JWT). Kept separate\n // from standalone identity so the transport receives only the selected\n // identity source.\n private licenseToken: string | null = null;\n // Standalone identity sent as a transport claim. It does not make an\n // event identified.\n private telemetryId: string | null = null;\n // License-derived identity. This client sends every event either way;\n // the id is what sets telemetry_identified on the sampling block, which\n // is how the two populations stay separable downstream.\n private licenseTelemetryId: string | null = null;\n // Properties merged into every event this client sends.\n //\n // For facts about the caller that are true for the whole process rather than\n // for one event: which product is embedding the runtime, for instance. A\n // distribution built on top of this can then be told apart in the existing\n // events instead of sending its own, which is the difference between one\n // extra field and a second pipeline nobody asked for.\n //\n // Sent as `global_properties`, a field of its own, so these stay separable\n // from an event's own properties all the way to the sink.\n //\n // Do not reuse a key an event already sets: the fanout spreads this bag last\n // for `oss.runtime.*`, so a collision resolves in favour of the global and\n // does so silently. Names here should describe the caller, not the call.\n private globalProperties: Record<string, unknown> = {};\n\n constructor({\n telemetryDisabled,\n sampleRate,\n }: {\n telemetryDisabled?: boolean;\n sampleRate?: number;\n } = {}) {\n this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled();\n this.setSampleRate(sampleRate);\n }\n\n private shouldSendEvent() {\n if (this.sampleRate >= 1) return true;\n return Math.random() < this.sampleRate;\n }\n\n /**\n * Add properties carried by every subsequent event.\n *\n * Merged rather than replaced, so two callers setting different fields do not\n * erase each other. Set once at runtime construction in practice; nothing\n * here is per-request.\n */\n setGlobalProperties(properties: Record<string, unknown>) {\n this.globalProperties = { ...this.globalProperties, ...properties };\n }\n\n /** Atomically replace the process-wide telemetry identity. */\n setTelemetryIdentity(identity: TelemetryIdentity): void {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n this.telemetryId = resolvedIdentity.telemetryId;\n this.licenseToken = resolvedIdentity.licenseToken;\n this.licenseTelemetryId = resolvedIdentity.licenseTelemetryId;\n }\n\n /** @deprecated Prefer {@link setTelemetryIdentity}. */\n setLicenseToken(licenseToken: string): void {\n this.setTelemetryIdentity({ licenseToken });\n }\n\n /** Create an immutable capture scope for one Runtime instance. */\n createScope(identity: TelemetryIdentity): TelemetryCapture {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n return {\n capture: <K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ) => this.captureWithIdentity(event, properties, resolvedIdentity),\n };\n }\n\n async capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void> {\n return this.captureWithIdentity(event, properties, {\n telemetryId: this.telemetryId,\n licenseToken: this.licenseToken,\n licenseTelemetryId: this.licenseTelemetryId,\n });\n }\n\n private async captureWithIdentity<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n identity: ResolvedTelemetryIdentity,\n ): Promise<void> {\n if (this.telemetryDisabled) return;\n // Nothing is gated at the default rate of 1. A caller who dialled it\n // down means it, and identified callers are exempt either way.\n if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;\n\n await lambdaClient.send({\n event,\n properties: properties as Record<string, unknown>,\n // Its own field on the wire rather than folded into `properties`, which\n // is what the sink expects: for `oss.runtime.*` the fanout treats\n // `global_properties` as the SDK's pass-through bag and spreads it into\n // the analytics event, and v1's client sends package name and version the\n // same way. Folding it in would work and would put a process-level fact\n // in the per-event slot, where nothing downstream expects to find one.\n // Sampling metadata rides in the same slot, as it does in v1. It\n // reads 1/1 unless a caller dialled the rate down, and is stamped\n // either way: a consumer summing sampleWeight across emitters must\n // not find the field missing on a quarter of the rows, which is the\n // state that made ~24% of runtime volume unweightable (OSS-1017).\n globalProperties: {\n ...this.globalProperties,\n ...computeSamplingMeta({\n telemetryId: identity.licenseTelemetryId,\n sampleRate: this.sampleRate,\n }),\n telemetry_emitter: TELEMETRY_EMITTER_V2,\n // Constant here: a v1 request never reaches this client. The v1\n // entrypoint hands its own capture scope to the V2 runtime it\n // builds, so v1 traffic is emitted by the v1 client and stamped\n // v1 there — which is also what keeps it on the Segment wire.\n telemetry_surface: TELEMETRY_SURFACE_V2,\n // This client has one transport, so the marker is constant here. It\n // is stamped anyway so the property means the same thing on every\n // event whichever client produced it (OSS-1019).\n telemetry_transport: \"lambda\",\n },\n packageName: RUNTIME_PACKAGE_NAME,\n packageVersion: RUNTIME_PACKAGE_VERSION,\n telemetryId: identity.telemetryId ?? undefined,\n licenseToken: identity.licenseToken ?? undefined,\n });\n }\n\n private resolveTelemetryIdentity(\n identity: TelemetryIdentity,\n ): ResolvedTelemetryIdentity {\n const telemetryId = firstNonBlankTelemetryId(identity.telemetryId);\n if (telemetryId !== undefined) {\n return {\n telemetryId,\n licenseToken: null,\n licenseTelemetryId: null,\n };\n }\n\n return {\n telemetryId: null,\n licenseToken: identity.licenseToken ?? null,\n licenseTelemetryId: identity.licenseToken\n ? parseAndWarnTelemetryId(identity.licenseToken)\n : null,\n };\n }\n\n private setSampleRate(sampleRate: number | undefined) {\n let _sampleRate: number;\n\n _sampleRate = sampleRate ?? 1;\n\n if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) {\n _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);\n }\n\n // Number.isNaN guards against parseFloat(\"nonsense\") slipping past the\n // range check (all NaN comparisons are false), which would silently\n // drop every anonymous event with no signal.\n if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) {\n throw new Error(\"Sample rate must be between 0 and 1\");\n }\n\n this.sampleRate = _sampleRate;\n }\n}\n\nconst telemetry = new TelemetryClient();\nexport default telemetry;\n"],"mappings":";;;;;;AAkCA,SAAgB,sBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAoC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BAzC6B;oBAOR;sBAIS;qBAGD;4BAIO;0BAeQ,EAAE;AASpD,OAAK,oBAAoB,qBAAqB,qBAAqB;AACnE,OAAK,cAAc,WAAW;;CAGhC,AAAQ,kBAAkB;AACxB,MAAI,KAAK,cAAc,EAAG,QAAO;AACjC,SAAO,KAAK,QAAQ,GAAG,KAAK;;;;;;;;;CAU9B,oBAAoB,YAAqC;AACvD,OAAK,mBAAmB;GAAE,GAAG,KAAK;GAAkB,GAAG;GAAY;;;CAIrE,qBAAqB,UAAmC;EACtD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,OAAK,cAAc,iBAAiB;AACpC,OAAK,eAAe,iBAAiB;AACrC,OAAK,qBAAqB,iBAAiB;;;CAI7C,gBAAgB,cAA4B;AAC1C,OAAK,qBAAqB,EAAE,cAAc,CAAC;;;CAI7C,YAAY,UAA+C;EACzD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,SAAO,EACL,UACE,OACA,eACG,KAAK,oBAAoB,OAAO,YAAY,iBAAiB,EACnE;;CAGH,MAAM,QACJ,OACA,YACe;AACf,SAAO,KAAK,oBAAoB,OAAO,YAAY;GACjD,aAAa,KAAK;GAClB,cAAc,KAAK;GACnB,oBAAoB,KAAK;GAC1B,CAAC;;CAGJ,MAAc,oBACZ,OACA,YACA,UACe;AACf,MAAI,KAAK,kBAAmB;AAG5B,MAAI,CAAC,SAAS,sBAAsB,CAAC,KAAK,iBAAiB,CAAE;AAE7D,QAAMA,gCAAa,KAAK;GACtB;GACY;GAYZ,kBAAkB;IAChB,GAAG,KAAK;IACR,+CAAuB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmBC;IAKnB,mBAAmBC;IAInB,qBAAqB;IACtB;GACD,aAAaC;GACb,gBAAgBC;GAChB,aAAa,SAAS,eAAe;GACrC,cAAc,SAAS,gBAAgB;GACxC,CAAC;;CAGJ,AAAQ,yBACN,UAC2B;EAC3B,MAAM,+DAAuC,SAAS,YAAY;AAClE,MAAI,gBAAgB,OAClB,QAAO;GACL;GACA,cAAc;GACd,oBAAoB;GACrB;AAGH,SAAO;GACL,aAAa;GACb,cAAc,SAAS,gBAAgB;GACvC,oBAAoB,SAAS,+DACD,SAAS,aAAa,GAC9C;GACL;;CAGH,AAAQ,cAAc,YAAgC;EACpD,IAAI;AAEJ,gBAAc,cAAc;AAE5B,MAAI,QAAQ,IAAI,iCACd,eAAc,WAAW,QAAQ,IAAI,iCAAiC;AAMxE,MAAI,OAAO,MAAM,YAAY,IAAI,cAAc,KAAK,cAAc,EAChE,OAAM,IAAI,MAAM,sCAAsC;AAGxD,OAAK,aAAa;;;AAItB,MAAM,YAAY,IAAI,iBAAiB"}
|
|
1
|
+
{"version":3,"file":"telemetry-client.cjs","names":["lambdaClient","TELEMETRY_EMITTER_V2","TELEMETRY_SURFACE_V2","RUNTIME_PACKAGE_NAME","RUNTIME_PACKAGE_VERSION"],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"sourcesContent":["import type { AnalyticsEvents } from \"./events\";\nimport {\n lambdaClient,\n parseAndWarnTelemetryId,\n computeSamplingMeta,\n TELEMETRY_EMITTER_V2,\n TELEMETRY_SURFACE_V2,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_PACKAGE_NAME,\n RUNTIME_PACKAGE_VERSION,\n} from \"../core/package-info\";\nimport { firstNonBlankTelemetryId } from \"./telemetry-identity\";\n\n/** Transport identity and sampling authority resolved for one runtime. */\nexport interface TelemetryIdentity {\n telemetryId?: string;\n licenseToken?: string;\n}\n\n/** Capture-only telemetry client bound to one runtime identity. */\nexport interface TelemetryCapture {\n capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void>;\n}\n\ninterface ResolvedTelemetryIdentity {\n telemetryId: string | null;\n licenseToken: string | null;\n licenseTelemetryId: string | null;\n}\n\nexport function isTelemetryDisabled(): boolean {\n return (\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"true\" ||\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"1\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK ===\n \"true\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK === \"1\"\n );\n}\n\nexport class TelemetryClient {\n private telemetryDisabled: boolean = false;\n // Opt-down for anonymous events, defaulting to 1: the sink is ours, so a\n // real count beats one extrapolated from a fraction of the population.\n // It stays configurable because it is the cross-SDK lever for reducing or\n // stopping anonymous volume — the Go, Python, Ruby, and .NET runtimes all\n // expose it, and the cross-language conformance suite drives it to 0 to\n // assert silence. Identified callers bypass it.\n private sampleRate: number = 1;\n // EIP / Intelligence license token (Ed25519-signed JWT). Kept separate\n // from standalone identity so the transport receives only the selected\n // identity source.\n private licenseToken: string | null = null;\n // Standalone identity sent as a transport claim. It does not make an\n // event identified.\n private telemetryId: string | null = null;\n // License-derived identity. This client sends every event either way;\n // the id is what sets telemetry_identified on the sampling block, which\n // is how the two populations stay separable downstream.\n private licenseTelemetryId: string | null = null;\n // Properties merged into every event this client sends.\n //\n // For facts about the caller that are true for the whole process rather than\n // for one event: which product is embedding the runtime, for instance. A\n // distribution built on top of this can then be told apart in the existing\n // events instead of sending its own, which is the difference between one\n // extra field and a second pipeline nobody asked for.\n //\n // Sent as `global_properties`, a field of its own, so these stay separable\n // from an event's own properties all the way to the sink.\n //\n // Do not reuse a key an event already sets: the fanout spreads this bag last\n // for `oss.runtime.*`, so a collision resolves in favour of the global and\n // does so silently. Names here should describe the caller, not the call.\n private globalProperties: Record<string, unknown> = {};\n\n constructor({\n telemetryDisabled,\n sampleRate,\n }: {\n telemetryDisabled?: boolean;\n sampleRate?: number;\n } = {}) {\n this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled();\n this.setSampleRate(sampleRate);\n }\n\n private shouldSendEvent() {\n if (this.sampleRate >= 1) return true;\n return Math.random() < this.sampleRate;\n }\n\n /**\n * Add properties carried by every subsequent event.\n *\n * Merged rather than replaced, so two callers setting different fields do not\n * erase each other. Set once at runtime construction in practice; nothing\n * here is per-request.\n */\n setGlobalProperties(properties: Record<string, unknown>) {\n this.globalProperties = { ...this.globalProperties, ...properties };\n }\n\n /** Atomically replace the process-wide telemetry identity. */\n setTelemetryIdentity(identity: TelemetryIdentity): void {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n this.telemetryId = resolvedIdentity.telemetryId;\n this.licenseToken = resolvedIdentity.licenseToken;\n this.licenseTelemetryId = resolvedIdentity.licenseTelemetryId;\n }\n\n /** @deprecated Prefer {@link setTelemetryIdentity}. */\n setLicenseToken(licenseToken: string): void {\n this.setTelemetryIdentity({ licenseToken });\n }\n\n /** Create an immutable capture scope for one Runtime instance. */\n createScope(identity: TelemetryIdentity): TelemetryCapture {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n return {\n capture: <K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ) => this.captureWithIdentity(event, properties, resolvedIdentity),\n };\n }\n\n async capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void> {\n return this.captureWithIdentity(event, properties, {\n telemetryId: this.telemetryId,\n licenseToken: this.licenseToken,\n licenseTelemetryId: this.licenseTelemetryId,\n });\n }\n\n private async captureWithIdentity<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n identity: ResolvedTelemetryIdentity,\n ): Promise<void> {\n // Re-read the environment: an opt-out set after import (for example a\n // dotenv call below the imports) must still stop events.\n if (this.telemetryDisabled || isTelemetryDisabled()) return;\n // Nothing is gated at the default rate of 1. A caller who dialled it\n // down means it, and identified callers are exempt either way.\n if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;\n\n await lambdaClient.send({\n event,\n properties: properties as Record<string, unknown>,\n // Its own field on the wire rather than folded into `properties`, which\n // is what the sink expects: for `oss.runtime.*` the fanout treats\n // `global_properties` as the SDK's pass-through bag and spreads it into\n // the analytics event, and v1's client sends package name and version the\n // same way. Folding it in would work and would put a process-level fact\n // in the per-event slot, where nothing downstream expects to find one.\n // Sampling metadata rides in the same slot, as it does in v1. It\n // reads 1/1 unless a caller dialled the rate down, and is stamped\n // either way: a consumer summing sampleWeight across emitters must\n // not find the field missing on a quarter of the rows, which is the\n // state that made ~24% of runtime volume unweightable (OSS-1017).\n globalProperties: {\n ...this.globalProperties,\n ...computeSamplingMeta({\n telemetryId: identity.licenseTelemetryId,\n sampleRate: this.sampleRate,\n }),\n telemetry_emitter: TELEMETRY_EMITTER_V2,\n // Constant here: a v1 request never reaches this client. The v1\n // entrypoint hands its own capture scope to the V2 runtime it\n // builds, so v1 traffic is emitted by the v1 client and stamped\n // v1 there — which is also what keeps it on the Segment wire.\n telemetry_surface: TELEMETRY_SURFACE_V2,\n // This client has one transport, so the marker is constant here. It\n // is stamped anyway so the property means the same thing on every\n // event whichever client produced it (OSS-1019).\n telemetry_transport: \"lambda\",\n },\n packageName: RUNTIME_PACKAGE_NAME,\n packageVersion: RUNTIME_PACKAGE_VERSION,\n telemetryId: identity.telemetryId ?? undefined,\n licenseToken: identity.licenseToken ?? undefined,\n });\n }\n\n private resolveTelemetryIdentity(\n identity: TelemetryIdentity,\n ): ResolvedTelemetryIdentity {\n const telemetryId = firstNonBlankTelemetryId(identity.telemetryId);\n if (telemetryId !== undefined) {\n return {\n telemetryId,\n licenseToken: null,\n licenseTelemetryId: null,\n };\n }\n\n return {\n telemetryId: null,\n licenseToken: identity.licenseToken ?? null,\n licenseTelemetryId: identity.licenseToken\n ? parseAndWarnTelemetryId(identity.licenseToken)\n : null,\n };\n }\n\n private setSampleRate(sampleRate: number | undefined) {\n let _sampleRate: number;\n\n _sampleRate = sampleRate ?? 1;\n\n if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) {\n _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);\n }\n\n // Number.isNaN guards against parseFloat(\"nonsense\") slipping past the\n // range check (all NaN comparisons are false), which would silently\n // drop every anonymous event with no signal.\n if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) {\n throw new Error(\"Sample rate must be between 0 and 1\");\n }\n\n this.sampleRate = _sampleRate;\n }\n}\n\nconst telemetry = new TelemetryClient();\nexport default telemetry;\n"],"mappings":";;;;;;AAkCA,SAAgB,sBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAoC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BAzC6B;oBAOR;sBAIS;qBAGD;4BAIO;0BAeQ,EAAE;AASpD,OAAK,oBAAoB,qBAAqB,qBAAqB;AACnE,OAAK,cAAc,WAAW;;CAGhC,AAAQ,kBAAkB;AACxB,MAAI,KAAK,cAAc,EAAG,QAAO;AACjC,SAAO,KAAK,QAAQ,GAAG,KAAK;;;;;;;;;CAU9B,oBAAoB,YAAqC;AACvD,OAAK,mBAAmB;GAAE,GAAG,KAAK;GAAkB,GAAG;GAAY;;;CAIrE,qBAAqB,UAAmC;EACtD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,OAAK,cAAc,iBAAiB;AACpC,OAAK,eAAe,iBAAiB;AACrC,OAAK,qBAAqB,iBAAiB;;;CAI7C,gBAAgB,cAA4B;AAC1C,OAAK,qBAAqB,EAAE,cAAc,CAAC;;;CAI7C,YAAY,UAA+C;EACzD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,SAAO,EACL,UACE,OACA,eACG,KAAK,oBAAoB,OAAO,YAAY,iBAAiB,EACnE;;CAGH,MAAM,QACJ,OACA,YACe;AACf,SAAO,KAAK,oBAAoB,OAAO,YAAY;GACjD,aAAa,KAAK;GAClB,cAAc,KAAK;GACnB,oBAAoB,KAAK;GAC1B,CAAC;;CAGJ,MAAc,oBACZ,OACA,YACA,UACe;AAGf,MAAI,KAAK,qBAAqB,qBAAqB,CAAE;AAGrD,MAAI,CAAC,SAAS,sBAAsB,CAAC,KAAK,iBAAiB,CAAE;AAE7D,QAAMA,gCAAa,KAAK;GACtB;GACY;GAYZ,kBAAkB;IAChB,GAAG,KAAK;IACR,+CAAuB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmBC;IAKnB,mBAAmBC;IAInB,qBAAqB;IACtB;GACD,aAAaC;GACb,gBAAgBC;GAChB,aAAa,SAAS,eAAe;GACrC,cAAc,SAAS,gBAAgB;GACxC,CAAC;;CAGJ,AAAQ,yBACN,UAC2B;EAC3B,MAAM,+DAAuC,SAAS,YAAY;AAClE,MAAI,gBAAgB,OAClB,QAAO;GACL;GACA,cAAc;GACd,oBAAoB;GACrB;AAGH,SAAO;GACL,aAAa;GACb,cAAc,SAAS,gBAAgB;GACvC,oBAAoB,SAAS,+DACD,SAAS,aAAa,GAC9C;GACL;;CAGH,AAAQ,cAAc,YAAgC;EACpD,IAAI;AAEJ,gBAAc,cAAc;AAE5B,MAAI,QAAQ,IAAI,iCACd,eAAc,WAAW,QAAQ,IAAI,iCAAiC;AAMxE,MAAI,OAAO,MAAM,YAAY,IAAI,cAAc,KAAK,cAAc,EAChE,OAAM,IAAI,MAAM,sCAAsC;AAGxD,OAAK,aAAa;;;AAItB,MAAM,YAAY,IAAI,iBAAiB"}
|
|
@@ -59,7 +59,7 @@ var TelemetryClient = class {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
async captureWithIdentity(event, properties, identity) {
|
|
62
|
-
if (this.telemetryDisabled) return;
|
|
62
|
+
if (this.telemetryDisabled || isTelemetryDisabled()) return;
|
|
63
63
|
if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;
|
|
64
64
|
await lambdaClient.send({
|
|
65
65
|
event,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.mjs","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"sourcesContent":["import type { AnalyticsEvents } from \"./events\";\nimport {\n lambdaClient,\n parseAndWarnTelemetryId,\n computeSamplingMeta,\n TELEMETRY_EMITTER_V2,\n TELEMETRY_SURFACE_V2,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_PACKAGE_NAME,\n RUNTIME_PACKAGE_VERSION,\n} from \"../core/package-info\";\nimport { firstNonBlankTelemetryId } from \"./telemetry-identity\";\n\n/** Transport identity and sampling authority resolved for one runtime. */\nexport interface TelemetryIdentity {\n telemetryId?: string;\n licenseToken?: string;\n}\n\n/** Capture-only telemetry client bound to one runtime identity. */\nexport interface TelemetryCapture {\n capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void>;\n}\n\ninterface ResolvedTelemetryIdentity {\n telemetryId: string | null;\n licenseToken: string | null;\n licenseTelemetryId: string | null;\n}\n\nexport function isTelemetryDisabled(): boolean {\n return (\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"true\" ||\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"1\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK ===\n \"true\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK === \"1\"\n );\n}\n\nexport class TelemetryClient {\n private telemetryDisabled: boolean = false;\n // Opt-down for anonymous events, defaulting to 1: the sink is ours, so a\n // real count beats one extrapolated from a fraction of the population.\n // It stays configurable because it is the cross-SDK lever for reducing or\n // stopping anonymous volume — the Go, Python, Ruby, and .NET runtimes all\n // expose it, and the cross-language conformance suite drives it to 0 to\n // assert silence. Identified callers bypass it.\n private sampleRate: number = 1;\n // EIP / Intelligence license token (Ed25519-signed JWT). Kept separate\n // from standalone identity so the transport receives only the selected\n // identity source.\n private licenseToken: string | null = null;\n // Standalone identity sent as a transport claim. It does not make an\n // event identified.\n private telemetryId: string | null = null;\n // License-derived identity. This client sends every event either way;\n // the id is what sets telemetry_identified on the sampling block, which\n // is how the two populations stay separable downstream.\n private licenseTelemetryId: string | null = null;\n // Properties merged into every event this client sends.\n //\n // For facts about the caller that are true for the whole process rather than\n // for one event: which product is embedding the runtime, for instance. A\n // distribution built on top of this can then be told apart in the existing\n // events instead of sending its own, which is the difference between one\n // extra field and a second pipeline nobody asked for.\n //\n // Sent as `global_properties`, a field of its own, so these stay separable\n // from an event's own properties all the way to the sink.\n //\n // Do not reuse a key an event already sets: the fanout spreads this bag last\n // for `oss.runtime.*`, so a collision resolves in favour of the global and\n // does so silently. Names here should describe the caller, not the call.\n private globalProperties: Record<string, unknown> = {};\n\n constructor({\n telemetryDisabled,\n sampleRate,\n }: {\n telemetryDisabled?: boolean;\n sampleRate?: number;\n } = {}) {\n this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled();\n this.setSampleRate(sampleRate);\n }\n\n private shouldSendEvent() {\n if (this.sampleRate >= 1) return true;\n return Math.random() < this.sampleRate;\n }\n\n /**\n * Add properties carried by every subsequent event.\n *\n * Merged rather than replaced, so two callers setting different fields do not\n * erase each other. Set once at runtime construction in practice; nothing\n * here is per-request.\n */\n setGlobalProperties(properties: Record<string, unknown>) {\n this.globalProperties = { ...this.globalProperties, ...properties };\n }\n\n /** Atomically replace the process-wide telemetry identity. */\n setTelemetryIdentity(identity: TelemetryIdentity): void {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n this.telemetryId = resolvedIdentity.telemetryId;\n this.licenseToken = resolvedIdentity.licenseToken;\n this.licenseTelemetryId = resolvedIdentity.licenseTelemetryId;\n }\n\n /** @deprecated Prefer {@link setTelemetryIdentity}. */\n setLicenseToken(licenseToken: string): void {\n this.setTelemetryIdentity({ licenseToken });\n }\n\n /** Create an immutable capture scope for one Runtime instance. */\n createScope(identity: TelemetryIdentity): TelemetryCapture {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n return {\n capture: <K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ) => this.captureWithIdentity(event, properties, resolvedIdentity),\n };\n }\n\n async capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void> {\n return this.captureWithIdentity(event, properties, {\n telemetryId: this.telemetryId,\n licenseToken: this.licenseToken,\n licenseTelemetryId: this.licenseTelemetryId,\n });\n }\n\n private async captureWithIdentity<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n identity: ResolvedTelemetryIdentity,\n ): Promise<void> {\n if (this.telemetryDisabled) return;\n // Nothing is gated at the default rate of 1. A caller who dialled it\n // down means it, and identified callers are exempt either way.\n if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;\n\n await lambdaClient.send({\n event,\n properties: properties as Record<string, unknown>,\n // Its own field on the wire rather than folded into `properties`, which\n // is what the sink expects: for `oss.runtime.*` the fanout treats\n // `global_properties` as the SDK's pass-through bag and spreads it into\n // the analytics event, and v1's client sends package name and version the\n // same way. Folding it in would work and would put a process-level fact\n // in the per-event slot, where nothing downstream expects to find one.\n // Sampling metadata rides in the same slot, as it does in v1. It\n // reads 1/1 unless a caller dialled the rate down, and is stamped\n // either way: a consumer summing sampleWeight across emitters must\n // not find the field missing on a quarter of the rows, which is the\n // state that made ~24% of runtime volume unweightable (OSS-1017).\n globalProperties: {\n ...this.globalProperties,\n ...computeSamplingMeta({\n telemetryId: identity.licenseTelemetryId,\n sampleRate: this.sampleRate,\n }),\n telemetry_emitter: TELEMETRY_EMITTER_V2,\n // Constant here: a v1 request never reaches this client. The v1\n // entrypoint hands its own capture scope to the V2 runtime it\n // builds, so v1 traffic is emitted by the v1 client and stamped\n // v1 there — which is also what keeps it on the Segment wire.\n telemetry_surface: TELEMETRY_SURFACE_V2,\n // This client has one transport, so the marker is constant here. It\n // is stamped anyway so the property means the same thing on every\n // event whichever client produced it (OSS-1019).\n telemetry_transport: \"lambda\",\n },\n packageName: RUNTIME_PACKAGE_NAME,\n packageVersion: RUNTIME_PACKAGE_VERSION,\n telemetryId: identity.telemetryId ?? undefined,\n licenseToken: identity.licenseToken ?? undefined,\n });\n }\n\n private resolveTelemetryIdentity(\n identity: TelemetryIdentity,\n ): ResolvedTelemetryIdentity {\n const telemetryId = firstNonBlankTelemetryId(identity.telemetryId);\n if (telemetryId !== undefined) {\n return {\n telemetryId,\n licenseToken: null,\n licenseTelemetryId: null,\n };\n }\n\n return {\n telemetryId: null,\n licenseToken: identity.licenseToken ?? null,\n licenseTelemetryId: identity.licenseToken\n ? parseAndWarnTelemetryId(identity.licenseToken)\n : null,\n };\n }\n\n private setSampleRate(sampleRate: number | undefined) {\n let _sampleRate: number;\n\n _sampleRate = sampleRate ?? 1;\n\n if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) {\n _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);\n }\n\n // Number.isNaN guards against parseFloat(\"nonsense\") slipping past the\n // range check (all NaN comparisons are false), which would silently\n // drop every anonymous event with no signal.\n if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) {\n throw new Error(\"Sample rate must be between 0 and 1\");\n }\n\n this.sampleRate = _sampleRate;\n }\n}\n\nconst telemetry = new TelemetryClient();\nexport default telemetry;\n"],"mappings":";;;;;;AAkCA,SAAgB,sBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAoC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BAzC6B;oBAOR;sBAIS;qBAGD;4BAIO;0BAeQ,EAAE;AASpD,OAAK,oBAAoB,qBAAqB,qBAAqB;AACnE,OAAK,cAAc,WAAW;;CAGhC,AAAQ,kBAAkB;AACxB,MAAI,KAAK,cAAc,EAAG,QAAO;AACjC,SAAO,KAAK,QAAQ,GAAG,KAAK;;;;;;;;;CAU9B,oBAAoB,YAAqC;AACvD,OAAK,mBAAmB;GAAE,GAAG,KAAK;GAAkB,GAAG;GAAY;;;CAIrE,qBAAqB,UAAmC;EACtD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,OAAK,cAAc,iBAAiB;AACpC,OAAK,eAAe,iBAAiB;AACrC,OAAK,qBAAqB,iBAAiB;;;CAI7C,gBAAgB,cAA4B;AAC1C,OAAK,qBAAqB,EAAE,cAAc,CAAC;;;CAI7C,YAAY,UAA+C;EACzD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,SAAO,EACL,UACE,OACA,eACG,KAAK,oBAAoB,OAAO,YAAY,iBAAiB,EACnE;;CAGH,MAAM,QACJ,OACA,YACe;AACf,SAAO,KAAK,oBAAoB,OAAO,YAAY;GACjD,aAAa,KAAK;GAClB,cAAc,KAAK;GACnB,oBAAoB,KAAK;GAC1B,CAAC;;CAGJ,MAAc,oBACZ,OACA,YACA,UACe;AACf,MAAI,KAAK,kBAAmB;AAG5B,MAAI,CAAC,SAAS,sBAAsB,CAAC,KAAK,iBAAiB,CAAE;AAE7D,QAAM,aAAa,KAAK;GACtB;GACY;GAYZ,kBAAkB;IAChB,GAAG,KAAK;IACR,GAAG,oBAAoB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmB;IAKnB,mBAAmB;IAInB,qBAAqB;IACtB;GACD,aAAa;GACb,gBAAgB;GAChB,aAAa,SAAS,eAAe;GACrC,cAAc,SAAS,gBAAgB;GACxC,CAAC;;CAGJ,AAAQ,yBACN,UAC2B;EAC3B,MAAM,cAAc,yBAAyB,SAAS,YAAY;AAClE,MAAI,gBAAgB,OAClB,QAAO;GACL;GACA,cAAc;GACd,oBAAoB;GACrB;AAGH,SAAO;GACL,aAAa;GACb,cAAc,SAAS,gBAAgB;GACvC,oBAAoB,SAAS,eACzB,wBAAwB,SAAS,aAAa,GAC9C;GACL;;CAGH,AAAQ,cAAc,YAAgC;EACpD,IAAI;AAEJ,gBAAc,cAAc;AAE5B,MAAI,QAAQ,IAAI,iCACd,eAAc,WAAW,QAAQ,IAAI,iCAAiC;AAMxE,MAAI,OAAO,MAAM,YAAY,IAAI,cAAc,KAAK,cAAc,EAChE,OAAM,IAAI,MAAM,sCAAsC;AAGxD,OAAK,aAAa;;;AAItB,MAAM,YAAY,IAAI,iBAAiB"}
|
|
1
|
+
{"version":3,"file":"telemetry-client.mjs","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"sourcesContent":["import type { AnalyticsEvents } from \"./events\";\nimport {\n lambdaClient,\n parseAndWarnTelemetryId,\n computeSamplingMeta,\n TELEMETRY_EMITTER_V2,\n TELEMETRY_SURFACE_V2,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_PACKAGE_NAME,\n RUNTIME_PACKAGE_VERSION,\n} from \"../core/package-info\";\nimport { firstNonBlankTelemetryId } from \"./telemetry-identity\";\n\n/** Transport identity and sampling authority resolved for one runtime. */\nexport interface TelemetryIdentity {\n telemetryId?: string;\n licenseToken?: string;\n}\n\n/** Capture-only telemetry client bound to one runtime identity. */\nexport interface TelemetryCapture {\n capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void>;\n}\n\ninterface ResolvedTelemetryIdentity {\n telemetryId: string | null;\n licenseToken: string | null;\n licenseTelemetryId: string | null;\n}\n\nexport function isTelemetryDisabled(): boolean {\n return (\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"true\" ||\n (process.env as Record<string, string | undefined>)\n .COPILOTKIT_TELEMETRY_DISABLED === \"1\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK ===\n \"true\" ||\n (process.env as Record<string, string | undefined>).DO_NOT_TRACK === \"1\"\n );\n}\n\nexport class TelemetryClient {\n private telemetryDisabled: boolean = false;\n // Opt-down for anonymous events, defaulting to 1: the sink is ours, so a\n // real count beats one extrapolated from a fraction of the population.\n // It stays configurable because it is the cross-SDK lever for reducing or\n // stopping anonymous volume — the Go, Python, Ruby, and .NET runtimes all\n // expose it, and the cross-language conformance suite drives it to 0 to\n // assert silence. Identified callers bypass it.\n private sampleRate: number = 1;\n // EIP / Intelligence license token (Ed25519-signed JWT). Kept separate\n // from standalone identity so the transport receives only the selected\n // identity source.\n private licenseToken: string | null = null;\n // Standalone identity sent as a transport claim. It does not make an\n // event identified.\n private telemetryId: string | null = null;\n // License-derived identity. This client sends every event either way;\n // the id is what sets telemetry_identified on the sampling block, which\n // is how the two populations stay separable downstream.\n private licenseTelemetryId: string | null = null;\n // Properties merged into every event this client sends.\n //\n // For facts about the caller that are true for the whole process rather than\n // for one event: which product is embedding the runtime, for instance. A\n // distribution built on top of this can then be told apart in the existing\n // events instead of sending its own, which is the difference between one\n // extra field and a second pipeline nobody asked for.\n //\n // Sent as `global_properties`, a field of its own, so these stay separable\n // from an event's own properties all the way to the sink.\n //\n // Do not reuse a key an event already sets: the fanout spreads this bag last\n // for `oss.runtime.*`, so a collision resolves in favour of the global and\n // does so silently. Names here should describe the caller, not the call.\n private globalProperties: Record<string, unknown> = {};\n\n constructor({\n telemetryDisabled,\n sampleRate,\n }: {\n telemetryDisabled?: boolean;\n sampleRate?: number;\n } = {}) {\n this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled();\n this.setSampleRate(sampleRate);\n }\n\n private shouldSendEvent() {\n if (this.sampleRate >= 1) return true;\n return Math.random() < this.sampleRate;\n }\n\n /**\n * Add properties carried by every subsequent event.\n *\n * Merged rather than replaced, so two callers setting different fields do not\n * erase each other. Set once at runtime construction in practice; nothing\n * here is per-request.\n */\n setGlobalProperties(properties: Record<string, unknown>) {\n this.globalProperties = { ...this.globalProperties, ...properties };\n }\n\n /** Atomically replace the process-wide telemetry identity. */\n setTelemetryIdentity(identity: TelemetryIdentity): void {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n this.telemetryId = resolvedIdentity.telemetryId;\n this.licenseToken = resolvedIdentity.licenseToken;\n this.licenseTelemetryId = resolvedIdentity.licenseTelemetryId;\n }\n\n /** @deprecated Prefer {@link setTelemetryIdentity}. */\n setLicenseToken(licenseToken: string): void {\n this.setTelemetryIdentity({ licenseToken });\n }\n\n /** Create an immutable capture scope for one Runtime instance. */\n createScope(identity: TelemetryIdentity): TelemetryCapture {\n const resolvedIdentity = this.resolveTelemetryIdentity(identity);\n return {\n capture: <K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ) => this.captureWithIdentity(event, properties, resolvedIdentity),\n };\n }\n\n async capture<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n ): Promise<void> {\n return this.captureWithIdentity(event, properties, {\n telemetryId: this.telemetryId,\n licenseToken: this.licenseToken,\n licenseTelemetryId: this.licenseTelemetryId,\n });\n }\n\n private async captureWithIdentity<K extends keyof AnalyticsEvents>(\n event: K,\n properties: AnalyticsEvents[K],\n identity: ResolvedTelemetryIdentity,\n ): Promise<void> {\n // Re-read the environment: an opt-out set after import (for example a\n // dotenv call below the imports) must still stop events.\n if (this.telemetryDisabled || isTelemetryDisabled()) return;\n // Nothing is gated at the default rate of 1. A caller who dialled it\n // down means it, and identified callers are exempt either way.\n if (!identity.licenseTelemetryId && !this.shouldSendEvent()) return;\n\n await lambdaClient.send({\n event,\n properties: properties as Record<string, unknown>,\n // Its own field on the wire rather than folded into `properties`, which\n // is what the sink expects: for `oss.runtime.*` the fanout treats\n // `global_properties` as the SDK's pass-through bag and spreads it into\n // the analytics event, and v1's client sends package name and version the\n // same way. Folding it in would work and would put a process-level fact\n // in the per-event slot, where nothing downstream expects to find one.\n // Sampling metadata rides in the same slot, as it does in v1. It\n // reads 1/1 unless a caller dialled the rate down, and is stamped\n // either way: a consumer summing sampleWeight across emitters must\n // not find the field missing on a quarter of the rows, which is the\n // state that made ~24% of runtime volume unweightable (OSS-1017).\n globalProperties: {\n ...this.globalProperties,\n ...computeSamplingMeta({\n telemetryId: identity.licenseTelemetryId,\n sampleRate: this.sampleRate,\n }),\n telemetry_emitter: TELEMETRY_EMITTER_V2,\n // Constant here: a v1 request never reaches this client. The v1\n // entrypoint hands its own capture scope to the V2 runtime it\n // builds, so v1 traffic is emitted by the v1 client and stamped\n // v1 there — which is also what keeps it on the Segment wire.\n telemetry_surface: TELEMETRY_SURFACE_V2,\n // This client has one transport, so the marker is constant here. It\n // is stamped anyway so the property means the same thing on every\n // event whichever client produced it (OSS-1019).\n telemetry_transport: \"lambda\",\n },\n packageName: RUNTIME_PACKAGE_NAME,\n packageVersion: RUNTIME_PACKAGE_VERSION,\n telemetryId: identity.telemetryId ?? undefined,\n licenseToken: identity.licenseToken ?? undefined,\n });\n }\n\n private resolveTelemetryIdentity(\n identity: TelemetryIdentity,\n ): ResolvedTelemetryIdentity {\n const telemetryId = firstNonBlankTelemetryId(identity.telemetryId);\n if (telemetryId !== undefined) {\n return {\n telemetryId,\n licenseToken: null,\n licenseTelemetryId: null,\n };\n }\n\n return {\n telemetryId: null,\n licenseToken: identity.licenseToken ?? null,\n licenseTelemetryId: identity.licenseToken\n ? parseAndWarnTelemetryId(identity.licenseToken)\n : null,\n };\n }\n\n private setSampleRate(sampleRate: number | undefined) {\n let _sampleRate: number;\n\n _sampleRate = sampleRate ?? 1;\n\n if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) {\n _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);\n }\n\n // Number.isNaN guards against parseFloat(\"nonsense\") slipping past the\n // range check (all NaN comparisons are false), which would silently\n // drop every anonymous event with no signal.\n if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) {\n throw new Error(\"Sample rate must be between 0 and 1\");\n }\n\n this.sampleRate = _sampleRate;\n }\n}\n\nconst telemetry = new TelemetryClient();\nexport default telemetry;\n"],"mappings":";;;;;;AAkCA,SAAgB,sBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAoC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BAzC6B;oBAOR;sBAIS;qBAGD;4BAIO;0BAeQ,EAAE;AASpD,OAAK,oBAAoB,qBAAqB,qBAAqB;AACnE,OAAK,cAAc,WAAW;;CAGhC,AAAQ,kBAAkB;AACxB,MAAI,KAAK,cAAc,EAAG,QAAO;AACjC,SAAO,KAAK,QAAQ,GAAG,KAAK;;;;;;;;;CAU9B,oBAAoB,YAAqC;AACvD,OAAK,mBAAmB;GAAE,GAAG,KAAK;GAAkB,GAAG;GAAY;;;CAIrE,qBAAqB,UAAmC;EACtD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,OAAK,cAAc,iBAAiB;AACpC,OAAK,eAAe,iBAAiB;AACrC,OAAK,qBAAqB,iBAAiB;;;CAI7C,gBAAgB,cAA4B;AAC1C,OAAK,qBAAqB,EAAE,cAAc,CAAC;;;CAI7C,YAAY,UAA+C;EACzD,MAAM,mBAAmB,KAAK,yBAAyB,SAAS;AAChE,SAAO,EACL,UACE,OACA,eACG,KAAK,oBAAoB,OAAO,YAAY,iBAAiB,EACnE;;CAGH,MAAM,QACJ,OACA,YACe;AACf,SAAO,KAAK,oBAAoB,OAAO,YAAY;GACjD,aAAa,KAAK;GAClB,cAAc,KAAK;GACnB,oBAAoB,KAAK;GAC1B,CAAC;;CAGJ,MAAc,oBACZ,OACA,YACA,UACe;AAGf,MAAI,KAAK,qBAAqB,qBAAqB,CAAE;AAGrD,MAAI,CAAC,SAAS,sBAAsB,CAAC,KAAK,iBAAiB,CAAE;AAE7D,QAAM,aAAa,KAAK;GACtB;GACY;GAYZ,kBAAkB;IAChB,GAAG,KAAK;IACR,GAAG,oBAAoB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmB;IAKnB,mBAAmB;IAInB,qBAAqB;IACtB;GACD,aAAa;GACb,gBAAgB;GAChB,aAAa,SAAS,eAAe;GACrC,cAAc,SAAS,gBAAgB;GACxC,CAAC;;CAGJ,AAAQ,yBACN,UAC2B;EAC3B,MAAM,cAAc,yBAAyB,SAAS,YAAY;AAClE,MAAI,gBAAgB,OAClB,QAAO;GACL;GACA,cAAc;GACd,oBAAoB;GACrB;AAGH,SAAO;GACL,aAAa;GACb,cAAc,SAAS,gBAAgB;GACvC,oBAAoB,SAAS,eACzB,wBAAwB,SAAS,aAAa,GAC9C;GACL;;CAGH,AAAQ,cAAc,YAAgC;EACpD,IAAI;AAEJ,gBAAc,cAAc;AAE5B,MAAI,QAAQ,IAAI,iCACd,eAAc,WAAW,QAAQ,IAAI,iCAAiC;AAMxE,MAAI,OAAO,MAAM,YAAY,IAAI,cAAc,KAAK,cAAc,EAChE,OAAM,IAAI,MAAM,sCAAsC;AAGxD,OAAK,aAAa;;;AAItB,MAAM,YAAY,IAAI,iBAAiB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.82.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -109,9 +109,9 @@
|
|
|
109
109
|
"ws": "^8.18.0",
|
|
110
110
|
"zod": "^3.25.18",
|
|
111
111
|
"yauzl": "2.10.0",
|
|
112
|
-
"@copilotkit/channels-core": "^0.11.1",
|
|
113
112
|
"@copilotkit/channels-intelligence": "^0.11.1",
|
|
114
|
-
"@copilotkit/shared": "1.
|
|
113
|
+
"@copilotkit/shared": "1.82.0",
|
|
114
|
+
"@copilotkit/channels-core": "^0.11.1"
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
117
|
"@copilotkit/aimock": "latest",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
"valibot": "^1.2.0",
|
|
137
137
|
"vitest": "^3.2.4",
|
|
138
138
|
"@types/yauzl": "2.10.3",
|
|
139
|
-
"
|
|
140
|
-
"
|
|
139
|
+
"@copilotkit/channels": "0.11.1",
|
|
140
|
+
"tsconfig": "1.4.12"
|
|
141
141
|
},
|
|
142
142
|
"peerDependencies": {
|
|
143
143
|
"@anthropic-ai/sdk": ">=0.57.0",
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"generate-graphql-schema": "node -e \"const fs=require('fs');fs.rmSync('__snapshots__',{recursive:true,force:true})\" && ts-node --transpile-only ./scripts/generate-gql-schema.ts",
|
|
204
204
|
"link:global": "pnpm link --global",
|
|
205
205
|
"unlink:global": "pnpm unlink --global",
|
|
206
|
-
"check-dts": "tsx ../../scripts/validate-dts-ambient.ts dist && tsx ../../scripts/validate-dts-imports.ts dist && tsx ../../scripts/validate-optional-peer-entries.ts . && tsx ../../scripts/validate-module-scope-create-require.ts . && tsc --noEmit -p type-fixtures/express4/tsconfig.json && tsc --noEmit -p type-fixtures/express5/tsconfig.json",
|
|
206
|
+
"check-dts": "tsx ../../scripts/validate-dts-ambient.ts dist && tsx ../../scripts/validate-dts-imports.ts dist && tsx ../../scripts/validate-optional-peer-entries.ts . && tsx ../../scripts/validate-module-scope-create-require.ts . && tsc --noEmit -p type-fixtures/express4/tsconfig.json && tsc --noEmit -p type-fixtures/express5/tsconfig.json && tsc --noEmit -p type-fixtures/learning-management/tsconfig.json",
|
|
207
207
|
"publint": "publint .",
|
|
208
208
|
"attw": "attw --pack . --profile node16"
|
|
209
209
|
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
require("reflect-metadata");
|
|
2
|
-
const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
-
const require_node_fetch_handler = require('./node-fetch-handler.cjs');
|
|
4
|
-
let _copilotkit_shared = require("@copilotkit/shared");
|
|
5
|
-
let _remix_run_node_fetch_server = require("@remix-run/node-fetch-server");
|
|
6
|
-
|
|
7
|
-
//#region src/v2/runtime/endpoints/express-fetch-bridge.ts
|
|
8
|
-
const METHODS_WITHOUT_BODY = new Set([
|
|
9
|
-
"GET",
|
|
10
|
-
"HEAD",
|
|
11
|
-
"OPTIONS"
|
|
12
|
-
]);
|
|
13
|
-
/**
|
|
14
|
-
* Creates a Node HTTP handler from a fetch handler, with Express body-parser
|
|
15
|
-
* compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.
|
|
16
|
-
*
|
|
17
|
-
* When the body stream hasn't been consumed, delegates to the generic
|
|
18
|
-
* `createCopilotNodeHandler`. Only intercepts when Express middleware has
|
|
19
|
-
* pre-parsed the body.
|
|
20
|
-
*/
|
|
21
|
-
function createExpressNodeHandler(handler) {
|
|
22
|
-
const nodeHandler = require_node_fetch_handler.createCopilotNodeHandler(handler);
|
|
23
|
-
return async (req, res) => {
|
|
24
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
25
|
-
if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) return nodeHandler(req, res);
|
|
26
|
-
try {
|
|
27
|
-
await (0, _remix_run_node_fetch_server.sendResponse)(res, await handler(buildPreParsedRequest(req, res)));
|
|
28
|
-
} catch (err) {
|
|
29
|
-
_copilotkit_shared.logger.error({ err }, "Error in Express fetch bridge (pre-parsed path)");
|
|
30
|
-
if (!res.headersSent) {
|
|
31
|
-
res.statusCode = 500;
|
|
32
|
-
res.end("Internal Server Error");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Build a Fetch Request from a Node IncomingMessage whose body stream has
|
|
39
|
-
* already been consumed by an Express body parser.
|
|
40
|
-
*/
|
|
41
|
-
function buildPreParsedRequest(req, res) {
|
|
42
|
-
const expressReq = req;
|
|
43
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
44
|
-
const url = `${req.protocol || "http"}://${req.headers.host ?? "localhost"}${req.originalUrl ?? req.url ?? ""}`;
|
|
45
|
-
const headers = new Headers();
|
|
46
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
47
|
-
if (value === void 0) continue;
|
|
48
|
-
if (Array.isArray(value)) for (const v of value) headers.append(key, v);
|
|
49
|
-
else headers.set(key, value);
|
|
50
|
-
}
|
|
51
|
-
const controller = new AbortController();
|
|
52
|
-
res.on("close", () => {
|
|
53
|
-
if (!res.writableFinished) controller.abort();
|
|
54
|
-
});
|
|
55
|
-
const init = {
|
|
56
|
-
method,
|
|
57
|
-
headers,
|
|
58
|
-
signal: controller.signal
|
|
59
|
-
};
|
|
60
|
-
const { body, contentType } = synthesizeBody(expressReq.body);
|
|
61
|
-
if (contentType) headers.set("content-type", contentType);
|
|
62
|
-
headers.delete("content-length");
|
|
63
|
-
if (body !== void 0) init.body = body;
|
|
64
|
-
return new Request(url, init);
|
|
65
|
-
}
|
|
66
|
-
function hasPreParsedBody(req) {
|
|
67
|
-
if (req.body === void 0 || req.body === null) return false;
|
|
68
|
-
return Boolean(req.readableEnded);
|
|
69
|
-
}
|
|
70
|
-
function synthesizeBody(body) {
|
|
71
|
-
if (Buffer.isBuffer(body) || body instanceof Uint8Array) return { body };
|
|
72
|
-
if (typeof body === "string") return { body };
|
|
73
|
-
if (typeof body === "object" && body !== null) return {
|
|
74
|
-
body: JSON.stringify(body),
|
|
75
|
-
contentType: "application/json"
|
|
76
|
-
};
|
|
77
|
-
return {};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
//#endregion
|
|
81
|
-
exports.createExpressNodeHandler = createExpressNodeHandler;
|
|
82
|
-
//# sourceMappingURL=express-fetch-bridge.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"express-fetch-bridge.cjs","names":["createCopilotNodeHandler"],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Only `readableEnded` means \"a parser drained this stream to its end\".\n // `req.complete` and the private `_readableState.ended` are set by the HTTP\n // parser once the socket has all the bytes, whether or not anything read them.\n //\n // That distinction matters because `req.body` being set does not prove a parser\n // ran: body-parser 1.x (Express 4) assigns `req.body = req.body || {}` before\n // its own content-type checks, so a request it declines to parse — multipart\n // upload, text/plain — reaches us with `req.body === {}` and a full, unread\n // stream. Treating that as pre-parsed rebuilt the request from `{}` and\n // dropped the real payload.\n return Boolean(req.readableEnded);\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n // Buffer/Uint8Array<ArrayBufferLike> are valid fetch bodies at runtime,\n // but the DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return { body: body as BodyInit };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAcA,oDAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,wDAAmB,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,6BAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;AAYxD,QAAO,QAAQ,IAAI,cAAc;;AAGnC,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,WAG3C,QAAO,EAAQ,MAAkB;AAEnC,KAAI,OAAO,SAAS,SAClB,QAAO,EAAE,MAAM;AAEjB,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;EAAE,MAAM,KAAK,UAAU,KAAK;EAAE,aAAa;EAAoB;AAExE,QAAO,EAAE"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import "reflect-metadata";
|
|
2
|
-
import { createCopilotNodeHandler } from "./node-fetch-handler.mjs";
|
|
3
|
-
import { logger } from "@copilotkit/shared";
|
|
4
|
-
import { sendResponse } from "@remix-run/node-fetch-server";
|
|
5
|
-
|
|
6
|
-
//#region src/v2/runtime/endpoints/express-fetch-bridge.ts
|
|
7
|
-
const METHODS_WITHOUT_BODY = new Set([
|
|
8
|
-
"GET",
|
|
9
|
-
"HEAD",
|
|
10
|
-
"OPTIONS"
|
|
11
|
-
]);
|
|
12
|
-
/**
|
|
13
|
-
* Creates a Node HTTP handler from a fetch handler, with Express body-parser
|
|
14
|
-
* compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.
|
|
15
|
-
*
|
|
16
|
-
* When the body stream hasn't been consumed, delegates to the generic
|
|
17
|
-
* `createCopilotNodeHandler`. Only intercepts when Express middleware has
|
|
18
|
-
* pre-parsed the body.
|
|
19
|
-
*/
|
|
20
|
-
function createExpressNodeHandler(handler) {
|
|
21
|
-
const nodeHandler = createCopilotNodeHandler(handler);
|
|
22
|
-
return async (req, res) => {
|
|
23
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
24
|
-
if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) return nodeHandler(req, res);
|
|
25
|
-
try {
|
|
26
|
-
await sendResponse(res, await handler(buildPreParsedRequest(req, res)));
|
|
27
|
-
} catch (err) {
|
|
28
|
-
logger.error({ err }, "Error in Express fetch bridge (pre-parsed path)");
|
|
29
|
-
if (!res.headersSent) {
|
|
30
|
-
res.statusCode = 500;
|
|
31
|
-
res.end("Internal Server Error");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Build a Fetch Request from a Node IncomingMessage whose body stream has
|
|
38
|
-
* already been consumed by an Express body parser.
|
|
39
|
-
*/
|
|
40
|
-
function buildPreParsedRequest(req, res) {
|
|
41
|
-
const expressReq = req;
|
|
42
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
43
|
-
const url = `${req.protocol || "http"}://${req.headers.host ?? "localhost"}${req.originalUrl ?? req.url ?? ""}`;
|
|
44
|
-
const headers = new Headers();
|
|
45
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
46
|
-
if (value === void 0) continue;
|
|
47
|
-
if (Array.isArray(value)) for (const v of value) headers.append(key, v);
|
|
48
|
-
else headers.set(key, value);
|
|
49
|
-
}
|
|
50
|
-
const controller = new AbortController();
|
|
51
|
-
res.on("close", () => {
|
|
52
|
-
if (!res.writableFinished) controller.abort();
|
|
53
|
-
});
|
|
54
|
-
const init = {
|
|
55
|
-
method,
|
|
56
|
-
headers,
|
|
57
|
-
signal: controller.signal
|
|
58
|
-
};
|
|
59
|
-
const { body, contentType } = synthesizeBody(expressReq.body);
|
|
60
|
-
if (contentType) headers.set("content-type", contentType);
|
|
61
|
-
headers.delete("content-length");
|
|
62
|
-
if (body !== void 0) init.body = body;
|
|
63
|
-
return new Request(url, init);
|
|
64
|
-
}
|
|
65
|
-
function hasPreParsedBody(req) {
|
|
66
|
-
if (req.body === void 0 || req.body === null) return false;
|
|
67
|
-
return Boolean(req.readableEnded);
|
|
68
|
-
}
|
|
69
|
-
function synthesizeBody(body) {
|
|
70
|
-
if (Buffer.isBuffer(body) || body instanceof Uint8Array) return { body };
|
|
71
|
-
if (typeof body === "string") return { body };
|
|
72
|
-
if (typeof body === "object" && body !== null) return {
|
|
73
|
-
body: JSON.stringify(body),
|
|
74
|
-
contentType: "application/json"
|
|
75
|
-
};
|
|
76
|
-
return {};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
//#endregion
|
|
80
|
-
export { createExpressNodeHandler };
|
|
81
|
-
//# sourceMappingURL=express-fetch-bridge.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"express-fetch-bridge.mjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Only `readableEnded` means \"a parser drained this stream to its end\".\n // `req.complete` and the private `_readableState.ended` are set by the HTTP\n // parser once the socket has all the bytes, whether or not anything read them.\n //\n // That distinction matters because `req.body` being set does not prove a parser\n // ran: body-parser 1.x (Express 4) assigns `req.body = req.body || {}` before\n // its own content-type checks, so a request it declines to parse — multipart\n // upload, text/plain — reaches us with `req.body === {}` and a full, unread\n // stream. Treating that as pre-parsed rebuilt the request from `{}` and\n // dropped the real payload.\n return Boolean(req.readableEnded);\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n // Buffer/Uint8Array<ArrayBufferLike> are valid fetch bodies at runtime,\n // but the DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return { body: body as BodyInit };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAc,yBAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,SAAM,aAAa,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,UAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;AAYxD,QAAO,QAAQ,IAAI,cAAc;;AAGnC,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,WAG3C,QAAO,EAAQ,MAAkB;AAEnC,KAAI,OAAO,SAAS,SAClB,QAAO,EAAE,MAAM;AAEjB,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;EAAE,MAAM,KAAK,UAAU,KAAK;EAAE,aAAa;EAAoB;AAExE,QAAO,EAAE"}
|