mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-13 07:40:18 +00:00
Add OpenRouter as an OpenAI-compatible reseller provider
Descriptor + curated matrix rows + sk-or- key auto-detect (server and GUI).
This commit is contained in:
@@ -11,8 +11,8 @@ falls back to the conservative heuristics in ``capabilities.py`` at their own ri
|
|||||||
degraded results. Ids verified against vendor/reseller catalogs on 2026-07-04; refresh the
|
degraded results. Ids verified against vendor/reseller catalogs on 2026-07-04; refresh the
|
||||||
reseller rows when catalogs rotate (they rename on every model generation).
|
reseller rows when catalogs rotate (they rename on every model generation).
|
||||||
|
|
||||||
Resellers: Together + Fireworks for now. TODO: add Groq and OpenRouter entries here AND their
|
Resellers: Together + Fireworks + OpenRouter. TODO: add Groq entries here AND its
|
||||||
descriptors in ``registry.py`` once the current provider surface is tested — deliberately
|
descriptor in ``registry.py`` once the current provider surface is tested — deliberately
|
||||||
deferred to bound how much needs verifying at once.
|
deferred to bound how much needs verifying at once.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -112,6 +112,14 @@ MATRIX: dict[str, ModelEntry] = {
|
|||||||
"fireworks:accounts/fireworks/models/llama4-maverick-instruct-basic": ModelEntry(
|
"fireworks:accounts/fireworks/models/llama4-maverick-instruct-basic": ModelEntry(
|
||||||
"Llama 4 Maverick · via Fireworks"
|
"Llama 4 Maverick · via Fireworks"
|
||||||
),
|
),
|
||||||
|
# OpenRouter slugs are lowercase `<lab>/<model>` (checked against their catalog
|
||||||
|
# 2026-07-25); same labs as above, one key for all of them.
|
||||||
|
"openrouter:z-ai/glm-5.2": ModelEntry("GLM-5.2 · via OpenRouter"),
|
||||||
|
"openrouter:moonshotai/kimi-k2.6": ModelEntry("Kimi K2.6 · via OpenRouter"),
|
||||||
|
"openrouter:deepseek/deepseek-v4-pro": ModelEntry("DeepSeek V4 Pro · via OpenRouter"),
|
||||||
|
"openrouter:meta-llama/llama-4-maverick": ModelEntry(
|
||||||
|
"Llama 4 Maverick · via OpenRouter"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ DESCRIPTORS: list[ProviderDescriptor] = [
|
|||||||
secret=False,
|
secret=False,
|
||||||
required=False,
|
required=False,
|
||||||
placeholder="https://…/openai/v1",
|
placeholder="https://…/openai/v1",
|
||||||
help="For Azure OpenAI, OpenRouter, vLLM, or any OpenAI-compliant server. Leave blank for api.openai.com.",
|
help="For Azure OpenAI, vLLM, or any OpenAI-compliant server. Leave blank for api.openai.com.",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
build=_build_openai,
|
build=_build_openai,
|
||||||
@@ -316,9 +316,9 @@ DESCRIPTORS: list[ProviderDescriptor] = [
|
|||||||
endpoint_help="Prefilled with the Meta Model API endpoint (public preview, US-only as of 2026-07).",
|
endpoint_help="Prefilled with the Meta Model API endpoint (public preview, US-only as of 2026-07).",
|
||||||
),
|
),
|
||||||
# Resellers: many labs' models behind one key, using THEIR model namespaces (the curated
|
# Resellers: many labs' models behind one key, using THEIR model namespaces (the curated
|
||||||
# ids + display labels live in providers/matrix.py). TODO: add Groq and OpenRouter here
|
# ids + display labels live in providers/matrix.py). TODO: add Groq here (+ its matrix
|
||||||
# (+ their matrix rows) once the current provider surface is tested — deliberately
|
# rows) once the current provider surface is tested — deliberately deferred to bound
|
||||||
# deferred to bound how much needs verifying at once (owner call, 2026-07-04).
|
# how much needs verifying at once (owner call, 2026-07-04).
|
||||||
_compat(
|
_compat(
|
||||||
"together",
|
"together",
|
||||||
"Together AI",
|
"Together AI",
|
||||||
@@ -333,6 +333,13 @@ DESCRIPTORS: list[ProviderDescriptor] = [
|
|||||||
recommended_model="accounts/fireworks/models/glm-5p2",
|
recommended_model="accounts/fireworks/models/glm-5p2",
|
||||||
env_key="FIREWORKS_API_KEY",
|
env_key="FIREWORKS_API_KEY",
|
||||||
),
|
),
|
||||||
|
_compat(
|
||||||
|
"openrouter",
|
||||||
|
"OpenRouter",
|
||||||
|
base_url="https://openrouter.ai/api/v1",
|
||||||
|
recommended_model="z-ai/glm-5.2",
|
||||||
|
env_key="OPENROUTER_API_KEY",
|
||||||
|
),
|
||||||
ProviderDescriptor(
|
ProviderDescriptor(
|
||||||
name="ollama",
|
name="ollama",
|
||||||
title="Ollama (local models)",
|
title="Ollama (local models)",
|
||||||
@@ -386,6 +393,8 @@ def detect_provider(api_key: str) -> Optional[str]:
|
|||||||
return None
|
return None
|
||||||
if key.startswith("sk-ant-"):
|
if key.startswith("sk-ant-"):
|
||||||
return "anthropic"
|
return "anthropic"
|
||||||
|
if key.startswith("sk-or-"):
|
||||||
|
return "openrouter"
|
||||||
if key.startswith("AIza"):
|
if key.startswith("AIza"):
|
||||||
return "gemini"
|
return "gemini"
|
||||||
if key.startswith(("sk-", "sk_")):
|
if key.startswith(("sk-", "sk_")):
|
||||||
|
|||||||
@@ -1324,6 +1324,7 @@ export function detectProvider(apiKey: string): string | null {
|
|||||||
const key = (apiKey || "").trim();
|
const key = (apiKey || "").trim();
|
||||||
if (!key) return null;
|
if (!key) return null;
|
||||||
if (key.startsWith("sk-ant-")) return "anthropic";
|
if (key.startsWith("sk-ant-")) return "anthropic";
|
||||||
|
if (key.startsWith("sk-or-")) return "openrouter";
|
||||||
if (key.startsWith("AIza")) return "gemini";
|
if (key.startsWith("AIza")) return "gemini";
|
||||||
if (key.startsWith("sk-") || key.startsWith("sk_")) return "openai";
|
if (key.startsWith("sk-") || key.startsWith("sk_")) return "openai";
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from coworker.providers import detect_provider, verify_provider_key
|
|||||||
"key,expected",
|
"key,expected",
|
||||||
[
|
[
|
||||||
("sk-ant-api03-abc", "anthropic"),
|
("sk-ant-api03-abc", "anthropic"),
|
||||||
|
("sk-or-v1-abc", "openrouter"),
|
||||||
("AIzaSyAbc123", "gemini"),
|
("AIzaSyAbc123", "gemini"),
|
||||||
("sk-proj-abc", "openai"),
|
("sk-proj-abc", "openai"),
|
||||||
("sk_live_abc", "openai"),
|
("sk_live_abc", "openai"),
|
||||||
|
|||||||
@@ -381,6 +381,8 @@ def test_matrix_answers_capabilities_for_reseller_ids():
|
|||||||
"together:zai-org/GLM-5.2",
|
"together:zai-org/GLM-5.2",
|
||||||
"together:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
|
"together:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
|
||||||
"fireworks:accounts/fireworks/models/kimi-k2p6",
|
"fireworks:accounts/fireworks/models/kimi-k2p6",
|
||||||
|
"openrouter:z-ai/glm-5.2",
|
||||||
|
"openrouter:meta-llama/llama-4-maverick",
|
||||||
):
|
):
|
||||||
caps = capabilities_for(mid)
|
caps = capabilities_for(mid)
|
||||||
assert caps.tools and caps.parallel_tool_calls and caps.streaming
|
assert caps.tools and caps.parallel_tool_calls and caps.streaming
|
||||||
@@ -402,12 +404,12 @@ def test_matrix_labels_and_custom_model_fallback():
|
|||||||
|
|
||||||
|
|
||||||
def test_reseller_descriptors_and_matrix_stay_in_lockstep():
|
def test_reseller_descriptors_and_matrix_stay_in_lockstep():
|
||||||
"""Together/Fireworks suggested models derive from the matrix, and each descriptor's
|
"""Reseller suggested models derive from the matrix, and each descriptor's
|
||||||
recommended model must be one of them (set_provider's auto-add depends on it)."""
|
recommended model must be one of them (set_provider's auto-add depends on it)."""
|
||||||
from coworker.providers.matrix import models_for_provider
|
from coworker.providers.matrix import models_for_provider
|
||||||
from coworker.providers.registry import get_descriptor
|
from coworker.providers.registry import get_descriptor
|
||||||
|
|
||||||
for name in ("together", "fireworks"):
|
for name in ("together", "fireworks", "openrouter"):
|
||||||
d = get_descriptor(name)
|
d = get_descriptor(name)
|
||||||
assert d is not None and d.needs_key
|
assert d is not None and d.needs_key
|
||||||
curated = models_for_provider(name)
|
curated = models_for_provider(name)
|
||||||
|
|||||||
Reference in New Issue
Block a user