feat(FN-4616): complete Step 1 — add OpenRouter settings shape/default keys

Ref: Runfusion/Fusion#325
Fusion-Task-Id: FN-4616
Fusion-Task-Lineage: ea5ea571-cc40-4ec0-86b4-2f003ac2834c
This commit is contained in:
Fusion
2026-05-15 09:58:48 -07:00
committed by gsxdsm
parent 5b3455bba9
commit d1909afc2a
3 changed files with 42 additions and 0 deletions

View File

@@ -147,6 +147,18 @@ describe("settings key parity", () => {
expect(normalizeAutoRecovery({ mode: "invalid" })).toEqual({ mode: "deterministic-only", perClass: undefined, maxRetries: 3 });
});
it("keeps OpenRouter advanced sync/routing settings global with undefined defaults", () => {
expect(DEFAULT_GLOBAL_SETTINGS.openrouterAppAttribution).toBeUndefined();
expect(DEFAULT_GLOBAL_SETTINGS.openrouterModelFilters).toBeUndefined();
expect(DEFAULT_GLOBAL_SETTINGS.openrouterProviderPreferences).toBeUndefined();
expect(isGlobalSettingsKey("openrouterAppAttribution")).toBe(true);
expect(isGlobalSettingsKey("openrouterModelFilters")).toBe(true);
expect(isGlobalSettingsKey("openrouterProviderPreferences")).toBe(true);
expect(isProjectSettingsKey("openrouterAppAttribution")).toBe(false);
expect(isProjectSettingsKey("openrouterModelFilters")).toBe(false);
expect(isProjectSettingsKey("openrouterProviderPreferences")).toBe(false);
});
it("defaults stale high fan-out blocker escalation age threshold", () => {
expect(DEFAULT_PROJECT_SETTINGS.staleHighFanoutBlockerAgeThresholdMs).toBe(2 * 60 * 60 * 1000);
expect(isProjectSettingsKey("staleHighFanoutBlockerAgeThresholdMs")).toBe(true);

View File

@@ -54,6 +54,9 @@ export const DEFAULT_GLOBAL_SETTINGS = {
favoriteProviders: undefined,
favoriteModels: undefined,
openrouterModelSync: true,
openrouterAppAttribution: undefined,
openrouterModelFilters: undefined,
openrouterProviderPreferences: undefined,
opencodeGoModelSync: true,
updateCheckEnabled: true,
fnBinaryCheckEnabled: true,

View File

@@ -1855,6 +1855,20 @@ export type AgentMemoryInclusionMode = "full" | "index" | "off";
export type HeartbeatScopeDisciplineMode = "strict" | "lite" | "off";
export type HeartbeatPromptTemplate = "default" | "compact";
export interface OpenRouterModelFilters {
supported_parameters?: string[];
output_modalities?: string[];
}
export interface OpenRouterProviderPreferences {
order?: string[];
ignore?: string[];
only?: string[];
allow_fallbacks?: boolean;
sort?: "price" | "throughput" | "latency";
require_parameters?: boolean;
}
export interface GlobalSettings {
/** Theme mode preference: dark, light, or system (follows OS). Default: "dark". */
themeMode?: ThemeMode;
@@ -1960,6 +1974,19 @@ export interface GlobalSettings {
* the OpenRouter API at startup so the model picker shows all available
* OpenRouter models (not just the static built-in list). Default: true. */
openrouterModelSync?: boolean;
/** Optional OpenRouter app-attribution header overrides.
* Use-time defaults are referer=`https://runfusion.ai` and title=`Fusion`.
* Empty string values intentionally suppress sending that header. */
openrouterAppAttribution?: { referer?: string; title?: string };
/** Optional OpenRouter model-catalog filters for startup sync fetches.
* Values are sent as comma-joined query params (`supported_parameters`,
* `output_modalities`) when configured. */
openrouterModelFilters?: OpenRouterModelFilters;
/** Optional OpenRouter provider routing preferences forwarded to chat
* completions as `compat.openRouterRouting`.
* Supports order/ignore/only provider lists, fallback behavior, sort mode,
* and require-parameters preference. */
openrouterProviderPreferences?: OpenRouterProviderPreferences;
/** When true, startup refreshes the opencode-go model catalog via
* `opencode models opencode --refresh` so model pickers expose an up-to-date
* opencode-go provider list without waiting for a later session bootstrap.