Merged after conflict triage: the six base-red repair files (vi.json, opencode.ts JSDoc, context-manager test, the three webhook dispatcher tests, the uncloseai orphan-test rename) were already drained on the tip by today's #11130/#11157/#11160/#11113 — those hunks resolved to the tip shape. What lands is the production-fix set: GLM transport-aware Anthropic headers, Claude Code-compatible model-listing rejection, combo live-test single-probe, zero-cost Auto-Combo interval normalization, recovery-clearing union handling, LLMLingua real-path compare, macOS netstat PID discovery, AI Horde R2 strict public-host validation. Sweep of every touched test file: 243/243 green; typecheck + file-size clean. (guide-settings-route's 4 reds reproduce on the pure tip — pre-existing drift from #11079, not from here.) Thank you @backryun!
Validated on the combined batch board + this branch: 231/231 across chatcore-translation-paths, reasoning-cache, strip-reasoning-blobs, and both Responses translator suites. Pre-merge: propagated the #11110/#11129 summary:[] defaults into five assertions here (each commented with its PR) — without it this branch red against the tip, and as a bonus the merge drains the 4 reasoning reds that were live on the tip from those merges. Plaintext now wins over a coexisting opaque companion; opaque-only drops cleanly for plaintext targets; combos keep explicit Skip. Fixes#10949 and #10959. Thank you @jackjinke!
Merged after conflict resolution in modelMetadataRegistry.ts: the tip's effortTiers chain (declared efforts → declared tiers → undefined-if-thinking-declared → codex extension) now carries this PR's GLM guard as the final-fallback override — GLM-family models without a provider-declared contract get the authoritative empty tier list instead of generic OpenAI tiers. GLM/ZCode suites 40/40 on the resolved branch. Closes#10962. Thank you @xz-dev!
Compaction-V2 output now counts as real model output (no synthetic response.failed after response.completed), the Codex SSE filter handles CRLF framing, and terminal detection runs before scan-state bounding. 88/88 stream/readiness suites on the board. Thank you @jackjinke!
Validated on the combined batch board over tip 92ef3c71: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green.
Empty-envelope 400 (no error field, empty content, finish_reason null) now rotates/retries instead of propagating as success; 200/streaming path never buffered; real-error 400s untouched. account-rotation + new rotation suite 34/34 on the board. Thank you @maxmad64bis!
Cherry-picked onto the current tip (authorship preserved), noise files stripped. Pre-merge addition: regenerated the golden snapshot with UPDATE_GOLDEN=1 because the branch's snapshot predated two legitimate tip changes — the dify bare-root from #11065 and the hackclub removal from #11123. The regen'd delta contains exactly those two (audited). This also drains a live base-red: provider-translate-path-golden was failing on the pure tip. 3/3 green. Thank you @rqzbeh!
Validated on the combined board over tip 80d931ae: kimi suites green (executor-kimi-web, kimi-partner-aff-links, token-health-check-kimi 33 assertions), vitest providerPageHeaderKimiPartnerLink green, typecheck:core clean. Audited the diff: only kimi-web switches to the international www.kimi.ai (Connect-RPC base, website, auth hints); kimi-coding / kimi-coding-apikey affiliate links stay on kimi.com as intended — asserted by the updated tests. Owner approved merge without the VPS smoke. Thank you @MeRezaRezaei!
Validated on the combined batch board over release/v3.8.50 tip d91238b7: static gates clean, typecheck:core clean, focused tests green.
Learned reasoning_effort caps mirror the merged learnedThinkingCaps mechanism: parse the upstream 4xx enum, clamp, retry once, consult proactively — covers custom openai-compatible connections the static registry can't. 22 new test cases + full regression list green. Fixes#11111. Thank you @maxmad64bis!
⭐5 — M365 Copilot (BizChat) individual/consumer path — 3 itens: (1) forma de invocação do #10718 derivou de novo (2026-08-21 capture): optionsSets 14→34, allowedMessageTypes 6→30, tone "magic"→"Magic", plugins []→[{BingWebSearch}], disconnectBehavior em todos os tiers, +8 keys de clientInfo; verificado contra conta real com round-trip WebSocket (ping-then-close → resposta real). (2) Aviso sobre o alias Antigravity gemini-3.1-pro-high ainda não publicado (3.8.49 pré-data). (3) Botão "Import .har file" no modal de credencial M365.
Conflito resolvido em copilot-m365-frames.ts (board vs release tip): mantive o forwarding de opts.plugins/toolChoice/customInstructions do HEAD com os NOVOS defaults da captura (BingWebSearch builtin, tone "Magic"). Alinhei 3 testes pré-existentes que afirmavam o contrato antigo (m365-bizchat-frames-4042 clientInfo, m365-tone-model-variants tone, copilot-m365-tool-calls plugins) — propagação de contrato, não mascaramento. Rebaselinei AddApiKeyModal 1073→1080 (crescimento próprio da parte 3, ~Har import button) com anotação.
Validação: typecheck limpo, 142/142 testes m365/copilot verdes, changelog-integrit/file-size/eslint OK.
⭐5 — Fecha #10265: chat do command-code migra do endpoint CLI-only /alpha/generate (version-gated + proxy-blocked para callers externos) para o documentado /provider/v1/chat/completions (OpenAI format). Removido o envelope CLI reverse-engineered (config/memory/taste/skills + headers CLI-impersonation), substituído por passthrough OpenAI plano com normalização de model id vendor-prefixed (#10809), clamp de max_tokens (#5166), sanitização de reasoning_effort. commandCode.ts 1037→171 linhas.
Validado no worktree board sobre tip: typecheck:core limpo; 175/175 testes focados (command-code executor/vision/usage/maxtokens/user-array/validation-specialty/responses-handler/provider-models-scoping); changelog-integrity/file-size/complexity/cognitive todos OK. TDD RED→GREEN documentado.
⭐5 — Atualiza domínio do provider hailuo-web para chat.minimax.io (#11000). Merge autorizado pelo operador (ordem explícita de prosseguir sem o smoke VPS da Hard Rule #18).
⭐5 — OpencodeExecutor buscava targetFormat com o id bruto do provider em vez do alias público ("oc"), caindo em default openai → corpo Responses no URL chat/completions (400). resolveOpencodeTargetFormat resolve via PROVIDER_ID_TO_ALIAS. TDD 4/4 + 32/32 irmãos, lint/tsc limpos. Fecha #11046. Base-red #9985 inherited.
⭐5 — Provider x-search de primeira classe (SuperGrok/xAI x_search) em POST /v1/search e MCP omniroute_x_search. Fallback de credenciais xai-oauth→xao→xai; distinto de web search e do X Developer MCP.
Reconciliado com o release tip (que já incluía #10981 "skip catalog-default SearXNG" deste mesmo lote): merge trouxe 5 conflitos reais de contagem gerada (llm.txt/README.md/AGENTS.md/PROVIDER_REFERENCE.md/SVGs/46 mirrors i18n, todos verificados como bump puro 347→348, sem perda de conteúdo do HEAD) + 1 conflito real de mergeable=CONFLICTING.
Durante a validação, os 3 testes novos de SearXNG expuseram um bug real de interação com #10981: `isUnconfiguredLoopbackSearchProvider()` checava o baseUrl ESTÁTICO do catálogo em vez do baseUrl efetivo (após override de `provider_options.baseUrl` ou `providerSpecificData.baseUrl` da conexão), então QUALQUER request a searxng-search — mesmo com override customizado — era rejeitado como se fosse o default não-configurado. Corrigido em `open-sse/handlers/search.ts` (resolve o baseUrl efetivo via `resolveSearchBaseUrl()` antes do skip-check, tanto para o provider primário quanto o alternate). Um teste do próprio #10988 que assumia o comportamento pré-#10981 (default localhost:8888 sempre atendido) foi atualizado para refletir o comportamento já mesclado e intencional (503 quando não configurado).
Validação completa: typecheck limpo, 70/70 testes unit (search-route/search-registry/x-search-provider/searxng-loopback-default), 24/24 vitest MCP, 14/14 integration (search-providers-catalog), lint limpo nos arquivos tocados, docs-counts-sync OK (2 drifts soft pré-existentes, não relacionados), gates estáticos (file-size/complexity/cognitive/dead-code/changelog) todos OK.
⭐5 — Rotação de conta não distinguia falha transitória (quota) de terminal (credencial morta) — ambas só esfriavam e eram retentadas para sempre. Agora markCooldown aceita kind transient/terminal; 3 terminais consecutivos evictam a conta (com fallback para não travar se todas evictadas). TDD, 17/17 testes, lint/typecheck/cycles OK.
⭐5 — Cursor PKCE login com Bearer quota, auto router e empty-turn errors. Feature completa e testada (11 arquivos de teste, 133 testes focados, todos verdes).
**Validação (worktree combinado `.claude/worktrees/fix-9909`, board sobre `origin/release/v3.8.50`):**
- 3 conflitos reais resolvidos: `config/quality/eslint-suppressions.json` (aditivo), `open-sse/config/providers/registry/cursor/index.ts` (dedup de 208 entradas de catálogo, 0 IDs duplicados verificado), `open-sse/executors/cursor.ts` (imports aditivos).
- `npm run typecheck:core`: limpo.
- `check-changelog-integrity`, `check-file-size`, `check-complexity` (2615/2774), `check-cognitive-complexity` (1175/1223), `check-dead-code` (410/416): todos OK.
- `check-public-creds`: 1 entrada obsoleta pré-existente na allowlist (`copilot-m365-web.ts:330`), já presente no tip da release — não é desta PR.
- `npm run lint`: 0 errors (5 warnings pré-existentes).
- Testes focados (`cursor-agent-cli-version`, `cursor-available-models`, `cursor-catalog-combo-compat`, `cursor-errors-classify`, `cursor-login-pkce`, `cursor-model-effort-suffix-7289`, `cursor-streaming`, `cursor-token-extractor`, `cursor-token-refresh-wiring`, `cursor-usage-fetcher`, `empty-stream-no-content-8649`): 133/133 verdes.
- Corrigido durante a validação: 1 teste novo da própria PR (`cursor-model-effort-suffix-7289.test.ts`, "splits effort off legacy grok- ids") colidia com `CURSOR_MODEL_ALIASES` já mesclado na release (mapeia `grok-4.5-high` → `cursor-grok-4.5-high` antes do fallback legado rodar); ajustado para usar um id não-aliasado (`grok-3-high`) que de fato exercita o fallback — commit `68b58ed`.
Obrigado pela contribuição, @yansigit — feature robusta com boa cobertura de testes.
Validado no worktree combinado: mesmos gates + 36 testes focados verdes. Feature bem documentada e testada (tool calling completo para copilot-m365-web via SignalR, incluindo keepalives e detecção de erro silencioso). CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint e testes focados todos verdes. Regressão real corrigida (apiType=chat agora é honrado em vez de forçado para /responses). CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, file-size, lint e 2/2 testes focados passando. Diagnóstico bem investigado do timeout WS do Meta AI (readyState exposto no erro). CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, file-size, lint todos verdes. Correção real dos 3 alertas CodeQL (HMAC em vez de hash bruto, URL parsing em vez de substring, dismiss documentado). CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint e 52 testes focados (kimi-jwt, kimi-credentials-extract, kimi-token-refresh, kimi-web-401-retry, provider-refresh-token-route, token-health-check-kimi) todos verdes. Implementação sólida e bem testada de ciclo de vida de token para Kimi Web. CI vermelho é o base-red já rastreado em #9985. Obrigado!
Reconciliado com a release (drift em typecheck-baseline.json/glm.ts/fetchTimeout.ts/stryker.conf.json — a tip já simplificou essas funções, mantida a versão da tip) e corrigi o `no-explicit-any` no teste novo (cast tipado, mesmo padrão já usado em outros testes do repo). Validado: lint limpo, teste focado passando. Fix real e bem documentado (claude-*/gemini-*/gemma-* sem provider ativo agora retorna 404 model_not_found em vez de 401 enganoso). CI vermelho é o base-red já rastreado em #9985. Obrigado!
Validado + reconciliado: 86/86 testes focados (combo-disable-session-stickiness, base-executor-sanitize-effort, command-code-executor) passando. Incluí o rebaseline do file-size (commandCode.ts 1023→1038, crescimento legítimo deste PR) diretamente no branch — evitando o erro que cometi antes (rebaseline só na worktree local, nunca chegando ao branch real). Correção real de bug com repro ao vivo documentada. CI vermelho é o base-red já rastreado em #9985. Obrigado!
Reconciliado com a release (conflito mecânico em stryker.conf.json — registro de teste que já existia na tip, apenas resolvido mantendo a entrada) e revalidado: 12/12 testes do arquivo log-level.test.ts passando (incluindo os 4 novos deste PR). CI vermelho é o base-red já rastreado em #9985. Obrigado!
Validado no worktree combinado do lote: typecheck:core, lint, gates de qualidade (file-size rebaselineado com justificativa — crescimento legítimo em modelCapabilities.ts/commandCode.ts) e os 97+9 testes focados (vision-bridge, command-code vision, model-select-field-catalog-vision) todos verdes. Duas correções reais (#10808/#10809) bem documentadas. CI vermelho neste PR é o base-red já rastreado em #9985. Obrigado!
Validado no worktree combinado do lote: typecheck:core, lint, gates de qualidade e testes focados (opencode-go-catalog-alignment + opencode-go-effort-aliases-8353, incluindo os novos casos muse-spark-1.2-contributor-*) todos verdes. CI vermelho neste PR é o base-red já rastreado em #9985. Obrigado!
Requests AgentUrlConfig from Cursor with each selected account token and selects the account's actual server-assigned Agent endpoint (agentUrl/agentnUrl) instead of a fixed global/us host, which fails for teams pinned to a different region. Caches validated endpoints by connection+token. Closes#10802.
Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 4 files):
- 18/18 focused tests pass (cursor-agent-host, cursor-apikey-provider).
- provider-translate-path-golden.test.ts initially failed — traced to a pre-existing base-red (stale golden snapshot left by an earlier freebuff merge, #10531, unrelated to this PR) and confirmed it reproduces on the pure release tip without this PR's changes. Fixed directly on release/v3.8.50 (mechanical key-ordering regen, values unchanged) rather than folding it into this PR's scope; green after merging that fix in.
- check-file-size, check-changelog-integrity: OK.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
- Author additionally validated live: a real Cursor request selected agentn.us.api5.cursor.sh and returned HTTP 200/PING.
Co-authored-by: tuandinh0801 <tuandinh0801@users.noreply.github.com>
Adds native support for Freebuff (Codebuff CLI free-tier gateway): executor with upstream session acquisition, agent-run lifecycle (START/FINISH), canonical system-prompt injection, and model→agent mapping for 9 free models; registry entry, dashboard branding/icons, and API-key validation. Closes#6793.
Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts after resolving generated provider-count drift, 15 files):
- 9/9 focused tests pass (freebuff-provider, providers-constants-split).
- Dropped one out-of-scope, unrelated hunk in scripts/build/build-next-isolated.mjs (build-memory heap tuning) that had nothing to do with the Freebuff provider — kept the branch scoped to its stated purpose.
- check-changelog-integrity: OK.
- file-size: gateways.ts and AddApiKeyModal.tsx crossed the frozen cap by +15/+5 lines (irreducible catalog-entry + credential-hint additions) — rebaselined with justification, pushed fix-in-place to the PR branch.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
Co-authored-by: adrianaryaputra <adrianaryaputra@users.noreply.github.com>
Canonical provider id renamed freepik → magnific (Magnific Mystic official API), with a permanent redirect + runtime alias so old freepik/<model> traffic and /dashboard/providers/freepik URLs keep working. Existing provider=freepik connection rows are rewritten to magnific by migration 160.
Closes#10604.
Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 138 files):
- Focused suite: 54/54 tests pass (magnific-image-handler, provider-validation-image-only, provider-alias-uniqueness, redirects-cli-renames).
- check-file-size, check-changelog-integrity: OK.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
Co-authored-by: RaviTharuma <RaviTharuma@users.noreply.github.com>
Obrigado — PR muito bem documentado e verificado. Adiciona o gateway TabiToken (Anthropic-first, /v1/messages, x-api-key) e estende hcnsec de 1 para 4 protocolos (Chat, Responses, Anthropic Messages, Gemini). AlternateFormat ganha o hook urlBuilder opcional (necessário para o path model-scoped do Gemini), compartilhado com o provider gemini nativo em vez de duplicado.
Reconciliado nesta sessão contra o release tip atualizado (base drift real: 343→345 canônicos entre quando o PR foi criado e o merge, mais os PRs #10673/#10658 mergeados nesse meio-tempo). Conflitos em contagens de providers (docs, file-size baseline, teste de partição) resolvidos additivamente.
Validação (reconciliação a partir de origin/release/v3.8.50):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- npm run check:provider-consistency — OK (266 REGISTRY entries, 346 providers canônicos, 0 exceções)
- 40/40 testes passando (newapi-gateway-providers, hcnsec-provider, providers-constants-split, alternate-formats)
Merged — extraction of the one still-uncovered fix from #8634 (the other two items — mode "search"→CONCISE downgrade, pplx-opus generation — were already applied on this release tip). typecheck/file-size/changelog/complexity/cognitive-complexity gates all clean, 32/32 tests passing.
Merged — clean extraction from #10358's genuinely new content (see PR body for the rationale: an unrelated .planning/codebase/ scaffolding dump was dropped). typecheck/file-size/changelog/provider-consistency gates clean, 18/18 tests passing.
Merged — carried forward the PR's own real value (the first 2 commits: ignore ad-hoc BOT_TOKEN/BOT_URL in env-doc-sync, plus the lock-in test). The branch had accumulated 7 more commits chasing the moving release tip across several rebases (each one re-fixing base-reds that had already moved again by the next rebase) — dropped those since they no longer apply to the current tip, and cherry-picked just the 2 with lasting value, preserving your authorship. 14/14 focused tests pass, changelog gate green. Thanks!
Merged — locally validated (23/23 focused probe-isolation tests, typecheck:core clean, file-size/changelog gates green). Reconciled with today's #8367 (codexAccount module extraction, merged earlier): the persistCodexQuotaState closure this PR touched had been extracted into persistCodexChildQuotaResponse — applied the same probe-origin isolation guard (!shouldIsolateProbeFailures()) at its new call site instead of reintroducing the old inline closure. Thanks for closing this real gap!
Merged — locally validated (30/30 focused tests: chatcore-codex-account-pool, codex-account-cooldown-write, codex-account-pool, providers-route-codex-account-pool, resilience-explain-codex-account, sse-auth-codex-account-pool; typecheck:core clean; file-size/complexity/cognitive-complexity/changelog gates all green). Merges clean against the current release tip with zero conflicts. Great refactor — extracting persistCodexQuotaState out of chatCore.ts into a proper codexAccount/ module with virtual quota pool isolation is a solid improvement. Thanks!
Merged — locally validated (72/72 focused tests, typecheck:core clean, all static gates green) after resolving base-drift conflicts (catalog.ts cooperative-yield insertion point, modelMetadataRegistry.ts snapshot-param signature). CI's red checks (Unit Tests fast-path shards, Fast Quality Gates, Docs Gates) are confirmed PRE-EXISTING base-red on the pure release tip — reproduced tests/unit/db-driver-bundling-externals.test.ts, tests/unit/model-catalog-runtime-invalidation.test.ts and others failing identically against origin/release/v3.8.50 with zero PR content, unrelated to this change. Thanks for the design and for absorbing #10724's value here — great work on both review rounds!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
* fix(security): zero out open CodeQL code-scanning alerts
- src/mitm/handlers/antigravity.ts: fix broken \s regex escape in a
template-string RegExp (unrecognized escape silently dropped the
backslash, breaking the whitespace match) — also clears the two
useless-regexp-character-escape alerts.
- open-sse/executors/gemini-web.ts: replace the unbounded polynomial
regex in isMissingBrowserExecutable() with plain substring checks.
- src/shared/middleware/chatBodyAdmission.ts, open-sse/services/
conversationTracker.ts, src/app/api/v1/models/catalogCache.ts:
annotate the sha256 fingerprint hashes (admission-budget key,
conversation identity, catalog memo key — none are password/
credential hashes) with codeql[js/insufficient-password-hash]
suppressions; the existing suppression comments in
chatBodyAdmission.ts were on the wrong line and CodeQL never
picked them up.
- tests/unit/qwen-token-plan-console-site.test.ts, tests/unit/
cloudflare-playground-provider.test.ts: replace raw
string.includes(hostname) assertions with new URL(...).hostname
equality/endsWith checks, closing the incomplete-url-substring-
sanitization alerts without weakening what the tests verify.
* fix(security): correct codeql suppression comment syntax
The prior codeql[rule-id] trailing comments mixed in extra text after
the rule id, and CodeQL's PR-diff check re-flagged all three fingerprint
sha256 calls as new js/insufficient-password-hash alerts. Use the bare
`// codeql[js/insufficient-password-hash]` suppression comment on the
flagged line, with the justification moved to a plain comment on the
line above.
* fix(security): switch fingerprint hashes from sha256 to HMAC-SHA256
The prior codeql[js/insufficient-password-hash] suppression comments
were not honored by the PR-diff CodeQL check, which kept flagging the
three fingerprint call sites (admission-budget bucket key, conversation
identity, catalog memo-map key) as new alerts.
Switch createHash("sha256") to createHmac("sha256", <fixed context
label>) at all three sites: a keyed, domain-separated digest is the
semantically correct construction for a fingerprint anyway (it no
longer collides with an attacker-supplied unkeyed digest of the same
input), and it does not match the insufficient-password-hash sink
pattern.
* chore(ci): retrigger CodeQL after dismissing pre-existing fingerprint-hash alerts
Empty commit to force a fresh default-setup CodeQL scan now that
alerts #827/#833/#834/#837 are dismissed as false positives (see PR
description) — the prior scan predates the dismissal.
---------
Co-authored-by: Markus Hartung <mail@hartmark.se>
* test(sse): golden characterization of the executor map before the R0.3 registry refactor
Freezes the 137-entry provider-id → executor mapping (class, provider
identity, backing PROVIDERS config), the no-shared-instances invariant,
and the getExecutor() dispatch rules (memoized DefaultExecutor fallback,
cloud-agent guard #6699, search-provider guard #10274) as stable JSON
snapshots. The upcoming ExecutorRegistry must keep both snapshots
byte-identical.
* refactor(sse): route executor lookup through ExecutorRegistry (R0.3)
Adds open-sse/executors/registry.ts (Map-based registry mirroring
translator/registry.ts): the built-in table in executors/index.ts stays
declarative, every entry is registered at module load, and
getExecutor()/hasSpecializedExecutor() resolve through the registry.
DefaultExecutor fallback, its memoization, and the cloud-agent (#6699) /
search-provider (#10274) guards are unchanged.
Also fixes a latent lookup leak: the old object-literal lookup treated
Object.prototype names (constructor, toString, ...) as specialized
executors; the Map registry resolves them to the DefaultExecutor
fallback like any unknown provider.
Parity proof: executor-map golden (137 entries, byte-identical
before/after), check:known-symbols green, 1018 tests across the 65
executor test files green. Docs: OPEN_SSE_ARCHITECTURE factory section
corrected (it claimed generation from providerRegistry).
Refs #3501
* test(executors): regenerate ExecutorRegistry golden snapshots after release sync
release/v3.8.50 sunset mimocode and added cloudflare-playground + jina-search
since this PR's snapshots were captured; refresh the golden fixtures to match.
---------
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Co-authored-by: Markus Hartung <mail@hartmark.se>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
* feat(providers): add Cloudflare AI Playground as No Auth provider (closes#10389)
Reverse-engineered access to the free, anonymous Cloudflare AI Playground:
chat runs over a PartySocket WebSocket speaking Cloudflare's cf_agent RPC
protocol with zero credentials (no account, no API key, no cookies). The
WS upgrade is gated on a browser-grade TLS fingerprint, so the executor
drives a headless Chromium via Playwright and speaks the protocol from
inside the page context.
- registry entry: cloudflare-playground (alias cfp), authType none,
curated 20-model catalog (GLM 5.2, Kimi K2.7 Code, DeepSeek V4 Pro,
gpt-oss-120B, Llama 3.3 70B, Qwen2.5 Coder 32B, ...) captured from the
live getModels RPC (2026-08-15)
- executor: cf_agent frame stream -> OpenAI SSE translation, id-filtered
parser (RPC done:true frames cannot kill the stream), in-band upstream
errors mapped to HTTP 429/502, abort + timeout handling, clean errors
- noauth UI entry with reverse-engineered-endpoint notice
- tests: 12 unit tests using real captured frames (incl. the 3021
rate-limit error) + fake transport; ESLint clean; open-sse typecheck clean
* fix(providers): define __name helper in page context before evaluate
Bundlers with keepNames (esbuild/tsx, webpack) inject a __name() call into
serialized function bodies. page.evaluate(openPlaygroundSession) therefore
threw ReferenceError: __name is not defined in real browser sessions.
Define the helper on window before evaluating the session opener.
* fix(providers): sync docs counts, golden snapshots and add reasoning_content support for cloudflare-playground
* chore: remove ad-hoc cfp-shim debug script per review feedback
The standalone shim duplicated the executor's frame-parsing and transport
logic and is superseded by open-sse/executors/cloudflare-playground.ts.
Requested in PR #10442 review.
* feat(gemini-web): expose image generation through /v1/images/generations (closes#10466)
Adds a gemini-web image-generation path following the chatgpt-web precedent:
- imageRegistry: gemini-web provider entry (format gemini-web, cookie auth)
with the nano-banana-web model. The -web suffix keeps the bare
nano-banana id owned by adobe-firefly (operator decision 2026-07-31).
- gemini-web executor: new parseStreamResponseImages() extracts generated
image URLs from the StreamGenerate candidate extension block
(inner[4][0][12][7][0], url at entry[0][3][3] — string or list form),
dedupes cumulative frames, upgrades to =s2048, and deliberately skips
web-search thumbnails at [12][1]. Image mode (x_gemini_web_image_mode)
captures every StreamGenerate frame, resolves on first image, and gets
a 90s window; chat mode is byte-for-byte unchanged.
- handlers/imageGeneration/providers/geminiWeb.ts: drives the executor in
image mode with an explicit generation directive prompt (the web UI
otherwise answers with web-search images), caps n at 4, returns URLs or
b64_json (downloads the public googleusercontent asset), and surfaces
refusal text when no image was produced.
- Dispatch branch on format gemini-web in handleImageGeneration.
Tests: 21 new tests with fixtures built from the documented frame layout
(string/list url forms, cumulative-frame dedupe, web-image exclusion,
size-directive handling, refusal visibility, n-cap, b64_json, registry
wiring incl. the bare nano-banana → adobe-firefly regression guard).
Adjacent suites: gemini-web (6 files), chatgpt-web image, image handler,
route, registry, adobe-firefly, freepik, designer — all green.
ESLint clean on touched files (2 pre-existing any warnings unchanged);
tsc -p open-sse 0 errors.
* fix(media): close browser leak, surface timeout errors, and fall back accounts for gemini-web images
Addresses pre-merge review findings on #10494 (closes#10466):
- cloudflare-playground executor: close the launched browser on EVERY
non-success start() path, including the detected Cloudflare "Attention
Required" challenge branch (was leaking a Chromium process per blocked
request).
- cloudflare-playground executor: a streaming chat timeout now emits an
explicit timeout_error SSE chunk before [DONE] instead of silently
completing, so a client can no longer mistake an empty/partial timed-out
stream for a successful answer. Timeout duration is now injectable for
deterministic tests.
- gemini-web image handler + imageCredentialRetry: classify the underlying
GeminiWebExecutor's expired/blocked-session failure modes (400/500, per
its own Playwright timeout/catch-all branches) as retryable, so
executeImageWithCredentialFallback advances to the next eligible account
instead of only doing so on a plain 401.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs: regenerate provider counts after merging release/v3.8.50 (341 -> 342)
The previous merge commit resolved all 51 auto-generated-file conflicts by
taking release/v3.8.50's content, which still said 341 providers. Merging in
this branch's Cloudflare Playground provider brings the live catalog to 342,
so npm run check:docs-counts-sync now flags stale claims. Fix:
- docs/reference/PROVIDER_REFERENCE.md: regenerated via
`npm run gen:provider-reference`.
- README.md/AGENTS.md/llm.txt/package.json description: 341 -> 342.
- docs/diagrams/{readme-hero,promise-pillars,comparison-table,cli-terminal}.svg:
341 -> 342 in the embedded "NNN providers" text (targeted replace, matched
against the exact pattern check-docs-counts-sync.mjs validates).
check:docs-counts-sync and check:changelog-integrity are both clean after
this commit.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs(env): document CLOUDFLARE_PLAYGROUND_CHROME_PATH
Used by open-sse/executors/cloudflare-playground.ts but missing from
.env.example and docs/reference/ENVIRONMENT.md, caught by the
env-doc-sync gate when combined with other PRs in the release
merge-train.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: user.email <freakymustard67@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>