Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062,
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051,
"src/shared/components/ModelSelectModal.tsx": 1138,
"src/shared/constants/providers/apikey/gateways.ts": 1250,
"src/shared/constants/providers/apikey/gateways.ts": 1255,
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1387,
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry": "DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legitima acima do cap; gateways.ts = god-file de catalogo de providers que cresceu com PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o proprio PR #9421 quebrou o arquivo); bridge.ts (PR #8949) = ponte Chromium vendored; proxyFetch.ts 1207->1220 = drift herdado de merges. Owner autorizou rebaseline com anotacao (2026-08-11).",
"src/lib/modelCapabilities.ts": 1006,
Expand Down Expand Up @@ -609,5 +609,6 @@
"_rebaseline_2026_08_06_9006_reconcile_onto_tip_2": "PR #9006 (fix/vertex-claude-catalog-dispatch) second rebase-onto-tip reconciliation. Same two files as _rebaseline_2026_08_04_9006_reconcile_onto_tip below, further inherited drift, still not this PR's own growth (verified via git diff against the fresh upstream/release/v3.8.50 merge-base — this PR's own commits still touch neither file): open-sse/executors/base.ts 1623->1640 (+17) and src/sse/handlers/chat.ts 1847->1881 (+34), both measured post-merge via split(\"\\n\").length. More already-merged release/v3.8.50 PRs grew these files without updating their baseline entries (same root cause as every other entry in this chain: fast-gates PR->release does not run check:file-size). No offending branch left to fix.",
"_rebaseline_2026_08_12_v3850_basereds_round3": "Base-reds round 3 (#9985, 2026-08-12): ModelSelectModal.tsx 1135->1138 = base drift from the #10198 SWR/build repair (flagged as non-blocking drift by Release-Green run 31634993212, rebaselined here so the PR queue's Fast Quality Gates stop failing on inherited drift); gateways.ts 1215->1250 = base drift from the 08-12 merges (#10131 regolo/naga-ac repair, #9210 void-ai+helixmind) plus this PR restoring the chatanywhere metadata entry that round 2 dropped along with its duplicate (wave3 audited entry, +16 lines; same god-file no-split rationale as the 2026-08-11 annotation). Owner-authorized sweep (/sweep-reds).",
"_rebaseline_2026_08_12_proxyfetch_redaction": "Base-reds round 3 (#9985): proxyFetch.ts 1220->1239 (+19) = redactProxyDetailsInMessage() helper closing the credential leak #10032 reintroduced (raw proxy URL with user:password appended to the propagated error, Hard Rule #12); irreducible security fix at the existing error-surface chokepoint. Covered by tests/unit/tls-proxy-context.test.ts (strengthened leak guards).",
"_rebaseline_2026_08_12_modelcapabilities_snapshot_routing": "Base-reds round 3 (#9985): modelCapabilities.ts crossed the new-file cap at 1006 (+~10) when the context/max-input-token override lookups were routed through the #9199 bulk snapshot (fixing 323 per-model SQLite reads per catalog prepare — auto-combo-context-advertising guard); cohesive change at the existing resolution chokepoints, not extractable. Covered by tests/unit/auto-combo-context-advertising.test.ts + model-capability-resolution-snapshot-9199.test.ts."
"_rebaseline_2026_08_12_modelcapabilities_snapshot_routing": "Base-reds round 3 (#9985): modelCapabilities.ts crossed the new-file cap at 1006 (+~10) when the context/max-input-token override lookups were routed through the #9199 bulk snapshot (fixing 323 per-model SQLite reads per catalog prepare — auto-combo-context-advertising guard); cohesive change at the existing resolution chokepoints, not extractable. Covered by tests/unit/auto-combo-context-advertising.test.ts + model-capability-resolution-snapshot-9199.test.ts.",
"_rebaseline_2026_08_14_imagetotext_servicekinds": "Image-to-Text category (#10275/#10291): gateways.ts grew 1250→1255 by data lines only — the serviceKinds: [\"llm\", \"imageToText\"] declarations on the openrouter and chutes catalog entries, plus the 3-line comment recording why chutes needs no static dots.ocr entry (passthroughModels discovery). No new logic or branching; the file is a provider catalog of declarative metadata. Splitting a catalog for five lines would be worse than the growth (semantic-families rule)."
}
5 changes: 3 additions & 2 deletions config/quality/quality-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
"_rebaseline_2026_07_28_v3849_release": "75.5 -> 99 (+23.5). Aperto EXIGIDO pelo modo --require-tighten do ratchet: a métrica melhorou de verdade no ciclo v3.8.49. A causa é o workflow assíncrono de tradução, que finalmente alcançou o denominador em EN — as rebaselines anteriores (v3.8.39/.44/.47) foram todas afrouxamentos registrando o atraso das traduções, e agora ele foi pago. O coletor SUBTRAI os placeholders (present - placeholder em scripts/quality/collect-metrics.mjs), então os 317 marcadores __MISSING__ que esta release introduziu para o drift de valor já estão descontados dos 99 — o número é honesto, não inflado por placeholder. Medido pelo collect-metrics do CI no run 30404226939."
},
"deadExports": {
"value": 409,
"value": 415,
"direction": "down",
"_rebaseline_2026_08_09_v3850_post_sweep": "227 -> 230. Measured by npm run check:dead-code on the unmodified release/v3.8.50 tip 382449d593 during the mandatory --full-ci pre-flight. The +3 is inherited cycle drift from the authorized merge sweep; this repair adds no production exports. Rebaseline records the actual tip so ci.yml quality-gate can run, while structural cleanup remains separate debt.",
"_rebaseline_2026_07_01_v3843_release": "225->227 (+2). v3.8.43 cycle drift, surfaced in the Quality Ratchet job after eslintWarnings was rebaselined (check:dead-code runs there). 227 = measured by check:dead-code (knip) on the release tip 4635076eb. The 5 CI fixes add 0 dead exports: safeHttpHref in linkify.ts is module-local AND used (called by linkifyText); no new exports; test files are not scanned. Tighten via --update next cycle.",
Expand All @@ -111,7 +111,8 @@
"_rebaseline_2026_06_27_v3838_release": "345->346 (+1). v3.8.38 cycle drift surfaced by the release-green pre-flight (Quality Ratchet does NOT run on PR->release fast-gates). Net +1 inherited from this cycle's feature/fix merges (new executors/providers, compression fidelity-gate module) minus #5138's removal of dead legacy store modules. Release-finalize working tree touches ONLY CHANGELOG.md + i18n mirrors + README + baselines — 0 production-code change. Structural cleanup tracked as debt.",
"_rebaseline_2026_06_26_v3837_release": "343->345. v3.8.37 cycle drift surfaced by the release-green pre-flight (the Quality Ratchet does NOT run on PR->release fast-gates, so warnings/complexity accrued unmeasured across this cycle's 76 commits — provider adds DGrid/Pioneer/xAI, headroom proxy lifecycle #4649, ~50 SSE/translator fixes, Engine Combos #5062). Trust-but-verify: this release-finalize working tree touches ONLY CHANGELOG.md, docs/i18n/*/CHANGELOG.md mirrors, and these baselines — 0 production-code change, so all drift is inherited cycle drift (`any` warn-allowed in open-sse/ + tests/). Tighten via --require-tighten next cycle.",
"_rebaseline_2026_08_11_v3850_merge_storm": "230 -> 248. Own drift from the 2026-08-11 merge storm (99 PRs into release/v3.8.50 via authorized sweep): new providers/executors/handlers added dead exports that knip cannot see as used. Measured on the base-fix tip (7ca73697b0 + this repair PR). Owner authorized rebaseline (2026-08-11) — structural cleanup remains separate debt.",
"_rebaseline_2026_08_13_v3850_knip_bump": "248 -> 409. NOT code-added dead exports: dependabot bump #10043 (2026-08-13) upgraded knip 6.27.0 -> 6.32.x, and the new knip detects 162 MORE genuinely-unused exports (331 vs 169 deadExports) that 6.27 missed. DEAD_FILES unchanged (78). Reproduced identically on the clean release/v3.8.50 tip 266e39d3 with a fresh knip 6.32 node_modules — so every PR is born red on this gate until the tool change is absorbed. Owner authorized rebaseline (2026-08-13, via base-reds PR #10260). Structural cleanup of the 162 newly-surfaced dead exports remains separate debt."
"_rebaseline_2026_08_13_v3850_knip_bump": "248 -> 409. NOT code-added dead exports: dependabot bump #10043 (2026-08-13) upgraded knip 6.27.0 -> 6.32.x, and the new knip detects 162 MORE genuinely-unused exports (331 vs 169 deadExports) that 6.27 missed. DEAD_FILES unchanged (78). Reproduced identically on the clean release/v3.8.50 tip 266e39d3 with a fresh knip 6.32 node_modules — so every PR is born red on this gate until the tool change is absorbed. Owner authorized rebaseline (2026-08-13, via base-reds PR #10260). Structural cleanup of the 162 newly-surfaced dead exports remains separate debt.",
"_rebaseline_2026_08_14_ocr_imagetotext_series": "OCR/image-to-text series (#10275/#10283/#10287/#10289/#10291): deadExports 409 -> 415. Each PR in the series adds public util/registry exports that are exercised by their unit tests but not yet by a second production caller — normalizeImageBuffer (imageNormalize), MISTRAL_PASSTHROUGH / AZURE_DI_TRANSFORMATION / getOcrTransformation (ocrRegistry), resolveOcrCredentials (v1/ocr route). They are the documented public surface of the new modules and are covered by tests; structural cleanup stays tracked in #3501."
},
"cognitiveComplexity": {
"value": 1223,
Expand Down
19 changes: 16 additions & 3 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6840,9 +6840,17 @@ paths:
- Images
summary: Document OCR
description: >-
Mistral OCR–compatible document OCR endpoint. Accepts a JSON body
referencing a document/image and returns extracted text. Success
responses carry the `X-OmniRoute-*` cost-telemetry headers.
Multi-provider document OCR endpoint (Mistral OCR–compatible request
and response shape). Accepts a JSON body referencing a document/image
and returns extracted text. `model` selects the provider via a
`provider/model` prefix (e.g. `mistral/mistral-ocr-latest`,
`azure-document-intelligence/prebuilt-read`); a bare model id (e.g.
`mistral-ocr-latest`) resolves to its registered provider, and an
omitted `model` defaults to Mistral. Azure Document Intelligence is
asynchronous upstream — the handler polls the returned operation
until it succeeds or fails before responding, so this endpoint can
take longer to return for that provider. Success responses carry the
`X-OmniRoute-*` cost-telemetry headers.
security:
- BearerAuth: []
requestBody:
Expand All @@ -6854,6 +6862,11 @@ paths:
properties:
model:
type: string
description: >-
`provider/model` id or bare model id. Registered ids:
`mistral/mistral-ocr-latest`,
`azure-document-intelligence/prebuilt-read`. Defaults to
`mistral-ocr-latest` when omitted.
document:
type: object
responses:
Expand Down
74 changes: 61 additions & 13 deletions docs/reference/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Complete reference for all OmniRoute API endpoints.
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [Document OCR](#document-ocr)
- [List Models](#list-models)
- [Provider Plugin Manifest](#provider-plugin-manifest)
- [Compatibility Endpoints](#compatibility-endpoints)
Expand Down Expand Up @@ -199,6 +200,53 @@ GET /v1/images/generations

---

## Document OCR

```bash
POST /v1/ocr
Authorization: Bearer your-api-key
Content-Type: application/json

{
"model": "mistral/mistral-ocr-latest",
"document": {
"type": "document_url",
"document_url": "https://example.com/invoice.pdf"
}
}
```

`model` selects the OCR provider via a `provider/model` prefix; a bare model id (e.g.
`mistral-ocr-latest`) resolves to its registered provider, and an omitted `model` defaults to
Mistral (`mistral-ocr-latest`). Registered providers (`open-sse/config/ocrRegistry.ts`):

| Provider id | Model id | `model` value | Notes |
| ----------------------------- | -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `mistral` | `mistral-ocr-latest` | `mistral/mistral-ocr-latest` (or bare `mistral-ocr-latest`) | Synchronous — the response is returned directly from the single upstream call. |
| `azure-document-intelligence` | `prebuilt-read` | `azure-document-intelligence/prebuilt-read` | Asynchronous upstream (`analyze` + poll) — see below. |

Both providers respond in the same Mistral-shaped body:

```json
{
"pages": [{ "index": 0, "markdown": "# Extracted text..." }],
"model": "mistral-ocr-latest",
"usage_info": { "pages_processed": 1 }
}
```

### Azure Document Intelligence poll flow

Azure Document Intelligence's `analyze` API is asynchronous: the initial request returns an
`Operation-Location` header instead of a body, and the result must be polled for. The handler
(`open-sse/handlers/ocr.ts`) polls that URL every second for up to 30 attempts, fails fast (does
not keep polling) on a non-`ok` poll response or a `"failed"` status, and returns `504` if the
operation is still running after the attempt budget is exhausted. The final Azure response is
normalized into the same `pages`/`markdown` shape used by Mistral before being returned to the
caller, so client code does not need to special-case the provider.

---

## List Models

```bash
Expand Down Expand Up @@ -489,18 +537,18 @@ call**, so the reported `X-OmniRoute-Response-Latency` is near-zero
(benchmarking, p50/p99 monitoring) should check the
`X-OmniRoute-Cache-Latency` response header:

| Value | Meaning |
|-------|---------|
| Value | Meaning |
| ----------- | ------------------------------------------------------------- |
| `synthetic` | Response served from cache; latency is not real upstream time |
| *(absent)* | Response from real upstream call |
| _(absent)_ | Response from real upstream call |

### Per-key cache bypass

API keys can opt out of semantic cache reads via `cacheDefaultMode`:

| Value | Behavior |
|-------|----------|
| `legacy` | Normal cache behavior (default) |
| Value | Behavior |
| -------- | ----------------------------------------------- |
| `legacy` | Normal cache behavior (default) |
| `bypass` | Skip cache lookup entirely; always hit upstream |

Set at key creation (`POST /api/keys`) or update (`PATCH /api/keys/[id]`):
Expand Down Expand Up @@ -603,13 +651,13 @@ X-OmniRoute-No-Cache: true

### Monitoring

| Endpoint | Method | Description |
| ------------------------ | ---------- | ---------------------------------------------------------------------------------------------------- |
| `/api/sessions` | GET | Active session tracking |
| `/api/rate-limits` | GET | Per-account rate limits |
| `/api/monitoring/health` | GET | Health check + provider summary (`catalogCount`, `configuredCount`, `activeCount`, `monitoredCount`) |
| `/api/cache/stats` | GET/DELETE | Cache stats / clear |
| `/api/modality-bridge/stats` | GET | In-memory Modality Bridge telemetry — per-modality `bridged`/`cacheHits`/`failures`/`lastUsedAt` counters (reset on restart; management auth) |
| Endpoint | Method | Description |
| ---------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `/api/sessions` | GET | Active session tracking |
| `/api/rate-limits` | GET | Per-account rate limits |
| `/api/monitoring/health` | GET | Health check + provider summary (`catalogCount`, `configuredCount`, `activeCount`, `monitoredCount`) |
| `/api/cache/stats` | GET/DELETE | Cache stats / clear |
| `/api/modality-bridge/stats` | GET | In-memory Modality Bridge telemetry — per-modality `bridged`/`cacheHits`/`failures`/`lastUsedAt` counters (reset on restart; management auth) |

### Backup & Export/Import

Expand Down
18 changes: 18 additions & 0 deletions open-sse/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,24 @@ export const HTTP_STATUS = {
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
};

/**
* #10360 — stable error code for an INTERNAL violation of the executor
* `execute()` result contract (`normalizeExecutorResult` received something
* that is neither a Response nor `{ response: Response }`).
*
* This is our own bug, never a provider/account health signal, so every
* resilience layer must treat it as request-scoped and terminal: no connection
* cooldown, no provider circuit-breaker trip, no retry. It rides on the error's
* `.code` (read by `getUpstreamErrorIdentifier`) and therefore reaches
* `checkFallbackError` as `structuredError.code` and the chat/combo predicates
* as `result.errorCode`.
*
* Lives here (leaf config module) so both `open-sse/handlers/` and
* `open-sse/services/` can import it without creating a cycle.
*/
export const EXECUTOR_CONTRACT_VIOLATION_CODE = "executor_contract_violation";

export {
BACKOFF_CONFIG,
COOLDOWN_MS,
Expand Down
Loading
Loading