@copilotkit/runtime 1.56.2 → 1.56.4-canary.1777529757

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.
Files changed (203) hide show
  1. package/dist/agent/converters/tanstack.cjs +121 -25
  2. package/dist/agent/converters/tanstack.cjs.map +1 -1
  3. package/dist/agent/converters/tanstack.d.cts.map +1 -1
  4. package/dist/agent/converters/tanstack.d.mts.map +1 -1
  5. package/dist/agent/converters/tanstack.mjs +121 -25
  6. package/dist/agent/converters/tanstack.mjs.map +1 -1
  7. package/dist/graphql/resolvers/copilot.resolver.cjs +2 -1
  8. package/dist/graphql/resolvers/copilot.resolver.cjs.map +1 -1
  9. package/dist/graphql/resolvers/copilot.resolver.mjs +2 -1
  10. package/dist/graphql/resolvers/copilot.resolver.mjs.map +1 -1
  11. package/dist/graphql/resolvers/resolve-message-id.cjs +19 -0
  12. package/dist/graphql/resolvers/resolve-message-id.cjs.map +1 -0
  13. package/dist/graphql/resolvers/resolve-message-id.mjs +18 -0
  14. package/dist/graphql/resolvers/resolve-message-id.mjs.map +1 -0
  15. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs +8 -1
  16. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs.map +1 -1
  17. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
  18. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
  19. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +8 -1
  20. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs.map +1 -1
  21. package/dist/lib/runtime/copilot-runtime.cjs +4 -2
  22. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  23. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  24. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  25. package/dist/lib/runtime/copilot-runtime.mjs +4 -2
  26. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  27. package/dist/package.cjs +7 -7
  28. package/dist/package.mjs +7 -7
  29. package/dist/v2/index.d.cts +2 -2
  30. package/dist/v2/index.d.mts +2 -2
  31. package/dist/v2/runtime/core/debug-event-bus.cjs +36 -0
  32. package/dist/v2/runtime/core/debug-event-bus.cjs.map +1 -0
  33. package/dist/v2/runtime/core/debug-event-bus.d.cts +19 -0
  34. package/dist/v2/runtime/core/debug-event-bus.d.cts.map +1 -0
  35. package/dist/v2/runtime/core/debug-event-bus.d.mts +19 -0
  36. package/dist/v2/runtime/core/debug-event-bus.d.mts.map +1 -0
  37. package/dist/v2/runtime/core/debug-event-bus.mjs +35 -0
  38. package/dist/v2/runtime/core/debug-event-bus.mjs.map +1 -0
  39. package/dist/v2/runtime/core/fetch-handler.cjs +8 -0
  40. package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
  41. package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -1
  42. package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -1
  43. package/dist/v2/runtime/core/fetch-handler.mjs +8 -0
  44. package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
  45. package/dist/v2/runtime/core/fetch-router.cjs +1 -0
  46. package/dist/v2/runtime/core/fetch-router.cjs.map +1 -1
  47. package/dist/v2/runtime/core/fetch-router.mjs +1 -0
  48. package/dist/v2/runtime/core/fetch-router.mjs.map +1 -1
  49. package/dist/v2/runtime/core/hooks.cjs.map +1 -1
  50. package/dist/v2/runtime/core/hooks.d.cts +2 -0
  51. package/dist/v2/runtime/core/hooks.d.cts.map +1 -1
  52. package/dist/v2/runtime/core/hooks.d.mts +2 -0
  53. package/dist/v2/runtime/core/hooks.d.mts.map +1 -1
  54. package/dist/v2/runtime/core/hooks.mjs.map +1 -1
  55. package/dist/v2/runtime/core/runtime.cjs +5 -0
  56. package/dist/v2/runtime/core/runtime.cjs.map +1 -1
  57. package/dist/v2/runtime/core/runtime.d.cts +5 -0
  58. package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
  59. package/dist/v2/runtime/core/runtime.d.mts +5 -1
  60. package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
  61. package/dist/v2/runtime/core/runtime.mjs +5 -0
  62. package/dist/v2/runtime/core/runtime.mjs.map +1 -1
  63. package/dist/v2/runtime/endpoints/express.cjs +5 -5
  64. package/dist/v2/runtime/endpoints/express.cjs.map +1 -1
  65. package/dist/v2/runtime/endpoints/express.mjs +5 -5
  66. package/dist/v2/runtime/endpoints/express.mjs.map +1 -1
  67. package/dist/v2/runtime/handlers/handle-connect.cjs +3 -2
  68. package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
  69. package/dist/v2/runtime/handlers/handle-connect.mjs +3 -2
  70. package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
  71. package/dist/v2/runtime/handlers/handle-debug-events.cjs +33 -0
  72. package/dist/v2/runtime/handlers/handle-debug-events.cjs.map +1 -0
  73. package/dist/v2/runtime/handlers/handle-debug-events.mjs +32 -0
  74. package/dist/v2/runtime/handlers/handle-debug-events.mjs.map +1 -0
  75. package/dist/v2/runtime/handlers/handle-run.cjs +1 -0
  76. package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
  77. package/dist/v2/runtime/handlers/handle-run.mjs +1 -0
  78. package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
  79. package/dist/v2/runtime/handlers/intelligence/connect.cjs +24 -4
  80. package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
  81. package/dist/v2/runtime/handlers/intelligence/connect.mjs +25 -5
  82. package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -1
  83. package/dist/v2/runtime/handlers/intelligence/run.cjs +111 -26
  84. package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
  85. package/dist/v2/runtime/handlers/intelligence/run.mjs +111 -26
  86. package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
  87. package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +7 -3
  88. package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -1
  89. package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +7 -3
  90. package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -1
  91. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +5 -1
  92. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -1
  93. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +5 -1
  94. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -1
  95. package/dist/v2/runtime/handlers/shared/sse-response.cjs +21 -1
  96. package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
  97. package/dist/v2/runtime/handlers/shared/sse-response.mjs +21 -1
  98. package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
  99. package/dist/v2/runtime/handlers/sse/connect.cjs +3 -1
  100. package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
  101. package/dist/v2/runtime/handlers/sse/connect.mjs +3 -1
  102. package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
  103. package/dist/v2/runtime/handlers/sse/run.cjs +3 -1
  104. package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
  105. package/dist/v2/runtime/handlers/sse/run.mjs +3 -1
  106. package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
  107. package/dist/v2/runtime/index.d.cts +1 -1
  108. package/dist/v2/runtime/index.d.mts +1 -2
  109. package/dist/v2/runtime/index.d.mts.map +1 -1
  110. package/dist/v2/runtime/intelligence-platform/client.cjs +6 -8
  111. package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
  112. package/dist/v2/runtime/intelligence-platform/client.d.cts +16 -21
  113. package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
  114. package/dist/v2/runtime/intelligence-platform/client.d.mts +16 -21
  115. package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
  116. package/dist/v2/runtime/intelligence-platform/client.mjs +6 -8
  117. package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
  118. package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
  119. package/dist/v2/runtime/runner/agent-runner.d.cts +0 -1
  120. package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
  121. package/dist/v2/runtime/runner/agent-runner.d.mts +0 -1
  122. package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
  123. package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
  124. package/dist/v2/runtime/runner/index.d.cts +1 -1
  125. package/dist/v2/runtime/runner/index.d.mts +1 -1
  126. package/dist/v2/runtime/runner/intelligence.cjs +47 -10
  127. package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
  128. package/dist/v2/runtime/runner/intelligence.d.cts +8 -1
  129. package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
  130. package/dist/v2/runtime/runner/intelligence.d.mts +8 -1
  131. package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
  132. package/dist/v2/runtime/runner/intelligence.mjs +47 -10
  133. package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
  134. package/dist/v2/runtime/telemetry/instance-created.cjs +33 -0
  135. package/dist/v2/runtime/telemetry/instance-created.cjs.map +1 -0
  136. package/dist/v2/runtime/telemetry/instance-created.mjs +33 -0
  137. package/dist/v2/runtime/telemetry/instance-created.mjs.map +1 -0
  138. package/dist/v2/runtime/telemetry/telemetry-client.cjs +1 -38
  139. package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
  140. package/dist/v2/runtime/telemetry/telemetry-client.mjs +1 -37
  141. package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
  142. package/package.json +8 -8
  143. package/src/agent/__tests__/agent-test-helpers.ts +31 -1
  144. package/src/agent/__tests__/converter-tanstack.test.ts +280 -0
  145. package/src/agent/converters/tanstack.ts +167 -10
  146. package/src/agents/langgraph/__tests__/event-source.test.ts +256 -0
  147. package/src/graphql/resolvers/__tests__/resolve-message-id.test.ts +25 -0
  148. package/src/graphql/resolvers/copilot.resolver.ts +2 -1
  149. package/src/graphql/resolvers/resolve-message-id.ts +14 -0
  150. package/src/lib/runtime/__tests__/handle-service-adapter.test.ts +108 -0
  151. package/src/lib/runtime/__tests__/retry-utils.test.ts +137 -0
  152. package/src/lib/runtime/agent-integrations/langgraph/__tests__/dispatch-event-filtering.test.ts +190 -0
  153. package/src/lib/runtime/agent-integrations/langgraph/agent.ts +8 -1
  154. package/src/lib/runtime/copilot-runtime.ts +20 -4
  155. package/src/lib/runtime/retry-utils.ts +41 -1
  156. package/src/v2/runtime/__tests__/express-fetch-bridge.test.ts +1 -1
  157. package/src/v2/runtime/__tests__/express-single-telemetry.integration.test.ts +65 -0
  158. package/src/v2/runtime/__tests__/express-telemetry.integration.test.ts +101 -0
  159. package/src/v2/runtime/__tests__/fetch-router.test.ts +22 -0
  160. package/src/v2/runtime/__tests__/handle-connect.test.ts +183 -23
  161. package/src/v2/runtime/__tests__/handle-run.test.ts +411 -33
  162. package/src/v2/runtime/__tests__/handle-threads.test.ts +66 -4
  163. package/src/v2/runtime/__tests__/hono-single-telemetry.integration.test.ts +46 -0
  164. package/src/v2/runtime/__tests__/hono-telemetry.integration.test.ts +99 -0
  165. package/src/v2/runtime/__tests__/integration/node-servers.integration.test.ts +19 -0
  166. package/src/v2/runtime/__tests__/integration/suites/debug-events.suite.ts +253 -0
  167. package/src/v2/runtime/__tests__/intelligence-run-telemetry.test.ts +194 -0
  168. package/src/v2/runtime/__tests__/runtime.test.ts +3 -1
  169. package/src/v2/runtime/__tests__/sse-response-telemetry.test.ts +108 -0
  170. package/src/v2/runtime/__tests__/telemetry.test.ts +0 -61
  171. package/src/v2/runtime/core/__tests__/debug-event-bus.test.ts +156 -0
  172. package/src/v2/runtime/core/debug-event-bus.ts +45 -0
  173. package/src/v2/runtime/core/fetch-handler.ts +7 -0
  174. package/src/v2/runtime/core/fetch-router.ts +11 -0
  175. package/src/v2/runtime/core/hooks.ts +2 -1
  176. package/src/v2/runtime/core/runtime.ts +12 -0
  177. package/src/v2/runtime/endpoints/express.ts +9 -3
  178. package/src/v2/runtime/handlers/__tests__/handle-debug-events.test.ts +176 -0
  179. package/src/v2/runtime/handlers/handle-connect.ts +2 -1
  180. package/src/v2/runtime/handlers/handle-debug-events.ts +52 -0
  181. package/src/v2/runtime/handlers/handle-run.ts +1 -0
  182. package/src/v2/runtime/handlers/intelligence/connect.ts +48 -11
  183. package/src/v2/runtime/handlers/intelligence/run.ts +162 -21
  184. package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -1
  185. package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +4 -1
  186. package/src/v2/runtime/handlers/shared/sse-response.ts +46 -0
  187. package/src/v2/runtime/handlers/sse/__tests__/sse-connect-agent-id.test.ts +71 -0
  188. package/src/v2/runtime/handlers/sse/connect.ts +6 -0
  189. package/src/v2/runtime/handlers/sse/run.ts +4 -0
  190. package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +33 -37
  191. package/src/v2/runtime/intelligence-platform/client.ts +37 -40
  192. package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +66 -8
  193. package/src/v2/runtime/runner/agent-runner.ts +0 -1
  194. package/src/v2/runtime/runner/intelligence.ts +74 -15
  195. package/src/v2/runtime/telemetry/__tests__/instance-created.test.ts +96 -0
  196. package/src/v2/runtime/telemetry/instance-created.ts +44 -0
  197. package/src/v2/runtime/telemetry/telemetry-client.ts +1 -57
  198. package/dist/v2/runtime/intelligence-platform/index.d.mts +0 -2
  199. package/dist/v2/runtime/telemetry/utils.cjs +0 -15
  200. package/dist/v2/runtime/telemetry/utils.cjs.map +0 -1
  201. package/dist/v2/runtime/telemetry/utils.mjs +0 -14
  202. package/dist/v2/runtime/telemetry/utils.mjs.map +0 -1
  203. package/src/v2/runtime/telemetry/utils.ts +0 -15
@@ -1,7 +1,27 @@
1
1
  import { PlatformRequestError } from "../../intelligence-platform/client";
2
2
 
3
+ /**
4
+ * Returns the HTTP status carried by platform request errors.
5
+ */
6
+ export function getPlatformErrorStatus(error: unknown): number | undefined {
7
+ if (error instanceof PlatformRequestError) {
8
+ return error.status;
9
+ }
10
+
11
+ if (
12
+ error !== null &&
13
+ typeof error === "object" &&
14
+ "status" in error &&
15
+ typeof error.status === "number"
16
+ ) {
17
+ return error.status;
18
+ }
19
+
20
+ return undefined;
21
+ }
22
+
3
23
  export function isPlatformNotFoundError(error: unknown): boolean {
4
- return error instanceof PlatformRequestError && error.status === 404;
24
+ return getPlatformErrorStatus(error) === 404;
5
25
  }
6
26
 
7
27
  const MAX_ID_LENGTH = 128;
@@ -16,8 +16,11 @@ export async function resolveIntelligenceUser(params: {
16
16
  if (!isValidIdentifier(user?.id)) {
17
17
  return errorResponse("identifyUser must return a valid user id", 400);
18
18
  }
19
+ if (typeof user?.name !== "string" || user.name.trim().length === 0) {
20
+ return errorResponse("identifyUser must return a valid user name", 400);
21
+ }
19
22
 
20
- return { id: user.id };
23
+ return { id: user.id, name: user.name };
21
24
  } catch (error) {
22
25
  console.error("Error identifying intelligence user:", error);
23
26
  return errorResponse("Failed to identify user", 500);
@@ -7,12 +7,15 @@ import {
7
7
  type CopilotRuntimeLogger,
8
8
  } from "../../../../lib/logger";
9
9
  import { telemetry } from "../../telemetry";
10
+ import { DebugEventBus } from "../../core/debug-event-bus";
10
11
 
11
12
  interface CreateSseEventResponseParams {
12
13
  request: Request;
13
14
  observableFactory: () =>
14
15
  | Promise<Observable<BaseEvent>>
15
16
  | Observable<BaseEvent>;
17
+ debugEventBus?: DebugEventBus;
18
+ agentId?: string;
16
19
  debug?: ResolvedDebugConfig;
17
20
  /** Pre-created logger instance to avoid creating a new pino logger per request. */
18
21
  logger?: CopilotRuntimeLogger;
@@ -21,6 +24,8 @@ interface CreateSseEventResponseParams {
21
24
  export function createSseEventResponse({
22
25
  request,
23
26
  observableFactory,
27
+ debugEventBus,
28
+ agentId,
24
29
  debug,
25
30
  logger,
26
31
  }: CreateSseEventResponseParams): Response {
@@ -28,6 +33,8 @@ export function createSseEventResponse({
28
33
  const writer = stream.writable.getWriter();
29
34
  const encoder = new EventEncoder();
30
35
  let streamClosed = false;
36
+ let debugThreadId = "";
37
+ let debugRunId = "";
31
38
 
32
39
  const debugLogger = debug?.enabled
33
40
  ? (logger ??
@@ -74,6 +81,37 @@ export function createSseEventResponse({
74
81
 
75
82
  subscription = observable.subscribe({
76
83
  next: async (event) => {
84
+ // Extract threadId/runId from RUN_STARTED
85
+ if (event.type === "RUN_STARTED") {
86
+ const e = event as { threadId?: string; runId?: string };
87
+ debugThreadId = e.threadId ?? "";
88
+ debugRunId = e.runId ?? "";
89
+ }
90
+
91
+ // Broadcast to debug listeners BEFORE the stream-closed gate below.
92
+ // Intentional: debug subscribers (e.g. the VS Code Inspector panel)
93
+ // should still receive trailing events after the SSE client for
94
+ // this request closed its connection — they're independent
95
+ // consumers observing the underlying runtime, not the request's
96
+ // response stream.
97
+ //
98
+ // Wrapped in try/catch so a buggy debug subscriber can't propagate
99
+ // an exception into this observer — if the throw reached the
100
+ // `next` callback it would get routed to `error` by RxJS, closing
101
+ // the SSE stream for an unrelated reason. Log via `logError` and
102
+ // move on.
103
+ if (debugEventBus) {
104
+ try {
105
+ debugEventBus.broadcast(event, {
106
+ agentId: agentId ?? "",
107
+ threadId: debugThreadId,
108
+ runId: debugRunId,
109
+ });
110
+ } catch (broadcastError) {
111
+ logError(broadcastError);
112
+ }
113
+ }
114
+
77
115
  if (!request.signal.aborted && !streamClosed) {
78
116
  try {
79
117
  eventCount++;
@@ -92,6 +130,14 @@ export function createSseEventResponse({
92
130
  } catch (error) {
93
131
  if (error instanceof Error && error.name === "AbortError") {
94
132
  streamClosed = true;
133
+ } else {
134
+ // Non-abort write failures (backpressure disconnects,
135
+ // transform-stream exceptions, …) were previously swallowed
136
+ // silently — `streamClosed` stayed `false` and the next
137
+ // event re-attempted a broken writer. Log and mark the
138
+ // stream closed so we stop trying.
139
+ logError(error);
140
+ streamClosed = true;
95
141
  }
96
142
  }
97
143
  }
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { of } from "rxjs";
3
+ import { EventType, type BaseEvent } from "@ag-ui/client";
4
+
5
+ vi.mock("pino", () => ({
6
+ default: vi.fn(() => ({
7
+ child: vi.fn(() => ({ debug: vi.fn() })),
8
+ debug: vi.fn(),
9
+ })),
10
+ }));
11
+ vi.mock("pino-pretty", () => ({ default: vi.fn() }));
12
+ vi.mock("../../../telemetry", () => ({
13
+ telemetry: { capture: vi.fn() },
14
+ }));
15
+
16
+ import { handleSseConnect } from "../connect";
17
+ import { DebugEventBus } from "../../../core/debug-event-bus";
18
+
19
+ /**
20
+ * Regression guard for the agentId forwarding fix. `handleSseConnect` used
21
+ * to hardcode `agentId: "connect"` in every debug envelope emitted on
22
+ * /agent/:agentId/connect; the fix threads the route-resolved agentId
23
+ * through to `createSseEventResponse`. Reverting that change would make
24
+ * this test fail — the /run-based integration coverage wouldn't catch it
25
+ * because /run is a different code path.
26
+ */
27
+ describe("handleSseConnect → debug envelope agentId", () => {
28
+ it("forwards the real agentId into envelopes on /connect", async () => {
29
+ const bus = new DebugEventBus();
30
+ const received: Array<{ agentId: string }> = [];
31
+ bus.subscribe((envelope) => {
32
+ received.push({ agentId: envelope.agentId });
33
+ });
34
+
35
+ const event: BaseEvent = {
36
+ type: EventType.RUN_STARTED,
37
+ threadId: "t-1",
38
+ runId: "r-1",
39
+ } as BaseEvent;
40
+
41
+ const fakeRuntime = {
42
+ debugEventBus: bus,
43
+ runner: {
44
+ connect: () => of(event),
45
+ },
46
+ } as any;
47
+
48
+ const response = handleSseConnect({
49
+ runtime: fakeRuntime,
50
+ request: new Request("http://localhost/agent/weather-agent/connect", {
51
+ method: "POST",
52
+ }),
53
+ agentId: "weather-agent",
54
+ threadId: "t-1",
55
+ });
56
+
57
+ // Drain to let the observable subscription fire.
58
+ const reader = response.body!.getReader();
59
+ while (true) {
60
+ const { done } = await reader.read();
61
+ if (done) break;
62
+ }
63
+
64
+ expect(received.length).toBeGreaterThan(0);
65
+ for (const env of received) {
66
+ // A revert to the pre-fix hardcoded "connect" would fail this
67
+ // positive assertion — no need for a separate not-toBe guard.
68
+ expect(env.agentId).toBe("weather-agent");
69
+ }
70
+ });
71
+ });
@@ -5,16 +5,22 @@ import { extractForwardableHeaders } from "../header-utils";
5
5
  interface HandleSseConnectParams {
6
6
  runtime: CopilotRuntimeLike;
7
7
  request: Request;
8
+ agentId: string;
8
9
  threadId: string;
9
10
  }
10
11
 
11
12
  export function handleSseConnect({
12
13
  runtime,
13
14
  request,
15
+ agentId,
14
16
  threadId,
15
17
  }: HandleSseConnectParams): Response {
16
18
  return createSseEventResponse({
17
19
  request,
20
+ debugEventBus: runtime.debugEventBus,
21
+ // Forward the real agentId so debug envelopes reflect the agent the
22
+ // route resolved to — not the literal string "connect".
23
+ agentId,
18
24
  observableFactory: () =>
19
25
  runtime.runner.connect({
20
26
  threadId,
@@ -9,6 +9,7 @@ interface HandleSseRunParams {
9
9
  request: Request;
10
10
  agent: AbstractAgent;
11
11
  input: RunAgentInput;
12
+ agentId: string;
12
13
  debug?: ResolvedDebugConfig;
13
14
  /** Pre-created logger instance to avoid creating a new pino logger per request. */
14
15
  logger?: CopilotRuntimeLogger;
@@ -19,11 +20,14 @@ export function handleSseRun({
19
20
  request,
20
21
  agent,
21
22
  input,
23
+ agentId,
22
24
  debug,
23
25
  logger,
24
26
  }: HandleSseRunParams): Response {
25
27
  return createSseEventResponse({
26
28
  request,
29
+ debugEventBus: runtime.debugEventBus,
30
+ agentId,
27
31
  debug,
28
32
  logger,
29
33
  observableFactory: () =>
@@ -35,7 +35,6 @@ describe("CopilotKitIntelligence", () => {
35
35
  apiUrl: "https://api.example.com",
36
36
  wsUrl: "wss://ws.example.com/socket",
37
37
  apiKey: "test-key",
38
- organizationId: "org-1",
39
38
  });
40
39
  });
41
40
 
@@ -44,7 +43,6 @@ describe("CopilotKitIntelligence", () => {
44
43
  apiUrl: "https://api.example.com/",
45
44
  wsUrl: "wss://ws.example.com/socket",
46
45
  apiKey: "k",
47
- organizationId: "org-1",
48
46
  });
49
47
  fetchMock.mockReturnValue(jsonResponse({ threads: [], joinCode: "" }));
50
48
  await c.listThreads({ userId: "u", agentId: "a" });
@@ -58,7 +56,6 @@ describe("CopilotKitIntelligence", () => {
58
56
  apiUrl: "https://api.example.com",
59
57
  wsUrl: "wss://ws.example.com",
60
58
  apiKey: "k",
61
- organizationId: "org-1",
62
59
  });
63
60
 
64
61
  expect(c.ɵgetRunnerWsUrl()).toBe("wss://ws.example.com/runner");
@@ -71,7 +68,6 @@ describe("CopilotKitIntelligence", () => {
71
68
  const headers = fetchMock.mock.calls[0][1].headers;
72
69
  expect(headers.Authorization).toBe("Bearer test-key");
73
70
  expect(headers["Content-Type"]).toBe("application/json");
74
- expect(headers["X-Organization-Id"]).toBe("org-1");
75
71
  });
76
72
 
77
73
  it("throws on non-ok response", async () => {
@@ -175,7 +171,6 @@ describe("CopilotKitIntelligence", () => {
175
171
  apiUrl: "https://api.example.com",
176
172
  wsUrl: "wss://ws.example.com/socket",
177
173
  apiKey: "test-key",
178
- organizationId: "org-1",
179
174
  onThreadUpdated,
180
175
  });
181
176
  const thread = { id: "t-1", name: "Renamed" };
@@ -225,7 +220,6 @@ describe("CopilotKitIntelligence", () => {
225
220
  apiUrl: "https://api.example.com",
226
221
  wsUrl: "wss://ws.example.com/socket",
227
222
  apiKey: "test-key",
228
- organizationId: "org-1",
229
223
  onThreadCreated,
230
224
  });
231
225
  const thread = { id: "t-1", name: null };
@@ -312,7 +306,6 @@ describe("CopilotKitIntelligence", () => {
312
306
  apiUrl: "https://api.example.com",
313
307
  wsUrl: "wss://ws.example.com/socket",
314
308
  apiKey: "test-key",
315
- organizationId: "org-1",
316
309
  onThreadUpdated,
317
310
  });
318
311
  const thread = { id: "t-1", name: "Archived", archived: true };
@@ -353,7 +346,6 @@ describe("CopilotKitIntelligence", () => {
353
346
  apiUrl: "https://api.example.com",
354
347
  wsUrl: "wss://ws.example.com/socket",
355
348
  apiKey: "test-key",
356
- organizationId: "org-1",
357
349
  onThreadDeleted,
358
350
  });
359
351
  fetchMock.mockReturnValue(jsonResponse(undefined));
@@ -376,7 +368,6 @@ describe("CopilotKitIntelligence", () => {
376
368
  apiUrl: "https://api.example.com",
377
369
  wsUrl: "wss://ws.example.com/socket",
378
370
  apiKey: "test-key",
379
- organizationId: "org-1",
380
371
  onThreadDeleted: () => {
381
372
  throw new Error("callback exploded");
382
373
  },
@@ -394,24 +385,34 @@ describe("CopilotKitIntelligence", () => {
394
385
  });
395
386
 
396
387
  describe("acquireThreadLock", () => {
397
- it("sends POST to lock endpoint and returns thread connection credentials", async () => {
388
+ it("sends POST to lock endpoint and returns canonical run credentials", async () => {
398
389
  fetchMock.mockReturnValue(
399
- jsonResponse({ joinToken: "jt-lock", joinCode: "jc-lock" }),
390
+ jsonResponse({
391
+ threadId: "t-1",
392
+ runId: "r-1",
393
+ joinToken: "jt-lock",
394
+ }),
400
395
  );
401
396
 
402
397
  const result = await client.ɵacquireThreadLock({
403
398
  threadId: "t-1",
404
399
  runId: "r-1",
405
400
  userId: "user-1",
401
+ agentId: "agent-1",
406
402
  });
407
403
 
408
- expect(result).toEqual({ joinToken: "jt-lock", joinCode: "jc-lock" });
404
+ expect(result).toEqual({
405
+ threadId: "t-1",
406
+ runId: "r-1",
407
+ joinToken: "jt-lock",
408
+ });
409
409
  const [url, opts] = fetchMock.mock.calls[0];
410
410
  expect(url).toBe("https://api.example.com/api/threads/t-1/lock");
411
411
  expect(opts.method).toBe("POST");
412
412
  expect(JSON.parse(opts.body)).toEqual({
413
413
  runId: "r-1",
414
414
  userId: "user-1",
415
+ agentId: "agent-1",
415
416
  });
416
417
  });
417
418
 
@@ -422,9 +423,24 @@ describe("CopilotKitIntelligence", () => {
422
423
  threadId: "t-1",
423
424
  runId: "r-1",
424
425
  userId: "user-1",
426
+ agentId: "agent-1",
425
427
  }),
426
428
  ).rejects.toThrow(/409/);
427
429
  });
430
+
431
+ it("sends compare-delete cleanup to the lock endpoint", async () => {
432
+ fetchMock.mockReturnValue(emptyResponse());
433
+
434
+ await client.ɵcleanupThreadLock({
435
+ threadId: "t-1",
436
+ runId: "r-1",
437
+ });
438
+
439
+ const [url, opts] = fetchMock.mock.calls[0];
440
+ expect(url).toBe("https://api.example.com/api/threads/t-1/lock");
441
+ expect(opts.method).toBe("DELETE");
442
+ expect(JSON.parse(opts.body)).toEqual({ runId: "r-1" });
443
+ });
428
444
  });
429
445
 
430
446
  describe("getActiveJoinCode", () => {
@@ -503,7 +519,6 @@ describe("CopilotKitIntelligence", () => {
503
519
  apiUrl: "https://api.example.com",
504
520
  wsUrl: "wss://ws.example.com/socket",
505
521
  apiKey: "test-key",
506
- organizationId: "org-1",
507
522
  onThreadUpdated: configCb,
508
523
  });
509
524
  client.onThreadUpdated(runtimeCb);
@@ -554,7 +569,7 @@ describe("CopilotKitIntelligence", () => {
554
569
  const result = await client.ɵconnectThread({
555
570
  threadId: "t-1",
556
571
  userId: "user-1",
557
- lastSeenEventId: "event-1",
572
+ agentId: "agent-1",
558
573
  });
559
574
 
560
575
  expect(result).toBeNull();
@@ -563,40 +578,21 @@ describe("CopilotKitIntelligence", () => {
563
578
  expect(opts.method).toBe("POST");
564
579
  expect(JSON.parse(opts.body)).toEqual({
565
580
  userId: "user-1",
566
- lastSeenEventId: "event-1",
581
+ agentId: "agent-1",
567
582
  });
568
583
  });
569
584
 
570
- it("returns a bootstrap connect plan", async () => {
585
+ it("returns credentials-only connect response", async () => {
571
586
  const payload = {
572
- mode: "bootstrap",
573
- latestEventId: "event-2",
574
- events: [{ type: "MESSAGES_SNAPSHOT", messages: [] }],
575
- };
576
- fetchMock.mockReturnValue(jsonResponse(payload));
577
-
578
- const result = await client.ɵconnectThread({
579
587
  threadId: "t-1",
580
- userId: "user-1",
581
- lastSeenEventId: "event-1",
582
- });
583
-
584
- expect(result).toEqual(payload);
585
- });
586
-
587
- it("returns a live connect plan", async () => {
588
- const payload = {
589
- mode: "live",
590
- joinToken: "jt-live",
591
- joinFromEventId: "event-2",
592
- events: [],
588
+ joinToken: "jt-connect",
593
589
  };
594
590
  fetchMock.mockReturnValue(jsonResponse(payload));
595
591
 
596
592
  const result = await client.ɵconnectThread({
597
593
  threadId: "t-1",
598
594
  userId: "user-1",
599
- lastSeenEventId: "event-2",
595
+ agentId: "agent-1",
600
596
  });
601
597
 
602
598
  expect(result).toEqual(payload);
@@ -1,5 +1,4 @@
1
1
  import { logger } from "@copilotkit/shared";
2
- import type { BaseEvent } from "@ag-ui/client";
3
2
 
4
3
  /**
5
4
  * Error thrown when an Intelligence platform HTTP request returns a non-2xx
@@ -42,7 +41,6 @@ export class PlatformRequestError extends Error {
42
41
  * apiUrl: "https://api.copilotkit.ai",
43
42
  * wsUrl: "wss://api.copilotkit.ai",
44
43
  * apiKey: process.env.COPILOTKIT_API_KEY!,
45
- * organizationId: process.env.COPILOTKIT_ORGANIZATION_ID!,
46
44
  * });
47
45
  *
48
46
  * const runtime = new CopilotRuntime({
@@ -66,8 +64,6 @@ export interface CopilotKitIntelligenceConfig {
66
64
  wsUrl: string;
67
65
  /** API key for authenticating with the intelligence platform */
68
66
  apiKey: string;
69
- /** Organization identifier used for self-hosted Intelligence instances */
70
- organizationId: string;
71
67
  /**
72
68
  * Initial listener invoked after a thread is created.
73
69
  * Prefer {@link CopilotKitIntelligence.onThreadCreated} for multiple listeners.
@@ -153,10 +149,12 @@ export interface CreateThreadRequest {
153
149
 
154
150
  /** Credentials returned when locking or joining a thread's realtime channel. */
155
151
  export interface ThreadConnectionResponse {
152
+ /** Canonical platform thread identifier for the run or connection. */
153
+ threadId: string;
154
+ /** Canonical platform run identifier for an active run lock. */
155
+ runId?: string;
156
156
  /** Short-lived token for authenticating the Phoenix channel join. */
157
157
  joinToken: string;
158
- /** Optional join code that can be shared with other clients to join the same channel. */
159
- joinCode?: string;
160
158
  /** Lock metadata echoed back by the platform. */
161
159
  lock?: ThreadLockInfo;
162
160
  }
@@ -169,24 +167,13 @@ export interface SubscribeToThreadsResponse {
169
167
  joinToken: string;
170
168
  }
171
169
 
172
- export interface ConnectThreadBootstrapResponse {
173
- mode: "bootstrap";
174
- latestEventId: string | null;
175
- events: BaseEvent[];
176
- }
170
+ export type ConnectThreadResponse = ThreadConnectionResponse | null;
177
171
 
178
- export interface ConnectThreadLiveResponse {
179
- mode: "live";
180
- joinToken: string;
181
- joinFromEventId: string | null;
182
- events: BaseEvent[];
172
+ export interface AcquireThreadLockResponse extends ThreadConnectionResponse {
173
+ /** Canonical platform run identifier for the acquired lock. */
174
+ runId: string;
183
175
  }
184
176
 
185
- export type ConnectThreadResponse =
186
- | ConnectThreadBootstrapResponse
187
- | ConnectThreadLiveResponse
188
- | null;
189
-
190
177
  /** A single message within a thread's persisted history. */
191
178
  export interface ThreadMessage {
192
179
  /** Unique identifier for this message. */
@@ -215,6 +202,7 @@ export interface AcquireThreadLockRequest {
215
202
  threadId: string;
216
203
  runId: string;
217
204
  userId: string;
205
+ agentId: string;
218
206
  /** Custom Redis key prefix for the lock (default: "thread"). */
219
207
  lockKeyPrefix?: string;
220
208
  /** Lock TTL in seconds. When set, the lock auto-expires after this duration. */
@@ -230,6 +218,11 @@ export interface RenewThreadLockRequest {
230
218
  lockKeyPrefix?: string;
231
219
  }
232
220
 
221
+ export interface CleanupThreadLockRequest {
222
+ threadId: string;
223
+ runId: string;
224
+ }
225
+
233
226
  export interface RenewThreadLockResponse {
234
227
  ttlSeconds: number;
235
228
  }
@@ -248,7 +241,6 @@ export class CopilotKitIntelligence {
248
241
  #runnerWsUrl: string;
249
242
  #clientWsUrl: string;
250
243
  #apiKey: string;
251
- #organizationId: string;
252
244
  #threadCreatedListeners = new Set<(thread: ThreadSummary) => void>();
253
245
  #threadUpdatedListeners = new Set<(thread: ThreadSummary) => void>();
254
246
  #threadDeletedListeners = new Set<(params: ThreadDeletedPayload) => void>();
@@ -260,7 +252,6 @@ export class CopilotKitIntelligence {
260
252
  this.#runnerWsUrl = deriveRunnerWsUrl(intelligenceWsUrl);
261
253
  this.#clientWsUrl = deriveClientWsUrl(intelligenceWsUrl);
262
254
  this.#apiKey = config.apiKey;
263
- this.#organizationId = config.organizationId;
264
255
 
265
256
  if (config.onThreadCreated) {
266
257
  this.onThreadCreated(config.onThreadCreated);
@@ -345,10 +336,6 @@ export class CopilotKitIntelligence {
345
336
  return this.#clientWsUrl;
346
337
  }
347
338
 
348
- ɵgetOrganizationId(): string {
349
- return this.#organizationId;
350
- }
351
-
352
339
  ɵgetRunnerAuthToken(): string {
353
340
  return this.#apiKey;
354
341
  }
@@ -359,7 +346,6 @@ export class CopilotKitIntelligence {
359
346
  const headers: Record<string, string> = {
360
347
  Authorization: `Bearer ${this.#apiKey}`,
361
348
  "Content-Type": "application/json",
362
- "X-Organization-Id": this.#organizationId,
363
349
  };
364
350
 
365
351
  const response = await fetch(url, {
@@ -400,7 +386,7 @@ export class CopilotKitIntelligence {
400
386
 
401
387
  for (const callback of listeners) {
402
388
  try {
403
- void (callback as (p: typeof payload) => void)(payload);
389
+ (callback as (p: typeof payload) => void)(payload);
404
390
  } catch (error) {
405
391
  logger.error(
406
392
  { err: error, callbackName, payload },
@@ -616,13 +602,14 @@ export class CopilotKitIntelligence {
616
602
 
617
603
  async ɵacquireThreadLock(
618
604
  params: AcquireThreadLockRequest,
619
- ): Promise<ThreadConnectionResponse> {
620
- return this.#request<ThreadConnectionResponse>(
605
+ ): Promise<AcquireThreadLockResponse> {
606
+ return this.#request<AcquireThreadLockResponse>(
621
607
  "POST",
622
608
  `/api/threads/${encodeURIComponent(params.threadId)}/lock`,
623
609
  {
624
610
  runId: params.runId,
625
611
  userId: params.userId,
612
+ agentId: params.agentId,
626
613
  ...(params.lockKeyPrefix !== undefined
627
614
  ? { lockKeyPrefix: params.lockKeyPrefix }
628
615
  : {}),
@@ -633,6 +620,16 @@ export class CopilotKitIntelligence {
633
620
  );
634
621
  }
635
622
 
623
+ async ɵcleanupThreadLock(params: CleanupThreadLockRequest): Promise<void> {
624
+ return this.#request<void>(
625
+ "DELETE",
626
+ `/api/threads/${encodeURIComponent(params.threadId)}/lock`,
627
+ {
628
+ runId: params.runId,
629
+ },
630
+ );
631
+ }
632
+
636
633
  async ɵrenewThreadLock(
637
634
  params: RenewThreadLockRequest,
638
635
  ): Promise<RenewThreadLockResponse> {
@@ -663,16 +660,16 @@ export class CopilotKitIntelligence {
663
660
  async ɵconnectThread(params: {
664
661
  threadId: string;
665
662
  userId: string;
666
- lastSeenEventId?: string | null;
663
+ agentId: string;
667
664
  }): Promise<ConnectThreadResponse> {
668
- const result = await this.#request<
669
- ConnectThreadBootstrapResponse | ConnectThreadLiveResponse
670
- >("POST", `/api/threads/${encodeURIComponent(params.threadId)}/connect`, {
671
- userId: params.userId,
672
- ...(params.lastSeenEventId !== undefined
673
- ? { lastSeenEventId: params.lastSeenEventId }
674
- : {}),
675
- });
665
+ const result = await this.#request<ThreadConnectionResponse>(
666
+ "POST",
667
+ `/api/threads/${encodeURIComponent(params.threadId)}/connect`,
668
+ {
669
+ userId: params.userId,
670
+ agentId: params.agentId,
671
+ },
672
+ );
676
673
 
677
674
  // request() returns undefined for empty/204 responses
678
675
  return result ?? null;