Verify native Pi OpenRouter accounts without the Legacy CLI

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-21 16:03:28 -05:00
1 parent 8104d32a06
commit 7d5fd0f139
2 files changed
+25 -1

No files matched your search

@@ -100,6 +100,27 @@ describe("managed AI connections", () => {
await expect(prepareManagedAiRuntime(db, { ...piInput, config: { ...piInput.config, env: { PAPERCLIP_PI_PROVIDERS: "{}" } } })).rejects.toThrow("routing is incompatible");
});
it.each([200, 401])("reverifies native Pi OpenRouter keys without requiring the Legacy Pi CLI (HTTP %s)", async status => {
const owner = `pi-adoption-${status}`;
await db.insert(companyMemberships).values({ companyId, principalId: owner, principalType: "user", status: "active", membershipRole: "member" });
const token = `fixture-pi-adoption-${status}`;
const account = await service.save(companyId, owner, { provider: "openrouter", method: "api_key", ownership: "personal", name: owner, apiKey: token, allAgents: true, agentIds: [], routing: { kind: "openrouter", protocol: "chat", auth: "bearer", models: [] } }, token);
const selected = { provider: "openrouter", method: "api_key", mode: "delegated", ...account } as const;
const runtime = await prepareManagedAiRuntime(db, { companyId, agentId, responsibleUserId: owner, adapterType: "paperclip_runner", binding: selected, config: { provider: "acpx", acpxAgent: "pi", model: "openrouter/anthropic/claude-sonnet-4.5" } });
const { requireServerAdapter } = await import("../adapters/index.js");
const { agentEnvironmentTestService } = await import("../services/agent-environment-test.js");
const native = vi.spyOn(requireServerAdapter("paperclip_runner"), "testEnvironment").mockResolvedValue({ adapterType: "paperclip_runner", status: "pass", testedAt: new Date().toISOString(), checks: [{ code: "acpx_runtime_ready", level: "info", message: "Pinned Pi runtime verified" }] });
const legacy = vi.spyOn(requireServerAdapter("pi_local"), "testEnvironment").mockRejectedValue(new Error("Legacy Pi CLI must not be required"));
const request = vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify({ data: {} }), { status }));
try {
const result = await agentEnvironmentTestService(db).testManagedEnvironment("paperclip_runner", { companyId, adapterType: "paperclip_runner", config: runtime.config }, selected, runtime, agentId);
expect(result.status).toBe(status === 200 ? "pass" : "fail");
expect(result.checks).toContainEqual(expect.objectContaining({ code: status === 200 ? "ai_connection_api_key_reverified" : "ai_connection_api_key_rejected" }));
expect(legacy).not.toHaveBeenCalled();
expect(request).toHaveBeenCalled();
} finally { native.mockRestore(); legacy.mockRestore(); request.mockRestore(); await runtime.cleanup(); }
});
it("defers a new plugin agent's Copilot check until its saved-agent lifecycle can acquire the computer", async () => {
const { errorHandler } = await import("../middleware/index.js");
const owner = "copilot-plugin-bootstrap", pluginId = randomUUID();
@@ -548,7 +548,10 @@ export function agentEnvironmentTestService(db: Db, pluginWorkerManager?: Plugin
// requirement stays for subscriptions: a stored login is a file layout
// only a provider CLI reads, so proving the runtime lane can consume it
// takes a real hello turn.
if (resolvedMethod === "api_key" && !context.config.managedAiRouting) {
const nativePiOpenRouter = adapterType === "paperclip_runner" && context.config.provider === "acpx"
&& context.config.acpxAgent === "pi" && binding.provider === "openrouter"
&& asRecord(context.config.managedAiRouting)?.kind === "openrouter";
if (resolvedMethod === "api_key" && (!context.config.managedAiRouting || nativePiOpenRouter)) {
const envKey = AI_CONNECTION_CAPABILITIES[binding.provider].methods.api_key?.envKey;
const key = envKey ? parseObject(context.config.env)[envKey] : undefined;
try {