@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.
Files changed (96) hide show
  1. package/.turbo/turbo-build.log +69 -54
  2. package/CHANGELOG.md +11 -0
  3. package/__snapshots__/schema/schema.graphql +15 -4
  4. package/dist/{chunk-2CCVVJDU.mjs → chunk-2PJG3NAC.mjs} +13 -15
  5. package/dist/chunk-2PJG3NAC.mjs.map +1 -0
  6. package/dist/{chunk-NFCPM5AM.mjs → chunk-6NZ4UMOD.mjs} +4 -4
  7. package/dist/chunk-6NZ4UMOD.mjs.map +1 -0
  8. package/dist/{chunk-XPAUPJMW.mjs → chunk-6YGDE3YI.mjs} +432 -220
  9. package/dist/chunk-6YGDE3YI.mjs.map +1 -0
  10. package/dist/chunk-BYB2LNMK.mjs +152 -0
  11. package/dist/chunk-BYB2LNMK.mjs.map +1 -0
  12. package/dist/{chunk-7IFP53C6.mjs → chunk-FRK6BXXV.mjs} +49 -11
  13. package/dist/chunk-FRK6BXXV.mjs.map +1 -0
  14. package/dist/{chunk-5HGYI6EG.mjs → chunk-JBDOA7MK.mjs} +34 -15
  15. package/dist/chunk-JBDOA7MK.mjs.map +1 -0
  16. package/dist/{chunk-4UA4RB4C.mjs → chunk-JIKPSUGQ.mjs} +45 -76
  17. package/dist/chunk-JIKPSUGQ.mjs.map +1 -0
  18. package/dist/{chunk-BLTAUVRP.mjs → chunk-OZMCHYYR.mjs} +5 -3
  19. package/dist/{chunk-BLTAUVRP.mjs.map → chunk-OZMCHYYR.mjs.map} +1 -1
  20. package/dist/chunk-RHQLCJGG.mjs +7 -0
  21. package/dist/chunk-RHQLCJGG.mjs.map +1 -0
  22. package/dist/failed-response-status-reasons-0ab19e06.d.ts +49 -0
  23. package/dist/graphql/types/base/index.mjs +2 -1
  24. package/dist/graphql/types/converted/index.mjs +3 -2
  25. package/dist/{index-f0875df3.d.ts → index-0e75acd2.d.ts} +86 -59
  26. package/dist/index.d.ts +7 -4
  27. package/dist/index.js +536 -169
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +16 -13
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{langchain-adapter-9ce103f3.d.ts → langchain-adapter-a02d1d38.d.ts} +4 -4
  32. package/dist/{langserve-fd5066ee.d.ts → langserve-75ebbc38.d.ts} +25 -9
  33. package/dist/lib/cloud/index.d.ts +6 -0
  34. package/dist/lib/cloud/index.js +18 -0
  35. package/dist/lib/cloud/index.js.map +1 -0
  36. package/dist/lib/cloud/index.mjs +1 -0
  37. package/dist/lib/cloud/index.mjs.map +1 -0
  38. package/dist/lib/index.d.ts +6 -4
  39. package/dist/lib/index.js +530 -169
  40. package/dist/lib/index.js.map +1 -1
  41. package/dist/lib/index.mjs +9 -13
  42. package/dist/lib/integrations/index.d.ts +5 -3
  43. package/dist/lib/integrations/index.js +426 -64
  44. package/dist/lib/integrations/index.js.map +1 -1
  45. package/dist/lib/integrations/index.mjs +7 -5
  46. package/dist/lib/integrations/node-http/index.d.ts +4 -2
  47. package/dist/lib/integrations/node-http/index.js +416 -52
  48. package/dist/lib/integrations/node-http/index.js.map +1 -1
  49. package/dist/lib/integrations/node-http/index.mjs +6 -4
  50. package/dist/pages-router-e81920d5.d.ts +21 -0
  51. package/dist/service-adapters/index.d.ts +2 -2
  52. package/dist/service-adapters/index.js +82 -25
  53. package/dist/service-adapters/index.js.map +1 -1
  54. package/dist/service-adapters/index.mjs +5 -4
  55. package/dist/utils/index.d.ts +1 -0
  56. package/dist/utils/index.js +174 -0
  57. package/dist/utils/index.js.map +1 -0
  58. package/dist/utils/index.mjs +12 -0
  59. package/dist/utils/index.mjs.map +1 -0
  60. package/package.json +6 -4
  61. package/src/graphql/inputs/cloud-guardrails.input.ts +2 -5
  62. package/src/graphql/inputs/cloud.input.ts +2 -2
  63. package/src/graphql/resolvers/copilot.resolver.ts +340 -30
  64. package/src/graphql/types/response-status.type.ts +16 -2
  65. package/src/index.ts +1 -0
  66. package/src/lib/cloud/index.ts +4 -0
  67. package/src/lib/copilot-runtime.ts +116 -70
  68. package/src/lib/index.ts +0 -1
  69. package/src/lib/integrations/nextjs/app-router.ts +9 -17
  70. package/src/lib/integrations/nextjs/pages-router.ts +9 -15
  71. package/src/lib/integrations/node-http/index.ts +6 -14
  72. package/src/lib/integrations/shared.ts +38 -18
  73. package/src/lib/logger.ts +28 -0
  74. package/src/service-adapters/events.ts +20 -2
  75. package/src/service-adapters/experimental/groq/groq-adapter.ts +3 -1
  76. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +3 -1
  77. package/src/service-adapters/google/google-genai-adapter.ts +6 -1
  78. package/src/service-adapters/google/utils.ts +1 -1
  79. package/src/service-adapters/index.ts +1 -1
  80. package/src/service-adapters/langchain/langchain-adapter.ts +8 -9
  81. package/src/service-adapters/langchain/langserve.ts +10 -4
  82. package/src/service-adapters/langchain/utils.ts +58 -9
  83. package/src/service-adapters/openai/openai-adapter.ts +8 -7
  84. package/src/service-adapters/openai/openai-assistant-adapter.ts +6 -8
  85. package/src/service-adapters/service-adapter.ts +1 -2
  86. package/src/utils/failed-response-status-reasons.ts +48 -0
  87. package/src/utils/index.ts +1 -0
  88. package/dist/chunk-2CCVVJDU.mjs.map +0 -1
  89. package/dist/chunk-4UA4RB4C.mjs.map +0 -1
  90. package/dist/chunk-5HGYI6EG.mjs.map +0 -1
  91. package/dist/chunk-7IFP53C6.mjs.map +0 -1
  92. package/dist/chunk-NFCPM5AM.mjs.map +0 -1
  93. package/dist/chunk-XPAUPJMW.mjs.map +0 -1
  94. package/dist/pages-router-b6bc6c60.d.ts +0 -30
  95. package/src/lib/copilot-cloud.ts +0 -63
  96. package/src/lib/guardrails.ts +0 -3
@@ -1,5 +1,16 @@
1
1
  import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql";
2
- import { Subject, firstValueFrom, shareReplay, skipWhile, takeWhile } from "rxjs";
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 { MessageStatusUnion, SuccessMessageStatus } from "../types/message-status.type";
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
- if (properties) {
29
- ctx._copilotkit.properties = { ...ctx._copilotkit.properties, ...properties };
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.process(copilotRuntime.actions).pipe(
55
- // shareReplay() ensures that later subscribers will see the whole stream instead of
56
- // just the events that were emitted after the subscriber was added.
57
- shareReplay(),
58
- );
59
- eventStream.subscribe({
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: nanoid(),
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
- // push the message content
85
- await textMessageContentStream.forEach(async (e: RuntimeEvent) => {
86
- if (e.type == RuntimeEventTypes.TextMessageContent) {
87
- await pushTextChunk(e.content);
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
- await actionExecutionArgumentStream.forEach(async (e: RuntimeEvent) => {
112
- if (e.type == RuntimeEventTypes.ActionExecutionArgs) {
113
- await pushArgumentsChunk(e.args);
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) => console.error("Error in event source", err),
137
- complete: () => {
138
- responseStatus.next(new SuccessResponseStatus());
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(() => String)
46
- reason: string;
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
@@ -1,2 +1,3 @@
1
1
  import "reflect-metadata";
2
2
  export * from "./lib";
3
+ export * from "./utils";
@@ -0,0 +1,4 @@
1
+ export interface CopilotCloudOptions {
2
+ baseUrl?: string;
3
+ publicApiKey?: string;
4
+ }