@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.
- package/dist/agent/converters/tanstack.cjs +121 -25
- package/dist/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs +121 -25
- package/dist/agent/converters/tanstack.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/runtime/agent-integrations/langgraph/agent.cjs +8 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +8 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs.map +1 -1
- 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 +7 -7
- package/dist/package.mjs +7 -7
- 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/endpoints/express.cjs +5 -5
- package/dist/v2/runtime/endpoints/express.cjs.map +1 -1
- package/dist/v2/runtime/endpoints/express.mjs +5 -5
- package/dist/v2/runtime/endpoints/express.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 +8 -8
- package/src/agent/__tests__/agent-test-helpers.ts +31 -1
- package/src/agent/__tests__/converter-tanstack.test.ts +280 -0
- package/src/agent/converters/tanstack.ts +167 -10
- 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/agent-integrations/langgraph/agent.ts +8 -1
- package/src/lib/runtime/copilot-runtime.ts +20 -4
- package/src/lib/runtime/retry-utils.ts +41 -1
- package/src/v2/runtime/__tests__/express-fetch-bridge.test.ts +1 -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/endpoints/express.ts +9 -3
- 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
|
@@ -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
|
|
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
|
|
388
|
+
it("sends POST to lock endpoint and returns canonical run credentials", async () => {
|
|
398
389
|
fetchMock.mockReturnValue(
|
|
399
|
-
jsonResponse({
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
581
|
+
agentId: "agent-1",
|
|
567
582
|
});
|
|
568
583
|
});
|
|
569
584
|
|
|
570
|
-
it("returns
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
173
|
-
mode: "bootstrap";
|
|
174
|
-
latestEventId: string | null;
|
|
175
|
-
events: BaseEvent[];
|
|
176
|
-
}
|
|
170
|
+
export type ConnectThreadResponse = ThreadConnectionResponse | null;
|
|
177
171
|
|
|
178
|
-
export interface
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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<
|
|
620
|
-
return this.#request<
|
|
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
|
-
|
|
663
|
+
agentId: string;
|
|
667
664
|
}): Promise<ConnectThreadResponse> {
|
|
668
|
-
const result = await this.#request<
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
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;
|