@copilotkit/runtime 1.56.2 → 1.56.4
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/graphql/resolvers/copilot.resolver.cjs +2 -1
- package/dist/graphql/resolvers/copilot.resolver.cjs.map +1 -1
- package/dist/graphql/resolvers/copilot.resolver.mjs +2 -1
- package/dist/graphql/resolvers/copilot.resolver.mjs.map +1 -1
- package/dist/graphql/resolvers/resolve-message-id.cjs +19 -0
- package/dist/graphql/resolvers/resolve-message-id.cjs.map +1 -0
- package/dist/graphql/resolvers/resolve-message-id.mjs +18 -0
- package/dist/graphql/resolvers/resolve-message-id.mjs.map +1 -0
- package/dist/lib/runtime/copilot-runtime.cjs +4 -2
- 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 +4 -2
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +2 -2
- package/dist/package.mjs +2 -2
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/runtime/core/debug-event-bus.cjs +36 -0
- package/dist/v2/runtime/core/debug-event-bus.cjs.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.d.cts +19 -0
- package/dist/v2/runtime/core/debug-event-bus.d.cts.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.d.mts +19 -0
- package/dist/v2/runtime/core/debug-event-bus.d.mts.map +1 -0
- package/dist/v2/runtime/core/debug-event-bus.mjs +35 -0
- package/dist/v2/runtime/core/debug-event-bus.mjs.map +1 -0
- package/dist/v2/runtime/core/fetch-handler.cjs +8 -0
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +8 -0
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.cjs +1 -0
- package/dist/v2/runtime/core/fetch-router.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-router.mjs +1 -0
- package/dist/v2/runtime/core/fetch-router.mjs.map +1 -1
- package/dist/v2/runtime/core/hooks.cjs.map +1 -1
- package/dist/v2/runtime/core/hooks.d.cts +2 -0
- package/dist/v2/runtime/core/hooks.d.cts.map +1 -1
- package/dist/v2/runtime/core/hooks.d.mts +2 -0
- package/dist/v2/runtime/core/hooks.d.mts.map +1 -1
- package/dist/v2/runtime/core/hooks.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +5 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +5 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +5 -1
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +5 -0
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +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 +33 -0
- package/dist/v2/runtime/handlers/handle-debug-events.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-debug-events.mjs +32 -0
- package/dist/v2/runtime/handlers/handle-debug-events.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +1 -0
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/connect.cjs +24 -4
- package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/connect.mjs +25 -5
- package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +111 -26
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +111 -26
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +7 -3
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +7 -3
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +5 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +5 -1
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +21 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +21 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs +3 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs +3 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.cjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.mjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -2
- package/dist/v2/runtime/index.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +6 -8
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +16 -21
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +16 -21
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +6 -8
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts +0 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts +0 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
- package/dist/v2/runtime/runner/index.d.cts +1 -1
- package/dist/v2/runtime/runner/index.d.mts +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs +47 -10
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts +8 -1
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts +8 -1
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs +47 -10
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/dist/v2/runtime/telemetry/instance-created.cjs +33 -0
- package/dist/v2/runtime/telemetry/instance-created.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/instance-created.mjs +33 -0
- package/dist/v2/runtime/telemetry/instance-created.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +1 -38
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +1 -37
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
- package/package.json +3 -3
- package/src/agents/langgraph/__tests__/event-source.test.ts +256 -0
- package/src/graphql/resolvers/__tests__/resolve-message-id.test.ts +25 -0
- package/src/graphql/resolvers/copilot.resolver.ts +2 -1
- package/src/graphql/resolvers/resolve-message-id.ts +14 -0
- package/src/lib/runtime/__tests__/handle-service-adapter.test.ts +108 -0
- package/src/lib/runtime/__tests__/retry-utils.test.ts +137 -0
- package/src/lib/runtime/agent-integrations/langgraph/__tests__/dispatch-event-filtering.test.ts +190 -0
- package/src/lib/runtime/copilot-runtime.ts +20 -4
- package/src/lib/runtime/retry-utils.ts +41 -1
- package/src/v2/runtime/__tests__/express-single-telemetry.integration.test.ts +65 -0
- package/src/v2/runtime/__tests__/express-telemetry.integration.test.ts +101 -0
- package/src/v2/runtime/__tests__/fetch-router.test.ts +22 -0
- package/src/v2/runtime/__tests__/handle-connect.test.ts +183 -23
- package/src/v2/runtime/__tests__/handle-run.test.ts +411 -33
- package/src/v2/runtime/__tests__/handle-threads.test.ts +66 -4
- package/src/v2/runtime/__tests__/hono-single-telemetry.integration.test.ts +46 -0
- package/src/v2/runtime/__tests__/hono-telemetry.integration.test.ts +99 -0
- package/src/v2/runtime/__tests__/integration/node-servers.integration.test.ts +19 -0
- package/src/v2/runtime/__tests__/integration/suites/debug-events.suite.ts +253 -0
- package/src/v2/runtime/__tests__/intelligence-run-telemetry.test.ts +194 -0
- package/src/v2/runtime/__tests__/runtime.test.ts +3 -1
- package/src/v2/runtime/__tests__/sse-response-telemetry.test.ts +108 -0
- package/src/v2/runtime/__tests__/telemetry.test.ts +0 -61
- package/src/v2/runtime/core/__tests__/debug-event-bus.test.ts +156 -0
- package/src/v2/runtime/core/debug-event-bus.ts +45 -0
- package/src/v2/runtime/core/fetch-handler.ts +7 -0
- package/src/v2/runtime/core/fetch-router.ts +11 -0
- package/src/v2/runtime/core/hooks.ts +2 -1
- package/src/v2/runtime/core/runtime.ts +12 -0
- package/src/v2/runtime/handlers/__tests__/handle-debug-events.test.ts +176 -0
- package/src/v2/runtime/handlers/handle-connect.ts +2 -1
- package/src/v2/runtime/handlers/handle-debug-events.ts +52 -0
- package/src/v2/runtime/handlers/handle-run.ts +1 -0
- package/src/v2/runtime/handlers/intelligence/connect.ts +48 -11
- package/src/v2/runtime/handlers/intelligence/run.ts +162 -21
- package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -1
- package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +4 -1
- package/src/v2/runtime/handlers/shared/sse-response.ts +46 -0
- package/src/v2/runtime/handlers/sse/__tests__/sse-connect-agent-id.test.ts +71 -0
- package/src/v2/runtime/handlers/sse/connect.ts +6 -0
- package/src/v2/runtime/handlers/sse/run.ts +4 -0
- package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +33 -37
- package/src/v2/runtime/intelligence-platform/client.ts +37 -40
- package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +66 -8
- package/src/v2/runtime/runner/agent-runner.ts +0 -1
- package/src/v2/runtime/runner/intelligence.ts +74 -15
- package/src/v2/runtime/telemetry/__tests__/instance-created.test.ts +96 -0
- package/src/v2/runtime/telemetry/instance-created.ts +44 -0
- package/src/v2/runtime/telemetry/telemetry-client.ts +1 -57
- package/dist/v2/runtime/intelligence-platform/index.d.mts +0 -2
- package/dist/v2/runtime/telemetry/utils.cjs +0 -15
- package/dist/v2/runtime/telemetry/utils.cjs.map +0 -1
- package/dist/v2/runtime/telemetry/utils.mjs +0 -14
- package/dist/v2/runtime/telemetry/utils.mjs.map +0 -1
- package/src/v2/runtime/telemetry/utils.ts +0 -15
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry lifecycle tests for `packages/runtime/src/v2/runtime/handlers/intelligence/run.ts`.
|
|
3
|
+
*
|
|
4
|
+
* intelligence/run.ts fires three events across the agent run lifecycle:
|
|
5
|
+
* - oss.runtime.agent_execution_stream_started (line 126, after thread lock)
|
|
6
|
+
* - oss.runtime.agent_execution_stream_errored (inside runner subscribe's error handler)
|
|
7
|
+
* - oss.runtime.agent_execution_stream_ended (inside runner subscribe's complete handler)
|
|
8
|
+
*
|
|
9
|
+
* This test verifies each fires under the expected condition. It's paired
|
|
10
|
+
* with sse-response-telemetry.test.ts which covers the SSE path of the
|
|
11
|
+
* same event names — kept separate so a regression in one file fails only
|
|
12
|
+
* its own test.
|
|
13
|
+
*/
|
|
14
|
+
import type { AbstractAgent, BaseEvent } from "@ag-ui/client";
|
|
15
|
+
import { Observable } from "rxjs";
|
|
16
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
17
|
+
|
|
18
|
+
import { handleRunAgent } from "../handlers/handle-run";
|
|
19
|
+
import { IntelligenceAgentRunner } from "../runner/intelligence";
|
|
20
|
+
import { telemetry } from "../telemetry";
|
|
21
|
+
import type { CopilotRuntime } from "../core/runtime";
|
|
22
|
+
|
|
23
|
+
// --- Minimal helpers (mirroring handle-run.test.ts's intelligence block) ---
|
|
24
|
+
|
|
25
|
+
interface MockIntelligencePlatform {
|
|
26
|
+
[key: string]: ((...args: any[]) => any) | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function makeAgent(): AbstractAgent {
|
|
30
|
+
const makeClone = () =>
|
|
31
|
+
({
|
|
32
|
+
clone: vi.fn(() => makeClone()),
|
|
33
|
+
setMessages: vi.fn(),
|
|
34
|
+
setState: vi.fn(),
|
|
35
|
+
threadId: undefined,
|
|
36
|
+
headers: {},
|
|
37
|
+
runAgent: vi.fn().mockResolvedValue(undefined),
|
|
38
|
+
}) as unknown as AbstractAgent;
|
|
39
|
+
const agent: any = {
|
|
40
|
+
clone: vi.fn(() => makeClone()),
|
|
41
|
+
setMessages: vi.fn(),
|
|
42
|
+
setState: vi.fn(),
|
|
43
|
+
threadId: undefined,
|
|
44
|
+
headers: {},
|
|
45
|
+
runAgent: vi.fn().mockResolvedValue(undefined),
|
|
46
|
+
};
|
|
47
|
+
return agent as AbstractAgent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function makeIntelligenceRuntime(
|
|
51
|
+
runObservable: Observable<BaseEvent>,
|
|
52
|
+
extraPlatform: MockIntelligencePlatform = {},
|
|
53
|
+
): CopilotRuntime {
|
|
54
|
+
const runner = Object.create(IntelligenceAgentRunner.prototype);
|
|
55
|
+
runner.run = vi.fn(() => runObservable);
|
|
56
|
+
|
|
57
|
+
const platform: MockIntelligencePlatform = {
|
|
58
|
+
getOrCreateThread: vi.fn().mockResolvedValue({
|
|
59
|
+
thread: { id: "thread-1", name: null },
|
|
60
|
+
created: false,
|
|
61
|
+
}),
|
|
62
|
+
getThreadMessages: vi.fn().mockResolvedValue({ messages: [] }),
|
|
63
|
+
ɵacquireThreadLock: vi.fn().mockResolvedValue({
|
|
64
|
+
threadId: "thread-1",
|
|
65
|
+
runId: "run-1",
|
|
66
|
+
joinToken: "jt-1",
|
|
67
|
+
}),
|
|
68
|
+
ɵcleanupThreadLock: vi.fn().mockResolvedValue(undefined),
|
|
69
|
+
ɵgetClientWsUrl: vi.fn(() => "wss://runtime.example/client"),
|
|
70
|
+
ɵrenewThreadLock: vi.fn().mockResolvedValue(undefined),
|
|
71
|
+
...extraPlatform,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
agents: Promise.resolve({ "my-agent": makeAgent() }),
|
|
76
|
+
transcriptionService: undefined,
|
|
77
|
+
beforeRequestMiddleware: undefined,
|
|
78
|
+
afterRequestMiddleware: undefined,
|
|
79
|
+
runner,
|
|
80
|
+
mode: "intelligence",
|
|
81
|
+
generateThreadNames: false,
|
|
82
|
+
intelligence: platform,
|
|
83
|
+
identifyUser: vi.fn().mockResolvedValue({ id: "user-1", name: "User One" }),
|
|
84
|
+
lockTtlSeconds: 20,
|
|
85
|
+
lockHeartbeatIntervalSeconds: 15,
|
|
86
|
+
} as unknown as CopilotRuntime;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function makeRunRequest(): Request {
|
|
90
|
+
return new Request("https://example.com/agent/my-agent/run", {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: { "Content-Type": "application/json" },
|
|
93
|
+
body: JSON.stringify({
|
|
94
|
+
threadId: "thread-1",
|
|
95
|
+
runId: "run-1",
|
|
96
|
+
state: {},
|
|
97
|
+
messages: [],
|
|
98
|
+
tools: [],
|
|
99
|
+
context: [],
|
|
100
|
+
forwardedProps: {},
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// --- Tests ---
|
|
106
|
+
|
|
107
|
+
describe("intelligence/run.ts — telemetry lifecycle", () => {
|
|
108
|
+
let captureSpy: ReturnType<typeof vi.spyOn>;
|
|
109
|
+
let errorSpy: ReturnType<typeof vi.spyOn>;
|
|
110
|
+
|
|
111
|
+
beforeEach(() => {
|
|
112
|
+
vi.useFakeTimers();
|
|
113
|
+
captureSpy = vi.spyOn(telemetry, "capture").mockResolvedValue(undefined);
|
|
114
|
+
// Swallow the logger.error that fires on simulated agent errors.
|
|
115
|
+
errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
afterEach(() => {
|
|
119
|
+
vi.useRealTimers();
|
|
120
|
+
captureSpy.mockRestore();
|
|
121
|
+
errorSpy.mockRestore();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("fires agent_execution_stream_started once thread lock is acquired", async () => {
|
|
125
|
+
// Observable that never completes — so only stream_started should fire.
|
|
126
|
+
const never = new Observable<BaseEvent>(() => {});
|
|
127
|
+
const runtime = makeIntelligenceRuntime(never);
|
|
128
|
+
|
|
129
|
+
await handleRunAgent({
|
|
130
|
+
runtime,
|
|
131
|
+
request: makeRunRequest(),
|
|
132
|
+
agentId: "my-agent",
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
136
|
+
"oss.runtime.agent_execution_stream_started",
|
|
137
|
+
{},
|
|
138
|
+
);
|
|
139
|
+
// And NOT the other two
|
|
140
|
+
expect(captureSpy).not.toHaveBeenCalledWith(
|
|
141
|
+
"oss.runtime.agent_execution_stream_errored",
|
|
142
|
+
expect.anything(),
|
|
143
|
+
);
|
|
144
|
+
expect(captureSpy).not.toHaveBeenCalledWith(
|
|
145
|
+
"oss.runtime.agent_execution_stream_ended",
|
|
146
|
+
expect.anything(),
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("fires agent_execution_stream_ended when runner.run observable completes", async () => {
|
|
151
|
+
// Observable that completes immediately.
|
|
152
|
+
const completing = new Observable<BaseEvent>((subscriber) => {
|
|
153
|
+
subscriber.complete();
|
|
154
|
+
});
|
|
155
|
+
const runtime = makeIntelligenceRuntime(completing);
|
|
156
|
+
|
|
157
|
+
await handleRunAgent({
|
|
158
|
+
runtime,
|
|
159
|
+
request: makeRunRequest(),
|
|
160
|
+
agentId: "my-agent",
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
164
|
+
"oss.runtime.agent_execution_stream_started",
|
|
165
|
+
{},
|
|
166
|
+
);
|
|
167
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
168
|
+
"oss.runtime.agent_execution_stream_ended",
|
|
169
|
+
{},
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("fires agent_execution_stream_errored when runner.run observable errors", async () => {
|
|
174
|
+
const failing = new Observable<BaseEvent>((subscriber) => {
|
|
175
|
+
subscriber.error(new Error("agent exploded"));
|
|
176
|
+
});
|
|
177
|
+
const runtime = makeIntelligenceRuntime(failing);
|
|
178
|
+
|
|
179
|
+
await handleRunAgent({
|
|
180
|
+
runtime,
|
|
181
|
+
request: makeRunRequest(),
|
|
182
|
+
agentId: "my-agent",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
186
|
+
"oss.runtime.agent_execution_stream_started",
|
|
187
|
+
{},
|
|
188
|
+
);
|
|
189
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
190
|
+
"oss.runtime.agent_execution_stream_errored",
|
|
191
|
+
expect.objectContaining({ error: "agent exploded" }),
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
@@ -11,7 +11,9 @@ import { IntelligenceAgentRunner } from "../runner/intelligence";
|
|
|
11
11
|
|
|
12
12
|
describe("runtime construction", () => {
|
|
13
13
|
const agents = {};
|
|
14
|
-
const identifyUser = vi
|
|
14
|
+
const identifyUser = vi
|
|
15
|
+
.fn()
|
|
16
|
+
.mockResolvedValue({ id: "user-1", name: "User One" });
|
|
15
17
|
const createMockIntelligence = (): CopilotKitIntelligence =>
|
|
16
18
|
({
|
|
17
19
|
ɵgetRunnerWsUrl: vi.fn().mockReturnValue("ws://runner.example"),
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry lifecycle tests for `packages/runtime/src/v2/runtime/handlers/shared/sse-response.ts`.
|
|
3
|
+
*
|
|
4
|
+
* sse-response.ts fires three events across the SSE stream lifecycle:
|
|
5
|
+
* - oss.runtime.agent_execution_stream_started (line 73, right after observableFactory resolves)
|
|
6
|
+
* - oss.runtime.agent_execution_stream_errored (inside subscribe's error handler)
|
|
7
|
+
* - oss.runtime.agent_execution_stream_ended (inside subscribe's complete handler)
|
|
8
|
+
*
|
|
9
|
+
* Paired with intelligence-run-telemetry.test.ts which covers the
|
|
10
|
+
* intelligence/run path of the same event names — kept separate so a
|
|
11
|
+
* regression in one source file fails only its own test.
|
|
12
|
+
*/
|
|
13
|
+
import { BaseEvent } from "@ag-ui/client";
|
|
14
|
+
import { Observable } from "rxjs";
|
|
15
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
16
|
+
|
|
17
|
+
import { createSseEventResponse } from "../handlers/shared/sse-response";
|
|
18
|
+
import { telemetry } from "../telemetry";
|
|
19
|
+
|
|
20
|
+
function makeRequest(): Request {
|
|
21
|
+
return new Request("https://example.com/agent/test/run", { method: "POST" });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("sse-response.ts — telemetry lifecycle", () => {
|
|
25
|
+
let captureSpy: ReturnType<typeof vi.spyOn>;
|
|
26
|
+
let errorSpy: ReturnType<typeof vi.spyOn>;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
captureSpy = vi.spyOn(telemetry, "capture").mockResolvedValue(undefined);
|
|
30
|
+
// Swallow the console.error from SSE logError on simulated failures.
|
|
31
|
+
errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
captureSpy.mockRestore();
|
|
36
|
+
errorSpy.mockRestore();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("fires agent_execution_stream_started once the observable factory resolves", async () => {
|
|
40
|
+
// Observable that never completes — only started should fire.
|
|
41
|
+
const never = new Observable<BaseEvent>(() => {});
|
|
42
|
+
createSseEventResponse({
|
|
43
|
+
request: makeRequest(),
|
|
44
|
+
observableFactory: () => never,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await vi.waitFor(() => {
|
|
48
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
49
|
+
"oss.runtime.agent_execution_stream_started",
|
|
50
|
+
{},
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(captureSpy).not.toHaveBeenCalledWith(
|
|
55
|
+
"oss.runtime.agent_execution_stream_errored",
|
|
56
|
+
expect.anything(),
|
|
57
|
+
);
|
|
58
|
+
expect(captureSpy).not.toHaveBeenCalledWith(
|
|
59
|
+
"oss.runtime.agent_execution_stream_ended",
|
|
60
|
+
expect.anything(),
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("fires agent_execution_stream_ended when the observable completes", async () => {
|
|
65
|
+
const completing = new Observable<BaseEvent>((subscriber) => {
|
|
66
|
+
subscriber.complete();
|
|
67
|
+
});
|
|
68
|
+
createSseEventResponse({
|
|
69
|
+
request: makeRequest(),
|
|
70
|
+
observableFactory: () => completing,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await vi.waitFor(() => {
|
|
74
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
75
|
+
"oss.runtime.agent_execution_stream_ended",
|
|
76
|
+
{},
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// started should also have fired before ended
|
|
81
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
82
|
+
"oss.runtime.agent_execution_stream_started",
|
|
83
|
+
{},
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("fires agent_execution_stream_errored with the error message when the observable errors", async () => {
|
|
88
|
+
const failing = new Observable<BaseEvent>((subscriber) => {
|
|
89
|
+
subscriber.error(new Error("stream blew up"));
|
|
90
|
+
});
|
|
91
|
+
createSseEventResponse({
|
|
92
|
+
request: makeRequest(),
|
|
93
|
+
observableFactory: () => failing,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await vi.waitFor(() => {
|
|
97
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
98
|
+
"oss.runtime.agent_execution_stream_errored",
|
|
99
|
+
expect.objectContaining({ error: "stream blew up" }),
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(captureSpy).toHaveBeenCalledWith(
|
|
104
|
+
"oss.runtime.agent_execution_stream_started",
|
|
105
|
+
{},
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -2,27 +2,15 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
2
2
|
import { TelemetryClient } from "../telemetry/telemetry-client";
|
|
3
3
|
import scarfClient from "../telemetry/scarf-client";
|
|
4
4
|
|
|
5
|
-
const { segmentTrackMock } = vi.hoisted(() => ({
|
|
6
|
-
segmentTrackMock: vi.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
vi.mock("@segment/analytics-node", () => ({
|
|
10
|
-
Analytics: vi.fn().mockImplementation(() => ({
|
|
11
|
-
track: segmentTrackMock,
|
|
12
|
-
})),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
5
|
describe("TelemetryClient", () => {
|
|
16
6
|
let scarfSpy: ReturnType<typeof vi.spyOn>;
|
|
17
7
|
|
|
18
8
|
beforeEach(() => {
|
|
19
9
|
scarfSpy = vi.spyOn(scarfClient, "logEvent").mockResolvedValue(undefined);
|
|
20
|
-
segmentTrackMock.mockClear();
|
|
21
10
|
});
|
|
22
11
|
|
|
23
12
|
afterEach(() => {
|
|
24
13
|
scarfSpy.mockRestore();
|
|
25
|
-
segmentTrackMock.mockClear();
|
|
26
14
|
});
|
|
27
15
|
|
|
28
16
|
it("sends event to scarf when sampled in", async () => {
|
|
@@ -44,33 +32,6 @@ describe("TelemetryClient", () => {
|
|
|
44
32
|
});
|
|
45
33
|
});
|
|
46
34
|
|
|
47
|
-
it("sends event with properties to segment when sampled in", async () => {
|
|
48
|
-
vi.spyOn(Math, "random").mockReturnValue(0);
|
|
49
|
-
const client = new TelemetryClient({
|
|
50
|
-
telemetryDisabled: false,
|
|
51
|
-
sampleRate: 1,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
await client.capture("oss.runtime.instance_created", {
|
|
55
|
-
actionsAmount: 5,
|
|
56
|
-
endpointTypes: ["rest"],
|
|
57
|
-
endpointsAmount: 2,
|
|
58
|
-
"cloud.api_key_provided": true,
|
|
59
|
-
"cloud.public_api_key": "pk_test_123",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(segmentTrackMock).toHaveBeenCalledTimes(1);
|
|
63
|
-
const call = segmentTrackMock.mock.calls[0][0];
|
|
64
|
-
expect(call.event).toBe("oss.runtime.instance_created");
|
|
65
|
-
expect(call.anonymousId).toMatch(/^anon_/);
|
|
66
|
-
expect(call.properties).toMatchObject({
|
|
67
|
-
actionsAmount: 5,
|
|
68
|
-
endpointsAmount: 2,
|
|
69
|
-
"cloud.api_key_provided": true,
|
|
70
|
-
"cloud.public_api_key": "pk_test_123",
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
35
|
it("only sends event name to scarf, not properties", async () => {
|
|
75
36
|
const client = new TelemetryClient({
|
|
76
37
|
telemetryDisabled: false,
|
|
@@ -106,7 +67,6 @@ describe("TelemetryClient", () => {
|
|
|
106
67
|
});
|
|
107
68
|
|
|
108
69
|
expect(scarfSpy).not.toHaveBeenCalled();
|
|
109
|
-
expect(segmentTrackMock).not.toHaveBeenCalled();
|
|
110
70
|
});
|
|
111
71
|
|
|
112
72
|
it("does not send events when sampled out", async () => {
|
|
@@ -124,7 +84,6 @@ describe("TelemetryClient", () => {
|
|
|
124
84
|
});
|
|
125
85
|
|
|
126
86
|
expect(scarfSpy).not.toHaveBeenCalled();
|
|
127
|
-
expect(segmentTrackMock).not.toHaveBeenCalled();
|
|
128
87
|
});
|
|
129
88
|
|
|
130
89
|
it("respects sample rate boundary", async () => {
|
|
@@ -139,26 +98,6 @@ describe("TelemetryClient", () => {
|
|
|
139
98
|
expect(scarfSpy).toHaveBeenCalled();
|
|
140
99
|
});
|
|
141
100
|
|
|
142
|
-
it("includes global properties in segment track call", async () => {
|
|
143
|
-
vi.spyOn(Math, "random").mockReturnValue(0);
|
|
144
|
-
const client = new TelemetryClient({
|
|
145
|
-
telemetryDisabled: false,
|
|
146
|
-
sampleRate: 1,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
client.setGlobalProperties({ "copilotkit.package.name": "test-pkg" });
|
|
150
|
-
|
|
151
|
-
await client.capture("oss.runtime.instance_created", {
|
|
152
|
-
actionsAmount: 1,
|
|
153
|
-
endpointTypes: [],
|
|
154
|
-
endpointsAmount: 0,
|
|
155
|
-
"cloud.api_key_provided": false,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const call = segmentTrackMock.mock.calls[0][0];
|
|
159
|
-
expect(call.properties["copilotkit.package.name"]).toBe("test-pkg");
|
|
160
|
-
});
|
|
161
|
-
|
|
162
101
|
it("throws when sample rate is out of range", () => {
|
|
163
102
|
expect(() => new TelemetryClient({ sampleRate: 1.5 })).toThrow(
|
|
164
103
|
"Sample rate must be between 0 and 1",
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { EventType } from "@ag-ui/client";
|
|
3
|
+
import type { BaseEvent } from "@ag-ui/client";
|
|
4
|
+
import type { DebugEventEnvelope } from "@copilotkit/shared";
|
|
5
|
+
import { DebugEventBus } from "../debug-event-bus";
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Helpers
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
function createBaseEvent(
|
|
12
|
+
overrides: Partial<BaseEvent> & { type: EventType } = {
|
|
13
|
+
type: EventType.RUN_STARTED,
|
|
14
|
+
},
|
|
15
|
+
): BaseEvent {
|
|
16
|
+
return { type: overrides.type, ...overrides };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const defaultMetadata = {
|
|
20
|
+
agentId: "test-agent",
|
|
21
|
+
threadId: "thread-1",
|
|
22
|
+
runId: "run-1",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Tests
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
describe("DebugEventBus", () => {
|
|
30
|
+
it("subscribe adds a listener and broadcast calls it with the correct envelope shape", () => {
|
|
31
|
+
const bus = new DebugEventBus();
|
|
32
|
+
const listener = vi.fn<[DebugEventEnvelope], void>();
|
|
33
|
+
const event = createBaseEvent({ type: EventType.RUN_STARTED });
|
|
34
|
+
|
|
35
|
+
bus.subscribe(listener);
|
|
36
|
+
bus.broadcast(event, defaultMetadata);
|
|
37
|
+
|
|
38
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
39
|
+
const envelope = listener.mock.calls[0][0];
|
|
40
|
+
expect(envelope).toEqual(
|
|
41
|
+
expect.objectContaining({
|
|
42
|
+
agentId: "test-agent",
|
|
43
|
+
threadId: "thread-1",
|
|
44
|
+
runId: "run-1",
|
|
45
|
+
event,
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
expect(typeof envelope.timestamp).toBe("number");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("unsubscribe removes the listener so subsequent broadcasts don't reach it", () => {
|
|
52
|
+
const bus = new DebugEventBus();
|
|
53
|
+
const listener = vi.fn<[DebugEventEnvelope], void>();
|
|
54
|
+
const event = createBaseEvent();
|
|
55
|
+
|
|
56
|
+
const unsub = bus.subscribe(listener);
|
|
57
|
+
unsub();
|
|
58
|
+
bus.broadcast(event, defaultMetadata);
|
|
59
|
+
|
|
60
|
+
expect(listener).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("multiple listeners all receive the same broadcast", () => {
|
|
64
|
+
const bus = new DebugEventBus();
|
|
65
|
+
const listenerA = vi.fn<[DebugEventEnvelope], void>();
|
|
66
|
+
const listenerB = vi.fn<[DebugEventEnvelope], void>();
|
|
67
|
+
const event = createBaseEvent();
|
|
68
|
+
|
|
69
|
+
bus.subscribe(listenerA);
|
|
70
|
+
bus.subscribe(listenerB);
|
|
71
|
+
bus.broadcast(event, defaultMetadata);
|
|
72
|
+
|
|
73
|
+
expect(listenerA).toHaveBeenCalledOnce();
|
|
74
|
+
expect(listenerB).toHaveBeenCalledOnce();
|
|
75
|
+
// Both receive the same envelope object
|
|
76
|
+
expect(listenerA.mock.calls[0][0]).toBe(listenerB.mock.calls[0][0]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("listener errors are swallowed and other listeners still receive the event", () => {
|
|
80
|
+
const bus = new DebugEventBus();
|
|
81
|
+
const failingListener = vi
|
|
82
|
+
.fn<[DebugEventEnvelope], void>()
|
|
83
|
+
.mockImplementation(() => {
|
|
84
|
+
throw new Error("boom");
|
|
85
|
+
});
|
|
86
|
+
const healthyListener = vi.fn<[DebugEventEnvelope], void>();
|
|
87
|
+
const event = createBaseEvent();
|
|
88
|
+
|
|
89
|
+
bus.subscribe(failingListener);
|
|
90
|
+
bus.subscribe(healthyListener);
|
|
91
|
+
|
|
92
|
+
// Should not throw
|
|
93
|
+
expect(() => bus.broadcast(event, defaultMetadata)).not.toThrow();
|
|
94
|
+
expect(failingListener).toHaveBeenCalledOnce();
|
|
95
|
+
expect(healthyListener).toHaveBeenCalledOnce();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("broadcasting with no listeners does not throw", () => {
|
|
99
|
+
const bus = new DebugEventBus();
|
|
100
|
+
const event = createBaseEvent();
|
|
101
|
+
|
|
102
|
+
expect(() => bus.broadcast(event, defaultMetadata)).not.toThrow();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("listenerCount reflects current count after subscribe and unsubscribe", () => {
|
|
106
|
+
const bus = new DebugEventBus();
|
|
107
|
+
|
|
108
|
+
expect(bus.listenerCount).toBe(0);
|
|
109
|
+
|
|
110
|
+
const unsub1 = bus.subscribe(vi.fn());
|
|
111
|
+
expect(bus.listenerCount).toBe(1);
|
|
112
|
+
|
|
113
|
+
const unsub2 = bus.subscribe(vi.fn());
|
|
114
|
+
expect(bus.listenerCount).toBe(2);
|
|
115
|
+
|
|
116
|
+
unsub1();
|
|
117
|
+
expect(bus.listenerCount).toBe(1);
|
|
118
|
+
|
|
119
|
+
unsub2();
|
|
120
|
+
expect(bus.listenerCount).toBe(0);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("envelope has correct timestamp, agentId, threadId, runId, and the original event", () => {
|
|
124
|
+
const bus = new DebugEventBus();
|
|
125
|
+
const listener = vi.fn<[DebugEventEnvelope], void>();
|
|
126
|
+
const event = createBaseEvent({ type: EventType.STEP_STARTED });
|
|
127
|
+
const metadata = { agentId: "agent-x", threadId: "t-42", runId: "r-99" };
|
|
128
|
+
|
|
129
|
+
const before = Date.now();
|
|
130
|
+
bus.subscribe(listener);
|
|
131
|
+
bus.broadcast(event, metadata);
|
|
132
|
+
const after = Date.now();
|
|
133
|
+
|
|
134
|
+
const envelope = listener.mock.calls[0][0];
|
|
135
|
+
expect(envelope.agentId).toBe("agent-x");
|
|
136
|
+
expect(envelope.threadId).toBe("t-42");
|
|
137
|
+
expect(envelope.runId).toBe("r-99");
|
|
138
|
+
expect(envelope.event).toBe(event);
|
|
139
|
+
expect(envelope.timestamp).toBeGreaterThanOrEqual(before);
|
|
140
|
+
expect(envelope.timestamp).toBeLessThanOrEqual(after);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("RUN_STARTED event type passthrough: envelope.event is the original object, not a copy", () => {
|
|
144
|
+
const bus = new DebugEventBus();
|
|
145
|
+
const listener = vi.fn<[DebugEventEnvelope], void>();
|
|
146
|
+
const event = createBaseEvent({ type: EventType.RUN_STARTED });
|
|
147
|
+
|
|
148
|
+
bus.subscribe(listener);
|
|
149
|
+
bus.broadcast(event, defaultMetadata);
|
|
150
|
+
|
|
151
|
+
const envelope = listener.mock.calls[0][0];
|
|
152
|
+
// Strict referential equality — the event is passed through, not cloned
|
|
153
|
+
expect(envelope.event).toBe(event);
|
|
154
|
+
expect(envelope.event.type).toBe(EventType.RUN_STARTED);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseEvent } from "@ag-ui/client";
|
|
2
|
+
import { DebugEventEnvelope } from "@copilotkit/shared";
|
|
3
|
+
|
|
4
|
+
export type DebugEventListener = (envelope: DebugEventEnvelope) => void;
|
|
5
|
+
|
|
6
|
+
export class DebugEventBus {
|
|
7
|
+
private listeners = new Set<DebugEventListener>();
|
|
8
|
+
|
|
9
|
+
subscribe(listener: DebugEventListener): () => void {
|
|
10
|
+
this.listeners.add(listener);
|
|
11
|
+
return () => {
|
|
12
|
+
this.listeners.delete(listener);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
broadcast(
|
|
17
|
+
event: BaseEvent,
|
|
18
|
+
metadata: { agentId: string; threadId: string; runId: string },
|
|
19
|
+
): void {
|
|
20
|
+
if (this.listeners.size === 0) return;
|
|
21
|
+
|
|
22
|
+
const envelope: DebugEventEnvelope = {
|
|
23
|
+
timestamp: Date.now(),
|
|
24
|
+
agentId: metadata.agentId,
|
|
25
|
+
threadId: metadata.threadId,
|
|
26
|
+
runId: metadata.runId,
|
|
27
|
+
event,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
for (const listener of this.listeners) {
|
|
31
|
+
try {
|
|
32
|
+
listener(envelope);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.warn(
|
|
35
|
+
"[DebugEventBus] Listener error suppressed:",
|
|
36
|
+
err instanceof Error ? err.message : err,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get listenerCount(): number {
|
|
43
|
+
return this.listeners.size;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -46,6 +46,7 @@ import { handleConnectAgent } from "../handlers/handle-connect";
|
|
|
46
46
|
import { handleStopAgent } from "../handlers/handle-stop";
|
|
47
47
|
import { handleGetRuntimeInfo } from "../handlers/get-runtime-info";
|
|
48
48
|
import { handleTranscribe } from "../handlers/handle-transcribe";
|
|
49
|
+
import { handleDebugEvents } from "../handlers/handle-debug-events";
|
|
49
50
|
import {
|
|
50
51
|
handleListThreads,
|
|
51
52
|
handleSubscribeToThreads,
|
|
@@ -61,6 +62,7 @@ import {
|
|
|
61
62
|
type MethodCall,
|
|
62
63
|
} from "../endpoints/single-route-helpers";
|
|
63
64
|
import { logger } from "@copilotkit/shared";
|
|
65
|
+
import { fireInstanceCreatedTelemetry } from "../telemetry/instance-created";
|
|
64
66
|
|
|
65
67
|
/* ------------------------------------------------------------------------------------------------
|
|
66
68
|
* Public types
|
|
@@ -113,6 +115,8 @@ export function createCopilotRuntimeHandler(
|
|
|
113
115
|
): CopilotRuntimeFetchHandler {
|
|
114
116
|
const { runtime, basePath, mode = "multi-route", cors, hooks } = options;
|
|
115
117
|
|
|
118
|
+
fireInstanceCreatedTelemetry({ runtime });
|
|
119
|
+
|
|
116
120
|
const corsConfig = resolveCorsConfig(cors);
|
|
117
121
|
|
|
118
122
|
return async (request: Request): Promise<Response> => {
|
|
@@ -339,6 +343,8 @@ function dispatchRoute(
|
|
|
339
343
|
request,
|
|
340
344
|
threadId: route.threadId,
|
|
341
345
|
});
|
|
346
|
+
case "cpk-debug-events":
|
|
347
|
+
return Promise.resolve(handleDebugEvents({ runtime, request }));
|
|
342
348
|
}
|
|
343
349
|
}
|
|
344
350
|
|
|
@@ -414,6 +420,7 @@ function validateHttpMethod(
|
|
|
414
420
|
case "info":
|
|
415
421
|
case "threads/list":
|
|
416
422
|
case "threads/messages":
|
|
423
|
+
case "cpk-debug-events":
|
|
417
424
|
if (method === "GET") return null;
|
|
418
425
|
return jsonResponse({ error: "Method not allowed" }, 405, {
|
|
419
426
|
Allow: "GET",
|
|
@@ -74,6 +74,17 @@ function matchSegments(path: string): RouteInfo | null {
|
|
|
74
74
|
return { method: "transcribe" };
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// /cpk-debug-events (1 segment)
|
|
78
|
+
// Reserved route name: the `cpk-` prefix makes collision with a
|
|
79
|
+
// user-named agent essentially impossible (the router only treats
|
|
80
|
+
// `agent/:agentId/...` patterns as agent lookups, so a bare
|
|
81
|
+
// `cpk-debug-events` segment would never fall through to one —
|
|
82
|
+
// the prefix is the real guard, not this branch's position).
|
|
83
|
+
// Handler returns 404 in production.
|
|
84
|
+
if (len >= 1 && segments[len - 1] === "cpk-debug-events") {
|
|
85
|
+
return { method: "cpk-debug-events" };
|
|
86
|
+
}
|
|
87
|
+
|
|
77
88
|
// /agent/:agentId/run (3 segments)
|
|
78
89
|
if (
|
|
79
90
|
len >= 3 &&
|
|
@@ -43,7 +43,8 @@ export type RouteInfo =
|
|
|
43
43
|
| { method: "threads/subscribe" }
|
|
44
44
|
| { method: "threads/update"; threadId: string }
|
|
45
45
|
| { method: "threads/archive"; threadId: string }
|
|
46
|
-
| { method: "threads/messages"; threadId: string }
|
|
46
|
+
| { method: "threads/messages"; threadId: string }
|
|
47
|
+
| { method: "cpk-debug-events" };
|
|
47
48
|
|
|
48
49
|
/* ------------------------------------------------------------------------------------------------
|
|
49
50
|
* Hook contexts
|