@copilotkit/runtime 1.56.0 → 1.56.2-canary.pin-to-send
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 +2 -2
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +2 -2
- package/dist/agent/index.mjs.map +1 -1
- 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/integrations/node-http/index.cjs +4 -1
- package/dist/lib/integrations/node-http/index.cjs.map +1 -1
- package/dist/lib/integrations/node-http/index.d.cts.map +1 -1
- package/dist/lib/integrations/node-http/index.d.mts.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +4 -1
- package/dist/lib/integrations/node-http/index.mjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +15 -3
- 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 +15 -3
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.cjs +21 -4
- package/dist/lib/runtime/mcp-tools-utils.cjs.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.d.cts.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.d.mts.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.mjs +21 -4
- package/dist/lib/runtime/mcp-tools-utils.mjs.map +1 -1
- package/dist/package.cjs +2 -2
- package/dist/package.mjs +2 -2
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs +11 -3
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts +6 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +6 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs +11 -3
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs.map +1 -1
- package/dist/service-adapters/anthropic/utils.cjs +27 -1
- package/dist/service-adapters/anthropic/utils.cjs.map +1 -1
- package/dist/service-adapters/anthropic/utils.mjs +27 -1
- package/dist/service-adapters/anthropic/utils.mjs.map +1 -1
- package/dist/service-adapters/langchain/utils.cjs +1 -1
- package/dist/service-adapters/langchain/utils.cjs.map +1 -1
- package/dist/service-adapters/langchain/utils.mjs +1 -1
- package/dist/service-adapters/langchain/utils.mjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.cjs +2 -1
- package/dist/service-adapters/openai/openai-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.cts +6 -0
- package/dist/service-adapters/openai/openai-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.mts +6 -0
- package/dist/service-adapters/openai/openai-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.mjs +2 -1
- package/dist/service-adapters/openai/openai-adapter.mjs.map +1 -1
- 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 +6 -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 +6 -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/middleware-sse-parser.cjs +5 -2
- package/dist/v2/runtime/core/middleware-sse-parser.cjs.map +1 -1
- package/dist/v2/runtime/core/middleware-sse-parser.mjs +5 -2
- package/dist/v2/runtime/core/middleware-sse-parser.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 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +5 -0
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +2 -0
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +2 -0
- 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 +32 -2
- package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/connect.mjs +31 -2
- package/dist/v2/runtime/handlers/intelligence/connect.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/intelligence-platform/client.cjs +2 -7
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +1 -4
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +1 -4
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +2 -7
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs +17 -5
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts +1 -0
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts +1 -0
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs +17 -5
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/package.json +3 -3
- package/src/agent/__tests__/provider-id-collision.test.ts +195 -0
- package/src/agent/index.ts +19 -11
- 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/integrations/node-http/__tests__/request-duck-type.test.ts +66 -0
- package/src/lib/integrations/node-http/index.ts +15 -1
- package/src/lib/runtime/__tests__/handle-service-adapter.test.ts +108 -0
- package/src/lib/runtime/__tests__/mcp-tools-utils.test.ts +30 -1
- package/src/lib/runtime/__tests__/on-after-request.test.ts +122 -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 +36 -7
- package/src/lib/runtime/mcp-tools-utils.ts +41 -6
- package/src/lib/runtime/retry-utils.ts +41 -1
- package/src/service-adapters/anthropic/anthropic-adapter.ts +22 -2
- package/src/service-adapters/anthropic/utils.ts +60 -1
- package/src/service-adapters/langchain/utils.ts +1 -1
- package/src/service-adapters/openai/openai-adapter.ts +14 -1
- package/src/v2/runtime/__tests__/fetch-router.test.ts +22 -0
- package/src/v2/runtime/__tests__/handle-connect.test.ts +58 -5
- package/src/v2/runtime/__tests__/handle-run.test.ts +31 -4
- package/src/v2/runtime/__tests__/handle-threads.test.ts +66 -4
- 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__/middleware-sse-parser.test.ts +50 -0
- package/src/v2/runtime/__tests__/runtime.test.ts +3 -1
- 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 +4 -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/middleware-sse-parser.ts +12 -2
- 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 -0
- 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 +58 -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 +13 -11
- package/src/v2/runtime/intelligence-platform/client.ts +3 -11
- package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +51 -1
- package/src/v2/runtime/runner/intelligence.ts +27 -9
- package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +268 -0
- package/tests/service-adapters/anthropic/utils-token-trimming.test.ts +301 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
2
|
+
import type { ServerHandle } from "../servers/types";
|
|
3
|
+
import { readSSEStream } from "../helpers/sse-reader";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Envelope shape returned in the debug SSE stream.
|
|
7
|
+
*/
|
|
8
|
+
interface DebugEnvelope {
|
|
9
|
+
timestamp: number;
|
|
10
|
+
agentId: string;
|
|
11
|
+
threadId: string;
|
|
12
|
+
runId: string;
|
|
13
|
+
event: { type: string; [key: string]: unknown };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Parse debug envelopes from SSE payload text.
|
|
18
|
+
* Each `data:` line contains a JSON DebugEventEnvelope.
|
|
19
|
+
*/
|
|
20
|
+
function parseDebugEnvelopes(ssePayload: string): DebugEnvelope[] {
|
|
21
|
+
const envelopes: DebugEnvelope[] = [];
|
|
22
|
+
for (const line of ssePayload.split("\n")) {
|
|
23
|
+
if (!line.startsWith("data:")) continue;
|
|
24
|
+
const json = line.slice("data:".length).trim();
|
|
25
|
+
if (!json) continue;
|
|
26
|
+
try {
|
|
27
|
+
envelopes.push(JSON.parse(json));
|
|
28
|
+
} catch {
|
|
29
|
+
// skip malformed lines
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return envelopes;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read from a long-lived debug SSE stream until we see a RUN_FINISHED envelope
|
|
37
|
+
* or a timeout elapses. Returns the raw text accumulated.
|
|
38
|
+
*
|
|
39
|
+
* IMPORTANT: The debug SSE stream is long-lived and never closes on its own.
|
|
40
|
+
* We MUST use a timeout to stop reading, and cancel the reader afterwards.
|
|
41
|
+
*/
|
|
42
|
+
async function readDebugStream(
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
stream: ReadableStream<any>,
|
|
45
|
+
opts: { waitMs?: number } = {},
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
const waitMs = opts.waitMs ?? 4_000;
|
|
48
|
+
const reader = stream.getReader();
|
|
49
|
+
const decoder = new TextDecoder();
|
|
50
|
+
let output = "";
|
|
51
|
+
let stopped = false;
|
|
52
|
+
|
|
53
|
+
const timer = setTimeout(() => {
|
|
54
|
+
stopped = true;
|
|
55
|
+
reader.cancel().catch(() => {});
|
|
56
|
+
}, waitMs);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
while (!stopped) {
|
|
60
|
+
const result = await reader.read().catch(() => ({
|
|
61
|
+
done: true as const,
|
|
62
|
+
value: undefined,
|
|
63
|
+
}));
|
|
64
|
+
if (result.done) break;
|
|
65
|
+
if (result.value) {
|
|
66
|
+
output +=
|
|
67
|
+
typeof result.value === "string"
|
|
68
|
+
? result.value
|
|
69
|
+
: decoder.decode(result.value as Uint8Array, { stream: true });
|
|
70
|
+
if (output.includes("RUN_FINISHED")) {
|
|
71
|
+
stopped = true;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
clearTimeout(timer);
|
|
78
|
+
// Do NOT await reader.cancel() — on tee'd streams (created by response.clone()
|
|
79
|
+
// inside the fetch handler), awaiting cancel hangs indefinitely because the
|
|
80
|
+
// other tee branch is never consumed.
|
|
81
|
+
reader.cancel().catch(() => {});
|
|
82
|
+
output += decoder.decode();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return output;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Shared debug-events integration test suite.
|
|
90
|
+
*
|
|
91
|
+
* @param name Display name, e.g. "Express"
|
|
92
|
+
* @param factory Creates & starts the server; returns a handle
|
|
93
|
+
*/
|
|
94
|
+
export function debugEventsSuite(
|
|
95
|
+
name: string,
|
|
96
|
+
factory: (opts?: {
|
|
97
|
+
capturedHeaders?: Record<string, string>[];
|
|
98
|
+
}) => Promise<ServerHandle & { handler?: (r: Request) => Promise<Response> }>,
|
|
99
|
+
) {
|
|
100
|
+
describe(`[${name}] Debug Events`, () => {
|
|
101
|
+
let handle: ServerHandle & { handler?: (r: Request) => Promise<Response> };
|
|
102
|
+
let doFetch: (
|
|
103
|
+
input: RequestInfo | URL,
|
|
104
|
+
init?: RequestInit,
|
|
105
|
+
) => Promise<Response>;
|
|
106
|
+
|
|
107
|
+
beforeAll(async () => {
|
|
108
|
+
handle = await factory();
|
|
109
|
+
doFetch = handle.handler
|
|
110
|
+
? (input, init) =>
|
|
111
|
+
handle.handler!(
|
|
112
|
+
new Request(
|
|
113
|
+
typeof input === "string" || input instanceof URL
|
|
114
|
+
? input
|
|
115
|
+
: input,
|
|
116
|
+
init,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
: fetch;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
afterAll(async () => {
|
|
123
|
+
await handle?.close();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const url = (path: string) => `${handle.baseUrl}${handle.basePath}${path}`;
|
|
127
|
+
|
|
128
|
+
// ─── SSE Format + Events + Envelope Structure ────────────────────
|
|
129
|
+
// Combined into a single test to avoid orphaned debug-stream subscribers
|
|
130
|
+
// across tests (the debug SSE endpoint is long-lived and its cleanup
|
|
131
|
+
// depends on the request signal being aborted).
|
|
132
|
+
|
|
133
|
+
it("streams debug event envelopes with correct structure during an agent run", async () => {
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
|
|
136
|
+
// Start the debug stream. For real HTTP servers, fetch blocks until
|
|
137
|
+
// the first chunk arrives, so we also start the agent run concurrently.
|
|
138
|
+
const debugFetchPromise = doFetch(url("/cpk-debug-events"), {
|
|
139
|
+
signal: controller.signal,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Give the subscription a tick to register
|
|
143
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
144
|
+
|
|
145
|
+
// Trigger an agent run. We start it AND begin consuming its stream
|
|
146
|
+
// concurrently with reading the debug stream.
|
|
147
|
+
const runRes = await doFetch(url("/agent/default/run"), {
|
|
148
|
+
method: "POST",
|
|
149
|
+
headers: { "Content-Type": "application/json" },
|
|
150
|
+
body: JSON.stringify({
|
|
151
|
+
threadId: "t-debug-1",
|
|
152
|
+
runId: "r-debug-1",
|
|
153
|
+
messages: [],
|
|
154
|
+
state: {},
|
|
155
|
+
tools: [],
|
|
156
|
+
context: [],
|
|
157
|
+
forwardedProps: {},
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Consume the run stream and the debug stream concurrently.
|
|
162
|
+
// Both are needed: the debug stream blocks until events arrive,
|
|
163
|
+
// and the run stream must be consumed to avoid backpressure.
|
|
164
|
+
const [debugRes, runPayload] = await Promise.all([
|
|
165
|
+
debugFetchPromise,
|
|
166
|
+
readSSEStream(runRes.body!),
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
// ── SSE response format ──
|
|
170
|
+
expect(debugRes.status).toBe(200);
|
|
171
|
+
expect(debugRes.headers.get("content-type")).toContain(
|
|
172
|
+
"text/event-stream",
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Run completed — events should be buffered in the debug stream.
|
|
176
|
+
expect(runPayload).toContain("RUN_FINISHED");
|
|
177
|
+
|
|
178
|
+
// Read the debug stream (events are already in the buffer)
|
|
179
|
+
const debugPayload = await readDebugStream(debugRes.body!, {
|
|
180
|
+
waitMs: 4_000,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const envelopes = parseDebugEnvelopes(debugPayload);
|
|
184
|
+
|
|
185
|
+
// ── Events flow through ──
|
|
186
|
+
expect(envelopes.length).toBeGreaterThan(0);
|
|
187
|
+
|
|
188
|
+
const eventTypes = envelopes.map((e) => e.event.type);
|
|
189
|
+
expect(eventTypes).toContain("RUN_STARTED");
|
|
190
|
+
expect(eventTypes).toContain("RUN_FINISHED");
|
|
191
|
+
|
|
192
|
+
// ── Envelope structure ──
|
|
193
|
+
for (const envelope of envelopes) {
|
|
194
|
+
expect(typeof envelope.timestamp).toBe("number");
|
|
195
|
+
expect(envelope.timestamp).toBeGreaterThan(0);
|
|
196
|
+
expect(envelope.agentId).toBe("default");
|
|
197
|
+
expect(typeof envelope.threadId).toBe("string");
|
|
198
|
+
expect(typeof envelope.runId).toBe("string");
|
|
199
|
+
expect(envelope.event).toBeDefined();
|
|
200
|
+
expect(typeof envelope.event.type).toBe("string");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Full event sequence
|
|
204
|
+
expect(eventTypes).toContain("TEXT_MESSAGE_START");
|
|
205
|
+
expect(eventTypes).toContain("TEXT_MESSAGE_CONTENT");
|
|
206
|
+
expect(eventTypes).toContain("TEXT_MESSAGE_END");
|
|
207
|
+
|
|
208
|
+
// Clean up: abort the request so the debug subscriber is removed
|
|
209
|
+
controller.abort();
|
|
210
|
+
}, 15_000);
|
|
211
|
+
|
|
212
|
+
// Regression guard for agentId forwarding on /connect lives in a
|
|
213
|
+
// dedicated unit test (sse-connect-agent-id.test.ts) — driving /connect
|
|
214
|
+
// through the integration runtime doesn't emit events in a
|
|
215
|
+
// test-friendly way, so the unit test feeds a synthetic observable
|
|
216
|
+
// into handleSseConnect and asserts the envelope carries the route
|
|
217
|
+
// agentId rather than the literal string "connect".
|
|
218
|
+
|
|
219
|
+
// ─── HTTP Method Validation ──────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
it("POST /cpk-debug-events returns 405", async () => {
|
|
222
|
+
const res = await doFetch(url("/cpk-debug-events"), { method: "POST" });
|
|
223
|
+
expect(res.status).toBe(405);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Production guard test -- only needs the fetch-direct handler since
|
|
230
|
+
* it doesn't require a real server. Tests that NODE_ENV=production
|
|
231
|
+
* returns 404 for the debug-events endpoint.
|
|
232
|
+
*/
|
|
233
|
+
export function debugEventsProductionGuardSuite(
|
|
234
|
+
createHandler: () => { handler: (r: Request) => Promise<Response> },
|
|
235
|
+
baseUrl: string,
|
|
236
|
+
basePath: string,
|
|
237
|
+
) {
|
|
238
|
+
describe("[Fetch] Debug Events – production guard", () => {
|
|
239
|
+
it("returns 404 when NODE_ENV=production", async () => {
|
|
240
|
+
const originalEnv = process.env.NODE_ENV;
|
|
241
|
+
try {
|
|
242
|
+
process.env.NODE_ENV = "production";
|
|
243
|
+
const { handler } = createHandler();
|
|
244
|
+
const res = await handler(
|
|
245
|
+
new Request(`${baseUrl}${basePath}/cpk-debug-events`),
|
|
246
|
+
);
|
|
247
|
+
expect(res.status).toBe(404);
|
|
248
|
+
} finally {
|
|
249
|
+
process.env.NODE_ENV = originalEnv;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
@@ -83,6 +83,56 @@ describe("parseSSEResponse", () => {
|
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
it("normalizes array content in TOOL_CALL_RESULT (MCP adapters)", async () => {
|
|
87
|
+
const response = buildSSEResponse([
|
|
88
|
+
{ type: "RUN_STARTED", threadId: "t-1", runId: "r-1" },
|
|
89
|
+
{
|
|
90
|
+
type: "TOOL_CALL_RESULT",
|
|
91
|
+
toolCallId: "tc-1",
|
|
92
|
+
messageId: "m-result",
|
|
93
|
+
role: "tool",
|
|
94
|
+
content: [
|
|
95
|
+
{ type: "text", text: '{"metric":"cpu","value":42}' },
|
|
96
|
+
{ type: "text", text: " extra info" },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{ type: "RUN_FINISHED", threadId: "t-1", runId: "r-1" },
|
|
100
|
+
]);
|
|
101
|
+
const result = await parseSSEResponse(response);
|
|
102
|
+
expect(result.messages).toContainEqual({
|
|
103
|
+
id: "m-result",
|
|
104
|
+
role: "tool",
|
|
105
|
+
content: '{"metric":"cpu","value":42} extra info',
|
|
106
|
+
toolCallId: "tc-1",
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("filters non-text parts when normalizing array content in TOOL_CALL_RESULT", async () => {
|
|
111
|
+
const response = buildSSEResponse([
|
|
112
|
+
{ type: "RUN_STARTED", threadId: "t-1", runId: "r-1" },
|
|
113
|
+
{
|
|
114
|
+
type: "TOOL_CALL_RESULT",
|
|
115
|
+
toolCallId: "tc-1",
|
|
116
|
+
messageId: "m-result",
|
|
117
|
+
role: "tool",
|
|
118
|
+
content: [
|
|
119
|
+
{ type: "text", text: "valid" },
|
|
120
|
+
{ type: "image", data: "binary" },
|
|
121
|
+
null,
|
|
122
|
+
{ type: "text", text: " part" },
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
{ type: "RUN_FINISHED", threadId: "t-1", runId: "r-1" },
|
|
126
|
+
]);
|
|
127
|
+
const result = await parseSSEResponse(response);
|
|
128
|
+
expect(result.messages).toContainEqual({
|
|
129
|
+
id: "m-result",
|
|
130
|
+
role: "tool",
|
|
131
|
+
content: "valid part",
|
|
132
|
+
toolCallId: "tc-1",
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
86
136
|
it("uses MESSAGES_SNAPSHOT when present", async () => {
|
|
87
137
|
const snapshotMessages = [
|
|
88
138
|
{ id: "u-1", role: "user", content: "hi" },
|
|
@@ -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,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,
|
|
@@ -339,6 +340,8 @@ function dispatchRoute(
|
|
|
339
340
|
request,
|
|
340
341
|
threadId: route.threadId,
|
|
341
342
|
});
|
|
343
|
+
case "cpk-debug-events":
|
|
344
|
+
return Promise.resolve(handleDebugEvents({ runtime, request }));
|
|
342
345
|
}
|
|
343
346
|
}
|
|
344
347
|
|
|
@@ -414,6 +417,7 @@ function validateHttpMethod(
|
|
|
414
417
|
case "info":
|
|
415
418
|
case "threads/list":
|
|
416
419
|
case "threads/messages":
|
|
420
|
+
case "cpk-debug-events":
|
|
417
421
|
if (method === "GET") return null;
|
|
418
422
|
return jsonResponse({ error: "Method not allowed" }, 405, {
|
|
419
423
|
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
|
|
@@ -167,14 +167,24 @@ export async function parseSSEResponse(
|
|
|
167
167
|
break;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
case "TOOL_CALL_RESULT":
|
|
170
|
+
case "TOOL_CALL_RESULT": {
|
|
171
|
+
// langchain-mcp-adapters may send content as an array of
|
|
172
|
+
// {type:"text", text:string} objects instead of a plain string.
|
|
173
|
+
let resultContent = event.content;
|
|
174
|
+
if (Array.isArray(resultContent)) {
|
|
175
|
+
resultContent = resultContent
|
|
176
|
+
.filter((part: any) => part && typeof part.text === "string")
|
|
177
|
+
.map((part: any) => part.text)
|
|
178
|
+
.join("");
|
|
179
|
+
}
|
|
171
180
|
messagesById.set(event.messageId, {
|
|
172
181
|
id: event.messageId,
|
|
173
182
|
role: "tool",
|
|
174
|
-
content:
|
|
183
|
+
content: resultContent,
|
|
175
184
|
toolCallId: event.toolCallId,
|
|
176
185
|
});
|
|
177
186
|
break;
|
|
187
|
+
}
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
} from "./middleware";
|
|
25
25
|
import { createLogger, type CopilotRuntimeLogger } from "../../../lib/logger";
|
|
26
26
|
import { TranscriptionService } from "../transcription-service/transcription-service";
|
|
27
|
+
import { DebugEventBus } from "./debug-event-bus";
|
|
27
28
|
import { AgentRunner } from "../runner/agent-runner";
|
|
28
29
|
import { InMemoryAgentRunner } from "../runner/in-memory";
|
|
29
30
|
import { IntelligenceAgentRunner } from "../runner/intelligence";
|
|
@@ -140,6 +141,7 @@ interface BaseCopilotRuntimeOptions extends CopilotRuntimeMiddlewares {
|
|
|
140
141
|
|
|
141
142
|
export interface CopilotRuntimeUser {
|
|
142
143
|
id: string;
|
|
144
|
+
name: string;
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
export type IdentifyUserCallback = (
|
|
@@ -189,6 +191,7 @@ export interface CopilotRuntimeLike {
|
|
|
189
191
|
identifyUser?: IdentifyUserCallback;
|
|
190
192
|
mode: RuntimeMode;
|
|
191
193
|
licenseChecker?: LicenseChecker;
|
|
194
|
+
debugEventBus?: DebugEventBus;
|
|
192
195
|
debug: ResolvedDebugConfig;
|
|
193
196
|
debugLogger?: CopilotRuntimeLogger;
|
|
194
197
|
}
|
|
@@ -218,6 +221,7 @@ abstract class BaseCopilotRuntime implements CopilotRuntimeLike {
|
|
|
218
221
|
public mcpApps: CopilotRuntimeOptions["mcpApps"];
|
|
219
222
|
public openGenerativeUI: CopilotRuntimeOptions["openGenerativeUI"];
|
|
220
223
|
public licenseChecker?: LicenseChecker;
|
|
224
|
+
public readonly debugEventBus?: DebugEventBus;
|
|
221
225
|
public debug: ResolvedDebugConfig;
|
|
222
226
|
public debugLogger?: CopilotRuntimeLogger;
|
|
223
227
|
|
|
@@ -243,6 +247,10 @@ abstract class BaseCopilotRuntime implements CopilotRuntimeLike {
|
|
|
243
247
|
this.mcpApps = mcpApps;
|
|
244
248
|
this.openGenerativeUI = openGenerativeUI;
|
|
245
249
|
this.runner = runner;
|
|
250
|
+
|
|
251
|
+
if (process.env.NODE_ENV !== "production") {
|
|
252
|
+
this.debugEventBus = new DebugEventBus();
|
|
253
|
+
}
|
|
246
254
|
this.debug = resolveDebugConfig(options.debug);
|
|
247
255
|
if (this.debug.enabled) {
|
|
248
256
|
this.debugLogger = createLogger({
|
|
@@ -407,6 +415,10 @@ export class CopilotRuntime implements CopilotRuntimeLike {
|
|
|
407
415
|
return this.delegate.licenseChecker;
|
|
408
416
|
}
|
|
409
417
|
|
|
418
|
+
get debugEventBus() {
|
|
419
|
+
return this.delegate.debugEventBus;
|
|
420
|
+
}
|
|
421
|
+
|
|
410
422
|
get debug(): ResolvedDebugConfig {
|
|
411
423
|
return this.delegate.debug;
|
|
412
424
|
}
|