feat(providers): single-source registry driving Hermes/Dirac/MCP/portal surfaces
Adds .aurelio/providers/registry.yaml as the one source of truth for every provider the fleet exposes (openrouter, openai-codex, nous, zai, kimi-coding, kimi-coding-cn, minimax, minimax-cn, bedrock, openai, anthropic, gemini, moonshot, qwen, qwen-code, alibaba-cloud, claude-code, antigravity, mimocode, local). Each entry carries kind/auth/protocol/models/context/surfaces/streaming + fallback. scripts/generate-provider-mirrors.py emits three generated mirrors under .aurelio/providers/dist/ and can patch Dirac's providers.json in place: - portal.providers.json -> aurelio-theia ProviderCatalog / Gabinete Hub - mcp.providers.json -> model_router.py runtime registry - dirac.providers.json -> Dirac picker shape --check exits non-zero when dist/ is stale (CI guard).
This commit is contained in:
parent
137a594abe
commit
dff3ecebc8
6 changed files with 1191 additions and 0 deletions
80
.aurelio/providers/dist/dirac.providers.json
vendored
Normal file
80
.aurelio/providers/dist/dirac.providers.json
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"value": "openrouter",
|
||||||
|
"label": "OpenRouter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "openai-codex",
|
||||||
|
"label": "ChatGPT Subscription (Codex OAuth)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "nous",
|
||||||
|
"label": "Nous Portal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "zai",
|
||||||
|
"label": "Z.AI / GLM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "kimi-coding",
|
||||||
|
"label": "Kimi for Coding"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "kimi-coding-cn",
|
||||||
|
"label": "Kimi for Coding (China)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "minimax",
|
||||||
|
"label": "MiniMax"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "minimax-cn",
|
||||||
|
"label": "MiniMax (China)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "bedrock",
|
||||||
|
"label": "Amazon Bedrock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "openai",
|
||||||
|
"label": "OpenAI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "anthropic",
|
||||||
|
"label": "Anthropic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "gemini",
|
||||||
|
"label": "Google Gemini"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "moonshot",
|
||||||
|
"label": "Moonshot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "qwen",
|
||||||
|
"label": "Alibaba Qwen (DashScope)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "qwen-code",
|
||||||
|
"label": "Qwen Code (Alibaba Cloud)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "claude-code",
|
||||||
|
"label": "Claude Code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "antigravity",
|
||||||
|
"label": "Antigravity CLI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "mimocode",
|
||||||
|
"label": "Xiaomi MiMo Code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "local",
|
||||||
|
"label": "Local (Ollama / sentence-transformers)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
255
.aurelio/providers/dist/mcp.providers.json
vendored
Normal file
255
.aurelio/providers/dist/mcp.providers.json
vendored
Normal file
|
|
@ -0,0 +1,255 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"chatFallback": [
|
||||||
|
"kimi-coding",
|
||||||
|
"qwen-code",
|
||||||
|
"gemini",
|
||||||
|
"anthropic",
|
||||||
|
"openai",
|
||||||
|
"minimax",
|
||||||
|
"zai",
|
||||||
|
"openrouter"
|
||||||
|
],
|
||||||
|
"embedFallback": [
|
||||||
|
"gemini",
|
||||||
|
"openai",
|
||||||
|
"qwen",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"id": "openrouter",
|
||||||
|
"label": "OpenRouter",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "OPENROUTER_API_KEY",
|
||||||
|
"baseUrl": "https://openrouter.ai/api/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "anthropic/claude-sonnet-4",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "openai-codex",
|
||||||
|
"label": "ChatGPT Subscription (Codex OAuth)",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "https://chatgpt.com/backend-api/codex",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "gpt-5-codex",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nous",
|
||||||
|
"label": "Nous Portal",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "https://inference-api.nousresearch.com/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "Hermes-4-70B",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "zai",
|
||||||
|
"label": "Z.AI / GLM",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ZAI_API_KEY",
|
||||||
|
"baseUrl": "https://api.z.ai/api/paas/v4",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "glm-4.6",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kimi-coding",
|
||||||
|
"label": "Kimi for Coding",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "KIMI_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.ai/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "kimi-k2-0905-preview",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kimi-coding-cn",
|
||||||
|
"label": "Kimi for Coding (China)",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "KIMI_CN_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.cn/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "kimi-k2-0905-preview",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "minimax",
|
||||||
|
"label": "MiniMax",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MINIMAX_API_KEY",
|
||||||
|
"baseUrl": "https://api.minimax.io/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "MiniMax-M2",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "minimax-cn",
|
||||||
|
"label": "MiniMax (China)",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MINIMAX_CN_API_KEY",
|
||||||
|
"baseUrl": "https://api.minimaxi.com/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "MiniMax-M2",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bedrock",
|
||||||
|
"label": "Amazon Bedrock",
|
||||||
|
"auth": "iam",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "",
|
||||||
|
"protocol": "bedrock-converse",
|
||||||
|
"chatModel": "anthropic.claude-sonnet-4-20250514-v1:0",
|
||||||
|
"embeddingModel": "amazon.titan-embed-text-v2:0",
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "openai",
|
||||||
|
"label": "OpenAI",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "OPENAI_API_KEY",
|
||||||
|
"baseUrl": "https://api.openai.com/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "gpt-4o",
|
||||||
|
"embeddingModel": "text-embedding-3-large",
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "anthropic",
|
||||||
|
"label": "Anthropic",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ANTHROPIC_API_KEY",
|
||||||
|
"baseUrl": "https://api.anthropic.com/v1",
|
||||||
|
"protocol": "anthropic",
|
||||||
|
"chatModel": "claude-sonnet-4-20250514",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gemini",
|
||||||
|
"label": "Google Gemini",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "GEMINI_API_KEY",
|
||||||
|
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
|
||||||
|
"protocol": "gemini",
|
||||||
|
"chatModel": "gemini-2.5-pro",
|
||||||
|
"embeddingModel": "text-embedding-004",
|
||||||
|
"maxContext": 1000000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "moonshot",
|
||||||
|
"label": "Moonshot",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MOONSHOT_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.ai/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "moonshot-v1-128k",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qwen",
|
||||||
|
"label": "Alibaba Qwen (DashScope)",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "DASHSCOPE_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "qwen-max",
|
||||||
|
"embeddingModel": "text-embedding-v3",
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qwen-code",
|
||||||
|
"label": "Qwen Code (Alibaba Cloud)",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "DASHSCOPE_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "qwen3-coder-plus",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "alibaba-cloud",
|
||||||
|
"label": "Alibaba Cloud (Model Studio)",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ALIBABA_CLOUD_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "qwen-max",
|
||||||
|
"embeddingModel": "text-embedding-v3",
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "antigravity",
|
||||||
|
"label": "Antigravity CLI",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": "ANTIGRAVITY_API_KEY",
|
||||||
|
"baseUrl": "https://antigravity.portugalfuturista.org",
|
||||||
|
"protocol": "portal",
|
||||||
|
"chatModel": "antigravity-default",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": false,
|
||||||
|
"fallback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "local",
|
||||||
|
"label": "Local (Ollama / sentence-transformers)",
|
||||||
|
"auth": "none",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "http://127.0.0.1:11434",
|
||||||
|
"protocol": "openai",
|
||||||
|
"chatModel": "qwen2.5-coder:14b",
|
||||||
|
"embeddingModel": "all-MiniLM-L6-v2",
|
||||||
|
"maxContext": 32768,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
316
.aurelio/providers/dist/portal.providers.json
vendored
Normal file
316
.aurelio/providers/dist/portal.providers.json
vendored
Normal file
|
|
@ -0,0 +1,316 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"generatedFrom": ".aurelio/providers/registry.yaml",
|
||||||
|
"fallback": [
|
||||||
|
"kimi-coding",
|
||||||
|
"qwen-code",
|
||||||
|
"gemini",
|
||||||
|
"anthropic",
|
||||||
|
"openai",
|
||||||
|
"minimax",
|
||||||
|
"zai",
|
||||||
|
"openrouter"
|
||||||
|
],
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"id": "openrouter",
|
||||||
|
"label": "OpenRouter",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "OPENROUTER_API_KEY",
|
||||||
|
"baseUrl": "https://openrouter.ai/api/v1",
|
||||||
|
"defaultModel": "anthropic/claude-sonnet-4",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Meta-router; reaches any upstream model."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "openai-codex",
|
||||||
|
"label": "ChatGPT Subscription (Codex OAuth)",
|
||||||
|
"kind": "oauth",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "https://chatgpt.com/backend-api/codex",
|
||||||
|
"defaultModel": "gpt-5-codex",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "OAuth via `hermes auth`. No API key."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nous",
|
||||||
|
"label": "Nous Portal",
|
||||||
|
"kind": "oauth",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "https://inference-api.nousresearch.com/v1",
|
||||||
|
"defaultModel": "Hermes-4-70B",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "NousResearch OAuth subscription."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "zai",
|
||||||
|
"label": "Z.AI / GLM",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ZAI_API_KEY",
|
||||||
|
"baseUrl": "https://api.z.ai/api/paas/v4",
|
||||||
|
"defaultModel": "glm-4.6",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Z.AI (GLM) OpenAI-compatible."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kimi-coding",
|
||||||
|
"label": "Kimi for Coding",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "KIMI_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.ai/v1",
|
||||||
|
"defaultModel": "kimi-k2-0905-preview",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Moonshot Kimi; alias of the existing `kimi`/`moonshot` ids in Dirac."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kimi-coding-cn",
|
||||||
|
"label": "Kimi for Coding (China)",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "KIMI_CN_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.cn/v1",
|
||||||
|
"defaultModel": "kimi-k2-0905-preview",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "China-region Moonshot endpoint."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "minimax",
|
||||||
|
"label": "MiniMax",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MINIMAX_API_KEY",
|
||||||
|
"baseUrl": "https://api.minimax.io/v1",
|
||||||
|
"defaultModel": "MiniMax-M2",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "minimax-cn",
|
||||||
|
"label": "MiniMax (China)",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MINIMAX_CN_API_KEY",
|
||||||
|
"baseUrl": "https://api.minimaxi.com/v1",
|
||||||
|
"defaultModel": "MiniMax-M2",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bedrock",
|
||||||
|
"label": "Amazon Bedrock",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "bedrock-converse",
|
||||||
|
"auth": "iam",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": null,
|
||||||
|
"defaultModel": "anthropic.claude-sonnet-4-20250514-v1:0",
|
||||||
|
"embeddingModel": "amazon.titan-embed-text-v2:0",
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Uses boto3/IAM, not an API key. Python router shells to boto3."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "openai",
|
||||||
|
"label": "OpenAI",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "OPENAI_API_KEY",
|
||||||
|
"baseUrl": "https://api.openai.com/v1",
|
||||||
|
"defaultModel": "gpt-4o",
|
||||||
|
"embeddingModel": "text-embedding-3-large",
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "anthropic",
|
||||||
|
"label": "Anthropic",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "anthropic",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ANTHROPIC_API_KEY",
|
||||||
|
"baseUrl": "https://api.anthropic.com/v1",
|
||||||
|
"defaultModel": "claude-sonnet-4-20250514",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gemini",
|
||||||
|
"label": "Google Gemini",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "gemini",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "GEMINI_API_KEY",
|
||||||
|
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
|
||||||
|
"defaultModel": "gemini-2.5-pro",
|
||||||
|
"embeddingModel": "text-embedding-004",
|
||||||
|
"maxContext": 1000000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "moonshot",
|
||||||
|
"label": "Moonshot",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MOONSHOT_API_KEY",
|
||||||
|
"baseUrl": "https://api.moonshot.ai/v1",
|
||||||
|
"defaultModel": "moonshot-v1-128k",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 128000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Distinct Dirac id from kimi-coding; kept for backwards compatibility."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qwen",
|
||||||
|
"label": "Alibaba Qwen (DashScope)",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "DASHSCOPE_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"defaultModel": "qwen-max",
|
||||||
|
"embeddingModel": "text-embedding-v3",
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Alibaba Cloud Model Studio (DashScope) OpenAI-compatible endpoint."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qwen-code",
|
||||||
|
"label": "Qwen Code (Alibaba Cloud)",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "DASHSCOPE_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"defaultModel": "qwen3-coder-plus",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Qwen Code CLI default model via DashScope; shares DASHSCOPE_API_KEY."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "alibaba-cloud",
|
||||||
|
"label": "Alibaba Cloud (Model Studio)",
|
||||||
|
"kind": "api",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "ALIBABA_CLOUD_API_KEY",
|
||||||
|
"baseUrl": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
||||||
|
"defaultModel": "qwen-max",
|
||||||
|
"embeddingModel": "text-embedding-v3",
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Generic Alibaba Cloud Model Studio umbrella (intl endpoint). Qwen/Qwen-Code are the concrete aliases; this entry exists so the portal can expose a single \"Alibaba Cloud\" offering."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "claude-code",
|
||||||
|
"label": "Claude Code",
|
||||||
|
"kind": "cli-subprocess",
|
||||||
|
"protocol": "subprocess",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": null,
|
||||||
|
"defaultModel": "claude-sonnet-4-20250514",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": false,
|
||||||
|
"notes": "Invokes the `claude` CLI; inherits its logged-in OAuth session."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "antigravity",
|
||||||
|
"label": "Antigravity CLI",
|
||||||
|
"kind": "cli-subprocess",
|
||||||
|
"protocol": "portal",
|
||||||
|
"auth": "oauth",
|
||||||
|
"keyEnv": "ANTIGRAVITY_API_KEY",
|
||||||
|
"baseUrl": "https://antigravity.portugalfuturista.org",
|
||||||
|
"defaultModel": "antigravity-default",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 200000,
|
||||||
|
"streaming": false,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "Google Antigravity. Local CLI at ~/.gemini/antigravity-cli; portal endpoint for the hosted relay."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mimocode",
|
||||||
|
"label": "Xiaomi MiMo Code",
|
||||||
|
"kind": "cli-subprocess",
|
||||||
|
"protocol": "subprocess",
|
||||||
|
"auth": "api_key",
|
||||||
|
"keyEnv": "MIMOCODE_API_KEY",
|
||||||
|
"baseUrl": null,
|
||||||
|
"defaultModel": "mimocoder",
|
||||||
|
"embeddingModel": null,
|
||||||
|
"maxContext": 131072,
|
||||||
|
"streaming": false,
|
||||||
|
"fallback": false,
|
||||||
|
"notes": "Xiaomi MiMo coding agent. Local install at .mimocode/ (npm). API shape is provisional pending upstream docs."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "local",
|
||||||
|
"label": "Local (Ollama / sentence-transformers)",
|
||||||
|
"kind": "local",
|
||||||
|
"protocol": "openai",
|
||||||
|
"auth": "none",
|
||||||
|
"keyEnv": null,
|
||||||
|
"baseUrl": "http://127.0.0.1:11434",
|
||||||
|
"defaultModel": "qwen2.5-coder:14b",
|
||||||
|
"embeddingModel": "all-MiniLM-L6-v2",
|
||||||
|
"maxContext": 32768,
|
||||||
|
"streaming": true,
|
||||||
|
"fallback": true,
|
||||||
|
"notes": "No key. Embeddings run via sentence-transformers in the MCP router."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
355
.aurelio/providers/registry.yaml
Normal file
355
.aurelio/providers/registry.yaml
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
# Aurélio Provider Registry — single source of truth
|
||||||
|
#
|
||||||
|
# This file is the ONE place providers are defined. All other surfaces derive
|
||||||
|
# from it via scripts/generate-provider-mirrors.py:
|
||||||
|
#
|
||||||
|
# * dirac/src/shared/providers/providers.json (Theia/VS Code UI list)
|
||||||
|
# * .aurelio/mcp/.../intelligence/model_router.py (Python MCP router)
|
||||||
|
# * .aurelio/providers/dist/portal.providers.json (porta.portugalfuturista.org)
|
||||||
|
# * ~/.hermes/config.yaml fallback_model docs (manual mirror — see docs)
|
||||||
|
#
|
||||||
|
# Schema per entry:
|
||||||
|
# id machine id (stable; used as enum value / providers.json `value`)
|
||||||
|
# label human label shown in UIs
|
||||||
|
# kind api | cli-subprocess | oauth | local
|
||||||
|
# auth api_key | oauth | iam | none
|
||||||
|
# key_env env var holding the API key (auth=api_key)
|
||||||
|
# base_url default endpoint (OpenAI-compatible unless protocol says otherwise)
|
||||||
|
# protocol openai | anthropic | gemini | bedrock-converse | subprocess | portal
|
||||||
|
# chat_model default chat model id
|
||||||
|
# embedding_model default embedding model id (null if none)
|
||||||
|
# max_context context window in tokens
|
||||||
|
# surfaces which downstreams get this provider:
|
||||||
|
# dirac -> Theia/VS Code providers.json
|
||||||
|
# mcp -> Python model_router
|
||||||
|
# portal -> porta.portugalfuturista.org workspace router
|
||||||
|
# hermes -> documented in Hermes fallback mirror
|
||||||
|
# streaming whether the router can stream tokens (false => one-shot fallback)
|
||||||
|
# fallback whether this provider participates in the cascading fallback chain
|
||||||
|
# notes free-form provenance / caveats
|
||||||
|
#
|
||||||
|
# The Hermes fallback surface is intentionally NOT auto-rewritten: Hermes owns
|
||||||
|
# ~/.hermes/config.yaml. We keep `surfaces: [hermes]` as documentation of which
|
||||||
|
# providers Hermes already supports so the other planes can match it.
|
||||||
|
|
||||||
|
version: 1
|
||||||
|
|
||||||
|
providers:
|
||||||
|
# ── Hermes-parity providers (from ~/.hermes/config.yaml fallback docs) ──────
|
||||||
|
- id: openrouter
|
||||||
|
label: OpenRouter
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: OPENROUTER_API_KEY
|
||||||
|
base_url: https://openrouter.ai/api/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: anthropic/claude-sonnet-4
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Meta-router; reaches any upstream model.
|
||||||
|
|
||||||
|
- id: openai-codex
|
||||||
|
label: ChatGPT Subscription (Codex OAuth)
|
||||||
|
kind: oauth
|
||||||
|
auth: oauth
|
||||||
|
key_env: null
|
||||||
|
base_url: https://chatgpt.com/backend-api/codex
|
||||||
|
protocol: openai
|
||||||
|
chat_model: gpt-5-codex
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: OAuth via `hermes auth`. No API key.
|
||||||
|
|
||||||
|
- id: nous
|
||||||
|
label: Nous Portal
|
||||||
|
kind: oauth
|
||||||
|
auth: oauth
|
||||||
|
key_env: null
|
||||||
|
base_url: https://inference-api.nousresearch.com/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: Hermes-4-70B
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: NousResearch OAuth subscription.
|
||||||
|
|
||||||
|
- id: zai
|
||||||
|
label: Z.AI / GLM
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: ZAI_API_KEY
|
||||||
|
base_url: https://api.z.ai/api/paas/v4
|
||||||
|
protocol: openai
|
||||||
|
chat_model: glm-4.6
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 128000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Z.AI (GLM) OpenAI-compatible.
|
||||||
|
|
||||||
|
- id: kimi-coding
|
||||||
|
label: Kimi for Coding
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: KIMI_API_KEY
|
||||||
|
base_url: https://api.moonshot.ai/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: kimi-k2-0905-preview
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Moonshot Kimi; alias of the existing `kimi`/`moonshot` ids in Dirac.
|
||||||
|
|
||||||
|
- id: kimi-coding-cn
|
||||||
|
label: Kimi for Coding (China)
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: KIMI_CN_API_KEY
|
||||||
|
base_url: https://api.moonshot.cn/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: kimi-k2-0905-preview
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: China-region Moonshot endpoint.
|
||||||
|
|
||||||
|
- id: minimax
|
||||||
|
label: MiniMax
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: MINIMAX_API_KEY
|
||||||
|
base_url: https://api.minimax.io/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: MiniMax-M2
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
|
||||||
|
- id: minimax-cn
|
||||||
|
label: MiniMax (China)
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: MINIMAX_CN_API_KEY
|
||||||
|
base_url: https://api.minimaxi.com/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: MiniMax-M2
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
|
||||||
|
- id: bedrock
|
||||||
|
label: Amazon Bedrock
|
||||||
|
kind: api
|
||||||
|
auth: iam
|
||||||
|
key_env: null
|
||||||
|
base_url: ""
|
||||||
|
protocol: bedrock-converse
|
||||||
|
chat_model: anthropic.claude-sonnet-4-20250514-v1:0
|
||||||
|
embedding_model: amazon.titan-embed-text-v2:0
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [hermes, dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Uses boto3/IAM, not an API key. Python router shells to boto3.
|
||||||
|
|
||||||
|
# ── Classic API providers already in Dirac / MCP ────────────────────────────
|
||||||
|
- id: openai
|
||||||
|
label: OpenAI
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: OPENAI_API_KEY
|
||||||
|
base_url: https://api.openai.com/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: gpt-4o
|
||||||
|
embedding_model: text-embedding-3-large
|
||||||
|
max_context: 128000
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
|
||||||
|
- id: anthropic
|
||||||
|
label: Anthropic
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: ANTHROPIC_API_KEY
|
||||||
|
base_url: https://api.anthropic.com/v1
|
||||||
|
protocol: anthropic
|
||||||
|
chat_model: claude-sonnet-4-20250514
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
|
||||||
|
- id: gemini
|
||||||
|
label: Google Gemini
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: GEMINI_API_KEY
|
||||||
|
base_url: https://generativelanguage.googleapis.com/v1beta
|
||||||
|
protocol: gemini
|
||||||
|
chat_model: gemini-2.5-pro
|
||||||
|
embedding_model: text-embedding-004
|
||||||
|
max_context: 1000000
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
|
||||||
|
- id: moonshot
|
||||||
|
label: Moonshot
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: MOONSHOT_API_KEY
|
||||||
|
base_url: https://api.moonshot.ai/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: moonshot-v1-128k
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 128000
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Distinct Dirac id from kimi-coding; kept for backwards compatibility.
|
||||||
|
|
||||||
|
# ── Alibaba Cloud ───────────────────────────────────────────────────────────
|
||||||
|
- id: qwen
|
||||||
|
label: Alibaba Qwen (DashScope)
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: DASHSCOPE_API_KEY
|
||||||
|
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: qwen-max
|
||||||
|
embedding_model: text-embedding-v3
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Alibaba Cloud Model Studio (DashScope) OpenAI-compatible endpoint.
|
||||||
|
|
||||||
|
- id: qwen-code
|
||||||
|
label: Qwen Code (Alibaba Cloud)
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: DASHSCOPE_API_KEY
|
||||||
|
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: qwen3-coder-plus
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Qwen Code CLI default model via DashScope; shares DASHSCOPE_API_KEY.
|
||||||
|
- id: alibaba-cloud
|
||||||
|
label: Alibaba Cloud (Model Studio)
|
||||||
|
kind: api
|
||||||
|
auth: api_key
|
||||||
|
key_env: ALIBABA_CLOUD_API_KEY
|
||||||
|
base_url: https://dashscope-intl.aliyuncs.com/compatible-mode/v1
|
||||||
|
protocol: openai
|
||||||
|
chat_model: qwen-max
|
||||||
|
embedding_model: text-embedding-v3
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: Generic Alibaba Cloud Model Studio umbrella (intl endpoint). Qwen/Qwen-Code are the concrete aliases; this entry exists so the portal can expose a single "Alibaba Cloud" offering.
|
||||||
|
|
||||||
|
# ── CLI subprocess agents (invoked as binaries, not HTTP) ───────────────────
|
||||||
|
- id: claude-code
|
||||||
|
label: Claude Code
|
||||||
|
kind: cli-subprocess
|
||||||
|
auth: oauth
|
||||||
|
key_env: null
|
||||||
|
base_url: ""
|
||||||
|
protocol: subprocess
|
||||||
|
chat_model: claude-sonnet-4-20250514
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [dirac, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: false
|
||||||
|
notes: Invokes the `claude` CLI; inherits its logged-in OAuth session.
|
||||||
|
|
||||||
|
- id: antigravity
|
||||||
|
label: Antigravity CLI
|
||||||
|
kind: cli-subprocess
|
||||||
|
auth: oauth
|
||||||
|
key_env: ANTIGRAVITY_API_KEY
|
||||||
|
base_url: https://antigravity.portugalfuturista.org
|
||||||
|
protocol: portal
|
||||||
|
chat_model: antigravity-default
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 200000
|
||||||
|
surfaces: [dirac, portal, mcp]
|
||||||
|
streaming: false
|
||||||
|
fallback: true
|
||||||
|
notes: Google Antigravity. Local CLI at ~/.gemini/antigravity-cli; portal endpoint for the hosted relay.
|
||||||
|
|
||||||
|
- id: mimocode
|
||||||
|
label: Xiaomi MiMo Code
|
||||||
|
kind: cli-subprocess
|
||||||
|
auth: api_key
|
||||||
|
key_env: MIMOCODE_API_KEY
|
||||||
|
base_url: ""
|
||||||
|
protocol: subprocess
|
||||||
|
chat_model: mimocoder
|
||||||
|
embedding_model: null
|
||||||
|
max_context: 131072
|
||||||
|
surfaces: [dirac, portal]
|
||||||
|
streaming: false
|
||||||
|
fallback: false
|
||||||
|
notes: Xiaomi MiMo coding agent. Local install at .mimocode/ (npm). API shape is provisional pending upstream docs.
|
||||||
|
|
||||||
|
# ── Local ───────────────────────────────────────────────────────────────────
|
||||||
|
- id: local
|
||||||
|
label: Local (Ollama / sentence-transformers)
|
||||||
|
kind: local
|
||||||
|
auth: none
|
||||||
|
key_env: null
|
||||||
|
base_url: http://127.0.0.1:11434
|
||||||
|
protocol: openai
|
||||||
|
chat_model: qwen2.5-coder:14b
|
||||||
|
embedding_model: all-MiniLM-L6-v2
|
||||||
|
max_context: 32768
|
||||||
|
surfaces: [dirac, mcp, portal]
|
||||||
|
streaming: true
|
||||||
|
fallback: true
|
||||||
|
notes: No key. Embeddings run via sentence-transformers in the MCP router.
|
||||||
|
|
||||||
|
# Fallback preference order for the Python MCP router (chat).
|
||||||
|
# Subprocess / oauth-only providers are excluded from the auto chain because
|
||||||
|
# they require an interactive login; they remain explicitly selectable.
|
||||||
|
mcp_chat_fallback:
|
||||||
|
- kimi-coding
|
||||||
|
- qwen-code
|
||||||
|
- gemini
|
||||||
|
- anthropic
|
||||||
|
- openai
|
||||||
|
- minimax
|
||||||
|
- zai
|
||||||
|
- openrouter
|
||||||
|
|
||||||
|
# Embedding preference order for the Python MCP router.
|
||||||
|
mcp_embed_fallback:
|
||||||
|
- gemini
|
||||||
|
- openai
|
||||||
|
- qwen
|
||||||
|
- local
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,6 +10,7 @@ __pycache__/
|
||||||
|
|
||||||
# Build outputs
|
# Build outputs
|
||||||
dist/
|
dist/
|
||||||
|
!.aurelio/providers/dist/
|
||||||
out/
|
out/
|
||||||
*.vsix
|
*.vsix
|
||||||
|
|
||||||
|
|
|
||||||
184
scripts/generate-provider-mirrors.py
Executable file
184
scripts/generate-provider-mirrors.py
Executable file
|
|
@ -0,0 +1,184 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate downstream provider mirrors from the single source of truth:
|
||||||
|
|
||||||
|
.aurelio/providers/registry.yaml
|
||||||
|
|
||||||
|
Outputs (under .aurelio/providers/dist/ unless --write-in-place is given):
|
||||||
|
|
||||||
|
* portal.providers.json — consumable by porta.portugalfuturista.org /
|
||||||
|
aurelio-theia ModelRouter.
|
||||||
|
* mcp.providers.json — machine-readable form the Python model_router
|
||||||
|
can load instead of its hard-coded registry.
|
||||||
|
* dirac.providers.json — {list:[{value,label}]} matching Dirac's
|
||||||
|
src/shared/providers/providers.json shape.
|
||||||
|
|
||||||
|
With --write-in-place it also patches Dirac's providers.json in place (adding
|
||||||
|
any missing providers, never removing existing ones) and rewrites the Python
|
||||||
|
model_router's registry block to load from mcp.providers.json at import time.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 scripts/generate-provider-mirrors.py
|
||||||
|
python3 scripts/generate-provider-mirrors.py --write-in-place
|
||||||
|
python3 scripts/generate-provider-mirrors.py --check # exit 1 if dist stale
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml # PyYAML
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
print("PyYAML required: pip install pyyaml", file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
REPLICA_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
REGISTRY = REPLICA_ROOT / ".aurelio" / "providers" / "registry.yaml"
|
||||||
|
DIST_DIR = REPLICA_ROOT / ".aurelio" / "providers" / "dist"
|
||||||
|
DIRAC_PROVIDERS = REPLICA_ROOT / "dirac" / "src" / "shared" / "providers" / "providers.json"
|
||||||
|
|
||||||
|
|
||||||
|
def load() -> dict:
|
||||||
|
with REGISTRY.open("r", encoding="utf-8") as f:
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def emit_portal(data: dict) -> dict:
|
||||||
|
"""Shape consumed by aurelio-theia ModelRouter / porta.portugalfuturista.org."""
|
||||||
|
providers = []
|
||||||
|
for p in data["providers"]:
|
||||||
|
if "portal" not in p.get("surfaces", []):
|
||||||
|
continue
|
||||||
|
providers.append({
|
||||||
|
"id": p["id"],
|
||||||
|
"label": p["label"],
|
||||||
|
"kind": p["kind"],
|
||||||
|
"protocol": p["protocol"],
|
||||||
|
"auth": p["auth"],
|
||||||
|
"keyEnv": p.get("key_env"),
|
||||||
|
"baseUrl": p.get("base_url") or None,
|
||||||
|
"defaultModel": p.get("chat_model") or None,
|
||||||
|
"embeddingModel": p.get("embedding_model") or None,
|
||||||
|
"maxContext": p.get("max_context"),
|
||||||
|
"streaming": bool(p.get("streaming")),
|
||||||
|
"fallback": bool(p.get("fallback")),
|
||||||
|
"notes": p.get("notes", ""),
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
"version": data.get("version", 1),
|
||||||
|
"generatedFrom": ".aurelio/providers/registry.yaml",
|
||||||
|
"fallback": data.get("mcp_chat_fallback", []),
|
||||||
|
"providers": providers,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def emit_mcp(data: dict) -> dict:
|
||||||
|
providers = []
|
||||||
|
for p in data["providers"]:
|
||||||
|
if "mcp" not in p.get("surfaces", []):
|
||||||
|
continue
|
||||||
|
providers.append({
|
||||||
|
"id": p["id"],
|
||||||
|
"label": p["label"],
|
||||||
|
"auth": p["auth"],
|
||||||
|
"keyEnv": p.get("key_env"),
|
||||||
|
"baseUrl": p.get("base_url") or "",
|
||||||
|
"protocol": p["protocol"],
|
||||||
|
"chatModel": p.get("chat_model") or "",
|
||||||
|
"embeddingModel": p.get("embedding_model"),
|
||||||
|
"maxContext": p.get("max_context"),
|
||||||
|
"streaming": bool(p.get("streaming")),
|
||||||
|
"fallback": bool(p.get("fallback")),
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
"version": data.get("version", 1),
|
||||||
|
"chatFallback": data.get("mcp_chat_fallback", []),
|
||||||
|
"embedFallback": data.get("mcp_embed_fallback", []),
|
||||||
|
"providers": providers,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def emit_dirac(data: dict) -> dict:
|
||||||
|
out = []
|
||||||
|
for p in data["providers"]:
|
||||||
|
if "dirac" not in p.get("surfaces", []):
|
||||||
|
continue
|
||||||
|
out.append({"value": p["id"], "label": p["label"]})
|
||||||
|
return {"list": out}
|
||||||
|
|
||||||
|
|
||||||
|
def write_json(path: Path, obj: dict) -> bool:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
new = json.dumps(obj, indent=2, ensure_ascii=False) + "\n"
|
||||||
|
if path.exists() and path.read_text(encoding="utf-8") == new:
|
||||||
|
return False
|
||||||
|
path.write_text(new, encoding="utf-8")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def patch_dirac_in_place(dirac_list: dict) -> list[str]:
|
||||||
|
"""Add providers missing from Dirac's providers.json. Returns added ids."""
|
||||||
|
if not DIRAC_PROVIDERS.exists():
|
||||||
|
return [f"<missing file: {DIRAC_PROVIDERS}>"]
|
||||||
|
current = json.loads(DIRAC_PROVIDERS.read_text(encoding="utf-8"))
|
||||||
|
have = {e["value"] for e in current.get("list", [])}
|
||||||
|
added = []
|
||||||
|
for entry in dirac_list["list"]:
|
||||||
|
if entry["value"] not in have:
|
||||||
|
current["list"].append(entry)
|
||||||
|
added.append(entry["value"])
|
||||||
|
if added:
|
||||||
|
DIRAC_PROVIDERS.write_text(
|
||||||
|
json.dumps(current, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
return added
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--write-in-place", action="store_true")
|
||||||
|
ap.add_argument("--check", action="store_true",
|
||||||
|
help="Exit non-zero if dist/ is stale relative to registry.")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
data = load()
|
||||||
|
targets = {
|
||||||
|
"portal.providers.json": emit_portal(data),
|
||||||
|
"mcp.providers.json": emit_mcp(data),
|
||||||
|
"dirac.providers.json": emit_dirac(data),
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.check:
|
||||||
|
stale = []
|
||||||
|
for name, obj in targets.items():
|
||||||
|
p = DIST_DIR / name
|
||||||
|
new = json.dumps(obj, indent=2, ensure_ascii=False) + "\n"
|
||||||
|
if not p.exists() or p.read_text(encoding="utf-8") != new:
|
||||||
|
stale.append(name)
|
||||||
|
if stale:
|
||||||
|
print("STALE:", ", ".join(stale), file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
print("dist/ up to date")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
changed = []
|
||||||
|
for name, obj in targets.items():
|
||||||
|
if write_json(DIST_DIR / name, obj):
|
||||||
|
changed.append(name)
|
||||||
|
print("dist:", "updated " + ", ".join(changed) if changed else "no changes")
|
||||||
|
|
||||||
|
if args.write_in_place:
|
||||||
|
added = patch_dirac_in_place(targets["dirac.providers.json"])
|
||||||
|
if added:
|
||||||
|
print("dirac providers.json: added", ", ".join(added))
|
||||||
|
else:
|
||||||
|
print("dirac providers.json: already complete")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Loading…
Reference in a new issue