UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

446 lines (444 loc) • 20.4 kB
import "reflect-metadata"; import { MessageRole } from "../types/enums.mjs"; import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.112.0/helpers/decorateMetadata.mjs"; import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.112.0/helpers/decorate.mjs"; import { FailedMessageStatus, SuccessMessageStatus } from "../types/message-status.type.mjs"; import { SuccessResponseStatus } from "../types/response-status.type.mjs"; import { CopilotResponse } from "../types/copilot-response.type.mjs"; import { CopilotKitLangGraphInterruptEvent, LangGraphInterruptEvent } from "../types/meta-events.type.mjs"; import { GenerateCopilotResponseInput } from "../inputs/generate-copilot-response.input.mjs"; import { ActionExecutionMessage, AgentStateMessage, ResultMessage, TextMessage } from "../types/converted/index.mjs"; import { RuntimeEventTypes, RuntimeMetaEventName } from "../../service-adapters/events.mjs"; import { GuardrailsValidationFailureResponse, MessageStreamInterruptedResponse, UnknownErrorResponse } from "../../utils/failed-response-status-reasons.mjs"; import telemetryClient from "../../lib/telemetry-client.mjs"; import { resolveMessageId } from "./resolve-message-id.mjs"; import { AgentsResponse } from "../types/agents-response.type.mjs"; import { LangGraphEventTypes } from "../../agents/langgraph/events.mjs"; import { __decorateParam } from "../../_virtual/_@oxc-project_runtime@0.112.0/helpers/decorateParam.mjs"; import { CopilotKitError, CopilotKitLowLevelError, randomId } from "@copilotkit/shared"; import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql"; import { ReplaySubject, Subject, filter, finalize, firstValueFrom, shareReplay, skipWhile, take, takeWhile, tap } from "rxjs"; import { GraphQLJSONObject } from "graphql-scalars"; import { Repeater } from "graphql-yoga"; import { plainToInstance } from "class-transformer"; import { GraphQLError } from "graphql"; //#region src/graphql/resolvers/copilot.resolver.ts var _ref; const invokeGuardrails = async ({ baseUrl, copilotCloudPublicApiKey, data, onResult, onError }) => { if (data.messages.length && data.messages[data.messages.length - 1].textMessage?.role === MessageRole.user) { const messages = data.messages.filter((m) => m.textMessage !== void 0 && (m.textMessage.role === MessageRole.user || m.textMessage.role === MessageRole.assistant)).map((m) => ({ role: m.textMessage.role, content: m.textMessage.content })); const lastMessage = messages[messages.length - 1]; const restOfMessages = messages.slice(0, -1); const body = { input: lastMessage.content, validTopics: data.cloud.guardrails.inputValidationRules.allowList, invalidTopics: data.cloud.guardrails.inputValidationRules.denyList, messages: restOfMessages }; const guardrailsResult = await fetch(`${baseUrl}/guardrails/validate`, { method: "POST", headers: { "Content-Type": "application/json", "X-CopilotCloud-Public-API-Key": copilotCloudPublicApiKey }, body: JSON.stringify(body) }); if (guardrailsResult.ok) onResult(await guardrailsResult.json()); else onError(await guardrailsResult.json()); } }; let CopilotResolver = class CopilotResolver { async hello() { return "Hello World"; } async availableAgents(ctx) { let logger = ctx.logger.child({ component: "CopilotResolver.availableAgents" }); logger.debug("Processing"); const agentsWithEndpoints = []; logger.debug("Event source created, creating response"); return { agents: agentsWithEndpoints.map(({ endpoint, ...agentWithoutEndpoint }) => agentWithoutEndpoint) }; } async generateCopilotResponse(ctx, data, properties) { telemetryClient.capture("oss.runtime.copilot_request_created", { "cloud.guardrails.enabled": data.cloud?.guardrails !== void 0, requestType: data.metadata.requestType, "cloud.api_key_provided": !!ctx.request.headers.get("x-copilotcloud-public-api-key"), ...ctx.request.headers.get("x-copilotcloud-public-api-key") ? { "cloud.public_api_key": ctx.request.headers.get("x-copilotcloud-public-api-key") } : {}, ...ctx._copilotkit.baseUrl ? { "cloud.base_url": ctx._copilotkit.baseUrl } : { "cloud.base_url": "https://api.cloud.copilotkit.ai" } }); let logger = ctx.logger.child({ component: "CopilotResolver.generateCopilotResponse" }); logger.debug({ data }, "Generating Copilot response"); if (properties) { logger.debug("Properties provided, merging with context properties"); ctx.properties = { ...ctx.properties, ...properties }; } ctx._copilotkit.runtime; ctx._copilotkit.serviceAdapter; let copilotCloudPublicApiKey = null; let copilotCloudBaseUrl; const publicApiKeyFromHeaders = ctx.request.headers.get("x-copilotcloud-public-api-key"); if (publicApiKeyFromHeaders) copilotCloudPublicApiKey = publicApiKeyFromHeaders; if (data.cloud) { logger = logger.child({ cloud: true }); logger.debug("Cloud configuration provided, checking for public API key in headers"); if (!copilotCloudPublicApiKey) { logger.error("Public API key not found in headers"); throw new GraphQLError("X-CopilotCloud-Public-API-Key header is required"); } if (process.env.COPILOT_CLOUD_BASE_URL) copilotCloudBaseUrl = process.env.COPILOT_CLOUD_BASE_URL; else if (ctx._copilotkit.cloud?.baseUrl) copilotCloudBaseUrl = ctx._copilotkit.cloud?.baseUrl; else copilotCloudBaseUrl = "https://api.cloud.copilotkit.ai"; logger = logger.child({ copilotCloudBaseUrl }); } logger.debug("Setting up subjects"); const responseStatus$ = new ReplaySubject(); const interruptStreaming$ = new ReplaySubject(); const guardrailsResult$ = new ReplaySubject(); let outputMessages = []; let resolveOutputMessagesPromise; let rejectOutputMessagesPromise; new Promise((resolve, reject) => { resolveOutputMessagesPromise = resolve; rejectOutputMessagesPromise = reject; }); if (copilotCloudPublicApiKey) ctx.properties["copilotCloudPublicApiKey"] = copilotCloudPublicApiKey; logger.debug("Processing"); let runtimeResponse; const { eventSource, threadId = randomId(), runId, serverSideActions, actionInputsWithoutAgents, extensions } = runtimeResponse; logger.debug("Event source created, creating response"); const eventStream = eventSource.processRuntimeEvents({ serverSideActions, guardrailsResult$: data.cloud?.guardrails ? guardrailsResult$ : null, actionInputsWithoutAgents: actionInputsWithoutAgents.filter((action) => !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name)), threadId }).pipe(shareReplay(), finalize(() => { logger.debug("Event stream finalized"); })); return { threadId, runId, status: firstValueFrom(responseStatus$), extensions, metaEvents: new Repeater(async (push, stop) => { let eventStreamSubscription; eventStreamSubscription = eventStream.subscribe({ next: async (event) => { if (event.type != RuntimeEventTypes.MetaEvent) return; switch (event.name) { case LangGraphEventTypes.OnInterrupt: push(plainToInstance(LangGraphInterruptEvent, { type: event.type, name: RuntimeMetaEventName.LangGraphInterruptEvent, value: event.value })); break; case RuntimeMetaEventName.LangGraphInterruptEvent: push(plainToInstance(LangGraphInterruptEvent, { type: event.type, name: event.name, value: event.value })); break; case RuntimeMetaEventName.CopilotKitLangGraphInterruptEvent: push(plainToInstance(CopilotKitLangGraphInterruptEvent, { type: event.type, name: event.name, data: { value: event.data.value, messages: event.data.messages.map((message) => { if (message.type === "TextMessage" || "content" in message && "role" in message) return plainToInstance(TextMessage, { id: message.id, createdAt: /* @__PURE__ */ new Date(), content: [message.content], role: message.role, status: new SuccessMessageStatus() }); if ("arguments" in message) return plainToInstance(ActionExecutionMessage, { name: message.name, id: message.id, arguments: [JSON.stringify(message.arguments)], createdAt: /* @__PURE__ */ new Date(), status: new SuccessMessageStatus() }); throw new Error("Unknown message in metaEvents copilot resolver"); }) } })); break; } }, error: (err) => { if (err?.name?.includes("CopilotKit") || err?.extensions?.visibility) responseStatus$.next(new UnknownErrorResponse({ description: err.message || "Agent error occurred" })); else responseStatus$.next(new UnknownErrorResponse({ description: `An unknown error has occurred in the event stream` })); eventStreamSubscription?.unsubscribe(); stop(); }, complete: async () => { logger.debug("Meta events stream completed"); responseStatus$.next(new SuccessResponseStatus()); eventStreamSubscription?.unsubscribe(); stop(); } }); }), messages: new Repeater(async (pushMessage, stopStreamingMessages) => { logger.debug("Messages repeater created"); if (data.cloud?.guardrails) { logger = logger.child({ guardrails: true }); logger.debug("Guardrails is enabled, validating input"); invokeGuardrails({ baseUrl: copilotCloudBaseUrl, copilotCloudPublicApiKey, data, onResult: (result) => { logger.debug({ status: result.status }, "Guardrails validation done"); guardrailsResult$.next(result); if (result.status === "denied") { responseStatus$.next(new GuardrailsValidationFailureResponse({ guardrailsReason: result.reason })); interruptStreaming$.next({ reason: `Interrupted due to Guardrails validation failure. Reason: ${result.reason}` }); outputMessages = [plainToInstance(TextMessage, { id: randomId(), createdAt: /* @__PURE__ */ new Date(), content: result.reason, role: MessageRole.assistant })]; resolveOutputMessagesPromise(outputMessages); } }, onError: (err) => { logger.error({ err }, "Error in guardrails validation"); responseStatus$.next(new UnknownErrorResponse({ description: `An unknown error has occurred in the guardrails validation` })); interruptStreaming$.next({ reason: `Interrupted due to unknown error in guardrails validation` }); rejectOutputMessagesPromise(err); } }); } let eventStreamSubscription; logger.debug("Event stream created, subscribing to event stream"); eventStreamSubscription = eventStream.subscribe({ next: async (event) => { switch (event.type) { case RuntimeEventTypes.MetaEvent: break; case RuntimeEventTypes.TextMessageStart: const textMessageContentStream = eventStream.pipe(skipWhile((e) => e !== event), takeWhile((e) => !(e.type === RuntimeEventTypes.TextMessageEnd && e.messageId == event.messageId)), filter((e) => e.type == RuntimeEventTypes.TextMessageContent && e.messageId == event.messageId)); const streamingTextStatus = new Subject(); const messageId = resolveMessageId(event.messageId); pushMessage({ id: messageId, parentMessageId: event.parentMessageId, status: firstValueFrom(streamingTextStatus), createdAt: /* @__PURE__ */ new Date(), role: MessageRole.assistant, content: new Repeater(async (pushTextChunk, stopStreamingText) => { logger.debug("Text message content repeater created"); const textChunks = []; let textSubscription; interruptStreaming$.pipe(shareReplay(), take(1), tap(({ reason, messageId }) => { logger.debug({ reason, messageId }, "Text streaming interrupted"); streamingTextStatus.next(plainToInstance(FailedMessageStatus, { reason })); responseStatus$.next(new MessageStreamInterruptedResponse({ messageId })); stopStreamingText(); textSubscription?.unsubscribe(); })).subscribe(); logger.debug("Subscribing to text message content stream"); textSubscription = textMessageContentStream.subscribe({ next: async (e) => { if (e.type == RuntimeEventTypes.TextMessageContent) { await pushTextChunk(e.content); textChunks.push(e.content); } }, error: (err) => { logger.error({ err }, "Error in text message content stream"); interruptStreaming$.next({ reason: "Error streaming message content", messageId }); stopStreamingText(); textSubscription?.unsubscribe(); }, complete: () => { logger.debug("Text message content stream completed"); streamingTextStatus.next(new SuccessMessageStatus()); stopStreamingText(); textSubscription?.unsubscribe(); outputMessages.push(plainToInstance(TextMessage, { id: messageId, createdAt: /* @__PURE__ */ new Date(), content: textChunks.join(""), role: MessageRole.assistant })); } }); }) }); break; case RuntimeEventTypes.ActionExecutionStart: logger.debug("Action execution start event received"); const actionExecutionArgumentStream = eventStream.pipe(skipWhile((e) => e !== event), takeWhile((e) => !(e.type === RuntimeEventTypes.ActionExecutionEnd && e.actionExecutionId == event.actionExecutionId)), filter((e) => e.type == RuntimeEventTypes.ActionExecutionArgs && e.actionExecutionId == event.actionExecutionId)); const streamingArgumentsStatus = new Subject(); pushMessage({ id: event.actionExecutionId, parentMessageId: event.parentMessageId, status: firstValueFrom(streamingArgumentsStatus), createdAt: /* @__PURE__ */ new Date(), name: event.actionName, arguments: new Repeater(async (pushArgumentsChunk, stopStreamingArguments) => { logger.debug("Action execution argument stream created"); const argumentChunks = []; let actionExecutionArgumentSubscription; actionExecutionArgumentSubscription = actionExecutionArgumentStream.subscribe({ next: async (e) => { if (e.type == RuntimeEventTypes.ActionExecutionArgs) { await pushArgumentsChunk(e.args); argumentChunks.push(e.args); } }, error: (err) => { logger.error({ err }, "Error in action execution argument stream"); streamingArgumentsStatus.next(plainToInstance(FailedMessageStatus, { reason: "An unknown error has occurred in the action execution argument stream" })); stopStreamingArguments(); actionExecutionArgumentSubscription?.unsubscribe(); }, complete: () => { logger.debug("Action execution argument stream completed"); streamingArgumentsStatus.next(new SuccessMessageStatus()); stopStreamingArguments(); actionExecutionArgumentSubscription?.unsubscribe(); outputMessages.push(plainToInstance(ActionExecutionMessage, { id: event.actionExecutionId, createdAt: /* @__PURE__ */ new Date(), name: event.actionName, arguments: argumentChunks.join("") })); } }); }) }); break; case RuntimeEventTypes.ActionExecutionResult: logger.debug({ result: event.result }, "Action execution result event received"); pushMessage({ id: "result-" + event.actionExecutionId, status: new SuccessMessageStatus(), createdAt: /* @__PURE__ */ new Date(), actionExecutionId: event.actionExecutionId, actionName: event.actionName, result: event.result }); outputMessages.push(plainToInstance(ResultMessage, { id: "result-" + event.actionExecutionId, createdAt: /* @__PURE__ */ new Date(), actionExecutionId: event.actionExecutionId, actionName: event.actionName, result: event.result })); break; case RuntimeEventTypes.AgentStateMessage: logger.debug({ event }, "Agent message event received"); pushMessage({ id: randomId(), status: new SuccessMessageStatus(), threadId: event.threadId, agentName: event.agentName, nodeName: event.nodeName, runId: event.runId, active: event.active, state: event.state, running: event.running, role: MessageRole.assistant, createdAt: /* @__PURE__ */ new Date() }); outputMessages.push(plainToInstance(AgentStateMessage, { id: randomId(), threadId: event.threadId, agentName: event.agentName, nodeName: event.nodeName, runId: event.runId, active: event.active, state: event.state, running: event.running, role: MessageRole.assistant, createdAt: /* @__PURE__ */ new Date() })); break; } }, error: (err) => { if (err instanceof CopilotKitError || err instanceof CopilotKitLowLevelError || err instanceof Error && err.name && err.name.includes("CopilotKit") || err?.extensions?.visibility) { responseStatus$.next(new UnknownErrorResponse({ description: err.message || "Agent error occurred", originalError: { code: err.code || err.extensions?.code, statusCode: err.statusCode || err.extensions?.statusCode, severity: err.severity || err.extensions?.severity, visibility: err.visibility || err.extensions?.visibility, originalErrorType: err.originalErrorType || err.extensions?.originalErrorType, extensions: err.extensions } })); eventStreamSubscription?.unsubscribe(); rejectOutputMessagesPromise(err); stopStreamingMessages(); return; } responseStatus$.next(new UnknownErrorResponse({ description: `An unknown error has occurred in the event stream` })); eventStreamSubscription?.unsubscribe(); stopStreamingMessages(); rejectOutputMessagesPromise(err); }, complete: async () => { logger.debug("Event stream completed"); if (data.cloud?.guardrails) { logger.debug("Guardrails is enabled, waiting for guardrails result"); await firstValueFrom(guardrailsResult$); } responseStatus$.next(new SuccessResponseStatus()); eventStreamSubscription?.unsubscribe(); stopStreamingMessages(); resolveOutputMessagesPromise(outputMessages); } }); }) }; } }; __decorate([ Query(() => String), __decorateMetadata("design:type", Function), __decorateMetadata("design:paramtypes", []), __decorateMetadata("design:returntype", Promise) ], CopilotResolver.prototype, "hello", null); __decorate([ Query(() => AgentsResponse), __decorateParam(0, Ctx()), __decorateMetadata("design:type", Function), __decorateMetadata("design:paramtypes", [Object]), __decorateMetadata("design:returntype", Promise) ], CopilotResolver.prototype, "availableAgents", null); __decorate([ Mutation(() => CopilotResponse), __decorateParam(0, Ctx()), __decorateParam(1, Arg("data")), __decorateParam(2, Arg("properties", () => GraphQLJSONObject, { nullable: true })), __decorateMetadata("design:type", Function), __decorateMetadata("design:paramtypes", [ Object, typeof (_ref = typeof GenerateCopilotResponseInput !== "undefined" && GenerateCopilotResponseInput) === "function" ? _ref : Object, Object ]), __decorateMetadata("design:returntype", Promise) ], CopilotResolver.prototype, "generateCopilotResponse", null); CopilotResolver = __decorate([Resolver(() => CopilotResponse)], CopilotResolver); //#endregion export { CopilotResolver }; //# sourceMappingURL=copilot.resolver.mjs.map