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

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 (132) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/chunk-2OZAGFV3.mjs +43 -0
  3. package/dist/chunk-2OZAGFV3.mjs.map +1 -0
  4. package/dist/chunk-62NE5S6M.mjs +226 -0
  5. package/dist/chunk-62NE5S6M.mjs.map +1 -0
  6. package/dist/chunk-6XRUR5UK.mjs +1 -0
  7. package/dist/chunk-6XRUR5UK.mjs.map +1 -0
  8. package/dist/chunk-AMUJQ6IR.mjs +50 -0
  9. package/dist/chunk-AMUJQ6IR.mjs.map +1 -0
  10. package/dist/chunk-BJEYMRDD.mjs +25 -0
  11. package/dist/chunk-BJEYMRDD.mjs.map +1 -0
  12. package/dist/chunk-DZV4ZIAR.mjs +3063 -0
  13. package/dist/chunk-DZV4ZIAR.mjs.map +1 -0
  14. package/dist/chunk-FHD4JECV.mjs +33 -0
  15. package/dist/chunk-FHD4JECV.mjs.map +1 -0
  16. package/dist/chunk-FMU55SEU.mjs +25 -0
  17. package/dist/chunk-FMU55SEU.mjs.map +1 -0
  18. package/dist/chunk-OWIGJONH.mjs +275 -0
  19. package/dist/chunk-OWIGJONH.mjs.map +1 -0
  20. package/dist/chunk-SBCOROE4.mjs +1112 -0
  21. package/dist/chunk-SBCOROE4.mjs.map +1 -0
  22. package/dist/chunk-TTUAEJLD.mjs +617 -0
  23. package/dist/chunk-TTUAEJLD.mjs.map +1 -0
  24. package/dist/chunk-XWBDEXDA.mjs +153 -0
  25. package/dist/chunk-XWBDEXDA.mjs.map +1 -0
  26. package/dist/chunk-Z752VE75.mjs +74 -0
  27. package/dist/chunk-Z752VE75.mjs.map +1 -0
  28. package/dist/graphql/message-conversion/index.d.ts +18 -0
  29. package/dist/graphql/message-conversion/index.js +725 -0
  30. package/dist/graphql/message-conversion/index.js.map +1 -0
  31. package/dist/graphql/message-conversion/index.mjs +245 -0
  32. package/dist/graphql/message-conversion/index.mjs.map +1 -0
  33. package/dist/graphql/types/base/index.d.ts +6 -0
  34. package/dist/graphql/types/base/index.js +63 -0
  35. package/dist/graphql/types/base/index.js.map +1 -0
  36. package/dist/graphql/types/base/index.mjs +8 -0
  37. package/dist/graphql/types/base/index.mjs.map +1 -0
  38. package/dist/graphql/types/converted/index.d.ts +2 -0
  39. package/dist/graphql/types/converted/index.js +294 -0
  40. package/dist/graphql/types/converted/index.js.map +1 -0
  41. package/dist/graphql/types/converted/index.mjs +20 -0
  42. package/dist/graphql/types/converted/index.mjs.map +1 -0
  43. package/dist/groq-adapter-50bc6e4a.d.ts +326 -0
  44. package/dist/index-adbd78f1.d.ts +154 -0
  45. package/dist/index.d.ts +136 -287
  46. package/dist/index.js +393 -287
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +385 -276
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/langgraph.d.ts +284 -0
  51. package/dist/langgraph.js +211 -0
  52. package/dist/langgraph.js.map +1 -0
  53. package/dist/langgraph.mjs +206 -0
  54. package/dist/langgraph.mjs.map +1 -0
  55. package/dist/langserve-74a52292.d.ts +242 -0
  56. package/dist/lib/cloud/index.d.ts +6 -0
  57. package/dist/lib/cloud/index.js +18 -0
  58. package/dist/lib/cloud/index.js.map +1 -0
  59. package/dist/lib/cloud/index.mjs +1 -0
  60. package/dist/lib/cloud/index.mjs.map +1 -0
  61. package/dist/lib/index.d.ts +266 -0
  62. package/dist/lib/index.js +4944 -0
  63. package/dist/lib/index.js.map +1 -0
  64. package/dist/lib/index.mjs +74 -0
  65. package/dist/lib/index.mjs.map +1 -0
  66. package/dist/lib/integrations/index.d.ts +28 -0
  67. package/dist/lib/integrations/index.js +3024 -0
  68. package/dist/lib/integrations/index.js.map +1 -0
  69. package/dist/lib/integrations/index.mjs +36 -0
  70. package/dist/lib/integrations/index.mjs.map +1 -0
  71. package/dist/lib/integrations/nest/index.d.ts +16 -0
  72. package/dist/lib/integrations/nest/index.js +2937 -0
  73. package/dist/lib/integrations/nest/index.js.map +1 -0
  74. package/dist/lib/integrations/nest/index.mjs +13 -0
  75. package/dist/lib/integrations/nest/index.mjs.map +1 -0
  76. package/dist/lib/integrations/node-express/index.d.ts +16 -0
  77. package/dist/lib/integrations/node-express/index.js +2937 -0
  78. package/dist/lib/integrations/node-express/index.js.map +1 -0
  79. package/dist/lib/integrations/node-express/index.mjs +13 -0
  80. package/dist/lib/integrations/node-express/index.mjs.map +1 -0
  81. package/dist/lib/integrations/node-http/index.d.ts +16 -0
  82. package/dist/lib/integrations/node-http/index.js +2923 -0
  83. package/dist/lib/integrations/node-http/index.js.map +1 -0
  84. package/dist/lib/integrations/node-http/index.mjs +12 -0
  85. package/dist/lib/integrations/node-http/index.mjs.map +1 -0
  86. package/dist/service-adapters/index.d.ts +166 -0
  87. package/dist/service-adapters/index.js +1800 -0
  88. package/dist/service-adapters/index.js.map +1 -0
  89. package/dist/service-adapters/index.mjs +36 -0
  90. package/dist/service-adapters/index.mjs.map +1 -0
  91. package/dist/service-adapters/shared/index.d.ts +9 -0
  92. package/dist/service-adapters/shared/index.js +72 -0
  93. package/dist/service-adapters/shared/index.js.map +1 -0
  94. package/dist/service-adapters/shared/index.mjs +8 -0
  95. package/dist/service-adapters/shared/index.mjs.map +1 -0
  96. package/dist/shared-f6d43ef8.d.ts +446 -0
  97. package/dist/utils/index.d.ts +65 -0
  98. package/dist/utils/index.js +175 -0
  99. package/dist/utils/index.js.map +1 -0
  100. package/dist/utils/index.mjs +12 -0
  101. package/dist/utils/index.mjs.map +1 -0
  102. package/dist/v2/index.d.ts +1 -0
  103. package/dist/v2/index.js +7 -0
  104. package/dist/v2/index.js.map +1 -1
  105. package/dist/v2/index.mjs +1 -0
  106. package/dist/v2/index.mjs.map +1 -1
  107. package/package.json +56 -18
  108. package/src/graphql/message-conversion/agui-to-gql.test.ts +2 -2
  109. package/src/graphql/message-conversion/gql-to-agui.test.ts +30 -28
  110. package/src/graphql/message-conversion/roundtrip-conversion.test.ts +8 -8
  111. package/src/langgraph.ts +1 -0
  112. package/src/lib/index.ts +42 -1
  113. package/src/lib/integrations/nextjs/app-router.ts +3 -1
  114. package/src/lib/integrations/node-http/index.ts +132 -11
  115. package/src/lib/integrations/shared.ts +2 -2
  116. package/src/lib/runtime/agent-integrations/{langgraph.agent.ts → langgraph/agent.ts} +5 -30
  117. package/src/lib/runtime/agent-integrations/langgraph/consts.ts +34 -0
  118. package/src/lib/runtime/agent-integrations/langgraph/index.ts +2 -0
  119. package/src/lib/runtime/copilot-runtime.ts +51 -68
  120. package/src/lib/runtime/telemetry-agent-runner.ts +134 -0
  121. package/src/service-adapters/anthropic/anthropic-adapter.ts +16 -3
  122. package/src/service-adapters/bedrock/bedrock-adapter.ts +4 -1
  123. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +2 -1
  124. package/src/service-adapters/google/google-genai-adapter.ts +9 -4
  125. package/src/service-adapters/groq/groq-adapter.ts +16 -3
  126. package/src/service-adapters/langchain/langchain-adapter.ts +5 -3
  127. package/src/service-adapters/langchain/langserve.ts +2 -1
  128. package/src/service-adapters/openai/openai-adapter.ts +17 -3
  129. package/src/service-adapters/openai/openai-assistant-adapter.ts +26 -11
  130. package/src/service-adapters/unify/unify-adapter.ts +3 -1
  131. package/src/v2/index.ts +1 -0
  132. package/tsup.config.ts +5 -2
@@ -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";
@@ -13,65 +13,47 @@
13
13
  */
14
14
 
15
15
  import {
16
- Action,
17
- CopilotErrorHandler,
16
+ type Action,
17
+ type CopilotErrorHandler,
18
18
  CopilotKitMisuseError,
19
- MaybePromise,
20
- NonEmptyRecord,
21
- Parameter,
19
+ type MaybePromise,
20
+ type NonEmptyRecord,
21
+ type Parameter,
22
22
  readBody,
23
23
  getZodParameters,
24
- PartialBy,
24
+ type PartialBy,
25
25
  } from "@copilotkit/shared";
26
- import { type RunAgentInput } from "@ag-ui/core";
26
+ import type { RunAgentInput } from "@ag-ui/core";
27
27
  import { aguiToGQL } from "../../graphql/message-conversion/agui-to-gql";
28
- import { CopilotServiceAdapter, RemoteChainParameters } from "../../service-adapters";
28
+ import type { CopilotServiceAdapter, RemoteChainParameters } from "../../service-adapters";
29
29
  import {
30
30
  CopilotRuntime as CopilotRuntimeVNext,
31
- CopilotRuntimeOptions,
32
- CopilotRuntimeOptions as CopilotRuntimeOptionsVNext,
33
- InMemoryAgentRunner as InMemoryAgentRunnerVNext,
31
+ type CopilotRuntimeOptions,
32
+ type CopilotRuntimeOptions as CopilotRuntimeOptionsVNext,
34
33
  } from "@copilotkitnext/runtime";
34
+ import { TelemetryAgentRunner } from "./telemetry-agent-runner";
35
35
 
36
- import { MessageInput } from "../../graphql/inputs/message.input";
37
- import { ActionInput } from "../../graphql/inputs/action.input";
38
- import { RuntimeEventSource } from "../../service-adapters/events";
39
- import { Message } from "../../graphql/types/converted";
40
- import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
36
+ import type { MessageInput } from "../../graphql/inputs/message.input";
37
+ import type { Message } from "../../graphql/types/converted";
41
38
 
42
39
  import {
43
40
  EndpointType,
44
- EndpointDefinition,
45
- CopilotKitEndpoint,
46
- LangGraphPlatformEndpoint,
41
+ type EndpointDefinition,
42
+ type CopilotKitEndpoint,
43
+ type 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";
62
- import { AbstractAgent } from "@ag-ui/client";
46
+ import type { CopilotObservabilityConfig, LLMRequestData, LLMResponseData } from "../observability";
47
+ import type { AbstractAgent } from "@ag-ui/client";
63
48
 
64
49
  // +++ MCP Imports +++
65
50
  import {
66
- MCPClient,
67
- MCPEndpointConfig,
68
- MCPTool,
51
+ type MCPClient,
52
+ type MCPEndpointConfig,
53
+ type MCPTool,
69
54
  extractParametersFromSchema,
70
- convertMCPToolsToActions,
71
- generateMcpToolInstructions,
72
55
  } from "./mcp-tools-utils";
73
- import { LangGraphAgent } from "./agent-integrations/langgraph.agent";
74
- import { BasicAgent, BasicAgentConfiguration } from "@copilotkitnext/agent";
56
+ import { BasicAgent, type 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>;
77
59
 
@@ -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,12 +303,16 @@ 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 },
329
- runner: params?.runner ?? new InMemoryAgentRunnerVNext(),
312
+ agents: { ...endpointAgents, ...agents },
313
+ // Use TelemetryAgentRunner by default to track agent execution telemetry
314
+ // Users can pass their own runner which will be wrapped for telemetry
315
+ runner: params?.runner ?? new TelemetryAgentRunner(),
330
316
  // TODO: add support for transcriptionService from CopilotRuntimeOptionsVNext once it is ready
331
317
  // transcriptionService: params?.transcriptionService,
332
318
 
@@ -345,28 +331,23 @@ export class CopilotRuntime {
345
331
  return this._instance;
346
332
  }
347
333
 
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
- });
334
+ private assignEndpointsToAgents(
335
+ endpoints: CopilotRuntimeConstructorParams<T>["remoteEndpoints"],
336
+ ): Record<string, AbstractAgent> {
337
+ let result: Record<string, AbstractAgent> = {};
361
338
 
362
- return {
363
- ...acc,
364
- ...lgAgents,
365
- };
366
- }
339
+ if (
340
+ endpoints.some((endpoint) => resolveEndpointType(endpoint) == EndpointType.LangGraphPlatform)
341
+ ) {
342
+ throw new CopilotKitMisuseError({
343
+ message:
344
+ "LangGraphPlatformEndpoint in remoteEndpoints is deprecated. " +
345
+ 'Please use the "agents" option instead with LangGraphAgent from "@copilotkit/runtime/langgraph". ' +
346
+ 'Example: agents: { myAgent: new LangGraphAgent({ deploymentUrl: "...", graphId: "..." }) }',
347
+ });
348
+ }
367
349
 
368
- return acc;
369
- }, {});
350
+ return result;
370
351
  }
371
352
 
372
353
  handleServiceAdapter(serviceAdapter: CopilotServiceAdapter) {
@@ -393,7 +374,7 @@ export class CopilotRuntime {
393
374
  });
394
375
  }
395
376
 
396
- if (this.params.actions?.length) {
377
+ if (this.params.actions) {
397
378
  const mcpTools = await this.getToolsFromMCP();
398
379
  agentsList = this.assignToolsToAgents(agents, [
399
380
  ...this.getToolsFromActions(this.params.actions),
@@ -423,6 +404,7 @@ export class CopilotRuntime {
423
404
  name: action.name,
424
405
  description: action.description || "",
425
406
  parameters: zodSchema,
407
+ execute: () => Promise.resolve(),
426
408
  };
427
409
  });
428
410
  }
@@ -454,7 +436,7 @@ export class CopilotRuntime {
454
436
  }
455
437
 
456
438
  private createOnBeforeRequestHandler(
457
- params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
439
+ params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
458
440
  ) {
459
441
  return async (hookParams: BeforeRequestMiddlewareFnParameters[0]) => {
460
442
  // TODO: get public api key and run with expected data
@@ -492,7 +474,7 @@ export class CopilotRuntime {
492
474
  }
493
475
 
494
476
  private createOnAfterRequestHandler(
495
- params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
477
+ params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
496
478
  ) {
497
479
  return async (hookParams: AfterRequestMiddlewareFnParameters[0]) => {
498
480
  // TODO: get public api key and run with expected data
@@ -636,6 +618,7 @@ export class CopilotRuntime {
636
618
  name: toolName,
637
619
  description: tool.description || `MCP tool: ${toolName} (from ${endpointUrl})`,
638
620
  parameters: zodSchema,
621
+ execute: () => Promise.resolve(),
639
622
  };
640
623
  },
641
624
  );
@@ -0,0 +1,134 @@
1
+ /**
2
+ * TelemetryAgentRunner - A wrapper around AgentRunner that adds telemetry
3
+ * for agent execution streams.
4
+ *
5
+ * This captures the following telemetry events:
6
+ * - oss.runtime.agent_execution_stream_started - when an agent execution starts
7
+ * - oss.runtime.agent_execution_stream_ended - when an agent execution completes
8
+ * - oss.runtime.agent_execution_stream_errored - when an agent execution fails
9
+ */
10
+
11
+ import { type AgentRunner, InMemoryAgentRunner } from "@copilotkitnext/runtime";
12
+ import { createHash } from "node:crypto";
13
+ import { tap, catchError, finalize } from "rxjs";
14
+ import telemetry from "../telemetry-client";
15
+ import type { AgentExecutionResponseInfo } from "@copilotkit/shared/src/telemetry/events";
16
+
17
+ /**
18
+ * Configuration options for TelemetryAgentRunner
19
+ */
20
+ export interface TelemetryAgentRunnerConfig {
21
+ /**
22
+ * The underlying runner to delegate to
23
+ * If not provided, defaults to InMemoryAgentRunner
24
+ */
25
+ runner?: AgentRunner;
26
+
27
+ /**
28
+ * Optional LangSmith API key (will be hashed for telemetry)
29
+ */
30
+ langsmithApiKey?: string;
31
+ }
32
+
33
+ /**
34
+ * An AgentRunner wrapper that adds telemetry tracking for agent executions.
35
+ *
36
+ * Usage:
37
+ * ```ts
38
+ * const runtime = new CopilotRuntime({
39
+ * runner: new TelemetryAgentRunner(),
40
+ * // or with custom runner:
41
+ * runner: new TelemetryAgentRunner({ runner: customRunner }),
42
+ * });
43
+ * ```
44
+ */
45
+ export class TelemetryAgentRunner implements AgentRunner {
46
+ private readonly _runner: AgentRunner;
47
+ private readonly hashedLgcKey: string | undefined;
48
+
49
+ constructor(config?: TelemetryAgentRunnerConfig) {
50
+ this._runner = config?.runner ?? new InMemoryAgentRunner();
51
+ this.hashedLgcKey = config?.langsmithApiKey
52
+ ? createHash("sha256").update(config.langsmithApiKey).digest("hex")
53
+ : undefined;
54
+ }
55
+
56
+ /**
57
+ * Runs an agent with telemetry tracking.
58
+ * Wraps the underlying runner's Observable stream with telemetry events.
59
+ */
60
+ run(
61
+ ...args: Parameters<AgentRunner["run"]>
62
+ ): ReturnType<AgentRunner["run"]> {
63
+ const streamInfo: AgentExecutionResponseInfo = {
64
+ hashedLgcKey: this.hashedLgcKey,
65
+ };
66
+ let streamErrored = false;
67
+
68
+ // Capture stream started event
69
+ telemetry.capture("oss.runtime.agent_execution_stream_started", {
70
+ hashedLgcKey: this.hashedLgcKey,
71
+ });
72
+
73
+ // Delegate to the underlying runner and wrap with telemetry
74
+ return this._runner.run(...args).pipe(
75
+ // Extract metadata from events if available
76
+ tap((event) => {
77
+ // Try to extract provider/model info from raw events
78
+ const rawEvent = (event as { rawEvent?: { metadata?: Record<string, unknown>; data?: Record<string, unknown> } }).rawEvent;
79
+ if (rawEvent?.data) {
80
+ const data = rawEvent.data as { output?: { model?: string } };
81
+ if (data?.output?.model) {
82
+ streamInfo.model = data.output.model;
83
+ streamInfo.provider = data.output.model;
84
+ }
85
+ }
86
+ if (rawEvent?.metadata) {
87
+ const metadata = rawEvent.metadata as { langgraph_host?: string; langgraph_version?: string };
88
+ if (metadata?.langgraph_host) {
89
+ streamInfo.langGraphHost = metadata.langgraph_host;
90
+ }
91
+ if (metadata?.langgraph_version) {
92
+ streamInfo.langGraphVersion = metadata.langgraph_version;
93
+ }
94
+ }
95
+ }),
96
+ catchError((error) => {
97
+ // Capture stream error event
98
+ streamErrored = true;
99
+ telemetry.capture("oss.runtime.agent_execution_stream_errored", {
100
+ ...streamInfo,
101
+ error: error instanceof Error ? error.message : String(error),
102
+ });
103
+ throw error;
104
+ }),
105
+ finalize(() => {
106
+ // Capture stream ended event (only if not errored)
107
+ if (!streamErrored) {
108
+ telemetry.capture("oss.runtime.agent_execution_stream_ended", streamInfo);
109
+ }
110
+ }),
111
+ );
112
+ }
113
+
114
+ /**
115
+ * Delegates to the underlying runner's connect method
116
+ */
117
+ connect(...args: Parameters<AgentRunner["connect"]>): ReturnType<AgentRunner["connect"]> {
118
+ return this._runner.connect(...args);
119
+ }
120
+
121
+ /**
122
+ * Delegates to the underlying runner's isRunning method
123
+ */
124
+ isRunning(...args: Parameters<AgentRunner["isRunning"]>): ReturnType<AgentRunner["isRunning"]> {
125
+ return this._runner.isRunning(...args);
126
+ }
127
+
128
+ /**
129
+ * Delegates to the underlying runner's stop method
130
+ */
131
+ stop(...args: Parameters<AgentRunner["stop"]>): ReturnType<AgentRunner["stop"]> {
132
+ return this._runner.stop(...args);
133
+ }
134
+ }
@@ -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,