@copilotkit/runtime 1.3.12-lgc-alpha-1.0 → 1.3.12

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 (56) hide show
  1. package/CHANGELOG.md +4 -3
  2. package/dist/{chunk-7MQDBRXJ.mjs → chunk-24WEOOFX.mjs} +2 -2
  3. package/dist/{chunk-E6ZFCM3B.mjs → chunk-F2KJWMGD.mjs} +133 -561
  4. package/dist/chunk-F2KJWMGD.mjs.map +1 -0
  5. package/dist/{chunk-6HXQC7IT.mjs → chunk-IXVCESAR.mjs} +9 -36
  6. package/dist/chunk-IXVCESAR.mjs.map +1 -0
  7. package/dist/{chunk-TM7ZRU3M.mjs → chunk-IZP72K7I.mjs} +2 -2
  8. package/dist/{chunk-6B3NPPSR.mjs → chunk-PRG6VWHR.mjs} +2 -2
  9. package/dist/{chunk-XMDH5MKI.mjs → chunk-WBLYFYMZ.mjs} +2 -2
  10. package/dist/{chunk-V7SK6QZN.mjs → chunk-ZEHCLFJ2.mjs} +9 -6
  11. package/dist/chunk-ZEHCLFJ2.mjs.map +1 -0
  12. package/dist/{copilot-runtime-aba7d4b4.d.ts → copilot-runtime-df3527ad.d.ts} +5 -27
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +186 -638
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +9 -13
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/lib/index.d.ts +1 -1
  19. package/dist/lib/index.js +186 -638
  20. package/dist/lib/index.js.map +1 -1
  21. package/dist/lib/index.mjs +9 -13
  22. package/dist/lib/integrations/index.d.ts +2 -2
  23. package/dist/lib/integrations/index.js +4 -5
  24. package/dist/lib/integrations/index.js.map +1 -1
  25. package/dist/lib/integrations/index.mjs +5 -5
  26. package/dist/lib/integrations/nest/index.d.ts +1 -1
  27. package/dist/lib/integrations/nest/index.js +4 -5
  28. package/dist/lib/integrations/nest/index.js.map +1 -1
  29. package/dist/lib/integrations/nest/index.mjs +3 -3
  30. package/dist/lib/integrations/node-express/index.d.ts +1 -1
  31. package/dist/lib/integrations/node-express/index.js +4 -5
  32. package/dist/lib/integrations/node-express/index.js.map +1 -1
  33. package/dist/lib/integrations/node-express/index.mjs +3 -3
  34. package/dist/lib/integrations/node-http/index.d.ts +1 -1
  35. package/dist/lib/integrations/node-http/index.js +4 -5
  36. package/dist/lib/integrations/node-http/index.js.map +1 -1
  37. package/dist/lib/integrations/node-http/index.mjs +2 -2
  38. package/dist/service-adapters/index.js +8 -5
  39. package/dist/service-adapters/index.js.map +1 -1
  40. package/dist/service-adapters/index.mjs +2 -2
  41. package/package.json +6 -7
  42. package/src/agents/langgraph/event-source.ts +67 -22
  43. package/src/lib/runtime/copilot-runtime.ts +11 -58
  44. package/src/lib/runtime/remote-actions.ts +159 -65
  45. package/src/service-adapters/events.ts +5 -1
  46. package/src/service-adapters/langchain/utils.test.ts +169 -0
  47. package/src/service-adapters/langchain/utils.ts +10 -5
  48. package/dist/chunk-6HXQC7IT.mjs.map +0 -1
  49. package/dist/chunk-E6ZFCM3B.mjs.map +0 -1
  50. package/dist/chunk-V7SK6QZN.mjs.map +0 -1
  51. package/src/lib/runtime/remote-action-constructors.ts +0 -283
  52. package/src/lib/runtime/remote-lg-cloud-action.ts +0 -441
  53. /package/dist/{chunk-7MQDBRXJ.mjs.map → chunk-24WEOOFX.mjs.map} +0 -0
  54. /package/dist/{chunk-TM7ZRU3M.mjs.map → chunk-IZP72K7I.mjs.map} +0 -0
  55. /package/dist/{chunk-6B3NPPSR.mjs.map → chunk-PRG6VWHR.mjs.map} +0 -0
  56. /package/dist/{chunk-XMDH5MKI.mjs.map → chunk-WBLYFYMZ.mjs.map} +0 -0
@@ -1,283 +0,0 @@
1
- import {
2
- CopilotKitEndpoint,
3
- LangGraphAgentHandlerParams,
4
- RemoteActionInfoResponse,
5
- LangGraphCloudEndpoint,
6
- } from "./remote-actions";
7
- import { GraphQLContext } from "../integrations";
8
- import { Logger } from "pino";
9
- import { Message } from "../../graphql/types/converted";
10
- import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
11
- import { Observable, ReplaySubject } from "rxjs";
12
- import { RuntimeEvent } from "../../service-adapters/events";
13
- import telemetry from "../telemetry-client";
14
- import { RemoteLangGraphEventSource } from "../../agents/langgraph/event-source";
15
- import { Action } from "@copilotkit/shared";
16
- import { LangGraphEvent } from "../../agents/langgraph/events";
17
- import { execute } from "./remote-lg-cloud-action";
18
-
19
- export function constructLGCRemoteAction({
20
- endpoint,
21
- graphqlContext,
22
- logger,
23
- messages,
24
- agentStates,
25
- }: {
26
- endpoint: LangGraphCloudEndpoint;
27
- graphqlContext: GraphQLContext;
28
- logger: Logger;
29
- messages: Message[];
30
- agentStates?: AgentStateInput[];
31
- }) {
32
- const agents = endpoint.agents.map((agent) => ({
33
- name: agent.name,
34
- description: agent.description,
35
- parameters: [],
36
- handler: async (_args: any) => {},
37
- langGraphAgentHandler: async ({
38
- name,
39
- actionInputsWithoutAgents,
40
- threadId,
41
- nodeName,
42
- }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
43
- logger.debug({ actionName: agent.name }, "Executing LangGraph Cloud agent");
44
-
45
- telemetry.capture("oss.runtime.remote_action_executed", {});
46
-
47
- let state = {};
48
- if (agentStates) {
49
- const jsonState = agentStates.find((state) => state.agentName === name)?.state;
50
- if (jsonState) {
51
- state = JSON.parse(jsonState);
52
- }
53
- }
54
-
55
- try {
56
- const response = await execute({
57
- deploymentUrl: endpoint.deploymentUrl,
58
- langsmithApiKey: endpoint.langsmithApiKey,
59
- agent,
60
- threadId,
61
- nodeName,
62
- messages,
63
- state,
64
- properties: graphqlContext.properties,
65
- actions: actionInputsWithoutAgents.map((action) => ({
66
- name: action.name,
67
- description: action.description,
68
- parameters: JSON.parse(action.jsonSchema) as string,
69
- })),
70
- });
71
-
72
- const eventSource = new RemoteLangGraphEventSource();
73
- streamResponse(response, eventSource.eventStream$);
74
- return eventSource.processLangGraphEvents();
75
- } catch (error) {
76
- logger.error(
77
- { url: endpoint.deploymentUrl, status: 500, body: error.message },
78
- "Failed to execute LangGraph Cloud agent",
79
- );
80
- throw new Error("Failed to execute LangGraph Cloud agent");
81
- }
82
- },
83
- }));
84
-
85
- return [...agents];
86
- }
87
-
88
- export function constructRemoteActions({
89
- json,
90
- url,
91
- onBeforeRequest,
92
- graphqlContext,
93
- logger,
94
- messages,
95
- agentStates,
96
- }: {
97
- json: RemoteActionInfoResponse;
98
- url: string;
99
- onBeforeRequest?: CopilotKitEndpoint["onBeforeRequest"];
100
- graphqlContext: GraphQLContext;
101
- logger: Logger;
102
- messages: Message[];
103
- agentStates?: AgentStateInput[];
104
- }): Action<any>[] {
105
- const actions = json["actions"].map((action) => ({
106
- name: action.name,
107
- description: action.description,
108
- parameters: action.parameters,
109
- handler: async (args: any) => {
110
- logger.debug({ actionName: action.name, args }, "Executing remote action");
111
-
112
- const headers = createHeaders(onBeforeRequest, graphqlContext);
113
- telemetry.capture("oss.runtime.remote_action_executed", {});
114
-
115
- try {
116
- const response = await fetch(`${url}/actions/execute`, {
117
- method: "POST",
118
- headers,
119
- body: JSON.stringify({
120
- name: action.name,
121
- arguments: args,
122
- properties: graphqlContext.properties,
123
- }),
124
- });
125
-
126
- if (!response.ok) {
127
- logger.error(
128
- { url, status: response.status, body: await response.text() },
129
- "Failed to execute remote action",
130
- );
131
- return "Failed to execute remote action";
132
- }
133
-
134
- const requestResult = await response.json();
135
-
136
- const result = requestResult["result"];
137
- logger.debug({ actionName: action.name, result }, "Executed remote action");
138
- return result;
139
- } catch (error) {
140
- logger.error(
141
- { error: error.message ? error.message : error + "" },
142
- "Failed to execute remote action",
143
- );
144
- return "Failed to execute remote action";
145
- }
146
- },
147
- }));
148
-
149
- const agents = json["agents"].map((agent) => ({
150
- name: agent.name,
151
- description: agent.description,
152
- parameters: [],
153
- handler: async (_args: any) => {},
154
-
155
- langGraphAgentHandler: async ({
156
- name,
157
- actionInputsWithoutAgents,
158
- threadId,
159
- nodeName,
160
- }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
161
- logger.debug({ actionName: agent.name }, "Executing remote agent");
162
-
163
- const headers = createHeaders(onBeforeRequest, graphqlContext);
164
- telemetry.capture("oss.runtime.remote_action_executed", {});
165
-
166
- let state = {};
167
- if (agentStates) {
168
- const jsonState = agentStates.find((state) => state.agentName === name)?.state;
169
- if (jsonState) {
170
- state = JSON.parse(jsonState);
171
- }
172
- }
173
-
174
- const response = await fetch(`${url}/agents/execute`, {
175
- method: "POST",
176
- headers,
177
- body: JSON.stringify({
178
- name,
179
- threadId,
180
- nodeName,
181
- messages,
182
- state,
183
- properties: graphqlContext.properties,
184
- actions: actionInputsWithoutAgents.map((action) => ({
185
- name: action.name,
186
- description: action.description,
187
- parameters: JSON.parse(action.jsonSchema),
188
- })),
189
- }),
190
- });
191
-
192
- if (!response.ok) {
193
- logger.error(
194
- { url, status: response.status, body: await response.text() },
195
- "Failed to execute remote agent",
196
- );
197
- throw new Error("Failed to execute remote agent");
198
- }
199
-
200
- const eventSource = new RemoteLangGraphEventSource();
201
- streamResponse(response.body!, eventSource.eventStream$);
202
- return eventSource.processLangGraphEvents();
203
- },
204
- }));
205
-
206
- return [...actions, ...agents];
207
- }
208
-
209
- async function streamResponse(
210
- response: ReadableStream<Uint8Array>,
211
- eventStream$: ReplaySubject<LangGraphEvent>,
212
- ) {
213
- const reader = response.getReader();
214
- const decoder = new TextDecoder();
215
- let buffer = [];
216
-
217
- function flushBuffer() {
218
- const currentBuffer = buffer.join("");
219
- if (currentBuffer.trim().length === 0) {
220
- return;
221
- }
222
- const parts = currentBuffer.split("\n");
223
- if (parts.length === 0) {
224
- return;
225
- }
226
-
227
- const lastPartIsComplete = currentBuffer.endsWith("\n");
228
-
229
- // truncate buffer
230
- buffer = [];
231
-
232
- if (!lastPartIsComplete) {
233
- // put back the last part
234
- buffer.push(parts.pop());
235
- }
236
-
237
- parts
238
- .map((part) => part.trim())
239
- .filter((part) => part != "")
240
- .forEach((part) => {
241
- eventStream$.next(JSON.parse(part));
242
- });
243
- }
244
-
245
- try {
246
- while (true) {
247
- const { done, value } = await reader.read();
248
-
249
- if (!done) {
250
- buffer.push(decoder.decode(value, { stream: true }));
251
- }
252
-
253
- flushBuffer();
254
-
255
- if (done) {
256
- break;
257
- }
258
- }
259
- } catch (error) {
260
- console.error("Error in stream", error);
261
- eventStream$.error(error);
262
- return;
263
- }
264
- eventStream$.complete();
265
- }
266
-
267
- export function createHeaders(
268
- onBeforeRequest: CopilotKitEndpoint["onBeforeRequest"],
269
- graphqlContext: GraphQLContext,
270
- ) {
271
- const headers = {
272
- "Content-Type": "application/json",
273
- };
274
-
275
- if (onBeforeRequest) {
276
- const { headers: additionalHeaders } = onBeforeRequest({ ctx: graphqlContext });
277
- if (additionalHeaders) {
278
- Object.assign(headers, additionalHeaders);
279
- }
280
- }
281
-
282
- return headers;
283
- }
@@ -1,441 +0,0 @@
1
- import { Client } from "@langchain/langgraph-sdk";
2
- import { randomUUID } from "node:crypto";
3
- import { parse as parsePartialJson } from "partial-json";
4
- import { ActionInput } from "../../graphql/inputs/action.input";
5
- import { LangGraphCloudAgent, LangGraphCloudEndpoint } from "./remote-actions";
6
- import { CopilotRequestContextProperties } from "../integrations";
7
- import { BaseMessageInput as CopilotKitBaseMessage } from "../../graphql/types/base";
8
- import { MessageRole } from "../../graphql/types/enums";
9
-
10
- type State = Record<string, any>;
11
-
12
- type ExecutionAction = Pick<ActionInput, "name" | "description"> & { parameters: string };
13
-
14
- interface ExecutionArgs extends Omit<LangGraphCloudEndpoint, "agents"> {
15
- agent: LangGraphCloudAgent;
16
- threadId: string;
17
- nodeName: string;
18
- messages: CopilotKitBaseMessage[];
19
- state: State;
20
- properties: CopilotRequestContextProperties;
21
- actions: ExecutionAction[];
22
- }
23
-
24
- export async function execute(args: ExecutionArgs): Promise<ReadableStream<Uint8Array>> {
25
- return new ReadableStream({
26
- async start(controller) {
27
- try {
28
- await streamEvents(controller, args);
29
- controller.close();
30
- } catch (err) {}
31
- },
32
- });
33
- }
34
-
35
- async function streamEvents(controller: ReadableStreamDefaultController, args: ExecutionArgs) {
36
- const {
37
- deploymentUrl,
38
- langsmithApiKey,
39
- threadId: agrsInitialThreadId,
40
- agent,
41
- nodeName: initialNodeName,
42
- state: initialState,
43
- messages,
44
- actions,
45
- } = args;
46
-
47
- let nodeName = initialNodeName;
48
- let state = initialState;
49
- const { name, assistantId: initialAssistantId } = agent;
50
-
51
- // TODO: deploymentUrl is not required in local development
52
- const client = new Client({ apiUrl: deploymentUrl, apiKey: langsmithApiKey });
53
- let initialThreadId = agrsInitialThreadId;
54
- const wasInitiatedWithExistingThread = !!initialThreadId;
55
- if (initialThreadId && initialThreadId.startsWith("ck-")) {
56
- initialThreadId = initialThreadId.substring(3);
57
- }
58
-
59
- const assistants = await client.assistants.search();
60
- const retrievedAssistant = assistants.find((a) => a.name === name);
61
- const threadId = initialThreadId ?? randomUUID();
62
- if (initialThreadId === threadId) {
63
- await client.threads.get(threadId);
64
- } else {
65
- await client.threads.create({ threadId: threadId });
66
- }
67
-
68
- let agentState = { values: {} };
69
- if (wasInitiatedWithExistingThread) {
70
- agentState = await client.threads.getState(threadId);
71
- }
72
- const agentStateValues = agentState.values as State;
73
- state.messages = agentStateValues.messages;
74
- const mode = wasInitiatedWithExistingThread && nodeName != "__end__" ? "continue" : "start";
75
- state = langGraphDefaultMergeState(state, formatMessages(messages), actions);
76
-
77
- if (mode === "continue") {
78
- await client.threads.updateState(threadId, { values: state, asNode: nodeName });
79
- }
80
-
81
- const assistantId = initialAssistantId ?? retrievedAssistant.assistant_id;
82
- const graphInfo = await client.assistants.getGraph(assistantId);
83
- const streamInput = mode === "start" ? state : null;
84
-
85
- let streamingStateExtractor = new StreamingStateExtractor([]);
86
- let prevNodeName = null;
87
- let emitIntermediateStateUntilEnd = null;
88
- let shouldExit = null;
89
- let externalRunId = null;
90
-
91
- const streamResponse = client.runs.stream(threadId, assistantId, {
92
- input: streamInput,
93
- streamMode: ["events", "values"],
94
- });
95
-
96
- const emit = (message: string) => controller.enqueue(new TextEncoder().encode(message));
97
-
98
- let latestStateValues = {};
99
-
100
- for await (const chunk of streamResponse) {
101
- if (!["events", "values"].includes(chunk.event)) continue;
102
-
103
- if (chunk.event === "values") {
104
- latestStateValues = chunk.data;
105
- continue;
106
- }
107
-
108
- const event = chunk.data;
109
- const currentNodeName = event.name;
110
- const eventType = event.event;
111
- const runId = event.metadata.run_id;
112
- externalRunId = runId;
113
- const metadata = event.metadata;
114
-
115
- shouldExit = shouldExit != null ? shouldExit : metadata["copilotkit:exit"];
116
- const emitIntermediateState = metadata["copilotkit:emit-intermediate-state"];
117
- const forceEmitIntermediateState = metadata["copilotkit:force-emit-intermediate-state"];
118
- const manuallyEmitMessage = metadata["copilotkit:manually-emit-messages"];
119
- const manuallyEmitToolCall = metadata["copilotkit:manually-emit-tool-calls"];
120
- // we only want to update the node name under certain conditions
121
- // since we don't need any internal node names to be sent to the frontend
122
- if (graphInfo["nodes"].some((node) => node.id === currentNodeName)) {
123
- nodeName = currentNodeName;
124
- }
125
-
126
- if (!nodeName) {
127
- continue;
128
- }
129
-
130
- if (forceEmitIntermediateState) {
131
- if (eventType === "on_chain_end") {
132
- state = event.data.output;
133
- emit(
134
- getStateSyncEvent({
135
- threadId,
136
- runId,
137
- agentName: agent.name,
138
- nodeName,
139
- state: event.data.output,
140
- running: true,
141
- active: true,
142
- }),
143
- );
144
- }
145
- continue;
146
- }
147
-
148
- if (manuallyEmitMessage) {
149
- if (eventType === "on_chain_end") {
150
- state = event.data.output;
151
- emit(
152
- JSON.stringify({
153
- event: "on_copilotkit_emit_message",
154
- message: event.data.output,
155
- messageId: randomUUID(),
156
- role: MessageRole.assistant,
157
- }) + "\n",
158
- );
159
- }
160
- continue;
161
- }
162
-
163
- if (manuallyEmitToolCall) {
164
- if (eventType === "on_chain_end") {
165
- state = event.data.output;
166
- emit(
167
- JSON.stringify({
168
- event: "on_copilotkit_emit_tool_call",
169
- name: event.data.output.name,
170
- args: event.data.output.args,
171
- id: event.data.output.id,
172
- }) + "\n",
173
- );
174
- }
175
- continue;
176
- }
177
-
178
- if (emitIntermediateState && emitIntermediateStateUntilEnd == null) {
179
- emitIntermediateStateUntilEnd = nodeName;
180
- }
181
-
182
- if (emitIntermediateState && eventType === "on_chat_model_start") {
183
- // reset the streaming state extractor
184
- streamingStateExtractor = new StreamingStateExtractor(emitIntermediateState);
185
- }
186
-
187
- let updatedState = latestStateValues;
188
-
189
- if (emitIntermediateState && eventType === "on_chat_model_stream") {
190
- streamingStateExtractor.bufferToolCalls(event);
191
- }
192
-
193
- if (emitIntermediateStateUntilEnd !== null) {
194
- updatedState = {
195
- ...updatedState,
196
- ...streamingStateExtractor.extractState(),
197
- };
198
- }
199
-
200
- if (
201
- !emitIntermediateState &&
202
- currentNodeName === emitIntermediateStateUntilEnd &&
203
- eventType === "on_chain_end"
204
- ) {
205
- // stop emitting function call state
206
- emitIntermediateStateUntilEnd = null;
207
- }
208
-
209
- const exitingNode = nodeName === currentNodeName && eventType === "on_chain_end";
210
-
211
- if (
212
- JSON.stringify(updatedState) !== JSON.stringify(state) ||
213
- prevNodeName != nodeName ||
214
- exitingNode
215
- ) {
216
- state = updatedState;
217
- prevNodeName = nodeName;
218
- emit(
219
- getStateSyncEvent({
220
- threadId,
221
- runId,
222
- agentName: agent.name,
223
- nodeName,
224
- state,
225
- running: true,
226
- active: !exitingNode,
227
- }),
228
- );
229
- }
230
-
231
- emit(JSON.stringify(event) + "\n");
232
- }
233
-
234
- state = await client.threads.getState(threadId);
235
- const isEndNode = state.next.length === 0;
236
- nodeName = Object.keys(state.metadata.writes)[0];
237
-
238
- emit(
239
- getStateSyncEvent({
240
- threadId,
241
- runId: externalRunId,
242
- agentName: agent.name,
243
- nodeName: isEndNode ? "__end__" : nodeName,
244
- state: state.values,
245
- running: !shouldExit,
246
- active: false,
247
- }),
248
- );
249
-
250
- return Promise.resolve();
251
- }
252
-
253
- function getStateSyncEvent({
254
- threadId,
255
- runId,
256
- agentName,
257
- nodeName,
258
- state,
259
- running,
260
- active,
261
- }: {
262
- threadId: string;
263
- runId: string;
264
- agentName: string;
265
- nodeName: string;
266
- state: State;
267
- running: boolean;
268
- active: boolean;
269
- }): string {
270
- const stateWithoutMessages = Object.keys(state).reduce((acc, key) => {
271
- if (key !== "messages") {
272
- acc[key] = state[key];
273
- }
274
- return acc;
275
- }, {} as State);
276
-
277
- return (
278
- JSON.stringify({
279
- event: "on_copilotkit_state_sync",
280
- thread_id: threadId,
281
- run_id: runId,
282
- agent_name: agentName,
283
- node_name: nodeName,
284
- active: active,
285
- state: stateWithoutMessages,
286
- running: running,
287
- role: "assistant",
288
- }) + "\n"
289
- );
290
- }
291
-
292
- class StreamingStateExtractor {
293
- private emitIntermediateState: { [key: string]: any }[];
294
- private toolCallBuffer: { [key: string]: string };
295
- private currentToolCall: string | null;
296
- private previouslyParsableState: { [key: string]: any };
297
-
298
- constructor(emitIntermediateState: { [key: string]: any }[]) {
299
- this.emitIntermediateState = emitIntermediateState;
300
- this.toolCallBuffer = {};
301
- this.currentToolCall = null;
302
- this.previouslyParsableState = {};
303
- }
304
-
305
- bufferToolCalls(event: {
306
- data: { chunk: { tool_call_chunks: { name: string | null; args: string }[] } };
307
- }) {
308
- if (event.data.chunk.tool_call_chunks.length > 0) {
309
- const chunk = event.data.chunk.tool_call_chunks[0];
310
-
311
- if (chunk.name !== null) {
312
- this.currentToolCall = chunk.name;
313
- this.toolCallBuffer[this.currentToolCall] = chunk.args;
314
- } else if (this.currentToolCall !== null) {
315
- this.toolCallBuffer[this.currentToolCall] += chunk.args;
316
- }
317
- }
318
- }
319
-
320
- getEmitStateConfig(currentToolName: string): [string | null, string | null] {
321
- for (const config of this.emitIntermediateState) {
322
- const stateKey = config["state_key"];
323
- const tool = config["tool"];
324
- const toolArgument = config["tool_argument"];
325
-
326
- if (currentToolName === tool) {
327
- return [toolArgument, stateKey];
328
- }
329
- }
330
- return [null, null];
331
- }
332
-
333
- extractState(): State {
334
- const state: State = {};
335
-
336
- for (const [key, value] of Object.entries(this.toolCallBuffer)) {
337
- const [argumentName, stateKey] = this.getEmitStateConfig(key);
338
-
339
- if (stateKey === null) {
340
- continue;
341
- }
342
-
343
- let parsedValue;
344
- try {
345
- parsedValue = parsePartialJson(value);
346
- } catch (error) {
347
- if (key in this.previouslyParsableState) {
348
- parsedValue = this.previouslyParsableState[key];
349
- } else {
350
- continue;
351
- }
352
- }
353
-
354
- this.previouslyParsableState[key] = parsedValue;
355
-
356
- if (!argumentName) {
357
- state[stateKey] = parsedValue;
358
- } else {
359
- state[stateKey] = parsedValue[argumentName];
360
- }
361
- }
362
-
363
- return state;
364
- }
365
- }
366
-
367
- // Start of Selection
368
- function langGraphDefaultMergeState(
369
- state: State,
370
- messages: CopilotKitBaseMessage[],
371
- actions: ExecutionAction[],
372
- ): State {
373
- if (messages.length > 0 && "role" in messages[0] && messages[0].role === "system") {
374
- // remove system message
375
- messages = messages.slice(1);
376
- }
377
-
378
- // merge with existing messages
379
- const mergedMessages = state.messages || [];
380
- const existingMessageIds = new Set(mergedMessages.map((message) => message.id));
381
-
382
- for (const message of messages) {
383
- if (!existingMessageIds.has(message.id)) {
384
- mergedMessages.push(message);
385
- }
386
- }
387
-
388
- return deepMerge(state, {
389
- messages: mergedMessages,
390
- copilotkit: {
391
- actions,
392
- },
393
- });
394
- }
395
-
396
- function deepMerge(obj1: State, obj2: State) {
397
- let result = { ...obj1 };
398
- for (let key in obj2) {
399
- if (typeof obj2[key] === "object" && !Array.isArray(obj2[key])) {
400
- if (obj1[key]) {
401
- result[key] = deepMerge(obj1[key], obj2[key]);
402
- } else {
403
- result[key] = { ...obj2[key] };
404
- }
405
- } else {
406
- result[key] = obj2[key];
407
- }
408
- }
409
- return result;
410
- }
411
-
412
- function formatMessages(messages: CopilotKitBaseMessage[]): CopilotKitBaseMessage[] {
413
- return messages.map((message) => {
414
- if ("content" in message) {
415
- return message;
416
- }
417
- if ("arguments" in message) {
418
- const toolCall = {
419
- name: message["name"],
420
- args: message["arguments"],
421
- id: message["id"],
422
- };
423
- return {
424
- ...message,
425
- content: "",
426
- tool_calls: [toolCall],
427
- role: message["role"] ?? MessageRole.assistant,
428
- };
429
- }
430
- if ("actionExecutionId" in message) {
431
- return {
432
- ...message,
433
- content: message["result"],
434
- name: message["actionName"],
435
- tool_call_id: message["actionExecutionId"] as string,
436
- role: message["role"] ?? MessageRole.user,
437
- };
438
- }
439
- return message;
440
- });
441
- }