@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;" />
91 lines (90 loc) • 4.55 kB
JavaScript
import "reflect-metadata";
//#region src/v2/runtime/core/channel-activation-config.ts
/**
* Error thrown when a Channel activation config cannot be derived — either the
* Intelligence API key does not carry a project id in the expected
* `cpk-{projectId}_...` format, or the {@link Channel} is missing a `name`.
*/
var ChannelConfigError = class extends Error {
constructor(message) {
super(message);
this.name = "ChannelConfigError";
}
};
/** Matches the `cpk-{projectId}_...` Intelligence API key format. */
const API_KEY_PROJECT_ID_PATTERN = /^cpk-(\d+)_/;
/**
* Parse the project id embedded in an Intelligence API key.
*
* Intelligence API keys are formatted `cpk-{projectId}_{rest}` — this
* extracts and numerically parses the `{projectId}` segment.
*
* @param apiKey - The Intelligence API key to parse.
* @returns The parsed, strictly-positive, safe-integer project id.
* @throws {ChannelConfigError} If `apiKey` does not match the expected
* `cpk-{projectId}_...` format — a wrong/missing prefix or an absent project
* id segment all fail the same match — or if the parsed project id is not a
* strictly-positive safe integer.
*/
function parseProjectIdFromApiKey(apiKey) {
const match = API_KEY_PROJECT_ID_PATTERN.exec(apiKey);
if (!match) throw new ChannelConfigError("Could not parse a project id from the Intelligence API key — expected the \"cpk-{projectId}_...\" format (the key value is omitted here to avoid leaking secret material).");
const projectId = Number(match[1]);
if (!Number.isSafeInteger(projectId) || projectId <= 0) throw new ChannelConfigError(`Parsed an invalid project id (${projectId}) from the Intelligence API key — the project id in "cpk-{projectId}_..." must be a positive safe integer (the key value is omitted here to avoid leaking secret material).`);
return projectId;
}
/**
* Derive the {@link ChannelActivationConfig} needed to activate `channel`
* against the given Intelligence runtime configuration.
*
* @param args.intelligence - The Intelligence runtime client to pull the
* runner websocket URL and auth token from.
* @param args.channel - The Channel being activated. Must have a `name`; its
* per-Channel `provider` selects the managed adapter declared to the gateway.
* @param args.runtimeInstanceId - Identifier for the activating runtime
* instance, passed through unchanged.
* @returns The resolved {@link ChannelActivationConfig}.
* @throws {ChannelConfigError} If the Intelligence API key does not carry a
* parseable, strictly-positive project id, or if `channel.name` is
* missing/empty.
*
* The managed provider is a PER-CHANNEL choice read from `channel.provider`, so
* one runtime can activate a Slack-backed Channel and a Teams-backed Channel
* side by side. When `channel.provider` is unset the config adapter defaults to
* `"slack"` — an explicit, documented default, not a silent global. The SDK
* only DECLARES this provider to the Intelligence gateway on join; the gateway
* resolves the actual connection and is the authority on which providers it
* accepts (it accepts only `"slack"` today — Teams gateway support is tracked
* in OSS-450).
*
* The Channel-name FORMAT rules (lowercase kebab-case, 3–64 chars) and the
* reserved-name rule are NOT re-checked here. Their single source of truth is
* the `@copilotkit/channels-intelligence` launcher
* (`assertValidChannelRealtimeScope` + `assertValidChannelNames`), which
* validates them at activation; a malformed name surfaces as a logged `error`
* status via {@link ChannelManager.ready} rather than an up-front throw. An
* empty/missing name is still rejected here because that is this config's own
* precondition (it has no name to forward at all), not a downstream replica.
*/
function deriveChannelActivationConfig(args) {
const { intelligence, channel, runtimeInstanceId } = args;
if (!channel.name) throw new ChannelConfigError("Channel is missing a `name` — pass createChannel({ name }) to activate it.");
const channelName = channel.name;
const wsUrl = intelligence.ɵgetRunnerWsUrl();
const apiUrl = intelligence.ɵgetApiUrl();
const apiKey = intelligence.ɵgetRunnerAuthToken();
const projectId = parseProjectIdFromApiKey(apiKey);
const trimmedProvider = channel.provider?.trim();
return {
wsUrl,
apiUrl,
apiKey,
projectId,
channelName,
adapter: trimmedProvider ? trimmedProvider : "slack",
runtimeInstanceId
};
}
//#endregion
export { ChannelConfigError, deriveChannelActivationConfig };
//# sourceMappingURL=channel-activation-config.mjs.map