mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 12:22:14 +03:00
* feat(mitm): add Antigravity reasoning-effort overrides
The Antigravity MITM alias mapping only ever swapped the destination model;
there was no way to override the reasoning effort Antigravity's own
thinkingConfig requested. Alias entries are now `{ model?, reasoningEffort? }`
(a legacy plain-string mapping still normalizes to `{ model }`, so no DB
migration is required). The standalone proxy (server.cjs) forwards the chosen
tier as a top-level `reasoningEffortOverride` on the intercepted request; the
antigravity->openai translator honors it ahead of its thinkingConfig-derived
guess, and an explicit "none" suppresses reasoning_effort entirely even when
Antigravity's own request asked for thinking. Reuses the existing canonical
5-tier reasoning vocabulary (`@/shared/reasoning/effortStandardization.ts`,
with max/extra aliasing to xhigh) instead of introducing a new one. The API
route validates the reasoning-effort value at the boundary and the Antigravity
tool card UI now exposes a per-model reasoning-effort selector alongside the
existing model-mapping input.
Co-authored-by: Truong Fiu <gnourtf@gmail.com>
Inspired-by: https://github.com/decolua/9router/pull/2584
* chore(changelog): fragment for #7228
---------
Co-authored-by: Truong Fiu <gnourtf@gmail.com>
84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
/**
|
|
* MITM alias-mapping normalization — Antigravity model + reasoning-effort overrides.
|
|
*
|
|
* Ported from upstream decolua/9router#2584 ("add Antigravity reasoning effort
|
|
* overrides"), adapted to OmniRoute's alias storage shape (`src/lib/db/models/mitmAlias.ts`,
|
|
* `Record<alias, string | MitmAliasEntry>`) and its existing canonical reasoning-effort
|
|
* vocabulary (`@/shared/reasoning/effortStandardization.ts`) instead of inventing a new one.
|
|
*
|
|
* A saved alias entry is either:
|
|
* - a legacy plain string — `"provider/model-id"` (model mapping only, no reasoning
|
|
* override; this is the shape every existing install already has on disk), or
|
|
* - a structured object — `{ model?: string, reasoningEffort?: CanonicalEffort }`,
|
|
* allowing a reasoning-effort override to be configured independently of (or without)
|
|
* a model remap.
|
|
*
|
|
* `normalizeAliasMappings` upgrades legacy strings to the structured shape on read, so no
|
|
* DB migration is required (mirrors upstream's stated backward-compatibility contract).
|
|
*/
|
|
import { normalizeEffort, type CanonicalEffort } from "@/shared/reasoning/effortStandardization";
|
|
|
|
export interface MitmAliasEntry {
|
|
model?: string;
|
|
reasoningEffort?: CanonicalEffort;
|
|
}
|
|
|
|
export type MitmAliasMappings = Record<string, MitmAliasEntry>;
|
|
|
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
/**
|
|
* Normalize a single stored alias value (legacy string or structured entry) into the
|
|
* canonical `MitmAliasEntry` shape. Returns `null` when the value carries neither a model
|
|
* nor a valid reasoning-effort override (i.e. it should be dropped from the mapping).
|
|
*/
|
|
export function normalizeAliasEntry(value: unknown): MitmAliasEntry | null {
|
|
if (typeof value === "string") {
|
|
const model = value.trim();
|
|
return model ? { model } : null;
|
|
}
|
|
if (!isPlainObject(value)) return null;
|
|
|
|
const model = typeof value.model === "string" ? value.model.trim() : "";
|
|
const reasoningEffort = normalizeEffort(value.reasoningEffort);
|
|
if (!model && !reasoningEffort) return null;
|
|
|
|
return {
|
|
...(model ? { model } : {}),
|
|
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Normalize a whole alias→mapping record (as stored under `mitmAlias.antigravity` /
|
|
* returned by `getMitmAlias()`), upgrading legacy string mappings and dropping empty
|
|
* entries. Always returns a well-formed object, even for malformed input.
|
|
*/
|
|
export function normalizeAliasMappings(mappings: unknown): MitmAliasMappings {
|
|
if (!isPlainObject(mappings)) return {};
|
|
const normalized: MitmAliasMappings = {};
|
|
for (const [alias, value] of Object.entries(mappings)) {
|
|
if (!alias) continue;
|
|
const entry = normalizeAliasEntry(value);
|
|
if (entry) normalized[alias] = entry;
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
/**
|
|
* True when any entry in the (not-yet-normalized) request payload carries a
|
|
* `reasoningEffort` value that fails to normalize onto the canonical vocabulary — used to
|
|
* reject the PUT at the API boundary with a 400 instead of silently dropping the override.
|
|
*/
|
|
export function hasInvalidReasoningEffort(mappings: unknown): boolean {
|
|
if (!isPlainObject(mappings)) return false;
|
|
return Object.values(mappings).some((value) => {
|
|
if (!isPlainObject(value)) return false;
|
|
const raw = value.reasoningEffort;
|
|
if (raw == null || raw === "") return false;
|
|
return normalizeEffort(raw) === undefined;
|
|
});
|
|
}
|