From 63274a49b5905a8769f217d26a02e55af4e4e3bf Mon Sep 17 00:00:00 2001 From: hobart9527 Date: Sat, 18 Jul 2026 21:35:09 +0800 Subject: [PATCH 1/2] fix: move headroom before translation to cover all output formats (#2620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move compressWithHeadroom call before translateRequest, operating on body (source messages) with sourceFormat instead of translatedBody with finalFormat. This ensures all output formats (commandcode, ollama, gemini, etc.) get compressed — previously non-OpenAI/Claude formats silently skipped compression because translated bodies lack body.messages. --- open-sse/handlers/chatCore.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/open-sse/handlers/chatCore.js b/open-sse/handlers/chatCore.js index 47190acfaa..d37779104e 100644 --- a/open-sse/handlers/chatCore.js +++ b/open-sse/handlers/chatCore.js @@ -132,6 +132,24 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred } catch (e) { log?.warn?.("MODALITY", `image prefetch failed: ${e.message}`); } } + + // Per-request opt-out: client can bypass all token savers via header + const tokenSaverEnabled = clientRawRequest?.headers?.[TOKEN_SAVER_HEADER]?.toLowerCase() !== "off"; + // Headroom: compress source messages before translation so all + // output formats (commandcode, ollama, gemini, ...) are covered. + // Uses sourceFormat so body.messages is always present. + // See: https://github.com/decolua/9router/issues/2620 + const headroomDiagnostics = {}; + const headroomStats = await compressWithHeadroom(body, { enabled: tokenSaverEnabled && headroomEnabled, url: headroomUrl, model: upstreamModel, format: sourceFormat, compressUserMessages: headroomCompressUserMessages, diagnostics: headroomDiagnostics }); + const headroomLine = formatHeadroomLog(headroomStats); + const headroomSizeLine = formatHeadroomSizeLog(headroomDiagnostics); + if (headroomLine) { + log?.info?.("HEADROOM", `${headroomLine}${headroomSizeLine ? ` | ${headroomSizeLine}` : ""}`); + if (isHeadroomPhantomSavings(headroomStats, headroomDiagnostics)) { + log?.warn?.("HEADROOM", `reported token delta, but outbound JSON shrank <5%; provider may bill near-original payload | ${headroomSizeLine}`); + } + } else if (tokenSaverEnabled && headroomEnabled) log?.warn?.("HEADROOM", `skipped: ${headroomDiagnostics.reason || "compression unavailable"}${headroomDiagnostics.endpoint ? ` (${headroomDiagnostics.endpoint})` : ""}`); + let translatedBody; let toolNameMap; if (passthrough) { @@ -190,26 +208,12 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred delete translatedBody.tools; } - // Per-request opt-out: client can bypass all token savers via header - const tokenSaverEnabled = clientRawRequest?.headers?.[TOKEN_SAVER_HEADER]?.toLowerCase() !== "off"; // RTK: compress tool_result content const rtkStats = compressMessages(translatedBody, tokenSaverEnabled && rtkEnabled); const rtkLine = formatRtkLog(rtkStats); if (rtkLine) console.log(rtkLine); - // Headroom: optional external proxy compression; fail open if proxy is absent. - const headroomDiagnostics = {}; - const headroomStats = await compressWithHeadroom(translatedBody, { enabled: tokenSaverEnabled && headroomEnabled, url: headroomUrl, model: upstreamModel, format: finalFormat, compressUserMessages: headroomCompressUserMessages, diagnostics: headroomDiagnostics }); - const headroomLine = formatHeadroomLog(headroomStats); - const headroomSizeLine = formatHeadroomSizeLog(headroomDiagnostics); - if (headroomLine) { - log?.info?.("HEADROOM", `${headroomLine}${headroomSizeLine ? ` | ${headroomSizeLine}` : ""}`); - if (isHeadroomPhantomSavings(headroomStats, headroomDiagnostics)) { - log?.warn?.("HEADROOM", `reported token delta, but outbound JSON shrank <5%; provider may bill near-original payload | ${formatHeadroomSizeLog(headroomDiagnostics)}`); - } - } else if (tokenSaverEnabled && headroomEnabled) log?.warn?.("HEADROOM", `skipped: ${headroomDiagnostics.reason || "compression unavailable"}${headroomDiagnostics.endpoint ? ` (${headroomDiagnostics.endpoint})` : ""}`); - // Token-saver flags accumulator for the single "⚙" log line below. const xf = []; From f363c3309d69d69348fe6df8b49f853f1377d800 Mon Sep 17 00:00:00 2001 From: hobart9527 Date: Sat, 18 Jul 2026 21:55:35 +0800 Subject: [PATCH 2/2] ci: build and push to GHCR only, add short sha tag --- .github/workflows/docker-publish.yml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e8ef957e3d..5a1df2f179 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -8,11 +8,11 @@ on: env: GHCR_IMAGE: ghcr.io/${{ github.repository }} - DOCKERHUB_IMAGE: decolua/9router jobs: build-and-push: runs-on: ubuntu-latest + timeout-minutes: 20 permissions: contents: read packages: write @@ -29,22 +29,16 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: | ${{ env.GHCR_IMAGE }} - ${{ env.DOCKERHUB_IMAGE }} tags: | type=semver,pattern={{version}} type=raw,value=latest,enable={{is_default_branch}} + type=sha,prefix=,suffix=,format=short - name: Build and push uses: docker/build-push-action@v6 @@ -53,8 +47,6 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.GHCR_IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.GHCR_IMAGE }}:buildcache,mode=max - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64 provenance: false sbom: false