fix(sse): reject a low-overlap stream-recovery continuation instead of concatenating it raw - #11152
Merged
diegosouzapw merged 32 commits intoAug 23, 2026
Conversation
added 2 commits
August 22, 2026 19:48
diegosouzapw#11099) (diegosouzapw#11132) Cherry-picked the value commit (ac09b6b) onto the current release tip, dropping the stale base-red sync commits that no longer apply. Focused test cline-model-format-11099 2/2 green; check:provider-consistency OK (267/348/0). Fixes diegosouzapw#11099 — the zai→z-ai namespace typo. Thank you @rqzbeh!
… i18n labels (diegosouzapw#11096) (diegosouzapw#11117) Cherry-picked the value commit (0e91881) onto the current tip, dropping the stale base-red sync commits. Focused tests: pollinations-api-key-required 1/1 plus the whole optional-key suite 142/142 (two legacy assertions in provider-route-schemas flipped to the new key-required contract, commented with the PR). Fixes diegosouzapw#11096 — Pollinations answers 401 anonymously now. Thank you @rqzbeh!
…ouzapw#11070) (diegosouzapw#11079) Cherry-picked the value commit (55da60f) onto the current tip, dropping the stale base-red sync commits. Focused tests: opencode-v2-config-11070 + merge-provider-guard + config-dir-single-source 12/12; mutation coverage gate no-drift (new test registered in tap.testFiles by the PR itself). Fixes diegosouzapw#11070 — setup-opencode now emits both V1 and V2 blocks. Thank you @rqzbeh!
…ction model lockout (diegosouzapw#11071) (diegosouzapw#11078) Cherry-picked the value commit (2c9202e) onto the current tip, dropping the stale base-red sync commits. Focused tests: ollama-404-model-lockout 2/2 + the five sibling lockout suites (combo-provider-cooldown-sibling, 8247-model-unhealthy, vertex-passthrough, nvidia-410, account-fallback-service) 112/112; mutation coverage no-drift. Fixes diegosouzapw#11071 — local/self-hosted 404s now scope to model lockout per the resilience doctrine. Thank you @rqzbeh!
…vider (diegosouzapw#11091) (diegosouzapw#11122) Cherry-picked both value commits (a1fa49a + a91f6e9, incl. the fail-open guard for unparseable hostnames) onto the current tip, dropping the stale base-red sync commits. Focused tests: is-local-provider-11091 + the isLocalProvider consumer suites (provider-validation-specialty, ollama-local-provider) 127/127; mutation coverage no-drift. Fixes diegosouzapw#11091 — RFC1918/CGNAT/link-local/mDNS hosts now classify as local via the existing isPrivateHost. Thank you @rqzbeh!
…gosouzapw#11100) (diegosouzapw#11125) Cherry-picked the three value commits onto the current tip, dropping the stale base-red sync commits. Focused tests: search-blocked-providers-11100 + search-registry/searxng-loopback/chat-guard/x-search suites 65/65. Fixes diegosouzapw#11100 (endpoint half) — GET /v1/search now honors blockedProviders via getAllSearchProviders. Thank you @rqzbeh!
…8n parity, eslint gate (diegosouzapw#9985) Discriminated against the pure base tip (all three reproduced without any PR diff): (1) getTokenLimit test aligned to the contract changes of diegosouzapw#8228/diegosouzapw#11034 with the bluesminds 200k pin kept as the original guard; (2) Vietnamese translations completed for harImport*/omni-webhooks (upstream already carried equivalent translations — conflict resolved to base); (3) eslint gate fixed by typing the dynamic core imports in capture-critical-db-state.test.ts (no-explicit-any). 41/41 tests green, typecheck clean, eslint exit 0.
…egosouzapw#11123) Cherry-picked the author's cleaned single-commit head onto the current tip. One fix applied pre-merge: the removal migration collided at number 161 with today's config_audit_log migration (diegosouzapw#11103) — renumbered to 162_remove_hackclub_provider.sql. Focused tests: remove-hackclub-11118 + provider-metrics-deleted-provider green; check:provider-consistency OK (266/348/0). Provider removal requested by Hack Club maintainers (diegosouzapw#11118). Thank you @rqzbeh!
…roviders (diegosouzapw#11081) Validated on a combined board over tip aa12873: focused tests local-rerank-logging + call-logs-row-filter green (7/7 across runs), typecheck:core clean. One pre-merge fix: widened waitForCallLogSaves 5s→15s — the call-log artifact writer's fsync latency exceeds 5s under a loaded host (pre-existing call-log-save-drain flakes identically on the pure tip), so the budget was load-flaky, not the code. Local rerank now logs call entries on success and error paths like embeddings/cloud rerank, captures full request/response payloads, attaches x-omniroute-* headers, and falls back /v1/rerank→/rerank on 404. Thank you @AndrianBalanescu!
…iegosouzapw#11082) Validated on a combined board over tip aa12873 (incl. sibling diegosouzapw#11081): call-logs-row-filter 4/4 green, typecheck:core clean. The merged-row predicate fix closes a real gap — in-memory (in-flight/recently-completed) rows bypassed every filter except correlationId; rowMatchesFilter() now applies search/model/provider/account/apiKey/status/combo uniformly while DB rows stay idempotent. Thank you @AndrianBalanescu!
…11045) Validated on the combined board over tip 80d931a: 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 board over tip 80d931a: quota-redis-store (incl. the KEY_PREFIX derivation test), local-redis-status and rate-limiter-redis-optional green, typecheck:core clean. One pre-merge fix pushed to the branch: docs/reference/ENVIRONMENT.md gained the REDIS_KEY_PREFIX row (env-doc-sync gate requires every .env.example var documented). Board note: the redis tests leave an ioredis retry handle open and hang the runner exit locally — assertions all pass; pre-existing pattern, not from this PR. Thank you @MeRezaRezaei!
Merged with the ENVIRONMENT.md hunk dropped: the tip already documents unset=unlimited for DEFAULT_RATE_LIMIT_PER_DAY via diegosouzapw#11022 (eba58cc), so the docs conflict resolved to the tip text. What lands is the .env.example comment correction, verified against src/shared/utils/apiKeyPolicy.ts::buildDefaultRateLimits — unset/empty → [] (unlimited), malformed → legacy 1000/day windows, explicit 0 → unlimited. Conflict resolution validated on the combined board (env-doc-sync gate green). Thank you @Prajeeth-12!
… calls (diegosouzapw#11085) Merged after conflict resolution validated on the combined board (50/50 casing tests green, typecheck:core clean). Two pre-merge adjustments on the branch: (1) the utilization route conflict resolved to the tip shape — its asNullableString/displayName version is newer than the branch's; (2) dropped the newly-added src/lib/db/connections.ts, orphaned once the route kept the tip shape (tip already uses getProviderConnectionById) — nothing imported it. The casing fix itself lands intact: non-streaming OpenAI→Claude conversion now restores canonical tool names, identity echoes no longer pin lowercase, and TOOL_RENAME_MAP gained the Task* tools. Fixes the live-reproduced Claude Code 'No such tool available: bash' failures. Thank you @linhdmn — outstanding repro and root-cause writeup!
…iegosouzapw#11035) (diegosouzapw#11157) Cherry-picked the JSDoc commit onto the current tip (authorship preserved), stripping the stale generated-count noise files. Focused: opencode-v2-config-11070 2/2. Comments now match the 128k fallback shipped in diegosouzapw#11035/diegosouzapw#11054. Thank you @rqzbeh!
…-web (diegosouzapw#11000) (diegosouzapw#11161) 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 diegosouzapw#11065 and the hackclub removal from diegosouzapw#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!
…dal Enter handler (diegosouzapw#10995) (diegosouzapw#11156) Cherry-picked onto the current tip (authorship preserved), generated-count noise stripped. Pre-merge: file-size baseline rebaselined 1080→1082 with dated annotation (the +2 lines are the Enter-handler isCheckDisabled mirror — owner-requested diegosouzapw#11056 polish; rest is Prettier reflow). Gate green; vitest add-api-key-modal-enter-key 2/2 (jsdom render test). Thank you @rqzbeh!
… oauth start (diegosouzapw#11164) (diegosouzapw#11173) Cherry-picked onto the current tip (authorship preserved), noise stripped. Focused: oauth-device-flow-11164 green + 9474-claude-code-oauth-mismap neighbor suite green. Device-code endpoint is tried first, camelCase/snake_case fallbacks normalized, no more blank code / 'Visit: undefined'. Fixes diegosouzapw#11164. Thank you @rqzbeh!
… providers (diegosouzapw#11100) (diegosouzapw#11155) Cherry-picked onto the current tip (authorship preserved), generated-count noise stripped. Two pre-merge adjustments: (1) dropped the unrelated localDb.ts re-export hunk (nothing in this PR uses those symbols); (2) automated security review flagged the blocked-provider list resolving once at server creation — the handler now rebuilds the schema per invocation via the resolver (advertised tools/list schema stays a creation-time snapshot, which is inherent to MCP). Vitest: new runtime-blocked-schema suite 3/3, full MCP __tests__ 118/118; contract suites (mcp-web-search-provider-enum-contract, search-blocked-providers-11100) 6/6; typecheck clean. This closes the residual gap noted when diegosouzapw#11120 was closed. Thank you @rqzbeh!
…antiation (diegosouzapw#11039) (diegosouzapw#11163) Cherry-picked onto the current tip (authorship preserved), noise stripped. Validated on BOTH runtimes: bun test tests/unit/db-adapters/ 44/44 under the pinned Bun 1.3.14 (native bun:sqlite path), and node --test on the same suite 52 pass / 0 fail / 1 skip (Bun-only adapter skips under Node, as designed). Dockerfile.bun entrypoint now matches the standalone runner shape. Follow-up to diegosouzapw#11039. Thank you @rqzbeh!
…workflow (diegosouzapw#11039) (diegosouzapw#11168) Cherry-picked onto the current tip (authorship preserved, Dockerfile.bun conflict with the just-merged diegosouzapw#11163 resolved additively — runner-web stage after the new entrypoint). Three pre-merge fixes on the branch: (1) generated-count noise stripped; (2) runner-web stage now returns to the non-root bun user after the apt install (mirrors the Node Dockerfile runner-web re-asserting USER node — the stage previously ended as root); (3) the 6 new build/manifest steps SHA-pinned so the zizmor ratchet stays at 191<=192 findings instead of regressing to 197 (actionlint clean). Workflow YAML parses; runner-base/runner-web targets cross-checked against the Dockerfile stages. Thank you @rqzbeh!
…apw#11122) (diegosouzapw#11154) Validated on a worktree over the current tip: the red it fixes reproduced exactly as described (media-page-client-browser-bundle red since diegosouzapw#11122 — providerRegistry became reachable from the dashboard client bundle via node:net). Post-fix: bundle test 2/2 green, new ip-parity suite + is-local-provider 7/7, all 7 outboundUrlGuard consumer suites 76/76 (the moved normalizeHost/isPrivateHost keep their re-exports; routing behavior untouched). Thank you @yourspraveen — clean surgical extraction with a pure-JS ipVersion mirroring Node's own regexes.
… test (diegosouzapw#11160) Validated against code before merge: 159 migration files on disk, 56 free-forever (Hack Club removal), 40 pools — counts verified, not trusted. check:docs-counts exit 0 (HARD failures drained; the 2 remaining soft executors-count notes are pre-existing on the tip) and check:test-discovery OK (orphan moved into the collected tree). These reds came from diegosouzapw#11103/diegosouzapw#11123 merging without the count regen — thanks for sweeping them @yourspraveen!
…uzapw#11071) (diegosouzapw#11165) Validated on a worktree over the current tip: account-fallback-service 91/91 plus the five sibling lockout suites 24/24. The measurement in the body (40 of 111 passthroughModels providers uncovered on this branch) is the clincher — one lookup via getProviderById().passthroughModels beside the existing checks, closing the diegosouzapw#11071 remainder for shared-registry gateways (port of diegosouzapw#11075 which had only landed on main). Thank you @yourspraveen!
… confirmed) (diegosouzapw#11114) Validated on the combined batch board over tip 92ef3c7: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green. Companion to diegosouzapw#11113 (consumer side): tokenrouter joins BUILTIN_PROVIDERS_SYSTEM_MUST_BE_FIRST — memory-system-first-6135 suite green. Live-confirmed 400 class documented in the body. Thank you @ggdayup!
…zapw#11162) Validated on the combined batch board over tip 92ef3c7: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green. Combo without models is now refused at the schema boundary (API 400), the CLI flags it, and openapi.yaml matches the real contract (phantom props removed). combo-* suites + cli-combo-create-models green on the board. Closes diegosouzapw#10954. Thank you @maxmad64bis!
…e) (diegosouzapw#11158) Validated on the combined batch board over tip 92ef3c7: 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!
…stem message (diegosouzapw#11113) Validated on the combined batch board: purify-system-first suite 4/4, typecheck clean. Pre-merge: file-size baseline gained a frozen entry for contextManager.ts at 1001 (+1, this PR's merge-into-leading-system branch) with a dated annotation — the gate caps unlisted files at 1000. Producer side of the live-confirmed TokenRouter 400 class: no internal path emits a mid-array system message anymore. Thank you @ggdayup — the call-log evidence made this airtight!
…ly output (diegosouzapw#11151) Merged after conflict resolution against the tip's diegosouzapw#11109 (per-call tool_call tracking): scanOpenAiSseText keeps the per-call finish_reason special-case AND gains reasoningText + literal finishReason; canContinue uses the in-flight predicate with the new reasoning-only-clean-stop escape. One integration fix on the branch: the PR's hallucinatedEmptyStop referenced emittedToolCall, which diegosouzapw#11109 had renamed — the branch now tracks emittedSawToolCall at the emitted level (any tool_call delta, complete or not), preserving the PR's don't-recover-after-tool-calls intent. Chain suites green: stream-continuation-wiring + stream-continuation + stream-recovery-toolcall 29/29. Thank you @maxmad64bis!
diegosouzapw
merged commit Aug 23, 2026
62ab93d
into
diegosouzapw:release/v3.8.50
4 of 7 checks passed
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…f concatenating it raw (diegosouzapw#11152) Merged after sibling diegosouzapw#11151 landed: streamRecovery.ts auto-merged byte-identical to the validated combined board; the test-file conflict (both PRs added suites at the same anchor) resolved keeping all 11 tests — diegosouzapw#11151's four clean-stop cases plus this PR's three threshold cases, with the PR's updated partial-tail fixture for the pre-existing overlap test. Full chain green: 32/32 (wiring + continuation + toolcall regression). The documented 8-char overlap threshold ends the silent mid-word gluing. Thank you @maxmad64bis!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The mid-stream continuation (Fase 4.4) re-requests with the already-emitted text as an
assistant prefill and expects the model to continue verbatim.
trimContinuationOverlapcorrectly reports "little/no overlap found", but the caller in
tryContinuetreated anynon-empty result as a successful stitch and appended it straight onto the emitted text
with no separator — producing a message cut in mid-word whenever the model ignored the
prefill and restarted on a fresh sentence instead of continuing.
A zero-overlap-only check is not enough: a model that
continues cleanly with zero echoed tokens is a legitimate outcome, indistinguishable
from a silent restart using string data alone. This PR uses a documented threshold
(
STREAM_RECOVERY.MIN_CONTINUATION_OVERLAP_CHARS = 8) instead of an exact-zero check,as a measured trade-off — see the constant's doc comment in
open-sse/config/constants.tsfor the explicit false-positive/false-negative analysis.
trimContinuationOverlapitselfis untouched — its "no overlap → return unchanged" contract is correct at the utility
level; the bug was purely in how the caller interpreted that result.
Related Issues
Validation
node --import tsx/esm --test tests/unit/stream-continuation.test.ts tests/unit/stream-continuation-wiring.test.ts tests/unit/stream-recovery.test.ts→ 34/34 PASSnpx eslint open-sse/services/streamRecovery.ts open-sse/config/constants.ts tests/unit/stream-continuation-wiring.test.ts→ 0 errorsrelease/v3.8.50tip (cut fromorigin/release/v3.8.50)Tests Added Or Updated
tests/unit/stream-continuation-wiring.test.ts— zero-overlap and below-thresholdrestarts are rejected and never concatenated raw; an overlap at/above the threshold is
still stitched correctly (regression guard); the pre-existing "silent post-commit
truncation" test's fixture was adjusted to an above-threshold partial overlap
("there world", 11/18) to make the trade-off explicit rather than silently masked.
Coverage Notes
open-sse/services/streamRecovery.ts+open-sse/config/constants.ts.Covered by the unit tests above.
above-threshold overlap ("Partial answer done.", 8/8) so it still exercises the happy
path under the new gate.
Reviewer Notes
overlapCharsis derived asscan.text.length - overlapResult.length(== matchedk);correct today, binds to
trimContinuationOverlapsemantics. Documented as a heuristic,not a solved distinction.
isSuspectedRestart; threshold 8 is uncalibrated.