@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
JavaScript
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