mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-15 19:52:50 +03:00
* fix(quality): clears two release/v3.8.50 base-red gates Unblocks Merge integrity and Docs Gates for every PR against release/v3.8.50, not just this branch: - changelog.d/features/9415-newapi-sub2api-aggregator-balance.md had a non-standard YAML frontmatter header that no other fragment in the tree uses. check-changelog-integrity.mjs reads a fragment's first non-blank line to validate it starts with a markdown bullet; the frontmatter's leading `---` made that check fail regardless of the actual bullet content further down. Removed the frontmatter and reformatted the body to match the documented changelog.d/README.md bullet convention. - docs/ops/VM_DEPLOYMENT_GUIDE.md documented OMNIROUTE_MAX_POOL_SIZE and OMNIROUTE_DB_POOL_SIZE as tunable env vars, but neither is read anywhere in the codebase (confirmed via full-repo grep) — this repo uses SQLite, which has no connection-pool concept these vars could plausibly control. check:fabricated-docs --strict correctly flags fabricated env-var claims; removed the bullet rather than implementing a feature to match invented documentation. * fix(i18n): completes Vietnamese parity, fixes empty migration query Two more release/v3.8.50 base-red items, both surfaced while chasing CI failures on unrelated PRs: - vi.json was missing 8 keys that #9539 (NewAPI/Sub2API aggregator balance) added to en.json without a matching i18n:sync-ui run — pt-BR.json already had all 8, only Vietnamese drifted. Added translations for the 6 provider-settings strings, the feature-flag description, and the quota tooltip; verified against tests/unit/i18n-vi-completeness.test.ts (parity, placeholder preservation, ICU parse — all 5 assertions pass). - src/lib/db/migrations/120_interception_rules.sql was pure comments documenting a no-schema-change key_value namespace, with no executable SQL statement — the migration runner logged "FAILED: 120_interception_rules — Query contained no valid SQL statement" on every fresh DB init. 118_provider_param_filters.sql (same pattern, two migrations earlier) already ends with a bare `SELECT 1;` no-op for exactly this reason; 120 was just missing it. Verified directly against better-sqlite3 that the file now executes without error. * fix(types): clears 6 pre-existing release/v3.8.50 typecheck errors typecheck:core is its own blocking CI job (quality.yml), separate from Docs Gates/Merge integrity. Confirmed pre-existing and unrelated to any current work by branching this worktree directly from upstream/release/v3.8.50 with no other merges applied. - accountSemaphore.ts: isBypassed() already excludes null/<=0 maxConcurrency before ensureGate() is called, but a boolean- returning helper isn't a type predicate TS can narrow through. Added a targeted `as number` at the one call site, with a comment explaining why it's safe. - combo/comboStructure.ts: two module-scope `const HARD_COMPAT_REASONS` declarations with different values — a genuine "can't redeclare" compile error, not a narrowing gap. The first (4-item set including "output_tokens") had zero usages between its own declaration and the second; the second (3-item set, matching the CompatFilterOptions doc comment exactly) is what hasHardCapabilityFailure/ describeCapabilityFilterExhaustion/the third call site all actually use. Removed the dead first declaration. - combo/comboStructure.ts + combo/fusionPanel.ts: both accessed `.prompt`/`.model` on a `ComboModelStep | ComboProviderWildcardStep` union after only excluding `combo-ref`, but `ComboProviderWildcardStep` has neither field — a real latent bug (fusionPanel would have pushed `undefined` into a fusion panel for a wildcard step). Narrowed to `step.kind === "model"` in comboStructure, and switched to the already-existing `getComboModelString()` helper in fusionPanel (which correctly resolves to null for unsupported step kinds, mirroring how combo-ref is already skipped there). Verified directly via a standalone script exercising both branches (wildcard vs. model step). - combo/quotaStrategies.ts: imported `preferAntigravityConnectionsWithStoredProject` from a module that never existed (`../antigravityProjectPersistence.ts`, distinct from the real `antigravityProjectPersist.ts`) — the function itself was referenced nowhere else in the codebase. Wrote the missing implementation: prefers Antigravity connections with a discovered `projectId` for reset-aware routing, failing open to the full list when none have one yet (per the file's own "Exclude... from reset-aware pool" changelog note, softened to a preference — strict exclusion would empty the pool entirely for a fleet of freshly-added accounts). Verified directly via a standalone script. - compression/engines/ccr/index.ts: `enforceGlobalBudget(owner, bytes)` was called with only `bytes` at one of its two call sites, missing the `owner` argument the other call site (and the function's own doc comment on preferring the calling principal's LRU eviction) already uses correctly. Added the missing `entry.principalId` argument. - firecrawlQuotaFetcher.ts: `fetchFirecrawlQuota` was annotated to return `Promise<QuotaInfo | null>` but every return path constructs a `FirecrawlQuota` (QuotaInfo extended with remainingCredits/planCredits/ extraCreditsInferred/overPlan) — the type the file already defines and the type `parseFirecrawlCreditUsage` already correctly returns. Widened the annotation to match; `FirecrawlQuota extends QuotaInfo` so this stays compatible with the `QuotaFetcher` contract. npm run typecheck:core and npm run check:dashboard-typecheck both pass cleanly. A subset of DB-backed tests in this area also fail, but 100% attributably to an already-tracked, unrelated migration version collision (134 -> [ccr_blocks, proxy_logs_egress_ip], see _tasks/features-v3.8.4/9route/POST-MERGE-AUDIT.md) — confirmed by every failure's stack trace bottoming out at that exact error, not at anything touched here. * fix(sse): update stale ALL_ACCOUNTS_INACTIVE test assertions to ALL_TARGETS_SKIPPED Two combo-routing-engine.test.ts cases assert the pre-dispatch-skip scenario (isModelAvailable always false, zero dispatch attempts) returns ALL_ACCOUNTS_INACTIVE. Production code already distinguishes this case via the recordedAttempts === 0 branch and returns the more precise ALL_TARGETS_SKIPPED -- the tests were never updated when that branch shipped upstream, so they fail on a clean release/v3.8.50 checkout independent of this PR's changes. * fix(sse): update second stale ALL_ACCOUNTS_INACTIVE assertion (T24) Same pre-existing upstream test-drift as038035f93: t23-t24-fallback-resilience.test.ts's T24 case asserts the pre-dispatch-skip scenario returns ALL_ACCOUNTS_INACTIVE, but production code returns the more precise ALL_TARGETS_SKIPPED when recordedAttempts === 0. Caught by this PR's own fresh CI run after the dirty-mergeable-state fix. * fix(quality): rebaseline combo-routing-engine.test.ts own-comment growth The ALL_ACCOUNTS_INACTIVE->ALL_TARGETS_SKIPPED fix (58ab721fe) added explanatory comments (+7 lines), pushing the file past its frozen 3457 cap. CI's PR-mode check:file-size caught it; local check-file-size.mjs was not re-run after that specific commit. * chore(tests): drop explanatory comments on ALL_TARGETS_SKIPPED assertions Kept the assertion value fix (ALL_ACCOUNTS_INACTIVE -> ALL_TARGETS_SKIPPED); the comments were unnecessary. Reverts the file-size baseline bump these comments caused (combo-routing-engine.test.ts back to its original 3457). --------- Co-authored-by: Will Gordon <wgordon@redhat.com>
84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
/**
|
|
* Fusion panel member extraction — resolves combo.models entries for the
|
|
* fusion strategy, including nested `combo-ref` steps (#6764).
|
|
*
|
|
* A combo-ref panel member is dispatched as ONE black-box panel voice (a full
|
|
* recursive handleComboChat call for the referenced combo, reusing the same
|
|
* executeComboRefUnit + cycle/depth guards every other combo-ref-consuming
|
|
* strategy already uses) — NOT a fan-out of the referenced combo's own
|
|
* targets. This keeps panel sizing and cost predictable and matches how a
|
|
* literal `auto/*` string panel member already behaves via the single-
|
|
* dispatch safety net in src/sse/handlers/chat.ts.
|
|
*/
|
|
import { getComboModelString, normalizeComboStep } from "../../../src/lib/combos/steps.ts";
|
|
import { executeComboRefUnit } from "./runtimeUnits.ts";
|
|
import type {
|
|
ComboCollectionLike,
|
|
ComboNestingContext,
|
|
HandleComboChatOptions,
|
|
HandleSingleModel,
|
|
ResolvedComboRefTarget,
|
|
} from "./types.ts";
|
|
|
|
export type FusionPanelSpec = {
|
|
/** Dispatch keys handed to fusion.ts's `models` — comboName for combo-ref members, plain model string otherwise. */
|
|
panel: string[];
|
|
/** comboName -> resolved combo-ref unit, consumed by buildFusionHandleSingleModel. */
|
|
comboRefUnits: Map<string, ResolvedComboRefTarget>;
|
|
};
|
|
|
|
export function extractFusionPanelSpec(
|
|
models: unknown[],
|
|
comboName: string,
|
|
allCombos: ComboCollectionLike
|
|
): FusionPanelSpec {
|
|
const panel: string[] = [];
|
|
const comboRefUnits = new Map<string, ResolvedComboRefTarget>();
|
|
models.forEach((entry, index) => {
|
|
const step = normalizeComboStep(entry, { comboName, index, allCombos });
|
|
if (!step) return;
|
|
if (step.kind === "combo-ref") {
|
|
if (!comboRefUnits.has(step.comboName)) {
|
|
comboRefUnits.set(step.comboName, {
|
|
kind: "combo-ref",
|
|
stepId: step.id,
|
|
executionKey: step.id,
|
|
comboName: step.comboName,
|
|
weight: step.weight,
|
|
label: step.label ?? null,
|
|
});
|
|
}
|
|
panel.push(step.comboName);
|
|
return;
|
|
}
|
|
// Provider-wildcard steps have no concrete model to dispatch — fusion is a
|
|
// fixed-size panel of literal models/combo-refs, not a wildcard-expanding
|
|
// strategy (see file header). Skip rather than push an undefined model.
|
|
const modelStr = getComboModelString(step);
|
|
if (modelStr) panel.push(modelStr);
|
|
});
|
|
return { panel, comboRefUnits };
|
|
}
|
|
|
|
export function buildFusionHandleSingleModel(args: {
|
|
handleSingleModel: HandleSingleModel;
|
|
comboRefUnits: Map<string, ResolvedComboRefTarget>;
|
|
allCombos: ComboCollectionLike;
|
|
nesting: ComboNestingContext;
|
|
baseOptions: HandleComboChatOptions;
|
|
runCombo: (options: HandleComboChatOptions) => Promise<Response>;
|
|
}): HandleSingleModel {
|
|
return (body, modelStr, target) => {
|
|
const unit = args.comboRefUnits.get(modelStr);
|
|
if (!unit) return args.handleSingleModel(body, modelStr, target);
|
|
return executeComboRefUnit({
|
|
body,
|
|
unit,
|
|
allCombos: args.allCombos,
|
|
runCombo: args.runCombo,
|
|
baseOptions: args.baseOptions,
|
|
nesting: args.nesting,
|
|
});
|
|
};
|
|
}
|