78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
import type { ModelCatalogEntry, ModelTier } from "@rakazo/contracts";
|
|
|
|
export const POPULAR_MODEL_PROVIDER_IDS = [
|
|
"openrouter",
|
|
"openai-codex",
|
|
"anthropic",
|
|
"openai",
|
|
"google",
|
|
"vercel-ai-gateway",
|
|
] as const;
|
|
|
|
const DEFAULT_PROVIDER_COUNT = POPULAR_MODEL_PROVIDER_IDS.length;
|
|
const POPULAR_MODEL_PROVIDER_ID_SET = new Set<string>(POPULAR_MODEL_PROVIDER_IDS);
|
|
|
|
/** Keep provider selection short while ensuring a deployment's current default is never hidden. */
|
|
export function featuredModelProviders(
|
|
providers: readonly ModelCatalogEntry[],
|
|
selectedProvider: string,
|
|
): ModelCatalogEntry[] {
|
|
const byId = new Map(providers.map((entry) => [entry.provider, entry]));
|
|
const ordered = [
|
|
...POPULAR_MODEL_PROVIDER_IDS.map((id) => byId.get(id)).filter(
|
|
(entry): entry is ModelCatalogEntry => entry !== undefined,
|
|
),
|
|
...providers.filter((entry) => !POPULAR_MODEL_PROVIDER_ID_SET.has(entry.provider)),
|
|
];
|
|
const featured = ordered.slice(0, DEFAULT_PROVIDER_COUNT);
|
|
const selected = byId.get(selectedProvider);
|
|
|
|
if (!selected || featured.some((entry) => entry.provider === selectedProvider)) return featured;
|
|
return [...featured.slice(0, DEFAULT_PROVIDER_COUNT - 1), selected];
|
|
}
|
|
|
|
/** Return the active choice separately when it is not one of the search results. */
|
|
export function selectedProviderOutsideSearchResults(
|
|
filteredProviders: readonly ModelCatalogEntry[],
|
|
allProviders: readonly ModelCatalogEntry[],
|
|
selectedProvider: string,
|
|
): ModelCatalogEntry | undefined {
|
|
if (filteredProviders.some((entry) => entry.provider === selectedProvider)) {
|
|
return undefined;
|
|
}
|
|
return allProviders.find((entry) => entry.provider === selectedProvider);
|
|
}
|
|
|
|
export type StepRoutingPhase =
|
|
| "engagement_judge"
|
|
| "memory_consolidation"
|
|
| "tool_execution"
|
|
| "synthesis";
|
|
|
|
export type StepRoutingInput = {
|
|
phase: StepRoutingPhase;
|
|
toolNames?: readonly string[];
|
|
promptText?: string;
|
|
};
|
|
|
|
const CODE_TOOL_PATTERNS = /^(bash|shell|exec|terminal|edit_file|write_file|git|computer_)/i;
|
|
const CODE_PROMPT_PATTERNS =
|
|
/\b(refactor|typescript|vitest|dockerfile|sql|stacktrace|compile|regex|bugfix)\b/i;
|
|
|
|
/**
|
|
* Selects the space model tier best suited for a run step so low-latency background checks use
|
|
* the fast tier, coding/sandbox operations use the code tier, and synthesis uses standard.
|
|
*/
|
|
export function selectStepModelTier(input: StepRoutingInput): ModelTier {
|
|
if (input.phase === "engagement_judge" || input.phase === "memory_consolidation") {
|
|
return "fast";
|
|
}
|
|
if (input.toolNames?.some((name) => CODE_TOOL_PATTERNS.test(name.trim()))) {
|
|
return "code";
|
|
}
|
|
if (input.promptText && CODE_PROMPT_PATTERNS.test(input.promptText)) {
|
|
return "code";
|
|
}
|
|
return "standard";
|
|
}
|