@copilotkit/runtime 0.0.0-test-custom-tag-prerelease-1-20250108200215

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 (146) hide show
  1. package/.eslintrc.js +7 -0
  2. package/CHANGELOG.md +729 -0
  3. package/README.md +46 -0
  4. package/__snapshots__/schema/schema.graphql +262 -0
  5. package/dist/chunk-2WXVJKUZ.mjs +25 -0
  6. package/dist/chunk-2WXVJKUZ.mjs.map +1 -0
  7. package/dist/chunk-44O2JGUY.mjs +12 -0
  8. package/dist/chunk-44O2JGUY.mjs.map +1 -0
  9. package/dist/chunk-CLGKEUOA.mjs +1408 -0
  10. package/dist/chunk-CLGKEUOA.mjs.map +1 -0
  11. package/dist/chunk-D2WLFQS6.mjs +43 -0
  12. package/dist/chunk-D2WLFQS6.mjs.map +1 -0
  13. package/dist/chunk-DFOKBSIS.mjs +1 -0
  14. package/dist/chunk-DFOKBSIS.mjs.map +1 -0
  15. package/dist/chunk-RFF5IIZJ.mjs +66 -0
  16. package/dist/chunk-RFF5IIZJ.mjs.map +1 -0
  17. package/dist/chunk-U3V2BCGI.mjs +152 -0
  18. package/dist/chunk-U3V2BCGI.mjs.map +1 -0
  19. package/dist/chunk-UYX3NHOI.mjs +25 -0
  20. package/dist/chunk-UYX3NHOI.mjs.map +1 -0
  21. package/dist/chunk-W3GSZTZR.mjs +3281 -0
  22. package/dist/chunk-W3GSZTZR.mjs.map +1 -0
  23. package/dist/chunk-WPNQ4AMN.mjs +80 -0
  24. package/dist/chunk-WPNQ4AMN.mjs.map +1 -0
  25. package/dist/copilot-runtime-6285d897.d.ts +189 -0
  26. package/dist/graphql/types/base/index.d.ts +6 -0
  27. package/dist/graphql/types/base/index.js +63 -0
  28. package/dist/graphql/types/base/index.js.map +1 -0
  29. package/dist/graphql/types/base/index.mjs +8 -0
  30. package/dist/graphql/types/base/index.mjs.map +1 -0
  31. package/dist/graphql/types/converted/index.d.ts +2 -0
  32. package/dist/graphql/types/converted/index.js +124 -0
  33. package/dist/graphql/types/converted/index.js.map +1 -0
  34. package/dist/graphql/types/converted/index.mjs +17 -0
  35. package/dist/graphql/types/converted/index.mjs.map +1 -0
  36. package/dist/groq-adapter-15d41154.d.ts +281 -0
  37. package/dist/index-ff3fbc33.d.ts +87 -0
  38. package/dist/index.d.ts +23 -0
  39. package/dist/index.js +5039 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/index.mjs +76 -0
  42. package/dist/index.mjs.map +1 -0
  43. package/dist/langserve-48e976ac.d.ts +176 -0
  44. package/dist/lib/cloud/index.d.ts +6 -0
  45. package/dist/lib/cloud/index.js +18 -0
  46. package/dist/lib/cloud/index.js.map +1 -0
  47. package/dist/lib/cloud/index.mjs +1 -0
  48. package/dist/lib/cloud/index.mjs.map +1 -0
  49. package/dist/lib/index.d.ts +20 -0
  50. package/dist/lib/index.js +4687 -0
  51. package/dist/lib/index.js.map +1 -0
  52. package/dist/lib/index.mjs +58 -0
  53. package/dist/lib/index.mjs.map +1 -0
  54. package/dist/lib/integrations/index.d.ts +33 -0
  55. package/dist/lib/integrations/index.js +2091 -0
  56. package/dist/lib/integrations/index.js.map +1 -0
  57. package/dist/lib/integrations/index.mjs +34 -0
  58. package/dist/lib/integrations/index.mjs.map +1 -0
  59. package/dist/lib/integrations/nest/index.d.ts +14 -0
  60. package/dist/lib/integrations/nest/index.js +2000 -0
  61. package/dist/lib/integrations/nest/index.js.map +1 -0
  62. package/dist/lib/integrations/nest/index.mjs +13 -0
  63. package/dist/lib/integrations/nest/index.mjs.map +1 -0
  64. package/dist/lib/integrations/node-express/index.d.ts +14 -0
  65. package/dist/lib/integrations/node-express/index.js +2000 -0
  66. package/dist/lib/integrations/node-express/index.js.map +1 -0
  67. package/dist/lib/integrations/node-express/index.mjs +13 -0
  68. package/dist/lib/integrations/node-express/index.mjs.map +1 -0
  69. package/dist/lib/integrations/node-http/index.d.ts +14 -0
  70. package/dist/lib/integrations/node-http/index.js +1986 -0
  71. package/dist/lib/integrations/node-http/index.js.map +1 -0
  72. package/dist/lib/integrations/node-http/index.mjs +12 -0
  73. package/dist/lib/integrations/node-http/index.mjs.map +1 -0
  74. package/dist/service-adapters/index.d.ts +84 -0
  75. package/dist/service-adapters/index.js +1448 -0
  76. package/dist/service-adapters/index.js.map +1 -0
  77. package/dist/service-adapters/index.mjs +26 -0
  78. package/dist/service-adapters/index.mjs.map +1 -0
  79. package/dist/utils/index.d.ts +49 -0
  80. package/dist/utils/index.js +174 -0
  81. package/dist/utils/index.js.map +1 -0
  82. package/dist/utils/index.mjs +12 -0
  83. package/dist/utils/index.mjs.map +1 -0
  84. package/jest.config.js +5 -0
  85. package/package.json +85 -0
  86. package/scripts/generate-gql-schema.ts +13 -0
  87. package/src/agents/langgraph/event-source.ts +287 -0
  88. package/src/agents/langgraph/events.ts +338 -0
  89. package/src/graphql/inputs/action.input.ts +16 -0
  90. package/src/graphql/inputs/agent-session.input.ts +13 -0
  91. package/src/graphql/inputs/agent-state.input.ts +10 -0
  92. package/src/graphql/inputs/cloud-guardrails.input.ts +16 -0
  93. package/src/graphql/inputs/cloud.input.ts +8 -0
  94. package/src/graphql/inputs/context-property.input.ts +10 -0
  95. package/src/graphql/inputs/custom-property.input.ts +15 -0
  96. package/src/graphql/inputs/forwarded-parameters.input.ts +22 -0
  97. package/src/graphql/inputs/frontend.input.ts +14 -0
  98. package/src/graphql/inputs/generate-copilot-response.input.ts +47 -0
  99. package/src/graphql/inputs/message.input.ts +92 -0
  100. package/src/graphql/resolvers/copilot.resolver.ts +540 -0
  101. package/src/graphql/types/base/index.ts +10 -0
  102. package/src/graphql/types/converted/index.ts +70 -0
  103. package/src/graphql/types/copilot-response.type.ts +113 -0
  104. package/src/graphql/types/enums.ts +37 -0
  105. package/src/graphql/types/guardrails-result.type.ts +20 -0
  106. package/src/graphql/types/message-status.type.ts +40 -0
  107. package/src/graphql/types/response-status.type.ts +66 -0
  108. package/src/index.ts +4 -0
  109. package/src/lib/cloud/index.ts +4 -0
  110. package/src/lib/index.ts +8 -0
  111. package/src/lib/integrations/index.ts +6 -0
  112. package/src/lib/integrations/nest/index.ts +17 -0
  113. package/src/lib/integrations/nextjs/app-router.ts +40 -0
  114. package/src/lib/integrations/nextjs/pages-router.ts +49 -0
  115. package/src/lib/integrations/node-express/index.ts +17 -0
  116. package/src/lib/integrations/node-http/index.ts +34 -0
  117. package/src/lib/integrations/shared.ts +109 -0
  118. package/src/lib/logger.ts +28 -0
  119. package/src/lib/runtime/copilot-runtime.ts +412 -0
  120. package/src/lib/runtime/remote-action-constructors.ts +304 -0
  121. package/src/lib/runtime/remote-actions.ts +174 -0
  122. package/src/lib/runtime/remote-lg-action.ts +657 -0
  123. package/src/lib/telemetry-client.ts +52 -0
  124. package/src/service-adapters/anthropic/anthropic-adapter.ts +205 -0
  125. package/src/service-adapters/anthropic/utils.ts +144 -0
  126. package/src/service-adapters/conversion.ts +64 -0
  127. package/src/service-adapters/events.ts +377 -0
  128. package/src/service-adapters/experimental/empty/empty-adapter.ts +33 -0
  129. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +79 -0
  130. package/src/service-adapters/google/google-genai-adapter.ts +39 -0
  131. package/src/service-adapters/groq/groq-adapter.ts +173 -0
  132. package/src/service-adapters/index.ts +16 -0
  133. package/src/service-adapters/langchain/langchain-adapter.ts +99 -0
  134. package/src/service-adapters/langchain/langserve.ts +87 -0
  135. package/src/service-adapters/langchain/types.ts +14 -0
  136. package/src/service-adapters/langchain/utils.ts +306 -0
  137. package/src/service-adapters/openai/openai-adapter.ts +210 -0
  138. package/src/service-adapters/openai/openai-assistant-adapter.ts +304 -0
  139. package/src/service-adapters/openai/utils.ts +161 -0
  140. package/src/service-adapters/service-adapter.ts +30 -0
  141. package/src/service-adapters/unify/unify-adapter.ts +145 -0
  142. package/src/utils/failed-response-status-reasons.ts +48 -0
  143. package/src/utils/index.ts +1 -0
  144. package/tsconfig.json +11 -0
  145. package/tsup.config.ts +16 -0
  146. package/typedoc.json +4 -0
@@ -0,0 +1,412 @@
1
+ /**
2
+ * <Callout type="info">
3
+ * This is the reference for the `CopilotRuntime` class. For more information and example code snippets, please see [Concept: Copilot Runtime](/concepts/copilot-runtime).
4
+ * </Callout>
5
+ *
6
+ * ## Usage
7
+ *
8
+ * ```tsx
9
+ * import { CopilotRuntime } from "@copilotkit/runtime";
10
+ *
11
+ * const copilotKit = new CopilotRuntime();
12
+ * ```
13
+ */
14
+
15
+ import { Action, actionParametersToJsonSchema, Parameter, randomId } from "@copilotkit/shared";
16
+ import { CopilotServiceAdapter, RemoteChain, RemoteChainParameters } from "../../service-adapters";
17
+ import { MessageInput } from "../../graphql/inputs/message.input";
18
+ import { ActionInput } from "../../graphql/inputs/action.input";
19
+ import { RuntimeEventSource } from "../../service-adapters/events";
20
+ import { convertGqlInputToMessages } from "../../service-adapters/conversion";
21
+ import { Message } from "../../graphql/types/converted";
22
+ import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
23
+ import {
24
+ isLangGraphAgentAction,
25
+ LangGraphAgentAction,
26
+ EndpointType,
27
+ setupRemoteActions,
28
+ EndpointDefinition,
29
+ CopilotKitEndpoint,
30
+ LangGraphPlatformEndpoint,
31
+ } from "./remote-actions";
32
+ import { GraphQLContext } from "../integrations/shared";
33
+ import { AgentSessionInput } from "../../graphql/inputs/agent-session.input";
34
+ import { from } from "rxjs";
35
+ import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
36
+ import { ActionInputAvailability } from "../../graphql/types/enums";
37
+
38
+ interface CopilotRuntimeRequest {
39
+ serviceAdapter: CopilotServiceAdapter;
40
+ messages: MessageInput[];
41
+ actions: ActionInput[];
42
+ agentSession?: AgentSessionInput;
43
+ agentStates?: AgentStateInput[];
44
+ outputMessagesPromise: Promise<Message[]>;
45
+ threadId?: string;
46
+ runId?: string;
47
+ publicApiKey?: string;
48
+ graphqlContext: GraphQLContext;
49
+ forwardedParameters?: ForwardedParametersInput;
50
+ url?: string;
51
+ }
52
+
53
+ interface CopilotRuntimeResponse {
54
+ threadId: string;
55
+ runId?: string;
56
+ eventSource: RuntimeEventSource;
57
+ serverSideActions: Action<any>[];
58
+ actionInputsWithoutAgents: ActionInput[];
59
+ }
60
+
61
+ type ActionsConfiguration<T extends Parameter[] | [] = []> =
62
+ | Action<T>[]
63
+ | ((ctx: { properties: any; url?: string }) => Action<T>[]);
64
+
65
+ interface OnBeforeRequestOptions {
66
+ threadId?: string;
67
+ runId?: string;
68
+ inputMessages: Message[];
69
+ properties: any;
70
+ url?: string;
71
+ }
72
+
73
+ type OnBeforeRequestHandler = (options: OnBeforeRequestOptions) => void | Promise<void>;
74
+
75
+ interface OnAfterRequestOptions {
76
+ threadId: string;
77
+ runId?: string;
78
+ inputMessages: Message[];
79
+ outputMessages: Message[];
80
+ properties: any;
81
+ url?: string;
82
+ }
83
+
84
+ type OnAfterRequestHandler = (options: OnAfterRequestOptions) => void | Promise<void>;
85
+
86
+ interface Middleware {
87
+ /**
88
+ * A function that is called before the request is processed.
89
+ */
90
+ onBeforeRequest?: OnBeforeRequestHandler;
91
+
92
+ /**
93
+ * A function that is called after the request is processed.
94
+ */
95
+ onAfterRequest?: OnAfterRequestHandler;
96
+ }
97
+
98
+ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []> {
99
+ /**
100
+ * Middleware to be used by the runtime.
101
+ *
102
+ * ```ts
103
+ * onBeforeRequest: (options: {
104
+ * threadId?: string;
105
+ * runId?: string;
106
+ * inputMessages: Message[];
107
+ * properties: any;
108
+ * }) => void | Promise<void>;
109
+ * ```
110
+ *
111
+ * ```ts
112
+ * onAfterRequest: (options: {
113
+ * threadId?: string;
114
+ * runId?: string;
115
+ * inputMessages: Message[];
116
+ * outputMessages: Message[];
117
+ * properties: any;
118
+ * }) => void | Promise<void>;
119
+ * ```
120
+ */
121
+ middleware?: Middleware;
122
+
123
+ /*
124
+ * A list of server side actions that can be executed.
125
+ */
126
+ actions?: ActionsConfiguration<T>;
127
+
128
+ /*
129
+ * Deprecated: Use `remoteEndpoints`.
130
+ */
131
+ remoteActions?: CopilotKitEndpoint[];
132
+
133
+ /*
134
+ * A list of remote actions that can be executed.
135
+ */
136
+ remoteEndpoints?: EndpointDefinition[];
137
+
138
+ /*
139
+ * An array of LangServer URLs.
140
+ */
141
+ langserve?: RemoteChainParameters[];
142
+ }
143
+
144
+ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
145
+ public actions: ActionsConfiguration<T>;
146
+ public remoteEndpointDefinitions: EndpointDefinition[];
147
+ private langserve: Promise<Action<any>>[] = [];
148
+ private onBeforeRequest?: OnBeforeRequestHandler;
149
+ private onAfterRequest?: OnAfterRequestHandler;
150
+
151
+ constructor(params?: CopilotRuntimeConstructorParams<T>) {
152
+ this.actions = params?.actions || [];
153
+
154
+ for (const chain of params?.langserve || []) {
155
+ const remoteChain = new RemoteChain(chain);
156
+ this.langserve.push(remoteChain.toAction());
157
+ }
158
+
159
+ this.remoteEndpointDefinitions = params?.remoteEndpoints ?? params?.remoteActions ?? [];
160
+
161
+ this.onBeforeRequest = params?.middleware?.onBeforeRequest;
162
+ this.onAfterRequest = params?.middleware?.onAfterRequest;
163
+ }
164
+
165
+ async processRuntimeRequest(request: CopilotRuntimeRequest): Promise<CopilotRuntimeResponse> {
166
+ const {
167
+ serviceAdapter,
168
+ messages: rawMessages,
169
+ actions: clientSideActionsInput,
170
+ threadId,
171
+ runId,
172
+ outputMessagesPromise,
173
+ graphqlContext,
174
+ forwardedParameters,
175
+ agentSession,
176
+ url,
177
+ } = request;
178
+
179
+ const eventSource = new RuntimeEventSource();
180
+
181
+ try {
182
+ if (agentSession) {
183
+ return await this.processAgentRequest(request);
184
+ }
185
+
186
+ const messages = rawMessages.filter((message) => !message.agentStateMessage);
187
+
188
+ const inputMessages = convertGqlInputToMessages(messages);
189
+ const serverSideActions = await this.getServerSideActions(request);
190
+
191
+ const serverSideActionsInput: ActionInput[] = serverSideActions.map((action) => ({
192
+ name: action.name,
193
+ description: action.description,
194
+ jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters)),
195
+ }));
196
+
197
+ const actionInputs = flattenToolCallsNoDuplicates([
198
+ ...serverSideActionsInput,
199
+ ...clientSideActionsInput.filter(
200
+ // Filter remote actions from CopilotKit core loop
201
+ (action) => action.available !== ActionInputAvailability.remote,
202
+ ),
203
+ ]);
204
+
205
+ await this.onBeforeRequest?.({
206
+ threadId,
207
+ runId,
208
+ inputMessages,
209
+ properties: graphqlContext.properties,
210
+ url,
211
+ });
212
+
213
+ const result = await serviceAdapter.process({
214
+ messages: inputMessages,
215
+ actions: actionInputs,
216
+ threadId,
217
+ runId,
218
+ eventSource,
219
+ forwardedParameters,
220
+ });
221
+
222
+ outputMessagesPromise
223
+ .then((outputMessages) => {
224
+ this.onAfterRequest?.({
225
+ threadId: result.threadId,
226
+ runId: result.runId,
227
+ inputMessages,
228
+ outputMessages,
229
+ properties: graphqlContext.properties,
230
+ url,
231
+ });
232
+ })
233
+ .catch((_error) => {});
234
+
235
+ return {
236
+ threadId: result.threadId,
237
+ runId: result.runId,
238
+ eventSource,
239
+ serverSideActions,
240
+ actionInputsWithoutAgents: actionInputs.filter(
241
+ (action) =>
242
+ // TODO-AGENTS: do not exclude ALL server side actions
243
+ !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
244
+ // !isLangGraphAgentAction(
245
+ // serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
246
+ // ),
247
+ ),
248
+ };
249
+ } catch (error) {
250
+ console.error("Error getting response:", error);
251
+ eventSource.sendErrorMessageToChat();
252
+ throw error;
253
+ }
254
+ }
255
+
256
+ private async processAgentRequest(
257
+ request: CopilotRuntimeRequest,
258
+ ): Promise<CopilotRuntimeResponse> {
259
+ const { messages: rawMessages, outputMessagesPromise, graphqlContext, agentSession } = request;
260
+ const { threadId, agentName, nodeName } = agentSession;
261
+ const serverSideActions = await this.getServerSideActions(request);
262
+
263
+ const messages = convertGqlInputToMessages(rawMessages);
264
+
265
+ const agent = serverSideActions.find(
266
+ (action) => action.name === agentName && isLangGraphAgentAction(action),
267
+ ) as LangGraphAgentAction;
268
+
269
+ if (!agent) {
270
+ throw new Error(`Agent ${agentName} not found`);
271
+ }
272
+
273
+ const serverSideActionsInput: ActionInput[] = serverSideActions
274
+ .filter((action) => !isLangGraphAgentAction(action))
275
+ .map((action) => ({
276
+ name: action.name,
277
+ description: action.description,
278
+ jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters)),
279
+ }));
280
+
281
+ const actionInputsWithoutAgents = flattenToolCallsNoDuplicates([
282
+ ...serverSideActionsInput,
283
+ ...request.actions,
284
+ ]);
285
+
286
+ await this.onBeforeRequest?.({
287
+ threadId,
288
+ runId: undefined,
289
+ inputMessages: messages,
290
+ properties: graphqlContext.properties,
291
+ });
292
+ try {
293
+ const eventSource = new RuntimeEventSource();
294
+ const stream = await agent.langGraphAgentHandler({
295
+ name: agentName,
296
+ threadId,
297
+ nodeName,
298
+ actionInputsWithoutAgents,
299
+ });
300
+
301
+ eventSource.stream(async (eventStream$) => {
302
+ from(stream).subscribe({
303
+ next: (event) => eventStream$.next(event),
304
+ error: (err) => console.error("Error in stream", err),
305
+ complete: () => eventStream$.complete(),
306
+ });
307
+ });
308
+
309
+ outputMessagesPromise
310
+ .then((outputMessages) => {
311
+ this.onAfterRequest?.({
312
+ threadId,
313
+ runId: undefined,
314
+ inputMessages: messages,
315
+ outputMessages,
316
+ properties: graphqlContext.properties,
317
+ });
318
+ })
319
+ .catch((_error) => {});
320
+
321
+ return {
322
+ threadId,
323
+ runId: undefined,
324
+ eventSource,
325
+ serverSideActions: [],
326
+ actionInputsWithoutAgents,
327
+ };
328
+ } catch (error) {
329
+ console.error("Error getting response:", error);
330
+ throw error;
331
+ }
332
+ }
333
+
334
+ private async getServerSideActions(request: CopilotRuntimeRequest): Promise<Action<any>[]> {
335
+ const { messages: rawMessages, graphqlContext, agentStates, url } = request;
336
+ const inputMessages = convertGqlInputToMessages(rawMessages);
337
+ const langserveFunctions: Action<any>[] = [];
338
+
339
+ for (const chainPromise of this.langserve) {
340
+ try {
341
+ const chain = await chainPromise;
342
+ langserveFunctions.push(chain);
343
+ } catch (error) {
344
+ console.error("Error loading langserve chain:", error);
345
+ }
346
+ }
347
+
348
+ const remoteEndpointDefinitions = this.remoteEndpointDefinitions.map(
349
+ (endpoint) =>
350
+ ({
351
+ ...endpoint,
352
+ type: resolveEndpointType(endpoint),
353
+ }) as EndpointDefinition,
354
+ );
355
+
356
+ const remoteActions = await setupRemoteActions({
357
+ remoteEndpointDefinitions,
358
+ graphqlContext,
359
+ messages: inputMessages,
360
+ agentStates,
361
+ frontendUrl: url,
362
+ });
363
+
364
+ const configuredActions =
365
+ typeof this.actions === "function"
366
+ ? this.actions({ properties: graphqlContext.properties, url })
367
+ : this.actions;
368
+
369
+ return [...configuredActions, ...langserveFunctions, ...remoteActions];
370
+ }
371
+ }
372
+
373
+ export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {
374
+ let allTools: ActionInput[] = [];
375
+ const allToolNames: string[] = [];
376
+ for (const tool of toolsByPriority) {
377
+ if (!allToolNames.includes(tool.name)) {
378
+ allTools.push(tool);
379
+ allToolNames.push(tool.name);
380
+ }
381
+ }
382
+ return allTools;
383
+ }
384
+
385
+ // The two functions below are "factory functions", meant to create the action objects that adhere to the expected interfaces
386
+ export function copilotKitEndpoint(config: Omit<CopilotKitEndpoint, "type">): CopilotKitEndpoint {
387
+ return {
388
+ ...config,
389
+ type: EndpointType.CopilotKit,
390
+ };
391
+ }
392
+
393
+ export function langGraphPlatformEndpoint(
394
+ config: Omit<LangGraphPlatformEndpoint, "type">,
395
+ ): LangGraphPlatformEndpoint {
396
+ return {
397
+ ...config,
398
+ type: EndpointType.LangGraphPlatform,
399
+ };
400
+ }
401
+
402
+ export function resolveEndpointType(endpoint: EndpointDefinition) {
403
+ if (!endpoint.type) {
404
+ if ("langsmithApiKey" in endpoint && "deploymentUrl" in endpoint && "agents" in endpoint) {
405
+ return EndpointType.LangGraphPlatform;
406
+ } else {
407
+ return EndpointType.CopilotKit;
408
+ }
409
+ }
410
+
411
+ return endpoint.type;
412
+ }
@@ -0,0 +1,304 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ CopilotKitEndpoint,
4
+ LangGraphAgentHandlerParams,
5
+ RemoteActionInfoResponse,
6
+ LangGraphPlatformEndpoint,
7
+ } from "./remote-actions";
8
+ import { GraphQLContext } from "../integrations";
9
+ import { Logger } from "pino";
10
+ import { Message } from "../../graphql/types/converted";
11
+ import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
12
+ import { Observable, ReplaySubject } from "rxjs";
13
+ import { RuntimeEvent } from "../../service-adapters/events";
14
+ import telemetry from "../telemetry-client";
15
+ import { RemoteLangGraphEventSource } from "../../agents/langgraph/event-source";
16
+ import { Action } from "@copilotkit/shared";
17
+ import { LangGraphEvent } from "../../agents/langgraph/events";
18
+ import { execute } from "./remote-lg-action";
19
+
20
+ export function constructLGCRemoteAction({
21
+ endpoint,
22
+ graphqlContext,
23
+ logger,
24
+ messages,
25
+ agentStates,
26
+ }: {
27
+ endpoint: LangGraphPlatformEndpoint;
28
+ graphqlContext: GraphQLContext;
29
+ logger: Logger;
30
+ messages: Message[];
31
+ agentStates?: AgentStateInput[];
32
+ }) {
33
+ const agents = endpoint.agents.map((agent) => ({
34
+ name: agent.name,
35
+ description: agent.description,
36
+ parameters: [],
37
+ handler: async (_args: any) => {},
38
+ langGraphAgentHandler: async ({
39
+ name,
40
+ actionInputsWithoutAgents,
41
+ threadId,
42
+ nodeName,
43
+ additionalMessages = [],
44
+ }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
45
+ logger.debug({ actionName: agent.name }, "Executing LangGraph Platform agent");
46
+
47
+ telemetry.capture("oss.runtime.remote_action_executed", {
48
+ agentExecution: true,
49
+ type: "langgraph-platform",
50
+ agentsAmount: endpoint.agents.length,
51
+ hashedLgcKey: createHash("sha256").update(endpoint.langsmithApiKey).digest("hex"),
52
+ });
53
+
54
+ let state = {};
55
+ if (agentStates) {
56
+ const jsonState = agentStates.find((state) => state.agentName === name)?.state;
57
+ if (jsonState) {
58
+ state = JSON.parse(jsonState);
59
+ }
60
+ }
61
+
62
+ try {
63
+ const response = await execute({
64
+ logger,
65
+ deploymentUrl: endpoint.deploymentUrl,
66
+ langsmithApiKey: endpoint.langsmithApiKey,
67
+ agent,
68
+ threadId,
69
+ nodeName,
70
+ messages: [...messages, ...additionalMessages],
71
+ state,
72
+ properties: graphqlContext.properties,
73
+ actions: actionInputsWithoutAgents.map((action) => ({
74
+ name: action.name,
75
+ description: action.description,
76
+ parameters: JSON.parse(action.jsonSchema) as string,
77
+ })),
78
+ });
79
+
80
+ const eventSource = new RemoteLangGraphEventSource();
81
+ streamResponse(response, eventSource.eventStream$);
82
+ return eventSource.processLangGraphEvents();
83
+ } catch (error) {
84
+ logger.error(
85
+ { url: endpoint.deploymentUrl, status: 500, body: error.message },
86
+ "Failed to execute LangGraph Platform agent",
87
+ );
88
+ throw new Error("Failed to execute LangGraph Platform agent");
89
+ }
90
+ },
91
+ }));
92
+
93
+ return [...agents];
94
+ }
95
+
96
+ export function constructRemoteActions({
97
+ json,
98
+ url,
99
+ onBeforeRequest,
100
+ graphqlContext,
101
+ logger,
102
+ messages,
103
+ agentStates,
104
+ }: {
105
+ json: RemoteActionInfoResponse;
106
+ url: string;
107
+ onBeforeRequest?: CopilotKitEndpoint["onBeforeRequest"];
108
+ graphqlContext: GraphQLContext;
109
+ logger: Logger;
110
+ messages: Message[];
111
+ agentStates?: AgentStateInput[];
112
+ }): Action<any>[] {
113
+ const totalAgents = Array.isArray(json["agents"]) ? json["agents"].length : 0;
114
+
115
+ const actions = json["actions"].map((action) => ({
116
+ name: action.name,
117
+ description: action.description,
118
+ parameters: action.parameters,
119
+ handler: async (args: any) => {
120
+ logger.debug({ actionName: action.name, args }, "Executing remote action");
121
+
122
+ const headers = createHeaders(onBeforeRequest, graphqlContext);
123
+ telemetry.capture("oss.runtime.remote_action_executed", {
124
+ agentExecution: false,
125
+ type: "self-hosted",
126
+ agentsAmount: totalAgents,
127
+ });
128
+
129
+ try {
130
+ const response = await fetch(`${url}/actions/execute`, {
131
+ method: "POST",
132
+ headers,
133
+ body: JSON.stringify({
134
+ name: action.name,
135
+ arguments: args,
136
+ properties: graphqlContext.properties,
137
+ }),
138
+ });
139
+
140
+ if (!response.ok) {
141
+ logger.error(
142
+ { url, status: response.status, body: await response.text() },
143
+ "Failed to execute remote action",
144
+ );
145
+ return "Failed to execute remote action";
146
+ }
147
+
148
+ const requestResult = await response.json();
149
+
150
+ const result = requestResult["result"];
151
+ logger.debug({ actionName: action.name, result }, "Executed remote action");
152
+ return result;
153
+ } catch (error) {
154
+ logger.error(
155
+ { error: error.message ? error.message : error + "" },
156
+ "Failed to execute remote action",
157
+ );
158
+ return "Failed to execute remote action";
159
+ }
160
+ },
161
+ }));
162
+
163
+ const agents = totalAgents
164
+ ? json["agents"].map((agent) => ({
165
+ name: agent.name,
166
+ description: agent.description,
167
+ parameters: [],
168
+ handler: async (_args: any) => {},
169
+
170
+ langGraphAgentHandler: async ({
171
+ name,
172
+ actionInputsWithoutAgents,
173
+ threadId,
174
+ nodeName,
175
+ additionalMessages = [],
176
+ }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
177
+ logger.debug({ actionName: agent.name }, "Executing remote agent");
178
+
179
+ const headers = createHeaders(onBeforeRequest, graphqlContext);
180
+ telemetry.capture("oss.runtime.remote_action_executed", {
181
+ agentExecution: true,
182
+ type: "self-hosted",
183
+ agentsAmount: json["agents"].length,
184
+ });
185
+
186
+ let state = {};
187
+ if (agentStates) {
188
+ const jsonState = agentStates.find((state) => state.agentName === name)?.state;
189
+ if (jsonState) {
190
+ state = JSON.parse(jsonState);
191
+ }
192
+ }
193
+
194
+ const response = await fetch(`${url}/agents/execute`, {
195
+ method: "POST",
196
+ headers,
197
+ body: JSON.stringify({
198
+ name,
199
+ threadId,
200
+ nodeName,
201
+ messages: [...messages, ...additionalMessages],
202
+ state,
203
+ properties: graphqlContext.properties,
204
+ actions: actionInputsWithoutAgents.map((action) => ({
205
+ name: action.name,
206
+ description: action.description,
207
+ parameters: JSON.parse(action.jsonSchema),
208
+ })),
209
+ }),
210
+ });
211
+
212
+ if (!response.ok) {
213
+ logger.error(
214
+ { url, status: response.status, body: await response.text() },
215
+ "Failed to execute remote agent",
216
+ );
217
+ throw new Error("Failed to execute remote agent");
218
+ }
219
+
220
+ const eventSource = new RemoteLangGraphEventSource();
221
+ streamResponse(response.body!, eventSource.eventStream$);
222
+ return eventSource.processLangGraphEvents();
223
+ },
224
+ }))
225
+ : [];
226
+
227
+ return [...actions, ...agents];
228
+ }
229
+
230
+ async function streamResponse(
231
+ response: ReadableStream<Uint8Array>,
232
+ eventStream$: ReplaySubject<LangGraphEvent>,
233
+ ) {
234
+ const reader = response.getReader();
235
+ const decoder = new TextDecoder();
236
+ let buffer = [];
237
+
238
+ function flushBuffer() {
239
+ const currentBuffer = buffer.join("");
240
+ if (currentBuffer.trim().length === 0) {
241
+ return;
242
+ }
243
+ const parts = currentBuffer.split("\n");
244
+ if (parts.length === 0) {
245
+ return;
246
+ }
247
+
248
+ const lastPartIsComplete = currentBuffer.endsWith("\n");
249
+
250
+ // truncate buffer
251
+ buffer = [];
252
+
253
+ if (!lastPartIsComplete) {
254
+ // put back the last part
255
+ buffer.push(parts.pop());
256
+ }
257
+
258
+ parts
259
+ .map((part) => part.trim())
260
+ .filter((part) => part != "")
261
+ .forEach((part) => {
262
+ eventStream$.next(JSON.parse(part));
263
+ });
264
+ }
265
+
266
+ try {
267
+ while (true) {
268
+ const { done, value } = await reader.read();
269
+
270
+ if (!done) {
271
+ buffer.push(decoder.decode(value, { stream: true }));
272
+ }
273
+
274
+ flushBuffer();
275
+
276
+ if (done) {
277
+ break;
278
+ }
279
+ }
280
+ } catch (error) {
281
+ console.error("Error in stream", error);
282
+ eventStream$.error(error);
283
+ return;
284
+ }
285
+ eventStream$.complete();
286
+ }
287
+
288
+ export function createHeaders(
289
+ onBeforeRequest: CopilotKitEndpoint["onBeforeRequest"],
290
+ graphqlContext: GraphQLContext,
291
+ ) {
292
+ const headers = {
293
+ "Content-Type": "application/json",
294
+ };
295
+
296
+ if (onBeforeRequest) {
297
+ const { headers: additionalHeaders } = onBeforeRequest({ ctx: graphqlContext });
298
+ if (additionalHeaders) {
299
+ Object.assign(headers, additionalHeaders);
300
+ }
301
+ }
302
+
303
+ return headers;
304
+ }