diff --git a/assistant/openapi.yaml b/assistant/openapi.yaml index b70c3b0ae4a..d709a77b487 100644 --- a/assistant/openapi.yaml +++ b/assistant/openapi.yaml @@ -13702,6 +13702,44 @@ paths: required: - sourceText additionalProperties: false + /v1/skills/import: + post: + operationId: skills_import_post + summary: Import skill from file + description: Import a custom skill by uploading a ZIP or tar.gz archive containing a SKILL.md file. + tags: + - skills + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + skillId: + type: string + required: + - ok + - skillId + additionalProperties: false + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + fileName: + type: string + fileContent: + type: string + required: + - fileName + - fileContent + additionalProperties: false /v1/skills/install: post: operationId: skills_install_post diff --git a/assistant/scripts/sync-llm-catalog.ts b/assistant/scripts/sync-llm-catalog.ts index a4c89a82c54..ba73ae1fe6e 100644 --- a/assistant/scripts/sync-llm-catalog.ts +++ b/assistant/scripts/sync-llm-catalog.ts @@ -97,8 +97,8 @@ function projectProvider(entry: ProviderCatalogEntry): Record { projected.apiKeyPlaceholder = entry.apiKeyPlaceholder; if (entry.credentialsGuide !== undefined) projected.credentialsGuide = entry.credentialsGuide; - if (entry.supportsManagedAuth !== undefined) - projected.supportsManagedAuth = entry.supportsManagedAuth; + if (entry.supportsPlatformAuth !== undefined) + projected.supportsPlatformAuth = entry.supportsPlatformAuth; projected.defaultModel = entry.defaultModel; projected.models = entry.models.map(projectModel); // NOTE: `apiKeyUrl` intentionally omitted — clients use diff --git a/assistant/src/__tests__/credential-security-invariants.test.ts b/assistant/src/__tests__/credential-security-invariants.test.ts index c2fc34ec635..db7e15c268f 100644 --- a/assistant/src/__tests__/credential-security-invariants.test.ts +++ b/assistant/src/__tests__/credential-security-invariants.test.ts @@ -189,7 +189,7 @@ describe("Invariant 2: no generic plaintext secret read API", () => { "messaging/providers/slack/adapter.ts", // Slack bot token lookup for Socket Mode connectivity check "credential-health/credential-health-service.ts", // proactive credential health monitoring "daemon/handlers/config-slack-channel.ts", // Slack channel config credential management - "providers/managed-proxy/context.ts", // managed proxy API key lookup for provider initialization + "providers/platform-proxy/context.ts", // managed proxy API key lookup for provider initialization "platform/client.ts", // platform client credential store fallback for standalone CLI auth "mcp/mcp-oauth-provider.ts", // MCP OAuth token/client/discovery persistence "runtime/routes/integrations/slack/token.ts", // shared Slack token resolver (bot/user token lookup for CLI use routes) diff --git a/assistant/src/__tests__/image-credentials.test.ts b/assistant/src/__tests__/image-credentials.test.ts index e72ab7e128c..97837742243 100644 --- a/assistant/src/__tests__/image-credentials.test.ts +++ b/assistant/src/__tests__/image-credentials.test.ts @@ -12,7 +12,7 @@ mock.module("../security/secure-keys.js", () => ({ getProviderKeyAsync: async (_provider: string) => mockProviderKey, })); -mock.module("../providers/managed-proxy/context.js", () => ({ +mock.module("../providers/platform-proxy/context.js", () => ({ resolveManagedProxyContext: async () => ({ enabled: !!mockPlatformBaseUrl && !!mockAssistantApiKey, platformBaseUrl: mockPlatformBaseUrl, diff --git a/assistant/src/__tests__/inference-no-mode-boot-e2e.test.ts b/assistant/src/__tests__/inference-no-mode-boot-e2e.test.ts index ebffd2bec30..9ceb3521083 100644 --- a/assistant/src/__tests__/inference-no-mode-boot-e2e.test.ts +++ b/assistant/src/__tests__/inference-no-mode-boot-e2e.test.ts @@ -35,7 +35,7 @@ mock.module("../security/secure-keys.js", () => ({ })); // Managed proxy context — always unavailable in this test (no platform auth). -mock.module("../providers/managed-proxy/context.js", () => ({ +mock.module("../providers/platform-proxy/context.js", () => ({ buildManagedBaseUrl: async () => null, resolveManagedProxyContext: async () => { throw new Error("managed proxy not available in test"); diff --git a/assistant/src/__tests__/llm-catalog-parity.test.ts b/assistant/src/__tests__/llm-catalog-parity.test.ts index 270f132d756..3c0c04c58ee 100644 --- a/assistant/src/__tests__/llm-catalog-parity.test.ts +++ b/assistant/src/__tests__/llm-catalog-parity.test.ts @@ -2,8 +2,8 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, test } from "bun:test"; -import { MANAGED_PROVIDER_META } from "../providers/managed-proxy/constants.js"; import { PROVIDER_CATALOG } from "../providers/model-catalog.js"; +import { PLATFORM_PROVIDER_META } from "../providers/platform-proxy/constants.js"; import { resolvePricing, resolvePricingForUsage } from "../util/pricing.js"; /** @@ -84,7 +84,7 @@ interface ClientCatalogEntry { envVar?: string; apiKeyPlaceholder?: string; credentialsGuide?: ClientCatalogCredentialsGuide; - supportsManagedAuth?: boolean; + supportsPlatformAuth?: boolean; defaultModel: string; models: ClientCatalogModel[]; } @@ -136,8 +136,8 @@ describe("LLM catalog parity: daemon vs client", () => { expect(clientEntry.setupHint).toBe(daemonEntry.setupHint); expect(clientEntry.envVar).toBe(daemonEntry.envVar); expect(clientEntry.apiKeyPlaceholder).toBe(daemonEntry.apiKeyPlaceholder); - expect(clientEntry.supportsManagedAuth).toBe( - daemonEntry.supportsManagedAuth, + expect(clientEntry.supportsPlatformAuth).toBe( + daemonEntry.supportsPlatformAuth, ); expect(clientEntry.credentialsGuide).toEqual( daemonEntry.credentialsGuide, @@ -146,16 +146,16 @@ describe("LLM catalog parity: daemon vs client", () => { } }); - test("supportsManagedAuth mirrors MANAGED_PROVIDER_META", () => { - // The catalog field is derived from MANAGED_PROVIDER_META at build + test("supportsPlatformAuth mirrors PLATFORM_PROVIDER_META", () => { + // The catalog field is derived from PLATFORM_PROVIDER_META at build // time. This test guards against future hand-edits to model-catalog.ts - // that would let the two drift. Adding a provider to MANAGED_PROVIDER_META + // that would let the two drift. Adding a provider to PLATFORM_PROVIDER_META // must auto-propagate; flipping `managed: true` to `false` (or vice // versa) must propagate too. for (const entry of PROVIDER_CATALOG) { const expectedSupportsManagedAuth = - MANAGED_PROVIDER_META[entry.id]?.managed === true; - expect(entry.supportsManagedAuth).toBe(expectedSupportsManagedAuth); + PLATFORM_PROVIDER_META[entry.id]?.managed === true; + expect(entry.supportsPlatformAuth).toBe(expectedSupportsManagedAuth); } }); diff --git a/assistant/src/__tests__/media-generate-image.test.ts b/assistant/src/__tests__/media-generate-image.test.ts index 2aab443791b..91da8f727c0 100644 --- a/assistant/src/__tests__/media-generate-image.test.ts +++ b/assistant/src/__tests__/media-generate-image.test.ts @@ -81,7 +81,7 @@ let mockManagedProxyContext = { assistantApiKey: "", }; -mock.module("../providers/managed-proxy/context.js", () => ({ +mock.module("../providers/platform-proxy/context.js", () => ({ buildManagedBaseUrl: async () => mockManagedBaseUrl, resolveManagedProxyContext: async () => mockManagedProxyContext, })); diff --git a/assistant/src/__tests__/managed-proxy-context.test.ts b/assistant/src/__tests__/platform-proxy-context.test.ts similarity index 99% rename from assistant/src/__tests__/managed-proxy-context.test.ts rename to assistant/src/__tests__/platform-proxy-context.test.ts index 6e7b5ed7ad9..171bce7eda3 100644 --- a/assistant/src/__tests__/managed-proxy-context.test.ts +++ b/assistant/src/__tests__/platform-proxy-context.test.ts @@ -32,7 +32,7 @@ import { hasManagedProxyPrereqs, managedFallbackEnabledFor, resolveManagedProxyContext, -} from "../providers/managed-proxy/context.js"; +} from "../providers/platform-proxy/context.js"; describe("resolveManagedProxyContext", () => { beforeEach(() => { diff --git a/assistant/src/__tests__/provider-managed-proxy-integration.test.ts b/assistant/src/__tests__/provider-platform-proxy-integration.test.ts similarity index 97% rename from assistant/src/__tests__/provider-managed-proxy-integration.test.ts rename to assistant/src/__tests__/provider-platform-proxy-integration.test.ts index ee282296ab4..eb1e6dd9aa2 100644 --- a/assistant/src/__tests__/provider-managed-proxy-integration.test.ts +++ b/assistant/src/__tests__/provider-platform-proxy-integration.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test"; -import { MANAGED_PROVIDER_META } from "../providers/managed-proxy/constants.js"; +import { PLATFORM_PROVIDER_META } from "../providers/platform-proxy/constants.js"; import { credentialKey } from "../security/credential-key.js"; // --------------------------------------------------------------------------- @@ -436,7 +436,7 @@ describe("managed proxy integration — ollama exclusion", () => { }); test("ollama metadata is marked as non-managed", () => { - const meta = MANAGED_PROVIDER_META.ollama; + const meta = PLATFORM_PROVIDER_META.ollama; expect(meta).toBeDefined(); expect(meta.managed).toBe(false); expect(meta.proxyPath).toBeUndefined(); @@ -478,7 +478,7 @@ describe("config mode flip → provider reinit", () => { describe("managed proxy integration — constants integrity", () => { test("anthropic, openai, and gemini have metadata with managed=true and a proxyPath", () => { for (const provider of ["anthropic", "openai", "gemini"]) { - const meta = MANAGED_PROVIDER_META[provider]; + const meta = PLATFORM_PROVIDER_META[provider]; expect(meta).toBeDefined(); expect(meta.managed).toBe(true); expect(meta.proxyPath).toBeTruthy(); @@ -487,27 +487,27 @@ describe("managed proxy integration — constants integrity", () => { }); test("anthropic routes through anthropic proxy path", () => { - expect(MANAGED_PROVIDER_META.anthropic.proxyPath).toBe( + expect(PLATFORM_PROVIDER_META.anthropic.proxyPath).toBe( "/v1/runtime-proxy/anthropic", ); }); test("gemini routes through gemini proxy path", () => { - expect(MANAGED_PROVIDER_META.gemini.proxyPath).toBe( + expect(PLATFORM_PROVIDER_META.gemini.proxyPath).toBe( "/v1/runtime-proxy/gemini", ); }); test("openai routes through openai proxy path", () => { - expect(MANAGED_PROVIDER_META.openai.proxyPath).toBe( + expect(PLATFORM_PROVIDER_META.openai.proxyPath).toBe( "/v1/runtime-proxy/openai", ); }); test("fireworks and openrouter are not managed proxy capable", () => { for (const provider of ["fireworks", "openrouter"]) { - expect(MANAGED_PROVIDER_META[provider].managed).toBe(false); - expect(MANAGED_PROVIDER_META[provider].proxyPath).toBeUndefined(); + expect(PLATFORM_PROVIDER_META[provider].managed).toBe(false); + expect(PLATFORM_PROVIDER_META[provider].proxyPath).toBeUndefined(); } }); }); diff --git a/assistant/src/__tests__/secret-routes-managed-proxy.test.ts b/assistant/src/__tests__/secret-routes-platform-proxy.test.ts similarity index 100% rename from assistant/src/__tests__/secret-routes-managed-proxy.test.ts rename to assistant/src/__tests__/secret-routes-platform-proxy.test.ts diff --git a/assistant/src/daemon/lifecycle.ts b/assistant/src/daemon/lifecycle.ts index 62f461e19ce..85ce4161085 100644 --- a/assistant/src/daemon/lifecycle.ts +++ b/assistant/src/daemon/lifecycle.ts @@ -59,7 +59,7 @@ import { loadUserPlugins } from "../plugins/user-loader.js"; import { backfillGuardIfNeeded } from "../proactive-artifact/index.js"; import { ensurePromptFiles } from "../prompts/system-prompt.js"; import { runProviderConnectionsBackfill } from "../providers/inference/backfill.js"; -import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js"; +import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js"; import { broadcastMessage } from "../runtime/assistant-event-hub.js"; import { initAuthSigningKey, diff --git a/assistant/src/media/image-credentials.ts b/assistant/src/media/image-credentials.ts index f5ac4e8cafd..526a9293416 100644 --- a/assistant/src/media/image-credentials.ts +++ b/assistant/src/media/image-credentials.ts @@ -8,8 +8,8 @@ * credentials are unavailable. */ -import { MANAGED_PROVIDER_META } from "../providers/managed-proxy/constants.js"; -import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js"; +import { PLATFORM_PROVIDER_META } from "../providers/platform-proxy/constants.js"; +import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js"; import { getProviderKeyAsync } from "../security/secure-keys.js"; import type { ImageGenCredentials, ImageGenProvider } from "./types.js"; @@ -33,7 +33,7 @@ export async function resolveImageGenCredentials(opts: { // Resolve platform URL + assistant API key from a single snapshot so // baseUrl and assistantApiKey can't diverge if the credential is cleared // between lookups. - const meta = MANAGED_PROVIDER_META[provider]; + const meta = PLATFORM_PROVIDER_META[provider]; const ctx = await resolveManagedProxyContext(); if ( !meta?.managed || diff --git a/assistant/src/memory/embedding-backend.ts b/assistant/src/memory/embedding-backend.ts index fd517dba125..7a126ed4864 100644 --- a/assistant/src/memory/embedding-backend.ts +++ b/assistant/src/memory/embedding-backend.ts @@ -4,8 +4,8 @@ import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags import { getOllamaBaseUrlEnv } from "../config/env.js"; import { resolveCallSiteConfig } from "../config/llm-resolver.js"; import type { AssistantConfig } from "../config/types.js"; -import { MANAGED_PROVIDER_META } from "../providers/managed-proxy/constants.js"; -import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js"; +import { PLATFORM_PROVIDER_META } from "../providers/platform-proxy/constants.js"; +import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js"; import { getProviderKeyAsync } from "../security/secure-keys.js"; import { getLogger } from "../util/logger.js"; import { GeminiEmbeddingBackend } from "./embedding-gemini.js"; @@ -311,7 +311,7 @@ export async function selectEmbeddingBackend( ) { const proxyCtx = await resolveManagedProxyContext(); if (proxyCtx.enabled) { - const meta = MANAGED_PROVIDER_META["gemini"]; + const meta = PLATFORM_PROVIDER_META["gemini"]; if (meta?.managed && meta.proxyPath) { const managedBaseUrl = `${proxyCtx.platformBaseUrl}${meta.proxyPath}`; const managedModel = config.memory.embeddings.geminiModel; @@ -685,7 +685,7 @@ async function selectFallbackBackends( ) { // Try managed proxy Gemini as fallback when no direct key exists. const proxyCtx = await resolveManagedProxyContext(); - const meta = MANAGED_PROVIDER_META["gemini"]; + const meta = PLATFORM_PROVIDER_META["gemini"]; if (proxyCtx.enabled && meta?.managed && meta.proxyPath) { const managedBaseUrl = `${proxyCtx.platformBaseUrl}${meta.proxyPath}`; const managedModel = config.memory.embeddings.geminiModel; diff --git a/assistant/src/platform/client.test.ts b/assistant/src/platform/client.test.ts index cc497d8da81..d418f64810c 100644 --- a/assistant/src/platform/client.test.ts +++ b/assistant/src/platform/client.test.ts @@ -15,7 +15,7 @@ let mockAssistantId = ""; // Module mocks // --------------------------------------------------------------------------- -mock.module("../providers/managed-proxy/context.js", () => ({ +mock.module("../providers/platform-proxy/context.js", () => ({ resolveManagedProxyContext: async () => mockManagedProxyCtx, })); diff --git a/assistant/src/platform/client.ts b/assistant/src/platform/client.ts index 55b8872aedc..bc6e91c7486 100644 --- a/assistant/src/platform/client.ts +++ b/assistant/src/platform/client.ts @@ -6,7 +6,7 @@ */ import { getPlatformAssistantId } from "../config/env.js"; -import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js"; +import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js"; import { credentialKey } from "../security/credential-key.js"; import { getSecureKeyAsync } from "../security/secure-keys.js"; import { getLogger } from "../util/logger.js"; diff --git a/assistant/src/providers/inference/resolve-auth.ts b/assistant/src/providers/inference/resolve-auth.ts index a3727e6460c..249942e2616 100644 --- a/assistant/src/providers/inference/resolve-auth.ts +++ b/assistant/src/providers/inference/resolve-auth.ts @@ -11,7 +11,7 @@ import { buildManagedBaseUrl, resolveManagedProxyContext, -} from "../../providers/managed-proxy/context.js"; +} from "../../providers/platform-proxy/context.js"; import { getSecureKeyAsync } from "../../security/secure-keys.js"; import type { Auth, ResolvedAuth } from "./auth.js"; diff --git a/assistant/src/providers/model-catalog.ts b/assistant/src/providers/model-catalog.ts index b842be8416e..e89a2b6b7e5 100644 --- a/assistant/src/providers/model-catalog.ts +++ b/assistant/src/providers/model-catalog.ts @@ -1,4 +1,4 @@ -import { MANAGED_PROVIDER_META } from "./managed-proxy/constants.js"; +import { PLATFORM_PROVIDER_META } from "./platform-proxy/constants.js"; export type LongContextMode = | "native-model" @@ -91,12 +91,12 @@ export interface ProviderCatalogEntry { /** * Whether this provider supports the `platform` auth type (Vellum-managed * keys routed through the platform proxy). Derived from - * `MANAGED_PROVIDER_META` at catalog build time so the two stay in lock + * `PLATFORM_PROVIDER_META` at catalog build time so the two stay in lock * step. Clients use this field to hide the "Platform (managed by Vellum)" * option from the auth-type dropdown for providers like Fireworks or * OpenRouter where managed keys are not available. */ - supportsManagedAuth?: boolean; + supportsPlatformAuth?: boolean; } /** @@ -874,11 +874,11 @@ export const PROVIDER_CATALOG: ProviderCatalogEntry[] = RAW_PROVIDER_CATALOG.map((entry) => ({ ...entry, models: entry.models.map(catalogModel), - // Derive supportsManagedAuth from MANAGED_PROVIDER_META so the catalog + // Derive supportsPlatformAuth from PLATFORM_PROVIDER_META so the catalog // and the proxy routing table can never drift. Adding a provider to - // MANAGED_PROVIDER_META with `managed: true` automatically opts it into + // PLATFORM_PROVIDER_META with `managed: true` automatically opts it into // the Platform auth-type dropdown in the clients. - supportsManagedAuth: MANAGED_PROVIDER_META[entry.id]?.managed === true, + supportsPlatformAuth: PLATFORM_PROVIDER_META[entry.id]?.managed === true, })); /** Check if a model ID is in the catalog for a given provider. */ diff --git a/assistant/src/providers/managed-proxy/constants.ts b/assistant/src/providers/platform-proxy/constants.ts similarity index 95% rename from assistant/src/providers/managed-proxy/constants.ts rename to assistant/src/providers/platform-proxy/constants.ts index 7082b5cf8f8..ffb9ed6d135 100644 --- a/assistant/src/providers/managed-proxy/constants.ts +++ b/assistant/src/providers/platform-proxy/constants.ts @@ -25,7 +25,7 @@ export interface ManagedProviderMeta { * managed credentials are present; that policy lives in the registry/context * fallback allowlists. */ -export const MANAGED_PROVIDER_META: Record = { +export const PLATFORM_PROVIDER_META: Record = { openai: { name: "openai", managed: true, diff --git a/assistant/src/providers/managed-proxy/context.ts b/assistant/src/providers/platform-proxy/context.ts similarity index 95% rename from assistant/src/providers/managed-proxy/context.ts rename to assistant/src/providers/platform-proxy/context.ts index 6d13faa921b..a0f72be5131 100644 --- a/assistant/src/providers/managed-proxy/context.ts +++ b/assistant/src/providers/platform-proxy/context.ts @@ -12,7 +12,7 @@ import { getPlatformBaseUrl } from "../../config/env.js"; import { credentialKey } from "../../security/credential-key.js"; import { getSecureKeyAsync } from "../../security/secure-keys.js"; -import { MANAGED_PROVIDER_META } from "./constants.js"; +import { PLATFORM_PROVIDER_META } from "./constants.js"; /** Storage key for the assistant API key credential. */ const ASSISTANT_API_KEY_STORAGE_KEY = credentialKey( @@ -70,7 +70,7 @@ export async function hasManagedProxyPrereqs(): Promise { export async function buildManagedBaseUrl( provider: string, ): Promise { - const meta = MANAGED_PROVIDER_META[provider]; + const meta = PLATFORM_PROVIDER_META[provider]; if (!meta?.managed || !meta.proxyPath) return undefined; const ctx = await resolveManagedProxyContext(); @@ -88,7 +88,7 @@ export async function buildManagedBaseUrl( export async function managedFallbackEnabledFor( provider: string, ): Promise { - const meta = MANAGED_PROVIDER_META[provider]; + const meta = PLATFORM_PROVIDER_META[provider]; if (!meta?.managed) return false; return await hasManagedProxyPrereqs(); } diff --git a/assistant/src/providers/provider-availability.ts b/assistant/src/providers/provider-availability.ts index 2fac3337711..92eab9d4bf5 100644 --- a/assistant/src/providers/provider-availability.ts +++ b/assistant/src/providers/provider-availability.ts @@ -7,7 +7,7 @@ import { API_KEY_PROVIDERS } from "../config/loader.js"; import { getProviderKeyAsync } from "../security/secure-keys.js"; -import { managedFallbackEnabledFor } from "./managed-proxy/context.js"; +import { managedFallbackEnabledFor } from "./platform-proxy/context.js"; /** * Check whether a single provider is usable — via a user-provided key diff --git a/assistant/src/providers/registry.ts b/assistant/src/providers/registry.ts index aa78dc05603..33166f7b44a 100644 --- a/assistant/src/providers/registry.ts +++ b/assistant/src/providers/registry.ts @@ -12,12 +12,12 @@ import { // --------------------------------------------------------------------------- import type { ProviderConnection } from "./inference/auth.js"; import { resolveAuth } from "./inference/resolve-auth.js"; +import { isModelInCatalog, PROVIDER_CATALOG } from "./model-catalog.js"; +import { getProviderDefaultModel } from "./model-intents.js"; import { buildManagedBaseUrl, resolveManagedProxyContext, -} from "./managed-proxy/context.js"; -import { isModelInCatalog, PROVIDER_CATALOG } from "./model-catalog.js"; -import { getProviderDefaultModel } from "./model-intents.js"; +} from "./platform-proxy/context.js"; import { RetryProvider } from "./retry.js"; import type { Provider } from "./types.js"; import { UsageTrackingProvider } from "./usage-tracking.js"; diff --git a/assistant/src/runtime/migrations/origin-mode.ts b/assistant/src/runtime/migrations/origin-mode.ts index 94feccc6815..0c20c93815b 100644 --- a/assistant/src/runtime/migrations/origin-mode.ts +++ b/assistant/src/runtime/migrations/origin-mode.ts @@ -14,7 +14,7 @@ * combination logic. */ -import { hasManagedProxyPrereqs } from "../../providers/managed-proxy/context.js"; +import { hasManagedProxyPrereqs } from "../../providers/platform-proxy/context.js"; import { getDaemonRuntimeMode } from "../runtime-mode.js"; export type VBundleOriginMode = diff --git a/assistant/src/runtime/routes/auth-routes.ts b/assistant/src/runtime/routes/auth-routes.ts index 44c91d45bf1..997f4b51462 100644 --- a/assistant/src/runtime/routes/auth-routes.ts +++ b/assistant/src/runtime/routes/auth-routes.ts @@ -12,7 +12,7 @@ import { getPlatformOrganizationId, getPlatformUserId, } from "../../config/env.js"; -import { resolveManagedProxyContext } from "../../providers/managed-proxy/context.js"; +import { resolveManagedProxyContext } from "../../providers/platform-proxy/context.js"; import type { RouteDefinition, RouteHandlerArgs } from "./types.js"; interface AuthInfoResult { diff --git a/clients/macos/vellum-assistant/Features/Settings/ProvidersSheet.swift b/clients/macos/vellum-assistant/Features/Settings/ProvidersSheet.swift index 93db47bbdb3..857b2420343 100644 --- a/clients/macos/vellum-assistant/Features/Settings/ProvidersSheet.swift +++ b/clients/macos/vellum-assistant/Features/Settings/ProvidersSheet.swift @@ -379,7 +379,7 @@ struct ProvidersSheet: View { editorDraft.credential = "" } else { if editorDraft.authType == "none" || - (editorDraft.authType == "platform" && !store.isManagedCapable(newProvider)) { + (editorDraft.authType == "platform" && !store.isPlatformCapable(newProvider)) { editorDraft.authType = "api_key" } editorDraft.credential = "credential/\(newProvider)/api_key" @@ -508,7 +508,7 @@ struct ProvidersSheet: View { var options: [(label: String, value: String)] = [ (label: "API Key", value: "api_key"), ] - if store.isManagedCapable(provider) { + if store.isPlatformCapable(provider) { options.append((label: "Platform (managed by Vellum)", value: "platform")) } // Preserve the current auth type in edit mode so existing connections diff --git a/clients/macos/vellum-assistant/Features/Settings/SettingsStore.swift b/clients/macos/vellum-assistant/Features/Settings/SettingsStore.swift index c8e98424f7f..f3f7874ab25 100644 --- a/clients/macos/vellum-assistant/Features/Settings/SettingsStore.swift +++ b/clients/macos/vellum-assistant/Features/Settings/SettingsStore.swift @@ -1197,15 +1197,15 @@ public final class SettingsStore: ObservableObject { private static let nativeWebSearchCapableProviderIds: Set = ["anthropic", "openai"] /// Returns the catalog entries for providers that support managed proxy routing. - /// Source of truth: the `supportsManagedAuth` field on `LLMProviderRegistry` - /// entries, which is derived upstream from `MANAGED_PROVIDER_META` at catalog + /// Source of truth: the `supportsPlatformAuth` field on `LLMProviderRegistry` + /// entries, which is derived upstream from `PLATFORM_PROVIDER_META` at catalog /// build time. Reading from the registry (not `providerCatalog`) keeps the /// answer stable across daemon `model_info` refreshes — the wire-protocol /// `ProviderCatalogEntry` doesn't carry capability flags. - var managedCapableProviders: [ProviderCatalogEntry] { + var platformCapableProviders: [ProviderCatalogEntry] { let managedIds = Set( LLMProviderRegistry.providers - .filter { $0.supportsManagedAuth == true } + .filter { $0.supportsPlatformAuth == true } .map(\.id) ) return providerCatalog.filter { managedIds.contains($0.id) } @@ -1217,9 +1217,9 @@ public final class SettingsStore: ObservableObject { } /// Whether a given provider supports managed proxy routing. - /// See `managedCapableProviders` for the source-of-truth rationale. - func isManagedCapable(_ provider: String) -> Bool { - LLMProviderRegistry.provider(id: provider)?.supportsManagedAuth == true + /// See `platformCapableProviders` for the source-of-truth rationale. + func isPlatformCapable(_ provider: String) -> Bool { + LLMProviderRegistry.provider(id: provider)?.supportsPlatformAuth == true } /// Whether the current inference selection supports native web search. diff --git a/clients/macos/vellum-assistantTests/SettingsStoreManagedInferenceSelectionTests.swift b/clients/macos/vellum-assistantTests/SettingsStoreManagedInferenceSelectionTests.swift index e2037d4e864..6c41513bce2 100644 --- a/clients/macos/vellum-assistantTests/SettingsStoreManagedInferenceSelectionTests.swift +++ b/clients/macos/vellum-assistantTests/SettingsStoreManagedInferenceSelectionTests.swift @@ -19,34 +19,34 @@ final class SettingsStoreManagedInferenceSelectionTests: XCTestCase { super.tearDown() } - // MARK: - isManagedCapable + // MARK: - isPlatformCapable func testAnthropicIsManagedCapable() { - XCTAssertTrue(store.isManagedCapable("anthropic")) + XCTAssertTrue(store.isPlatformCapable("anthropic")) } func testOpenAIIsManagedCapable() { - XCTAssertTrue(store.isManagedCapable("openai")) + XCTAssertTrue(store.isPlatformCapable("openai")) } func testGeminiIsManagedCapable() { - XCTAssertTrue(store.isManagedCapable("gemini")) + XCTAssertTrue(store.isPlatformCapable("gemini")) } func testOllamaIsNotManagedCapable() { - XCTAssertFalse(store.isManagedCapable("ollama")) + XCTAssertFalse(store.isPlatformCapable("ollama")) } func testFireworksIsNotManagedCapable() { - XCTAssertFalse(store.isManagedCapable("fireworks")) + XCTAssertFalse(store.isPlatformCapable("fireworks")) } func testOpenRouterIsNotManagedCapable() { - XCTAssertFalse(store.isManagedCapable("openrouter")) + XCTAssertFalse(store.isPlatformCapable("openrouter")) } func testUnknownProviderIsNotManagedCapable() { - XCTAssertFalse(store.isManagedCapable("unknown-provider")) + XCTAssertFalse(store.isPlatformCapable("unknown-provider")) } // MARK: - isNativeWebSearchCapable @@ -80,17 +80,17 @@ final class SettingsStoreManagedInferenceSelectionTests: XCTestCase { XCTAssertFalse(store.isNativeWebSearchCapable("openrouter", model: "")) } - // MARK: - managedCapableProviders + // MARK: - platformCapableProviders func testManagedCapableProvidersContainsExpectedEntries() { - let ids = store.managedCapableProviders.map(\.id) + let ids = store.platformCapableProviders.map(\.id) XCTAssertTrue(ids.contains("anthropic"), "expected anthropic in managed-capable providers") XCTAssertTrue(ids.contains("openai"), "expected openai in managed-capable providers") XCTAssertTrue(ids.contains("gemini"), "expected gemini in managed-capable providers") } func testManagedCapableProvidersExcludesNonManagedEntries() { - let ids = store.managedCapableProviders.map(\.id) + let ids = store.platformCapableProviders.map(\.id) XCTAssertFalse(ids.contains("ollama"), "ollama should not be in managed-capable providers") XCTAssertFalse(ids.contains("fireworks"), "fireworks should not be in managed-capable providers") XCTAssertFalse(ids.contains("openrouter"), "openrouter should not be in managed-capable providers") @@ -174,20 +174,20 @@ final class SettingsStoreManagedInferenceSelectionTests: XCTestCase { func testManagedOpenAIPlusProviderNativeIsValid() { // OpenAI is both managed-capable and native-web-search-capable, // so managed inference + inference-provider-native should be allowed. - XCTAssertTrue(store.isManagedCapable("openai")) + XCTAssertTrue(store.isPlatformCapable("openai")) XCTAssertTrue(store.isNativeWebSearchCapable("openai", model: "gpt-5")) } func testManagedAnthropicPlusProviderNativeIsValid() { // Anthropic is both managed-capable and native-web-search-capable. - XCTAssertTrue(store.isManagedCapable("anthropic")) + XCTAssertTrue(store.isPlatformCapable("anthropic")) XCTAssertTrue(store.isNativeWebSearchCapable("anthropic", model: "claude-opus-4.7")) } func testManagedGeminiPlusProviderNativeIsInvalid() { // Gemini is managed-capable but NOT native-web-search-capable, // so managed Gemini + inference-provider-native should be rejected. - XCTAssertTrue(store.isManagedCapable("gemini")) + XCTAssertTrue(store.isPlatformCapable("gemini")) XCTAssertFalse(store.isNativeWebSearchCapable("gemini", model: "gemini-2.5-pro")) } diff --git a/clients/shared/Resources/llm-provider-catalog.json b/clients/shared/Resources/llm-provider-catalog.json index 4a08785d745..089e958c163 100644 --- a/clients/shared/Resources/llm-provider-catalog.json +++ b/clients/shared/Resources/llm-provider-catalog.json @@ -14,7 +14,7 @@ "url": "https://console.anthropic.com/settings/keys", "linkLabel": "Open Anthropic Console" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "claude-opus-4-7", "models": [ { @@ -107,7 +107,7 @@ "url": "https://platform.openai.com/api-keys", "linkLabel": "Open OpenAI Platform" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "gpt-5.5", "models": [ { @@ -252,7 +252,7 @@ "url": "https://aistudio.google.com/apikey", "linkLabel": "Open Google AI Studio" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "gemini-2.5-flash", "models": [ { @@ -414,7 +414,7 @@ "url": "https://ollama.com/download", "linkLabel": "Download Ollama" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "llama3.2", "models": [ { @@ -456,7 +456,7 @@ "url": "https://fireworks.ai/account/api-keys", "linkLabel": "Open Fireworks Dashboard" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "accounts/fireworks/models/kimi-k2p5", "models": [ { @@ -490,7 +490,7 @@ "url": "https://openrouter.ai/keys", "linkLabel": "Open OpenRouter" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "x-ai/grok-4.20-beta", "models": [ { diff --git a/clients/shared/Utilities/LLMProviderRegistry.swift b/clients/shared/Utilities/LLMProviderRegistry.swift index c50a781302b..a3e2f96bc53 100644 --- a/clients/shared/Utilities/LLMProviderRegistry.swift +++ b/clients/shared/Utilities/LLMProviderRegistry.swift @@ -150,13 +150,13 @@ public struct LLMProviderEntry: Decodable { public let credentialsGuide: LLMCredentialsGuide? /// Whether this provider supports the `platform` auth type — i.e. /// Vellum-managed keys routed through the platform proxy. Derived - /// upstream from `MANAGED_PROVIDER_META` in - /// `assistant/src/providers/managed-proxy/constants.ts`. When `false` + /// upstream from `PLATFORM_PROVIDER_META` in + /// `assistant/src/providers/platform-proxy/constants.ts`. When `false` /// (or absent in older catalog versions, in which case it defaults to /// `false`), the auth-type dropdown hides the "Platform (managed by /// Vellum)" option for this provider — selecting it would have no /// effect since there's no managed proxy route for the provider. - public let supportsManagedAuth: Bool? + public let supportsPlatformAuth: Bool? /// The default model ID (must be present in `models`). public let defaultModel: String /// All models offered by this provider. @@ -171,7 +171,7 @@ public struct LLMProviderEntry: Decodable { envVar: String?, apiKeyPlaceholder: String?, credentialsGuide: LLMCredentialsGuide?, - supportsManagedAuth: Bool? = nil, + supportsPlatformAuth: Bool? = nil, defaultModel: String, models: [LLMModelEntry] ) { @@ -183,7 +183,7 @@ public struct LLMProviderEntry: Decodable { self.envVar = envVar self.apiKeyPlaceholder = apiKeyPlaceholder self.credentialsGuide = credentialsGuide - self.supportsManagedAuth = supportsManagedAuth + self.supportsPlatformAuth = supportsPlatformAuth self.defaultModel = defaultModel self.models = models } diff --git a/meta/llm-provider-catalog.json b/meta/llm-provider-catalog.json index 4a08785d745..089e958c163 100644 --- a/meta/llm-provider-catalog.json +++ b/meta/llm-provider-catalog.json @@ -14,7 +14,7 @@ "url": "https://console.anthropic.com/settings/keys", "linkLabel": "Open Anthropic Console" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "claude-opus-4-7", "models": [ { @@ -107,7 +107,7 @@ "url": "https://platform.openai.com/api-keys", "linkLabel": "Open OpenAI Platform" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "gpt-5.5", "models": [ { @@ -252,7 +252,7 @@ "url": "https://aistudio.google.com/apikey", "linkLabel": "Open Google AI Studio" }, - "supportsManagedAuth": true, + "supportsPlatformAuth": true, "defaultModel": "gemini-2.5-flash", "models": [ { @@ -414,7 +414,7 @@ "url": "https://ollama.com/download", "linkLabel": "Download Ollama" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "llama3.2", "models": [ { @@ -456,7 +456,7 @@ "url": "https://fireworks.ai/account/api-keys", "linkLabel": "Open Fireworks Dashboard" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "accounts/fireworks/models/kimi-k2p5", "models": [ { @@ -490,7 +490,7 @@ "url": "https://openrouter.ai/keys", "linkLabel": "Open OpenRouter" }, - "supportsManagedAuth": false, + "supportsPlatformAuth": false, "defaultModel": "x-ai/grok-4.20-beta", "models": [ {