From 26096e6706daea4e73a428e3caa0fa4c3e3f102e Mon Sep 17 00:00:00 2001 From: adevwithpurpose Date: Thu, 13 Aug 2026 09:49:21 -0300 Subject: [PATCH] fix(ci): clear base-reds on release/v3.8.50 (round 4) Drains the HARD failures reported by Release-Green run 31693210948 on issue #9985 (ESLint errors: 2) plus the merge-integrity red every open PR is inheriting. - ESLint error 1: @omniroute/opencode-plugin/src/index.ts had a stray extra '});' (introduced by #9316) that broke parsing with 'unexpected file in NFT list' on the build path. - ESLint error 2: cli-env-inline-comment-10100.test.ts used new Function to extract parseEnvValue from the bin entrypoint (no-new-func, Hard Rule #3). Extracted the helper to bin/cli/utils/parseEnvValue.mjs and import it from both the entrypoint and the test (same behavior, no eval). - open-sse-typecheck (Fast Quality Gates): open-sse/utils/stream.ts imported sseCommentsEnabled twice (#9378) causing TS2300 Duplicate identifier; removed the duplicate import. - Merge integrity (changelog + generated skills): skills/omni-settings/SKILL.md was edited manually by #10169 without updating the generator source, so check:agent-skills-sync failed on every PR (Generated: 1). Moved the curated thinking-budget content into a block (the documented preservation mechanism), which the generator now keeps in sync. Refs #9985 --- @omniroute/opencode-plugin/src/index.ts | 1 - bin/cli/utils/parseEnvValue.mjs | 21 +++++++++ bin/omniroute.mjs | 23 +--------- open-sse/utils/stream.ts | 1 - skills/omni-settings/SKILL.md | 45 ++++++++++++------- .../unit/cli-env-inline-comment-10100.test.ts | 31 +------------ 6 files changed, 53 insertions(+), 69 deletions(-) create mode 100644 bin/cli/utils/parseEnvValue.mjs diff --git a/@omniroute/opencode-plugin/src/index.ts b/@omniroute/opencode-plugin/src/index.ts index 09e3825676..bc18518cad 100644 --- a/@omniroute/opencode-plugin/src/index.ts +++ b/@omniroute/opencode-plugin/src/index.ts @@ -5478,7 +5478,6 @@ export function createOmniRouteConfigHook( rawConnections: localRawConnections, expiresAt: now() + resolved.modelCacheTtl, }); - }); // Startup diagnostics (file-based) — fires at startup via config hook if (resolved.features?.startupDebug === true) { diff --git a/bin/cli/utils/parseEnvValue.mjs b/bin/cli/utils/parseEnvValue.mjs new file mode 100644 index 0000000000..3388bda419 --- /dev/null +++ b/bin/cli/utils/parseEnvValue.mjs @@ -0,0 +1,21 @@ +/** + * Parse a `.env` value with dotenv-compatible comment handling. + * + * Without this, `KEY=value # note` stored the comment text as part of the + * value. The shipped .env ships exactly such a line for QUOTA_STORE_DRIVER, and + * consumers compare it with `===`, so annotating a variable inline silently + * disabled it (#10100). + * + * Quoted values are returned verbatim — a `#` inside quotes is data. For + * unquoted values a `#` *preceded by whitespace* starts a comment, so + * `pass#word` is preserved. + */ +export function parseEnvValue(raw) { + const value = String(raw).trim(); + + const quoted = value.match(/^(['"])([\s\S]*)\1\s*(?:#.*)?$/); + if (quoted) return quoted[2]; + + const commentIdx = value.search(/\s#/); + return (commentIdx === -1 ? value : value.slice(0, commentIdx)).trim(); +} diff --git a/bin/omniroute.mjs b/bin/omniroute.mjs index bfec91fead..c023879da8 100755 --- a/bin/omniroute.mjs +++ b/bin/omniroute.mjs @@ -23,6 +23,7 @@ import { getNodeRuntimeSupport, getNodeRuntimeWarning } from "./nodeRuntimeSuppo import { getDefaultDataDir } from "./cli/data-dir.mjs"; import { shouldProvisionStorageKey } from "./cli/utils/storageKeyProvision.mjs"; import { isVersionFastPath } from "./cli/utils/versionFastPath.mjs"; +import { parseEnvValue } from "./cli/utils/parseEnvValue.mjs"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -93,28 +94,6 @@ function migrateElectronServerEnv(dataDir) { } } -/** - * Parse a `.env` value with dotenv-compatible comment handling. - * - * Without this, `KEY=value # note` stored the comment text as part of the - * value. The shipped .env ships exactly such a line for QUOTA_STORE_DRIVER, and - * consumers compare it with `===`, so annotating a variable inline silently - * disabled it (#10100). - * - * Quoted values are returned verbatim — a `#` inside quotes is data. For - * unquoted values a `#` *preceded by whitespace* starts a comment, so - * `pass#word` is preserved. - */ -function parseEnvValue(raw) { - const value = String(raw).trim(); - - const quoted = value.match(/^(['"])([\s\S]*)\1\s*(?:#.*)?$/); - if (quoted) return quoted[2]; - - const commentIdx = value.search(/\s#/); - return (commentIdx === -1 ? value : value.slice(0, commentIdx)).trim(); -} - function loadEnvFile() { const envPaths = []; const loadedEnvPaths = []; diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index 24999c2eee..0eeccec17d 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -74,7 +74,6 @@ import { hasUnsupportedReasoningSignal, } from "./reasoningFields.ts"; import { applyThinkTag, flushThink, initThinkState } from "./thinkTagParser.ts"; -import { sseCommentsEnabled } from "./sseHeartbeat.ts"; import { caseInsensitiveToolNameLookup, restoreOpenAIToolNames, diff --git a/skills/omni-settings/SKILL.md b/skills/omni-settings/SKILL.md index 79d930097b..9ab8f95dfb 100644 --- a/skills/omni-settings/SKILL.md +++ b/skills/omni-settings/SKILL.md @@ -319,15 +319,7 @@ curl -X PUT https://localhost:20128/api/settings/system-prompt \ Get thinking budget configuration -Returns proxy-level thinking/reasoning **request rewrite** settings: - -| Field | Meaning | -|-------|---------| -| `mode` | `passthrough` (leave client reasoning alone — **required for Codex visible thinking**), `auto` (**strips** all client thinking fields), `custom`, `adaptive` | -| `customBudget` | Fixed budget when `mode=custom` | -| `effortLevel` | Base effort when `mode=adaptive` | - -**Not** compression and **not** “decrypt encrypted reasoning”. Full guide: `docs/guides/THINKING_BUDGET.md`. +Returns the current thinking/reasoning budget settings for AI models. ```bash curl https://localhost:20128/api/settings/thinking-budget \ @@ -338,17 +330,13 @@ curl https://localhost:20128/api/settings/thinking-budget \ Update thinking budget configuration -Example — keep client-controlled reasoning (Codex/Desktop): - ```bash curl -X PUT https://localhost:20128/api/settings/thinking-budget \ - -H "Authorization: Bearer $OMNIROUTE_TOKEN" \ + -H "Authorization: Bearer $OMNIROUTE_TOKEN" -H "Content-Type: application/json" \ - -d '{"mode":"passthrough","customBudget":10240,"effortLevel":"medium"}' + -d '{}' ``` -Warning: `mode=auto` deletes `reasoning` / `reasoning_effort` / Claude `thinking` from the outbound body before upstream. That can empty thinking panels even when the client requested Ultra + summary. - ### GET /api/tags List Ollama-compatible model tags @@ -398,3 +386,30 @@ curl -X POST https://localhost:20128/api/settings/purge-usage-history \ ## Payloads See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas. + + + + +### GET /api/settings/thinking-budget — behavior + +Returns proxy-level thinking/reasoning **request rewrite** settings: + +| Field | Meaning | +|-------|---------| +| `mode` | `passthrough` (leave client reasoning alone — **required for Codex visible thinking**), `auto` (**strips** all client thinking fields), `custom`, `adaptive` | +| `customBudget` | Fixed budget when `mode=custom` | +| `effortLevel` | Base effort when `mode=adaptive` | + +**Not** compression and **not** "decrypt encrypted reasoning". Full guide: `docs/guides/THINKING_BUDGET.md`. + +Example — keep client-controlled reasoning (Codex/Desktop): + +```bash +curl -X PUT https://localhost:20128/api/settings/thinking-budget \ + -H "Authorization: Bearer $OMNIROUTE_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"mode":"passthrough","customBudget":10240,"effortLevel":"medium"}' +``` + +Warning: `mode=auto` deletes `reasoning` / `reasoning_effort` / Claude `thinking` from the outbound body before upstream. That can empty thinking panels even when the client requested Ultra + summary. + diff --git a/tests/unit/cli-env-inline-comment-10100.test.ts b/tests/unit/cli-env-inline-comment-10100.test.ts index 2e3b41a725..4a3959c701 100644 --- a/tests/unit/cli-env-inline-comment-10100.test.ts +++ b/tests/unit/cli-env-inline-comment-10100.test.ts @@ -2,6 +2,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; +import { parseEnvValue } from "../../bin/cli/utils/parseEnvValue.mjs"; // #10100 — the .env loader kept inline comments inside values, so the shipped // `QUOTA_STORE_DRIVER=sqlite # sqlite | redis` line produced the literal value @@ -9,36 +10,6 @@ import path from "node:path"; // user annotating `QUOTA_STORE_DRIVER=redis # ...` silently got SQLite with no // warning (the existing warning lives inside the `redis` branch). -const LOADER = path.resolve("bin/omniroute.mjs"); - -/** - * The loader is a CLI entrypoint with side effects on import, so exercise the - * pure helper by extracting it from source rather than importing the module. - */ -function loadParseEnvValue(): (raw: string) => string { - const source = fs.readFileSync(LOADER, "utf8"); - const start = source.indexOf("function parseEnvValue("); - assert.ok(start > -1, "parseEnvValue should exist in bin/omniroute.mjs"); - // Walk to the end of the function body. - let depth = 0; - let end = start; - for (let i = source.indexOf("{", start); i < source.length; i++) { - if (source[i] === "{") depth++; - else if (source[i] === "}") { - depth--; - if (depth === 0) { - end = i + 1; - break; - } - } - } - return new Function(`${source.slice(start, end)}; return parseEnvValue;`)() as ( - raw: string - ) => string; -} - -const parseEnvValue = loadParseEnvValue(); - test("an unquoted inline comment is stripped", () => { assert.equal(parseEnvValue("sqlite # sqlite | redis"), "sqlite"); assert.equal(parseEnvValue("redis # sqlite | redis"), "redis");