feat(ai): add CoreWeave Serverless Inference provider
This commit is contained in:
@@ -77,6 +77,7 @@
|
||||
- Fixed OpenRouter Anthropic models on the Responses path omitting `cache_control`, so prompt caching engages without forcing Chat Completions. ([#3397](https://github.com/can1357/oh-my-pi/issues/3397))
|
||||
- Fixed OpenRouter Anthropic Responses follow-up requests replaying prior reasoning items with stale signatures, which caused HTTP 400 `Invalid signature in thinking block` errors after a thinking turn. ([#3399](https://github.com/can1357/oh-my-pi/issues/3399))
|
||||
- Fixed OpenRouter Anthropic models on the Responses path omitting `cache_control`, so prompt caching engages without forcing Chat Completions. `cacheRetention: "long"` now upgrades the breakpoint to `ttl: "1h"`. ([#3397](https://github.com/can1357/oh-my-pi/issues/3397))
|
||||
- Added CoreWeave Serverless Inference provider login support via `COREWEAVE_API_KEY` and `WANDB_API_KEY` fallback.
|
||||
|
||||
## [16.1.16] - 2026-06-23
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ import type {
|
||||
ResolvedOpenAISharedCompat,
|
||||
VercelGatewayRouting,
|
||||
} from "@oh-my-pi/pi-catalog/types";
|
||||
import {
|
||||
COREWEAVE_PROJECT_HEADER,
|
||||
coreWeaveProjectHeaders,
|
||||
hasCoreWeaveProjectHeader,
|
||||
} from "@oh-my-pi/pi-catalog/wire/coreweave";
|
||||
import { parseGitHubCopilotApiKey } from "@oh-my-pi/pi-catalog/wire/github-copilot";
|
||||
import { $env, extractHttpStatusFromError, logger, structuredCloneJSON } from "@oh-my-pi/pi-utils";
|
||||
import {
|
||||
@@ -141,6 +146,16 @@ function resolveSakanaRequestBaseUrl(): string | undefined {
|
||||
return normalizeSakanaRequestBaseUrl($env.SAKANA_BASE_URL) ?? normalizeSakanaRequestBaseUrl($env.FUGU_BASE_URL);
|
||||
}
|
||||
|
||||
function applyCoreWeaveProjectHeader(headers: Record<string, string>): void {
|
||||
if (hasCoreWeaveProjectHeader(headers)) {
|
||||
return;
|
||||
}
|
||||
const projectHeaders = coreWeaveProjectHeaders($env);
|
||||
if (projectHeaders) {
|
||||
headers[COREWEAVE_PROJECT_HEADER] = projectHeaders[COREWEAVE_PROJECT_HEADER];
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveOpenAIRequestSetup(
|
||||
model: OpenAIRequestSetupModel,
|
||||
options: OpenAIRequestSetupOptions,
|
||||
@@ -160,6 +175,9 @@ export function resolveOpenAIRequestSetup(
|
||||
Object.assign(headers, getOpenRouterHeaders());
|
||||
}
|
||||
Object.assign(headers, options.extraHeaders);
|
||||
if (model.provider === "coreweave") {
|
||||
applyCoreWeaveProjectHeader(headers);
|
||||
}
|
||||
if (options.prependHeaders) {
|
||||
headers = { ...options.prependHeaders(), ...headers };
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ type ModelsEndpointValidation = {
|
||||
kind: "models-endpoint";
|
||||
provider: string;
|
||||
modelsUrl: string;
|
||||
headers?: Record<string, string> | (() => Record<string, string> | undefined);
|
||||
};
|
||||
|
||||
export type ApiKeyLoginConfig = {
|
||||
@@ -98,6 +99,7 @@ export function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthCon
|
||||
provider: config.validation.provider,
|
||||
apiKey: trimmed,
|
||||
modelsUrl: config.validation.modelsUrl,
|
||||
headers: config.validation.headers,
|
||||
signal: options.signal,
|
||||
fetch: options.fetch,
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ type ModelListValidationOptions = {
|
||||
provider: string;
|
||||
apiKey: string;
|
||||
modelsUrl: string;
|
||||
headers?: Record<string, string> | (() => Record<string, string> | undefined);
|
||||
signal?: AbortSignal;
|
||||
fetch?: FetchImpl;
|
||||
};
|
||||
@@ -32,6 +33,12 @@ function normalizeAnthropicCompatibleBaseUrl(baseUrl: string): string {
|
||||
return trimmed.endsWith("/v1") ? trimmed.slice(0, -3) : trimmed;
|
||||
}
|
||||
|
||||
function resolveValidationHeaders(
|
||||
headers: Record<string, string> | (() => Record<string, string> | undefined) | undefined,
|
||||
): Record<string, string> | undefined {
|
||||
return typeof headers === "function" ? headers() : headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an API key against an OpenAI-compatible chat completions endpoint.
|
||||
*
|
||||
@@ -129,6 +136,7 @@ export async function validateApiKeyAgainstModelsEndpoint(options: ModelListVali
|
||||
const response = await fetchImpl(options.modelsUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
...(resolveValidationHeaders(options.headers) ?? {}),
|
||||
Authorization: `Bearer ${options.apiKey}`,
|
||||
},
|
||||
signal,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { coreWeaveProjectHeaders } from "@oh-my-pi/pi-catalog/wire/coreweave";
|
||||
import { $env } from "@oh-my-pi/pi-utils";
|
||||
import { createApiKeyLogin } from "./api-key-login";
|
||||
import type { OAuthLoginCallbacks } from "./oauth/types";
|
||||
import type { ProviderDefinition } from "./types";
|
||||
|
||||
const PROJECT_SETUP_INSTRUCTIONS =
|
||||
"Create or select a CoreWeave Serverless Inference project, set COREWEAVE_PROJECT=<team>/<project> for the OpenAI-Project header, then copy your API key from account settings";
|
||||
|
||||
function requireCoreWeaveProjectHeaders(): Record<string, string> {
|
||||
const headers = coreWeaveProjectHeaders($env);
|
||||
if (!headers) {
|
||||
throw new Error(
|
||||
"CoreWeave Serverless Inference requires OpenAI-Project. Set COREWEAVE_PROJECT=<team>/<project> before running /login coreweave.",
|
||||
);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
export const loginCoreWeave = createApiKeyLogin({
|
||||
providerLabel: "CoreWeave Serverless Inference",
|
||||
authUrl: "https://wandb.ai/settings",
|
||||
instructions: PROJECT_SETUP_INSTRUCTIONS,
|
||||
promptMessage: "Paste your CoreWeave Serverless Inference API key",
|
||||
placeholder: "api-key",
|
||||
validation: {
|
||||
kind: "models-endpoint",
|
||||
provider: "CoreWeave Serverless Inference",
|
||||
modelsUrl: "https://api.inference.wandb.ai/v1/models",
|
||||
headers: requireCoreWeaveProjectHeaders,
|
||||
},
|
||||
});
|
||||
|
||||
export const coreWeaveProvider = {
|
||||
id: "coreweave",
|
||||
name: "CoreWeave Serverless Inference",
|
||||
login: (cb: OAuthLoginCallbacks) => loginCoreWeave(cb),
|
||||
} as const satisfies ProviderDefinition;
|
||||
@@ -6,6 +6,7 @@ import { anthropicProvider } from "./anthropic";
|
||||
import { azureProvider } from "./azure";
|
||||
import { cerebrasProvider } from "./cerebras";
|
||||
import { cloudflareAiGatewayProvider } from "./cloudflare-ai-gateway";
|
||||
import { coreWeaveProvider } from "./coreweave";
|
||||
import { cursorProvider } from "./cursor";
|
||||
import { deepseekProvider } from "./deepseek";
|
||||
import { devinProvider } from "./devin";
|
||||
@@ -112,6 +113,7 @@ const ALL = [
|
||||
syntheticProvider,
|
||||
nanogptProvider,
|
||||
waferServerlessProvider,
|
||||
coreWeaveProvider,
|
||||
vercelAiGatewayProvider,
|
||||
cloudflareAiGatewayProvider,
|
||||
litellmProvider,
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { afterEach, describe, expect, test, vi } from "bun:test";
|
||||
import { loginCoreWeave } from "@oh-my-pi/pi-ai/registry/coreweave";
|
||||
import type { FetchImpl } from "@oh-my-pi/pi-ai/types";
|
||||
|
||||
const COREWEAVE_ENV_KEYS = ["COREWEAVE_PROJECT", "WANDB_INFERENCE_PROJECT", "WANDB_ENTITY", "WANDB_PROJECT"] as const;
|
||||
const ORIGINAL_ENV = new Map(COREWEAVE_ENV_KEYS.map(key => [key, Bun.env[key]]));
|
||||
|
||||
function restoreCoreWeaveEnv(): void {
|
||||
for (const key of COREWEAVE_ENV_KEYS) {
|
||||
const value = ORIGINAL_ENV.get(key);
|
||||
if (value === undefined) {
|
||||
delete Bun.env[key];
|
||||
} else {
|
||||
Bun.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
restoreCoreWeaveEnv();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("CoreWeave Serverless Inference login", () => {
|
||||
test("validates API key against the models endpoint with the project header", async () => {
|
||||
Bun.env.COREWEAVE_PROJECT = "team/project";
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
delete Bun.env.WANDB_ENTITY;
|
||||
delete Bun.env.WANDB_PROJECT;
|
||||
|
||||
const fetchMock: FetchImpl = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
|
||||
const url = typeof input === "string" ? input : input.toString();
|
||||
expect(url).toBe("https://api.inference.wandb.ai/v1/models");
|
||||
expect(init?.method).toBe("GET");
|
||||
expect(init?.headers).toEqual({
|
||||
"OpenAI-Project": "team/project",
|
||||
Authorization: "Bearer coreweave-test-key",
|
||||
});
|
||||
return new Response(JSON.stringify({ object: "list", data: [] }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
});
|
||||
|
||||
const authMessages: string[] = [];
|
||||
const apiKey = await loginCoreWeave({
|
||||
onAuth: auth => {
|
||||
if (auth.instructions) {
|
||||
authMessages.push(auth.instructions);
|
||||
}
|
||||
},
|
||||
onPrompt: async () => " coreweave-test-key ",
|
||||
fetch: fetchMock,
|
||||
});
|
||||
|
||||
expect(apiKey).toBe("coreweave-test-key");
|
||||
expect(authMessages[0]).toContain("COREWEAVE_PROJECT=<team>/<project>");
|
||||
expect(authMessages[0]).toContain("OpenAI-Project");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("requires a project header before validating the API key", async () => {
|
||||
delete Bun.env.COREWEAVE_PROJECT;
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
delete Bun.env.WANDB_ENTITY;
|
||||
delete Bun.env.WANDB_PROJECT;
|
||||
const fetchMock: FetchImpl = vi.fn(async () => {
|
||||
return new Response(JSON.stringify({ object: "list", data: [] }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
});
|
||||
|
||||
await expect(
|
||||
loginCoreWeave({
|
||||
onPrompt: async () => "coreweave-test-key",
|
||||
fetch: fetchMock,
|
||||
}),
|
||||
).rejects.toThrow("Set COREWEAVE_PROJECT=<team>/<project>");
|
||||
expect(fetchMock).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("surfaces validation errors from the CoreWeave Serverless Inference models endpoint", async () => {
|
||||
Bun.env.COREWEAVE_PROJECT = "team/project";
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
delete Bun.env.WANDB_ENTITY;
|
||||
delete Bun.env.WANDB_PROJECT;
|
||||
|
||||
const fetchMock: FetchImpl = vi.fn(async () => {
|
||||
return new Response("Unauthorized", {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
});
|
||||
});
|
||||
|
||||
await expect(
|
||||
loginCoreWeave({
|
||||
onPrompt: async () => "coreweave-test-key",
|
||||
fetch: fetchMock,
|
||||
}),
|
||||
).rejects.toThrow("CoreWeave Serverless Inference API key validation failed (401)");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import { resolveOpenAIRequestSetup } from "@oh-my-pi/pi-ai/providers/openai-shared";
|
||||
|
||||
const COREWEAVE_ENV_KEYS = ["COREWEAVE_PROJECT", "WANDB_INFERENCE_PROJECT", "WANDB_ENTITY", "WANDB_PROJECT"] as const;
|
||||
const ORIGINAL_ENV = new Map(COREWEAVE_ENV_KEYS.map(key => [key, Bun.env[key]]));
|
||||
|
||||
function restoreCoreWeaveEnv(): void {
|
||||
for (const key of COREWEAVE_ENV_KEYS) {
|
||||
const value = ORIGINAL_ENV.get(key);
|
||||
if (value === undefined) {
|
||||
delete Bun.env[key];
|
||||
} else {
|
||||
Bun.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
restoreCoreWeaveEnv();
|
||||
});
|
||||
|
||||
describe("CoreWeave Serverless Inference project header", () => {
|
||||
const coreWeaveModel = {
|
||||
provider: "coreweave",
|
||||
id: "zai-org/GLM-5.2",
|
||||
baseUrl: "https://api.inference.wandb.ai/v1",
|
||||
};
|
||||
|
||||
test("adds OpenAI-Project from COREWEAVE_PROJECT", () => {
|
||||
Bun.env.COREWEAVE_PROJECT = "team/project";
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
delete Bun.env.WANDB_ENTITY;
|
||||
delete Bun.env.WANDB_PROJECT;
|
||||
|
||||
const setup = resolveOpenAIRequestSetup(coreWeaveModel, {
|
||||
apiKey: "coreweave-key",
|
||||
messages: [],
|
||||
});
|
||||
|
||||
expect(setup.headers["OpenAI-Project"]).toBe("team/project");
|
||||
});
|
||||
|
||||
test("builds OpenAI-Project from W&B entity and project fallbacks", () => {
|
||||
delete Bun.env.COREWEAVE_PROJECT;
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
Bun.env.WANDB_ENTITY = "wandb-team";
|
||||
Bun.env.WANDB_PROJECT = "inference-project";
|
||||
|
||||
const setup = resolveOpenAIRequestSetup(coreWeaveModel, {
|
||||
apiKey: "coreweave-key",
|
||||
messages: [],
|
||||
});
|
||||
|
||||
expect(setup.headers["OpenAI-Project"]).toBe("wandb-team/inference-project");
|
||||
});
|
||||
|
||||
test("preserves an explicit request project header", () => {
|
||||
Bun.env.COREWEAVE_PROJECT = "team/project";
|
||||
|
||||
const setup = resolveOpenAIRequestSetup(coreWeaveModel, {
|
||||
apiKey: "coreweave-key",
|
||||
extraHeaders: { "openai-project": "explicit/team" },
|
||||
messages: [],
|
||||
});
|
||||
|
||||
expect(setup.headers["openai-project"]).toBe("explicit/team");
|
||||
expect(setup.headers["OpenAI-Project"]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -14,11 +14,13 @@ import { getEnvApiKey } from "@oh-my-pi/pi-ai/stream";
|
||||
|
||||
const FIXTURE_SOURCE = "provider-registry-test";
|
||||
const ENV_KEYS = [
|
||||
"COREWEAVE_API_KEY",
|
||||
"ZENMUX_API_KEY",
|
||||
"EXA_API_KEY",
|
||||
"XAI_OAUTH_TOKEN",
|
||||
"UMANS_AI_CODING_PLAN_API_KEY",
|
||||
"LLAMA_CPP_API_KEY",
|
||||
"WANDB_API_KEY",
|
||||
] as const;
|
||||
const originalEnv = new Map(ENV_KEYS.map(key => [key, Bun.env[key]]));
|
||||
|
||||
@@ -52,6 +54,11 @@ describe("provider registry auth surface", () => {
|
||||
test("multi-var catalog env fallback picks names in order", () => {
|
||||
Bun.env.XAI_OAUTH_TOKEN = "xai-oauth-env";
|
||||
expect(getEnvApiKey("xai-oauth")).toBe("xai-oauth-env");
|
||||
|
||||
Bun.env.WANDB_API_KEY = "wandb-env";
|
||||
expect(getEnvApiKey("coreweave")).toBe("wandb-env");
|
||||
Bun.env.COREWEAVE_API_KEY = "coreweave-env";
|
||||
expect(getEnvApiKey("coreweave")).toBe("coreweave-env");
|
||||
});
|
||||
|
||||
test("login list contains loginable providers and excludes env-only model providers", () => {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- Fixed the Umans GLM-5.2 thinking-level picker collapsing to a single `high` tier after dynamic discovery: the `max` upstream level now resolves to the internal `xhigh` effort, the picker shows both `high` and `xhigh`, and the metadata maps `xhigh` back to Umans's native `max` wire tier. ([#3192](https://github.com/can1357/oh-my-pi/issues/3192))
|
||||
- Fixed GitHub Copilot business and enterprise endpoints accepting image inputs that they reject with `400 vision is not supported`. The Copilot `/models` response advertises `capabilities.supports.vision = true` for Claude/GPT chat models on every host, but only the canonical personal endpoint (`https://api.githubcopilot.com`) actually serves them; `githubCopilotModelManagerOptions` now forces `input: ["text"]` whenever discovery resolves to a non-personal base URL, and `mergeDynamicModel` honours the dynamic value (instead of OR-upgrading) when the merged endpoint differs from the bundled reference. ([#3387](https://github.com/can1357/oh-my-pi/issues/3387))
|
||||
- Fixed OpenRouter Anthropic compat to strip Responses reasoning history during replay so signed thinking blocks are not sent back to routed Anthropic providers. ([#3399](https://github.com/can1357/oh-my-pi/issues/3399))
|
||||
- Added CoreWeave Serverless Inference as an OpenAI-compatible provider with models.dev-backed bundled catalog metadata.
|
||||
|
||||
## [16.1.14] - 2026-06-22
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ const packageRoot = path.join(import.meta.dir, "..");
|
||||
* and never written to models.json.
|
||||
*/
|
||||
const DISCOVERY_ONLY_PROVIDERS = new Set(["ollama", "vllm", "lm-studio", "litellm"]);
|
||||
const RETIRED_PROVIDERS = new Set(["wafer-pass"]);
|
||||
const RETIRED_PROVIDERS = new Set(["wafer-pass", "wandb"]);
|
||||
|
||||
async function resolveProviderApiKey(providerId: string, catalog: CatalogDiscoveryConfig): Promise<string | undefined> {
|
||||
for (const envVar of catalog.envVars ?? []) {
|
||||
|
||||
@@ -12,5 +12,6 @@ export * from "./types";
|
||||
export * from "./utils";
|
||||
export * from "./variant-collapse";
|
||||
export * from "./wire/codex";
|
||||
export * from "./wire/coreweave";
|
||||
export * from "./wire/gemini-headers";
|
||||
export * from "./wire/github-copilot";
|
||||
|
||||
@@ -13487,6 +13487,786 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"coreweave": {
|
||||
"deepseek-ai/DeepSeek-V3.1": {
|
||||
"id": "deepseek-ai/DeepSeek-V3.1",
|
||||
"name": "DeepSeek V3.1",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.55,
|
||||
"output": 1.65,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 161000,
|
||||
"maxTokens": 161000
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V4-Flash": {
|
||||
"id": "deepseek-ai/DeepSeek-V4-Flash",
|
||||
"name": "DeepSeek V4 Flash",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1048576,
|
||||
"maxTokens": 384000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
],
|
||||
"effortMap": {
|
||||
"minimal": "high",
|
||||
"low": "high",
|
||||
"medium": "high",
|
||||
"high": "high",
|
||||
"xhigh": "max"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V4-Pro": {
|
||||
"id": "deepseek-ai/DeepSeek-V4-Pro",
|
||||
"name": "DeepSeek V4 Pro",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1048576,
|
||||
"maxTokens": 393216,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
],
|
||||
"effortMap": {
|
||||
"minimal": "high",
|
||||
"low": "high",
|
||||
"medium": "high",
|
||||
"high": "high",
|
||||
"xhigh": "max"
|
||||
}
|
||||
}
|
||||
},
|
||||
"google/gemma-4-31B-it": {
|
||||
"id": "google/gemma-4-31B-it",
|
||||
"name": "Gemma 4 31B Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 131072,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ibm-granite/granite-4.1-8b": {
|
||||
"id": "ibm-granite/granite-4.1-8b",
|
||||
"name": "Granite 4.1 8B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072
|
||||
},
|
||||
"JetBrains/Mellum2-12B-A2.5B-Instruct": {
|
||||
"id": "JetBrains/Mellum2-12B-A2.5B-Instruct",
|
||||
"name": "JetBrains/Mellum2-12B-A2.5B-Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": null,
|
||||
"maxTokens": null
|
||||
},
|
||||
"meta-llama/Llama-3.1-70B-Instruct": {
|
||||
"id": "meta-llama/Llama-3.1-70B-Instruct",
|
||||
"name": "Llama 3.1 70B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.8,
|
||||
"output": 0.8,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 128000
|
||||
},
|
||||
"meta-llama/Llama-3.1-8B-Instruct": {
|
||||
"id": "meta-llama/Llama-3.1-8B-Instruct",
|
||||
"name": "Meta-Llama-3.1-8B-Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.22,
|
||||
"output": 0.22,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 128000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"meta-llama/Llama-3.3-70B-Instruct": {
|
||||
"id": "meta-llama/Llama-3.3-70B-Instruct",
|
||||
"name": "Llama-3.3-70B-Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.71,
|
||||
"output": 0.71,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 128000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"meta-llama/Llama-4-Scout-17B-16E-Instruct": {
|
||||
"id": "meta-llama/Llama-4-Scout-17B-16E-Instruct",
|
||||
"name": "Llama 4 Scout 17B 16E Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.17,
|
||||
"output": 0.66,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 64000,
|
||||
"maxTokens": 64000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"microsoft/Phi-4-mini-instruct": {
|
||||
"id": "microsoft/Phi-4-mini-instruct",
|
||||
"name": "Phi-4-mini-instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.08,
|
||||
"output": 0.35,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 128000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"MiniMaxAI/MiniMax-M2.5": {
|
||||
"id": "MiniMaxAI/MiniMax-M2.5",
|
||||
"name": "MiniMax M2.5",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 196608,
|
||||
"maxTokens": 196608
|
||||
},
|
||||
"moonshotai/Kimi-K2.5": {
|
||||
"id": "moonshotai/Kimi-K2.5",
|
||||
"name": "Kimi K2.5",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.5,
|
||||
"output": 2.85,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"moonshotai/Kimi-K2.6": {
|
||||
"id": "moonshotai/Kimi-K2.6",
|
||||
"name": "Kimi-K2.6",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"moonshotai/Kimi-K2.7-Code": {
|
||||
"id": "moonshotai/Kimi-K2.7-Code",
|
||||
"name": "Kimi K2.7 Code",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8": {
|
||||
"id": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8",
|
||||
"name": "NVIDIA Nemotron 3 Super 120B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.2,
|
||||
"output": 0.8,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144
|
||||
},
|
||||
"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": {
|
||||
"id": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
|
||||
"name": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": null,
|
||||
"maxTokens": null
|
||||
},
|
||||
"openai/gpt-oss-120b": {
|
||||
"id": "openai/gpt-oss-120b",
|
||||
"name": "gpt-oss-120b",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.15,
|
||||
"output": 0.6,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072
|
||||
},
|
||||
"openai/gpt-oss-20b": {
|
||||
"id": "openai/gpt-oss-20b",
|
||||
"name": "gpt-oss-20b",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.05,
|
||||
"output": 0.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072
|
||||
},
|
||||
"OpenPipe/Qwen3-14B-Instruct": {
|
||||
"id": "OpenPipe/Qwen3-14B-Instruct",
|
||||
"name": "OpenPipe Qwen3 14B Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.05,
|
||||
"output": 0.22,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 32768,
|
||||
"maxTokens": 32768
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B-Instruct-2507": {
|
||||
"id": "Qwen/Qwen3-235B-A22B-Instruct-2507",
|
||||
"name": "Qwen3 235B A22B Instruct 2507",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.1,
|
||||
"output": 0.1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B-Thinking-2507": {
|
||||
"id": "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
"name": "Qwen3-235B-A22B-Thinking-2507",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.1,
|
||||
"output": 0.1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
],
|
||||
"requiresEffort": true
|
||||
}
|
||||
},
|
||||
"Qwen/Qwen3-30B-A3B-Instruct-2507": {
|
||||
"id": "Qwen/Qwen3-30B-A3B-Instruct-2507",
|
||||
"name": "Qwen3 30B A3B Instruct 2507",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0.1,
|
||||
"output": 0.3,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144
|
||||
},
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct": {
|
||||
"id": "Qwen/Qwen3-Coder-480B-A35B-Instruct",
|
||||
"name": "Qwen3-Coder-480B-A35B-Instruct",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 1,
|
||||
"output": 1.5,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144
|
||||
},
|
||||
"Qwen/Qwen3.5-27B": {
|
||||
"id": "Qwen/Qwen3.5-27B",
|
||||
"name": "Qwen3.5 27B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Qwen/Qwen3.5-35B-A3B": {
|
||||
"id": "Qwen/Qwen3.5-35B-A3B",
|
||||
"name": "Qwen3.5 35B-A3B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Qwen/Qwen3.6-27B": {
|
||||
"id": "Qwen/Qwen3.6-27B",
|
||||
"name": "Qwen3.6 27B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Qwen/Qwen3.6-35B-A3B": {
|
||||
"id": "Qwen/Qwen3.6-35B-A3B",
|
||||
"name": "Qwen3.6 35B-A3B",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text",
|
||||
"image"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
]
|
||||
}
|
||||
},
|
||||
"zai-org/GLM-5-FP8": {
|
||||
"id": "zai-org/GLM-5-FP8",
|
||||
"name": "GLM 5",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": false,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 1,
|
||||
"output": 3.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 200000,
|
||||
"maxTokens": 200000
|
||||
},
|
||||
"zai-org/GLM-5.1": {
|
||||
"id": "zai-org/GLM-5.1",
|
||||
"name": "GLM-5.1",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 1.4,
|
||||
"output": 4.4,
|
||||
"cacheRead": 0.26,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 200000,
|
||||
"maxTokens": 131072,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
},
|
||||
"zai-org/GLM-5.2": {
|
||||
"id": "zai-org/GLM-5.2",
|
||||
"name": "GLM-5.2",
|
||||
"api": "openai-completions",
|
||||
"provider": "coreweave",
|
||||
"baseUrl": "https://api.inference.wandb.ai/v1",
|
||||
"reasoning": true,
|
||||
"input": [
|
||||
"text"
|
||||
],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 164000,
|
||||
"thinking": {
|
||||
"mode": "effort",
|
||||
"efforts": [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"cursor": {
|
||||
"claude-4.5-opus-high": {
|
||||
"id": "claude-4.5-opus-high",
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
anthropicModelManagerOptions,
|
||||
cerebrasModelManagerOptions,
|
||||
cloudflareAiGatewayModelManagerOptions,
|
||||
coreWeaveModelManagerOptions,
|
||||
deepseekModelManagerOptions,
|
||||
firepassModelManagerOptions,
|
||||
fireworksModelManagerOptions,
|
||||
@@ -375,6 +376,13 @@ export const CATALOG_PROVIDERS = [
|
||||
oauthProvider: "wafer-serverless",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "coreweave",
|
||||
defaultModel: "openai/gpt-oss-120b",
|
||||
envVars: ["COREWEAVE_API_KEY", "WANDB_API_KEY"],
|
||||
createModelManagerOptions: (config: ModelManagerConfig) => coreWeaveModelManagerOptions(config),
|
||||
catalogDiscovery: { label: "CoreWeave Serverless Inference" },
|
||||
},
|
||||
{
|
||||
id: "xai",
|
||||
defaultModel: "grok-4-fast-non-reasoning",
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { ModelManagerOptions } from "../model-manager";
|
||||
import { getBundledModels } from "../models";
|
||||
import type { Api, FetchImpl, Model, ModelSpec, Provider, ThinkingConfig } from "../types";
|
||||
import { isAnthropicOAuthToken, isRecord, toBoolean, toNumber, toPositiveNumber } from "../utils";
|
||||
import { coreWeaveProjectHeaders } from "../wire/coreweave";
|
||||
import {
|
||||
COPILOT_API_HEADERS,
|
||||
getGitHubCopilotBaseUrl,
|
||||
@@ -470,7 +471,19 @@ function isLikelyNanoGptTextModelId(id: string): boolean {
|
||||
return !NANO_GPT_NON_TEXT_MODEL_TOKENS.some(token => normalized.includes(token));
|
||||
}
|
||||
|
||||
type SimpleProviderConfig = { apiKey?: string; baseUrl?: string; fetch?: FetchImpl };
|
||||
type SimpleProviderDiscoveryHeaders = Record<string, string> | (() => Record<string, string> | undefined);
|
||||
type SimpleProviderConfig = {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
fetch?: FetchImpl;
|
||||
headers?: SimpleProviderDiscoveryHeaders;
|
||||
};
|
||||
|
||||
function resolveSimpleProviderHeaders(
|
||||
headers: SimpleProviderDiscoveryHeaders | undefined,
|
||||
): Record<string, string> | undefined {
|
||||
return typeof headers === "function" ? headers() : headers;
|
||||
}
|
||||
|
||||
export function createSimpleOpenAICompletionsOptions(
|
||||
providerId: Parameters<typeof getBundledModels>[0],
|
||||
@@ -489,6 +502,7 @@ export function createSimpleOpenAICompletionsOptions(
|
||||
provider: providerId,
|
||||
baseUrl,
|
||||
apiKey,
|
||||
headers: resolveSimpleProviderHeaders(config?.headers),
|
||||
mapModel: (entry, defaults) => {
|
||||
const reference = references.get(defaults.id);
|
||||
return mapWithBundledReference(entry, defaults, reference);
|
||||
@@ -516,6 +530,7 @@ function createSimpleOpenAIResponsesOptions(
|
||||
provider: providerId,
|
||||
baseUrl,
|
||||
apiKey,
|
||||
headers: resolveSimpleProviderHeaders(config?.headers),
|
||||
mapModel: (entry, defaults) => {
|
||||
const reference = references.get(defaults.id);
|
||||
return mapWithBundledReference(entry, defaults, reference);
|
||||
@@ -2480,6 +2495,25 @@ export function togetherModelManagerOptions(
|
||||
return createSimpleOpenAICompletionsOptions("together", "https://api.together.xyz/v1", config);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 15.5 CoreWeave Serverless Inference
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface CoreWeaveModelManagerConfig {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
fetch?: FetchImpl;
|
||||
}
|
||||
|
||||
export function coreWeaveModelManagerOptions(
|
||||
config?: CoreWeaveModelManagerConfig,
|
||||
): ModelManagerOptions<"openai-completions"> {
|
||||
return createSimpleOpenAICompletionsOptions("coreweave", "https://api.inference.wandb.ai/v1", {
|
||||
...config,
|
||||
headers: () => coreWeaveProjectHeaders(Bun.env),
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 16. Moonshot
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -3653,6 +3687,8 @@ const MODELS_DEV_PROVIDER_DESCRIPTORS_CORE: readonly ModelsDevProviderDescriptor
|
||||
openAiCompletionsDescriptor("cerebras", "cerebras", "https://api.cerebras.ai/v1"),
|
||||
// --- Together ---
|
||||
openAiCompletionsDescriptor("togetherai", "together", "https://api.together.xyz/v1"),
|
||||
// --- CoreWeave Serverless Inference ---
|
||||
openAiCompletionsDescriptor("wandb", "coreweave", "https://api.inference.wandb.ai/v1"),
|
||||
// --- NVIDIA ---
|
||||
openAiCompletionsDescriptor("nvidia", "nvidia", "https://integrate.api.nvidia.com/v1", {
|
||||
defaultContextWindow: 131072,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
export const COREWEAVE_PROJECT_HEADER = "OpenAI-Project" as const;
|
||||
|
||||
export interface CoreWeaveProjectEnv {
|
||||
[key: string]: string | undefined;
|
||||
COREWEAVE_PROJECT?: string;
|
||||
WANDB_INFERENCE_PROJECT?: string;
|
||||
WANDB_ENTITY?: string;
|
||||
WANDB_PROJECT?: string;
|
||||
}
|
||||
|
||||
function cleanEnvValue(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
export function resolveCoreWeaveProject(env: CoreWeaveProjectEnv): string | undefined {
|
||||
const explicitProject = cleanEnvValue(env.COREWEAVE_PROJECT) ?? cleanEnvValue(env.WANDB_INFERENCE_PROJECT);
|
||||
if (explicitProject) {
|
||||
return explicitProject;
|
||||
}
|
||||
|
||||
const wandbProject = cleanEnvValue(env.WANDB_PROJECT);
|
||||
if (!wandbProject) {
|
||||
return undefined;
|
||||
}
|
||||
if (wandbProject.includes("/")) {
|
||||
return wandbProject;
|
||||
}
|
||||
|
||||
const wandbEntity = cleanEnvValue(env.WANDB_ENTITY);
|
||||
return wandbEntity ? `${wandbEntity}/${wandbProject}` : undefined;
|
||||
}
|
||||
|
||||
export function coreWeaveProjectHeaders(env: CoreWeaveProjectEnv): Record<string, string> | undefined {
|
||||
const project = resolveCoreWeaveProject(env);
|
||||
return project ? { [COREWEAVE_PROJECT_HEADER]: project } : undefined;
|
||||
}
|
||||
|
||||
export function hasCoreWeaveProjectHeader(headers: Record<string, string>): boolean {
|
||||
const normalized = COREWEAVE_PROJECT_HEADER.toLowerCase();
|
||||
return Object.keys(headers).some(header => header.toLowerCase() === normalized);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { afterEach, describe, expect, test, vi } from "bun:test";
|
||||
import { getBundledModels } from "@oh-my-pi/pi-catalog/models";
|
||||
import { DEFAULT_MODEL_PER_PROVIDER, PROVIDER_DESCRIPTORS } from "@oh-my-pi/pi-catalog/provider-models/descriptors";
|
||||
import {
|
||||
coreWeaveModelManagerOptions,
|
||||
MODELS_DEV_PROVIDER_DESCRIPTORS,
|
||||
mapModelsDevToModels,
|
||||
} from "@oh-my-pi/pi-catalog/provider-models/openai-compat";
|
||||
import type { FetchImpl } from "@oh-my-pi/pi-catalog/types";
|
||||
|
||||
const COREWEAVE_ENV_KEYS = ["COREWEAVE_PROJECT", "WANDB_INFERENCE_PROJECT", "WANDB_ENTITY", "WANDB_PROJECT"] as const;
|
||||
const ORIGINAL_ENV = new Map(COREWEAVE_ENV_KEYS.map(key => [key, Bun.env[key]]));
|
||||
|
||||
function restoreCoreWeaveEnv(): void {
|
||||
for (const key of COREWEAVE_ENV_KEYS) {
|
||||
const value = ORIGINAL_ENV.get(key);
|
||||
if (value === undefined) {
|
||||
delete Bun.env[key];
|
||||
} else {
|
||||
Bun.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
restoreCoreWeaveEnv();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("CoreWeave Serverless Inference provider support", () => {
|
||||
test("registers descriptor, default model, environment key, and bundled models", () => {
|
||||
const descriptor = PROVIDER_DESCRIPTORS.find(item => item.providerId === "coreweave");
|
||||
expect(descriptor).toBeDefined();
|
||||
expect(descriptor?.defaultModel).toBe("openai/gpt-oss-120b");
|
||||
expect(descriptor?.catalogDiscovery?.label).toBe("CoreWeave Serverless Inference");
|
||||
expect(descriptor?.catalogDiscovery?.envVars).toEqual(["COREWEAVE_API_KEY", "WANDB_API_KEY"]);
|
||||
expect(DEFAULT_MODEL_PER_PROVIDER.coreweave).toBe("openai/gpt-oss-120b");
|
||||
|
||||
const bundled = getBundledModels("coreweave");
|
||||
expect(bundled.find(model => model.id === "openai/gpt-oss-120b")).toMatchObject({
|
||||
api: "openai-completions",
|
||||
provider: "coreweave",
|
||||
baseUrl: "https://api.inference.wandb.ai/v1",
|
||||
});
|
||||
});
|
||||
|
||||
test("discovers dynamic models with the CoreWeave project header", async () => {
|
||||
Bun.env.COREWEAVE_PROJECT = "team/project";
|
||||
delete Bun.env.WANDB_INFERENCE_PROJECT;
|
||||
delete Bun.env.WANDB_ENTITY;
|
||||
delete Bun.env.WANDB_PROJECT;
|
||||
|
||||
const calls: Array<{ url: string; authorization: string | null; project: string | null }> = [];
|
||||
const fetchMock: FetchImpl = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers);
|
||||
calls.push({
|
||||
url: input.toString(),
|
||||
authorization: headers.get("authorization"),
|
||||
project: headers.get("openai-project"),
|
||||
});
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
data: [{ id: "openai/gpt-oss-120b", name: "GPT OSS 120B" }, { id: "meta-llama/Llama-3.1-8B-Instruct" }],
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}) as unknown as FetchImpl;
|
||||
|
||||
const options = coreWeaveModelManagerOptions({ apiKey: "coreweave-test-key", fetch: fetchMock });
|
||||
const models = await options.fetchDynamicModels?.();
|
||||
|
||||
expect(options.providerId).toBe("coreweave");
|
||||
expect(calls).toEqual([
|
||||
{
|
||||
url: "https://api.inference.wandb.ai/v1/models",
|
||||
authorization: "Bearer coreweave-test-key",
|
||||
project: "team/project",
|
||||
},
|
||||
]);
|
||||
expect(models?.find(model => model.id === "openai/gpt-oss-120b")).toMatchObject({
|
||||
id: "openai/gpt-oss-120b",
|
||||
name: "GPT OSS 120B",
|
||||
api: "openai-completions",
|
||||
provider: "coreweave",
|
||||
baseUrl: "https://api.inference.wandb.ai/v1",
|
||||
});
|
||||
});
|
||||
|
||||
test("maps models.dev wandb metadata into OpenAI chat completions models", () => {
|
||||
const mapped = mapModelsDevToModels(
|
||||
{
|
||||
wandb: {
|
||||
models: {
|
||||
"openai/gpt-oss-120b": {
|
||||
id: "openai/gpt-oss-120b",
|
||||
name: "GPT OSS 120B",
|
||||
tool_call: true,
|
||||
reasoning: true,
|
||||
modalities: { input: ["text"] },
|
||||
limit: { context: 131072, output: 32768 },
|
||||
cost: { input: 0.15, output: 0.6 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MODELS_DEV_PROVIDER_DESCRIPTORS,
|
||||
);
|
||||
|
||||
expect(mapped.find(model => model.provider === "coreweave")).toMatchObject({
|
||||
id: "openai/gpt-oss-120b",
|
||||
name: "GPT OSS 120B",
|
||||
api: "openai-completions",
|
||||
provider: "coreweave",
|
||||
baseUrl: "https://api.inference.wandb.ai/v1",
|
||||
reasoning: true,
|
||||
contextWindow: 131072,
|
||||
maxTokens: 32768,
|
||||
cost: { input: 0.15, output: 0.6, cacheRead: 0, cacheWrite: 0 },
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user