From ebed68dac21e83db7847deda701b5a9a88f5aa77 Mon Sep 17 00:00:00 2001 From: Guillaume Gay Date: Mon, 6 Jul 2026 07:47:53 +0200 Subject: [PATCH] feat: add Manifest provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Manifest — an open-source, OpenAI-compatible gateway for AI agents — as a built-in provider. Changes: - core/llm/llms/Manifest.ts — provider class extending OpenAI (single auto model, server-side routing) - core/llm/llms/Manifest.vitest.ts — provider name, defaults, reasoning - core/llm/llms/index.ts — register in LLMClasses - core/llm/autodetect.ts — handles templating + images - core/llm/toolSupport.ts — tool support (gateway assumption) - core/llm/toolSupport.test.ts — manifest tests - packages/openai-adapters/src/apis/Manifest.ts — API adapter - packages/openai-adapters/src/apis/Manifest.test.ts — adapter tests - packages/openai-adapters/src/apis/AiSdk.ts — AI SDK provider map - packages/openai-adapters/src/index.ts — constructLlmApi routing - packages/openai-adapters/src/types.ts — provider enum - gui/src/pages/AddNewModel/configs/providers.ts — UI config - gui/src/pages/AddNewModel/configs/models.ts — manifestAuto model - gui/public/logos/manifest.png — provider logo - extensions/vscode/config_schema.json — VS Code schema - docs/customize/model-providers/more/manifest.mdx — provider docs - docs/customize/model-providers/overview.mdx — overview table - docs/docs.json — docs navigation --- core/llm/autodetect.ts | 2 + core/llm/llms/Manifest.ts | 28 +++++++++ core/llm/llms/Manifest.vitest.ts | 36 +++++++++++ core/llm/llms/index.ts | 2 + core/llm/toolSupport.test.ts | 13 ++++ core/llm/toolSupport.ts | 6 ++ .../model-providers/more/manifest.mdx | 56 ++++++++++++++++++ docs/customize/model-providers/overview.mdx | 1 + docs/docs.json | 1 + extensions/vscode/config_schema.json | 1 + gui/public/logos/manifest.png | Bin 0 -> 17131 bytes gui/src/pages/AddNewModel/configs/models.ts | 14 +++++ .../pages/AddNewModel/configs/providers.ts | 36 +++++++++++ packages/openai-adapters/package.json | 2 +- packages/openai-adapters/src/apis/AiSdk.ts | 5 ++ .../openai-adapters/src/apis/Manifest.test.ts | 34 +++++++++++ packages/openai-adapters/src/apis/Manifest.ts | 28 +++++++++ packages/openai-adapters/src/index.ts | 3 + packages/openai-adapters/src/types.ts | 1 + 19 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 core/llm/llms/Manifest.ts create mode 100644 core/llm/llms/Manifest.vitest.ts create mode 100644 docs/customize/model-providers/more/manifest.mdx create mode 100644 gui/public/logos/manifest.png create mode 100644 packages/openai-adapters/src/apis/Manifest.test.ts create mode 100644 packages/openai-adapters/src/apis/Manifest.ts diff --git a/core/llm/autodetect.ts b/core/llm/autodetect.ts index c8511554b8b..fc71af74a45 100644 --- a/core/llm/autodetect.ts +++ b/core/llm/autodetect.ts @@ -65,6 +65,7 @@ const PROVIDER_HANDLES_TEMPLATING: string[] = [ "relace", "openrouter", "clawrouter", + "manifest", "deepseek", "xAI", "minimax", @@ -123,6 +124,7 @@ const PROVIDER_SUPPORTS_IMAGES: string[] = [ "sagemaker", "openrouter", "clawrouter", + "manifest", "venice", "sambanova", "vertexai", diff --git a/core/llm/llms/Manifest.ts b/core/llm/llms/Manifest.ts new file mode 100644 index 00000000000..16e6274ee50 --- /dev/null +++ b/core/llm/llms/Manifest.ts @@ -0,0 +1,28 @@ +import { LLMOptions } from "../../index.js"; + +import OpenAI from "./OpenAI.js"; + +/** + * Manifest LLM Provider + * + * Manifest is an open-source, OpenAI-compatible gateway for AI agents. It + * exposes a single endpoint in front of multiple providers (API keys, + * subscriptions, local models), with per-message cost/token tracking and + * automatic fallback when a provider fails. + * + * The served model is resolved server-side from the user's dashboard + * configuration, so requests always target the single `auto` model id. + * + * @see https://github.com/mnfst/manifest + */ +class Manifest extends OpenAI { + static providerName = "manifest"; + + static defaultOptions: Partial = { + apiBase: "https://app.manifest.build/v1/", + model: "auto", + useLegacyCompletionsEndpoint: false, + }; +} + +export default Manifest; diff --git a/core/llm/llms/Manifest.vitest.ts b/core/llm/llms/Manifest.vitest.ts new file mode 100644 index 00000000000..24f15426c41 --- /dev/null +++ b/core/llm/llms/Manifest.vitest.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from "vitest"; + +import Manifest from "./Manifest"; + +describe("Manifest", () => { + it("should have correct provider name", () => { + expect(Manifest.providerName).toBe("manifest"); + }); + + it("should have correct default options", () => { + expect(Manifest.defaultOptions?.apiBase).toBe( + "https://app.manifest.build/v1/", + ); + expect(Manifest.defaultOptions?.model).toBe("auto"); + expect(Manifest.defaultOptions?.useLegacyCompletionsEndpoint).toBe(false); + }); + + it("should default to the auto model", () => { + const manifest = new Manifest({ + model: "auto", + apiKey: "mnfst_test", + }); + + expect(manifest.model).toBe("auto"); + }); + + it("should allow overriding the apiBase", () => { + const manifest = new Manifest({ + model: "auto", + apiKey: "mnfst_test", + apiBase: "http://localhost:3000/v1/", + }); + + expect(manifest.apiBase).toBe("http://localhost:3000/v1/"); + }); +}); diff --git a/core/llm/llms/index.ts b/core/llm/llms/index.ts index 4978f0617f2..6a8f3d0cbd7 100644 --- a/core/llm/llms/index.ts +++ b/core/llm/llms/index.ts @@ -36,6 +36,7 @@ import Llamafile from "./Llamafile"; import LlamaStack from "./LlamaStack"; import Lemonade from "./Lemonade"; import LMStudio from "./LMStudio"; +import Manifest from "./Manifest"; import Mistral from "./Mistral"; import Mimo from "./Mimo"; import MiniMax from "./MiniMax"; @@ -92,6 +93,7 @@ export const LLMClasses = [ OVHcloud, Lemonade, LMStudio, + Manifest, Mistral, Mimo, MiniMax, diff --git a/core/llm/toolSupport.test.ts b/core/llm/toolSupport.test.ts index be14a76d619..aea39b1123e 100644 --- a/core/llm/toolSupport.test.ts +++ b/core/llm/toolSupport.test.ts @@ -380,6 +380,19 @@ describe("PROVIDER_TOOL_SUPPORT", () => { }); }); + describe("manifest", () => { + const supportsFn = PROVIDER_TOOL_SUPPORT["manifest"]; + + it("should return true for auto model", () => { + expect(supportsFn("auto")).toBe(true); + }); + + it("should return true for any model", () => { + expect(supportsFn("gpt-4o")).toBe(true); + expect(supportsFn("claude-sonnet-4")).toBe(true); + }); + }); + describe("edge cases", () => { it("should handle empty model names", () => { expect(PROVIDER_TOOL_SUPPORT["anthropic"]("")).toBe(false); diff --git a/core/llm/toolSupport.ts b/core/llm/toolSupport.ts index 3f65473233c..7c702cd2d61 100644 --- a/core/llm/toolSupport.ts +++ b/core/llm/toolSupport.ts @@ -412,6 +412,12 @@ export const PROVIDER_TOOL_SUPPORT: Record boolean> = !!lower.match(/\bo[1-9]\b/) ); }, + manifest: (model) => { + // Manifest is a gateway that routes to various providers server-side. + // The "auto" model resolves to whatever the user has configured in + // their dashboard, which may support tools. + return true; + }, zAI: (model) => { const lower = model.toLowerCase(); return !!lower.match(/^glm-[4-9]/); diff --git a/docs/customize/model-providers/more/manifest.mdx b/docs/customize/model-providers/more/manifest.mdx new file mode 100644 index 00000000000..ab172c7c68f --- /dev/null +++ b/docs/customize/model-providers/more/manifest.mdx @@ -0,0 +1,56 @@ +--- +title: Manifest +description: OpenAI-compatible gateway with multi-provider support +--- + +# Manifest + +[Manifest](https://manifest.build) is an open-source, OpenAI-compatible gateway for AI agents. It exposes a single endpoint in front of multiple providers (API keys, subscriptions, local models), with per-message cost/token tracking and automatic fallback when a provider fails. + +The served model is resolved server-side from your dashboard configuration, so requests always target the single `auto` model id. + +## Setup + +1. Sign up at [manifest.build](https://manifest.build) +2. Add your provider API keys (OpenAI, Anthropic, etc.) in the dashboard +3. Configure Continue to use Manifest as your provider + +### config.json + +```json +{ + "models": [ + { + "title": "Manifest Auto", + "provider": "manifest", + "model": "auto", + "apiKey": "YOUR_MANIFEST_API_KEY" + } + ] +} +``` + +### config.yaml + +```yaml +models: + - title: "Manifest Auto" + provider: manifest + model: auto + apiKey: "YOUR_MANIFEST_API_KEY" +``` + +## Configuration Options + +| Field | Required | Default | Description | +| ---------- | -------- | --------------------------- | ------------------------------------ | +| `apiKey` | Yes | - | Your Manifest API key | +| `apiBase` | No | `https://app.manifest.build/v1/` | Custom API base URL (e.g. for self-hosted) | +| `model` | No | `auto` | Model identifier (always `auto`) | + +## Features + +- **Multi-provider routing** — one endpoint, multiple providers +- **Cost & token tracking** — per-message breakdown in the dashboard +- **Automatic fallback** — if one provider fails, Manifest retries with the next +- **Self-hostable** — deploy your own instance from [github.com/mnfst/manifest](https://github.com/mnfst/manifest) diff --git a/docs/customize/model-providers/overview.mdx b/docs/customize/model-providers/overview.mdx index 7ba030dcb4d..783fae94dba 100644 --- a/docs/customize/model-providers/overview.mdx +++ b/docs/customize/model-providers/overview.mdx @@ -35,6 +35,7 @@ Beyond the top-level providers, Continue supports many other options: | [DeepInfra](/customize/model-providers/more/deepinfra) | Hosting for various open source models | | [OpenRouter](/customize/model-providers/top-level/openrouter) | Gateway to multiple model providers | | [ClawRouter](/customize/model-providers/more/clawrouter) | Open-source LLM router with automatic cost-optimized model selection | +| [Manifest](/customize/model-providers/more/manifest) | OpenAI-compatible gateway with multi-provider routing, cost tracking, and automatic fallback | | [Tetrate Agent Router Service](/customize/model-providers/top-level/tetrate_agent_router_service) | Gateway with intelligent routing across multiple model providers | | [Cohere](/customize/model-providers/more/cohere) | Models specialized for semantic search and text generation | | [NVIDIA](/customize/model-providers/more/nvidia) | GPU-accelerated model hosting | diff --git a/docs/docs.json b/docs/docs.json index b7a1d83f13a..1435e58a2a0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -107,6 +107,7 @@ "pages": [ "customize/model-providers/more/asksage", "customize/model-providers/more/clawrouter", + "customize/model-providers/more/manifest", "customize/model-providers/more/deepseek", "customize/model-providers/more/deepinfra", "customize/model-providers/more/groq", diff --git a/extensions/vscode/config_schema.json b/extensions/vscode/config_schema.json index fb3f4c61362..d037391d133 100644 --- a/extensions/vscode/config_schema.json +++ b/extensions/vscode/config_schema.json @@ -217,6 +217,7 @@ "watsonx", "openrouter", "clawrouter", + "manifest", "sambanova", "nvidia", "vllm", diff --git a/gui/public/logos/manifest.png b/gui/public/logos/manifest.png new file mode 100644 index 0000000000000000000000000000000000000000..14dfa8566aa18ff6e442217df9a0ab2a42f2b05d GIT binary patch literal 17131 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 mxKw0iZaE%b+V8pU6@LO2o>0|?WL{?g0000> = { ], }, + manifest: { + title: "Manifest", + provider: "manifest", + description: + "OpenAI-compatible gateway with multi-provider support, cost/token tracking, and automatic fallback.", + longDescription: `[Manifest](https://manifest.build) is an open-source OpenAI-compatible gateway for AI agents. It exposes a single endpoint in front of multiple providers (API keys, subscriptions, local models), with per-message cost/token tracking and automatic fallback when a provider fails. + +The served model is resolved server-side from your dashboard configuration, so you always use the \`auto\` model id. + +To get started: +1. Sign up at [manifest.build](https://manifest.build) +2. Add your provider API keys in the dashboard +3. Enter your API key below + +**Features:** +- Multi-provider routing (one endpoint) +- Per-message cost and token tracking +- Automatic fallback on provider failures +- Compatible with any OpenAI SDK`, + icon: "manifest.png", + tags: [ModelProviderTags.RequiresApiKey], + refPage: "manifest", + apiKeyUrl: "https://app.manifest.build/settings/keys", + collectInputFor: [ + { + inputType: "text", + key: "apiKey", + label: "API Key", + placeholder: "Enter your Manifest API key", + required: true, + }, + ...completionParamsInputsConfigs, + ], + packages: [models.manifestAuto], + }, + moonshot: { title: "Moonshot", provider: "moonshot", diff --git a/packages/openai-adapters/package.json b/packages/openai-adapters/package.json index bfc5cda47be..fba0cdcfac8 100644 --- a/packages/openai-adapters/package.json +++ b/packages/openai-adapters/package.json @@ -48,7 +48,7 @@ "semantic-release": "^24.2.7", "ts-jest": "^29.2.3", "ts-node": "^10.9.2", - "vitest": "^3.2.4" + "vitest": "^3.1.4" }, "overrides": { "picomatch": "^4.0.4" diff --git a/packages/openai-adapters/src/apis/AiSdk.ts b/packages/openai-adapters/src/apis/AiSdk.ts index c0f68689988..620e7ae0b1c 100644 --- a/packages/openai-adapters/src/apis/AiSdk.ts +++ b/packages/openai-adapters/src/apis/AiSdk.ts @@ -46,6 +46,11 @@ const PROVIDER_MAP: Record = { ...options, baseURL: options.baseURL ?? "http://localhost:1337/v1/", }), + manifest: (options) => + createOpenAI({ + ...options, + baseURL: options.baseURL ?? "https://app.manifest.build/v1/", + }), }; export class AiSdkApi implements BaseLlmApi { diff --git a/packages/openai-adapters/src/apis/Manifest.test.ts b/packages/openai-adapters/src/apis/Manifest.test.ts new file mode 100644 index 00000000000..a6bc24bab5c --- /dev/null +++ b/packages/openai-adapters/src/apis/Manifest.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; + +import { ManifestApi } from "./Manifest.js"; + +describe("ManifestApi", () => { + const baseConfig = { + provider: "manifest" as const, + }; + + it("should use default apiBase when not provided", () => { + const api = new ManifestApi(baseConfig); + expect(api["config"].apiBase).toBe("https://app.manifest.build/v1/"); + }); + + it("should allow custom apiBase", () => { + const api = new ManifestApi({ + ...baseConfig, + apiBase: "http://localhost:3000/v1/", + }); + expect(api["config"].apiBase).toBe("http://localhost:3000/v1/"); + }); + + it("should include standard OpenAI headers", () => { + const api = new ManifestApi({ + ...baseConfig, + apiKey: "mnfst_test", + }); + const headers = api["getHeaders"](); + + expect(headers["Content-Type"]).toBe("application/json"); + expect(headers["Accept"]).toBe("application/json"); + expect(headers["Authorization"]).toBe("Bearer mnfst_test"); + }); +}); diff --git a/packages/openai-adapters/src/apis/Manifest.ts b/packages/openai-adapters/src/apis/Manifest.ts new file mode 100644 index 00000000000..9eb05eba7ac --- /dev/null +++ b/packages/openai-adapters/src/apis/Manifest.ts @@ -0,0 +1,28 @@ +import { OpenAIApi } from "./OpenAI.js"; +import { OpenAIConfig } from "../types.js"; + +export interface ManifestConfig extends OpenAIConfig {} + +/** + * Manifest API adapter + * + * Manifest is an open-source, OpenAI-compatible gateway for AI agents. + * It exposes a single endpoint in front of multiple providers (API keys, + * subscriptions, local models), with per-message cost/token tracking and + * automatic fallback when a provider fails. + * + * The served model is resolved server-side from the user's dashboard + * configuration, so requests always target the single `auto` model id. + * + * @see https://github.com/mnfst/manifest + */ +export class ManifestApi extends OpenAIApi { + constructor(config: ManifestConfig) { + super({ + ...config, + apiBase: config.apiBase ?? "https://app.manifest.build/v1/", + }); + } +} + +export default ManifestApi; diff --git a/packages/openai-adapters/src/index.ts b/packages/openai-adapters/src/index.ts index 52fb2d33a0c..d836176426d 100644 --- a/packages/openai-adapters/src/index.ts +++ b/packages/openai-adapters/src/index.ts @@ -19,6 +19,7 @@ import { MoonshotApi } from "./apis/Moonshot.js"; import { OpenAIApi } from "./apis/OpenAI.js"; import { OpenRouterApi } from "./apis/OpenRouter.js"; import { ClawRouterApi } from "./apis/ClawRouter.js"; +import { ManifestApi } from "./apis/Manifest.js"; import { RelaceApi } from "./apis/Relace.js"; import { VertexAIApi } from "./apis/VertexAI.js"; import { WatsonXApi } from "./apis/WatsonX.js"; @@ -180,6 +181,8 @@ export function constructLlmApi(config: LLMConfig): BaseLlmApi | undefined { return new OpenRouterApi(config); case "clawrouter": return new ClawRouterApi(config); + case "manifest": + return new ManifestApi(config); case "llama.cpp": case "llamafile": return openAICompatible("http://localhost:8000/", config); diff --git a/packages/openai-adapters/src/types.ts b/packages/openai-adapters/src/types.ts index 14b9512f75b..648064026da 100644 --- a/packages/openai-adapters/src/types.ts +++ b/packages/openai-adapters/src/types.ts @@ -53,6 +53,7 @@ export const OpenAIConfigSchema = BasePlusConfig.extend({ z.literal("msty"), z.literal("openrouter"), z.literal("clawrouter"), + z.literal("manifest"), z.literal("sambanova"), z.literal("text-gen-webui"), z.literal("vllm"),