@copilotkit/runtime 1.72.0 → 1.72.1-canary.sp-longthread-perf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +34 -0
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +36 -2
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +36 -2
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +35 -2
- package/dist/agent/index.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +23 -16
- package/dist/index.d.mts +23 -16
- package/dist/index.mjs +1 -1
- package/dist/langgraph.d.cts +3 -1
- package/dist/langgraph.d.mts +3 -1
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.d.cts.map +1 -1
- package/dist/lib/index.d.mts.map +1 -1
- package/dist/lib/index.mjs +1 -1
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.cjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.mjs.map +1 -1
- package/dist/lib/integrations/node-express/index.cjs.map +1 -1
- package/dist/lib/integrations/node-express/index.mjs.map +1 -1
- package/dist/lib/integrations/node-http/index.cjs.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +2 -16
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +3 -17
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/v2/index.cjs +1 -0
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/channel-manager.d.mts +1 -0
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/debug-event-bus.cjs +22 -0
- package/dist/v2/runtime/core/debug-event-bus.cjs.map +1 -1
- package/dist/v2/runtime/core/debug-event-bus.d.cts +1 -1
- package/dist/v2/runtime/core/debug-event-bus.d.mts +1 -1
- package/dist/v2/runtime/core/debug-event-bus.mjs +22 -1
- package/dist/v2/runtime/core/debug-event-bus.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +5 -5
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +11 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +11 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +6 -6
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +3 -2
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +3 -2
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-debug-events.cjs +2 -1
- package/dist/v2/runtime/handlers/handle-debug-events.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-debug-events.mjs +3 -1
- package/dist/v2/runtime/handlers/handle-debug-events.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs +5 -3
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +5 -3
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/cloud-telemetry.cjs +31 -0
- package/dist/v2/runtime/handlers/shared/cloud-telemetry.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/cloud-telemetry.mjs +30 -0
- package/dist/v2/runtime/handlers/shared/cloud-telemetry.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +31 -3
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +31 -3
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.cjs +1 -0
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.mjs +1 -0
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
- package/dist/v2/runtime/telemetry/events.d.cts +12 -0
- package/dist/v2/runtime/telemetry/events.d.cts.map +1 -1
- package/dist/v2/runtime/telemetry/events.d.mts +12 -0
- package/dist/v2/runtime/telemetry/events.d.mts.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +3 -2
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.d.cts.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.d.mts.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +7 -6
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -5,7 +5,7 @@ const require_telemetry_client = require('../../telemetry/telemetry-client.cjs')
|
|
|
5
5
|
let _ag_ui_encoder = require("@ag-ui/encoder");
|
|
6
6
|
|
|
7
7
|
//#region src/v2/runtime/handlers/shared/sse-response.ts
|
|
8
|
-
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = require_telemetry_client.default, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
8
|
+
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = require_telemetry_client.default, executionSeed, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
9
9
|
const stream = new TransformStream();
|
|
10
10
|
const writer = stream.writable.getWriter();
|
|
11
11
|
const encoder = new _ag_ui_encoder.EventEncoder();
|
|
@@ -53,8 +53,10 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
53
53
|
if (debug?.lifecycle) debugLogger.debug("SSE stream opened");
|
|
54
54
|
let eventCount = 0;
|
|
55
55
|
let loggedEventCount = 0;
|
|
56
|
+
const executionInfo = { ...executionSeed };
|
|
56
57
|
subscription = observable.subscribe({
|
|
57
58
|
next: async (event) => {
|
|
59
|
+
collectExecutionInfo(event, executionInfo);
|
|
58
60
|
if (event.type === "RUN_STARTED") {
|
|
59
61
|
const e = event;
|
|
60
62
|
debugThreadId = e.threadId ?? "";
|
|
@@ -96,13 +98,16 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
96
98
|
},
|
|
97
99
|
error: async (error) => {
|
|
98
100
|
reportAgentError(error, "sse.subscription");
|
|
99
|
-
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_errored", {
|
|
101
|
+
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_errored", {
|
|
102
|
+
...executionInfo,
|
|
103
|
+
error: error instanceof Error ? error.message : String(error)
|
|
104
|
+
});
|
|
100
105
|
if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
|
|
101
106
|
logError(error);
|
|
102
107
|
await closeStream();
|
|
103
108
|
},
|
|
104
109
|
complete: async () => {
|
|
105
|
-
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_ended",
|
|
110
|
+
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_ended", executionInfo);
|
|
106
111
|
if (debug?.lifecycle) debugLogger.debug({
|
|
107
112
|
eventCount,
|
|
108
113
|
loggedEventCount
|
|
@@ -145,6 +150,29 @@ function summarizeEvent(event) {
|
|
|
145
150
|
if (e.stepName) summary.stepName = e.stepName;
|
|
146
151
|
return summary;
|
|
147
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Accumulate provider, model, and LangGraph facts from one upstream event.
|
|
155
|
+
*
|
|
156
|
+
* Mutates rather than returns so the caller keeps one record across the whole
|
|
157
|
+
* stream: these arrive on different events and the last one wins. Only fields
|
|
158
|
+
* the upstream actually sent are set, so an agent that reports none leaves the
|
|
159
|
+
* record empty and the stream events carry `{}` as before.
|
|
160
|
+
*
|
|
161
|
+
* `rawEvent` is the untransformed upstream payload, present on AG-UI events
|
|
162
|
+
* that wrap one. Its shape is the provider's, not ours, hence the narrowing.
|
|
163
|
+
*/
|
|
164
|
+
function collectExecutionInfo(event, into) {
|
|
165
|
+
const rawEvent = event.rawEvent;
|
|
166
|
+
if (!rawEvent) return;
|
|
167
|
+
const model = rawEvent.data?.output?.model;
|
|
168
|
+
if (model) {
|
|
169
|
+
into.model = model;
|
|
170
|
+
into.provider = model;
|
|
171
|
+
}
|
|
172
|
+
const metadata = rawEvent.metadata;
|
|
173
|
+
if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;
|
|
174
|
+
if (metadata?.langgraph_version) into.langGraphVersion = metadata.langgraph_version;
|
|
175
|
+
}
|
|
148
176
|
|
|
149
177
|
//#endregion
|
|
150
178
|
exports.createSseEventResponse = createSseEventResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-response.cjs","names":["defaultTelemetry","EventEncoder","createLogger"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encodeBinary(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sse-response.cjs","names":["defaultTelemetry","EventEncoder","createLogger"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { AgentExecutionResponseInfo } from \"../../telemetry/events\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Execution facts known before the stream opens, merged under anything the\n * upstream reports as it runs. Carries `llmHostClass`, which is knowable\n * from the agent's configuration and never appears on a streamed event.\n */\n executionSeed?: AgentExecutionResponseInfo;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n executionSeed,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n // Provider/model/LangGraph facts, scraped off raw upstream events as\n // they pass and reported once the stream finishes. This moved here from\n // the v1 TelemetryAgentRunner, which wrapped the runner purely to\n // collect it and emitted its own duplicate copy of every stream event\n // to carry it. v2 callers had no equivalent and reported `{}`.\n // Seeded rather than empty: `llmHostClass` comes from the agent's config,\n // not from the wire, so nothing streamed will ever fill it in. Scraped\n // fields still win, since `collectExecutionInfo` writes over this.\n const executionInfo: AgentExecutionResponseInfo = { ...executionSeed };\n\n subscription = observable.subscribe({\n next: async (event) => {\n collectExecutionInfo(event, executionInfo);\n\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encodeBinary(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n ...executionInfo,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\n \"oss.runtime.agent_execution_stream_ended\",\n executionInfo,\n );\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n\n/**\n * Accumulate provider, model, and LangGraph facts from one upstream event.\n *\n * Mutates rather than returns so the caller keeps one record across the whole\n * stream: these arrive on different events and the last one wins. Only fields\n * the upstream actually sent are set, so an agent that reports none leaves the\n * record empty and the stream events carry `{}` as before.\n *\n * `rawEvent` is the untransformed upstream payload, present on AG-UI events\n * that wrap one. Its shape is the provider's, not ours, hence the narrowing.\n */\nfunction collectExecutionInfo(\n event: BaseEvent,\n into: AgentExecutionResponseInfo,\n): void {\n const rawEvent = (\n event as {\n rawEvent?: {\n metadata?: Record<string, unknown>;\n data?: Record<string, unknown>;\n };\n }\n ).rawEvent;\n if (!rawEvent) return;\n\n const model = (rawEvent.data as { output?: { model?: string } } | undefined)\n ?.output?.model;\n if (model) {\n into.model = model;\n // Carried forward from the v1 implementation, which set both from the\n // same field. The upstream sends no separate provider name.\n into.provider = model;\n }\n\n const metadata = rawEvent.metadata as\n | { langgraph_host?: string; langgraph_version?: string }\n | undefined;\n if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;\n if (metadata?.langgraph_version) {\n into.langGraphVersion = metadata.langgraph_version;\n }\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import telemetry from "../../telemetry/telemetry-client.mjs";
|
|
|
4
4
|
import { EventEncoder } from "@ag-ui/encoder";
|
|
5
5
|
|
|
6
6
|
//#region src/v2/runtime/handlers/shared/sse-response.ts
|
|
7
|
-
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = telemetry, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
7
|
+
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = telemetry, executionSeed, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
8
8
|
const stream = new TransformStream();
|
|
9
9
|
const writer = stream.writable.getWriter();
|
|
10
10
|
const encoder = new EventEncoder();
|
|
@@ -52,8 +52,10 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
52
52
|
if (debug?.lifecycle) debugLogger.debug("SSE stream opened");
|
|
53
53
|
let eventCount = 0;
|
|
54
54
|
let loggedEventCount = 0;
|
|
55
|
+
const executionInfo = { ...executionSeed };
|
|
55
56
|
subscription = observable.subscribe({
|
|
56
57
|
next: async (event) => {
|
|
58
|
+
collectExecutionInfo(event, executionInfo);
|
|
57
59
|
if (event.type === "RUN_STARTED") {
|
|
58
60
|
const e = event;
|
|
59
61
|
debugThreadId = e.threadId ?? "";
|
|
@@ -95,13 +97,16 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
95
97
|
},
|
|
96
98
|
error: async (error) => {
|
|
97
99
|
reportAgentError(error, "sse.subscription");
|
|
98
|
-
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_errored", {
|
|
100
|
+
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_errored", {
|
|
101
|
+
...executionInfo,
|
|
102
|
+
error: error instanceof Error ? error.message : String(error)
|
|
103
|
+
});
|
|
99
104
|
if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
|
|
100
105
|
logError(error);
|
|
101
106
|
await closeStream();
|
|
102
107
|
},
|
|
103
108
|
complete: async () => {
|
|
104
|
-
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_ended",
|
|
109
|
+
if (captureTelemetry) telemetry$1.capture("oss.runtime.agent_execution_stream_ended", executionInfo);
|
|
105
110
|
if (debug?.lifecycle) debugLogger.debug({
|
|
106
111
|
eventCount,
|
|
107
112
|
loggedEventCount
|
|
@@ -144,6 +149,29 @@ function summarizeEvent(event) {
|
|
|
144
149
|
if (e.stepName) summary.stepName = e.stepName;
|
|
145
150
|
return summary;
|
|
146
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Accumulate provider, model, and LangGraph facts from one upstream event.
|
|
154
|
+
*
|
|
155
|
+
* Mutates rather than returns so the caller keeps one record across the whole
|
|
156
|
+
* stream: these arrive on different events and the last one wins. Only fields
|
|
157
|
+
* the upstream actually sent are set, so an agent that reports none leaves the
|
|
158
|
+
* record empty and the stream events carry `{}` as before.
|
|
159
|
+
*
|
|
160
|
+
* `rawEvent` is the untransformed upstream payload, present on AG-UI events
|
|
161
|
+
* that wrap one. Its shape is the provider's, not ours, hence the narrowing.
|
|
162
|
+
*/
|
|
163
|
+
function collectExecutionInfo(event, into) {
|
|
164
|
+
const rawEvent = event.rawEvent;
|
|
165
|
+
if (!rawEvent) return;
|
|
166
|
+
const model = rawEvent.data?.output?.model;
|
|
167
|
+
if (model) {
|
|
168
|
+
into.model = model;
|
|
169
|
+
into.provider = model;
|
|
170
|
+
}
|
|
171
|
+
const metadata = rawEvent.metadata;
|
|
172
|
+
if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;
|
|
173
|
+
if (metadata?.langgraph_version) into.langGraphVersion = metadata.langgraph_version;
|
|
174
|
+
}
|
|
147
175
|
|
|
148
176
|
//#endregion
|
|
149
177
|
export { createSseEventResponse };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-response.mjs","names":["defaultTelemetry"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encodeBinary(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sse-response.mjs","names":["defaultTelemetry"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { AgentExecutionResponseInfo } from \"../../telemetry/events\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Execution facts known before the stream opens, merged under anything the\n * upstream reports as it runs. Carries `llmHostClass`, which is knowable\n * from the agent's configuration and never appears on a streamed event.\n */\n executionSeed?: AgentExecutionResponseInfo;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n executionSeed,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n // Provider/model/LangGraph facts, scraped off raw upstream events as\n // they pass and reported once the stream finishes. This moved here from\n // the v1 TelemetryAgentRunner, which wrapped the runner purely to\n // collect it and emitted its own duplicate copy of every stream event\n // to carry it. v2 callers had no equivalent and reported `{}`.\n // Seeded rather than empty: `llmHostClass` comes from the agent's config,\n // not from the wire, so nothing streamed will ever fill it in. Scraped\n // fields still win, since `collectExecutionInfo` writes over this.\n const executionInfo: AgentExecutionResponseInfo = { ...executionSeed };\n\n subscription = observable.subscribe({\n next: async (event) => {\n collectExecutionInfo(event, executionInfo);\n\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encodeBinary(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n ...executionInfo,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\n \"oss.runtime.agent_execution_stream_ended\",\n executionInfo,\n );\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n\n/**\n * Accumulate provider, model, and LangGraph facts from one upstream event.\n *\n * Mutates rather than returns so the caller keeps one record across the whole\n * stream: these arrive on different events and the last one wins. Only fields\n * the upstream actually sent are set, so an agent that reports none leaves the\n * record empty and the stream events carry `{}` as before.\n *\n * `rawEvent` is the untransformed upstream payload, present on AG-UI events\n * that wrap one. Its shape is the provider's, not ours, hence the narrowing.\n */\nfunction collectExecutionInfo(\n event: BaseEvent,\n into: AgentExecutionResponseInfo,\n): void {\n const rawEvent = (\n event as {\n rawEvent?: {\n metadata?: Record<string, unknown>;\n data?: Record<string, unknown>;\n };\n }\n ).rawEvent;\n if (!rawEvent) return;\n\n const model = (rawEvent.data as { output?: { model?: string } } | undefined)\n ?.output?.model;\n if (model) {\n into.model = model;\n // Carried forward from the v1 implementation, which set both from the\n // same field. The upstream sends no separate provider name.\n into.provider = model;\n }\n\n const metadata = rawEvent.metadata as\n | { langgraph_host?: string; langgraph_version?: string }\n | undefined;\n if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;\n if (metadata?.langgraph_version) {\n into.langGraphVersion = metadata.langgraph_version;\n }\n}\n"],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ function handleSseRun({ runtime, request, agent, input, agentId, debug, logger,
|
|
|
13
13
|
runtimeErrorReporter: require_runtime_error_reporter.getRuntimeErrorReporter(runtime),
|
|
14
14
|
startTime,
|
|
15
15
|
telemetry: runtime.telemetry,
|
|
16
|
+
executionSeed: { llmHostClass: agent.modelHostClass ?? "unknown" },
|
|
16
17
|
observableFactory: () => runtime.runner.run({
|
|
17
18
|
threadId: input.threadId,
|
|
18
19
|
agent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["createSseEventResponse","getRuntimeErrorReporter"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n agentId: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n startTime?: number;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug,\n logger,\n startTime,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n agentId,\n debug,\n logger,\n runtimeErrorReporter: getRuntimeErrorReporter(runtime),\n startTime,\n telemetry: runtime.telemetry,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;;AAmBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,SACA,OACA,QACA,aAC+B;AAC/B,QAAOA,4CAAuB;EAC5B;EACA,eAAe,QAAQ;EACvB;EACA;EACA;EACA,sBAAsBC,uDAAwB,QAAQ;EACtD;EACA,WAAW,QAAQ;
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["createSseEventResponse","getRuntimeErrorReporter"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport type { ResolvedDebugConfig, ModelHostClass } from \"@copilotkit/shared\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n agentId: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n startTime?: number;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug,\n logger,\n startTime,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n agentId,\n debug,\n logger,\n runtimeErrorReporter: getRuntimeErrorReporter(runtime),\n startTime,\n telemetry: runtime.telemetry,\n // Read structurally rather than via `instanceof BuiltInAgent`, which would\n // pull the agent module into this handler. Any agent can opt in by\n // exposing the same property.\n executionSeed: {\n llmHostClass:\n (agent as { modelHostClass?: ModelHostClass }).modelHostClass ??\n \"unknown\",\n },\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;;AAmBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,SACA,OACA,QACA,aAC+B;AAC/B,QAAOA,4CAAuB;EAC5B;EACA,eAAe,QAAQ;EACvB;EACA;EACA;EACA,sBAAsBC,uDAAwB,QAAQ;EACtD;EACA,WAAW,QAAQ;EAInB,eAAe,EACb,cACG,MAA8C,kBAC/C,WACH;EACD,yBACE,QAAQ,OAAO,IAAI;GACjB,UAAU,MAAM;GAChB;GACA;GACD,CAAC;EACL,CAAC"}
|
|
@@ -13,6 +13,7 @@ function handleSseRun({ runtime, request, agent, input, agentId, debug, logger,
|
|
|
13
13
|
runtimeErrorReporter: getRuntimeErrorReporter(runtime),
|
|
14
14
|
startTime,
|
|
15
15
|
telemetry: runtime.telemetry,
|
|
16
|
+
executionSeed: { llmHostClass: agent.modelHostClass ?? "unknown" },
|
|
16
17
|
observableFactory: () => runtime.runner.run({
|
|
17
18
|
threadId: input.threadId,
|
|
18
19
|
agent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n agentId: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n startTime?: number;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug,\n logger,\n startTime,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n agentId,\n debug,\n logger,\n runtimeErrorReporter: getRuntimeErrorReporter(runtime),\n startTime,\n telemetry: runtime.telemetry,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;;AAmBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,SACA,OACA,QACA,aAC+B;AAC/B,QAAO,uBAAuB;EAC5B;EACA,eAAe,QAAQ;EACvB;EACA;EACA;EACA,sBAAsB,wBAAwB,QAAQ;EACtD;EACA,WAAW,QAAQ;
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport type { ResolvedDebugConfig, ModelHostClass } from \"@copilotkit/shared\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n agentId: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n startTime?: number;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug,\n logger,\n startTime,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n agentId,\n debug,\n logger,\n runtimeErrorReporter: getRuntimeErrorReporter(runtime),\n startTime,\n telemetry: runtime.telemetry,\n // Read structurally rather than via `instanceof BuiltInAgent`, which would\n // pull the agent module into this handler. Any agent can opt in by\n // exposing the same property.\n executionSeed: {\n llmHostClass:\n (agent as { modelHostClass?: ModelHostClass }).modelHostClass ??\n \"unknown\",\n },\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;;AAmBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,SACA,OACA,QACA,aAC+B;AAC/B,QAAO,uBAAuB;EAC5B;EACA,eAAe,QAAQ;EACvB;EACA;EACA;EACA,sBAAsB,wBAAwB,QAAQ;EACtD;EACA,WAAW,QAAQ;EAInB,eAAe,EACb,cACG,MAA8C,kBAC/C,WACH;EACD,yBACE,QAAQ,OAAO,IAAI;GACjB,UAAU,MAAM;GAChB;GACA;GACD,CAAC;EACL,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
|
|
2
|
+
import { ModelHostClass } from "@copilotkit/shared";
|
|
3
|
+
|
|
2
4
|
//#region src/v2/runtime/telemetry/events.d.ts
|
|
3
5
|
type AnalyticsEvents = {
|
|
4
6
|
"oss.runtime.instance_created": RuntimeInstanceCreatedInfo;
|
|
@@ -44,6 +46,16 @@ interface RuntimeInstanceCreatedInfo {
|
|
|
44
46
|
"cloud.base_url"?: string;
|
|
45
47
|
}
|
|
46
48
|
interface AgentExecutionResponseInfo {
|
|
49
|
+
/**
|
|
50
|
+
* Which vendor the runtime actually sent the completion to, as a closed
|
|
51
|
+
* vocabulary — see `classifyModelHost`. Distinct from `provider` below,
|
|
52
|
+
* which the upstream reports as a model name and which cannot tell Azure,
|
|
53
|
+
* OpenRouter or a local server apart from OpenAI.
|
|
54
|
+
*
|
|
55
|
+
* `unknown` when the developer handed us an already-built model, because
|
|
56
|
+
* the endpoint is unrecoverable from one.
|
|
57
|
+
*/
|
|
58
|
+
llmHostClass?: ModelHostClass;
|
|
47
59
|
provider?: string;
|
|
48
60
|
model?: string;
|
|
49
61
|
langGraphHost?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.cts","names":[],"sources":["../../../../src/v2/runtime/telemetry/events.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"events.d.cts","names":[],"sources":["../../../../src/v2/runtime/telemetry/events.ts"],"mappings":";;;;KAEY,eAAA;EACV,8BAAA,EAAgC,0BAAA;EAChC,qCAAA;IACE,0BAAA;IACA,WAAA;IACA,wBAAA;IACA,sBAAA;IACA,gBAAA;EAAA;EAEF,4CAAA;IAAgD,YAAA;EAAA;EAChD,0CAAA,EAA4C,0BAAA;EAC5C,4CAAA;IACE,YAAA;IACA,KAAA;EAAA;EANA;;;;;EAaF,qCAAA,EAAuC,yBAAA,EARrC;EAUF,uCAAA;IAA2C,SAAA;EAAA;AAAA;AAAA,UAG5B,yBAAA;EAHqC;EAKpD,MAAA;EAFe;EAIf,IAAA;AAAA;AAAA,UAGe,0BAAA;EACf,aAAA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,YAAA;EACA,wBAAA;EACA,sBAAA;EACA,gBAAA;AAAA;AAAA,UAGe,0BAAA;EALf;;;;;AAKF;;;;EAUE,YAAA,GAAe,cAAA;EACf,QAAA;EACA,KAAA;EACA,aAAA;EACA,gBAAA;EACA,YAAA;AAAA"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
|
|
2
|
+
import { ModelHostClass } from "@copilotkit/shared";
|
|
3
|
+
|
|
2
4
|
//#region src/v2/runtime/telemetry/events.d.ts
|
|
3
5
|
type AnalyticsEvents = {
|
|
4
6
|
"oss.runtime.instance_created": RuntimeInstanceCreatedInfo;
|
|
@@ -44,6 +46,16 @@ interface RuntimeInstanceCreatedInfo {
|
|
|
44
46
|
"cloud.base_url"?: string;
|
|
45
47
|
}
|
|
46
48
|
interface AgentExecutionResponseInfo {
|
|
49
|
+
/**
|
|
50
|
+
* Which vendor the runtime actually sent the completion to, as a closed
|
|
51
|
+
* vocabulary — see `classifyModelHost`. Distinct from `provider` below,
|
|
52
|
+
* which the upstream reports as a model name and which cannot tell Azure,
|
|
53
|
+
* OpenRouter or a local server apart from OpenAI.
|
|
54
|
+
*
|
|
55
|
+
* `unknown` when the developer handed us an already-built model, because
|
|
56
|
+
* the endpoint is unrecoverable from one.
|
|
57
|
+
*/
|
|
58
|
+
llmHostClass?: ModelHostClass;
|
|
47
59
|
provider?: string;
|
|
48
60
|
model?: string;
|
|
49
61
|
langGraphHost?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.mts","names":[],"sources":["../../../../src/v2/runtime/telemetry/events.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"events.d.mts","names":[],"sources":["../../../../src/v2/runtime/telemetry/events.ts"],"mappings":";;;;KAEY,eAAA;EACV,8BAAA,EAAgC,0BAAA;EAChC,qCAAA;IACE,0BAAA;IACA,WAAA;IACA,wBAAA;IACA,sBAAA;IACA,gBAAA;EAAA;EAEF,4CAAA;IAAgD,YAAA;EAAA;EAChD,0CAAA,EAA4C,0BAAA;EAC5C,4CAAA;IACE,YAAA;IACA,KAAA;EAAA;EANA;;;;;EAaF,qCAAA,EAAuC,yBAAA,EARrC;EAUF,uCAAA;IAA2C,SAAA;EAAA;AAAA;AAAA,UAG5B,yBAAA;EAHqC;EAKpD,MAAA;EAFe;EAIf,IAAA;AAAA;AAAA,UAGe,0BAAA;EACf,aAAA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,YAAA;EACA,wBAAA;EACA,sBAAA;EACA,gBAAA;AAAA;AAAA,UAGe,0BAAA;EALf;;;;;AAKF;;;;EAUE,YAAA,GAAe,cAAA;EACf,QAAA;EACA,KAAA;EACA,aAAA;EACA,gBAAA;EACA,YAAA;AAAA"}
|
|
@@ -11,7 +11,7 @@ function isTelemetryDisabled() {
|
|
|
11
11
|
var TelemetryClient = class {
|
|
12
12
|
constructor({ telemetryDisabled, sampleRate } = {}) {
|
|
13
13
|
this.telemetryDisabled = false;
|
|
14
|
-
this.sampleRate =
|
|
14
|
+
this.sampleRate = 1;
|
|
15
15
|
this.licenseToken = null;
|
|
16
16
|
this.telemetryId = null;
|
|
17
17
|
this.licenseTelemetryId = null;
|
|
@@ -72,6 +72,7 @@ var TelemetryClient = class {
|
|
|
72
72
|
sampleRate: this.sampleRate
|
|
73
73
|
}),
|
|
74
74
|
telemetry_emitter: _copilotkit_shared.TELEMETRY_EMITTER_V2,
|
|
75
|
+
telemetry_surface: _copilotkit_shared.TELEMETRY_SURFACE_V2,
|
|
75
76
|
telemetry_transport: "lambda"
|
|
76
77
|
},
|
|
77
78
|
packageName: import_package.name,
|
|
@@ -95,7 +96,7 @@ var TelemetryClient = class {
|
|
|
95
96
|
}
|
|
96
97
|
setSampleRate(sampleRate) {
|
|
97
98
|
let _sampleRate;
|
|
98
|
-
_sampleRate = sampleRate ??
|
|
99
|
+
_sampleRate = sampleRate ?? 1;
|
|
99
100
|
if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);
|
|
100
101
|
if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) throw new Error("Sample rate must be between 0 and 1");
|
|
101
102
|
this.sampleRate = _sampleRate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.cjs","names":["lambdaClient","TELEMETRY_EMITTER_V2","packageJson"],"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} from \"@copilotkit/shared\";\nimport * as packageJson from \"../../../../package.json\";\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 // Client-side sampling rate for anonymous events. Identified callers\n // (license token with telemetry_id) bypass the gate. Default 0.05\n // caps anonymous OSS-runtime egress; identified customers send at\n // full fidelity. Override via COPILOTKIT_TELEMETRY_SAMPLE_RATE.\n private sampleRate: number = 0.05;\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 grant sampling\n // authority.\n private telemetryId: string | null = null;\n // License-derived identity used only as sampling authority.\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 // Standalone identity is a transport claim, not sampling authority.\n // Only a legacy license token with telemetry_id bypasses sampleRate.\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: an event\n // that records no sampling decision can't be weighted, and anyone\n // counting raw events understates anonymous volume ~20× (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 // 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: packageJson.name,\n packageVersion: packageJson.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 ?? 0.05;\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":";;;;;;;AA8BA,SAAgB,sBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAgC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BArC6B;oBAKR;sBAIS;qBAGD;4BAEO;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;GAUZ,kBAAkB;IAChB,GAAG,KAAK;IACR,+CAAuB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmBC;IAInB,qBAAqB;IACtB;GACD,aAAaC,eAAY;GACzB,gBAAgBA,eAAY;GAC5B,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","packageJson"],"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 * as packageJson from \"../../../../package.json\";\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: packageJson.name,\n packageVersion: packageJson.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":";;;;;;;AA+BA,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,eAAY;GACzB,gBAAgBA,eAAY;GAC5B,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.d.cts","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"telemetry-client.d.cts","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"mappings":";;;;;UAkBiB,gBAAA;EACf,OAAA,iBAAwB,eAAA,EACtB,KAAA,EAAO,CAAA,EACP,UAAA,EAAY,eAAA,CAAgB,CAAA,IAC3B,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.d.mts","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"telemetry-client.d.mts","names":[],"sources":["../../../../src/v2/runtime/telemetry/telemetry-client.ts"],"mappings":";;;;;UAkBiB,gBAAA;EACf,OAAA,iBAAwB,eAAA,EACtB,KAAA,EAAO,CAAA,EACP,UAAA,EAAY,eAAA,CAAgB,CAAA,IAC3B,OAAA;AAAA"}
|
|
@@ -2,22 +2,22 @@ import "reflect-metadata";
|
|
|
2
2
|
import { __toESM } from "../../../_virtual/_rolldown/runtime.mjs";
|
|
3
3
|
import { require_package } from "../../../package.mjs";
|
|
4
4
|
import { firstNonBlankTelemetryId } from "./telemetry-identity.mjs";
|
|
5
|
-
import { TELEMETRY_EMITTER_V2, computeSamplingMeta, lambdaClient, parseAndWarnTelemetryId } from "@copilotkit/shared";
|
|
5
|
+
import { TELEMETRY_EMITTER_V2, TELEMETRY_SURFACE_V2, computeSamplingMeta, lambdaClient, parseAndWarnTelemetryId } from "@copilotkit/shared";
|
|
6
6
|
|
|
7
7
|
//#region src/v2/runtime/telemetry/telemetry-client.ts
|
|
8
8
|
var import_package = /* @__PURE__ */ __toESM(require_package());
|
|
9
|
-
function isTelemetryDisabled
|
|
9
|
+
function isTelemetryDisabled() {
|
|
10
10
|
return process.env.COPILOTKIT_TELEMETRY_DISABLED === "true" || process.env.COPILOTKIT_TELEMETRY_DISABLED === "1" || process.env.DO_NOT_TRACK === "true" || process.env.DO_NOT_TRACK === "1";
|
|
11
11
|
}
|
|
12
12
|
var TelemetryClient = class {
|
|
13
13
|
constructor({ telemetryDisabled, sampleRate } = {}) {
|
|
14
14
|
this.telemetryDisabled = false;
|
|
15
|
-
this.sampleRate =
|
|
15
|
+
this.sampleRate = 1;
|
|
16
16
|
this.licenseToken = null;
|
|
17
17
|
this.telemetryId = null;
|
|
18
18
|
this.licenseTelemetryId = null;
|
|
19
19
|
this.globalProperties = {};
|
|
20
|
-
this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled
|
|
20
|
+
this.telemetryDisabled = telemetryDisabled || isTelemetryDisabled();
|
|
21
21
|
this.setSampleRate(sampleRate);
|
|
22
22
|
}
|
|
23
23
|
shouldSendEvent() {
|
|
@@ -73,6 +73,7 @@ var TelemetryClient = class {
|
|
|
73
73
|
sampleRate: this.sampleRate
|
|
74
74
|
}),
|
|
75
75
|
telemetry_emitter: TELEMETRY_EMITTER_V2,
|
|
76
|
+
telemetry_surface: TELEMETRY_SURFACE_V2,
|
|
76
77
|
telemetry_transport: "lambda"
|
|
77
78
|
},
|
|
78
79
|
packageName: import_package.name,
|
|
@@ -96,7 +97,7 @@ var TelemetryClient = class {
|
|
|
96
97
|
}
|
|
97
98
|
setSampleRate(sampleRate) {
|
|
98
99
|
let _sampleRate;
|
|
99
|
-
_sampleRate = sampleRate ??
|
|
100
|
+
_sampleRate = sampleRate ?? 1;
|
|
100
101
|
if (process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE) _sampleRate = parseFloat(process.env.COPILOTKIT_TELEMETRY_SAMPLE_RATE);
|
|
101
102
|
if (Number.isNaN(_sampleRate) || _sampleRate < 0 || _sampleRate > 1) throw new Error("Sample rate must be between 0 and 1");
|
|
102
103
|
this.sampleRate = _sampleRate;
|
|
@@ -105,5 +106,5 @@ var TelemetryClient = class {
|
|
|
105
106
|
const telemetry = new TelemetryClient();
|
|
106
107
|
|
|
107
108
|
//#endregion
|
|
108
|
-
export { telemetry as default, isTelemetryDisabled
|
|
109
|
+
export { telemetry as default, isTelemetryDisabled };
|
|
109
110
|
//# sourceMappingURL=telemetry-client.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-client.mjs","names":["isTelemetryDisabled","packageJson"],"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} from \"@copilotkit/shared\";\nimport * as packageJson from \"../../../../package.json\";\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 // Client-side sampling rate for anonymous events. Identified callers\n // (license token with telemetry_id) bypass the gate. Default 0.05\n // caps anonymous OSS-runtime egress; identified customers send at\n // full fidelity. Override via COPILOTKIT_TELEMETRY_SAMPLE_RATE.\n private sampleRate: number = 0.05;\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 grant sampling\n // authority.\n private telemetryId: string | null = null;\n // License-derived identity used only as sampling authority.\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 // Standalone identity is a transport claim, not sampling authority.\n // Only a legacy license token with telemetry_id bypasses sampleRate.\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: an event\n // that records no sampling decision can't be weighted, and anyone\n // counting raw events understates anonymous volume ~20× (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 // 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: packageJson.name,\n packageVersion: packageJson.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 ?? 0.05;\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":";;;;;;;;AA8BA,SAAgBA,wBAA+B;AAC7C,QACG,QAAQ,IACN,kCAAkC,UACpC,QAAQ,IACN,kCAAkC,OACpC,QAAQ,IAA2C,iBAClD,UACD,QAAQ,IAA2C,iBAAiB;;AAIzE,IAAa,kBAAb,MAA6B;CAgC3B,YAAY,EACV,mBACA,eAIE,EAAE,EAAE;2BArC6B;oBAKR;sBAIS;qBAGD;4BAEO;0BAeQ,EAAE;AASpD,OAAK,oBAAoB,qBAAqBA,uBAAqB;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;GAUZ,kBAAkB;IAChB,GAAG,KAAK;IACR,GAAG,oBAAoB;KACrB,aAAa,SAAS;KACtB,YAAY,KAAK;KAClB,CAAC;IACF,mBAAmB;IAInB,qBAAqB;IACtB;GACD,aAAaC,eAAY;GACzB,gBAAgBA,eAAY;GAC5B,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":["packageJson"],"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 * as packageJson from \"../../../../package.json\";\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: packageJson.name,\n packageVersion: packageJson.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":";;;;;;;;AA+BA,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,aAAaA,eAAY;GACzB,gBAAgBA,eAAY;GAC5B,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.72.
|
|
3
|
+
"version": "1.72.1-canary.sp-longthread-perf",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"@ai-sdk/openai": "^3.0.36",
|
|
79
79
|
"@cfworker/json-schema": "^4.1.1",
|
|
80
80
|
"@copilotkit/license-verifier": "~0.5.0",
|
|
81
|
+
"@copilotkit/shared": "1.72.1-canary.sp-longthread-perf",
|
|
81
82
|
"@graphql-yoga/plugin-defer-stream": "^3.3.1",
|
|
82
83
|
"@hono/node-server": "^1.13.5",
|
|
83
84
|
"@modelcontextprotocol/sdk": "^1.18.2",
|
|
@@ -108,7 +109,6 @@
|
|
|
108
109
|
"ws": "^8.18.0",
|
|
109
110
|
"zod": "^3.23.3",
|
|
110
111
|
"@copilotkit/channels-core": "^0.10.0",
|
|
111
|
-
"@copilotkit/shared": "1.72.0",
|
|
112
112
|
"@copilotkit/channels-intelligence": "0.10.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|