feat: wire paseo agent provider catalog

This commit is contained in:
Mohamed Boudra
2026-07-02 11:07:49 +02:00
parent fce3d14a83
commit 4e5737169f
20 changed files with 1226 additions and 83 deletions

View File

@@ -6,6 +6,7 @@ import { createLoginCommand } from "./index.js";
interface RecordedLogin {
mode: "browser" | "device";
providerInstance?: string;
baseUrl?: string;
envHome?: string | undefined;
}
@@ -60,12 +61,12 @@ describe("paseo login command", () => {
serverId: "test-daemon",
features: { paseoAgentConfig: true },
}),
storePaseoAgentChatGptCredential: async (input) => {
storePaseoAgentOAuthCredential: async (input) => {
stored.push(input);
return {
requestId: "request-1",
success: true,
providerName: input.providerName,
name: input.name,
auth: { kind: "oauth", configured: true, source: "stored" },
error: null,
};
@@ -83,7 +84,7 @@ describe("paseo login command", () => {
expect(recorded).toEqual([{ mode: "browser" }]);
expect(stored).toEqual([
{
providerName: "chatgpt",
name: "chatgpt",
credential: {
type: "oauth",
access: "access-token",
@@ -121,6 +122,7 @@ describe("paseo login command", () => {
loginDeviceCode: async (options) => {
recorded.push({
providerInstance: options.providerInstance,
baseUrl: options.baseUrl,
envHome: options.env?.PASEO_HOME,
mode: "device",
});
@@ -144,7 +146,12 @@ describe("paseo login command", () => {
]);
expect(recorded).toEqual([
{ providerInstance: "chatgpt", envHome: "/tmp/paseo-home", mode: "device" },
{
providerInstance: "chatgpt",
baseUrl: "https://chatgpt.com/backend-api",
envHome: "/tmp/paseo-home",
mode: "device",
},
]);
expect(output.join("\n")).toContain("headless device-code flow");
expect(output.join("\n")).toContain("ABCD-EFGH");
@@ -211,7 +218,7 @@ describe("paseo login command", () => {
serverId: "test-daemon",
features: {},
}),
storePaseoAgentChatGptCredential: async (input) => {
storePaseoAgentOAuthCredential: async (input) => {
stored.push(input);
throw new Error("store RPC should not be called without the capability flag");
},
@@ -252,10 +259,10 @@ describe("paseo login command", () => {
serverId: "test-daemon",
features: { paseoAgentConfig: true },
}),
storePaseoAgentChatGptCredential: async (input) => ({
storePaseoAgentOAuthCredential: async (input) => ({
requestId: "request-1",
success: true,
providerName: input.providerName,
name: input.name,
auth: { kind: "oauth", configured: true, source: "stored" },
error: null,
}),

View File

@@ -22,6 +22,7 @@ import {
const PROVIDER_INSTANCE = "chatgpt";
const OAUTH_FLOW = "openai-codex";
const OAUTH_BASE_URL = "https://chatgpt.com/backend-api";
interface LoginChatgptOptions extends CommandOptions {
deviceCode?: boolean;
@@ -41,7 +42,7 @@ interface LoginCommandDependencies {
connectDaemon: (options: {
host?: string;
}) => Promise<
Pick<DaemonClient, "getLastServerInfoMessage" | "storePaseoAgentChatGptCredential" | "close">
Pick<DaemonClient, "getLastServerInfoMessage" | "storePaseoAgentOAuthCredential" | "close">
>;
openBrowser: (url: string) => boolean;
promptForCode: (message: string) => Promise<string>;
@@ -139,6 +140,7 @@ async function runChatgptLogin(
write("Paseo login — ChatGPT/Codex subscription (headless device-code flow)\n");
const { path } = await dependencies.loginDeviceCode({
flow: OAUTH_FLOW,
baseUrl: OAUTH_BASE_URL,
providerInstance: PROVIDER_INSTANCE,
env,
onDeviceCode: (info) => printDeviceCode(write, info),
@@ -176,8 +178,8 @@ async function runChatgptLogin(
onProgress: (message) => write(message),
promptForCode: dependencies.promptForCode,
});
const result = await client.storePaseoAgentChatGptCredential({
providerName: PROVIDER_INSTANCE,
const result = await client.storePaseoAgentOAuthCredential({
name: PROVIDER_INSTANCE,
credential,
});
if (!result.success || result.error) {

View File

@@ -101,7 +101,7 @@ function toConfiguredItem(provider: RedactedPaseoAgentProviderConfig): OpenRoute
return {
name: provider.name,
providerType: provider.providerType,
auth: provider.auth.configured ? (provider.auth.source ?? "configured") : "not configured",
auth: provider.auth?.configured ? (provider.auth.source ?? "configured") : "not configured",
available: provider.available ? "yes" : "no",
models: provider.models.map((model) => model.id).join(", "),
};