@copilotkit/runtime 1.5.0-tyler-reset-chat.0 → 1.5.0

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 (77) hide show
  1. package/CHANGELOG.md +141 -3
  2. package/__snapshots__/schema/schema.graphql +7 -9
  3. package/dist/{chunk-K67A6XOJ.mjs → chunk-25G6SHWM.mjs} +458 -331
  4. package/dist/chunk-25G6SHWM.mjs.map +1 -0
  5. package/dist/{chunk-OKQVDDJ2.mjs → chunk-4AYRDPWK.mjs} +285 -63
  6. package/dist/chunk-4AYRDPWK.mjs.map +1 -0
  7. package/dist/{chunk-ZBG4KJW5.mjs → chunk-AFKLCW76.mjs} +2 -2
  8. package/dist/{chunk-AGSBOD2T.mjs → chunk-D6J2N5ZQ.mjs} +2 -2
  9. package/dist/{chunk-QNQ6UT3D.mjs → chunk-PIUHAIBR.mjs} +2 -2
  10. package/dist/{chunk-B74M7FXG.mjs → chunk-RFF5IIZJ.mjs} +3 -2
  11. package/dist/chunk-RFF5IIZJ.mjs.map +1 -0
  12. package/dist/{copilot-runtime-12e7ac40.d.ts → copilot-runtime-2e46a7b6.d.ts} +2 -2
  13. package/dist/graphql/types/converted/index.d.ts +1 -1
  14. package/dist/graphql/types/converted/index.js +2 -1
  15. package/dist/graphql/types/converted/index.js.map +1 -1
  16. package/dist/graphql/types/converted/index.mjs +1 -1
  17. package/dist/{groq-adapter-24abe931.d.ts → groq-adapter-7bf6824b.d.ts} +1 -1
  18. package/dist/{index-10b1c870.d.ts → index-ff3fbc33.d.ts} +7 -8
  19. package/dist/index.d.ts +5 -5
  20. package/dist/index.js +832 -480
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +15 -11
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{langserve-f021ab9c.d.ts → langserve-f318db89.d.ts} +53 -14
  25. package/dist/lib/index.d.ts +4 -4
  26. package/dist/lib/index.js +737 -459
  27. package/dist/lib/index.js.map +1 -1
  28. package/dist/lib/index.mjs +7 -7
  29. package/dist/lib/integrations/index.d.ts +4 -4
  30. package/dist/lib/integrations/index.js +71 -30
  31. package/dist/lib/integrations/index.js.map +1 -1
  32. package/dist/lib/integrations/index.mjs +6 -6
  33. package/dist/lib/integrations/nest/index.d.ts +3 -3
  34. package/dist/lib/integrations/nest/index.js +71 -30
  35. package/dist/lib/integrations/nest/index.js.map +1 -1
  36. package/dist/lib/integrations/nest/index.mjs +4 -4
  37. package/dist/lib/integrations/node-express/index.d.ts +3 -3
  38. package/dist/lib/integrations/node-express/index.js +71 -30
  39. package/dist/lib/integrations/node-express/index.js.map +1 -1
  40. package/dist/lib/integrations/node-express/index.mjs +4 -4
  41. package/dist/lib/integrations/node-http/index.d.ts +3 -3
  42. package/dist/lib/integrations/node-http/index.js +71 -30
  43. package/dist/lib/integrations/node-http/index.js.map +1 -1
  44. package/dist/lib/integrations/node-http/index.mjs +3 -3
  45. package/dist/service-adapters/index.d.ts +36 -5
  46. package/dist/service-adapters/index.js +285 -61
  47. package/dist/service-adapters/index.js.map +1 -1
  48. package/dist/service-adapters/index.mjs +5 -1
  49. package/package.json +4 -4
  50. package/src/agents/langgraph/event-source.ts +140 -148
  51. package/src/agents/langgraph/events.ts +1 -1
  52. package/src/graphql/inputs/message.input.ts +15 -3
  53. package/src/graphql/resolvers/copilot.resolver.ts +32 -6
  54. package/src/graphql/types/converted/index.ts +4 -3
  55. package/src/graphql/types/copilot-response.type.ts +12 -3
  56. package/src/graphql/types/enums.ts +0 -11
  57. package/src/lib/runtime/copilot-runtime.ts +1 -7
  58. package/src/lib/runtime/remote-action-constructors.ts +64 -58
  59. package/src/lib/runtime/remote-actions.ts +1 -0
  60. package/src/lib/runtime/remote-lg-action.ts +184 -154
  61. package/src/service-adapters/anthropic/anthropic-adapter.ts +16 -6
  62. package/src/service-adapters/conversion.ts +2 -1
  63. package/src/service-adapters/events.ts +118 -54
  64. package/src/service-adapters/experimental/empty/empty-adapter.ts +33 -0
  65. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +7 -3
  66. package/src/service-adapters/groq/groq-adapter.ts +23 -8
  67. package/src/service-adapters/index.ts +7 -1
  68. package/src/service-adapters/langchain/utils.ts +55 -32
  69. package/src/service-adapters/openai/openai-adapter.ts +22 -9
  70. package/src/service-adapters/openai/openai-assistant-adapter.ts +22 -8
  71. package/src/service-adapters/unify/unify-adapter.ts +28 -11
  72. package/dist/chunk-B74M7FXG.mjs.map +0 -1
  73. package/dist/chunk-K67A6XOJ.mjs.map +0 -1
  74. package/dist/chunk-OKQVDDJ2.mjs.map +0 -1
  75. /package/dist/{chunk-ZBG4KJW5.mjs.map → chunk-AFKLCW76.mjs.map} +0 -0
  76. /package/dist/{chunk-AGSBOD2T.mjs.map → chunk-D6J2N5ZQ.mjs.map} +0 -0
  77. /package/dist/{chunk-QNQ6UT3D.mjs.map → chunk-PIUHAIBR.mjs.map} +0 -0
@@ -40,6 +40,7 @@ export function constructLGCRemoteAction({
40
40
  actionInputsWithoutAgents,
41
41
  threadId,
42
42
  nodeName,
43
+ additionalMessages = [],
43
44
  }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
44
45
  logger.debug({ actionName: agent.name }, "Executing LangGraph Platform agent");
45
46
 
@@ -66,7 +67,7 @@ export function constructLGCRemoteAction({
66
67
  agent,
67
68
  threadId,
68
69
  nodeName,
69
- messages,
70
+ messages: [...messages, ...additionalMessages],
70
71
  state,
71
72
  properties: graphqlContext.properties,
72
73
  actions: actionInputsWithoutAgents.map((action) => ({
@@ -109,6 +110,8 @@ export function constructRemoteActions({
109
110
  messages: Message[];
110
111
  agentStates?: AgentStateInput[];
111
112
  }): Action<any>[] {
113
+ const totalAgents = Array.isArray(json["agents"]) ? json["agents"].length : 0;
114
+
112
115
  const actions = json["actions"].map((action) => ({
113
116
  name: action.name,
114
117
  description: action.description,
@@ -120,7 +123,7 @@ export function constructRemoteActions({
120
123
  telemetry.capture("oss.runtime.remote_action_executed", {
121
124
  agentExecution: false,
122
125
  type: "self-hosted",
123
- agentsAmount: json["agents"].length,
126
+ agentsAmount: totalAgents,
124
127
  });
125
128
 
126
129
  try {
@@ -157,66 +160,69 @@ export function constructRemoteActions({
157
160
  },
158
161
  }));
159
162
 
160
- const agents = json["agents"].map((agent) => ({
161
- name: agent.name,
162
- description: agent.description,
163
- parameters: [],
164
- handler: async (_args: any) => {},
165
-
166
- langGraphAgentHandler: async ({
167
- name,
168
- actionInputsWithoutAgents,
169
- threadId,
170
- nodeName,
171
- }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
172
- logger.debug({ actionName: agent.name }, "Executing remote agent");
173
-
174
- const headers = createHeaders(onBeforeRequest, graphqlContext);
175
- telemetry.capture("oss.runtime.remote_action_executed", {
176
- agentExecution: true,
177
- type: "self-hosted",
178
- agentsAmount: json["agents"].length,
179
- });
180
-
181
- let state = {};
182
- if (agentStates) {
183
- const jsonState = agentStates.find((state) => state.agentName === name)?.state;
184
- if (jsonState) {
185
- state = JSON.parse(jsonState);
186
- }
187
- }
163
+ const agents = totalAgents
164
+ ? json["agents"].map((agent) => ({
165
+ name: agent.name,
166
+ description: agent.description,
167
+ parameters: [],
168
+ handler: async (_args: any) => {},
188
169
 
189
- const response = await fetch(`${url}/agents/execute`, {
190
- method: "POST",
191
- headers,
192
- body: JSON.stringify({
170
+ langGraphAgentHandler: async ({
193
171
  name,
172
+ actionInputsWithoutAgents,
194
173
  threadId,
195
174
  nodeName,
196
- messages,
197
- state,
198
- properties: graphqlContext.properties,
199
- actions: actionInputsWithoutAgents.map((action) => ({
200
- name: action.name,
201
- description: action.description,
202
- parameters: JSON.parse(action.jsonSchema),
203
- })),
204
- }),
205
- });
206
-
207
- if (!response.ok) {
208
- logger.error(
209
- { url, status: response.status, body: await response.text() },
210
- "Failed to execute remote agent",
211
- );
212
- throw new Error("Failed to execute remote agent");
213
- }
214
-
215
- const eventSource = new RemoteLangGraphEventSource();
216
- streamResponse(response.body!, eventSource.eventStream$);
217
- return eventSource.processLangGraphEvents();
218
- },
219
- }));
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
+ : [];
220
226
 
221
227
  return [...actions, ...agents];
222
228
  }
@@ -53,6 +53,7 @@ export type LangGraphAgentHandlerParams = {
53
53
  actionInputsWithoutAgents: ActionInput[];
54
54
  threadId?: string;
55
55
  nodeName?: string;
56
+ additionalMessages?: Message[];
56
57
  };
57
58
 
58
59
  export type LangGraphAgentAction = Action<any> & {
@@ -5,7 +5,7 @@ import { Logger } from "pino";
5
5
  import { ActionInput } from "../../graphql/inputs/action.input";
6
6
  import { LangGraphPlatformAgent, LangGraphPlatformEndpoint } from "./remote-actions";
7
7
  import { CopilotRequestContextProperties } from "../integrations";
8
- import { Message, MessageType } from "../../graphql/types/converted";
8
+ import { ActionExecutionMessage, Message, MessageType } from "../../graphql/types/converted";
9
9
  import { MessageRole } from "../../graphql/types/enums";
10
10
  import { CustomEventNames, LangGraphEventTypes } from "../../agents/langgraph/events";
11
11
  import telemetry from "../telemetry-client";
@@ -96,8 +96,6 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
96
96
  initialThreadId = initialThreadId.substring(3);
97
97
  }
98
98
 
99
- const assistants = await client.assistants.search();
100
- const retrievedAssistant = assistants.find((a) => a.name === name);
101
99
  const threadId = initialThreadId ?? randomUUID();
102
100
  if (initialThreadId === threadId) {
103
101
  await client.threads.get(threadId);
@@ -114,7 +112,7 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
114
112
  const mode = wasInitiatedWithExistingThread && nodeName != "__end__" ? "continue" : "start";
115
113
  let formattedMessages = [];
116
114
  try {
117
- formattedMessages = formatMessages(messages);
115
+ formattedMessages = copilotkitMessagesToLangChain(messages);
118
116
  } catch (e) {
119
117
  logger.error(e, `Error event thrown: ${e.message}`);
120
118
  }
@@ -124,8 +122,24 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
124
122
  await client.threads.updateState(threadId, { values: state, asNode: nodeName });
125
123
  }
126
124
 
127
- const assistantId = initialAssistantId ?? retrievedAssistant?.assistant_id;
128
- if (!assistantId) {
125
+ let streamInfo: {
126
+ provider?: string;
127
+ langGraphHost?: string;
128
+ langGraphVersion?: string;
129
+ hashedLgcKey: string;
130
+ } = {
131
+ hashedLgcKey: createHash("sha256").update(langsmithApiKey).digest("hex"),
132
+ };
133
+
134
+ const assistants = await client.assistants.search();
135
+ const retrievedAssistant = assistants.find(
136
+ (a) => a.name === name || a.assistant_id === initialAssistantId,
137
+ );
138
+ if (!retrievedAssistant) {
139
+ telemetry.capture("oss.runtime.agent_execution_stream_errored", {
140
+ ...streamInfo,
141
+ error: `Found no assistants for given information, while ${assistants.length} assistants exists`,
142
+ });
129
143
  console.error(`
130
144
  No agent found for the agent name specified in CopilotKit provider
131
145
  Please check your available agents or provide an agent ID in the LangGraph Platform endpoint definition.\n
@@ -134,6 +148,8 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
134
148
  `);
135
149
  throw new Error("No agent id found");
136
150
  }
151
+ const assistantId = retrievedAssistant.assistant_id;
152
+
137
153
  const graphInfo = await client.assistants.getGraph(assistantId);
138
154
  const streamInput = mode === "start" ? state : null;
139
155
 
@@ -155,14 +171,6 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
155
171
  // If a manual emittance happens, it is the ultimate source of truth of state, unless a node has exited.
156
172
  // Therefore, this value should either hold null, or the only edition of state that should be used.
157
173
  let manuallyEmittedState = null;
158
- let streamInfo: {
159
- provider?: string;
160
- langGraphHost?: string;
161
- langGraphVersion?: string;
162
- hashedLgcKey: string;
163
- } = {
164
- hashedLgcKey: createHash("sha256").update(langsmithApiKey).digest("hex"),
165
- };
166
174
 
167
175
  try {
168
176
  telemetry.capture("oss.runtime.agent_execution_stream_started", {
@@ -172,7 +180,6 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
172
180
  if (!["events", "values", "error"].includes(chunk.event)) continue;
173
181
 
174
182
  if (chunk.event === "error") {
175
- logger.error(chunk, `Error event thrown: ${chunk.data.message}`);
176
183
  throw new Error(`Error event thrown: ${chunk.data.message}`);
177
184
  }
178
185
 
@@ -312,12 +319,17 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
312
319
  state: state.values,
313
320
  running: !shouldExit,
314
321
  active: false,
322
+ includeMessages: true,
315
323
  }),
316
324
  );
317
325
 
318
326
  return Promise.resolve();
319
327
  } catch (e) {
320
- // TODO: handle error state here.
328
+ logger.error(e);
329
+ telemetry.capture("oss.runtime.agent_execution_stream_errored", {
330
+ ...streamInfo,
331
+ error: e.message,
332
+ });
321
333
  return Promise.resolve();
322
334
  }
323
335
  }
@@ -330,6 +342,7 @@ function getStateSyncEvent({
330
342
  state,
331
343
  running,
332
344
  active,
345
+ includeMessages = false,
333
346
  }: {
334
347
  threadId: string;
335
348
  runId: string;
@@ -338,13 +351,21 @@ function getStateSyncEvent({
338
351
  state: State;
339
352
  running: boolean;
340
353
  active: boolean;
354
+ includeMessages?: boolean;
341
355
  }): string {
342
- const stateWithoutMessages = Object.keys(state).reduce((acc, key) => {
343
- if (key !== "messages") {
344
- acc[key] = state[key];
345
- }
346
- return acc;
347
- }, {} as State);
356
+ if (!includeMessages) {
357
+ state = Object.keys(state).reduce((acc, key) => {
358
+ if (key !== "messages") {
359
+ acc[key] = state[key];
360
+ }
361
+ return acc;
362
+ }, {} as State);
363
+ } else {
364
+ state = {
365
+ ...state,
366
+ messages: langchainMessagesToCopilotKit(state.messages || []),
367
+ };
368
+ }
348
369
 
349
370
  return (
350
371
  JSON.stringify({
@@ -354,7 +375,7 @@ function getStateSyncEvent({
354
375
  agent_name: agentName,
355
376
  node_name: nodeName,
356
377
  active: active,
357
- state: stateWithoutMessages,
378
+ state: state,
358
379
  running: running,
359
380
  role: "assistant",
360
381
  }) + "\n"
@@ -449,179 +470,188 @@ function langGraphDefaultMergeState(
449
470
  }
450
471
 
451
472
  // merge with existing messages
452
- const mergedMessages: LangGraphPlatformMessage[] = state.messages || [];
453
- const existingMessageIds = new Set(mergedMessages.map((message) => message.id));
454
- const existingToolCallResults = new Set<string>();
473
+ const existingMessages: LangGraphPlatformMessage[] = state.messages || [];
474
+ const existingMessageIds = new Set(existingMessages.map((message) => message.id));
475
+ const newMessages = messages.filter((message) => !existingMessageIds.has(message.id));
476
+
477
+ return {
478
+ ...state,
479
+ messages: newMessages,
480
+ copilotkit: {
481
+ actions,
482
+ },
483
+ };
484
+ }
455
485
 
456
- for (const message of mergedMessages) {
457
- if ("tool_call_id" in message) {
458
- existingToolCallResults.add(message.tool_call_id);
486
+ function langchainMessagesToCopilotKit(messages: any[]): any[] {
487
+ const result: any[] = [];
488
+ const tool_call_names: Record<string, string> = {};
489
+
490
+ // First pass: gather all tool call names from AI messages
491
+ for (const message of messages) {
492
+ if (message.type === "ai") {
493
+ for (const tool_call of message.tool_calls) {
494
+ tool_call_names[tool_call.id] = tool_call.name;
495
+ }
459
496
  }
460
497
  }
461
498
 
462
499
  for (const message of messages) {
463
- // filter tool calls to activate the agent itself
464
- if (
465
- "tool_calls" in message &&
466
- message.tool_calls.length > 0 &&
467
- message.tool_calls[0].name === agentName
468
- ) {
469
- continue;
500
+ let content: any = message.content;
501
+ if (content instanceof Array) {
502
+ content = content[0];
470
503
  }
471
-
472
- // filter results from activating the agent
473
- if ("name" in message && message.name === agentName) {
474
- continue;
504
+ if (content instanceof Object) {
505
+ content = content.text;
475
506
  }
476
507
 
477
- if (!existingMessageIds.has(message.id)) {
478
- // skip duplicate tool call results
479
- if ("tool_call_id" in message && existingToolCallResults.has(message.tool_call_id)) {
480
- console.warn("Warning: Duplicate tool call result, skipping:", message.tool_call_id);
481
- continue;
482
- }
483
-
484
- mergedMessages.push(message);
485
- } else {
486
- // Replace the message with the existing one
487
- for (let i = 0; i < mergedMessages.length; i++) {
488
- if (mergedMessages[i].id === message.id && message.role === "assistant") {
489
- if (
490
- ("tool_calls" in mergedMessages[i] || "additional_kwargs" in mergedMessages[i]) &&
491
- mergedMessages[i].content
492
- ) {
493
- // @ts-expect-error -- message did not have a tool call, now it will
494
- message.tool_calls = mergedMessages[i]["tool_calls"];
495
- message.additional_kwargs = mergedMessages[i].additional_kwargs;
496
- }
497
- mergedMessages[i] = message;
508
+ if (message.type === "human") {
509
+ result.push({
510
+ role: "user",
511
+ content: content,
512
+ id: message.id,
513
+ });
514
+ } else if (message.type === "system") {
515
+ result.push({
516
+ role: "system",
517
+ content: content,
518
+ id: message.id,
519
+ });
520
+ } else if (message.type === "ai") {
521
+ if (message.tool_calls && message.tool_calls.length > 0) {
522
+ for (const tool_call of message.tool_calls) {
523
+ result.push({
524
+ id: tool_call.id,
525
+ name: tool_call.name,
526
+ arguments: tool_call.args,
527
+ parentMessageId: message.id,
528
+ });
498
529
  }
530
+ } else {
531
+ result.push({
532
+ role: "assistant",
533
+ content: content,
534
+ id: message.id,
535
+ parentMessageId: message.id,
536
+ });
499
537
  }
538
+ } else if (message.type === "tool") {
539
+ const actionName = tool_call_names[message.tool_call_id] || message.name || "";
540
+ result.push({
541
+ actionExecutionId: message.tool_call_id,
542
+ actionName: actionName,
543
+ result: content,
544
+ id: message.id,
545
+ });
500
546
  }
501
547
  }
502
-
503
- // fix wrong tool call ids
504
- for (let i = 0; i < mergedMessages.length - 1; i++) {
505
- const currentMessage = mergedMessages[i];
506
- const nextMessage = mergedMessages[i + 1];
507
-
508
- if (
509
- "tool_calls" in currentMessage &&
510
- currentMessage.tool_calls.length > 0 &&
511
- "tool_call_id" in nextMessage
512
- ) {
513
- nextMessage.tool_call_id = currentMessage.tool_calls[0].id;
548
+ const resultsDict: Record<string, any> = {};
549
+ for (const msg of result) {
550
+ if (msg.actionExecutionId) {
551
+ resultsDict[msg.actionExecutionId] = msg;
514
552
  }
515
553
  }
516
554
 
517
- // try to auto-correct and log alignment issues
518
- const correctedMessages: LangGraphPlatformMessage[] = [];
555
+ const reorderedResult: Message[] = [];
519
556
 
520
- for (let i = 0; i < mergedMessages.length; i++) {
521
- const currentMessage = mergedMessages[i];
522
- const nextMessage = mergedMessages[i + 1] || null;
523
- const prevMessage = mergedMessages[i - 1] || null;
557
+ for (const msg of result) {
558
+ // If it's not a tool result, just append it
559
+ if (!("actionExecutionId" in msg)) {
560
+ reorderedResult.push(msg);
561
+ }
524
562
 
525
- if ("tool_calls" in currentMessage && currentMessage.tool_calls.length > 0) {
526
- if (!nextMessage) {
527
- console.warn(
528
- "No next message to auto-correct tool call, skipping:",
529
- currentMessage.tool_calls[0].id,
530
- );
531
- continue;
563
+ // If the message has arguments (i.e., is a tool call invocation),
564
+ // append the corresponding result right after it
565
+ if ("arguments" in msg) {
566
+ const msgId = msg.id;
567
+ if (msgId in resultsDict) {
568
+ reorderedResult.push(resultsDict[msgId]);
532
569
  }
570
+ }
571
+ }
533
572
 
534
- if (
535
- !("tool_call_id" in nextMessage) ||
536
- nextMessage.tool_call_id !== currentMessage.tool_calls[0].id
537
- ) {
538
- const toolMessage = mergedMessages.find(
539
- (m) => "tool_call_id" in m && m.tool_call_id === currentMessage.tool_calls[0].id,
540
- );
573
+ return reorderedResult;
574
+ }
541
575
 
542
- if (toolMessage) {
543
- console.warn(
544
- "Auto-corrected tool call alignment issue:",
545
- currentMessage.tool_calls[0].id,
546
- );
547
- correctedMessages.push(currentMessage, toolMessage);
548
- continue;
549
- } else {
550
- console.warn(
551
- "No corresponding tool call result found for tool call, skipping:",
552
- currentMessage.tool_calls[0].id,
553
- );
554
- continue;
555
- }
556
- }
576
+ function copilotkitMessagesToLangChain(messages: Message[]): LangGraphPlatformMessage[] {
577
+ const result: LangGraphPlatformMessage[] = [];
578
+ const processedActionExecutions = new Set<string>();
557
579
 
558
- correctedMessages.push(currentMessage);
580
+ for (const message of messages) {
581
+ // Handle TextMessage
582
+ if (message.isTextMessage()) {
583
+ if (message.role === "user") {
584
+ // Human message
585
+ result.push({
586
+ ...message,
587
+ role: MessageRole.user,
588
+ });
589
+ } else if (message.role === "system") {
590
+ // System message
591
+ result.push({
592
+ ...message,
593
+ role: MessageRole.system,
594
+ });
595
+ } else if (message.role === "assistant") {
596
+ // Assistant message
597
+ result.push({
598
+ ...message,
599
+ role: MessageRole.assistant,
600
+ });
601
+ }
559
602
  continue;
560
603
  }
561
604
 
562
- if ("tool_call_id" in currentMessage) {
563
- if (!prevMessage || !("tool_calls" in prevMessage)) {
564
- console.warn("No previous tool call, skipping tool call result:", currentMessage.id);
565
- continue;
566
- }
605
+ // Handle ActionExecutionMessage (multiple tool calls per parentMessageId)
606
+ if (message.isActionExecutionMessage()) {
607
+ const messageId = message.parentMessageId ?? message.id;
567
608
 
568
- if (prevMessage.tool_calls && prevMessage.tool_calls[0].id !== currentMessage.tool_call_id) {
569
- console.warn("Tool call id is incorrect, skipping tool call result:", currentMessage.id);
609
+ // If we've already processed this action execution group, skip
610
+ if (processedActionExecutions.has(messageId)) {
570
611
  continue;
571
612
  }
572
613
 
573
- correctedMessages.push(currentMessage);
574
- continue;
575
- }
614
+ processedActionExecutions.add(messageId);
576
615
 
577
- correctedMessages.push(currentMessage);
578
- }
616
+ // Gather all tool calls related to this messageId
617
+ const relatedActionExecutions = messages.filter(
618
+ (m) =>
619
+ m.isActionExecutionMessage() &&
620
+ ((m.parentMessageId && m.parentMessageId === messageId) || m.id === messageId),
621
+ ) as ActionExecutionMessage[];
579
622
 
580
- return {
581
- ...state,
582
- messages: correctedMessages,
583
- copilotkit: {
584
- actions,
585
- },
586
- };
587
- }
623
+ const tool_calls: ToolCall[] = relatedActionExecutions.map((m) => ({
624
+ name: m.name,
625
+ args: m.arguments,
626
+ id: m.id,
627
+ }));
588
628
 
589
- function formatMessages(messages: Message[]): LangGraphPlatformMessage[] {
590
- return messages.map((message) => {
591
- if (message.isTextMessage() && message.role === "assistant") {
592
- return message;
593
- }
594
- if (message.isTextMessage() && message.role === "system") {
595
- return message;
596
- }
597
- if (message.isTextMessage() && message.role === "user") {
598
- return message;
599
- }
600
- if (message.isActionExecutionMessage()) {
601
- const toolCall: ToolCall = {
602
- name: message.name,
603
- args: message.arguments,
604
- id: message.id,
605
- };
606
- return {
607
- type: message.type,
629
+ result.push({
630
+ id: messageId,
631
+ type: "ActionExecutionMessage",
608
632
  content: "",
609
- tool_calls: [toolCall],
633
+ tool_calls: tool_calls,
610
634
  role: MessageRole.assistant,
611
- id: message.id,
612
- } satisfies LangGraphPlatformActionExecutionMessage;
635
+ } satisfies LangGraphPlatformActionExecutionMessage);
636
+
637
+ continue;
613
638
  }
639
+
640
+ // Handle ResultMessage
614
641
  if (message.isResultMessage()) {
615
- return {
642
+ result.push({
616
643
  type: message.type,
617
644
  content: message.result,
618
645
  id: message.id,
619
646
  tool_call_id: message.actionExecutionId,
620
647
  name: message.actionName,
621
648
  role: MessageRole.tool,
622
- } satisfies LangGraphPlatformResultMessage;
649
+ } satisfies LangGraphPlatformResultMessage);
650
+ continue;
623
651
  }
624
652
 
625
653
  throw new Error(`Unknown message type ${message.type}`);
626
- });
654
+ }
655
+
656
+ return result;
627
657
  }