@copilotkit/runtime 0.0.0-test-custom-tag-prerelease-1-20250108200215

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 (146) hide show
  1. package/.eslintrc.js +7 -0
  2. package/CHANGELOG.md +729 -0
  3. package/README.md +46 -0
  4. package/__snapshots__/schema/schema.graphql +262 -0
  5. package/dist/chunk-2WXVJKUZ.mjs +25 -0
  6. package/dist/chunk-2WXVJKUZ.mjs.map +1 -0
  7. package/dist/chunk-44O2JGUY.mjs +12 -0
  8. package/dist/chunk-44O2JGUY.mjs.map +1 -0
  9. package/dist/chunk-CLGKEUOA.mjs +1408 -0
  10. package/dist/chunk-CLGKEUOA.mjs.map +1 -0
  11. package/dist/chunk-D2WLFQS6.mjs +43 -0
  12. package/dist/chunk-D2WLFQS6.mjs.map +1 -0
  13. package/dist/chunk-DFOKBSIS.mjs +1 -0
  14. package/dist/chunk-DFOKBSIS.mjs.map +1 -0
  15. package/dist/chunk-RFF5IIZJ.mjs +66 -0
  16. package/dist/chunk-RFF5IIZJ.mjs.map +1 -0
  17. package/dist/chunk-U3V2BCGI.mjs +152 -0
  18. package/dist/chunk-U3V2BCGI.mjs.map +1 -0
  19. package/dist/chunk-UYX3NHOI.mjs +25 -0
  20. package/dist/chunk-UYX3NHOI.mjs.map +1 -0
  21. package/dist/chunk-W3GSZTZR.mjs +3281 -0
  22. package/dist/chunk-W3GSZTZR.mjs.map +1 -0
  23. package/dist/chunk-WPNQ4AMN.mjs +80 -0
  24. package/dist/chunk-WPNQ4AMN.mjs.map +1 -0
  25. package/dist/copilot-runtime-6285d897.d.ts +189 -0
  26. package/dist/graphql/types/base/index.d.ts +6 -0
  27. package/dist/graphql/types/base/index.js +63 -0
  28. package/dist/graphql/types/base/index.js.map +1 -0
  29. package/dist/graphql/types/base/index.mjs +8 -0
  30. package/dist/graphql/types/base/index.mjs.map +1 -0
  31. package/dist/graphql/types/converted/index.d.ts +2 -0
  32. package/dist/graphql/types/converted/index.js +124 -0
  33. package/dist/graphql/types/converted/index.js.map +1 -0
  34. package/dist/graphql/types/converted/index.mjs +17 -0
  35. package/dist/graphql/types/converted/index.mjs.map +1 -0
  36. package/dist/groq-adapter-15d41154.d.ts +281 -0
  37. package/dist/index-ff3fbc33.d.ts +87 -0
  38. package/dist/index.d.ts +23 -0
  39. package/dist/index.js +5039 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/index.mjs +76 -0
  42. package/dist/index.mjs.map +1 -0
  43. package/dist/langserve-48e976ac.d.ts +176 -0
  44. package/dist/lib/cloud/index.d.ts +6 -0
  45. package/dist/lib/cloud/index.js +18 -0
  46. package/dist/lib/cloud/index.js.map +1 -0
  47. package/dist/lib/cloud/index.mjs +1 -0
  48. package/dist/lib/cloud/index.mjs.map +1 -0
  49. package/dist/lib/index.d.ts +20 -0
  50. package/dist/lib/index.js +4687 -0
  51. package/dist/lib/index.js.map +1 -0
  52. package/dist/lib/index.mjs +58 -0
  53. package/dist/lib/index.mjs.map +1 -0
  54. package/dist/lib/integrations/index.d.ts +33 -0
  55. package/dist/lib/integrations/index.js +2091 -0
  56. package/dist/lib/integrations/index.js.map +1 -0
  57. package/dist/lib/integrations/index.mjs +34 -0
  58. package/dist/lib/integrations/index.mjs.map +1 -0
  59. package/dist/lib/integrations/nest/index.d.ts +14 -0
  60. package/dist/lib/integrations/nest/index.js +2000 -0
  61. package/dist/lib/integrations/nest/index.js.map +1 -0
  62. package/dist/lib/integrations/nest/index.mjs +13 -0
  63. package/dist/lib/integrations/nest/index.mjs.map +1 -0
  64. package/dist/lib/integrations/node-express/index.d.ts +14 -0
  65. package/dist/lib/integrations/node-express/index.js +2000 -0
  66. package/dist/lib/integrations/node-express/index.js.map +1 -0
  67. package/dist/lib/integrations/node-express/index.mjs +13 -0
  68. package/dist/lib/integrations/node-express/index.mjs.map +1 -0
  69. package/dist/lib/integrations/node-http/index.d.ts +14 -0
  70. package/dist/lib/integrations/node-http/index.js +1986 -0
  71. package/dist/lib/integrations/node-http/index.js.map +1 -0
  72. package/dist/lib/integrations/node-http/index.mjs +12 -0
  73. package/dist/lib/integrations/node-http/index.mjs.map +1 -0
  74. package/dist/service-adapters/index.d.ts +84 -0
  75. package/dist/service-adapters/index.js +1448 -0
  76. package/dist/service-adapters/index.js.map +1 -0
  77. package/dist/service-adapters/index.mjs +26 -0
  78. package/dist/service-adapters/index.mjs.map +1 -0
  79. package/dist/utils/index.d.ts +49 -0
  80. package/dist/utils/index.js +174 -0
  81. package/dist/utils/index.js.map +1 -0
  82. package/dist/utils/index.mjs +12 -0
  83. package/dist/utils/index.mjs.map +1 -0
  84. package/jest.config.js +5 -0
  85. package/package.json +85 -0
  86. package/scripts/generate-gql-schema.ts +13 -0
  87. package/src/agents/langgraph/event-source.ts +287 -0
  88. package/src/agents/langgraph/events.ts +338 -0
  89. package/src/graphql/inputs/action.input.ts +16 -0
  90. package/src/graphql/inputs/agent-session.input.ts +13 -0
  91. package/src/graphql/inputs/agent-state.input.ts +10 -0
  92. package/src/graphql/inputs/cloud-guardrails.input.ts +16 -0
  93. package/src/graphql/inputs/cloud.input.ts +8 -0
  94. package/src/graphql/inputs/context-property.input.ts +10 -0
  95. package/src/graphql/inputs/custom-property.input.ts +15 -0
  96. package/src/graphql/inputs/forwarded-parameters.input.ts +22 -0
  97. package/src/graphql/inputs/frontend.input.ts +14 -0
  98. package/src/graphql/inputs/generate-copilot-response.input.ts +47 -0
  99. package/src/graphql/inputs/message.input.ts +92 -0
  100. package/src/graphql/resolvers/copilot.resolver.ts +540 -0
  101. package/src/graphql/types/base/index.ts +10 -0
  102. package/src/graphql/types/converted/index.ts +70 -0
  103. package/src/graphql/types/copilot-response.type.ts +113 -0
  104. package/src/graphql/types/enums.ts +37 -0
  105. package/src/graphql/types/guardrails-result.type.ts +20 -0
  106. package/src/graphql/types/message-status.type.ts +40 -0
  107. package/src/graphql/types/response-status.type.ts +66 -0
  108. package/src/index.ts +4 -0
  109. package/src/lib/cloud/index.ts +4 -0
  110. package/src/lib/index.ts +8 -0
  111. package/src/lib/integrations/index.ts +6 -0
  112. package/src/lib/integrations/nest/index.ts +17 -0
  113. package/src/lib/integrations/nextjs/app-router.ts +40 -0
  114. package/src/lib/integrations/nextjs/pages-router.ts +49 -0
  115. package/src/lib/integrations/node-express/index.ts +17 -0
  116. package/src/lib/integrations/node-http/index.ts +34 -0
  117. package/src/lib/integrations/shared.ts +109 -0
  118. package/src/lib/logger.ts +28 -0
  119. package/src/lib/runtime/copilot-runtime.ts +412 -0
  120. package/src/lib/runtime/remote-action-constructors.ts +304 -0
  121. package/src/lib/runtime/remote-actions.ts +174 -0
  122. package/src/lib/runtime/remote-lg-action.ts +657 -0
  123. package/src/lib/telemetry-client.ts +52 -0
  124. package/src/service-adapters/anthropic/anthropic-adapter.ts +205 -0
  125. package/src/service-adapters/anthropic/utils.ts +144 -0
  126. package/src/service-adapters/conversion.ts +64 -0
  127. package/src/service-adapters/events.ts +377 -0
  128. package/src/service-adapters/experimental/empty/empty-adapter.ts +33 -0
  129. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +79 -0
  130. package/src/service-adapters/google/google-genai-adapter.ts +39 -0
  131. package/src/service-adapters/groq/groq-adapter.ts +173 -0
  132. package/src/service-adapters/index.ts +16 -0
  133. package/src/service-adapters/langchain/langchain-adapter.ts +99 -0
  134. package/src/service-adapters/langchain/langserve.ts +87 -0
  135. package/src/service-adapters/langchain/types.ts +14 -0
  136. package/src/service-adapters/langchain/utils.ts +306 -0
  137. package/src/service-adapters/openai/openai-adapter.ts +210 -0
  138. package/src/service-adapters/openai/openai-assistant-adapter.ts +304 -0
  139. package/src/service-adapters/openai/utils.ts +161 -0
  140. package/src/service-adapters/service-adapter.ts +30 -0
  141. package/src/service-adapters/unify/unify-adapter.ts +145 -0
  142. package/src/utils/failed-response-status-reasons.ts +48 -0
  143. package/src/utils/index.ts +1 -0
  144. package/tsconfig.json +11 -0
  145. package/tsup.config.ts +16 -0
  146. package/typedoc.json +4 -0
@@ -0,0 +1,540 @@
1
+ import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql";
2
+ import {
3
+ ReplaySubject,
4
+ Subject,
5
+ Subscription,
6
+ filter,
7
+ finalize,
8
+ firstValueFrom,
9
+ shareReplay,
10
+ skipWhile,
11
+ take,
12
+ takeWhile,
13
+ tap,
14
+ } from "rxjs";
15
+ import { GenerateCopilotResponseInput } from "../inputs/generate-copilot-response.input";
16
+ import { CopilotResponse } from "../types/copilot-response.type";
17
+ import { ActionInputAvailability, MessageRole } from "../types/enums";
18
+ import { Repeater } from "graphql-yoga";
19
+ import type { CopilotRequestContextProperties, GraphQLContext } from "../../lib/integrations";
20
+ import { RuntimeEvent, RuntimeEventTypes } from "../../service-adapters/events";
21
+ import {
22
+ FailedMessageStatus,
23
+ MessageStatusUnion,
24
+ SuccessMessageStatus,
25
+ } from "../types/message-status.type";
26
+ import { ResponseStatusUnion, SuccessResponseStatus } from "../types/response-status.type";
27
+ import { GraphQLJSONObject } from "graphql-scalars";
28
+ import { plainToInstance } from "class-transformer";
29
+ import { GuardrailsResult } from "../types/guardrails-result.type";
30
+ import { GraphQLError } from "graphql";
31
+ import {
32
+ GuardrailsValidationFailureResponse,
33
+ MessageStreamInterruptedResponse,
34
+ UnknownErrorResponse,
35
+ } from "../../utils";
36
+ import {
37
+ ActionExecutionMessage,
38
+ AgentStateMessage,
39
+ Message,
40
+ ResultMessage,
41
+ TextMessage,
42
+ } from "../types/converted";
43
+ import telemetry from "../../lib/telemetry-client";
44
+ import { randomId } from "@copilotkit/shared";
45
+
46
+ const invokeGuardrails = async ({
47
+ baseUrl,
48
+ copilotCloudPublicApiKey,
49
+ data,
50
+ onResult,
51
+ onError,
52
+ }: {
53
+ baseUrl: string;
54
+ copilotCloudPublicApiKey: string;
55
+ data: GenerateCopilotResponseInput;
56
+ onResult: (result: GuardrailsResult) => void;
57
+ onError: (err: Error) => void;
58
+ }) => {
59
+ if (
60
+ data.messages.length &&
61
+ data.messages[data.messages.length - 1].textMessage?.role === MessageRole.user
62
+ ) {
63
+ const messages = data.messages
64
+ .filter(
65
+ (m) =>
66
+ m.textMessage !== undefined &&
67
+ (m.textMessage.role === MessageRole.user || m.textMessage.role === MessageRole.assistant),
68
+ )
69
+ .map((m) => ({
70
+ role: m.textMessage!.role,
71
+ content: m.textMessage.content,
72
+ }));
73
+
74
+ const lastMessage = messages[messages.length - 1];
75
+ const restOfMessages = messages.slice(0, -1);
76
+
77
+ const body = {
78
+ input: lastMessage.content,
79
+ validTopics: data.cloud.guardrails.inputValidationRules.allowList,
80
+ invalidTopics: data.cloud.guardrails.inputValidationRules.denyList,
81
+ messages: restOfMessages,
82
+ };
83
+
84
+ const guardrailsResult = await fetch(`${baseUrl}/guardrails/validate`, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ "X-CopilotCloud-Public-API-Key": copilotCloudPublicApiKey,
89
+ },
90
+ body: JSON.stringify(body),
91
+ });
92
+
93
+ if (guardrailsResult.ok) {
94
+ const resultJson: GuardrailsResult = await guardrailsResult.json();
95
+ onResult(resultJson);
96
+ } else {
97
+ onError(await guardrailsResult.json());
98
+ }
99
+ }
100
+ };
101
+
102
+ @Resolver(() => CopilotResponse)
103
+ export class CopilotResolver {
104
+ @Query(() => String)
105
+ async hello() {
106
+ return "Hello World";
107
+ }
108
+
109
+ @Mutation(() => CopilotResponse)
110
+ async generateCopilotResponse(
111
+ @Ctx() ctx: GraphQLContext,
112
+ @Arg("data") data: GenerateCopilotResponseInput,
113
+ @Arg("properties", () => GraphQLJSONObject, { nullable: true })
114
+ properties?: CopilotRequestContextProperties,
115
+ ) {
116
+ telemetry.capture("oss.runtime.copilot_request_created", {
117
+ "cloud.guardrails.enabled": data.cloud?.guardrails !== undefined,
118
+ requestType: data.metadata.requestType,
119
+ });
120
+
121
+ let logger = ctx.logger.child({ component: "CopilotResolver.generateCopilotResponse" });
122
+ logger.debug({ data }, "Generating Copilot response");
123
+
124
+ if (properties) {
125
+ logger.debug("Properties provided, merging with context properties");
126
+ ctx.properties = { ...ctx.properties, ...properties };
127
+ }
128
+
129
+ const copilotRuntime = ctx._copilotkit.runtime;
130
+ const serviceAdapter = ctx._copilotkit.serviceAdapter;
131
+
132
+ let copilotCloudPublicApiKey: string | null = null;
133
+ let copilotCloudBaseUrl: string;
134
+
135
+ if (data.cloud) {
136
+ logger = logger.child({ cloud: true });
137
+ logger.debug("Cloud configuration provided, checking for public API key in headers");
138
+ const key = ctx.request.headers.get("x-copilotcloud-public-api-key");
139
+ if (key) {
140
+ logger.debug("Public API key found in headers");
141
+ copilotCloudPublicApiKey = key;
142
+ } else {
143
+ logger.error("Public API key not found in headers");
144
+ throw new GraphQLError("X-CopilotCloud-Public-API-Key header is required");
145
+ }
146
+
147
+ if (process.env.COPILOT_CLOUD_BASE_URL) {
148
+ copilotCloudBaseUrl = process.env.COPILOT_CLOUD_BASE_URL;
149
+ } else if (ctx._copilotkit.cloud?.baseUrl) {
150
+ copilotCloudBaseUrl = ctx._copilotkit.cloud?.baseUrl;
151
+ } else {
152
+ copilotCloudBaseUrl = "https://api.cloud.copilotkit.ai";
153
+ }
154
+
155
+ logger = logger.child({ copilotCloudBaseUrl });
156
+ }
157
+
158
+ logger.debug("Setting up subjects");
159
+ const responseStatus$ = new ReplaySubject<typeof ResponseStatusUnion>();
160
+ const interruptStreaming$ = new ReplaySubject<{ reason: string; messageId?: string }>();
161
+ const guardrailsResult$ = new ReplaySubject<GuardrailsResult>();
162
+
163
+ let outputMessages: Message[] = [];
164
+ let resolveOutputMessagesPromise: (messages: Message[]) => void;
165
+ let rejectOutputMessagesPromise: (err: Error) => void;
166
+
167
+ const outputMessagesPromise = new Promise<Message[]>((resolve, reject) => {
168
+ resolveOutputMessagesPromise = resolve;
169
+ rejectOutputMessagesPromise = reject;
170
+ });
171
+
172
+ logger.debug("Processing");
173
+ const {
174
+ eventSource,
175
+ threadId = randomId(),
176
+ runId,
177
+ serverSideActions,
178
+ actionInputsWithoutAgents,
179
+ } = await copilotRuntime.processRuntimeRequest({
180
+ serviceAdapter,
181
+ messages: data.messages,
182
+ actions: data.frontend.actions.filter(
183
+ (action) => action.available !== ActionInputAvailability.disabled,
184
+ ),
185
+ threadId: data.threadId,
186
+ runId: data.runId,
187
+ publicApiKey: undefined,
188
+ outputMessagesPromise,
189
+ graphqlContext: ctx,
190
+ forwardedParameters: data.forwardedParameters,
191
+ agentSession: data.agentSession,
192
+ agentStates: data.agentStates,
193
+ url: data.frontend.url,
194
+ });
195
+
196
+ logger.debug("Event source created, creating response");
197
+
198
+ const response = {
199
+ threadId,
200
+ runId,
201
+ status: firstValueFrom(responseStatus$),
202
+ messages: new Repeater(async (pushMessage, stopStreamingMessages) => {
203
+ logger.debug("Messages repeater created");
204
+
205
+ if (data.cloud?.guardrails) {
206
+ logger = logger.child({ guardrails: true });
207
+ logger.debug("Guardrails is enabled, validating input");
208
+
209
+ invokeGuardrails({
210
+ baseUrl: copilotCloudBaseUrl,
211
+ copilotCloudPublicApiKey,
212
+ data,
213
+ onResult: (result) => {
214
+ logger.debug({ status: result.status }, "Guardrails validation done");
215
+ guardrailsResult$.next(result);
216
+
217
+ // Guardrails validation failed
218
+ if (result.status === "denied") {
219
+ // send the reason to the client and interrupt streaming
220
+ responseStatus$.next(
221
+ new GuardrailsValidationFailureResponse({ guardrailsReason: result.reason }),
222
+ );
223
+ interruptStreaming$.next({
224
+ reason: `Interrupted due to Guardrails validation failure. Reason: ${result.reason}`,
225
+ });
226
+
227
+ // resolve messages promise to the middleware
228
+ outputMessages = [
229
+ plainToInstance(TextMessage, {
230
+ id: randomId(),
231
+ createdAt: new Date(),
232
+ content: result.reason,
233
+ role: MessageRole.assistant,
234
+ }),
235
+ ];
236
+ resolveOutputMessagesPromise(outputMessages);
237
+ }
238
+ },
239
+ onError: (err) => {
240
+ logger.error({ err }, "Error in guardrails validation");
241
+ responseStatus$.next(
242
+ new UnknownErrorResponse({
243
+ description: `An unknown error has occurred in the guardrails validation`,
244
+ }),
245
+ );
246
+ interruptStreaming$.next({
247
+ reason: `Interrupted due to unknown error in guardrails validation`,
248
+ });
249
+
250
+ // reject the middleware promise
251
+ rejectOutputMessagesPromise(err);
252
+ },
253
+ });
254
+ }
255
+
256
+ let eventStreamSubscription: Subscription;
257
+
258
+ // run and process the event stream
259
+ const eventStream = eventSource
260
+ .processRuntimeEvents({
261
+ serverSideActions,
262
+ guardrailsResult$: data.cloud?.guardrails ? guardrailsResult$ : null,
263
+ actionInputsWithoutAgents: actionInputsWithoutAgents.filter(
264
+ // TODO-AGENTS: do not exclude ALL server side actions
265
+ (action) =>
266
+ !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
267
+ ),
268
+ })
269
+ .pipe(
270
+ // shareReplay() ensures that later subscribers will see the whole stream instead of
271
+ // just the events that were emitted after the subscriber was added.
272
+ shareReplay(),
273
+ finalize(() => {
274
+ logger.debug("Event stream finalized");
275
+ }),
276
+ );
277
+
278
+ logger.debug("Event stream created, subscribing to event stream");
279
+
280
+ eventStreamSubscription = eventStream.subscribe({
281
+ next: async (event) => {
282
+ switch (event.type) {
283
+ ////////////////////////////////
284
+ // TextMessageStart
285
+ ////////////////////////////////
286
+ case RuntimeEventTypes.TextMessageStart:
287
+ // create a sub stream that contains the message content
288
+ const textMessageContentStream = eventStream.pipe(
289
+ // skip until this message start event
290
+ skipWhile((e) => e !== event),
291
+ // take until the message end event
292
+ takeWhile(
293
+ (e) =>
294
+ !(
295
+ e.type === RuntimeEventTypes.TextMessageEnd &&
296
+ e.messageId == event.messageId
297
+ ),
298
+ ),
299
+ // filter out any other message events or message ids
300
+ filter(
301
+ (e) =>
302
+ e.type == RuntimeEventTypes.TextMessageContent &&
303
+ e.messageId == event.messageId,
304
+ ),
305
+ );
306
+
307
+ // signal when we are done streaming
308
+ const streamingTextStatus = new Subject<typeof MessageStatusUnion>();
309
+
310
+ const messageId = event.messageId;
311
+ // push the new message
312
+ pushMessage({
313
+ id: messageId,
314
+ parentMessageId: event.parentMessageId,
315
+ status: firstValueFrom(streamingTextStatus),
316
+ createdAt: new Date(),
317
+ role: MessageRole.assistant,
318
+ content: new Repeater(async (pushTextChunk, stopStreamingText) => {
319
+ logger.debug("Text message content repeater created");
320
+
321
+ const textChunks: string[] = [];
322
+ let textSubscription: Subscription;
323
+
324
+ interruptStreaming$
325
+ .pipe(
326
+ shareReplay(),
327
+ take(1),
328
+ tap(({ reason, messageId }) => {
329
+ logger.debug({ reason, messageId }, "Text streaming interrupted");
330
+
331
+ streamingTextStatus.next(
332
+ plainToInstance(FailedMessageStatus, { reason }),
333
+ );
334
+
335
+ responseStatus$.next(new MessageStreamInterruptedResponse({ messageId }));
336
+ stopStreamingText();
337
+ textSubscription?.unsubscribe();
338
+ }),
339
+ )
340
+ .subscribe();
341
+
342
+ logger.debug("Subscribing to text message content stream");
343
+
344
+ textSubscription = textMessageContentStream.subscribe({
345
+ next: async (e: RuntimeEvent) => {
346
+ if (e.type == RuntimeEventTypes.TextMessageContent) {
347
+ await pushTextChunk(e.content);
348
+ textChunks.push(e.content);
349
+ }
350
+ },
351
+ error: (err) => {
352
+ logger.error({ err }, "Error in text message content stream");
353
+ interruptStreaming$.next({
354
+ reason: "Error streaming message content",
355
+ messageId,
356
+ });
357
+ stopStreamingText();
358
+ textSubscription?.unsubscribe();
359
+ },
360
+ complete: () => {
361
+ logger.debug("Text message content stream completed");
362
+ streamingTextStatus.next(new SuccessMessageStatus());
363
+ stopStreamingText();
364
+ textSubscription?.unsubscribe();
365
+
366
+ outputMessages.push(
367
+ plainToInstance(TextMessage, {
368
+ id: messageId,
369
+ createdAt: new Date(),
370
+ content: textChunks.join(""),
371
+ role: MessageRole.assistant,
372
+ }),
373
+ );
374
+ },
375
+ });
376
+ }),
377
+ });
378
+ break;
379
+ ////////////////////////////////
380
+ // ActionExecutionStart
381
+ ////////////////////////////////
382
+ case RuntimeEventTypes.ActionExecutionStart:
383
+ logger.debug("Action execution start event received");
384
+ const actionExecutionArgumentStream = eventStream.pipe(
385
+ skipWhile((e) => e !== event),
386
+ // take until the action execution end event
387
+ takeWhile(
388
+ (e) =>
389
+ !(
390
+ e.type === RuntimeEventTypes.ActionExecutionEnd &&
391
+ e.actionExecutionId == event.actionExecutionId
392
+ ),
393
+ ),
394
+ // filter out any other action execution events or action execution ids
395
+ filter(
396
+ (e) =>
397
+ e.type == RuntimeEventTypes.ActionExecutionArgs &&
398
+ e.actionExecutionId == event.actionExecutionId,
399
+ ),
400
+ );
401
+ const streamingArgumentsStatus = new Subject<typeof MessageStatusUnion>();
402
+ pushMessage({
403
+ id: event.actionExecutionId,
404
+ parentMessageId: event.parentMessageId,
405
+ status: firstValueFrom(streamingArgumentsStatus),
406
+ createdAt: new Date(),
407
+ name: event.actionName,
408
+ arguments: new Repeater(async (pushArgumentsChunk, stopStreamingArguments) => {
409
+ logger.debug("Action execution argument stream created");
410
+
411
+ const argumentChunks: string[] = [];
412
+ let actionExecutionArgumentSubscription: Subscription;
413
+
414
+ actionExecutionArgumentSubscription = actionExecutionArgumentStream.subscribe({
415
+ next: async (e: RuntimeEvent) => {
416
+ if (e.type == RuntimeEventTypes.ActionExecutionArgs) {
417
+ await pushArgumentsChunk(e.args);
418
+ argumentChunks.push(e.args);
419
+ }
420
+ },
421
+ error: (err) => {
422
+ logger.error({ err }, "Error in action execution argument stream");
423
+ streamingArgumentsStatus.next(
424
+ plainToInstance(FailedMessageStatus, {
425
+ reason:
426
+ "An unknown error has occurred in the action execution argument stream",
427
+ }),
428
+ );
429
+ stopStreamingArguments();
430
+ actionExecutionArgumentSubscription?.unsubscribe();
431
+ },
432
+ complete: () => {
433
+ logger.debug("Action execution argument stream completed");
434
+ streamingArgumentsStatus.next(new SuccessMessageStatus());
435
+ stopStreamingArguments();
436
+ actionExecutionArgumentSubscription?.unsubscribe();
437
+
438
+ outputMessages.push(
439
+ plainToInstance(ActionExecutionMessage, {
440
+ id: event.actionExecutionId,
441
+ createdAt: new Date(),
442
+ name: event.actionName,
443
+ arguments: argumentChunks.join(""),
444
+ }),
445
+ );
446
+ },
447
+ });
448
+ }),
449
+ });
450
+ break;
451
+ ////////////////////////////////
452
+ // ActionExecutionResult
453
+ ////////////////////////////////
454
+ case RuntimeEventTypes.ActionExecutionResult:
455
+ logger.debug({ result: event.result }, "Action execution result event received");
456
+ pushMessage({
457
+ id: "result-" + event.actionExecutionId,
458
+ status: new SuccessMessageStatus(),
459
+ createdAt: new Date(),
460
+ actionExecutionId: event.actionExecutionId,
461
+ actionName: event.actionName,
462
+ result: event.result,
463
+ });
464
+
465
+ outputMessages.push(
466
+ plainToInstance(ResultMessage, {
467
+ id: "result-" + event.actionExecutionId,
468
+ createdAt: new Date(),
469
+ actionExecutionId: event.actionExecutionId,
470
+ actionName: event.actionName,
471
+ result: event.result,
472
+ }),
473
+ );
474
+ break;
475
+ ////////////////////////////////
476
+ // AgentStateMessage
477
+ ////////////////////////////////
478
+ case RuntimeEventTypes.AgentStateMessage:
479
+ logger.debug({ event }, "Agent message event received");
480
+ pushMessage({
481
+ id: randomId(),
482
+ status: new SuccessMessageStatus(),
483
+ threadId: event.threadId,
484
+ agentName: event.agentName,
485
+ nodeName: event.nodeName,
486
+ runId: event.runId,
487
+ active: event.active,
488
+ state: event.state,
489
+ running: event.running,
490
+ role: MessageRole.assistant,
491
+ createdAt: new Date(),
492
+ });
493
+ outputMessages.push(
494
+ plainToInstance(AgentStateMessage, {
495
+ id: randomId(),
496
+ threadId: event.threadId,
497
+ agentName: event.agentName,
498
+ nodeName: event.nodeName,
499
+ runId: event.runId,
500
+ active: event.active,
501
+ state: event.state,
502
+ running: event.running,
503
+ role: MessageRole.assistant,
504
+ createdAt: new Date(),
505
+ }),
506
+ );
507
+ break;
508
+ }
509
+ },
510
+ error: (err) => {
511
+ logger.error({ err }, "Error in event stream");
512
+ responseStatus$.next(
513
+ new UnknownErrorResponse({
514
+ description: `An unknown error has occurred in the event stream`,
515
+ }),
516
+ );
517
+ eventStreamSubscription?.unsubscribe();
518
+ stopStreamingMessages();
519
+
520
+ rejectOutputMessagesPromise(err);
521
+ },
522
+ complete: async () => {
523
+ logger.debug("Event stream completed");
524
+ if (data.cloud?.guardrails) {
525
+ logger.debug("Guardrails is enabled, waiting for guardrails result");
526
+ await firstValueFrom(guardrailsResult$);
527
+ }
528
+ responseStatus$.next(new SuccessResponseStatus());
529
+ eventStreamSubscription?.unsubscribe();
530
+ stopStreamingMessages();
531
+
532
+ resolveOutputMessagesPromise(outputMessages);
533
+ },
534
+ });
535
+ }),
536
+ };
537
+
538
+ return response;
539
+ }
540
+ }
@@ -0,0 +1,10 @@
1
+ import { Field, InputType } from "type-graphql";
2
+
3
+ @InputType()
4
+ export class BaseMessageInput {
5
+ @Field(() => String)
6
+ id: string;
7
+
8
+ @Field(() => Date)
9
+ createdAt: Date;
10
+ }
@@ -0,0 +1,70 @@
1
+ import {
2
+ ActionExecutionMessageInput,
3
+ ResultMessageInput,
4
+ TextMessageInput,
5
+ AgentStateMessageInput,
6
+ } from "../../inputs/message.input";
7
+ import { BaseMessageInput } from "../base";
8
+ import { MessageRole } from "../enums";
9
+
10
+ export type MessageType =
11
+ | "TextMessage"
12
+ | "ActionExecutionMessage"
13
+ | "ResultMessage"
14
+ | "AgentStateMessage";
15
+
16
+ export class Message extends BaseMessageInput {
17
+ type: MessageType;
18
+
19
+ isTextMessage(): this is TextMessage {
20
+ return this.type === "TextMessage";
21
+ }
22
+
23
+ isActionExecutionMessage(): this is ActionExecutionMessage {
24
+ return this.type === "ActionExecutionMessage";
25
+ }
26
+
27
+ isResultMessage(): this is ResultMessage {
28
+ return this.type === "ResultMessage";
29
+ }
30
+
31
+ isAgentStateMessage(): this is AgentStateMessage {
32
+ return this.type === "AgentStateMessage";
33
+ }
34
+ }
35
+
36
+ export class TextMessage extends Message implements TextMessageInput {
37
+ type: MessageType = "TextMessage";
38
+ content: string;
39
+ role: MessageRole;
40
+ parentMessageId?: string;
41
+ }
42
+
43
+ export class ActionExecutionMessage
44
+ extends Message
45
+ implements Omit<ActionExecutionMessageInput, "arguments" | "scope">
46
+ {
47
+ type: MessageType = "ActionExecutionMessage";
48
+ name: string;
49
+ arguments: Record<string, any>;
50
+ parentMessageId?: string;
51
+ }
52
+
53
+ export class ResultMessage extends Message implements ResultMessageInput {
54
+ type: MessageType = "ResultMessage";
55
+ actionExecutionId: string;
56
+ actionName: string;
57
+ result: string;
58
+ }
59
+
60
+ export class AgentStateMessage extends Message implements Omit<AgentStateMessageInput, "state"> {
61
+ type: MessageType = "AgentStateMessage";
62
+ threadId: string;
63
+ agentName: string;
64
+ nodeName: string;
65
+ runId: string;
66
+ active: boolean;
67
+ role: MessageRole;
68
+ state: any;
69
+ running: boolean;
70
+ }