@copilotkit/runtime 1.3.11 → 1.3.12-feat-langgraph-cloud-release-alpha.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.
- package/CHANGELOG.md +8 -0
- package/dist/{chunk-REA4Z4VP.mjs → chunk-6A7HQSQE.mjs} +2 -2
- package/dist/{chunk-ZSMR26MX.mjs → chunk-BPLF4QB2.mjs} +2 -2
- package/dist/{chunk-BYL3ABWM.mjs → chunk-IPCABAGS.mjs} +2 -2
- package/dist/{chunk-AP2CCJ3J.mjs → chunk-RKGJG3QX.mjs} +552 -122
- package/dist/chunk-RKGJG3QX.mjs.map +1 -0
- package/dist/{chunk-ZUQH5YKI.mjs → chunk-Z5LICW7Z.mjs} +35 -8
- package/dist/chunk-Z5LICW7Z.mjs.map +1 -0
- package/dist/{copilot-runtime-df3527ad.d.ts → copilot-runtime-aba7d4b4.d.ts} +27 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +625 -168
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -7
- package/dist/index.mjs.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +625 -168
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +11 -7
- package/dist/lib/integrations/index.d.ts +2 -2
- package/dist/lib/integrations/index.js +3 -1
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +4 -4
- package/dist/lib/integrations/nest/index.d.ts +1 -1
- package/dist/lib/integrations/nest/index.js +3 -1
- package/dist/lib/integrations/nest/index.js.map +1 -1
- package/dist/lib/integrations/nest/index.mjs +2 -2
- package/dist/lib/integrations/node-express/index.d.ts +1 -1
- package/dist/lib/integrations/node-express/index.js +3 -1
- package/dist/lib/integrations/node-express/index.js.map +1 -1
- package/dist/lib/integrations/node-express/index.mjs +2 -2
- package/dist/lib/integrations/node-http/index.d.ts +1 -1
- package/dist/lib/integrations/node-http/index.js +3 -1
- package/dist/lib/integrations/node-http/index.js.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +1 -1
- package/package.json +6 -4
- package/src/agents/langgraph/event-source.ts +22 -67
- package/src/lib/runtime/copilot-runtime.ts +58 -11
- package/src/lib/runtime/remote-action-constructors.ts +281 -0
- package/src/lib/runtime/remote-actions.ts +65 -159
- package/src/lib/runtime/remote-lg-cloud-action.ts +438 -0
- package/dist/chunk-AP2CCJ3J.mjs.map +0 -1
- package/dist/chunk-ZUQH5YKI.mjs.map +0 -1
- /package/dist/{chunk-REA4Z4VP.mjs.map → chunk-6A7HQSQE.mjs.map} +0 -0
- /package/dist/{chunk-ZSMR26MX.mjs.map → chunk-BPLF4QB2.mjs.map} +0 -0
- /package/dist/{chunk-BYL3ABWM.mjs.map → chunk-IPCABAGS.mjs.map} +0 -0
|
@@ -15,63 +15,7 @@ interface LangGraphEventWithState {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export class RemoteLangGraphEventSource {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
async streamResponse(response: Response) {
|
|
21
|
-
const reader = response.body!.getReader();
|
|
22
|
-
const decoder = new TextDecoder();
|
|
23
|
-
let buffer = [];
|
|
24
|
-
const eventStream$ = this.eventStream$;
|
|
25
|
-
|
|
26
|
-
function flushBuffer() {
|
|
27
|
-
const currentBuffer = buffer.join("");
|
|
28
|
-
if (currentBuffer.trim().length === 0) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const parts = currentBuffer.split("\n");
|
|
32
|
-
if (parts.length === 0) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const lastPartIsComplete = currentBuffer.endsWith("\n");
|
|
37
|
-
|
|
38
|
-
// truncate buffer
|
|
39
|
-
buffer = [];
|
|
40
|
-
|
|
41
|
-
if (!lastPartIsComplete) {
|
|
42
|
-
// put back the last part
|
|
43
|
-
buffer.push(parts.pop());
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
parts
|
|
47
|
-
.map((part) => part.trim())
|
|
48
|
-
.filter((part) => part != "")
|
|
49
|
-
.forEach((part) => {
|
|
50
|
-
eventStream$.next(JSON.parse(part));
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
while (true) {
|
|
56
|
-
const { done, value } = await reader.read();
|
|
57
|
-
|
|
58
|
-
if (!done) {
|
|
59
|
-
buffer.push(decoder.decode(value, { stream: true }));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
flushBuffer();
|
|
63
|
-
|
|
64
|
-
if (done) {
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.error("Error in stream", error);
|
|
70
|
-
eventStream$.error(error);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
eventStream$.complete();
|
|
74
|
-
}
|
|
18
|
+
public eventStream$ = new ReplaySubject<LangGraphEvent>();
|
|
75
19
|
|
|
76
20
|
private shouldEmitToolCall(
|
|
77
21
|
shouldEmitToolCalls: string | string[] | boolean,
|
|
@@ -93,7 +37,7 @@ export class RemoteLangGraphEventSource {
|
|
|
93
37
|
scan(
|
|
94
38
|
(acc, event) => {
|
|
95
39
|
if (event.event === LangGraphEventTypes.OnChatModelStream) {
|
|
96
|
-
// @ts-
|
|
40
|
+
// @ts-expect-error -- LangGraph Cloud implementation stores data outside of kwargs
|
|
97
41
|
const content = event.data?.chunk?.kwargs?.content ?? event.data?.chunk?.content;
|
|
98
42
|
|
|
99
43
|
if (typeof content === "string") {
|
|
@@ -104,20 +48,28 @@ export class RemoteLangGraphEventSource {
|
|
|
104
48
|
acc.content = null;
|
|
105
49
|
}
|
|
106
50
|
|
|
107
|
-
|
|
51
|
+
const toolCallChunks =
|
|
52
|
+
// @ts-expect-error -- LangGraph Cloud implementation stores data outside of kwargs
|
|
53
|
+
event.data?.chunk?.kwargs?.tool_call_chunks ?? event.data?.chunk?.tool_call_chunks;
|
|
54
|
+
|
|
55
|
+
const toolCallMessageId =
|
|
56
|
+
event.data?.chunk?.kwargs?.id ??
|
|
57
|
+
(event.data?.chunk?.id as unknown as string | undefined);
|
|
58
|
+
|
|
59
|
+
if (toolCallChunks && toolCallChunks.length > 0) {
|
|
108
60
|
acc.prevToolCallMessageId = acc.toolCallMessageId;
|
|
109
|
-
acc.toolCallMessageId =
|
|
110
|
-
if (
|
|
111
|
-
acc.toolCallName =
|
|
61
|
+
acc.toolCallMessageId = toolCallMessageId;
|
|
62
|
+
if (toolCallChunks[0]?.name) {
|
|
63
|
+
acc.toolCallName = toolCallChunks[0].name;
|
|
112
64
|
}
|
|
113
|
-
if (
|
|
114
|
-
acc.toolCallId =
|
|
65
|
+
if (toolCallChunks[0]?.id) {
|
|
66
|
+
acc.toolCallId = toolCallChunks[0].id;
|
|
115
67
|
}
|
|
116
68
|
acc.prevMessageId = acc.messageId;
|
|
117
|
-
acc.messageId =
|
|
69
|
+
acc.messageId = toolCallMessageId;
|
|
118
70
|
} else if (acc.content && acc.content != "") {
|
|
119
71
|
acc.prevMessageId = acc.messageId;
|
|
120
|
-
acc.messageId =
|
|
72
|
+
acc.messageId = toolCallMessageId;
|
|
121
73
|
} else {
|
|
122
74
|
acc.prevToolCallMessageId = acc.toolCallMessageId;
|
|
123
75
|
acc.prevMessageId = acc.messageId;
|
|
@@ -266,7 +218,10 @@ export class RemoteLangGraphEventSource {
|
|
|
266
218
|
}
|
|
267
219
|
}
|
|
268
220
|
|
|
269
|
-
const args =
|
|
221
|
+
const args =
|
|
222
|
+
eventWithState.event.data?.chunk?.kwargs?.tool_call_chunks?.[0]?.args ??
|
|
223
|
+
// @ts-expect-error -- sdf
|
|
224
|
+
eventWithState.event.data?.chunk?.tool_call_chunks?.[0]?.args;
|
|
270
225
|
const content = eventWithState.content;
|
|
271
226
|
|
|
272
227
|
// Tool call args: emit ActionExecutionArgs
|
|
@@ -12,19 +12,22 @@
|
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { Action, actionParametersToJsonSchema, Parameter
|
|
16
|
-
import { RemoteChain, RemoteChainParameters
|
|
15
|
+
import { Action, actionParametersToJsonSchema, Parameter } from "@copilotkit/shared";
|
|
16
|
+
import { CopilotServiceAdapter, RemoteChain, RemoteChainParameters } from "../../service-adapters";
|
|
17
17
|
import { MessageInput } from "../../graphql/inputs/message.input";
|
|
18
18
|
import { ActionInput } from "../../graphql/inputs/action.input";
|
|
19
19
|
import { RuntimeEventSource } from "../../service-adapters/events";
|
|
20
20
|
import { convertGqlInputToMessages } from "../../service-adapters/conversion";
|
|
21
|
-
import {
|
|
21
|
+
import { Message } from "../../graphql/types/converted";
|
|
22
22
|
import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
|
|
23
23
|
import {
|
|
24
|
-
setupRemoteActions,
|
|
25
|
-
RemoteActionDefinition,
|
|
26
|
-
LangGraphAgentAction,
|
|
27
24
|
isLangGraphAgentAction,
|
|
25
|
+
LangGraphAgentAction,
|
|
26
|
+
EndpointType,
|
|
27
|
+
setupRemoteActions,
|
|
28
|
+
EndpointDefinition,
|
|
29
|
+
CopilotKitEndpoint,
|
|
30
|
+
LangGraphCloudEndpoint,
|
|
28
31
|
} from "./remote-actions";
|
|
29
32
|
import { GraphQLContext } from "../integrations/shared";
|
|
30
33
|
import { AgentSessionInput } from "../../graphql/inputs/agent-session.input";
|
|
@@ -121,10 +124,15 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
|
|
|
121
124
|
*/
|
|
122
125
|
actions?: ActionsConfiguration<T>;
|
|
123
126
|
|
|
127
|
+
/*
|
|
128
|
+
* Deprecated: See `remoteEndpoints`.
|
|
129
|
+
*/
|
|
130
|
+
remoteActions?: EndpointDefinition[];
|
|
131
|
+
|
|
124
132
|
/*
|
|
125
133
|
* A list of remote actions that can be executed.
|
|
126
134
|
*/
|
|
127
|
-
|
|
135
|
+
remoteEndpoints?: EndpointDefinition[];
|
|
128
136
|
|
|
129
137
|
/*
|
|
130
138
|
* An array of LangServer URLs.
|
|
@@ -134,7 +142,7 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
|
|
|
134
142
|
|
|
135
143
|
export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
136
144
|
public actions: ActionsConfiguration<T>;
|
|
137
|
-
private
|
|
145
|
+
private remoteEndpointDefinitions: EndpointDefinition[];
|
|
138
146
|
private langserve: Promise<Action<any>>[] = [];
|
|
139
147
|
private onBeforeRequest?: OnBeforeRequestHandler;
|
|
140
148
|
private onAfterRequest?: OnAfterRequestHandler;
|
|
@@ -147,7 +155,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
147
155
|
this.langserve.push(remoteChain.toAction());
|
|
148
156
|
}
|
|
149
157
|
|
|
150
|
-
this.
|
|
158
|
+
this.remoteEndpointDefinitions = params?.remoteEndpoints || [];
|
|
151
159
|
|
|
152
160
|
this.onBeforeRequest = params?.middleware?.onBeforeRequest;
|
|
153
161
|
this.onAfterRequest = params?.middleware?.onAfterRequest;
|
|
@@ -244,7 +252,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
244
252
|
request: CopilotRuntimeRequest,
|
|
245
253
|
): Promise<CopilotRuntimeResponse> {
|
|
246
254
|
const { messages: rawMessages, outputMessagesPromise, graphqlContext, agentSession } = request;
|
|
247
|
-
const { threadId
|
|
255
|
+
const { threadId, agentName, nodeName } = agentSession;
|
|
248
256
|
const serverSideActions = await this.getServerSideActions(request);
|
|
249
257
|
|
|
250
258
|
const messages = convertGqlInputToMessages(rawMessages);
|
|
@@ -331,8 +339,17 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
331
339
|
console.error("Error loading langserve chain:", error);
|
|
332
340
|
}
|
|
333
341
|
}
|
|
342
|
+
|
|
343
|
+
const remoteEndpointDefinitions = this.remoteEndpointDefinitions.map(
|
|
344
|
+
(endpoint) =>
|
|
345
|
+
({
|
|
346
|
+
...endpoint,
|
|
347
|
+
type: this.resolveEndpointType(endpoint),
|
|
348
|
+
}) as EndpointDefinition,
|
|
349
|
+
);
|
|
350
|
+
|
|
334
351
|
const remoteActions = await setupRemoteActions({
|
|
335
|
-
|
|
352
|
+
remoteEndpointDefinitions,
|
|
336
353
|
graphqlContext,
|
|
337
354
|
messages: inputMessages,
|
|
338
355
|
agentStates,
|
|
@@ -346,6 +363,19 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
346
363
|
|
|
347
364
|
return [...configuredActions, ...langserveFunctions, ...remoteActions];
|
|
348
365
|
}
|
|
366
|
+
|
|
367
|
+
private resolveEndpointType(endpoint: EndpointDefinition) {
|
|
368
|
+
if (
|
|
369
|
+
!endpoint.type &&
|
|
370
|
+
"langsmithApiKey" in endpoint &&
|
|
371
|
+
"deploymentUrl" in endpoint &&
|
|
372
|
+
"agents" in endpoint
|
|
373
|
+
) {
|
|
374
|
+
return EndpointType.LangGraphCloud;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return endpoint.type;
|
|
378
|
+
}
|
|
349
379
|
}
|
|
350
380
|
|
|
351
381
|
export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {
|
|
@@ -359,3 +389,20 @@ export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): Ac
|
|
|
359
389
|
}
|
|
360
390
|
return allTools;
|
|
361
391
|
}
|
|
392
|
+
|
|
393
|
+
// The two functions below are "factory functions", meant to create the action objects that adhere to the expected interfaces
|
|
394
|
+
export function copilotKitEndpoint(config: Omit<CopilotKitEndpoint, "type">): CopilotKitEndpoint {
|
|
395
|
+
return {
|
|
396
|
+
...config,
|
|
397
|
+
type: EndpointType.CopilotKit,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function langGraphCloudEndpoint(
|
|
402
|
+
config: Omit<LangGraphCloudEndpoint, "type">,
|
|
403
|
+
): LangGraphCloudEndpoint {
|
|
404
|
+
return {
|
|
405
|
+
...config,
|
|
406
|
+
type: EndpointType.LangGraphCloud,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
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
|
+
agent,
|
|
58
|
+
threadId,
|
|
59
|
+
nodeName,
|
|
60
|
+
messages,
|
|
61
|
+
state,
|
|
62
|
+
properties: graphqlContext.properties,
|
|
63
|
+
actions: actionInputsWithoutAgents.map((action) => ({
|
|
64
|
+
name: action.name,
|
|
65
|
+
description: action.description,
|
|
66
|
+
parameters: JSON.parse(action.jsonSchema) as string,
|
|
67
|
+
})),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const eventSource = new RemoteLangGraphEventSource();
|
|
71
|
+
streamResponse(response, eventSource.eventStream$);
|
|
72
|
+
return eventSource.processLangGraphEvents();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.error(
|
|
75
|
+
{ url: endpoint.deploymentUrl, status: 500, body: error.message },
|
|
76
|
+
"Failed to execute LangGraph Cloud agent",
|
|
77
|
+
);
|
|
78
|
+
throw new Error("Failed to execute LangGraph Cloud agent");
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
return [...agents];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function constructRemoteActions({
|
|
87
|
+
json,
|
|
88
|
+
url,
|
|
89
|
+
onBeforeRequest,
|
|
90
|
+
graphqlContext,
|
|
91
|
+
logger,
|
|
92
|
+
messages,
|
|
93
|
+
agentStates,
|
|
94
|
+
}: {
|
|
95
|
+
json: RemoteActionInfoResponse;
|
|
96
|
+
url: string;
|
|
97
|
+
onBeforeRequest?: CopilotKitEndpoint["onBeforeRequest"];
|
|
98
|
+
graphqlContext: GraphQLContext;
|
|
99
|
+
logger: Logger;
|
|
100
|
+
messages: Message[];
|
|
101
|
+
agentStates?: AgentStateInput[];
|
|
102
|
+
}): Action<any>[] {
|
|
103
|
+
const actions = json["actions"].map((action) => ({
|
|
104
|
+
name: action.name,
|
|
105
|
+
description: action.description,
|
|
106
|
+
parameters: action.parameters,
|
|
107
|
+
handler: async (args: any) => {
|
|
108
|
+
logger.debug({ actionName: action.name, args }, "Executing remote action");
|
|
109
|
+
|
|
110
|
+
const headers = createHeaders(onBeforeRequest, graphqlContext);
|
|
111
|
+
telemetry.capture("oss.runtime.remote_action_executed", {});
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch(`${url}/actions/execute`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers,
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
name: action.name,
|
|
119
|
+
arguments: args,
|
|
120
|
+
properties: graphqlContext.properties,
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
logger.error(
|
|
126
|
+
{ url, status: response.status, body: await response.text() },
|
|
127
|
+
"Failed to execute remote action",
|
|
128
|
+
);
|
|
129
|
+
return "Failed to execute remote action";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const requestResult = await response.json();
|
|
133
|
+
|
|
134
|
+
const result = requestResult["result"];
|
|
135
|
+
logger.debug({ actionName: action.name, result }, "Executed remote action");
|
|
136
|
+
return result;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
logger.error(
|
|
139
|
+
{ error: error.message ? error.message : error + "" },
|
|
140
|
+
"Failed to execute remote action",
|
|
141
|
+
);
|
|
142
|
+
return "Failed to execute remote action";
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
const agents = json["agents"].map((agent) => ({
|
|
148
|
+
name: agent.name,
|
|
149
|
+
description: agent.description,
|
|
150
|
+
parameters: [],
|
|
151
|
+
handler: async (_args: any) => {},
|
|
152
|
+
|
|
153
|
+
langGraphAgentHandler: async ({
|
|
154
|
+
name,
|
|
155
|
+
actionInputsWithoutAgents,
|
|
156
|
+
threadId,
|
|
157
|
+
nodeName,
|
|
158
|
+
}: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
|
|
159
|
+
logger.debug({ actionName: agent.name }, "Executing remote agent");
|
|
160
|
+
|
|
161
|
+
const headers = createHeaders(onBeforeRequest, graphqlContext);
|
|
162
|
+
telemetry.capture("oss.runtime.remote_action_executed", {});
|
|
163
|
+
|
|
164
|
+
let state = {};
|
|
165
|
+
if (agentStates) {
|
|
166
|
+
const jsonState = agentStates.find((state) => state.agentName === name)?.state;
|
|
167
|
+
if (jsonState) {
|
|
168
|
+
state = JSON.parse(jsonState);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const response = await fetch(`${url}/agents/execute`, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers,
|
|
175
|
+
body: JSON.stringify({
|
|
176
|
+
name,
|
|
177
|
+
threadId,
|
|
178
|
+
nodeName,
|
|
179
|
+
messages,
|
|
180
|
+
state,
|
|
181
|
+
properties: graphqlContext.properties,
|
|
182
|
+
actions: actionInputsWithoutAgents.map((action) => ({
|
|
183
|
+
name: action.name,
|
|
184
|
+
description: action.description,
|
|
185
|
+
parameters: JSON.parse(action.jsonSchema),
|
|
186
|
+
})),
|
|
187
|
+
}),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
logger.error(
|
|
192
|
+
{ url, status: response.status, body: await response.text() },
|
|
193
|
+
"Failed to execute remote agent",
|
|
194
|
+
);
|
|
195
|
+
throw new Error("Failed to execute remote agent");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const eventSource = new RemoteLangGraphEventSource();
|
|
199
|
+
streamResponse(response.body!, eventSource.eventStream$);
|
|
200
|
+
return eventSource.processLangGraphEvents();
|
|
201
|
+
},
|
|
202
|
+
}));
|
|
203
|
+
|
|
204
|
+
return [...actions, ...agents];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function streamResponse(
|
|
208
|
+
response: ReadableStream<Uint8Array>,
|
|
209
|
+
eventStream$: ReplaySubject<LangGraphEvent>,
|
|
210
|
+
) {
|
|
211
|
+
const reader = response.getReader();
|
|
212
|
+
const decoder = new TextDecoder();
|
|
213
|
+
let buffer = [];
|
|
214
|
+
|
|
215
|
+
function flushBuffer() {
|
|
216
|
+
const currentBuffer = buffer.join("");
|
|
217
|
+
if (currentBuffer.trim().length === 0) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const parts = currentBuffer.split("\n");
|
|
221
|
+
if (parts.length === 0) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const lastPartIsComplete = currentBuffer.endsWith("\n");
|
|
226
|
+
|
|
227
|
+
// truncate buffer
|
|
228
|
+
buffer = [];
|
|
229
|
+
|
|
230
|
+
if (!lastPartIsComplete) {
|
|
231
|
+
// put back the last part
|
|
232
|
+
buffer.push(parts.pop());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
parts
|
|
236
|
+
.map((part) => part.trim())
|
|
237
|
+
.filter((part) => part != "")
|
|
238
|
+
.forEach((part) => {
|
|
239
|
+
eventStream$.next(JSON.parse(part));
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
while (true) {
|
|
245
|
+
const { done, value } = await reader.read();
|
|
246
|
+
|
|
247
|
+
if (!done) {
|
|
248
|
+
buffer.push(decoder.decode(value, { stream: true }));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
flushBuffer();
|
|
252
|
+
|
|
253
|
+
if (done) {
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error("Error in stream", error);
|
|
259
|
+
eventStream$.error(error);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
eventStream$.complete();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function createHeaders(
|
|
266
|
+
onBeforeRequest: CopilotKitEndpoint["onBeforeRequest"],
|
|
267
|
+
graphqlContext: GraphQLContext,
|
|
268
|
+
) {
|
|
269
|
+
const headers = {
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
if (onBeforeRequest) {
|
|
274
|
+
const { headers: additionalHeaders } = onBeforeRequest({ ctx: graphqlContext });
|
|
275
|
+
if (additionalHeaders) {
|
|
276
|
+
Object.assign(headers, additionalHeaders);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return headers;
|
|
281
|
+
}
|