feat(providers): add Venice AI provider
OpenAI-compatible apikey provider (chat/embedding/image) with dynamic model discovery via modelsFetcher + passthroughModels. No executor needed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
// Auto-generated: static imports of all registry entries
|
// Auto-generated: static imports of all registry entries
|
||||||
import p0 from "./alicode.js";
|
import p0 from "./alicode-intl.js";
|
||||||
import p1 from "./alicode-intl.js";
|
import p1 from "./alicode.js";
|
||||||
import p2 from "./anthropic.js";
|
import p2 from "./anthropic.js";
|
||||||
import p3 from "./antigravity.js";
|
import p3 from "./antigravity.js";
|
||||||
import p4 from "./assemblyai.js";
|
import p4 from "./assemblyai.js";
|
||||||
@@ -31,12 +31,12 @@ import p28 from "./exa.js";
|
|||||||
import p29 from "./fal-ai.js";
|
import p29 from "./fal-ai.js";
|
||||||
import p30 from "./firecrawl.js";
|
import p30 from "./firecrawl.js";
|
||||||
import p31 from "./fireworks.js";
|
import p31 from "./fireworks.js";
|
||||||
import p32 from "./gemini.js";
|
import p32 from "./gemini-cli.js";
|
||||||
import p33 from "./gemini-cli.js";
|
import p33 from "./gemini.js";
|
||||||
import p34 from "./github.js";
|
import p34 from "./github.js";
|
||||||
import p35 from "./gitlab.js";
|
import p35 from "./gitlab.js";
|
||||||
import p36 from "./glm.js";
|
import p36 from "./glm-cn.js";
|
||||||
import p37 from "./glm-cn.js";
|
import p37 from "./glm.js";
|
||||||
import p38 from "./google-pse.js";
|
import p38 from "./google-pse.js";
|
||||||
import p39 from "./google-tts.js";
|
import p39 from "./google-tts.js";
|
||||||
import p40 from "./grok-web.js";
|
import p40 from "./grok-web.js";
|
||||||
@@ -48,27 +48,27 @@ import p45 from "./inworld.js";
|
|||||||
import p46 from "./jina-ai.js";
|
import p46 from "./jina-ai.js";
|
||||||
import p47 from "./jina-reader.js";
|
import p47 from "./jina-reader.js";
|
||||||
import p48 from "./kilocode.js";
|
import p48 from "./kilocode.js";
|
||||||
import p49 from "./kimi.js";
|
import p49 from "./kimi-coding.js";
|
||||||
import p50 from "./kimi-coding.js";
|
import p50 from "./kimi.js";
|
||||||
import p51 from "./kiro.js";
|
import p51 from "./kiro.js";
|
||||||
import p52 from "./linkup.js";
|
import p52 from "./linkup.js";
|
||||||
import p53 from "./local-device.js";
|
import p53 from "./local-device.js";
|
||||||
import p54 from "./mimo-free.js";
|
import p54 from "./mimo-free.js";
|
||||||
import p55 from "./minimax.js";
|
import p55 from "./minimax-cn.js";
|
||||||
import p56 from "./minimax-cn.js";
|
import p56 from "./minimax.js";
|
||||||
import p57 from "./mistral.js";
|
import p57 from "./mistral.js";
|
||||||
import p58 from "./mmf.js";
|
import p58 from "./mmf.js";
|
||||||
import p59 from "./nanobanana.js";
|
import p59 from "./nanobanana.js";
|
||||||
import p60 from "./nebius.js";
|
import p60 from "./nebius.js";
|
||||||
import p61 from "./nvidia.js";
|
import p61 from "./nvidia.js";
|
||||||
import p62 from "./ollama.js";
|
import p62 from "./ollama-local.js";
|
||||||
import p63 from "./ollama-local.js";
|
import p63 from "./ollama.js";
|
||||||
import p64 from "./openai.js";
|
import p64 from "./openai.js";
|
||||||
import p65 from "./opencode.js";
|
import p65 from "./opencode-go.js";
|
||||||
import p66 from "./opencode-go.js";
|
import p66 from "./opencode.js";
|
||||||
import p67 from "./openrouter.js";
|
import p67 from "./openrouter.js";
|
||||||
import p68 from "./perplexity.js";
|
import p68 from "./perplexity-web.js";
|
||||||
import p69 from "./perplexity-web.js";
|
import p69 from "./perplexity.js";
|
||||||
import p70 from "./playht.js";
|
import p70 from "./playht.js";
|
||||||
import p71 from "./qoder.js";
|
import p71 from "./qoder.js";
|
||||||
import p72 from "./qwen.js";
|
import p72 from "./qwen.js";
|
||||||
@@ -84,15 +84,16 @@ import p81 from "./tavily.js";
|
|||||||
import p82 from "./together.js";
|
import p82 from "./together.js";
|
||||||
import p83 from "./topaz.js";
|
import p83 from "./topaz.js";
|
||||||
import p84 from "./tortoise.js";
|
import p84 from "./tortoise.js";
|
||||||
import p85 from "./vercel-ai-gateway.js";
|
import p85 from "./venice.js";
|
||||||
import p86 from "./vertex.js";
|
import p86 from "./vercel-ai-gateway.js";
|
||||||
import p87 from "./vertex-partner.js";
|
import p87 from "./vertex-partner.js";
|
||||||
import p88 from "./volcengine-ark.js";
|
import p88 from "./vertex.js";
|
||||||
import p89 from "./voyage-ai.js";
|
import p89 from "./volcengine-ark.js";
|
||||||
import p90 from "./xai.js";
|
import p90 from "./voyage-ai.js";
|
||||||
import p91 from "./xiaomi-mimo.js";
|
import p91 from "./xai.js";
|
||||||
import p92 from "./xiaomi-tokenplan.js";
|
import p92 from "./xiaomi-mimo.js";
|
||||||
import p93 from "./youcom.js";
|
import p93 from "./xiaomi-tokenplan.js";
|
||||||
|
import p94 from "./youcom.js";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
p0,
|
p0,
|
||||||
@@ -188,5 +189,6 @@ export default [
|
|||||||
p90,
|
p90,
|
||||||
p91,
|
p91,
|
||||||
p92,
|
p92,
|
||||||
p93
|
p93,
|
||||||
|
p94
|
||||||
];
|
];
|
||||||
|
|||||||
56
open-sse/providers/registry/venice.js
Normal file
56
open-sse/providers/registry/venice.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
export default {
|
||||||
|
id: "venice",
|
||||||
|
priority: 115,
|
||||||
|
alias: "venice",
|
||||||
|
aliases: [
|
||||||
|
"vn",
|
||||||
|
],
|
||||||
|
uiAlias: "venice",
|
||||||
|
display: {
|
||||||
|
name: "Venice AI",
|
||||||
|
icon: "shield",
|
||||||
|
color: "#DC2626",
|
||||||
|
textIcon: "VE",
|
||||||
|
website: "https://venice.ai",
|
||||||
|
notice: {
|
||||||
|
text: "OpenAI-compatible. Private inference + uncensored models (Venice Uncensored, GLM, Qwen, DeepSeek, Llama).",
|
||||||
|
apiKeyUrl: "https://venice.ai/settings/api",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
category: "apikey",
|
||||||
|
transport: {
|
||||||
|
baseUrl: "https://api.venice.ai/api/v1/chat/completions",
|
||||||
|
validateUrl: "https://api.venice.ai/api/v1/models",
|
||||||
|
thinkingFormat: "openai",
|
||||||
|
},
|
||||||
|
// Curated seed; the full live catalogue (90+ text models) is fetched via
|
||||||
|
// modelsFetcher and any other id is accepted via passthroughModels.
|
||||||
|
models: [
|
||||||
|
{ id: "venice-uncensored-1-2", name: "Venice Uncensored 1.2" },
|
||||||
|
{ id: "zai-org-glm-5", name: "GLM-5" },
|
||||||
|
{ id: "qwen3-235b-a22b-instruct-2507", name: "Qwen3 235B A22B Instruct" },
|
||||||
|
{ id: "qwen3-coder-480b-a35b-instruct-turbo", name: "Qwen3 Coder 480B A35B Turbo" },
|
||||||
|
{ id: "qwen3-vl-235b-a22b", name: "Qwen3 VL 235B A22B" },
|
||||||
|
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro" },
|
||||||
|
{ id: "llama-3.3-70b", name: "Llama 3.3 70B" },
|
||||||
|
{ id: "hermes-3-llama-3.1-405b", name: "Hermes 3 Llama 3.1 405B" },
|
||||||
|
{ id: "mistral-small-3-2-24b-instruct", name: "Mistral Small 3.2 24B" },
|
||||||
|
{ id: "text-embedding-3-large", name: "Text Embedding 3 Large", kind: "embedding" },
|
||||||
|
{ id: "text-embedding-bge-m3", name: "BGE-M3 Embedding", kind: "embedding" },
|
||||||
|
{ id: "text-embedding-qwen3-8b", name: "Qwen3 8B Embedding", kind: "embedding" },
|
||||||
|
{ id: "venice-sd35", name: "Venice SD3.5", params: ["n", "size"], kind: "image" },
|
||||||
|
{ id: "flux-2-pro", name: "FLUX.2 Pro", params: ["n", "size"], kind: "image" },
|
||||||
|
{ id: "gpt-image-2", name: "GPT Image 2 (via Venice)", params: ["n", "size", "quality"], kind: "image" },
|
||||||
|
],
|
||||||
|
serviceKinds: ["llm", "embedding", "image"],
|
||||||
|
embeddingConfig: {
|
||||||
|
baseUrl: "https://api.venice.ai/api/v1/embeddings",
|
||||||
|
authType: "apikey",
|
||||||
|
authHeader: "bearer",
|
||||||
|
},
|
||||||
|
imageConfig: {
|
||||||
|
baseUrl: "https://api.venice.ai/api/v1/images/generations",
|
||||||
|
},
|
||||||
|
modelsFetcher: { url: "https://api.venice.ai/api/v1/models", type: "openai" },
|
||||||
|
passthroughModels: true,
|
||||||
|
};
|
||||||
41
tests/unit/venice-provider.test.js
Normal file
41
tests/unit/venice-provider.test.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import REGISTRY from "../../open-sse/providers/registry/index.js";
|
||||||
|
import { PROVIDERS, PROVIDER_MODELS } from "../../open-sse/providers/index.js";
|
||||||
|
|
||||||
|
describe("Venice AI provider", () => {
|
||||||
|
const venice = REGISTRY.find((e) => e.id === "venice");
|
||||||
|
|
||||||
|
it("is registered as an OpenAI-compatible apikey provider", () => {
|
||||||
|
expect(venice).toBeDefined();
|
||||||
|
expect(venice.category).toBe("apikey");
|
||||||
|
expect(venice.transport.baseUrl).toBe("https://api.venice.ai/api/v1/chat/completions");
|
||||||
|
expect(venice.alias).toBe("venice");
|
||||||
|
expect(venice.aliases).toContain("vn");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("enables dynamic model discovery and passthrough", () => {
|
||||||
|
expect(venice.passthroughModels).toBe(true);
|
||||||
|
expect(venice.modelsFetcher).toMatchObject({
|
||||||
|
url: "https://api.venice.ai/api/v1/models",
|
||||||
|
type: "openai",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds into the runtime PROVIDERS map with the openai format default", () => {
|
||||||
|
expect(PROVIDERS.venice).toBeDefined();
|
||||||
|
expect(PROVIDERS.venice.format).toBe("openai");
|
||||||
|
expect(PROVIDERS.venice.baseUrl).toBe("https://api.venice.ai/api/v1/chat/completions");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exposes its seed models (incl. the signature uncensored model)", () => {
|
||||||
|
const ids = (PROVIDER_MODELS.venice || []).map((m) => m.id);
|
||||||
|
expect(ids.length).toBeGreaterThan(0);
|
||||||
|
expect(ids).toContain("venice-uncensored-1-2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps every registry id unique after adding venice", () => {
|
||||||
|
const ids = REGISTRY.map((e) => e.id);
|
||||||
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user