@copilotkit/runtime 0.37.0 → 0.38.0-beta.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/.turbo/turbo-build.log +69 -54
- package/CHANGELOG.md +11 -0
- package/__snapshots__/schema/schema.graphql +15 -4
- package/dist/{chunk-2CCVVJDU.mjs → chunk-2PJG3NAC.mjs} +13 -15
- package/dist/chunk-2PJG3NAC.mjs.map +1 -0
- package/dist/{chunk-NFCPM5AM.mjs → chunk-6NZ4UMOD.mjs} +4 -4
- package/dist/chunk-6NZ4UMOD.mjs.map +1 -0
- package/dist/{chunk-XPAUPJMW.mjs → chunk-6YGDE3YI.mjs} +432 -220
- package/dist/chunk-6YGDE3YI.mjs.map +1 -0
- package/dist/chunk-BYB2LNMK.mjs +152 -0
- package/dist/chunk-BYB2LNMK.mjs.map +1 -0
- package/dist/{chunk-7IFP53C6.mjs → chunk-FRK6BXXV.mjs} +49 -11
- package/dist/chunk-FRK6BXXV.mjs.map +1 -0
- package/dist/{chunk-5HGYI6EG.mjs → chunk-JBDOA7MK.mjs} +34 -15
- package/dist/chunk-JBDOA7MK.mjs.map +1 -0
- package/dist/{chunk-4UA4RB4C.mjs → chunk-JIKPSUGQ.mjs} +45 -76
- package/dist/chunk-JIKPSUGQ.mjs.map +1 -0
- package/dist/{chunk-BLTAUVRP.mjs → chunk-OZMCHYYR.mjs} +5 -3
- package/dist/{chunk-BLTAUVRP.mjs.map → chunk-OZMCHYYR.mjs.map} +1 -1
- package/dist/chunk-RHQLCJGG.mjs +7 -0
- package/dist/chunk-RHQLCJGG.mjs.map +1 -0
- package/dist/failed-response-status-reasons-0ab19e06.d.ts +49 -0
- package/dist/graphql/types/base/index.mjs +2 -1
- package/dist/graphql/types/converted/index.mjs +3 -2
- package/dist/{index-f0875df3.d.ts → index-0e75acd2.d.ts} +86 -59
- package/dist/index.d.ts +7 -4
- package/dist/index.js +536 -169
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -13
- package/dist/index.mjs.map +1 -1
- package/dist/{langchain-adapter-9ce103f3.d.ts → langchain-adapter-a02d1d38.d.ts} +4 -4
- package/dist/{langserve-fd5066ee.d.ts → langserve-75ebbc38.d.ts} +25 -9
- package/dist/lib/cloud/index.d.ts +6 -0
- package/dist/lib/cloud/index.js +18 -0
- package/dist/lib/cloud/index.js.map +1 -0
- package/dist/lib/cloud/index.mjs +1 -0
- package/dist/lib/cloud/index.mjs.map +1 -0
- package/dist/lib/index.d.ts +6 -4
- package/dist/lib/index.js +530 -169
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +9 -13
- package/dist/lib/integrations/index.d.ts +5 -3
- package/dist/lib/integrations/index.js +426 -64
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +7 -5
- package/dist/lib/integrations/node-http/index.d.ts +4 -2
- package/dist/lib/integrations/node-http/index.js +416 -52
- package/dist/lib/integrations/node-http/index.js.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +6 -4
- package/dist/pages-router-e81920d5.d.ts +21 -0
- package/dist/service-adapters/index.d.ts +2 -2
- package/dist/service-adapters/index.js +82 -25
- package/dist/service-adapters/index.js.map +1 -1
- package/dist/service-adapters/index.mjs +5 -4
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +174 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +12 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +6 -4
- package/src/graphql/inputs/cloud-guardrails.input.ts +2 -5
- package/src/graphql/inputs/cloud.input.ts +2 -2
- package/src/graphql/resolvers/copilot.resolver.ts +340 -30
- package/src/graphql/types/response-status.type.ts +16 -2
- package/src/index.ts +1 -0
- package/src/lib/cloud/index.ts +4 -0
- package/src/lib/copilot-runtime.ts +116 -70
- package/src/lib/index.ts +0 -1
- package/src/lib/integrations/nextjs/app-router.ts +9 -17
- package/src/lib/integrations/nextjs/pages-router.ts +9 -15
- package/src/lib/integrations/node-http/index.ts +6 -14
- package/src/lib/integrations/shared.ts +38 -18
- package/src/lib/logger.ts +28 -0
- package/src/service-adapters/events.ts +20 -2
- package/src/service-adapters/experimental/groq/groq-adapter.ts +3 -1
- package/src/service-adapters/experimental/ollama/ollama-adapter.ts +3 -1
- package/src/service-adapters/google/google-genai-adapter.ts +6 -1
- package/src/service-adapters/google/utils.ts +1 -1
- package/src/service-adapters/index.ts +1 -1
- package/src/service-adapters/langchain/langchain-adapter.ts +8 -9
- package/src/service-adapters/langchain/langserve.ts +10 -4
- package/src/service-adapters/langchain/utils.ts +58 -9
- package/src/service-adapters/openai/openai-adapter.ts +8 -7
- package/src/service-adapters/openai/openai-assistant-adapter.ts +6 -8
- package/src/service-adapters/service-adapter.ts +1 -2
- package/src/utils/failed-response-status-reasons.ts +48 -0
- package/src/utils/index.ts +1 -0
- package/dist/chunk-2CCVVJDU.mjs.map +0 -1
- package/dist/chunk-4UA4RB4C.mjs.map +0 -1
- package/dist/chunk-5HGYI6EG.mjs.map +0 -1
- package/dist/chunk-7IFP53C6.mjs.map +0 -1
- package/dist/chunk-NFCPM5AM.mjs.map +0 -1
- package/dist/chunk-XPAUPJMW.mjs.map +0 -1
- package/dist/pages-router-b6bc6c60.d.ts +0 -30
- package/src/lib/copilot-cloud.ts +0 -63
- package/src/lib/guardrails.ts +0 -3
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ReplaySubject,
|
|
4
|
+
Subject,
|
|
5
|
+
Subscription,
|
|
6
|
+
finalize,
|
|
7
|
+
firstValueFrom,
|
|
8
|
+
shareReplay,
|
|
9
|
+
skipWhile,
|
|
10
|
+
take,
|
|
11
|
+
takeWhile,
|
|
12
|
+
tap,
|
|
13
|
+
} from "rxjs";
|
|
3
14
|
import { GenerateCopilotResponseInput } from "../inputs/generate-copilot-response.input";
|
|
4
15
|
import { CopilotResponse } from "../types/copilot-response.type";
|
|
5
16
|
import { MessageRole } from "../types/enums";
|
|
@@ -7,9 +18,78 @@ import { Repeater } from "graphql-yoga";
|
|
|
7
18
|
import type { CopilotRequestContextProperties, GraphQLContext } from "../../lib/integrations";
|
|
8
19
|
import { nanoid } from "nanoid";
|
|
9
20
|
import { RuntimeEvent, RuntimeEventTypes } from "../../service-adapters/events";
|
|
10
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
FailedMessageStatus,
|
|
23
|
+
MessageStatusUnion,
|
|
24
|
+
SuccessMessageStatus,
|
|
25
|
+
} from "../types/message-status.type";
|
|
11
26
|
import { ResponseStatusUnion, SuccessResponseStatus } from "../types/response-status.type";
|
|
12
27
|
import { GraphQLJSONObject } from "graphql-scalars";
|
|
28
|
+
import { plainToInstance } from "class-transformer";
|
|
29
|
+
import { GuardrailsResult, GuardrailsResultStatus } from "../types/guardrails-result.type";
|
|
30
|
+
import { GraphQLError } from "graphql";
|
|
31
|
+
import {
|
|
32
|
+
GuardrailsValidationFailureResponse,
|
|
33
|
+
MessageStreamInterruptedResponse,
|
|
34
|
+
UnknownErrorResponse,
|
|
35
|
+
} from "../../utils";
|
|
36
|
+
import { ActionExecutionMessage, Message, ResultMessage, TextMessage } from "../types/converted";
|
|
37
|
+
|
|
38
|
+
const invokeGuardrails = async ({
|
|
39
|
+
baseUrl,
|
|
40
|
+
copilotCloudPublicApiKey,
|
|
41
|
+
data,
|
|
42
|
+
onResult,
|
|
43
|
+
onError,
|
|
44
|
+
}: {
|
|
45
|
+
baseUrl: string;
|
|
46
|
+
copilotCloudPublicApiKey: string;
|
|
47
|
+
data: GenerateCopilotResponseInput;
|
|
48
|
+
onResult: (result: GuardrailsResult) => void;
|
|
49
|
+
onError: (err: Error) => void;
|
|
50
|
+
}) => {
|
|
51
|
+
if (
|
|
52
|
+
data.messages.length &&
|
|
53
|
+
data.messages[data.messages.length - 1].textMessage?.role === MessageRole.user
|
|
54
|
+
) {
|
|
55
|
+
const messages = data.messages
|
|
56
|
+
.filter(
|
|
57
|
+
(m) =>
|
|
58
|
+
m.textMessage !== undefined &&
|
|
59
|
+
(m.textMessage.role === MessageRole.user || m.textMessage.role === MessageRole.assistant),
|
|
60
|
+
)
|
|
61
|
+
.map((m) => ({
|
|
62
|
+
role: m.textMessage!.role,
|
|
63
|
+
content: m.textMessage.content,
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
const lastMessage = messages[messages.length - 1];
|
|
67
|
+
const restOfMessages = messages.slice(0, -1);
|
|
68
|
+
|
|
69
|
+
const body = {
|
|
70
|
+
input: lastMessage.content,
|
|
71
|
+
validTopics: data.cloud.guardrails.inputValidationRules.allowList,
|
|
72
|
+
invalidTopics: data.cloud.guardrails.inputValidationRules.denyList,
|
|
73
|
+
messages: restOfMessages,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const guardrailsResult = await fetch(`${baseUrl}/guardrails/validate`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: {
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
"X-CopilotCloud-Public-API-Key": copilotCloudPublicApiKey,
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(body),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (guardrailsResult.ok) {
|
|
86
|
+
const resultJson: GuardrailsResult = await guardrailsResult.json();
|
|
87
|
+
onResult(resultJson);
|
|
88
|
+
} else {
|
|
89
|
+
onError(await guardrailsResult.json());
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
13
93
|
|
|
14
94
|
@Resolver(() => CopilotResponse)
|
|
15
95
|
export class CopilotResolver {
|
|
@@ -25,17 +105,62 @@ export class CopilotResolver {
|
|
|
25
105
|
@Arg("properties", () => GraphQLJSONObject, { nullable: true })
|
|
26
106
|
properties?: CopilotRequestContextProperties,
|
|
27
107
|
) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
108
|
+
let logger = ctx.logger.child({ component: "CopilotResolver.generateCopilotResponse" });
|
|
109
|
+
logger.debug({ data }, "Generating Copilot response");
|
|
110
|
+
|
|
31
111
|
const copilotRuntime = ctx._copilotkit.runtime;
|
|
32
112
|
const serviceAdapter = ctx._copilotkit.serviceAdapter;
|
|
33
|
-
const responseStatus = new Subject<typeof ResponseStatusUnion>();
|
|
34
113
|
|
|
114
|
+
if (properties) {
|
|
115
|
+
logger.debug("Properties provided, merging with context properties");
|
|
116
|
+
ctx.properties = { ...ctx.properties, ...properties };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let copilotCloudPublicApiKey: string | null = null;
|
|
120
|
+
let copilotCloudBaseUrl: string;
|
|
121
|
+
|
|
122
|
+
if (data.cloud) {
|
|
123
|
+
logger = logger.child({ cloud: true });
|
|
124
|
+
logger.debug("Cloud configuration provided, checking for public API key in headers");
|
|
125
|
+
const key = ctx.request.headers.get("x-copilotcloud-public-api-key");
|
|
126
|
+
if (key) {
|
|
127
|
+
logger.debug("Public API key found in headers");
|
|
128
|
+
copilotCloudPublicApiKey = key;
|
|
129
|
+
} else {
|
|
130
|
+
logger.error("Public API key not found in headers");
|
|
131
|
+
throw new GraphQLError("X-CopilotCloud-Public-API-Key header is required");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (process.env.COPILOT_CLOUD_BASE_URL) {
|
|
135
|
+
copilotCloudBaseUrl = process.env.COPILOT_CLOUD_BASE_URL;
|
|
136
|
+
} else if (ctx._copilotkit.baseUrl) {
|
|
137
|
+
copilotCloudBaseUrl = ctx._copilotkit.baseUrl;
|
|
138
|
+
} else {
|
|
139
|
+
copilotCloudBaseUrl = "https://api.cloud.copilotkit.ai";
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
logger = logger.child({ copilotCloudBaseUrl });
|
|
143
|
+
}
|
|
144
|
+
logger.debug("Setting up subjects");
|
|
145
|
+
const responseStatus$ = new ReplaySubject<typeof ResponseStatusUnion>();
|
|
146
|
+
const interruptStreaming$ = new ReplaySubject<{ reason: string; messageId?: string }>();
|
|
147
|
+
const guardrailsResult$ = new ReplaySubject<GuardrailsResult>();
|
|
148
|
+
|
|
149
|
+
let outputMessages: Message[] = [];
|
|
150
|
+
let resolveOutputMessagesPromise: (messages: Message[]) => void;
|
|
151
|
+
let rejectOutputMessagesPromise: (err: Error) => void;
|
|
152
|
+
|
|
153
|
+
const outputMessagesPromise = new Promise<Message[]>((resolve, reject) => {
|
|
154
|
+
resolveOutputMessagesPromise = resolve;
|
|
155
|
+
rejectOutputMessagesPromise = reject;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
logger.debug("Processing");
|
|
35
159
|
const {
|
|
36
160
|
eventSource,
|
|
37
161
|
threadId = nanoid(),
|
|
38
162
|
runId,
|
|
163
|
+
actions,
|
|
39
164
|
} = await copilotRuntime.process({
|
|
40
165
|
serviceAdapter,
|
|
41
166
|
messages: data.messages,
|
|
@@ -43,20 +168,90 @@ export class CopilotResolver {
|
|
|
43
168
|
threadId: data.threadId,
|
|
44
169
|
runId: data.runId,
|
|
45
170
|
publicApiKey: undefined,
|
|
171
|
+
properties: ctx.properties || {},
|
|
172
|
+
outputMessagesPromise,
|
|
46
173
|
});
|
|
47
174
|
|
|
175
|
+
logger.debug("Event source created, creating response");
|
|
176
|
+
|
|
48
177
|
const response = {
|
|
49
178
|
threadId,
|
|
50
179
|
runId,
|
|
51
|
-
status: firstValueFrom(responseStatus),
|
|
180
|
+
status: firstValueFrom(responseStatus$),
|
|
52
181
|
messages: new Repeater(async (pushMessage, stopStreamingMessages) => {
|
|
182
|
+
logger.debug("Messages repeater created");
|
|
183
|
+
|
|
184
|
+
if (data.cloud?.guardrails) {
|
|
185
|
+
logger = logger.child({ guardrails: true });
|
|
186
|
+
logger.debug("Guardrails is enabled, validating input");
|
|
187
|
+
|
|
188
|
+
invokeGuardrails({
|
|
189
|
+
baseUrl: copilotCloudBaseUrl,
|
|
190
|
+
copilotCloudPublicApiKey,
|
|
191
|
+
data,
|
|
192
|
+
onResult: (result) => {
|
|
193
|
+
logger.debug({ status: result.status }, "Guardrails validation done");
|
|
194
|
+
guardrailsResult$.next(result);
|
|
195
|
+
|
|
196
|
+
// Guardrails validation failed
|
|
197
|
+
if (result.status === "denied") {
|
|
198
|
+
// send the reason to the client and interrupt streaming
|
|
199
|
+
responseStatus$.next(
|
|
200
|
+
new GuardrailsValidationFailureResponse({ guardrailsReason: result.reason }),
|
|
201
|
+
);
|
|
202
|
+
interruptStreaming$.next({
|
|
203
|
+
reason: `Interrupted due to Guardrails validation failure. Reason: ${result.reason}`,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// resolve messages promise to the middleware
|
|
207
|
+
outputMessages = [
|
|
208
|
+
plainToInstance(TextMessage, {
|
|
209
|
+
id: nanoid(),
|
|
210
|
+
createdAt: new Date(),
|
|
211
|
+
content: result.reason,
|
|
212
|
+
role: MessageRole.assistant,
|
|
213
|
+
}),
|
|
214
|
+
];
|
|
215
|
+
resolveOutputMessagesPromise(outputMessages);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
onError: (err) => {
|
|
219
|
+
logger.error({ err }, "Error in guardrails validation");
|
|
220
|
+
responseStatus$.next(
|
|
221
|
+
new UnknownErrorResponse({
|
|
222
|
+
description: `An unknown error has occurred in the guardrails validation`,
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
225
|
+
interruptStreaming$.next({
|
|
226
|
+
reason: `Interrupted due to unknown error in guardrails validation`,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// reject the middleware promise
|
|
230
|
+
rejectOutputMessagesPromise(err);
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let eventStreamSubscription: Subscription;
|
|
236
|
+
|
|
53
237
|
// run and process the event stream
|
|
54
|
-
const eventStream = eventSource
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
238
|
+
const eventStream = eventSource
|
|
239
|
+
.process({
|
|
240
|
+
serversideActions: actions,
|
|
241
|
+
guardrailsResult$: data.cloud?.guardrails ? guardrailsResult$ : null,
|
|
242
|
+
})
|
|
243
|
+
.pipe(
|
|
244
|
+
// shareReplay() ensures that later subscribers will see the whole stream instead of
|
|
245
|
+
// just the events that were emitted after the subscriber was added.
|
|
246
|
+
shareReplay(),
|
|
247
|
+
finalize(() => {
|
|
248
|
+
logger.debug("Event stream finalized");
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
logger.debug("Event stream created, subscribing to event stream");
|
|
253
|
+
|
|
254
|
+
eventStreamSubscription = eventStream.subscribe({
|
|
60
255
|
next: async (event) => {
|
|
61
256
|
switch (event.type) {
|
|
62
257
|
////////////////////////////////
|
|
@@ -74,21 +269,72 @@ export class CopilotResolver {
|
|
|
74
269
|
// signal when we are done streaming
|
|
75
270
|
const streamingTextStatus = new Subject<typeof MessageStatusUnion>();
|
|
76
271
|
|
|
272
|
+
const messageId = nanoid();
|
|
273
|
+
|
|
77
274
|
// push the new message
|
|
78
275
|
pushMessage({
|
|
79
|
-
id:
|
|
276
|
+
id: messageId,
|
|
80
277
|
status: firstValueFrom(streamingTextStatus),
|
|
81
278
|
createdAt: new Date(),
|
|
82
279
|
role: MessageRole.assistant,
|
|
83
280
|
content: new Repeater(async (pushTextChunk, stopStreamingText) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
281
|
+
logger.debug("Text message content repeater created");
|
|
282
|
+
|
|
283
|
+
const textChunks: string[] = [];
|
|
284
|
+
let textSubscription: Subscription;
|
|
285
|
+
|
|
286
|
+
interruptStreaming$
|
|
287
|
+
.pipe(
|
|
288
|
+
shareReplay(),
|
|
289
|
+
take(1),
|
|
290
|
+
tap(({ reason, messageId }) => {
|
|
291
|
+
logger.debug({ reason, messageId }, "Text streaming interrupted");
|
|
292
|
+
|
|
293
|
+
streamingTextStatus.next(
|
|
294
|
+
plainToInstance(FailedMessageStatus, { reason }),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
responseStatus$.next(new MessageStreamInterruptedResponse({ messageId }));
|
|
298
|
+
stopStreamingText();
|
|
299
|
+
textSubscription?.unsubscribe();
|
|
300
|
+
}),
|
|
301
|
+
)
|
|
302
|
+
.subscribe();
|
|
303
|
+
|
|
304
|
+
logger.debug("Subscribing to text message content stream");
|
|
305
|
+
|
|
306
|
+
textSubscription = textMessageContentStream.subscribe({
|
|
307
|
+
next: async (e: RuntimeEvent) => {
|
|
308
|
+
if (e.type == RuntimeEventTypes.TextMessageContent) {
|
|
309
|
+
await pushTextChunk(e.content);
|
|
310
|
+
textChunks.push(e.content);
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
error: (err) => {
|
|
314
|
+
logger.error({ err }, "Error in text message content stream");
|
|
315
|
+
interruptStreaming$.next({
|
|
316
|
+
reason: "Error streaming message content",
|
|
317
|
+
messageId,
|
|
318
|
+
});
|
|
319
|
+
stopStreamingText();
|
|
320
|
+
textSubscription?.unsubscribe();
|
|
321
|
+
},
|
|
322
|
+
complete: () => {
|
|
323
|
+
logger.debug("Text message content stream completed");
|
|
324
|
+
streamingTextStatus.next(new SuccessMessageStatus());
|
|
325
|
+
stopStreamingText();
|
|
326
|
+
textSubscription?.unsubscribe();
|
|
327
|
+
|
|
328
|
+
outputMessages.push(
|
|
329
|
+
plainToInstance(TextMessage, {
|
|
330
|
+
id: messageId,
|
|
331
|
+
createdAt: new Date(),
|
|
332
|
+
content: textChunks.join(""),
|
|
333
|
+
role: MessageRole.assistant,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
},
|
|
89
337
|
});
|
|
90
|
-
stopStreamingText();
|
|
91
|
-
streamingTextStatus.next(new SuccessMessageStatus());
|
|
92
338
|
}),
|
|
93
339
|
});
|
|
94
340
|
break;
|
|
@@ -96,6 +342,7 @@ export class CopilotResolver {
|
|
|
96
342
|
// ActionExecutionStart
|
|
97
343
|
////////////////////////////////
|
|
98
344
|
case RuntimeEventTypes.ActionExecutionStart:
|
|
345
|
+
logger.debug("Action execution start event received");
|
|
99
346
|
const actionExecutionArgumentStream = eventStream.pipe(
|
|
100
347
|
skipWhile((e) => e !== event),
|
|
101
348
|
takeWhile((e) => e.type != RuntimeEventTypes.ActionExecutionEnd),
|
|
@@ -108,13 +355,46 @@ export class CopilotResolver {
|
|
|
108
355
|
name: event.actionName,
|
|
109
356
|
scope: event.scope!,
|
|
110
357
|
arguments: new Repeater(async (pushArgumentsChunk, stopStreamingArguments) => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
358
|
+
logger.debug("Action execution argument stream created");
|
|
359
|
+
|
|
360
|
+
const argumentChunks: string[] = [];
|
|
361
|
+
let actionExecutionArgumentSubscription: Subscription;
|
|
362
|
+
|
|
363
|
+
actionExecutionArgumentSubscription = actionExecutionArgumentStream.subscribe({
|
|
364
|
+
next: async (e: RuntimeEvent) => {
|
|
365
|
+
if (e.type == RuntimeEventTypes.ActionExecutionArgs) {
|
|
366
|
+
await pushArgumentsChunk(e.args);
|
|
367
|
+
argumentChunks.push(e.args);
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
error: (err) => {
|
|
371
|
+
logger.error({ err }, "Error in action execution argument stream");
|
|
372
|
+
streamingArgumentsStatus.next(
|
|
373
|
+
plainToInstance(FailedMessageStatus, {
|
|
374
|
+
reason:
|
|
375
|
+
"An unknown error has occurred in the action execution argument stream",
|
|
376
|
+
}),
|
|
377
|
+
);
|
|
378
|
+
stopStreamingArguments();
|
|
379
|
+
actionExecutionArgumentSubscription?.unsubscribe();
|
|
380
|
+
},
|
|
381
|
+
complete: () => {
|
|
382
|
+
logger.debug("Action execution argument stream completed");
|
|
383
|
+
streamingArgumentsStatus.next(new SuccessMessageStatus());
|
|
384
|
+
stopStreamingArguments();
|
|
385
|
+
actionExecutionArgumentSubscription?.unsubscribe();
|
|
386
|
+
|
|
387
|
+
outputMessages.push(
|
|
388
|
+
plainToInstance(ActionExecutionMessage, {
|
|
389
|
+
id: event.actionExecutionId,
|
|
390
|
+
createdAt: new Date(),
|
|
391
|
+
name: event.actionName,
|
|
392
|
+
scope: event.scope!,
|
|
393
|
+
arguments: argumentChunks.join(""),
|
|
394
|
+
}),
|
|
395
|
+
);
|
|
396
|
+
},
|
|
115
397
|
});
|
|
116
|
-
stopStreamingArguments();
|
|
117
|
-
streamingArgumentsStatus.next(new SuccessMessageStatus());
|
|
118
398
|
}),
|
|
119
399
|
});
|
|
120
400
|
break;
|
|
@@ -122,6 +402,7 @@ export class CopilotResolver {
|
|
|
122
402
|
// ActionExecutionResult
|
|
123
403
|
////////////////////////////////
|
|
124
404
|
case RuntimeEventTypes.ActionExecutionResult:
|
|
405
|
+
logger.debug({ result: event.result }, "Action execution result event received");
|
|
125
406
|
pushMessage({
|
|
126
407
|
id: nanoid(),
|
|
127
408
|
status: new SuccessMessageStatus(),
|
|
@@ -130,13 +411,42 @@ export class CopilotResolver {
|
|
|
130
411
|
actionName: event.actionName,
|
|
131
412
|
result: event.result,
|
|
132
413
|
});
|
|
414
|
+
|
|
415
|
+
outputMessages.push(
|
|
416
|
+
plainToInstance(ResultMessage, {
|
|
417
|
+
id: nanoid(),
|
|
418
|
+
createdAt: new Date(),
|
|
419
|
+
actionExecutionId: event.actionExecutionId,
|
|
420
|
+
actionName: event.actionName,
|
|
421
|
+
result: event.result,
|
|
422
|
+
}),
|
|
423
|
+
);
|
|
133
424
|
break;
|
|
134
425
|
}
|
|
135
426
|
},
|
|
136
|
-
error: (err) =>
|
|
137
|
-
|
|
138
|
-
responseStatus
|
|
427
|
+
error: (err) => {
|
|
428
|
+
logger.error({ err }, "Error in event stream");
|
|
429
|
+
responseStatus$.next(
|
|
430
|
+
new UnknownErrorResponse({
|
|
431
|
+
description: `An unknown error has occurred in the event stream`,
|
|
432
|
+
}),
|
|
433
|
+
);
|
|
434
|
+
eventStreamSubscription?.unsubscribe();
|
|
139
435
|
stopStreamingMessages();
|
|
436
|
+
|
|
437
|
+
rejectOutputMessagesPromise(err);
|
|
438
|
+
},
|
|
439
|
+
complete: async () => {
|
|
440
|
+
logger.debug("Event stream completed");
|
|
441
|
+
if (data.cloud?.guardrails) {
|
|
442
|
+
logger.debug("Guardrails is enabled, waiting for guardrails result");
|
|
443
|
+
await firstValueFrom(guardrailsResult$);
|
|
444
|
+
}
|
|
445
|
+
responseStatus$.next(new SuccessResponseStatus());
|
|
446
|
+
eventStreamSubscription?.unsubscribe();
|
|
447
|
+
stopStreamingMessages();
|
|
448
|
+
|
|
449
|
+
resolveOutputMessagesPromise(outputMessages);
|
|
140
450
|
},
|
|
141
451
|
});
|
|
142
452
|
}),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GraphQLJSON } from "graphql-scalars";
|
|
1
2
|
import { Field, InterfaceType, ObjectType, createUnionType, registerEnumType } from "type-graphql";
|
|
2
3
|
|
|
3
4
|
export enum ResponseStatusCode {
|
|
@@ -38,12 +39,25 @@ export class SuccessResponseStatus extends BaseResponseStatus {
|
|
|
38
39
|
code: ResponseStatusCode = ResponseStatusCode.Success;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
export enum FailedResponseStatusReason {
|
|
43
|
+
GUARDRAILS_VALIDATION_FAILED = "GUARDRAILS_VALIDATION_FAILED",
|
|
44
|
+
MESSAGE_STREAM_INTERRUPTED = "MESSAGE_STREAM_INTERRUPTED",
|
|
45
|
+
UNKNOWN_ERROR = "UNKNOWN_ERROR",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
registerEnumType(FailedResponseStatusReason, {
|
|
49
|
+
name: "FailedResponseStatusReason",
|
|
50
|
+
});
|
|
51
|
+
|
|
41
52
|
@ObjectType({ implements: BaseResponseStatus })
|
|
42
53
|
export class FailedResponseStatus extends BaseResponseStatus {
|
|
43
54
|
code: ResponseStatusCode = ResponseStatusCode.Failed;
|
|
44
55
|
|
|
45
|
-
@Field(() =>
|
|
46
|
-
reason:
|
|
56
|
+
@Field(() => FailedResponseStatusReason)
|
|
57
|
+
reason: FailedResponseStatusReason;
|
|
58
|
+
|
|
59
|
+
@Field(() => GraphQLJSON, { nullable: true })
|
|
60
|
+
details?: Record<string, any> = null;
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
export const ResponseStatusUnion = createUnionType({
|
package/src/index.ts
CHANGED