mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Merge PR #578: feat — add configurable context length to model metadata (by @hijak)
This commit is contained in:
@@ -16,6 +16,8 @@ export interface RegistryModel {
|
||||
toolCalling?: boolean;
|
||||
targetFormat?: string;
|
||||
unsupportedParams?: readonly string[];
|
||||
/** Maximum context window in tokens */
|
||||
contextLength?: number;
|
||||
}
|
||||
|
||||
// Reasoning models reject temperature, top_p, penalties, logprobs, n.
|
||||
@@ -65,6 +67,8 @@ export interface RegistryEntry {
|
||||
chatPath?: string;
|
||||
clientVersion?: string;
|
||||
passthroughModels?: boolean;
|
||||
/** Default context window for all models in this provider (can be overridden per-model) */
|
||||
defaultContextLength?: number;
|
||||
}
|
||||
|
||||
interface LegacyProvider {
|
||||
@@ -137,6 +141,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
urlSuffix: "?beta=true",
|
||||
authType: "oauth",
|
||||
authHeader: "x-api-key",
|
||||
defaultContextLength: 200000,
|
||||
headers: {
|
||||
"Anthropic-Version": "2023-06-01",
|
||||
"Anthropic-Beta":
|
||||
@@ -180,6 +185,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
},
|
||||
authType: "apikey",
|
||||
authHeader: "x-goog-api-key",
|
||||
defaultContextLength: 1000000,
|
||||
oauth: {
|
||||
clientIdEnv: "GEMINI_OAUTH_CLIENT_ID",
|
||||
clientIdDefault: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
|
||||
@@ -216,6 +222,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
},
|
||||
authType: "oauth",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 1000000,
|
||||
oauth: {
|
||||
clientIdEnv: "GEMINI_CLI_OAUTH_CLIENT_ID",
|
||||
clientIdDefault: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
|
||||
@@ -247,6 +254,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
baseUrl: "https://chatgpt.com/backend-api/codex/responses",
|
||||
authType: "oauth",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 400000,
|
||||
headers: {
|
||||
Version: "0.92.0",
|
||||
"Openai-Beta": "responses=experimental",
|
||||
@@ -399,6 +407,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
responsesBaseUrl: "https://api.githubcopilot.com/responses",
|
||||
authType: "oauth",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 128000,
|
||||
headers: {
|
||||
"copilot-integration-id": "vscode-chat",
|
||||
"editor-version": "vscode/1.110.0",
|
||||
@@ -447,6 +456,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
baseUrl: "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse",
|
||||
authType: "oauth",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 200000,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/vnd.amazon.eventstream",
|
||||
@@ -473,6 +483,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
chatPath: "/aiserver.v1.ChatService/StreamUnifiedChatWithTools",
|
||||
authType: "oauth",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 200000,
|
||||
headers: {
|
||||
"connect-accept-encoding": "gzip",
|
||||
"connect-protocol-version": "1",
|
||||
@@ -501,6 +512,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
baseUrl: "https://api.openai.com/v1/chat/completions",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 128000,
|
||||
models: [
|
||||
{ id: "gpt-4o", name: "GPT-4o" },
|
||||
{ id: "gpt-4o-mini", name: "GPT-4o Mini" },
|
||||
@@ -522,6 +534,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
urlSuffix: "?beta=true",
|
||||
authType: "apikey",
|
||||
authHeader: "x-api-key",
|
||||
defaultContextLength: 200000,
|
||||
headers: {
|
||||
"Anthropic-Version": "2023-06-01",
|
||||
},
|
||||
@@ -548,6 +561,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
authType: "apikey",
|
||||
authHeader: "Authorization",
|
||||
authPrefix: "Bearer",
|
||||
defaultContextLength: 200000,
|
||||
models: [
|
||||
{ id: "glm-5", name: "GLM-5" },
|
||||
{ id: "kimi-k2.5", name: "Kimi K2.5" },
|
||||
@@ -565,6 +579,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
authType: "apikey",
|
||||
authHeader: "Authorization",
|
||||
authPrefix: "Bearer",
|
||||
defaultContextLength: 200000,
|
||||
models: [
|
||||
{ id: "minimax-m2.5-free", name: "MiniMax M2.5 Free" },
|
||||
{ id: "big-pickle", name: "Big Pickle" },
|
||||
@@ -580,6 +595,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
baseUrl: "https://openrouter.ai/api/v1/chat/completions",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 128000,
|
||||
headers: {
|
||||
"HTTP-Referer": "https://endpoint-proxy.local",
|
||||
"X-Title": "Endpoint Proxy",
|
||||
@@ -593,6 +609,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
format: "claude",
|
||||
executor: "default",
|
||||
baseUrl: "https://api.z.ai/api/anthropic/v1/messages",
|
||||
defaultContextLength: 200000,
|
||||
urlSuffix: "?beta=true",
|
||||
authType: "apikey",
|
||||
authHeader: "x-api-key",
|
||||
|
||||
@@ -5,14 +5,34 @@
|
||||
* 3 layers: trim tool messages, compress thinking, aggressive purification.
|
||||
*/
|
||||
|
||||
// Default token limits per provider (rough estimates based on model context windows)
|
||||
const DEFAULT_LIMITS = {
|
||||
import { REGISTRY } from "../config/providerRegistry.ts";
|
||||
|
||||
// Default token limits per provider (fallbacks when not in registry)
|
||||
const DEFAULT_LIMITS: Record<string, number> = {
|
||||
claude: 200000,
|
||||
openai: 128000,
|
||||
gemini: 1000000,
|
||||
codex: 400000,
|
||||
default: 128000,
|
||||
};
|
||||
|
||||
// Environment variable overrides (highest priority)
|
||||
function getEnvOverride(provider: string): number | null {
|
||||
const envKey = `CONTEXT_LENGTH_${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
||||
const envValue = process.env[envKey];
|
||||
if (envValue) {
|
||||
const parsed = parseInt(envValue, 10);
|
||||
if (!isNaN(parsed) && parsed > 0) return parsed;
|
||||
}
|
||||
// Global override
|
||||
const globalValue = process.env.CONTEXT_LENGTH_DEFAULT;
|
||||
if (globalValue) {
|
||||
const parsed = parseInt(globalValue, 10);
|
||||
if (!isNaN(parsed) && parsed > 0) return parsed;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Rough chars-per-token ratio for quick estimation
|
||||
const CHARS_PER_TOKEN = 4;
|
||||
|
||||
@@ -27,9 +47,20 @@ export function estimateTokens(text) {
|
||||
|
||||
/**
|
||||
* Get token limit for a provider/model combination
|
||||
* Priority: Env override > Registry defaultContextLength > DEFAULT_LIMITS
|
||||
*/
|
||||
export function getTokenLimit(provider, model = null) {
|
||||
// Check if model has a known limit
|
||||
// 1. Check environment variable override first
|
||||
const envOverride = getEnvOverride(provider);
|
||||
if (envOverride) return envOverride;
|
||||
|
||||
// 2. Check registry for provider default
|
||||
const registryEntry = REGISTRY[provider];
|
||||
if (registryEntry?.defaultContextLength) {
|
||||
return registryEntry.defaultContextLength;
|
||||
}
|
||||
|
||||
// 3. Check if model name hints at a known limit
|
||||
if (model) {
|
||||
const lower = model.toLowerCase();
|
||||
if (lower.includes("claude")) return DEFAULT_LIMITS.claude;
|
||||
@@ -38,10 +69,13 @@ export function getTokenLimit(provider, model = null) {
|
||||
lower.includes("gpt") ||
|
||||
lower.includes("o1") ||
|
||||
lower.includes("o3") ||
|
||||
lower.includes("o4")
|
||||
lower.includes("o4") ||
|
||||
lower.includes("codex")
|
||||
)
|
||||
return DEFAULT_LIMITS.openai;
|
||||
return DEFAULT_LIMITS.codex;
|
||||
}
|
||||
|
||||
// 4. Fallback to DEFAULT_LIMITS or default
|
||||
return DEFAULT_LIMITS[provider] || DEFAULT_LIMITS.default;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { getAllAudioModels } from "@omniroute/open-sse/config/audioRegistry.ts";
|
||||
import { getAllModerationModels } from "@omniroute/open-sse/config/moderationRegistry.ts";
|
||||
import { getAllVideoModels, getVideoProvider } from "@omniroute/open-sse/config/videoRegistry.ts";
|
||||
import { getAllMusicModels, getMusicProvider } from "@omniroute/open-sse/config/musicRegistry.ts";
|
||||
import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts";
|
||||
|
||||
const FALLBACK_ALIAS_TO_PROVIDER = {
|
||||
ag: "antigravity",
|
||||
@@ -190,6 +191,7 @@ export async function getUnifiedModelsResponse(
|
||||
permission: [],
|
||||
root: combo.name,
|
||||
parent: null,
|
||||
...(combo.context_length ? { context_length: combo.context_length } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -206,8 +208,15 @@ export async function getUnifiedModelsResponse(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get default context length from registry (provider-level default)
|
||||
const registryEntry = REGISTRY[alias] || REGISTRY[canonicalProviderId];
|
||||
const defaultContextLength = registryEntry?.defaultContextLength;
|
||||
|
||||
for (const model of providerModels) {
|
||||
const aliasId = `${alias}/${model.id}`;
|
||||
// Model-level context length overrides provider default
|
||||
const contextLength = model.contextLength || defaultContextLength;
|
||||
|
||||
models.push({
|
||||
id: aliasId,
|
||||
object: "model",
|
||||
@@ -216,6 +225,7 @@ export async function getUnifiedModelsResponse(
|
||||
permission: [],
|
||||
root: model.id,
|
||||
parent: null,
|
||||
...(contextLength ? { context_length: contextLength } : {}),
|
||||
});
|
||||
|
||||
// Add provider-id prefix in addition to short alias (ex: kiro/model + kr/model).
|
||||
@@ -229,6 +239,7 @@ export async function getUnifiedModelsResponse(
|
||||
permission: [],
|
||||
root: model.id,
|
||||
parent: aliasId,
|
||||
...(contextLength ? { context_length: contextLength } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ export const createComboSchema = z.object({
|
||||
system_message: z.string().max(50000).optional(),
|
||||
tool_filter_regex: z.string().max(1000).optional(),
|
||||
context_cache_protection: z.boolean().optional(),
|
||||
context_length: z.number().int().min(1000).max(2000000).optional(),
|
||||
});
|
||||
|
||||
// ──── Auto-Combo Schemas ────
|
||||
|
||||
Reference in New Issue
Block a user