Compare commits

...

7 Commits

Author SHA1 Message Date
Markus Hartung
abf8938fc2 docs(providers): register providers removed at their operator's request and guard against reintroduction
Adds docs/reference/REMOVED_PROVIDERS.md (policy + register: puter #10210,
the keyless provider removed in #12440), links it from the docs index and
AGENTS.md's provider checklist, and adds a regression test that fails if any
registered id, alias or domain shows up again in the provider catalogs, the
executor map or the registry/executor sources.
2026-09-02 10:20:37 -03:00
Diego Rodrigues de Sa e Souza
53b037051b test(grok): format web executor suite (#12412)
Applies the repository Prettier style to tests/unit/grok-web.test.ts. No production code, no assertion changes.

The AST-identical claim was verified independently rather than taken on trust: minifying both sides through esbuild produces byte-identical output.

The reformat expands the file from 2436 to 2713 lines, past its 2437 cap, so the baseline carries a new annotated entry at 2985 — the real LOC plus ~10% headroom, per the operator's instruction, so routine additions to this suite do not re-trip the gate on formatting alone. It is recorded as a deliberate exception to the down-only ratchet #12411 re-tightened; no other entry moves.

Verified: 68/68 in the reformatted suite, check-file-size OK.
2026-09-02 10:14:53 -03:00
Diego Rodrigues de Sa e Souza
c420a51df6 fix(providers): finalize Nimble and Opper asset provenance (#12415)
Closes the two remaining unresolved provider-asset records without weakening the provenance boundary: public/providers/nimble-search.svg is removed because no sufficient redistribution evidence is recorded, and Nimble Search renders with the internal generic icon before any CDN tier while staying fully functional; Opper is registered in the local SVG resolver with its existing bytes proven against opper-ai/provider-omniroute at immutable commit 9aacef7d6a, recording the MIT repository license from that same commit while keeping trademarkClearance null.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to #12427, which is held back.
2026-09-02 10:02:03 -03:00
Diego Rodrigues de Sa e Souza
d6412532c4 chore(quality): ratchet open-sse typecheck baseline to zero (#12418)
The current release dependencies already resolve the ChatGPT Web vendor diagnostics the allowance covered, so the stale open-sse typecheck allowance is removed and any future diagnostic becomes a blocking regression again. No vendor source, package manifest, checker script or runtime behaviour changes.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to #12427, which is held back.
2026-09-02 10:01:58 -03:00
Diego Rodrigues de Sa e Souza
a25ac4d979 fix(types): make system prompt injection noImplicitAny-safe (#12416)
Closes the remaining noImplicitAny gap in global system-prompt injection without changing valid OpenAI or Claude request behaviour: injectSystemPrompt gets a caller-preserving generic type, unknown bodies/message entries/content are narrowed before access, malformed entries are skipped instead of throwing, and request/message/content immutability is preserved.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to #12427, which is held back.
2026-09-02 10:01:55 -03:00
Diego Rodrigues de Sa e Souza
089e70cbc5 fix(quality): validate typecheck baseline schema (#12419)
The API-route and Open-SSE typecheck gates treated every top-level baseline value as a diagnostic map, so policy metadata such as _relax_velocity_2026_08_30 was iterated character by character and reported as fabricated numeric TypeScript improvements. Both gates now share one fail-closed baseline boundary: underscore-prefixed top-level keys are reserved for metadata and skipped, and real file entries must be plain objects.

Worth a follow-up: check-dashboard-typecheck still prints the same fabricated entries, so it looks like a third gate with the same defect that this PR's scope does not cover.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to #12427, which is held back.
2026-09-02 10:01:51 -03:00
Diego Rodrigues de Sa e Souza
7c119dd7ed fix(memory): resolve rerank provider node cache import (#12421)
The rerank-provider listing route dynamically imported @/lib/localDb — the barrel Hard Rule #2 forbids — and the stale path meant local rerank-capable provider nodes never appeared in GET /api/memory/rerank-providers. Now imports the specific @/lib/db/readCache module, with a route-level regression test through the public GET handler.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to #12427, which is held back.
2026-09-02 10:01:47 -03:00
22 changed files with 899 additions and 234 deletions

View File

@@ -343,6 +343,7 @@ Documentation must describe verified behavior, not plausible behavior.
### Adding a New Provider
0. Check `docs/reference/REMOVED_PROVIDERS.md` first — providers removed at their operator's request must never be reintroduced (guarded by `tests/unit/removed-providers-blocklist.test.ts`)
1. Register in `src/shared/constants/providers.ts` (Zod-validated at load)
2. Add executor in `open-sse/executors/` if custom logic needed (extend `BaseExecutor`)
3. Add translator in `open-sse/translator/` if non-OpenAI format

View File

@@ -0,0 +1 @@
- Render Nimble Search with the generic provider icon and serve Opper's proven logo locally.

View File

@@ -1,4 +1,5 @@
{
"_rebaseline_2026_09_02_12412_grok_web_prettier": "PR #12412 (repository Prettier style applied to tests/unit/grok-web.test.ts): the reformat expands the file +277 lines (2436 -> 2713) with an identical parsed AST — no production code, no assertion changes. Cap set to 2985 rather than the exact 2713 on the operator's instruction (2026-09-02): ~10% headroom so routine additions to this suite do not re-trip the gate on formatting alone. Previous cap 2437. This is a deliberate exception to the down-only ratchet for one reformatted test file; every other entry keeps the #12411 tightening.",
"_rebaseline_2026_09_02_v3851_merged_growth_basereds": "Base-red drain: the 2026-09-02 merge waves (#12359-#12404, #11461, #11513, #12423) each grew a frozen file at an existing chokepoint, but the rebaseline was computed in the throwaway combined validation worktree and never reached any PR branch, so the growth landed while the caps did not and check-file-size went red on the release tip. Recorded here against the merged state: src/app/api/providers/[id]/models/route.ts 2429->2432 (#12389 gemini-business listing on top of #11461's 2429); src/app/api/v1/models/catalog.ts 2066->2075 (#12381 self-aliased canonical rows + #12403 NUL escape); src/lib/db/core.ts 1740->1745 (#12394 busy_timeout ordering + probe classification); src/sse/handlers/chat.ts 2375->2384 (#12360 breaker result classification + #12365 shadowed-node error); src/sse/services/auth.ts 3420->3427 (#12375 backoffLevel tie-break); open-sse/handlers/imageGeneration.ts 3255->3259 (#11513 uc-image branch + #12423 uc-image id scoping); open-sse/utils/proxyFetch.ts 1261->1271 (#12380 hasAmbientProxyContext()); tests/unit/image-generation-handler.test.ts 2110->2133 (#12362 regression coverage); tests/unit/sse-auth.test.ts 1697->1729 (#12375 regression coverage). No cap is raised beyond the merged LOC; every other entry is untouched.",
"_rebaseline_2026_09_02_11513_uc_provider": "PR #11513 (arminanton, feat/uc-native-standalone) own growth: open-sse/handlers/imageGeneration.ts 3243->3255 (+12) — the uc-image format branch for the UC persona provider's image surface. Additive at the existing per-format chokepoint, same rationale as _rebaseline_2026_09_02_11461_maxai_tls_profile.",
"_rebaseline_2026_09_02_11461_maxai_tls_profile": "PR #11461 (arminanton, feat/maxai-provider) own growth, three files at existing per-provider chokepoints: open-sse/utils/proxyFetch.ts 1241->1261 (+20, the TLS_PROVIDER_PROFILE map giving MaxAI a Windows/firefox_150 impersonation profile instead of the tlsClient chrome_124/macos default); open-sse/handlers/imageGeneration.ts 3231->3243 (+12, the maxai-image format branch); src/app/api/providers/[id]/models/route.ts 2381->2429 (+48, live model listing via maxaiModels). Additive data, same no-split rationale as _rebaseline_2026_08_20_10531_freebuff_provider.",
@@ -210,7 +211,7 @@
"tests/unit/db-migration-runner.test.ts": 1509,
"tests/unit/executor-codex.test.ts": 1465,
"tests/unit/executor-default-base.test.ts": 1632,
"tests/unit/grok-web.test.ts": 2437,
"tests/unit/grok-web.test.ts": 2985,
"tests/unit/image-generation-handler.test.ts": 2133,
"tests/unit/models-catalog-route.test.ts": 1652,
"tests/unit/perplexity-web.test.ts": 1384,

View File

@@ -1,9 +1 @@
{
"src/lib/guardrails/videoBridgeHelpers.ts": {
"TS2488": 2,
"TS2365": 3,
"TS2322": 2,
"TS2345": 2
},
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (5 → 9); velocity phase, see quality-baseline.json _policy."
}
{}

View File

@@ -1,4 +1,4 @@
{"recordType": "manifest", "schemaVersion": 1, "expectedAssetCount": 142, "auditedCommit": "7d57d9f4a15931aa33a9ab968e4e5d76a205e27c", "auditedAt": "2026-08-28", "scope": "Every regular file directly under public/providers at the audited commit.", "statusSemantics": {"proven": "Immutable source plus byte-exact or SVG path-data match.", "probable": "Repository evidence suggests provenance, but no immutable upstream match is proven.", "unresolved": "No sufficient immutable provenance evidence is recorded."}, "enforcement": "All physical files, hashes, magic MIME values, statuses, and duplicate aliases are blocking. Probable and unresolved statuses are recorded but non-blocking in schema version 1.", "legalScope": "Provenance records source matching only; it does not establish copyright or trademark clearance."}
{"recordType": "manifest", "schemaVersion": 1, "expectedAssetCount": 141, "auditedCommit": "ccb024cfa9a7612fa65b1f1795740572369d58f5", "auditedAt": "2026-09-02", "scope": "Every regular file directly under public/providers at the audited commit.", "statusSemantics": {"proven": "Immutable source plus byte-exact or SVG path-data match.", "probable": "Repository evidence suggests provenance, but no immutable upstream match is proven.", "unresolved": "No sufficient immutable provenance evidence is recorded."}, "enforcement": "All physical files, hashes, magic MIME values, statuses, and duplicate aliases are blocking. Probable and unresolved statuses are recorded but non-blocking in schema version 1.", "legalScope": "Provenance records source matching only; it does not establish copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/360ai.svg", "mediaType": "image/svg+xml", "sha256": "59366fe04a4336518b8277b430f4a464a91e7ec944c9cf6f40a945c74002386d", "provenanceStatus": "proven", "source": {"kind": "npm", "url": "https://registry.npmjs.org/@lobehub/icons/-/icons-5.10.0.tgz", "ref": "5.10.0", "path": "package/es/Ai360/components/Color.js", "integrity": "sha512-CIpjkISCLRK7haDtSugGFd0o3odaJts8ewJOkUiEFtns3xvsqbl8i24eowBnjw+yMDQVQyNONlhqTD58YC6Ljg==", "packageShasum": "add1baced073a60157d39c7820b8d5c1928a1054", "match": "svg-path-data", "matchDetail": "All 5/5 local SVG path d values match the pinned Color component."}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "@lobehub/icons@5.10.0 package/LICENSE", "evidence": "https://registry.npmjs.org/@lobehub/icons/-/icons-5.10.0.tgz#package/LICENSE", "independentlyVerified": true, "scope": "Pinned package distribution only; no trademark clearance."}, "trademarkClearance": null, "evidenceNote": "All local SVG path data matches the pinned LobeHub Color component. This proves source provenance only, not trademark clearance."}
{"recordType": "asset", "path": "public/providers/alibaba.svg", "mediaType": "image/svg+xml", "sha256": "1cd1e7be5108d1e847508dc9e40591fb6eb29aac20bbf7f4c56c6f082359b323", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/alibaba/default.svg", "integrity": "sha256:1cd1e7be5108d1e847508dc9e40591fb6eb29aac20bbf7f4c56c6f082359b323", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://alibaba.com"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/anthropic.svg", "mediaType": "image/svg+xml", "sha256": "7fea3100bfc2a9480e181fc615d4791cab014f54674b83953785abb86dc293f0", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/anthropic/default.svg", "integrity": "sha256:7fea3100bfc2a9480e181fc615d4791cab014f54674b83953785abb86dc293f0", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "CC0-1.0", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://www.anthropic.com/"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
@@ -80,7 +80,6 @@
{"recordType": "asset", "path": "public/providers/moonshot.svg", "mediaType": "image/svg+xml", "sha256": "a6ac95d972fdb044cd4155b0f75d9c1c816348868c810f63c7e5c8840c9e3e12", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/moonshot/default.svg", "integrity": "sha256:a6ac95d972fdb044cd4155b0f75d9c1c816348868c810f63c7e5c8840c9e3e12", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://moonshot.cn"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/morph.svg", "mediaType": "image/svg+xml", "sha256": "0fdb479e13c5d5de15aa89d1f87c8d55f8f8a56d33fc5dee8c566d2e0dbd5b96", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/morph/default.svg", "integrity": "sha256:0fdb479e13c5d5de15aa89d1f87c8d55f8f8a56d33fc5dee8c566d2e0dbd5b96", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://morphllm.com"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/nebius.svg", "mediaType": "image/svg+xml", "sha256": "fb190b4efb1d143442ef6c5eb0258801fc27b7316e88216c59a0f4b58b8b0281", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/nebius/default.svg", "integrity": "sha256:fb190b4efb1d143442ef6c5eb0258801fc27b7316e88216c59a0f4b58b8b0281", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://nebius.com"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/nimble-search.svg", "mediaType": "image/svg+xml", "sha256": "c22d214880d1cbf48aa08617fbc245b96f7372fe5602ef1382978eee522c6575", "provenanceStatus": "unresolved", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Added by an unrelated already-merged provider PR (#11620/#11629); no provenance research recorded yet. Flagged unresolved pending review, per schema v1 (non-blocking)."}
{"recordType": "asset", "path": "public/providers/nomic.svg", "mediaType": "image/svg+xml", "sha256": "73cc513c9d5f460ec8f00a097f3fabaa54c0e1f824944412e9a4461c0620fba6", "provenanceStatus": "probable", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Repository history shows a shared generic initial-badge pattern, but no immutable authorship or license evidence is recorded."}
{"recordType": "asset", "path": "public/providers/novita.svg", "mediaType": "image/svg+xml", "sha256": "ab99ef3113a12e64ef8b44eda132094017359ede5bdb33e830ed855b69520612", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/novita/default.svg", "integrity": "sha256:ab99ef3113a12e64ef8b44eda132094017359ede5bdb33e830ed855b69520612", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://novita.ai/"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/nube.svg", "mediaType": "image/svg+xml", "sha256": "e5eff793cbc8a917e499c18365979f001010b229dd53b0802d5f29d9dfb963e1", "provenanceStatus": "probable", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Repository PR #6926 describes this family as letter-in-circle placeholders, but original authorship and license were not independently proven."}
@@ -90,7 +89,7 @@
{"recordType": "asset", "path": "public/providers/openai.svg", "mediaType": "image/svg+xml", "sha256": "db81a8225166f02f773304ba4d8f0141343da5f43870d8b41f10bf6bc59840c8", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/openai/default.svg", "integrity": "sha256:db81a8225166f02f773304ba4d8f0141343da5f43870d8b41f10bf6bc59840c8", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://openai.com/"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/openclaw.svg", "mediaType": "image/svg+xml", "sha256": "4123c0c75dda5b28e3e0d38075514085bf546178a620776344813c08fa41277c", "provenanceStatus": "proven", "source": {"kind": "npm", "url": "https://registry.npmjs.org/@lobehub/icons/-/icons-5.10.0.tgz", "ref": "5.10.0", "path": "package/es/OpenClaw/components/Color.js", "integrity": "sha512-CIpjkISCLRK7haDtSugGFd0o3odaJts8ewJOkUiEFtns3xvsqbl8i24eowBnjw+yMDQVQyNONlhqTD58YC6Ljg==", "packageShasum": "add1baced073a60157d39c7820b8d5c1928a1054", "match": "svg-path-data", "matchDetail": "All 6/6 local SVG path d values match the pinned Color component."}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "@lobehub/icons@5.10.0 package/LICENSE", "evidence": "https://registry.npmjs.org/@lobehub/icons/-/icons-5.10.0.tgz#package/LICENSE", "independentlyVerified": true, "scope": "Pinned package distribution only; no trademark clearance."}, "trademarkClearance": null, "evidenceNote": "All local SVG path data matches the pinned LobeHub Color component. This proves source provenance only, not trademark clearance."}
{"recordType": "asset", "path": "public/providers/openrouter.svg", "mediaType": "image/svg+xml", "sha256": "d05021526e72fddf3426eabc066924aca83da0cd66a699a3de3bac58ed2fe0a2", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/openrouter/default.svg", "integrity": "sha256:d05021526e72fddf3426eabc066924aca83da0cd66a699a3de3bac58ed2fe0a2", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "CC0-1.0", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://openrouter.ai/"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/opper.svg", "mediaType": "image/svg+xml", "sha256": "e45d0409e7746946f204903ad6e7da267d805b7d7534fa684eeb7b8ac5717791", "provenanceStatus": "unresolved", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Added by an unrelated already-merged provider PR (#11620/#11629); no provenance research recorded yet. Flagged unresolved pending review, per schema v1 (non-blocking)."}
{"recordType": "asset", "path": "public/providers/opper.svg", "mediaType": "image/svg+xml", "sha256": "e45d0409e7746946f204903ad6e7da267d805b7d7534fa684eeb7b8ac5717791", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/opper-ai/provider-omniroute", "ref": "9aacef7d6ae68d8d79f5aee042a25e9b646d2338", "path": "public/providers/opper.svg", "integrity": "sha256:e45d0409e7746946f204903ad6e7da267d805b7d7534fa684eeb7b8ac5717791", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "MIT", "assertedBy": "opper-ai/provider-omniroute LICENSE at the pinned commit", "evidence": "https://github.com/opper-ai/provider-omniroute/blob/9aacef7d6ae68d8d79f5aee042a25e9b646d2338/LICENSE", "independentlyVerified": true, "scope": "Pinned repository distribution only; no trademark clearance."}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned official-organization repository source. The same commit carries an MIT license. This proves source and repository-license provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/orcarouter.svg", "mediaType": "image/svg+xml", "sha256": "06b36d030492901cada4c1e757b613c3ada340727d74f601fe407cfad7b529cf", "provenanceStatus": "probable", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Repository PR #6926 describes this family as letter-in-circle placeholders, but original authorship and license were not independently proven."}
{"recordType": "asset", "path": "public/providers/ovhcloud.svg", "mediaType": "image/svg+xml", "sha256": "ab65efec83d5106fa649e1f3ec5db98beb20ec6708158362844c912c34e1d31a", "provenanceStatus": "proven", "source": {"kind": "git", "url": "https://github.com/GLINCKER/thesvg", "ref": "7870bc1c5f657d9accbb7f96cc457b8dd3363ee8", "path": "public/icons/ovhcloud/default.svg", "integrity": "sha256:ab65efec83d5106fa649e1f3ec5db98beb20ec6708158362844c912c34e1d31a", "match": "byte-exact"}, "upstreamLicenseClaim": {"value": "brand-use", "assertedBy": "theSVG pinned registry", "evidence": "https://github.com/GLINCKER/thesvg/blob/7870bc1c5f657d9accbb7f96cc457b8dd3363ee8/src/data/icons.json", "independentlyVerified": false, "scope": "Upstream SVG copyright claim only; no trademark clearance.", "upstreamUrl": "https://ovhcloud.com"}, "trademarkClearance": null, "evidenceNote": "Local bytes are byte-identical to the pinned theSVG source. This proves source provenance only, not copyright or trademark clearance."}
{"recordType": "asset", "path": "public/providers/perplexity.svg", "mediaType": "image/svg+xml", "sha256": "c7a4c847b6b3c0e8a10868d35b0b4a89727c03f8db3394060dcdb33c4b21c83b", "provenanceStatus": "probable", "source": null, "upstreamLicenseClaim": null, "trademarkClearance": null, "evidenceNote": "Repository PR #6317 and the asset structure indicate a likely source family, but no immutable upstream source or hash was proven."}

View File

@@ -79,6 +79,7 @@ Lookup material — API surface, environment variables, CLI flags, provider cata
- [API_REFERENCE.md](reference/API_REFERENCE.md) — REST API endpoints and shapes.
- [PROVIDER_REFERENCE.md](reference/PROVIDER_REFERENCE.md) — auto-generated provider catalog (do not edit by hand).
- [REMOVED_PROVIDERS.md](reference/REMOVED_PROVIDERS.md) — providers removed at their operator's request; never reintroduce without written permission.
- [PROVIDER_PLUGIN_MANIFEST.md](reference/PROVIDER_PLUGIN_MANIFEST.md) — sidecar-safe provider plugin contract for Bifrost and CLIProxyAPI migration.
- [openapi.yaml](openapi.yaml) — OpenAPI spec for the public API.
- [ENVIRONMENT.md](reference/ENVIRONMENT.md) — environment variables reference.

View File

@@ -0,0 +1,60 @@
# Providers removed at their operator's request
Some services were integrated into OmniRoute and later removed because the people who run
them asked for it. This page is the durable record of those removals. Its only purpose is to
keep them from coming back by accident: a contributor who finds an old fork, a cached npm
tarball, an archived issue or a "restore provider X" request needs one place that says **do
not reintroduce**.
This page is **not** a list of dead or discontinued services. Those are tracked in
[`FREE_TIERS.md`](FREE_TIERS.md) ("Removed / no free tier") and can come back if the service
does. The entries below can only come back with written permission from the operator named in
the request, and that permission must be linked from the entry.
## Policy
1. **A takedown request from a service operator is honored, not negotiated.** OmniRoute is
not affiliated with any upstream service. When the operator of a service asks for the
integration to go, it goes, whether the integration used an official API or not.
2. **"Removed" means every surface OmniRoute controls.** Executor, registry entry, provider
id and alias, model list, endpoints, environment variables, icon, dashboard cards, the
generated provider reference, `FREE_TIERS.md`, the environment reference, README counts,
`llm.txt` mirrors, dedicated tests and golden snapshots, code comments, CHANGELOG bullets
(with a ledgered reconciliation, see `config/release/changelog-reconciliations.json`),
GitHub Releases notes, the wiki, and the GitHub issues, discussions and pull requests whose
subject was that provider (issues and discussions deleted; pull requests retitled, their
description replaced and the thread locked, because GitHub cannot delete pull requests).
3. **Never reintroduce an entry on this page without written permission.** That includes
adding the id or alias back to any provider catalog, adding the domains to an executor,
accepting a contributor PR that "restores" it, adding it to the free-model catalog, or
documenting a manual way to reach it through OmniRoute. Close such PRs and issues with a
link to this page.
4. **Keep the entry minimal.** Record only what a reviewer needs to recognize a
reintroduction: identifiers, domains, dates and the pull request that did the removal.
Do not describe how the integration worked.
5. **The regression guard is `tests/unit/removed-providers-blocklist.test.ts`.** It fails when
any identifier or domain below shows up again in the provider catalogs, the executor map or
the provider registry sources. Add the new identifiers to that test in the same PR that
adds a row here.
## Register
| Removed on | Provider id | Alias | Domains | Requested by | Removal PR | Notes |
| ---------- | ----------- | ------ | --------------------------------------- | ------------------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| 2026-08-12 | `puter` | `pu` | `puter.com` | Puter's owner (Nariman Jelveh) | [#10210](https://github.com/diegosouzapw/OmniRoute/pull/10210) | API-key provider. Migration `152_remove_puter_provider.sql` cleans stored config. |
| 2026-09-02 | `theoldllm` | `tllm` | `theoldllm.com`, `theoldllm.vercel.app` | The service operator (support email) | [#12440](https://github.com/diegosouzapw/OmniRoute/pull/12440) | Keyless provider. Written request received 2026-08-30. Dedicated issues and discussion deleted, PRs retitled. |
## Adding an entry
When a new takedown request arrives:
1. Confirm the request comes from the operator of the service (their support address or a
domain they control), and keep the message privately.
2. Remove the integration following the checklist in policy item 2. Use
[#12440](https://github.com/diegosouzapw/OmniRoute/pull/12440) as the reference for a
keyless provider and [#10210](https://github.com/diegosouzapw/OmniRoute/pull/10210) for an
API-key provider with stored connections (add a migration).
3. Add one row to the table above and the identifiers to
`tests/unit/removed-providers-blocklist.test.ts`, in the same PR.
4. Reply to the operator once the PR is merged, listing what was removed and what OmniRoute
cannot change (already-published npm and Docker versions, git history, third-party forks).

View File

@@ -8,6 +8,7 @@
"FREE_TIERS",
"FREE_PROXIES_API",
"PROVIDER_REFERENCE",
"REMOVED_PROVIDERS",
"PROVIDER_PLUGIN_MANIFEST",
"RELAY_BACKEND_STRATEGY",
"RELAY_TROUBLESHOOTING"

View File

@@ -20,6 +20,14 @@ interface SystemPromptConfig {
prompt: string;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function isSystemMessage(value: unknown): value is Record<string, unknown> {
return isRecord(value) && (value.role === "system" || value.role === "developer");
}
// Typed accessor for globalThis storage — avoids `as any` casts (#2470)
const _store = globalThis as unknown as Record<string, SystemPromptConfig | undefined>;
@@ -74,45 +82,50 @@ export function getSystemPromptConfig() {
* suffixPrompt is appended after existing system content.
* This ensures: prefix → agent instructions → suffix (#2468).
*
* @param {object} body - Request body
* @returns {object} Modified body
* @param body - Request body
* @returns Modified body
*/
export function injectSystemPrompt(body) {
export function injectSystemPrompt<T>(body: T): T {
const cfg = getConfig();
if (!cfg.enabled) return body;
const prefix = cfg.prefixPrompt || "";
const suffix = cfg.suffixPrompt || "";
if (!prefix && !suffix) return body;
if (!body || typeof body !== "object") return body;
if (!isRecord(body)) return body;
if (body._skipSystemPrompt) return body;
const result = { ...body };
const result: Record<string, unknown> = { ...body };
// OpenAI/Claude format (messages[])
if (result.messages && Array.isArray(result.messages)) {
const sysIdx = result.messages.findIndex((m) => m.role === "system" || m.role === "developer");
result.messages = [...result.messages];
const messages: unknown[] = result.messages;
const sysIdx = messages.findIndex(isSystemMessage);
const nextMessages = [...messages];
if (sysIdx >= 0) {
const msg = { ...result.messages[sysIdx] };
if (Array.isArray(msg.content)) {
const content = [...msg.content];
if (prefix) content.unshift({ type: "text", text: prefix });
if (suffix) content.push({ type: "text", text: suffix });
msg.content = content;
} else {
let content = msg.content || "";
if (prefix) content = prefix + "\n\n" + content;
if (suffix) content = content + "\n\n" + suffix;
msg.content = content;
const existingMessage = nextMessages[sysIdx];
if (isRecord(existingMessage)) {
const msg = { ...existingMessage };
if (Array.isArray(msg.content)) {
const content: unknown[] = [...msg.content];
if (prefix) content.unshift({ type: "text", text: prefix });
if (suffix) content.push({ type: "text", text: suffix });
msg.content = content;
} else {
let content = String(msg.content || "");
if (prefix) content = prefix + "\n\n" + content;
if (suffix) content = content + "\n\n" + suffix;
msg.content = content;
}
nextMessages[sysIdx] = msg;
}
result.messages[sysIdx] = msg;
} else {
// No existing system message — combine both into one
const combined = [prefix, suffix].filter(Boolean).join("\n\n");
if (combined) {
result.messages = [{ role: "system", content: combined }, ...result.messages];
nextMessages.unshift({ role: "system", content: combined });
}
}
result.messages = nextMessages;
}
// Claude format (system field)
@@ -123,14 +136,14 @@ export function injectSystemPrompt(body) {
if (suffix) sys = sys + "\n\n" + suffix;
result.system = sys;
} else if (Array.isArray(result.system)) {
let arr = [...result.system];
let arr: unknown[] = [...result.system];
if (prefix) arr = [{ type: "text", text: prefix }, ...arr];
if (suffix) arr = [...arr, { type: "text", text: suffix }];
result.system = arr;
}
}
return result;
return Object.assign({}, body, result);
}
/**

View File

@@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Nimble">
<rect width="24" height="24" rx="5" fill="#6D28D9" />
<path
d="M7 17V7h2.1l5.8 6.6V7H17v10h-2.1L9.1 10.4V17H7z"
fill="#fff"
/>
</svg>

Before

Width:  |  Height:  |  Size: 240 B

View File

@@ -19,53 +19,15 @@ import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { diffAgainstBaseline, parseTscOutput } from "./typecheckBaseline.mjs";
export { diffAgainstBaseline, parseTscOutput } from "./typecheckBaseline.mjs";
const ROOT = process.cwd();
const TSCONFIG = path.join(ROOT, "tsconfig.typecheck-api.json");
const BASELINE_PATH = path.join(ROOT, "config/quality/api-typecheck-baseline.json");
const UPDATE = process.argv.includes("--update");
const TSC_ERROR_LINE = /^(.+?)\((\d+),(\d+)\): error (TS\d+):/;
export function parseTscOutput(raw) {
const counts = {};
for (const line of String(raw).split("\n")) {
const match = TSC_ERROR_LINE.exec(line);
if (!match) continue;
const [, file, , , code] = match;
if (!counts[file]) counts[file] = {};
counts[file][code] = (counts[file][code] || 0) + 1;
}
return counts;
}
export function diffAgainstBaseline(live, baseline) {
const regressions = [];
const improvements = [];
for (const [file, codes] of Object.entries(live)) {
for (const [code, liveCount] of Object.entries(codes)) {
const baselineCount = (baseline[file] && baseline[file][code]) || 0;
if (liveCount > baselineCount) {
regressions.push({ file, code, liveCount, baselineCount });
} else if (liveCount < baselineCount) {
improvements.push({ file, code, liveCount, baselineCount });
}
}
}
for (const [file, codes] of Object.entries(baseline)) {
for (const [code, baselineCount] of Object.entries(codes)) {
const liveCount = (live[file] && live[file][code]) || 0;
if (liveCount === 0 && baselineCount > 0) {
improvements.push({ file, code, liveCount: 0, baselineCount });
}
}
}
return { regressions, improvements };
}
function runTsc() {
try {
return execFileSync(
@@ -117,7 +79,9 @@ function main() {
`[api-typecheck] ${improvements.length} baselined error(s) no longer present ` +
`— run 'node scripts/check/check-api-typecheck.mjs --update' to ratchet the baseline down:\n` +
improvements
.map((i) => ` - ${i.file} ${i.code} (baseline ${i.baselineCount} -> live ${i.liveCount})`)
.map(
(i) => ` - ${i.file} ${i.code} (baseline ${i.baselineCount} -> live ${i.liveCount})`
)
.join("\n")
);
}

View File

@@ -22,74 +22,15 @@ import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { diffAgainstBaseline, parseTscOutput } from "./typecheckBaseline.mjs";
export { diffAgainstBaseline, parseTscOutput } from "./typecheckBaseline.mjs";
const ROOT = process.cwd();
const TSCONFIG = path.join(ROOT, "open-sse", "tsconfig.json");
const BASELINE_PATH = path.join(ROOT, "config/quality/open-sse-typecheck-baseline.json");
const UPDATE = process.argv.includes("--update");
// Matches tsc --pretty false output lines, e.g.:
// src/app/api/v1/chat/route.ts(12,7): error TS2304: Cannot find name 'bar'.
// open-sse/handlers/chatCore.ts(45,3): error TS7053: Element implicitly has an 'any'...
const TSC_ERROR_LINE = /^(.+?)\((\d+),(\d+)\): error (TS\d+):/;
/**
* Parses raw `tsc --pretty false` stdout into a nested count map:
* { "<relative file path>": { "<TS code>": <count> } }
*
* Pure/exported for unit testing against synthetic tsc output — no child
* process involved here.
*/
export function parseTscOutput(raw) {
const counts = {};
const lines = String(raw).split("\n");
for (const line of lines) {
const match = TSC_ERROR_LINE.exec(line);
if (!match) continue;
const [, file, , , code] = match;
if (!counts[file]) counts[file] = {};
counts[file][code] = (counts[file][code] || 0) + 1;
}
return counts;
}
/**
* Compares live (file, TS code) error counts against a frozen baseline.
* Returns `{ regressions, improvements }`:
* - regressions: entries where live count > baselined count (or the pair is
* entirely new/unbaselined) — these fail the gate.
* - improvements: entries where live count < baselined count — informational,
* do not fail (use --update to ratchet the baseline down).
*
* Exported for unit testing.
*/
export function diffAgainstBaseline(live, baseline) {
const regressions = [];
const improvements = [];
for (const [file, codes] of Object.entries(live)) {
for (const [code, liveCount] of Object.entries(codes)) {
const baselineCount = (baseline[file] && baseline[file][code]) || 0;
if (liveCount > baselineCount) {
regressions.push({ file, code, liveCount, baselineCount });
} else if (liveCount < baselineCount) {
improvements.push({ file, code, liveCount, baselineCount });
}
}
}
for (const [file, codes] of Object.entries(baseline)) {
for (const [code, baselineCount] of Object.entries(codes)) {
const liveCount = (live[file] && live[file][code]) || 0;
if (liveCount === 0 && baselineCount > 0) {
improvements.push({ file, code, liveCount: 0, baselineCount });
}
}
}
return { regressions, improvements };
}
function runTsc() {
try {
const stdout = execFileSync(
@@ -143,7 +84,9 @@ function main() {
`[open-sse-typecheck] ${improvements.length} baselined error(s) no longer present ` +
`— run 'node scripts/check/check-open-sse-typecheck.mjs --update' to ratchet the baseline down:\n` +
improvements
.map((i) => ` - ${i.file} ${i.code} (baseline ${i.baselineCount} -> live ${i.liveCount})`)
.map(
(i) => ` - ${i.file} ${i.code} (baseline ${i.baselineCount} -> live ${i.liveCount})`
)
.join("\n")
);
}

View File

@@ -0,0 +1,91 @@
// Shared parsing and frozen-baseline comparison for the scoped TypeScript gates.
const TSC_ERROR_LINE = /^(.+?)\((\d+),(\d+)\): error (TS\d+):/;
const TS_CODE = /^TS\d+$/;
const UNSAFE_PROPERTY_KEYS = new Set(["__proto__", "constructor", "prototype"]);
function isPlainObject(value) {
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || prototype === null;
}
function normalizeDiagnosticCounts(value, label) {
if (!isPlainObject(value)) {
throw new TypeError(`${label} must be a plain object`);
}
const normalized = Object.create(null);
for (const [file, codes] of Object.entries(value)) {
if (UNSAFE_PROPERTY_KEYS.has(file)) {
throw new TypeError(`${label} contains unsupported property key "${file}"`);
}
if (file.startsWith("_")) continue;
if (!isPlainObject(codes)) {
throw new TypeError(`${label} entry "${file}" must be a plain object`);
}
const normalizedCodes = Object.create(null);
for (const [code, count] of Object.entries(codes)) {
if (!TS_CODE.test(code)) {
throw new TypeError(`${label} entry "${file}" has invalid TypeScript code "${code}"`);
}
if (!Number.isFinite(count) || !Number.isInteger(count) || count < 0) {
throw new TypeError(
`${label} entry "${file}" code "${code}" must be a finite nonnegative integer`
);
}
normalizedCodes[code] = count;
}
normalized[file] = normalizedCodes;
}
return normalized;
}
/** Parse `tsc --pretty false` output into per-file/per-code diagnostic counts. */
export function parseTscOutput(raw) {
const counts = {};
for (const line of String(raw).split("\n")) {
const match = TSC_ERROR_LINE.exec(line);
if (!match) continue;
const [, file, , , code] = match;
if (!counts[file]) counts[file] = {};
counts[file][code] = (counts[file][code] || 0) + 1;
}
return counts;
}
/**
* Compare live diagnostic counts with a frozen baseline.
*
* Underscore-prefixed top-level keys are reserved for baseline metadata and
* never participate in the diagnostic comparison.
*/
export function diffAgainstBaseline(live, baseline) {
const liveCounts = normalizeDiagnosticCounts(live, "live diagnostics");
const baselineCounts = normalizeDiagnosticCounts(baseline, "typecheck baseline");
const regressions = [];
const improvements = [];
for (const [file, codes] of Object.entries(liveCounts)) {
for (const [code, liveCount] of Object.entries(codes)) {
const baselineCount = baselineCounts[file]?.[code] ?? 0;
if (liveCount > baselineCount) {
regressions.push({ file, code, liveCount, baselineCount });
} else if (liveCount < baselineCount) {
improvements.push({ file, code, liveCount, baselineCount });
}
}
}
for (const [file, codes] of Object.entries(baselineCounts)) {
for (const [code, baselineCount] of Object.entries(codes)) {
const liveCodes = liveCounts[file];
if (!Object.hasOwn(liveCodes ?? {}, code) && baselineCount > 0) {
improvements.push({ file, code, liveCount: 0, baselineCount });
}
}
}
return { regressions, improvements };
}

View File

@@ -141,7 +141,6 @@ const KNOWN_SVGS = new Set([
"moonshot",
"morph",
"nebius",
"nimble-search",
"nlpcloud",
"nomic",
"novita",
@@ -152,6 +151,7 @@ const KNOWN_SVGS = new Set([
"openai",
"openclaw",
"openrouter",
"opper",
"orcarouter",
"ovhcloud",
"perplexity",
@@ -240,6 +240,7 @@ const GENERIC_PROVIDER_IDS = new Set([
"leonardo",
"modal",
"modelscope",
"nimble-search",
"nlpcloud",
"oauth",
"oci",

View File

@@ -7,6 +7,7 @@ import {
parseTscOutput,
diffAgainstBaseline,
} from "../../../scripts/check/check-api-typecheck.mjs";
import { diffAgainstBaseline as diffOpenSseAgainstBaseline } from "../../../scripts/check/check-open-sse-typecheck.mjs";
test("parseTscOutput: parses an API-route TS2554 regression", () => {
const raw =
@@ -85,3 +86,130 @@ test("diffAgainstBaseline: reports a disappeared diagnostic as an improvement",
assert.equal(improvements[0].liveCount, 0);
assert.equal(improvements[0].baselineCount, 2);
});
test("diffAgainstBaseline: ignores underscore-prefixed baseline metadata", () => {
const baseline = {
_relax_velocity_2026_08_30:
"per-file TS diagnostic counts raised by 20% (289 -> 455); velocity phase",
"src/app/api/foo/route.ts": { TS2339: 1 },
};
const live = { "src/app/api/foo/route.ts": { TS2339: 1 } };
for (const compare of [diffAgainstBaseline, diffOpenSseAgainstBaseline]) {
assert.deepEqual(compare(live, baseline), {
regressions: [],
improvements: [],
});
}
});
test("diffAgainstBaseline: rejects a string in place of a real file diagnostic map", () => {
const malformedBaseline = {
"src/app/api/foo/route.ts": "TS2339: 1",
};
assert.throws(
() => diffAgainstBaseline({}, malformedBaseline),
/src\/app\/api\/foo\/route\.ts.*plain object/
);
assert.throws(
() => diffOpenSseAgainstBaseline({}, malformedBaseline),
/src\/app\/api\/foo\/route\.ts.*plain object/
);
});
test("diffAgainstBaseline: rejects non-plain roots and file maps", () => {
const inheritedRoot = Object.create({
"src/app/api/inherited/route.ts": { TS2339: 1 },
});
const inheritedFileMap = Object.create({ TS2339: 1 });
for (const malformedBaseline of [[], "not an object", null, inheritedRoot]) {
assert.throws(
() => diffAgainstBaseline({}, malformedBaseline),
/typecheck baseline must be a plain object/
);
}
for (const malformedFileMap of [[], null, inheritedFileMap]) {
assert.throws(
() =>
diffAgainstBaseline(
{},
{
"src/app/api/foo/route.ts": malformedFileMap,
}
),
/src\/app\/api\/foo\/route\.ts.*plain object/
);
}
});
test("diffAgainstBaseline: rejects prototype property keys", () => {
const malformedBaseline = JSON.parse('{"__proto__":{"TS2339":1}}');
assert.throws(
() => diffAgainstBaseline({}, malformedBaseline),
/unsupported property key "__proto__"/
);
});
test("diffAgainstBaseline: rejects non-TypeScript diagnostic keys", () => {
for (const code of ["2339", "TSX2339", "TS23x", "constructor"]) {
assert.throws(
() =>
diffAgainstBaseline(
{},
{
"src/app/api/foo/route.ts": { [code]: 1 },
}
),
/invalid TypeScript code/
);
}
});
test("diffAgainstBaseline: rejects invalid diagnostic counts", () => {
for (const count of [Number.NaN, Number.POSITIVE_INFINITY, -1, 1.5, "1"]) {
assert.throws(
() =>
diffAgainstBaseline(
{},
{
"src/app/api/foo/route.ts": { TS2339: count },
}
),
/finite nonnegative integer/
);
}
});
test("diffAgainstBaseline: validates live diagnostics with the same schema", () => {
assert.throws(
() =>
diffAgainstBaseline(
{ "src/app/api/foo/route.ts": { TS2339: -1 } },
{ "src/app/api/foo/route.ts": { TS2339: 1 } }
),
/live diagnostics.*finite nonnegative integer/
);
});
test("diffAgainstBaseline: accepts zero counts without fabricating a second improvement", () => {
assert.deepEqual(
diffAgainstBaseline(
{ "src/app/api/foo/route.ts": { TS2339: 0 } },
{ "src/app/api/foo/route.ts": { TS2339: 1 } }
),
{
regressions: [],
improvements: [
{
file: "src/app/api/foo/route.ts",
code: "TS2339",
liveCount: 0,
baselineCount: 1,
},
],
}
);
});

View File

@@ -541,7 +541,7 @@ test("provider asset provenance gate binds auditedCommit to the physical provide
}
});
test("repository provider asset manifest covers the audited 142-file snapshot", (t) => {
test("repository provider asset manifest covers the audited 141-file snapshot", (t) => {
const manifestPath = join(REPO_ROOT, "config/quality/provider-assets-provenance.jsonl");
const { auditedCommit } = JSON.parse(readFileSync(manifestPath, "utf8").split("\n")[0]);
if (!gitHasCommit(auditedCommit) && isShallowRepository()) {
@@ -556,7 +556,7 @@ test("repository provider asset manifest covers the audited 142-file snapshot",
assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
assert.match(
result.stdout,
/142\/142 registered; proven=71 probable=69 unresolved=2; duplicate-groups=1/
/141\/141 registered; proven=72 probable=69 unresolved=0; duplicate-groups=1/
);
});

View File

@@ -609,7 +609,9 @@ test("Non-streaming: routes native Grok webSearch to URL fetch tool when user as
const result = await executor.execute({
model: "grok-4.1-fast",
body: {
messages: [{ role: "user", content: "Haz webfetch de http://endless.horse/ y dime que hay" }],
messages: [
{ role: "user", content: "Haz webfetch de http://endless.horse/ y dime que hay" },
],
stream: false,
tools: [
{
@@ -645,7 +647,10 @@ test("Non-streaming: routes native Grok webSearch to URL fetch tool when user as
});
const json = (await result.response.json()) as any;
assert.equal(json.choices[0].message.tool_calls[0].function.name, "webfetch");
assert.equal(json.choices[0].message.tool_calls[0].function.arguments, JSON.stringify({ url: "http://endless.horse/" }));
assert.equal(
json.choices[0].message.tool_calls[0].function.arguments,
JSON.stringify({ url: "http://endless.horse/" })
);
} finally {
restore();
}
@@ -678,7 +683,11 @@ test("Non-streaming: keeps native Grok webSearch on search tool when user asks s
function: {
name: "public_search_tool",
description: "Search the web for any topic",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -686,7 +695,11 @@ test("Non-streaming: keeps native Grok webSearch on search tool when user asks s
function: {
name: "webfetch",
description: "Fetch a URL and extract page content",
parameters: { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
parameters: {
type: "object",
properties: { url: { type: "string" } },
required: ["url"],
},
},
},
],
@@ -729,7 +742,11 @@ test("Non-streaming: native Grok webSearch does not choose context memory search
function: {
name: "memory_context_tool",
description: "Search across project memories and conversation history",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -737,7 +754,11 @@ test("Non-streaming: native Grok webSearch does not choose context memory search
function: {
name: "public_search_tool",
description: "Search the web for current public information",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -778,7 +799,12 @@ test("Non-streaming: maps native Grok browsePage to URL fetch tool", async () =>
const result = await executor.execute({
model: "grok-4.1-fast",
body: {
messages: [{ role: "user", content: "Busca la release oficial de Ubuntu y abre la pagina del anuncio" }],
messages: [
{
role: "user",
content: "Busca la release oficial de Ubuntu y abre la pagina del anuncio",
},
],
stream: false,
tools: [
{
@@ -786,7 +812,11 @@ test("Non-streaming: maps native Grok browsePage to URL fetch tool", async () =>
function: {
name: "public_search_tool",
description: "Search the web for any topic",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -794,7 +824,11 @@ test("Non-streaming: maps native Grok browsePage to URL fetch tool", async () =>
function: {
name: "webfetch",
description: "Fetch a URL with better extraction for static/docs pages",
parameters: { type: "object", properties: { url: { type: "string" }, prompt: { type: "string" } }, required: ["url"] },
parameters: {
type: "object",
properties: { url: { type: "string" }, prompt: { type: "string" } },
required: ["url"],
},
},
},
],
@@ -849,7 +883,15 @@ test("Non-streaming: does not repeat a tool call that already has a tool result"
{ role: "tool", tool_call_id: "call_1", name: "bash", content: "413 /tmp/a" },
],
stream: false,
tools: [{ type: "function", function: { name: "bash", parameters: { type: "object", properties: { command: { type: "string" } } } } }],
tools: [
{
type: "function",
function: {
name: "bash",
parameters: { type: "object", properties: { command: { type: "string" } } },
},
},
],
},
stream: false,
credentials: { apiKey: "test-sso-token" },
@@ -894,7 +936,10 @@ test("Non-streaming: does not repeat equivalent terminal command with different
type: "function",
function: {
name: "bash",
arguments: JSON.stringify({ command: 'wc -l "/tmp/a"', description: "previous run" }),
arguments: JSON.stringify({
command: 'wc -l "/tmp/a"',
description: "previous run",
}),
},
},
],
@@ -953,15 +998,31 @@ test("Non-streaming: allows a different tool after a completed call", async () =
role: "assistant",
content: null,
tool_calls: [
{ id: "call_1", type: "function", function: { name: "bash", arguments: JSON.stringify({ command: "wc -l /tmp/a" }) } },
{
id: "call_1",
type: "function",
function: { name: "bash", arguments: JSON.stringify({ command: "wc -l /tmp/a" }) },
},
],
},
{ role: "tool", tool_call_id: "call_1", name: "bash", content: "413 /tmp/a" },
],
stream: false,
tools: [
{ type: "function", function: { name: "bash", parameters: { type: "object", properties: { command: { type: "string" } } } } },
{ type: "function", function: { name: "read", parameters: { type: "object", properties: { filePath: { type: "string" } } } } },
{
type: "function",
function: {
name: "bash",
parameters: { type: "object", properties: { command: { type: "string" } } },
},
},
{
type: "function",
function: {
name: "read",
parameters: { type: "object", properties: { filePath: { type: "string" } } },
},
},
],
},
stream: false,
@@ -1011,11 +1072,19 @@ test("Non-streaming: raw_function_result is not emitted as final content", async
{
id: "call_1",
type: "function",
function: { name: "bash", arguments: JSON.stringify({ command: "wc -l /tmp/project/config.json" }) },
function: {
name: "bash",
arguments: JSON.stringify({ command: "wc -l /tmp/project/config.json" }),
},
},
],
},
{ role: "tool", tool_call_id: "call_1", name: "bash", content: "413 /tmp/project/config.json" },
{
role: "tool",
tool_call_id: "call_1",
name: "bash",
content: "413 /tmp/project/config.json",
},
],
stream: false,
},
@@ -1099,7 +1168,9 @@ test("Request: forwards tool results into Grok prompt for the next turn", async
status: 200,
headers: new Headers({ "Content-Type": "application/json" }),
text: null,
body: mockGrokStream([{ result: { response: { modelResponse: { message: "It is sunny." } } } }]),
body: mockGrokStream([
{ result: { response: { modelResponse: { message: "It is sunny." } } } },
]),
};
});
try {
@@ -1113,7 +1184,11 @@ test("Request: forwards tool results into Grok prompt for the next turn", async
role: "assistant",
content: null,
tool_calls: [
{ id: "call_weather", type: "function", function: { name: "get_weather", arguments: "{}" } },
{
id: "call_weather",
type: "function",
function: { name: "get_weather", arguments: "{}" },
},
],
},
{ role: "tool", tool_call_id: "call_weather", name: "get_weather", content: "sunny" },
@@ -1127,7 +1202,11 @@ test("Request: forwards tool results into Grok prompt for the next turn", async
});
const payload = JSON.parse(capturedBody);
assert.ok(payload.message.includes("Previous assistant tool calls"));
assert.ok(payload.message.includes("CLIENT TOOL RESULT from caller runtime for get_weather (call_weather)"));
assert.ok(
payload.message.includes(
"CLIENT TOOL RESULT from caller runtime for get_weather (call_weather)"
)
);
assert.ok(payload.message.includes("do not call the same tool again"));
assert.ok(payload.message.includes("sunny"));
} finally {
@@ -1209,7 +1288,9 @@ test("Request: leaves native Grok search enabled when client tools are absent",
});
test("Request: places tool manifest next to latest user after noisy history", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1218,7 +1299,10 @@ test("Request: places tool manifest next to latest user after noisy history", as
messages: [
{ role: "user", content: "old question" },
{ role: "assistant", content: "old answer claiming file does not exist" },
{ role: "user", content: "/tmp/project/config.json dime cuantas lineas tiene este archivo" },
{
role: "user",
content: "/tmp/project/config.json dime cuantas lineas tiene este archivo",
},
],
stream: false,
tools: [
@@ -1227,7 +1311,11 @@ test("Request: places tool manifest next to latest user after noisy history", as
function: {
name: "bash",
description: "Run a shell command",
parameters: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
parameters: {
type: "object",
properties: { command: { type: "string" } },
required: ["command"],
},
},
},
],
@@ -1250,7 +1338,9 @@ test("Request: places tool manifest next to latest user after noisy history", as
});
test("Request: strips injected internal reminders from Grok prompt", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1270,7 +1360,11 @@ test("Request: strips injected internal reminders from Grok prompt", async () =>
function: {
name: "fetch_url_tool",
description: "Fetch URL or browse web page content",
parameters: { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
parameters: {
type: "object",
properties: { url: { type: "string" } },
required: ["url"],
},
},
},
],
@@ -1290,7 +1384,9 @@ test("Request: strips injected internal reminders from Grok prompt", async () =>
});
test("Request: old completed tools do not suppress fresh latest-user tool calls", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1320,7 +1416,11 @@ test("Request: old completed tools do not suppress fresh latest-user tool calls"
function: {
name: "bash",
description: "Run a shell command",
parameters: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
parameters: {
type: "object",
properties: { command: { type: "string" } },
required: ["command"],
},
},
},
],
@@ -1339,7 +1439,9 @@ test("Request: old completed tools do not suppress fresh latest-user tool calls"
});
test("Request: appends tool manifest after tool results during multi-step continuation", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1351,7 +1453,11 @@ test("Request: appends tool manifest after tool results during multi-step contin
role: "assistant",
content: "",
tool_calls: [
{ id: "read_call", type: "function", function: { name: "read", arguments: JSON.stringify({ filePath: "/tmp/a" }) } },
{
id: "read_call",
type: "function",
function: { name: "read", arguments: JSON.stringify({ filePath: "/tmp/a" }) },
},
],
},
{ role: "tool", tool_call_id: "read_call", name: "read", content: "file content" },
@@ -1363,7 +1469,11 @@ test("Request: appends tool manifest after tool results during multi-step contin
function: {
name: "memory_context_tool",
description: "Search across project memories and raw conversation history.",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1371,7 +1481,11 @@ test("Request: appends tool manifest after tool results during multi-step contin
function: {
name: "public_search_tool",
description: "Search the web for any topic and get clean content.",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -1393,7 +1507,9 @@ test("Request: appends tool manifest after tool results during multi-step contin
});
test("Request: keeps generic manifest ordered for file understanding tasks", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1412,7 +1528,11 @@ test("Request: keeps generic manifest ordered for file understanding tasks", asy
function: {
name: "bash",
description: "Execute shell command",
parameters: { type: "object", properties: { command: { type: "string" }, description: { type: "string" } }, required: ["command"] },
parameters: {
type: "object",
properties: { command: { type: "string" }, description: { type: "string" } },
required: ["command"],
},
},
},
{
@@ -1420,7 +1540,11 @@ test("Request: keeps generic manifest ordered for file understanding tasks", asy
function: {
name: "read",
description: "Read a file or directory from the local filesystem",
parameters: { type: "object", properties: { filePath: { type: "string" } }, required: ["filePath"] },
parameters: {
type: "object",
properties: { filePath: { type: "string" } },
required: ["filePath"],
},
},
},
],
@@ -1448,21 +1572,33 @@ test("Request: keeps generic manifest ordered for file understanding tasks", asy
});
test("Request: keeps generic manifest ordered for official web facts", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
model: "grok-4.1-fast",
body: {
messages: [{ role: "user", content: "contrasta con una fuente web oficial la ultima release de Ubuntu 24.04" }],
messages: [
{
role: "user",
content: "contrasta con una fuente web oficial la ultima release de Ubuntu 24.04",
},
],
stream: false,
tools: [
{
type: "function",
function: {
name: "memory_context_tool",
description: "Search across project memories, indexed git commits, and raw conversation history.",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
description:
"Search across project memories, indexed git commits, and raw conversation history.",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1470,7 +1606,11 @@ test("Request: keeps generic manifest ordered for official web facts", async ()
function: {
name: "public_search_tool",
description: "Search the web for any topic and get clean, ready-to-use content.",
parameters: { type: "object", properties: { query: { type: "string" }, numResults: { type: "number" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" }, numResults: { type: "number" } },
required: ["query"],
},
},
},
],
@@ -1498,7 +1638,9 @@ test("Request: keeps generic manifest ordered for official web facts", async ()
});
test("Request: base manifest order puts public web search before context memory", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1512,7 +1654,11 @@ test("Request: base manifest order puts public web search before context memory"
function: {
name: "memory_context_tool",
description: "Search across project memories and conversation history",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1520,7 +1666,11 @@ test("Request: base manifest order puts public web search before context memory"
function: {
name: "public_search_tool",
description: "Search the web for current public information",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -1531,14 +1681,18 @@ test("Request: base manifest order puts public web search before context memory"
log: null,
});
const prompt = String(capture.body.message);
assert.ok(prompt.indexOf("name: public_search_tool") < prompt.indexOf("name: memory_context_tool"));
assert.ok(
prompt.indexOf("name: public_search_tool") < prompt.indexOf("name: memory_context_tool")
);
} finally {
capture.restore();
}
});
test("Request: ranks public web search before infrastructure search", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1551,8 +1705,13 @@ test("Request: ranks public web search before infrastructure search", async () =
type: "function",
function: {
name: "tool_discovery_search",
description: "Search and discover available upstream tools using BM25 full-text search",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
description:
"Search and discover available upstream tools using BM25 full-text search",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1560,7 +1719,11 @@ test("Request: ranks public web search before infrastructure search", async () =
function: {
name: "public_search_tool",
description: "Search the web for current public information",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -1571,14 +1734,18 @@ test("Request: ranks public web search before infrastructure search", async () =
log: null,
});
const prompt = String(capture.body.message);
assert.ok(prompt.indexOf("name: public_search_tool") < prompt.indexOf("name: tool_discovery_search"));
assert.ok(
prompt.indexOf("name: public_search_tool") < prompt.indexOf("name: tool_discovery_search")
);
} finally {
capture.restore();
}
});
test("Request: ranks URL fetch before generic MCP read", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1591,8 +1758,13 @@ test("Request: ranks URL fetch before generic MCP read", async () => {
type: "function",
function: {
name: "mcp_read_tool",
description: "Execute a read-only upstream tool such as fetch, get, query, list, or search",
parameters: { type: "object", properties: { name: { type: "string" }, args: { type: "object" } }, required: ["name"] },
description:
"Execute a read-only upstream tool such as fetch, get, query, list, or search",
parameters: {
type: "object",
properties: { name: { type: "string" }, args: { type: "object" } },
required: ["name"],
},
},
},
{
@@ -1600,7 +1772,11 @@ test("Request: ranks URL fetch before generic MCP read", async () => {
function: {
name: "fetch_url_tool",
description: "Fetch URL or browse web page content",
parameters: { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
parameters: {
type: "object",
properties: { url: { type: "string" } },
required: ["url"],
},
},
},
],
@@ -1618,7 +1794,9 @@ test("Request: ranks URL fetch before generic MCP read", async () => {
});
test("Request: ranks shell command before infrastructure command config", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1632,7 +1810,11 @@ test("Request: ranks shell command before infrastructure command config", async
function: {
name: "upstream_server_config",
description: "Manage upstream MCP servers, including stdio command configuration",
parameters: { type: "object", properties: { command: { type: "string" }, name: { type: "string" } }, required: ["name"] },
parameters: {
type: "object",
properties: { command: { type: "string" }, name: { type: "string" } },
required: ["name"],
},
},
},
{
@@ -1640,7 +1822,11 @@ test("Request: ranks shell command before infrastructure command config", async
function: {
name: "shell_command_tool",
description: "Execute a shell command and return output",
parameters: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
parameters: {
type: "object",
properties: { command: { type: "string" } },
required: ["command"],
},
},
},
],
@@ -1651,20 +1837,26 @@ test("Request: ranks shell command before infrastructure command config", async
log: null,
});
const prompt = String(capture.body.message);
assert.ok(prompt.indexOf("name: shell_command_tool") < prompt.indexOf("name: upstream_server_config"));
assert.ok(
prompt.indexOf("name: shell_command_tool") < prompt.indexOf("name: upstream_server_config")
);
} finally {
capture.restore();
}
});
test("Request: commit wording does not prioritize memory over shell", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
model: "grok-4.1-fast",
body: {
messages: [{ role: "user", content: "ejecuta git rev-parse HEAD para ver el commit actual" }],
messages: [
{ role: "user", content: "ejecuta git rev-parse HEAD para ver el commit actual" },
],
stream: false,
tools: [
{
@@ -1672,7 +1864,11 @@ test("Request: commit wording does not prioritize memory over shell", async () =
function: {
name: "memory_context_tool",
description: "Search project memories and conversation history",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1680,7 +1876,11 @@ test("Request: commit wording does not prioritize memory over shell", async () =
function: {
name: "shell_command_tool",
description: "Execute a shell command and return output",
parameters: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
parameters: {
type: "object",
properties: { command: { type: "string" } },
required: ["command"],
},
},
},
],
@@ -1691,14 +1891,18 @@ test("Request: commit wording does not prioritize memory over shell", async () =
log: null,
});
const prompt = String(capture.body.message);
assert.ok(prompt.indexOf("name: shell_command_tool") < prompt.indexOf("name: memory_context_tool"));
assert.ok(
prompt.indexOf("name: shell_command_tool") < prompt.indexOf("name: memory_context_tool")
);
} finally {
capture.restore();
}
});
test("Request: explicit memory request prioritizes context over public web", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1712,7 +1916,11 @@ test("Request: explicit memory request prioritizes context over public web", asy
function: {
name: "public_search_tool",
description: "Search the web for current public information",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
{
@@ -1720,7 +1928,11 @@ test("Request: explicit memory request prioritizes context over public web", asy
function: {
name: "memory_context_tool",
description: "Search project memories and conversation history",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -1731,14 +1943,18 @@ test("Request: explicit memory request prioritizes context over public web", asy
log: null,
});
const prompt = String(capture.body.message);
assert.ok(prompt.indexOf("name: memory_context_tool") < prompt.indexOf("name: public_search_tool"));
assert.ok(
prompt.indexOf("name: memory_context_tool") < prompt.indexOf("name: public_search_tool")
);
} finally {
capture.restore();
}
});
test("Request: explicit tool_choice exposes only the forced tool", async () => {
const capture = mockFetchCapture([{ result: { response: { modelResponse: { message: "{}" } } } }]);
const capture = mockFetchCapture([
{ result: { response: { modelResponse: { message: "{}" } } } },
]);
try {
const executor = new GrokWebExecutor();
await executor.execute({
@@ -1753,7 +1969,11 @@ test("Request: explicit tool_choice exposes only the forced tool", async () => {
function: {
name: "other_tool",
description: "Other available tool",
parameters: { type: "object", properties: { input: { type: "string" } }, required: ["input"] },
parameters: {
type: "object",
properties: { input: { type: "string" } },
required: ["input"],
},
},
},
{
@@ -1761,7 +1981,11 @@ test("Request: explicit tool_choice exposes only the forced tool", async () => {
function: {
name: "forced_tool",
description: "Forced tool",
parameters: { type: "object", properties: { input: { type: "string" } }, required: ["input"] },
parameters: {
type: "object",
properties: { input: { type: "string" } },
required: ["input"],
},
},
},
],
@@ -1843,7 +2067,11 @@ test("Non-streaming: routes URL-like webfetch requests conservatively", async ()
function: {
name: "fetch_url_tool",
description: "Fetch URL or browse web page content",
parameters: { type: "object", properties: { url: { type: "string" } }, required: ["url"] },
parameters: {
type: "object",
properties: { url: { type: "string" } },
required: ["url"],
},
},
},
{
@@ -1851,7 +2079,11 @@ test("Non-streaming: routes URL-like webfetch requests conservatively", async ()
function: {
name: "public_search_tool",
description: "Search the web for current public information",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],
@@ -1862,8 +2094,16 @@ test("Non-streaming: routes URL-like webfetch requests conservatively", async ()
log: null,
});
const json = (await result.response.json()) as any;
assert.equal(json.choices[0].message.tool_calls[0].function.name, item.expectedName, item.title);
assert.equal(json.choices[0].message.tool_calls[0].function.arguments, JSON.stringify(item.expectedArgs), item.title);
assert.equal(
json.choices[0].message.tool_calls[0].function.name,
item.expectedName,
item.title
);
assert.equal(
json.choices[0].message.tool_calls[0].function.arguments,
JSON.stringify(item.expectedArgs),
item.title
);
} finally {
restore();
}
@@ -1963,7 +2203,11 @@ test("Streaming: handles Grok card closing tags split across chunks", async () =
test("Streaming: strips self-closing Grok render cards without swallowing later text", async () => {
const restore = mockFetch(200, [
{ result: { response: { token: "Alpha " } } },
{ result: { response: { token: '<grok:render card_id="c1" card_type="citation_card" /> omega' } } },
{
result: {
response: { token: '<grok:render card_id="c1" card_type="citation_card" /> omega' },
},
},
{ result: { response: { modelResponse: { message: "Alpha omega" } } } },
]);
try {
@@ -2040,10 +2284,39 @@ test("Streaming: maps structured Grok thinking to reasoning_content", async () =
test("Streaming: routes Grok thinking tokens separately from content", async () => {
const restore = mockFetch(200, [
{ result: { response: { token: "Thinking about your request", isThinking: true, messageTag: "header", messageStepId: 0 } } },
{ result: { response: { token: "Buscando fecha de lanzamiento", isThinking: true, messageTag: "header" } } },
{ result: { response: { token: "- Tool calls succeeded, confirming Ubuntu 24.04.4.\n", isThinking: true, messageTag: "summary" } } },
{ result: { response: { token: "Tool call ejecutado.\nweb_search ejecutado correctamente.\n" } } },
{
result: {
response: {
token: "Thinking about your request",
isThinking: true,
messageTag: "header",
messageStepId: 0,
},
},
},
{
result: {
response: {
token: "Buscando fecha de lanzamiento",
isThinking: true,
messageTag: "header",
},
},
},
{
result: {
response: {
token: "- Tool calls succeeded, confirming Ubuntu 24.04.4.\n",
isThinking: true,
messageTag: "summary",
},
},
},
{
result: {
response: { token: "Tool call ejecutado.\nweb_search ejecutado correctamente.\n" },
},
},
{ result: { response: { token: "Resultados clave:\n- Ubuntu 24.04.4 LTS liberado.\n" } } },
{
result: {
@@ -2322,7 +2595,11 @@ test("Request: preserves selected mode and native search state when client tools
function: {
name: "public_search_tool",
description: "Search the public web",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
},
],

View File

@@ -35,6 +35,7 @@ const LOCAL_SVG_IDS_WITHOUT_PROVENANCE = [
"leonardo",
"modal",
"modelscope",
"nimble-search",
"nlpcloud",
"oauth",
"oci",
@@ -177,9 +178,9 @@ const AUDITED_REFERENCE_FILES = [
...referenceRoots.flatMap((directory) => collectTextFiles(join(root, directory))),
];
test("provider bundle retires exactly the 78 unresolved assets and keeps the generic icon", () => {
assert.equal(retiredAssetNames.length, 78);
assert.equal(new Set(retiredAssetNames).size, 78);
test("provider bundle retires exactly the 79 unresolved assets and keeps the generic icon", () => {
assert.equal(retiredAssetNames.length, 79);
assert.equal(new Set(retiredAssetNames).size, 79);
for (const assetName of retiredAssetNames) {
assert.equal(
@@ -196,8 +197,9 @@ test("provider bundle retires exactly the 78 unresolved assets and keeps the gen
// provenance PRs (#11735, #11736, #11711) landed first and independently retired
// 6 further unproven files this PR never targeted (freebuff-dark.svg,
// freebuff-light.svg, freebuff.png, openvecta.svg, picoclaw.jpg, zoocode.png),
// so the real remaining count is 142, not 148.
assert.equal(distributedAssets.length, 142, "all 142 non-target assets must remain");
// so the real pre-fix count was 142, not 148. This fix retires the unresolved
// Nimble asset as well, leaving 141 distributed assets.
assert.equal(distributedAssets.length, 141, "all 141 non-target assets must remain");
assert.ok(distributedAssets.includes("cli-generic.svg"));
});

View File

@@ -0,0 +1,107 @@
/**
* Regression guard for docs/reference/REMOVED_PROVIDERS.md.
*
* Providers removed at their operator's request must never come back: not in the
* provider catalogs, not in the executor map, not in the registry sources and not
* as an upstream domain in any executor. Keep this list in sync with the table in
* the doc; add the identifiers of a new takedown here in the same PR.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { getProviderById, getProviderByAlias } =
await import("../../src/shared/constants/providers.ts");
const { hasSpecializedExecutor } = await import("../../open-sse/executors/index.ts");
const { FREE_MODEL_BUDGETS } = await import("../../open-sse/config/freeModelCatalog.data.ts");
interface RemovedProvider {
id: string;
alias: string;
domains: string[];
removalPr: number;
}
export const REMOVED_PROVIDERS: readonly RemovedProvider[] = [
{ id: "puter", alias: "pu", domains: ["puter.com"], removalPr: 10210 },
{
id: "theoldllm",
alias: "tllm",
domains: ["theoldllm.com", "theoldllm.vercel.app"],
removalPr: 12440,
},
];
// Source trees where a reintroduction would land. Scanned for ids, aliases and domains.
const SCANNED_DIRS = [
"open-sse/config/providers",
"open-sse/executors",
"src/shared/constants/providers",
];
function walk(dir: string, out: string[] = []): string[] {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walk(full, out);
else if (/\.(ts|tsx|mts|js|mjs|json)$/.test(entry.name)) out.push(full);
}
return out;
}
const ROOT = process.cwd();
const scannedFiles = SCANNED_DIRS.flatMap((dir) => walk(path.join(ROOT, dir)));
for (const removed of REMOVED_PROVIDERS) {
test(`removed provider "${removed.id}" (PR #${removed.removalPr}) stays out of the chat registry`, () => {
assert.equal(REGISTRY[removed.id], undefined, `${removed.id} must not be in REGISTRY`);
assert.equal(REGISTRY[removed.alias], undefined, `${removed.alias} must not be in REGISTRY`);
});
test(`removed provider "${removed.id}" stays out of the provider catalogs`, () => {
assert.equal(getProviderById(removed.id), undefined, `${removed.id} must not be a provider`);
assert.equal(
getProviderByAlias(removed.alias),
null,
`alias ${removed.alias} must not be reused by any provider`
);
});
test(`removed provider "${removed.id}" has no executor (id or alias)`, () => {
assert.equal(hasSpecializedExecutor(removed.id), false);
assert.equal(hasSpecializedExecutor(removed.alias), false);
});
test(`removed provider "${removed.id}" has no free-model catalog entries`, () => {
assert.deepEqual(
FREE_MODEL_BUDGETS.filter((b) => b.provider === removed.id),
[],
`${removed.id} must not appear in FREE_MODEL_BUDGETS`
);
});
test(`removed provider "${removed.id}" identifiers and domains are absent from registry/executor sources`, () => {
const needles = [`"${removed.id}"`, `"${removed.alias}"`, ...removed.domains];
const offenders: string[] = [];
for (const file of scannedFiles) {
const text = fs.readFileSync(file, "utf8");
for (const needle of needles) {
if (text.includes(needle)) offenders.push(`${path.relative(ROOT, file)} :: ${needle}`);
}
}
assert.deepEqual(
offenders,
[],
`reintroduction of "${removed.id}" detected — see docs/reference/REMOVED_PROVIDERS.md`
);
});
}
test("the REMOVED_PROVIDERS doc lists every guarded id", () => {
const doc = fs.readFileSync(path.join(ROOT, "docs/reference/REMOVED_PROVIDERS.md"), "utf8");
for (const removed of REMOVED_PROVIDERS) {
assert.ok(doc.includes(`\`${removed.id}\``), `${removed.id} must have a row in the doc`);
assert.ok(doc.includes(`#${removed.removalPr}`), `PR #${removed.removalPr} must be linked`);
}
});

View File

@@ -0,0 +1,42 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { NextRequest } from "next/server";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-rerank-providers-route-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const { createProviderNode } = await import("../../src/lib/db/providers/nodes.ts");
const rerankProvidersRoute = await import("../../src/app/api/memory/rerank-providers/route.ts");
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
});
test("GET /api/memory/rerank-providers includes rerank-capable local provider nodes", async () => {
await createProviderNode({
id: "rerank-route-test-node",
type: "openai-compatible",
name: "Local reranker",
prefix: "local-reranker",
apiType: "rerank",
baseUrl: "http://127.0.0.1:8099/v1",
});
const response = await rerankProvidersRoute.GET(
new NextRequest("http://localhost/api/memory/rerank-providers")
);
const body = await response.json();
assert.equal(response.status, 200);
assert.deepEqual(
body.providers.find(
(provider: { provider?: string }) => provider.provider === "local-reranker"
),
{ provider: "local-reranker", hasKey: true, models: [] }
);
});

View File

@@ -120,6 +120,52 @@ test("injectSystemPrompt: null body returns as-is", () => {
assert.equal(injectSystemPrompt(null), null);
});
test("injectSystemPrompt: non-object bodies return as-is", () => {
setSystemPromptConfig({ enabled: true, suffixPrompt: "test" });
for (const body of [undefined, "prompt", 42, true]) {
assert.equal(injectSystemPrompt(body), body);
}
});
test("injectSystemPrompt: skips malformed message entries safely", () => {
setSystemPromptConfig({ enabled: true, prefixPrompt: "PRE", suffixPrompt: "SUF" });
const body = {
messages: [
{ role: "user", content: "hi" },
null,
{ role: "system", content: "Original prompt" },
],
};
const result = injectSystemPrompt(body);
assert.equal(result.messages[2].content, "PRE\n\nOriginal prompt\n\nSUF");
assert.equal(result.messages[1], null);
});
test("injectSystemPrompt: does not mutate the request or nested message content", () => {
setSystemPromptConfig({ enabled: true, prefixPrompt: "PRE", suffixPrompt: "SUF" });
const systemContent = [{ type: "text", text: "Original prompt" }];
const systemMessage = { role: "system", content: systemContent };
const body = {
messages: [systemMessage, { role: "user", content: "hi" }],
};
const result = injectSystemPrompt(body);
assert.notEqual(result, body);
assert.notEqual(result.messages, body.messages);
assert.notEqual(result.messages[0], systemMessage);
assert.notEqual(result.messages[0].content, systemContent);
assert.deepEqual(body, {
messages: [
{ role: "system", content: [{ type: "text", text: "Original prompt" }] },
{ role: "user", content: "hi" },
],
});
});
test("injectSystemPrompt: developer role treated as system", () => {
setSystemPromptConfig({ enabled: true, prefixPrompt: "PRE", suffixPrompt: "SUF" });
const body = {

View File

@@ -54,6 +54,7 @@ const PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE = [
"leonardo",
"modal",
"modelscope",
"nimble-search",
"nlpcloud",
"oauth",
"oci",
@@ -229,6 +230,7 @@ describe("ProviderIcon — local SVG dimensions", () => {
it.each([
["cline", "/providers/cline.svg"],
["kimi-coding", "/providers/kimi-logomark-light.svg"],
["opper", "/providers/opper.svg"],
])("gives %s a definite square layout size", (providerId, expectedSrc) => {
const container = renderIcon({ providerId, size: 24 });
const img = container.querySelector(`img[src="${expectedSrc}"]`);
@@ -244,8 +246,8 @@ describe("ProviderIcon — local SVG dimensions", () => {
describe("ProviderIcon — unresolved local asset provenance", () => {
it("covers the complete provider and alias inventory", () => {
expect(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE).toHaveLength(78);
expect(new Set(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)).toHaveLength(78);
expect(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE).toHaveLength(79);
expect(new Set(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)).toHaveLength(79);
});
it.each(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)(