From e97f47695c8ca238cd8c6daf13c691bca48dd0d0 Mon Sep 17 00:00:00 2001 From: elf-mouse Date: Tue, 4 Aug 2026 22:30:55 -0700 Subject: [PATCH] fix(admin): resolve custom provider routes under subpath and load catalog on onboarding This commit fixes routing, dependency wiring, and frontend catalog rendering issues for Custom Providers in the Admin plugin: 1. `plugins/admin/src/index.ts`: - Strip `ADMIN_BASE_PATH` (e.g. `/admin`) at request entry so `/admin/api/custom-providers` routes correctly without throwing 404 `not_found`. 2. `src/index.ts`: - Pass `customProviders` and `refreshCustomProviders` into `createServer()` options so `ctx.deps.customProviders` is properly initialized in Core handlers. 3. `plugins/admin/public/index.html`: - Invoke `await loadCustomProviders()` inside `loadOnboarding()` to automatically populate saved custom providers on page refresh and menu navigation. - Improve status error reporting to display `saved.data?.error` when `message` is omitted. --- plugins/admin/public/index.html | 8 +++++++- plugins/admin/src/index.ts | 5 ++++- src/index.ts | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/admin/public/index.html b/plugins/admin/public/index.html index e7c0367b..87e05a91 100644 --- a/plugins/admin/public/index.html +++ b/plugins/admin/public/index.html @@ -7087,6 +7087,7 @@

Confirm governance change

$("onboarding-oauth-summary").textContent = configured.length ? configured.map((item) => connectorName(item.provider)).join(", ") + " available in the web UI." : "Add Google, GitHub, Notion, or other OAuth clients to make those connectors available."; + await loadCustomProviders(); viewLoadedAt.onboarding = Date.now(); } $("onboarding-model-provider").onchange = () => renderOnboardingModelOptions(); @@ -7228,7 +7229,12 @@

Confirm governance change

const saved = await api("PUT", "/api/custom-providers/" + encodeURIComponent(id), body); $("custom-provider-save").disabled = false; if (!saved.ok) { - setStatus("st-custom-provider", saved.data?.message || "Could not save this provider.", "err", true); + setStatus( + "st-custom-provider", + saved.data?.message || (saved.data?.error ? "Error: " + saved.data.error : "Could not save this provider."), + "err", + true, + ); return; } $("custom-provider-key").value = ""; diff --git a/plugins/admin/src/index.ts b/plugins/admin/src/index.ts index 25106783..e71bf689 100644 --- a/plugins/admin/src/index.ts +++ b/plugins/admin/src/index.ts @@ -313,7 +313,10 @@ async function handle(req: IncomingMessage, res: ServerResponse): Promise res.setHeader("x-frame-options", "DENY"); res.setHeader("content-security-policy", ADMIN_CSP); const url = new URL(req.url ?? "/", "http://localhost"); - const { pathname } = url; + let pathname = url.pathname; + if (ADMIN_BASE_PATH && (pathname === ADMIN_BASE_PATH || pathname.startsWith(ADMIN_BASE_PATH + "/"))) { + pathname = pathname.slice(ADMIN_BASE_PATH.length) || "/"; + } const method = req.method ?? "GET"; const serveShell = async (): Promise => { diff --git a/src/index.ts b/src/index.ts index fbd390c3..c3188894 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,6 +33,8 @@ const server = createServer(built.app, { modelProviders: modelProviderAvailabilityFor(config.harness, providerKeysPresent(config)), providerKeys: providerKeysPresent(config), modelCredentials: built.modelCredentials, + customProviders: built.customProviders, + refreshCustomProviders: built.refreshCustomProviders, ...(config.brandingDefault ? { brandingDefault: config.brandingDefault } : {}), harnessId: config.harness, connectorTokens: built.connectorTokens,