@copilotkit/runtime 1.6.0 → 1.7.0-next.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 +21 -0
- package/dist/{chunk-MPI4JZZR.mjs → chunk-2BN7NZNC.mjs} +2 -2
- package/dist/{chunk-DUW72ZZB.mjs → chunk-34Y5DNNJ.mjs} +88 -67
- package/dist/chunk-34Y5DNNJ.mjs.map +1 -0
- package/dist/{chunk-WUMAYJP3.mjs → chunk-PH24IU7T.mjs} +2 -2
- package/dist/{chunk-2RP2NR4F.mjs → chunk-ZYFN76KV.mjs} +2 -2
- package/dist/index.js +87 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/lib/index.js +87 -66
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +4 -4
- package/dist/lib/integrations/index.js +4 -1
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +4 -4
- package/dist/lib/integrations/nest/index.js +4 -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.js +4 -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.js +4 -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 +2 -2
- package/src/graphql/resolvers/copilot.resolver.ts +4 -0
- package/src/lib/runtime/__tests__/remote-action-constructors.test.ts +45 -35
- package/src/lib/runtime/copilot-runtime.ts +14 -14
- package/src/lib/runtime/remote-action-constructors.ts +28 -68
- package/src/lib/runtime/remote-actions.ts +5 -5
- package/src/lib/streaming.ts +59 -0
- package/src/service-adapters/events.ts +3 -3
- package/dist/chunk-DUW72ZZB.mjs.map +0 -1
- /package/dist/{chunk-MPI4JZZR.mjs.map → chunk-2BN7NZNC.mjs.map} +0 -0
- /package/dist/{chunk-WUMAYJP3.mjs.map → chunk-PH24IU7T.mjs.map} +0 -0
- /package/dist/{chunk-2RP2NR4F.mjs.map → chunk-ZYFN76KV.mjs.map} +0 -0
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"version": "1.
|
|
12
|
+
"version": "1.7.0-next.0",
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"main": "./dist/index.js",
|
|
15
15
|
"module": "./dist/index.mjs",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"rxjs": "^7.8.1",
|
|
60
60
|
"type-graphql": "2.0.0-rc.1",
|
|
61
61
|
"zod": "^3.23.3",
|
|
62
|
-
"@copilotkit/shared": "1.
|
|
62
|
+
"@copilotkit/shared": "1.7.0-next.0"
|
|
63
63
|
},
|
|
64
64
|
"keywords": [
|
|
65
65
|
"copilotkit",
|
|
@@ -196,6 +196,10 @@ export class CopilotResolver {
|
|
|
196
196
|
rejectOutputMessagesPromise = reject;
|
|
197
197
|
});
|
|
198
198
|
|
|
199
|
+
if (copilotCloudPublicApiKey) {
|
|
200
|
+
ctx.properties["copilotCloudPublicApiKey"] = copilotCloudPublicApiKey;
|
|
201
|
+
}
|
|
202
|
+
|
|
199
203
|
logger.debug("Processing");
|
|
200
204
|
const {
|
|
201
205
|
eventSource,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
1
2
|
import { TextEncoder } from "util";
|
|
2
3
|
import { RemoteLangGraphEventSource } from "../../../agents/langgraph/event-source";
|
|
3
4
|
import telemetry from "../../telemetry-client";
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
createHeaders,
|
|
8
9
|
} from "../remote-action-constructors";
|
|
9
10
|
import { execute } from "../remote-lg-action";
|
|
11
|
+
import { ReplaySubject } from "rxjs";
|
|
10
12
|
|
|
11
13
|
// Mock external dependencies
|
|
12
14
|
jest.mock("../remote-lg-action", () => ({
|
|
@@ -49,7 +51,7 @@ beforeEach(() => {
|
|
|
49
51
|
|
|
50
52
|
describe("remote action constructors", () => {
|
|
51
53
|
describe("constructLGCRemoteAction", () => {
|
|
52
|
-
it("should create an agent with
|
|
54
|
+
it("should create an agent with remoteAgentHandler that processes events", async () => {
|
|
53
55
|
// Arrange: simulate execute returning a dummy ReadableStream
|
|
54
56
|
const dummyEncodedEvent = new TextEncoder().encode(JSON.stringify({ event: "test" }) + "\n");
|
|
55
57
|
const readerMock = {
|
|
@@ -72,7 +74,7 @@ describe("remote action constructors", () => {
|
|
|
72
74
|
processLangGraphEvents: processLangGraphEventsMock,
|
|
73
75
|
}));
|
|
74
76
|
|
|
75
|
-
// Act: build the action and call
|
|
77
|
+
// Act: build the action and call remoteAgentHandler
|
|
76
78
|
const actions = constructLGCRemoteAction({
|
|
77
79
|
endpoint,
|
|
78
80
|
graphqlContext,
|
|
@@ -84,7 +86,7 @@ describe("remote action constructors", () => {
|
|
|
84
86
|
const action = actions[0];
|
|
85
87
|
expect(action.name).toEqual(dummyAgent.name);
|
|
86
88
|
|
|
87
|
-
const result = await action.
|
|
89
|
+
const result = await action.remoteAgentHandler({
|
|
88
90
|
name: dummyAgent.name,
|
|
89
91
|
actionInputsWithoutAgents: [],
|
|
90
92
|
threadId: "thread1",
|
|
@@ -160,26 +162,46 @@ describe("remote action constructors", () => {
|
|
|
160
162
|
});
|
|
161
163
|
|
|
162
164
|
it("should create remote agent handler that processes events", async () => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
165
|
+
const json = {
|
|
166
|
+
agents: [
|
|
167
|
+
{
|
|
168
|
+
name: "agent2",
|
|
169
|
+
description: "agent desc",
|
|
170
|
+
type: "langgraph", // Add type to match RemoteAgentType.LangGraph
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
actions: [
|
|
174
|
+
{
|
|
175
|
+
name: "action1",
|
|
176
|
+
description: "action desc",
|
|
177
|
+
parameters: { param: "value" },
|
|
178
|
+
},
|
|
179
|
+
],
|
|
173
180
|
};
|
|
174
|
-
global.fetch = jest.fn().mockResolvedValue({
|
|
175
|
-
ok: true,
|
|
176
|
-
text: jest.fn().mockResolvedValue("ok"),
|
|
177
|
-
body: dummyStreamResponse,
|
|
178
|
-
});
|
|
179
181
|
|
|
180
|
-
const
|
|
182
|
+
const dummyEncodedAgentEvent = new TextEncoder().encode('{"type":"data","content":"test"}\n');
|
|
183
|
+
|
|
184
|
+
const mockResponse = new Response(
|
|
185
|
+
new ReadableStream({
|
|
186
|
+
start(controller) {
|
|
187
|
+
controller.enqueue(dummyEncodedAgentEvent);
|
|
188
|
+
controller.close();
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
{
|
|
192
|
+
status: 200,
|
|
193
|
+
statusText: "OK",
|
|
194
|
+
headers: new Headers({
|
|
195
|
+
"content-type": "application/json",
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
global.fetch = jest.fn().mockResolvedValue(mockResponse);
|
|
201
|
+
|
|
202
|
+
const processLangGraphEventsMock = jest.fn().mockResolvedValue("agent events processed");
|
|
181
203
|
(RemoteLangGraphEventSource as jest.Mock).mockImplementation(() => ({
|
|
182
|
-
eventStream$:
|
|
204
|
+
eventStream$: new ReplaySubject(),
|
|
183
205
|
processLangGraphEvents: processLangGraphEventsMock,
|
|
184
206
|
}));
|
|
185
207
|
|
|
@@ -192,29 +214,17 @@ describe("remote action constructors", () => {
|
|
|
192
214
|
messages: [],
|
|
193
215
|
agentStates,
|
|
194
216
|
});
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const remoteAgentHandler = (actionsArray[1] as any).langGraphAgentHandler;
|
|
217
|
+
|
|
218
|
+
const remoteAgentHandler = (actionsArray[1] as any).remoteAgentHandler;
|
|
198
219
|
const result = await remoteAgentHandler({
|
|
199
220
|
name: "agent2",
|
|
200
221
|
actionInputsWithoutAgents: [],
|
|
201
222
|
threadId: "thread2",
|
|
202
223
|
nodeName: "node2",
|
|
203
|
-
additionalMessages: [],
|
|
204
|
-
metaEvents: [],
|
|
205
224
|
});
|
|
225
|
+
|
|
206
226
|
expect(processLangGraphEventsMock).toHaveBeenCalled();
|
|
207
227
|
expect(result).toBe("agent events processed");
|
|
208
|
-
|
|
209
|
-
// Check telemetry.capture for agent execution
|
|
210
|
-
expect(telemetry.capture).toHaveBeenCalledWith(
|
|
211
|
-
"oss.runtime.remote_action_executed",
|
|
212
|
-
expect.objectContaining({
|
|
213
|
-
agentExecution: true,
|
|
214
|
-
type: "self-hosted",
|
|
215
|
-
agentsAmount: 1,
|
|
216
|
-
}),
|
|
217
|
-
);
|
|
218
228
|
});
|
|
219
229
|
});
|
|
220
230
|
|
|
@@ -39,8 +39,8 @@ import { Message } from "../../graphql/types/converted";
|
|
|
39
39
|
import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
|
|
40
40
|
|
|
41
41
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
isRemoteAgentAction,
|
|
43
|
+
RemoteAgentAction,
|
|
44
44
|
EndpointType,
|
|
45
45
|
setupRemoteActions,
|
|
46
46
|
EndpointDefinition,
|
|
@@ -305,7 +305,7 @@ please use an LLM adapter instead.`,
|
|
|
305
305
|
(action) =>
|
|
306
306
|
// TODO-AGENTS: do not exclude ALL server side actions
|
|
307
307
|
!serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
|
|
308
|
-
// !
|
|
308
|
+
// !isRemoteAgentAction(
|
|
309
309
|
// serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
|
|
310
310
|
// ),
|
|
311
311
|
),
|
|
@@ -322,7 +322,6 @@ please use an LLM adapter instead.`,
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
|
|
325
|
-
const headers = createHeaders(null, graphqlContext);
|
|
326
325
|
const agents = this.remoteEndpointDefinitions.reduce(
|
|
327
326
|
async (acc: Promise<Agent[]>, endpoint) => {
|
|
328
327
|
const agents = await acc;
|
|
@@ -355,12 +354,12 @@ please use an LLM adapter instead.`,
|
|
|
355
354
|
description: string;
|
|
356
355
|
}>;
|
|
357
356
|
}
|
|
358
|
-
|
|
359
|
-
const fetchUrl = `${
|
|
357
|
+
const cpkEndpoint = endpoint as CopilotKitEndpoint;
|
|
358
|
+
const fetchUrl = `${endpoint.url}/info`;
|
|
360
359
|
try {
|
|
361
360
|
const response = await fetch(fetchUrl, {
|
|
362
361
|
method: "POST",
|
|
363
|
-
headers,
|
|
362
|
+
headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
|
|
364
363
|
body: JSON.stringify({ properties: graphqlContext.properties }),
|
|
365
364
|
});
|
|
366
365
|
if (!response.ok) {
|
|
@@ -444,11 +443,12 @@ please use an LLM adapter instead.`,
|
|
|
444
443
|
agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
|
|
445
444
|
!("type" in agentWithEndpoint.endpoint)
|
|
446
445
|
) {
|
|
447
|
-
const
|
|
446
|
+
const cpkEndpoint = agentWithEndpoint.endpoint as CopilotKitEndpoint;
|
|
447
|
+
const fetchUrl = `${cpkEndpoint.url}/agents/state`;
|
|
448
448
|
try {
|
|
449
449
|
const response = await fetch(fetchUrl, {
|
|
450
450
|
method: "POST",
|
|
451
|
-
headers,
|
|
451
|
+
headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
|
|
452
452
|
body: JSON.stringify({
|
|
453
453
|
properties: graphqlContext.properties,
|
|
454
454
|
threadId,
|
|
@@ -505,8 +505,8 @@ please use an LLM adapter instead.`,
|
|
|
505
505
|
const messages = convertGqlInputToMessages(rawMessages);
|
|
506
506
|
|
|
507
507
|
const currentAgent = serverSideActions.find(
|
|
508
|
-
(action) => action.name === agentName &&
|
|
509
|
-
) as
|
|
508
|
+
(action) => action.name === agentName && isRemoteAgentAction(action),
|
|
509
|
+
) as RemoteAgentAction;
|
|
510
510
|
|
|
511
511
|
if (!currentAgent) {
|
|
512
512
|
throw new CopilotKitAgentDiscoveryError({ agentName });
|
|
@@ -519,9 +519,9 @@ please use an LLM adapter instead.`,
|
|
|
519
519
|
.filter(
|
|
520
520
|
(action) =>
|
|
521
521
|
// Case 1: Keep all regular (non-agent) actions
|
|
522
|
-
!
|
|
522
|
+
!isRemoteAgentAction(action) ||
|
|
523
523
|
// Case 2: For agent actions, keep all except self (prevent infinite loops)
|
|
524
|
-
(
|
|
524
|
+
(isRemoteAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
|
|
525
525
|
)
|
|
526
526
|
.map((action) => ({
|
|
527
527
|
name: action.name,
|
|
@@ -542,7 +542,7 @@ please use an LLM adapter instead.`,
|
|
|
542
542
|
});
|
|
543
543
|
try {
|
|
544
544
|
const eventSource = new RuntimeEventSource();
|
|
545
|
-
const stream = await currentAgent.
|
|
545
|
+
const stream = await currentAgent.remoteAgentHandler({
|
|
546
546
|
name: agentName,
|
|
547
547
|
threadId,
|
|
548
548
|
nodeName,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import {
|
|
3
3
|
CopilotKitEndpoint,
|
|
4
|
-
|
|
4
|
+
RemoteAgentHandlerParams,
|
|
5
5
|
RemoteActionInfoResponse,
|
|
6
6
|
LangGraphPlatformEndpoint,
|
|
7
7
|
} from "./remote-actions";
|
|
@@ -10,13 +10,18 @@ import { Logger } from "pino";
|
|
|
10
10
|
import { Message } from "../../graphql/types/converted";
|
|
11
11
|
import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
|
|
12
12
|
import { Observable, ReplaySubject } from "rxjs";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
RuntimeEvent,
|
|
15
|
+
RuntimeEventSource,
|
|
16
|
+
RuntimeEventSubject,
|
|
17
|
+
} from "../../service-adapters/events";
|
|
14
18
|
import telemetry from "../telemetry-client";
|
|
15
19
|
import { RemoteLangGraphEventSource } from "../../agents/langgraph/event-source";
|
|
16
20
|
import { Action } from "@copilotkit/shared";
|
|
17
21
|
import { LangGraphEvent } from "../../agents/langgraph/events";
|
|
18
22
|
import { execute } from "./remote-lg-action";
|
|
19
23
|
import { CopilotKitError, CopilotKitLowLevelError } from "@copilotkit/shared";
|
|
24
|
+
import { writeJsonLineResponseToEventStream } from "../streaming";
|
|
20
25
|
import { CopilotKitApiDiscoveryError, ResolvedCopilotKitError } from "@copilotkit/shared";
|
|
21
26
|
import { parseJson, tryMap } from "@copilotkit/shared";
|
|
22
27
|
import { ActionInput } from "../../graphql/inputs/action.input";
|
|
@@ -39,14 +44,14 @@ export function constructLGCRemoteAction({
|
|
|
39
44
|
description: agent.description,
|
|
40
45
|
parameters: [],
|
|
41
46
|
handler: async (_args: any) => {},
|
|
42
|
-
|
|
47
|
+
remoteAgentHandler: async ({
|
|
43
48
|
name,
|
|
44
49
|
actionInputsWithoutAgents,
|
|
45
50
|
threadId,
|
|
46
51
|
nodeName,
|
|
47
52
|
additionalMessages = [],
|
|
48
53
|
metaEvents,
|
|
49
|
-
}:
|
|
54
|
+
}: RemoteAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
|
|
50
55
|
logger.debug({ actionName: agent.name }, "Executing LangGraph Platform agent");
|
|
51
56
|
|
|
52
57
|
telemetry.capture("oss.runtime.remote_action_executed", {
|
|
@@ -87,7 +92,7 @@ export function constructLGCRemoteAction({
|
|
|
87
92
|
});
|
|
88
93
|
|
|
89
94
|
const eventSource = new RemoteLangGraphEventSource();
|
|
90
|
-
|
|
95
|
+
writeJsonLineResponseToEventStream(response, eventSource.eventStream$);
|
|
91
96
|
return eventSource.processLangGraphEvents();
|
|
92
97
|
} catch (error) {
|
|
93
98
|
logger.error(
|
|
@@ -102,6 +107,11 @@ export function constructLGCRemoteAction({
|
|
|
102
107
|
return [...agents];
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
export enum RemoteAgentType {
|
|
111
|
+
LangGraph = "langgraph",
|
|
112
|
+
CrewAI = "crewai",
|
|
113
|
+
}
|
|
114
|
+
|
|
105
115
|
export function constructRemoteActions({
|
|
106
116
|
json,
|
|
107
117
|
url,
|
|
@@ -183,14 +193,14 @@ export function constructRemoteActions({
|
|
|
183
193
|
parameters: [],
|
|
184
194
|
handler: async (_args: any) => {},
|
|
185
195
|
|
|
186
|
-
|
|
196
|
+
remoteAgentHandler: async ({
|
|
187
197
|
name,
|
|
188
198
|
actionInputsWithoutAgents,
|
|
189
199
|
threadId,
|
|
190
200
|
nodeName,
|
|
191
201
|
additionalMessages = [],
|
|
192
202
|
metaEvents,
|
|
193
|
-
}:
|
|
203
|
+
}: RemoteAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
|
|
194
204
|
logger.debug({ actionName: agent.name }, "Executing remote agent");
|
|
195
205
|
|
|
196
206
|
const headers = createHeaders(onBeforeRequest, graphqlContext);
|
|
@@ -247,9 +257,17 @@ export function constructRemoteActions({
|
|
|
247
257
|
});
|
|
248
258
|
}
|
|
249
259
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
260
|
+
if (agent.type === RemoteAgentType.LangGraph) {
|
|
261
|
+
const eventSource = new RemoteLangGraphEventSource();
|
|
262
|
+
writeJsonLineResponseToEventStream(response.body!, eventSource.eventStream$);
|
|
263
|
+
return eventSource.processLangGraphEvents();
|
|
264
|
+
} else if (agent.type === RemoteAgentType.CrewAI) {
|
|
265
|
+
const eventStream$ = new RuntimeEventSubject();
|
|
266
|
+
writeJsonLineResponseToEventStream(response.body!, eventStream$);
|
|
267
|
+
return eventStream$;
|
|
268
|
+
} else {
|
|
269
|
+
throw new Error("Unsupported agent type");
|
|
270
|
+
}
|
|
253
271
|
} catch (error) {
|
|
254
272
|
if (error instanceof CopilotKitError) {
|
|
255
273
|
throw error;
|
|
@@ -263,64 +281,6 @@ export function constructRemoteActions({
|
|
|
263
281
|
return [...actions, ...agents];
|
|
264
282
|
}
|
|
265
283
|
|
|
266
|
-
async function streamResponse(
|
|
267
|
-
response: ReadableStream<Uint8Array>,
|
|
268
|
-
eventStream$: ReplaySubject<LangGraphEvent>,
|
|
269
|
-
) {
|
|
270
|
-
const reader = response.getReader();
|
|
271
|
-
const decoder = new TextDecoder();
|
|
272
|
-
let buffer = [];
|
|
273
|
-
|
|
274
|
-
function flushBuffer() {
|
|
275
|
-
const currentBuffer = buffer.join("");
|
|
276
|
-
if (currentBuffer.trim().length === 0) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
const parts = currentBuffer.split("\n");
|
|
280
|
-
if (parts.length === 0) {
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const lastPartIsComplete = currentBuffer.endsWith("\n");
|
|
285
|
-
|
|
286
|
-
// truncate buffer
|
|
287
|
-
buffer = [];
|
|
288
|
-
|
|
289
|
-
if (!lastPartIsComplete) {
|
|
290
|
-
// put back the last part
|
|
291
|
-
buffer.push(parts.pop());
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
parts
|
|
295
|
-
.map((part) => part.trim())
|
|
296
|
-
.filter((part) => part != "")
|
|
297
|
-
.forEach((part) => {
|
|
298
|
-
eventStream$.next(JSON.parse(part));
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
try {
|
|
303
|
-
while (true) {
|
|
304
|
-
const { done, value } = await reader.read();
|
|
305
|
-
|
|
306
|
-
if (!done) {
|
|
307
|
-
buffer.push(decoder.decode(value, { stream: true }));
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
flushBuffer();
|
|
311
|
-
|
|
312
|
-
if (done) {
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
} catch (error) {
|
|
317
|
-
console.error("Error in stream", error);
|
|
318
|
-
eventStream$.error(error);
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
eventStream$.complete();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
284
|
export function createHeaders(
|
|
325
285
|
onBeforeRequest: CopilotKitEndpoint["onBeforeRequest"],
|
|
326
286
|
graphqlContext: GraphQLContext,
|
|
@@ -54,7 +54,7 @@ export type RemoteActionInfoResponse = {
|
|
|
54
54
|
agents: any[];
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
export type
|
|
57
|
+
export type RemoteAgentHandlerParams = {
|
|
58
58
|
name: string;
|
|
59
59
|
actionInputsWithoutAgents: ActionInput[];
|
|
60
60
|
threadId?: string;
|
|
@@ -63,15 +63,15 @@ export type LangGraphAgentHandlerParams = {
|
|
|
63
63
|
metaEvents?: MetaEventInput[];
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
export type
|
|
67
|
-
|
|
66
|
+
export type RemoteAgentAction = Action<any> & {
|
|
67
|
+
remoteAgentHandler: (params: RemoteAgentHandlerParams) => Promise<Observable<RuntimeEvent>>;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
export function
|
|
70
|
+
export function isRemoteAgentAction(action: Action<any>): action is RemoteAgentAction {
|
|
71
71
|
if (!action) {
|
|
72
72
|
return false;
|
|
73
73
|
}
|
|
74
|
-
return typeof (action as
|
|
74
|
+
return typeof (action as RemoteAgentAction).remoteAgentHandler === "function";
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
async function fetchRemoteInfo({
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ReplaySubject } from "rxjs";
|
|
2
|
+
|
|
3
|
+
export async function writeJsonLineResponseToEventStream<T>(
|
|
4
|
+
response: ReadableStream<Uint8Array>,
|
|
5
|
+
eventStream$: ReplaySubject<T>,
|
|
6
|
+
) {
|
|
7
|
+
const reader = response.getReader();
|
|
8
|
+
const decoder = new TextDecoder();
|
|
9
|
+
let buffer = [];
|
|
10
|
+
|
|
11
|
+
function flushBuffer() {
|
|
12
|
+
const currentBuffer = buffer.join("");
|
|
13
|
+
if (currentBuffer.trim().length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const parts = currentBuffer.split("\n");
|
|
17
|
+
if (parts.length === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const lastPartIsComplete = currentBuffer.endsWith("\n");
|
|
22
|
+
|
|
23
|
+
// truncate buffer
|
|
24
|
+
buffer = [];
|
|
25
|
+
|
|
26
|
+
if (!lastPartIsComplete) {
|
|
27
|
+
// put back the last part
|
|
28
|
+
buffer.push(parts.pop());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
parts
|
|
32
|
+
.map((part) => part.trim())
|
|
33
|
+
.filter((part) => part != "")
|
|
34
|
+
.forEach((part) => {
|
|
35
|
+
eventStream$.next(JSON.parse(part));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
while (true) {
|
|
41
|
+
const { done, value } = await reader.read();
|
|
42
|
+
|
|
43
|
+
if (!done) {
|
|
44
|
+
buffer.push(decoder.decode(value, { stream: true }));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
flushBuffer();
|
|
48
|
+
|
|
49
|
+
if (done) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("Error in stream", error);
|
|
55
|
+
eventStream$.error(error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
eventStream$.complete();
|
|
59
|
+
}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { streamLangChainResponse } from "./langchain/utils";
|
|
15
15
|
import { GuardrailsResult } from "../graphql/types/guardrails-result.type";
|
|
16
16
|
import telemetry from "../lib/telemetry-client";
|
|
17
|
-
import {
|
|
17
|
+
import { isRemoteAgentAction } from "../lib/runtime/remote-actions";
|
|
18
18
|
import { ActionInput } from "../graphql/inputs/action.input";
|
|
19
19
|
import { ActionExecutionMessage, ResultMessage, TextMessage } from "../graphql/types/converted";
|
|
20
20
|
import { plainToInstance } from "class-transformer";
|
|
@@ -372,7 +372,7 @@ async function executeAction(
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
// handle LangGraph agents
|
|
375
|
-
if (
|
|
375
|
+
if (isRemoteAgentAction(action)) {
|
|
376
376
|
const result = `${action.name} agent started`;
|
|
377
377
|
|
|
378
378
|
const agentExecution = plainToInstance(ActionExecutionMessage, {
|
|
@@ -397,7 +397,7 @@ async function executeAction(
|
|
|
397
397
|
result,
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
-
const stream = await action.
|
|
400
|
+
const stream = await action.remoteAgentHandler({
|
|
401
401
|
name: action.name,
|
|
402
402
|
threadId,
|
|
403
403
|
actionInputsWithoutAgents,
|