Skip to content

Commit bc3af1f

Browse files
committed
fix(config): accept the Intelligence runtime key written by the CLI
1 parent 2fbeb1b commit bc3af1f

12 files changed

Lines changed: 91 additions & 32 deletions

‎.env.example‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,13 @@ INTELLIGENCE_GATEWAY_WS_URL=wss://realtime.intelligence.copilotkit.ai
129129
#
130130
# npx --yes copilotkit@latest login # browser sign-in
131131
# npx --yes copilotkit@latest project select # writes the cpk-... key to .env as CPK_INTELLIGENCE_API_KEY
132-
# bun scripts/setup-learning.ts # copies it here, as INTELLIGENCE_API_KEY
132+
# bun scripts/setup-learning.ts # ensures the Learning container exists
133133
#
134-
# The server reads only INTELLIGENCE_API_KEY, so a key left as CPK_INTELLIGENCE_API_KEY is not seen.
134+
# OpenBot reads CPK_INTELLIGENCE_API_KEY directly. INTELLIGENCE_API_KEY is a legacy fallback.
135+
# When both are set, the non-empty CPK_INTELLIGENCE_API_KEY takes precedence.
135136
#
136137
# The runtime key is also under "API Keys" in your project at https://intelligence.copilotkit.ai
137-
INTELLIGENCE_API_KEY=
138+
CPK_INTELLIGENCE_API_KEY=
138139

139140
# Optional, and blank on purpose. Managed Intelligence derives entitlement from the project key
140141
# above and issues no licence token. A self-hosted Intelligence with its own licence sets this and

‎README.md‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,10 @@ not a production installation. Run its
138138
`npx copilotkit@latest local connect` from the OpenBot root, where `.env` is.
139139

140140
That command writes `INTELLIGENCE_API_URL`, `INTELLIGENCE_GATEWAY_WS_URL` and
141-
`CPK_INTELLIGENCE_API_KEY` to `.env`. OpenBot reads the first two as they are, but takes its project
142-
key only from `INTELLIGENCE_API_KEY` and refuses to start without it, so copy the `cpk-...` value
143-
across before `bash scripts/start.sh`:
144-
145-
```sh
146-
INTELLIGENCE_API_KEY=cpk-... # the value of CPK_INTELLIGENCE_API_KEY
147-
```
141+
`CPK_INTELLIGENCE_API_KEY` to `.env`. OpenBot reads those settings directly; no key
142+
copying or renaming is needed. `INTELLIGENCE_API_KEY` remains supported for older
143+
configurations. When both are set, the non-empty CLI key takes precedence so
144+
reconnecting uses the new project's key.
148145

149146
To give the Bots a Learning container on that stack, see
150147
[Automatic Learning](docs/automatic-learning.md).

‎docs/configuration.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ bash scripts/start.sh
2222
| `KEY_ENCRYPTION_KEY` | Base64-encoded 32-byte key for encrypted stored credentials. Generate with `openssl rand -base64 32`. |
2323
| `INTELLIGENCE_API_URL` | CopilotKit Intelligence API URL. |
2424
| `INTELLIGENCE_GATEWAY_WS_URL` | CopilotKit Intelligence realtime gateway URL. |
25-
| `INTELLIGENCE_API_KEY` | Runtime key for the Intelligence project. |
25+
| `CPK_INTELLIGENCE_API_KEY` | Runtime key written by the CopilotKit CLI. Preferred when non-empty. |
26+
| `INTELLIGENCE_API_KEY` | Legacy runtime key; used when `CPK_INTELLIGENCE_API_KEY` is empty or absent. |
2627

2728
All five above stop server startup if missing. The three `INTELLIGENCE_` values are additionally
2829
checked as a set, so a partial set is refused as a misconfiguration rather than treated as

‎prompt.txt‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ OpenBot root where `.env` is:
103103
npx copilotkit@latest local connect --approve-connection
104104

105105
`local connect` writes INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL and
106-
CPK_INTELLIGENCE_API_KEY to `.env`. OpenBot reads the first two as they are but takes its project
107-
key only from INTELLIGENCE_API_KEY, so copy the `cpk-...` value of CPK_INTELLIGENCE_API_KEY into
108-
INTELLIGENCE_API_KEY before `bash scripts/start.sh`. The local licence lasts 30 days;
106+
CPK_INTELLIGENCE_API_KEY to `.env`. OpenBot reads those values directly; do not copy or rename
107+
the key. INTELLIGENCE_API_KEY remains a legacy fallback when the CLI key is empty or absent.
108+
When both are set, the non-empty CLI key takes precedence. The local licence lasts 30 days;
109109
`npx copilotkit@latest local renew` renews it as often as needed while the account is in good
110110
standing. Skip the managed `project select` and setup-learning commands on this path.
111111

‎scripts/setup-learning.test.ts‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,27 @@ test("self-hosted setup failure or concurrent env edits do not save credentials"
601601
);
602602
});
603603

604-
test("a partial key provision cannot reuse a stale CLI key or create a container", async () => {
605-
const f = await fixture("CPK_INTELLIGENCE_API_KEY=cpk-old-project-key\n");
604+
test.each(["", "INTELLIGENCE_API_KEY=cpk-old-project-key\n"])(
605+
"a CLI key is used without reprovisioning or rewriting configuration: %s",
606+
async (legacy) => {
607+
const f = await fixture(`${legacy}CPK_INTELLIGENCE_API_KEY=cpk-cli-key\n`);
608+
const before = await readFile(f.envPath, "utf8");
609+
const view = keyView(["present"]);
610+
expect(
611+
await setupLearning({
612+
...f.options,
613+
runCli: f.runCli,
614+
keyIntelligence: view.keyIntelligence,
615+
}),
616+
).toBe("present");
617+
expect(view.keys).toEqual(["cpk-cli-key"]);
618+
expect(f.calls).toHaveLength(0);
619+
expect(await readFile(f.envPath, "utf8")).toBe(before);
620+
},
621+
);
622+
623+
test("a partial key provision does not create a container", async () => {
624+
const f = await fixture();
606625
const before = await readFile(f.envPath, "utf8");
607626
await expect(
608627
setupLearning({

‎scripts/setup-learning.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { readFile, rename, rm, writeFile } from "node:fs/promises";
22
import { resolve } from "node:path";
33
import { createInterface } from "node:readline/promises";
44
import { parseEnv } from "node:util";
5+
import { intelligenceApiKey } from "../shared/intelligence-key";
56
import {
67
cliLoginPresent,
78
containerMissing,
@@ -136,7 +137,10 @@ export async function setupLearning(
136137
const effective = (name: string) =>
137138
(environment[name] || values[name] || "").trim();
138139
if (effective(CONTAINER)) return "preserved";
139-
const existingKey = effective("INTELLIGENCE_API_KEY");
140+
const existingKey = intelligenceApiKey({
141+
CPK_INTELLIGENCE_API_KEY: effective("CPK_INTELLIGENCE_API_KEY"),
142+
INTELLIGENCE_API_KEY: effective("INTELLIGENCE_API_KEY"),
143+
});
140144
if (existingKey) {
141145
/*
142146
* The key cannot create containers, and it is never replaced here. Creation goes through a

‎scripts/start-restart-guard.test.ts‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,17 +351,20 @@ describe("start.sh Learning container check", () => {
351351
* The server assigns `openbot` once it exists, but its runtime key cannot create it. start.sh asks
352352
* the setup helper, without a browser or a prompt, to make sure it exists, and relays its last line.
353353
*/
354-
test("runs the non-interactive check when a key is set and nothing is assigned", async () => {
355-
const result = await runStartWithStaleServerProbe(401, {
356-
settings: { INTELLIGENCE_API_KEY: "cpk-synthetic" },
357-
});
354+
test.each(["INTELLIGENCE_API_KEY", "CPK_INTELLIGENCE_API_KEY"])(
355+
"runs the non-interactive check when %s is set",
356+
async (keyName) => {
357+
const result = await runStartWithStaleServerProbe(401, {
358+
settings: { [keyName]: "cpk-synthetic" },
359+
});
358360

359-
expect(result.exitCode).toBe(0);
360-
expect(result.stdout).toContain(
361-
"LEARNING-CHECK scripts/setup-learning.ts --non-interactive",
362-
);
363-
expect(result.stdout).not.toContain("noise");
364-
});
361+
expect(result.exitCode).toBe(0);
362+
expect(result.stdout).toContain(
363+
"LEARNING-CHECK scripts/setup-learning.ts --non-interactive",
364+
);
365+
expect(result.stdout).not.toContain("noise");
366+
},
367+
);
365368

366369
test.each([
367370
[

‎scripts/start.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ green " managed coworker endpoint: $MANAGED_AGENT_AG_UI_URL"
300300
LEARNING_CONTAINER="$(setting CPK_INTELLIGENCE_LEARNING_CONTAINER_ID "")"
301301
LEARNING_AUTO_ASSIGN="$(setting OPENBOT_LEARNING_AUTO_ASSIGN true)"
302302
if [ -z "$LEARNING_CONTAINER" ] && [ "$LEARNING_AUTO_ASSIGN" != "false" ] \
303-
&& [ "$LEARNING_AUTO_ASSIGN" != "0" ] && [ -n "$(setting INTELLIGENCE_API_KEY "")" ]; then
303+
&& [ "$LEARNING_AUTO_ASSIGN" != "0" ] && { [ -n "$(setting CPK_INTELLIGENCE_API_KEY "")" ] || [ -n "$(setting INTELLIGENCE_API_KEY "")" ]; }; then
304304
LEARNING_LINE="$(bun scripts/setup-learning.ts --non-interactive 2>>"$LOGS/learning-setup.log" | tail -1 || true)"
305305
info " ${LEARNING_LINE:-Automatic Learning: the container check did not run. Log: $LOGS/learning-setup.log}"
306306
fi
@@ -413,7 +413,7 @@ const status = info.licenseStatus;
413413
const agents = Object.keys(info.agents ?? {});
414414
if (status !== "valid") {
415415
console.log(`\x1b[31m licence is '${status}', not 'valid'.\x1b[0m`);
416-
console.log("\x1b[31m Check INTELLIGENCE_API_KEY: npx copilotkit@latest login && npx copilotkit@latest project select\x1b[0m");
416+
console.log("\x1b[31m Check CPK_INTELLIGENCE_API_KEY (or INTELLIGENCE_API_KEY): npx copilotkit@latest login && npx copilotkit@latest project select\x1b[0m");
417417
console.log("\x1b[31m See README.md for Intelligence setup.\x1b[0m");
418418
process.exit(1);
419419
}

‎server/src/config.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* for durable threads and memory. Configuration the product cannot function without belongs at the
44
* boot boundary.
55
*/
6+
import { intelligenceApiKey } from "@openbot/shared/intelligence-key";
67
import {
78
isLearningContainerId,
89
type LearningTarget,
@@ -950,7 +951,7 @@ function runtimeCapabilities(environment: Environment): RuntimeCapabilities {
950951
const settings = {
951952
apiUrl: url(environment, "INTELLIGENCE_API_URL"),
952953
gatewayWsUrl: url(environment, "INTELLIGENCE_GATEWAY_WS_URL"),
953-
apiKey: optional(environment, "INTELLIGENCE_API_KEY"),
954+
apiKey: intelligenceApiKey(environment),
954955
licenseToken: optional(environment, "COPILOTKIT_LICENSE_TOKEN"),
955956
};
956957

‎server/src/learning/ensure-container.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* Shared by `scripts/setup-learning.ts` (run by `scripts/start.sh`), the server (at boot and from
2222
* Admin → Automatic Learning), and the Helm chart's setup Job, which runs this file directly.
2323
*/
24+
import { intelligenceApiKey } from "@openbot/shared/intelligence-key";
2425
import { spawn } from "node:child_process";
2526
import { existsSync } from "node:fs";
2627
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
@@ -536,8 +537,11 @@ export async function ensureLearningContainer(input: {
536537
async function jobMain() {
537538
const environment = process.env;
538539
const apiUrl = intelligenceApiOrigin(environment.INTELLIGENCE_API_URL ?? "");
539-
const apiKey = environment.INTELLIGENCE_API_KEY?.trim();
540-
if (!apiKey) throw new Error("INTELLIGENCE_API_KEY is required.");
540+
const apiKey = intelligenceApiKey(environment);
541+
if (!apiKey)
542+
throw new Error(
543+
"CPK_INTELLIGENCE_API_KEY (or INTELLIGENCE_API_KEY) is required.",
544+
);
541545
const token = environment.INTELLIGENCE_SERVICE_TOKEN?.trim();
542546
const projectId = environment.INTELLIGENCE_PROJECT_ID?.trim();
543547
if (Boolean(token) !== Boolean(projectId))

0 commit comments

Comments
 (0)