@copilotkit/runtime 1.50.0-beta.1 → 1.50.0-beta.3

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 (41) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/index.d.ts +76 -286
  3. package/dist/index.js +306 -281
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +299 -270
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/langgraph.d.ts +284 -0
  8. package/dist/langgraph.js +211 -0
  9. package/dist/langgraph.js.map +1 -0
  10. package/dist/langgraph.mjs +206 -0
  11. package/dist/langgraph.mjs.map +1 -0
  12. package/dist/v2/index.d.ts +1 -0
  13. package/dist/v2/index.js +7 -0
  14. package/dist/v2/index.js.map +1 -1
  15. package/dist/v2/index.mjs +1 -0
  16. package/dist/v2/index.mjs.map +1 -1
  17. package/package.json +55 -17
  18. package/src/graphql/message-conversion/agui-to-gql.test.ts +2 -2
  19. package/src/graphql/message-conversion/gql-to-agui.test.ts +30 -28
  20. package/src/graphql/message-conversion/roundtrip-conversion.test.ts +8 -8
  21. package/src/langgraph.ts +1 -0
  22. package/src/lib/index.ts +41 -1
  23. package/src/lib/integrations/nextjs/app-router.ts +3 -1
  24. package/src/lib/integrations/node-http/index.ts +132 -11
  25. package/src/lib/integrations/shared.ts +2 -2
  26. package/src/lib/runtime/agent-integrations/{langgraph.agent.ts → langgraph/agent.ts} +5 -30
  27. package/src/lib/runtime/agent-integrations/langgraph/consts.ts +34 -0
  28. package/src/lib/runtime/agent-integrations/langgraph/index.ts +2 -0
  29. package/src/lib/runtime/copilot-runtime.ts +25 -46
  30. package/src/service-adapters/anthropic/anthropic-adapter.ts +16 -3
  31. package/src/service-adapters/bedrock/bedrock-adapter.ts +4 -1
  32. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +2 -1
  33. package/src/service-adapters/google/google-genai-adapter.ts +9 -4
  34. package/src/service-adapters/groq/groq-adapter.ts +16 -3
  35. package/src/service-adapters/langchain/langchain-adapter.ts +5 -3
  36. package/src/service-adapters/langchain/langserve.ts +2 -1
  37. package/src/service-adapters/openai/openai-adapter.ts +17 -3
  38. package/src/service-adapters/openai/openai-assistant-adapter.ts +26 -11
  39. package/src/service-adapters/unify/unify-adapter.ts +3 -1
  40. package/src/v2/index.ts +1 -0
  41. package/tsup.config.ts +5 -2
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, vi } from "vitest";
1
+ import { describe, test, expect } from "@jest/globals";
2
2
  import * as gql from "../types/converted/index";
3
3
  import agui from "@copilotkit/shared";
4
4
  import { aguiToGQL } from "./agui-to-gql";
@@ -131,7 +131,7 @@ describe("roundtrip message conversion", () => {
131
131
  });
132
132
 
133
133
  test("action execution with render function roundtrip", () => {
134
- const mockRender = vi.fn();
134
+ const mockRender = jest.fn();
135
135
  const aguiMsg: agui.Message = {
136
136
  id: "assistant-1",
137
137
  role: "assistant",
@@ -211,7 +211,7 @@ describe("roundtrip message conversion", () => {
211
211
  });
212
212
 
213
213
  test("wild card action roundtrip conversion", () => {
214
- const mockRender = vi.fn((props) => `Wildcard rendered: ${props.args.test}`);
214
+ const mockRender = jest.fn((props) => `Wildcard rendered: ${props.args.test}`);
215
215
  const aguiMsg: agui.Message = {
216
216
  id: "assistant-wildcard-1",
217
217
  role: "assistant",
@@ -256,7 +256,7 @@ describe("roundtrip message conversion", () => {
256
256
  });
257
257
 
258
258
  test("wild card action with specific action priority roundtrip", () => {
259
- const mockRender = vi.fn((props) => `Specific action rendered: ${props.args.test}`);
259
+ const mockRender = jest.fn((props) => `Specific action rendered: ${props.args.test}`);
260
260
  const aguiMsg: agui.Message = {
261
261
  id: "assistant-priority-1",
262
262
  role: "assistant",
@@ -313,7 +313,7 @@ describe("roundtrip message conversion", () => {
313
313
  const actions: Record<string, any> = {
314
314
  "*": {
315
315
  name: "*",
316
- render: vi.fn((props) => `GQL wildcard rendered: ${props.args.test}`),
316
+ render: jest.fn((props) => `GQL wildcard rendered: ${props.args.test}`),
317
317
  },
318
318
  };
319
319
 
@@ -379,7 +379,7 @@ describe("roundtrip message conversion", () => {
379
379
  });
380
380
 
381
381
  test("roundtrip conversion with action execution and result parsing", () => {
382
- const mockRender = vi.fn((props) => `Rendered: ${JSON.stringify(props.result)}`);
382
+ const mockRender = jest.fn((props) => `Rendered: ${JSON.stringify(props.result)}`);
383
383
 
384
384
  // Create action execution message
385
385
  const actionExecMsg = new gql.ActionExecutionMessage({
@@ -439,7 +439,7 @@ describe("roundtrip message conversion", () => {
439
439
  });
440
440
 
441
441
  test("roundtrip conversion verifies correct property distribution for regular actions", () => {
442
- const mockRender = vi.fn((props) => `Regular action: ${JSON.stringify(props.args)}`);
442
+ const mockRender = jest.fn((props) => `Regular action: ${JSON.stringify(props.args)}`);
443
443
 
444
444
  const actionExecMsg = new gql.ActionExecutionMessage({
445
445
  id: "regular-action-test",
@@ -481,7 +481,7 @@ describe("roundtrip message conversion", () => {
481
481
  });
482
482
 
483
483
  test("roundtrip conversion verifies correct property distribution for wildcard actions", () => {
484
- const mockRender = vi.fn(
484
+ const mockRender = jest.fn(
485
485
  (props) => `Wildcard action: ${props.name} with ${JSON.stringify(props.args)}`,
486
486
  );
487
487
 
@@ -0,0 +1 @@
1
+ export * from "./lib/runtime/agent-integrations/langgraph";
package/src/lib/index.ts CHANGED
@@ -8,4 +8,44 @@ export * from "./integrations";
8
8
  export * from "./logger";
9
9
  export * from "./runtime/copilot-runtime";
10
10
  export * from "./runtime/mcp-tools-utils";
11
- export * from "./runtime/agent-integrations/langgraph.agent";
11
+
12
+ // The below re-exports "dummy" classes and types, to get a deprecation warning redirecting the users to import these from the correct, new route
13
+
14
+ /**
15
+ * @deprecated LangGraphAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
16
+ */
17
+ export class LangGraphAgent {
18
+ constructor() {
19
+ throw new Error(
20
+ "LangGraphAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead",
21
+ );
22
+ }
23
+ }
24
+
25
+ /**
26
+ * @deprecated LangGraphHttpAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
27
+ */
28
+ export class LangGraphHttpAgent {
29
+ constructor() {
30
+ throw new Error(
31
+ "LangGraphHttpAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead",
32
+ );
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @deprecated TextMessageEvents import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
38
+ */
39
+ export type TextMessageEvents = any;
40
+ /**
41
+ * @deprecated ToolCallEvents import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
42
+ */
43
+ export type ToolCallEvents = any;
44
+ /**
45
+ * @deprecated CustomEventNames import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
46
+ */
47
+ export type CustomEventNames = any;
48
+ /**
49
+ * @deprecated PredictStateTool import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
50
+ */
51
+ export type PredictStateTool = any;
@@ -24,7 +24,9 @@ export function copilotRuntimeNextJSAppRouterEndpoint(options: CreateCopilotRunt
24
24
  logger.debug("Creating NextJS App Router endpoint");
25
25
 
26
26
  const serviceAdapter = options.serviceAdapter;
27
- options.runtime.handleServiceAdapter(serviceAdapter);
27
+ if (serviceAdapter) {
28
+ options.runtime.handleServiceAdapter(serviceAdapter);
29
+ }
28
30
 
29
31
  const copilotRoute = createCopilotEndpointSingleRoute({
30
32
  runtime: options.runtime.instance,
@@ -4,6 +4,8 @@ import { createCopilotEndpointSingleRoute } from "@copilotkitnext/runtime";
4
4
  import { IncomingMessage, ServerResponse } from "http";
5
5
  import { Readable } from "node:stream";
6
6
 
7
+ type IncomingWithBody = IncomingMessage & { body?: unknown; complete?: boolean };
8
+
7
9
  export function readableStreamToNodeStream(webStream: ReadableStream): Readable {
8
10
  const reader = webStream.getReader();
9
11
 
@@ -24,7 +26,10 @@ export function readableStreamToNodeStream(webStream: ReadableStream): Readable
24
26
  }
25
27
 
26
28
  function getFullUrl(req: IncomingMessage): string {
27
- const path = req.url || "/";
29
+ const expressPath =
30
+ (req as any).originalUrl ??
31
+ ((req as any).baseUrl ? `${(req as any).baseUrl}${req.url ?? ""}` : undefined);
32
+ const path = expressPath || req.url || "/";
28
33
  const host =
29
34
  (req.headers["x-forwarded-host"] as string) || (req.headers.host as string) || "localhost";
30
35
  const proto =
@@ -34,6 +39,61 @@ function getFullUrl(req: IncomingMessage): string {
34
39
  return `${proto}://${host}${path}`;
35
40
  }
36
41
 
42
+ function toHeaders(rawHeaders: IncomingMessage["headers"]): Headers {
43
+ const headers = new Headers();
44
+
45
+ for (const [key, value] of Object.entries(rawHeaders)) {
46
+ if (value === undefined) continue;
47
+
48
+ if (Array.isArray(value)) {
49
+ value.forEach((entry) => headers.append(key, entry));
50
+ continue;
51
+ }
52
+
53
+ headers.append(key, value);
54
+ }
55
+
56
+ return headers;
57
+ }
58
+
59
+ function isStreamConsumed(req: IncomingWithBody): boolean {
60
+ const readableState = (req as any)._readableState;
61
+
62
+ return Boolean(
63
+ req.readableEnded || req.complete || readableState?.ended || readableState?.endEmitted,
64
+ );
65
+ }
66
+
67
+ function synthesizeBodyFromParsedBody(
68
+ parsedBody: unknown,
69
+ headers: Headers,
70
+ ): { body: BodyInit | null; contentType?: string } {
71
+ if (parsedBody === null || parsedBody === undefined) {
72
+ return { body: null };
73
+ }
74
+
75
+ if (parsedBody instanceof Buffer || parsedBody instanceof Uint8Array) {
76
+ return { body: parsedBody };
77
+ }
78
+
79
+ if (typeof parsedBody === "string") {
80
+ return { body: parsedBody, contentType: headers.get("content-type") ?? "text/plain" };
81
+ }
82
+
83
+ return {
84
+ body: JSON.stringify(parsedBody),
85
+ contentType: "application/json",
86
+ };
87
+ }
88
+
89
+ function isDisturbedOrLockedError(error: unknown): boolean {
90
+ return (
91
+ error instanceof TypeError &&
92
+ typeof error.message === "string" &&
93
+ (error.message.includes("disturbed") || error.message.includes("locked"))
94
+ );
95
+ }
96
+
37
97
  export function copilotRuntimeNodeHttpEndpoint(options: CreateCopilotRuntimeServerOptions) {
38
98
  const commonConfig = getCommonConfig(options);
39
99
 
@@ -55,26 +115,87 @@ export function copilotRuntimeNodeHttpEndpoint(options: CreateCopilotRuntimeServ
55
115
  logger.debug("Creating Node HTTP endpoint");
56
116
 
57
117
  const serviceAdapter = options.serviceAdapter;
58
- options.runtime.handleServiceAdapter(serviceAdapter);
118
+ if (serviceAdapter) {
119
+ options.runtime.handleServiceAdapter(serviceAdapter);
120
+ }
59
121
 
60
122
  const honoApp = createCopilotEndpointSingleRoute({
61
123
  runtime: options.runtime.instance,
62
124
  basePath: options.baseUrl ?? options.endpoint,
63
125
  });
64
126
 
65
- return async function handler(req: IncomingMessage, res: ServerResponse) {
127
+ return async function handler(req: IncomingWithBody, res: ServerResponse) {
66
128
  const url = getFullUrl(req);
67
129
  const hasBody = req.method !== "GET" && req.method !== "HEAD";
68
130
 
69
- const request = new Request(url, {
70
- method: req.method,
71
- headers: req.headers as any,
72
- body: hasBody ? (req as any) : undefined,
73
- // Node/undici extension
74
- duplex: hasBody ? "half" : undefined,
75
- } as any);
131
+ const baseHeaders = toHeaders(req.headers);
132
+ const parsedBody = req.body;
133
+
134
+ const streamConsumed = isStreamConsumed(req) || parsedBody !== undefined;
135
+ const canStream = hasBody && !streamConsumed;
76
136
 
77
- const response = await honoApp.fetch(request);
137
+ let requestBody: BodyInit | null | undefined = undefined;
138
+ let useDuplex = false;
139
+
140
+ if (hasBody && canStream) {
141
+ requestBody = req as unknown as BodyInit;
142
+ useDuplex = true;
143
+ }
144
+
145
+ if (hasBody && streamConsumed) {
146
+ if (parsedBody !== undefined) {
147
+ const synthesized = synthesizeBodyFromParsedBody(parsedBody, baseHeaders);
148
+ requestBody = synthesized.body ?? undefined;
149
+ baseHeaders.delete("content-length");
150
+
151
+ if (synthesized.contentType) {
152
+ baseHeaders.set("content-type", synthesized.contentType);
153
+ }
154
+
155
+ logger.debug("Request stream already consumed; using parsed req.body to rebuild request.");
156
+ } else {
157
+ logger.warn("Request stream consumed with no available body; sending empty payload.");
158
+ requestBody = undefined;
159
+ }
160
+ }
161
+
162
+ const buildRequest = (body: BodyInit | null | undefined, headers: Headers, duplex: boolean) =>
163
+ new Request(url, {
164
+ method: req.method,
165
+ headers,
166
+ body,
167
+ duplex: duplex ? "half" : undefined,
168
+ } as RequestInit);
169
+
170
+ let response: Response;
171
+ try {
172
+ response = await honoApp.fetch(buildRequest(requestBody, baseHeaders, useDuplex));
173
+ } catch (error) {
174
+ if (isDisturbedOrLockedError(error) && hasBody) {
175
+ logger.warn(
176
+ "Encountered disturbed/locked request body; rebuilding request using parsed body or empty payload.",
177
+ );
178
+
179
+ const fallbackHeaders = new Headers(baseHeaders);
180
+ let fallbackBody: BodyInit | null | undefined;
181
+
182
+ if (parsedBody !== undefined) {
183
+ const synthesized = synthesizeBodyFromParsedBody(parsedBody, fallbackHeaders);
184
+ fallbackBody = synthesized.body ?? undefined;
185
+ fallbackHeaders.delete("content-length");
186
+
187
+ if (synthesized.contentType) {
188
+ fallbackHeaders.set("content-type", synthesized.contentType);
189
+ }
190
+ } else {
191
+ fallbackBody = undefined;
192
+ }
193
+
194
+ response = await honoApp.fetch(buildRequest(fallbackBody, fallbackHeaders, false));
195
+ } else {
196
+ throw error;
197
+ }
198
+ }
78
199
 
79
200
  res.statusCode = response.status;
80
201
  response.headers.forEach((value, key) => {
@@ -34,8 +34,8 @@ export type GraphQLContext = YogaInitialContext & {
34
34
  };
35
35
 
36
36
  export interface CreateCopilotRuntimeServerOptions {
37
- runtime: CopilotRuntime;
38
- serviceAdapter: CopilotServiceAdapter;
37
+ runtime: CopilotRuntime<any>;
38
+ serviceAdapter?: CopilotServiceAdapter;
39
39
  endpoint: string;
40
40
  baseUrl?: string;
41
41
  cloud?: CopilotCloudOptions;
@@ -1,16 +1,5 @@
1
- import {
2
- RunAgentInput,
3
- EventType,
4
- CustomEvent,
5
- TextMessageStartEvent,
6
- TextMessageContentEvent,
7
- TextMessageEndEvent,
8
- ToolCallStartEvent,
9
- ToolCallArgsEvent,
10
- ToolCallEndEvent,
11
- } from "@ag-ui/client";
12
1
  import { map } from "rxjs";
13
- import { LangGraphEventTypes } from "../../../agents/langgraph/events";
2
+ import { LangGraphEventTypes } from "../../../../agents/langgraph/events";
14
3
  import { RawEvent } from "@ag-ui/core";
15
4
  import {
16
5
  LangGraphAgent as AGUILangGraphAgent,
@@ -31,25 +20,11 @@ interface CopilotKitStateEnrichment {
31
20
  };
32
21
  }
33
22
 
34
- export interface PredictStateTool {
35
- tool: string;
36
- state_key: string;
37
- tool_argument: string;
38
- }
39
-
40
- export type TextMessageEvents =
41
- | TextMessageStartEvent
42
- | TextMessageContentEvent
43
- | TextMessageEndEvent;
23
+ import { RunAgentInput, EventType, CustomEvent } from "@ag-ui/client";
44
24
 
45
- export type ToolCallEvents = ToolCallStartEvent | ToolCallArgsEvent | ToolCallEndEvent;
46
-
47
- export enum CustomEventNames {
48
- CopilotKitManuallyEmitMessage = "copilotkit_manually_emit_message",
49
- CopilotKitManuallyEmitToolCall = "copilotkit_manually_emit_tool_call",
50
- CopilotKitManuallyEmitIntermediateState = "copilotkit_manually_emit_intermediate_state",
51
- CopilotKitExit = "copilotkit_exit",
52
- }
25
+ // Import and re-export from separate file to maintain API compatibility
26
+ import { CustomEventNames, TextMessageEvents, ToolCallEvents, PredictStateTool } from "./consts";
27
+ export { CustomEventNames };
53
28
 
54
29
  export class LangGraphAgent extends AGUILangGraphAgent {
55
30
  constructor(config: LangGraphAgentConfig) {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Constants for LangGraph integration.
3
+ * This file is separate from langgraph.agent.ts to avoid pulling in @ag-ui/langgraph
4
+ * when only these constants are needed.
5
+ */
6
+
7
+ import {
8
+ TextMessageStartEvent,
9
+ TextMessageContentEvent,
10
+ TextMessageEndEvent,
11
+ ToolCallStartEvent,
12
+ ToolCallArgsEvent,
13
+ ToolCallEndEvent,
14
+ } from "@ag-ui/client";
15
+
16
+ export type TextMessageEvents =
17
+ | TextMessageStartEvent
18
+ | TextMessageContentEvent
19
+ | TextMessageEndEvent;
20
+
21
+ export type ToolCallEvents = ToolCallStartEvent | ToolCallArgsEvent | ToolCallEndEvent;
22
+
23
+ export enum CustomEventNames {
24
+ CopilotKitManuallyEmitMessage = "copilotkit_manually_emit_message",
25
+ CopilotKitManuallyEmitToolCall = "copilotkit_manually_emit_tool_call",
26
+ CopilotKitManuallyEmitIntermediateState = "copilotkit_manually_emit_intermediate_state",
27
+ CopilotKitExit = "copilotkit_exit",
28
+ }
29
+
30
+ export interface PredictStateTool {
31
+ tool: string;
32
+ state_key: string;
33
+ tool_argument: string;
34
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./consts";
2
+ export * from "./agent";
@@ -34,10 +34,7 @@ import {
34
34
  } from "@copilotkitnext/runtime";
35
35
 
36
36
  import { MessageInput } from "../../graphql/inputs/message.input";
37
- import { ActionInput } from "../../graphql/inputs/action.input";
38
- import { RuntimeEventSource } from "../../service-adapters/events";
39
37
  import { Message } from "../../graphql/types/converted";
40
- import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
41
38
 
42
39
  import {
43
40
  EndpointType,
@@ -46,19 +43,7 @@ import {
46
43
  LangGraphPlatformEndpoint,
47
44
  } from "./types";
48
45
 
49
- import { GraphQLContext } from "../integrations/shared";
50
- import { AgentSessionInput } from "../../graphql/inputs/agent-session.input";
51
- import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
52
- import { Agent } from "../../graphql/types/agents-response.type";
53
- import { ExtensionsInput } from "../../graphql/inputs/extensions.input";
54
- import { ExtensionsResponse } from "../../graphql/types/extensions-response.type";
55
- import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
56
- import {
57
- CopilotObservabilityConfig,
58
- LLMRequestData,
59
- LLMResponseData,
60
- LLMErrorData,
61
- } from "../observability";
46
+ import { CopilotObservabilityConfig, LLMRequestData, LLMResponseData } from "../observability";
62
47
  import { AbstractAgent } from "@ag-ui/client";
63
48
 
64
49
  // +++ MCP Imports +++
@@ -67,10 +52,7 @@ import {
67
52
  MCPEndpointConfig,
68
53
  MCPTool,
69
54
  extractParametersFromSchema,
70
- convertMCPToolsToActions,
71
- generateMcpToolInstructions,
72
55
  } from "./mcp-tools-utils";
73
- import { LangGraphAgent } from "./agent-integrations/langgraph.agent";
74
56
  import { BasicAgent, BasicAgentConfiguration } from "@copilotkitnext/agent";
75
57
  // Define the function type alias here or import if defined elsewhere
76
58
  type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
@@ -312,8 +294,8 @@ interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []>
312
294
  /**
313
295
  * Central runtime object passed to all request handlers.
314
296
  */
315
- export class CopilotRuntime {
316
- params?: CopilotRuntimeConstructorParams;
297
+ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
298
+ params?: CopilotRuntimeConstructorParams<T>;
317
299
  private observability?: CopilotObservabilityConfig;
318
300
  // Cache MCP tools per endpoint to avoid re-fetching repeatedly
319
301
  private mcpToolsCache: Map<string, BasicAgentConfiguration["tools"]> = new Map();
@@ -321,11 +303,13 @@ export class CopilotRuntime {
321
303
  private _instance: CopilotRuntimeVNext;
322
304
 
323
305
  constructor(
324
- params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
306
+ params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
325
307
  ) {
326
308
  const agents = params?.agents ?? {};
309
+ const endpointAgents = this.assignEndpointsToAgents(params?.remoteEndpoints ?? []);
310
+
327
311
  this.runtimeArgs = {
328
- agents: { ...this.assignEndpointsToAgents(params?.remoteEndpoints ?? []), ...agents },
312
+ agents: { ...endpointAgents, ...agents },
329
313
  runner: params?.runner ?? new InMemoryAgentRunnerVNext(),
330
314
  // TODO: add support for transcriptionService from CopilotRuntimeOptionsVNext once it is ready
331
315
  // transcriptionService: params?.transcriptionService,
@@ -345,28 +329,23 @@ export class CopilotRuntime {
345
329
  return this._instance;
346
330
  }
347
331
 
348
- private assignEndpointsToAgents(endpoints: CopilotRuntimeConstructorParams["remoteEndpoints"]) {
349
- return endpoints.reduce((acc, endpoint) => {
350
- if (resolveEndpointType(endpoint) == EndpointType.LangGraphPlatform) {
351
- let lgAgents = {};
352
- const lgEndpoint = endpoint as LangGraphPlatformEndpoint;
353
- lgEndpoint.agents.forEach((agent) => {
354
- const graphId = agent.assistantId ?? agent.name;
355
- lgAgents[graphId] = new LangGraphAgent({
356
- deploymentUrl: lgEndpoint.deploymentUrl,
357
- langsmithApiKey: lgEndpoint.langsmithApiKey,
358
- graphId,
359
- });
360
- });
332
+ private assignEndpointsToAgents(
333
+ endpoints: CopilotRuntimeConstructorParams<T>["remoteEndpoints"],
334
+ ): Record<string, AbstractAgent> {
335
+ let result: Record<string, AbstractAgent> = {};
361
336
 
362
- return {
363
- ...acc,
364
- ...lgAgents,
365
- };
366
- }
337
+ if (
338
+ endpoints.some((endpoint) => resolveEndpointType(endpoint) == EndpointType.LangGraphPlatform)
339
+ ) {
340
+ throw new CopilotKitMisuseError({
341
+ message:
342
+ "LangGraphPlatformEndpoint in remoteEndpoints is deprecated. " +
343
+ 'Please use the "agents" option instead with LangGraphAgent from "@copilotkit/runtime/langgraph". ' +
344
+ 'Example: agents: { myAgent: new LangGraphAgent({ deploymentUrl: "...", graphId: "..." }) }',
345
+ });
346
+ }
367
347
 
368
- return acc;
369
- }, {});
348
+ return result;
370
349
  }
371
350
 
372
351
  handleServiceAdapter(serviceAdapter: CopilotServiceAdapter) {
@@ -393,7 +372,7 @@ export class CopilotRuntime {
393
372
  });
394
373
  }
395
374
 
396
- if (this.params.actions?.length) {
375
+ if (this.params.actions) {
397
376
  const mcpTools = await this.getToolsFromMCP();
398
377
  agentsList = this.assignToolsToAgents(agents, [
399
378
  ...this.getToolsFromActions(this.params.actions),
@@ -454,7 +433,7 @@ export class CopilotRuntime {
454
433
  }
455
434
 
456
435
  private createOnBeforeRequestHandler(
457
- params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
436
+ params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
458
437
  ) {
459
438
  return async (hookParams: BeforeRequestMiddlewareFnParameters[0]) => {
460
439
  // TODO: get public api key and run with expected data
@@ -492,7 +471,7 @@ export class CopilotRuntime {
492
471
  }
493
472
 
494
473
  private createOnAfterRequestHandler(
495
- params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
474
+ params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
496
475
  ) {
497
476
  return async (hookParams: AfterRequestMiddlewareFnParameters[0]) => {
498
477
  // TODO: get public api key and run with expected data
@@ -22,7 +22,7 @@
22
22
  * });
23
23
  * ```
24
24
  */
25
- import Anthropic from "@anthropic-ai/sdk";
25
+ import type Anthropic from "@anthropic-ai/sdk";
26
26
  import {
27
27
  CopilotServiceAdapter,
28
28
  CopilotRuntimeChatCompletionRequest,
@@ -84,13 +84,25 @@ export class AnthropicAdapter implements CopilotServiceAdapter {
84
84
  }
85
85
 
86
86
  constructor(params?: AnthropicAdapterParams) {
87
- this._anthropic = params?.anthropic || new Anthropic({});
87
+ if (params?.anthropic) {
88
+ this._anthropic = params.anthropic;
89
+ }
90
+ // If no instance provided, we'll lazy-load in ensureAnthropic()
88
91
  if (params?.model) {
89
92
  this.model = params.model;
90
93
  }
91
94
  this.promptCaching = params?.promptCaching || { enabled: false };
92
95
  }
93
96
 
97
+ private ensureAnthropic(): Anthropic {
98
+ if (!this._anthropic) {
99
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
100
+ const Anthropic = require("@anthropic-ai/sdk").default;
101
+ this._anthropic = new Anthropic({});
102
+ }
103
+ return this._anthropic;
104
+ }
105
+
94
106
  /**
95
107
  * Adds cache control to system prompt
96
108
  */
@@ -306,7 +318,8 @@ export class AnthropicAdapter implements CopilotServiceAdapter {
306
318
  stream: true,
307
319
  };
308
320
 
309
- const stream = await this.anthropic.messages.create(createParams);
321
+ const anthropic = this.ensureAnthropic();
322
+ const stream = await anthropic.messages.create(createParams);
310
323
 
311
324
  eventSource.stream(async (eventStream$) => {
312
325
  let mode: "function" | "message" | null = null;
@@ -19,7 +19,6 @@
19
19
  * ```
20
20
  */
21
21
 
22
- import { ChatBedrockConverse } from "@langchain/aws";
23
22
  import { LangChainAdapter } from "../langchain/langchain-adapter";
24
23
 
25
24
  export interface BedrockAdapterParams {
@@ -52,6 +51,10 @@ export class BedrockAdapter extends LangChainAdapter {
52
51
  constructor(options?: BedrockAdapterParams) {
53
52
  super({
54
53
  chainFn: async ({ messages, tools, threadId }) => {
54
+ // Lazy require for optional peer dependency
55
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
56
+ const { ChatBedrockConverse } = require("@langchain/aws");
57
+
55
58
  this.model = options?.model ?? "amazon.nova-lite-v1:0";
56
59
  const model = new ChatBedrockConverse({
57
60
  model: this.model,
@@ -23,7 +23,6 @@ import {
23
23
  CopilotRuntimeChatCompletionRequest,
24
24
  CopilotRuntimeChatCompletionResponse,
25
25
  } from "../../service-adapter";
26
- import { Ollama } from "@langchain/community/llms/ollama";
27
26
  import { randomId, randomUUID } from "@copilotkit/shared";
28
27
 
29
28
  const DEFAULT_MODEL = "llama3:latest";
@@ -53,6 +52,8 @@ export class ExperimentalOllamaAdapter implements CopilotServiceAdapter {
53
52
  const { messages, actions, eventSource } = request;
54
53
  // const messages = this.transformMessages(forwardedProps.messages);
55
54
 
55
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
56
+ const { Ollama } = require("@langchain/community/llms/ollama");
56
57
  const ollama = new Ollama({
57
58
  model: this.model,
58
59
  });
@@ -14,9 +14,7 @@
14
14
  * return new GoogleGenerativeAIAdapter({ model: "gemini-1.5-pro" });
15
15
  * ```
16
16
  */
17
- import { ChatGoogle } from "@langchain/google-gauth";
18
17
  import { LangChainAdapter } from "../langchain/langchain-adapter";
19
- import { AIMessage } from "@langchain/core/messages";
20
18
 
21
19
  interface GoogleGenerativeAIAdapterOptions {
22
20
  /**
@@ -38,6 +36,12 @@ export class GoogleGenerativeAIAdapter extends LangChainAdapter {
38
36
  constructor(options?: GoogleGenerativeAIAdapterOptions) {
39
37
  super({
40
38
  chainFn: async ({ messages, tools, threadId }) => {
39
+ // Lazy require for optional peer dependencies
40
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
41
+ const { ChatGoogle } = require("@langchain/google-gauth");
42
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
43
+ const { AIMessage } = require("@langchain/core/messages");
44
+
41
45
  // Filter out empty assistant messages to prevent Gemini validation errors
42
46
  // Gemini specifically rejects conversations containing AIMessages with empty content
43
47
  const filteredMessages = messages.filter((message) => {
@@ -48,9 +52,10 @@ export class GoogleGenerativeAIAdapter extends LangChainAdapter {
48
52
 
49
53
  // For AIMessages, only keep those with non-empty content
50
54
  // Also keep AIMessages with tool_calls even if content is empty
55
+ const aiMsg = message as any;
51
56
  return (
52
- (message.content && String(message.content).trim().length > 0) ||
53
- (message.tool_calls && message.tool_calls.length > 0)
57
+ (aiMsg.content && String(aiMsg.content).trim().length > 0) ||
58
+ (aiMsg.tool_calls && aiMsg.tool_calls.length > 0)
54
59
  );
55
60
  });
56
61