Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c428043
chore(release): open v3.8.40 development cycle
diegosouzapw Jun 28, 2026
8da9e6a
chore(docker): harden base image against container-scan CVEs (#5229)
diegosouzapw Jun 28, 2026
051285a
test(docker): skip comment lines in #4076 builder heap-ordering check…
diegosouzapw Jun 28, 2026
7854b1e
chore(ci): Trivy advisory scan ignores unfixed CVEs (Security-tab noi…
diegosouzapw Jun 28, 2026
5f4cd53
Scope textual thinking tag extraction (#5224)
rdself Jun 28, 2026
3ab9723
Add more Icons (#5220)
backryun Jun 28, 2026
3ee53cd
fix(mcp): forward HTTP auth to internal tool fetches (#5218)
KooshaPari Jun 28, 2026
6143ffc
fix(cli): ship scripts/build/runtime-env.mjs in npm package (#5227) (…
diegosouzapw Jun 28, 2026
6f150cf
fix(antigravity): retry excluded accounts via fallback LRU (#5222)
Ardem2025 Jun 28, 2026
e8d13ec
fix(command-code): omit max_tokens when client omits it (#5221)
adivekar-utexas Jun 28, 2026
d8a392a
fix(command-code): omit max_tokens when client omits it; correct regi…
adivekar-utexas Jun 28, 2026
0568c37
fix(providers): refresh impersonation User-Agents + TLS profiles to c…
backryun Jun 28, 2026
462bca6
feat(compression): risk-gate pre-pass — shield sensitive spans from l…
diegosouzapw Jun 28, 2026
4c4dcbd
🛡️ Sentinel: Security hardening (#5241)
iamedwardngo Jun 28, 2026
dbe44bb
fix(combo): wire session stickiness into round-robin dispatch (#3825)…
diegosouzapw Jun 28, 2026
cf8c161
fix(qoder): coalesce concurrent job token exchanges (#5254)
KooshaPari Jun 28, 2026
503b120
fix(codex): drop local_shell tool (no longer supported upstream) (#5250)
KooshaPari Jun 28, 2026
fa7f81c
Remove discontinued Gemini CLI channel (#5246)
rdself Jun 28, 2026
b87b9ab
fix(proxy): shorten fast-fail negative health cache (#5255)
KooshaPari Jun 28, 2026
c779be6
fix: preserve provider request headers in logs (#5257)
rdself Jun 28, 2026
2932145
fix(deps): resolve install warnings and audit vulnerabilities (#5252)
yunaamelia Jun 28, 2026
04ae5a7
feat(kilocode): anonymous no-auth access to free models (#4019) (#5259)
diegosouzapw Jun 28, 2026
8adb40e
fix(proxy): scope fallback cache by target url (#5261)
KooshaPari Jun 28, 2026
2513934
fix(responses): keep shell tool caller-side (#5256)
KooshaPari Jun 28, 2026
bce5d17
fix(grok-cli): accept full auth.json object in import-token endpoint …
fulorgnas Jun 28, 2026
2b0c129
fix(dashboard): add GitHub releases fallback to Update Available look…
diegosouzapw Jun 28, 2026
598beba
fix(agent-bridge): unwrap cloudcode-pa .request envelope for Antigrav…
diegosouzapw Jun 28, 2026
35f373e
fix(qoder): decouple shared job token exchange abort (#5265)
KooshaPari Jun 28, 2026
99b17f1
feat(mcp): omniroute_tool_search + one-line TS signatures — roadmap #…
diegosouzapw Jun 29, 2026
ba38e31
fix(cli): wire --tray Unix path through the runtime systray2 loader (…
diegosouzapw Jun 29, 2026
bc00e32
fix(compression): record no-op compression runs so Stacked is visible…
diegosouzapw Jun 29, 2026
9dc31c7
feat(compression): RTK semantic command-output renderers (opt-in) — r…
diegosouzapw Jun 29, 2026
898aac5
feat(compression): QuantumLock cache-prefix stabilization (opt-in, de…
diegosouzapw Jun 29, 2026
5ac4637
docs: reorganize docs/ + accuracy audit + drop Node 20 (rebased onto …
diegosouzapw Jun 29, 2026
1fd19c4
fix(authz): require auth for v1beta client API (#5274)
rdself Jun 29, 2026
57f81f6
fix(grok-cli): strip unsupported params (presencePenalty, etc.) befor…
fulorgnas Jun 29, 2026
9b0adab
fix(mcp): break tools.ts ↔ toolSearch.ts cycle (check:cycles red on r…
diegosouzapw Jun 29, 2026
f862074
feat(compression): composite-command splitter for RTK detection — roa…
diegosouzapw Jun 29, 2026
f5445a2
fix(providers): drop retired chatgpt-web/codex models (#5280)
backryun Jun 29, 2026
9a89158
feat(logging): call-log correlation ID (safe core subset of #5275) (#…
diegosouzapw Jun 29, 2026
72f8bf2
feat(compression): saliency heatmap in the compression studio — roadm…
diegosouzapw Jun 29, 2026
a71157a
feat(compression): inline transparency annotation — roadmap #18 (#5284)
diegosouzapw Jun 29, 2026
43da1bb
feat(compression): result memoization for deterministic engines (opt-…
diegosouzapw Jun 29, 2026
c8833fd
fix(dashboard): keep disabled no-auth providers visible with in-place…
diegosouzapw Jun 29, 2026
fa94f38
feat(compression): hard-budget mode (compress to ≤ N tokens) — roadma…
diegosouzapw Jun 29, 2026
21c1f54
feat(compression): relevance extractive engine — roadmap #7 (#5289)
diegosouzapw Jun 29, 2026
12de25b
fix(combo): advance to next model on 400 'model not supported' (#5249)
Chewji9875 Jun 29, 2026
4008bdc
fix(compression): propagate hard-budget unreachable-target warning th…
diegosouzapw Jun 29, 2026
5ba5bcd
test(combo): reconcile #4279 stop-guard test with #5249 advance polic…
diegosouzapw Jun 29, 2026
b14fb89
docs(changelog): reconcile v3.8.40 cycle — cover all 47 merged PRs + …
diegosouzapw Jun 29, 2026
401a7b4
fix(auth): compare-and-swap guard on OAuth refresh persist (#4038) (#…
diegosouzapw Jun 29, 2026
1a096c4
fix(sse): omit Command Code max_tokens when client sends a non-positi…
diegosouzapw Jun 29, 2026
c0f1ee2
fix(sse): replace synthesized kiro "Continue" turn with neutral fille…
diegosouzapw Jun 29, 2026
223e67a
test(targets): add 14 unit tests for targetExhaustion handler (#5296)
KooshaPari Jun 29, 2026
601e2a8
feat(providers): add Microsoft 365 Copilot individual provider (#5302)
skyzea1 Jun 29, 2026
dbe750f
fix(dashboard): add /dashboard/context parent route + missing sidebar…
diegosouzapw Jun 29, 2026
d4c54f6
fix(sse): non-stream OpenAI-compatible requests no longer coerced to …
diegosouzapw Jun 29, 2026
d5b0350
fix(ci): re-point Docker :latest tag on release (#5301) (#5311)
diegosouzapw Jun 29, 2026
004e5f5
docs(changelog): cover M365 Copilot provider (#5302) + targetExhausti…
diegosouzapw Jun 29, 2026
7ccd1b2
merge: origin/main into release/v3.8.40 — resolve authz pipeline test…
diegosouzapw Jun 29, 2026
165c823
test: align health-autopilot cross-site + chat-pipeline Accept tests …
diegosouzapw Jun 29, 2026
ecb17e6
chore(quality): rebaseline eslintWarnings 4090->4103 — v3.8.40 cycle …
diegosouzapw Jun 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 10 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,6 @@ NEXT_PUBLIC_CLOUD_URL=
# debugging or when routing through a corporate mirror. Used by:
# open-sse/services/usage.ts.
#OMNIROUTE_CROF_USAGE_URL=https://crof.ai/usage_api/
#OMNIROUTE_GEMINI_CLI_USAGE_URL=https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist
#OMNIROUTE_CODEWHISPERER_BASE_URL=https://codewhisperer.us-east-1.amazonaws.com
#OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/quota
#OMNIROUTE_OPENCODE_GO_QUOTA_URL=https://api.z.ai/api/monitor/usage/quota/limit
Expand Down Expand Up @@ -721,7 +720,7 @@ CODEX_OAUTH_CLIENT_ID=app_EMoamEEZ73f0CkXaXp7hrann
# Used by: open-sse/executors/theoldllm.ts. Default: 30000 (30s).
# THEOLDLLM_NAV_TIMEOUT_MS=30000

# ── Gemini / Gemini CLI / Antigravity / Windsurf (all Google-based) ──
# ── Gemini / Antigravity / Windsurf (all Google-based) ──
# These providers ship public OAuth client_id/secret values (or Firebase Web
# keys) embedded in their public CLIs/binaries. Defaults are baked into the
# code via open-sse/utils/publicCreds.ts — leave the env vars unset to use
Expand All @@ -730,8 +729,6 @@ CODEX_OAUTH_CLIENT_ID=app_EMoamEEZ73f0CkXaXp7hrann
#
# GEMINI_OAUTH_CLIENT_ID=
# GEMINI_OAUTH_CLIENT_SECRET=
# GEMINI_CLI_OAUTH_CLIENT_ID=
# GEMINI_CLI_OAUTH_CLIENT_SECRET=
# ANTIGRAVITY_OAUTH_CLIENT_ID=
# ANTIGRAVITY_OAUTH_CLIENT_SECRET=
# WINDSURF_FIREBASE_API_KEY=
Expand Down Expand Up @@ -819,7 +816,7 @@ GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98
# VISION_BRIDGE_API_KEY=

# ─────────────────────────────────────────────────────────────────────────────
# ⚠️ GOOGLE OAUTH (Antigravity, Gemini CLI) & OTHER PROVIDERS — REMOTE SERVERS
# ⚠️ GOOGLE OAUTH (Antigravity) & OTHER PROVIDERS — REMOTE SERVERS
# ─────────────────────────────────────────────────────────────────────────────
# The default Client IDs above ONLY work when OmniRoute runs on localhost.
# For remote/VPS hosting (including Docker containers on remote servers):
Expand Down Expand Up @@ -847,7 +844,7 @@ GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98
# Used by: open-sse/executors/base.ts — buildHeaders() dynamic lookup.
# Update these when providers release new CLI versions to avoid blocks.

CLAUDE_USER_AGENT="claude-cli/2.1.187 (external, cli)"
CLAUDE_USER_AGENT="claude-cli/2.1.195 (external, cli)"

# Disable the deterministic tool-name cloak applied on both Anthropic-bound paths
# (executors/base.ts native OAuth + executors/cliproxyapi.ts CLIProxyAPI) —
Expand All @@ -857,7 +854,7 @@ CLAUDE_USER_AGENT="claude-cli/2.1.187 (external, cli)"
# forward the original names verbatim (debugging only).
# CLAUDE_DISABLE_TOOL_NAME_CLOAK=false
CODEX_USER_AGENT="codex-cli/0.142.0 (Windows 10.0.26200; x64)"
GITHUB_USER_AGENT="GitHubCopilotChat/0.45.1"
GITHUB_USER_AGENT="GitHubCopilotChat/0.54.0"
ANTIGRAVITY_USER_AGENT="antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0"
KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0"
# KIRO_VERIFY_FULL_CRC=false # opt-in: full per-frame message CRC validation on the Kiro event stream (debug corrupted streams; prelude CRC + TLS already protect framing)
Expand All @@ -872,9 +869,8 @@ KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0"
# Used by: open-sse/executors/kiro.ts
# KIRO_VERIFY_FULL_CRC=false
QODER_USER_AGENT="Qoder-Cli"
QWEN_USER_AGENT="QwenCode/0.15.11 (linux; x64)"
QWEN_USER_AGENT="QwenCode/0.19.3 (linux; x64)"
CURSOR_USER_AGENT="Cursor/3.4"
GEMINI_CLI_USER_AGENT="google-api-nodejs-client/10.3.0"

# Override Codex client version sent in headers independently of the
# CODEX_USER_AGENT string. Used by: open-sse/config/codexClient.ts.
Expand Down Expand Up @@ -1362,6 +1358,11 @@ APP_LOG_TO_FILE=true
# Health check result cache TTL (ms). Default: 30000 (30s)
# PROXY_HEALTH_CACHE_TTL_MS=30000

# Unhealthy health check result cache TTL (ms). Default: 2000 (2s)
# Keeps transient fast-fail timeouts from poisoning a proxy for the full
# healthy-result cache window under high concurrency.
# PROXY_HEALTH_UNHEALTHY_CACHE_TTL_MS=2000

# Allow OAuth and provider validation flows to bypass a pinned proxy and connect
# directly when proxy reachability pre-checks fail. Default: false.
# Also configurable from Dashboard > Settings > Feature Flags.
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ jobs:
PROMOTE="${PROMOTE_INPUT:-false}"
else
git fetch --tags --quiet || true
HIGHEST=$(git tag -l 'v[0-9]*' | sed 's/^v//' | grep -vE -- '-(rc|alpha|beta|pre|next)' | sort -V | tail -1 || echo "")
if [ -n "$HIGHEST" ] && [ "$VERSION" = "$HIGHEST" ]; then
PROMOTE="true"
else
echo "Version $VERSION is not the highest semver tag (highest=${HIGHEST:-<none>}). Not promoting :latest."
# Decide via the extracted helper, which folds VERSION into the
# candidate set so the result is independent of git-tag sync timing
# on `release` events (#5301). Without that, the freshly-created tag
# is often not yet visible here and :latest stays a release behind.
PROMOTE=$(git tag -l 'v[0-9]*' | bash scripts/ci/should-promote-latest.sh "$VERSION")
if [ "$PROMOTE" != "true" ]; then
echo "Version $VERSION is not the highest stable semver. Not promoting :latest."
fi
fi
echo "promote_latest=$PROMOTE" >> "$GITHUB_OUTPUT"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/wiki-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ name: Wiki Sync
# It does NOT overwrite existing wiki pages by default: several docs sources still carry
# stale counts (e.g. ARCHITECTURE.md says "177 providers" while the wiki cover is 226),
# so blind overwrite would regress the wiki. Full content parity (--update-existing) is
# gated on regenerating those sources — see docs/ops/DOCUMENTATION_AUDIT_REPORT.md.
# gated on regenerating those sources first.

on:
push:
Expand Down
17 changes: 0 additions & 17 deletions .mcp.json.example

This file was deleted.

2 changes: 1 addition & 1 deletion @omniroute/opencode-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Every field is optional. Defaults mirror v0.1.0 behaviour so existing `opencode.
| `combos` | `boolean` | `true` | Discover `/api/combos` and surface them as pseudo-models with LCD capabilities. Combos are keyed under the `combo/<slug>` namespace and labelled `Combo: <name>` in the model picker so they're distinguishable from raw provider/model pairs. |
| `enrichment` | `boolean` | `true` | Pull display names from `/api/pricing/models` AND per-million-token pricing (`input`, `output`, `cached` → `cacheRead`, `cache_creation` → `cacheWrite`) from `/api/pricing`, then overlay both onto the live catalog (so the UI shows `Claude 4.7 Opus` with `cost.input: 5`, `cost.output: 25` instead of raw IDs and zeroed cost). |
| `compressionMetadata` | `boolean` | `false` | Pull `/api/context/combos` so combo names get tagged with their compression pipeline, e.g. `Combo: claude-primary [rtk🟡 → caveman🟠]`. Intensity tokens render as traffic-light emoji (🟢 lite/minimal · 🟡 standard · 🟠 aggressive/full · 🔴 ultra) so the picker advertises "how compressed" each combo is at a glance. |
| `providerTag` | `boolean` | `true` | Prepend a short upstream-provider label to the enriched display name with `" - "` separator, so `cc/claude-opus-4-7 → Claude - Claude Opus 4.7` differs visibly from `kr/claude-opus-4-7 → Kiro - Claude Opus 4.7` in the OC TUI model picker. Label resolution: use `/api/pricing/models[<alias>].name` verbatim when ≤8 chars (e.g. `Claude`, `Kiro`, `Codex`, `Qwen`), otherwise fall back to `UPPER(alias)` (e.g. `GitHub Models` → `GHM`, `Gemini-cli` → `GEMINI-CLI`). Idempotent. Combos intentionally skipped (the `Combo: ` prefix already conveys multi-upstream). |
| `providerTag` | `boolean` | `true` | Prepend a short upstream-provider label to the enriched display name with `" - "` separator, so `cc/claude-opus-4-7 → Claude - Claude Opus 4.7` differs visibly from `kr/claude-opus-4-7 → Kiro - Claude Opus 4.7` in the OC TUI model picker. Label resolution: use `/api/pricing/models[<alias>].name` verbatim when ≤8 chars (e.g. `Claude`, `Kiro`, `Codex`, `Qwen`), otherwise fall back to `UPPER(alias)` (e.g. `GitHub Models` → `GHM`, `Gemini` → `GEMINI`). Idempotent. Combos intentionally skipped (the `Combo: ` prefix already conveys multi-upstream). |
| `usableOnly` | `boolean` | `false` | Read `/api/providers` and filter the catalog to providers that have at least one connection with `isActive: true` AND `testStatus: 'active'`. Subtract-filter semantics: providers unknown to BOTH the pricing-models catalog AND the connection table pass through (so synthetic prefixes like `agentrouter/*` survive). On fetch failure the filter is disabled for the refresh — never hides the whole catalog. |
| `diskCache` | `boolean` | `true` | Persist the last successful `/v1/models` + `/api/combos` + enrichment + connections + compression snapshot to `${OPENCODE_DATA_DIR ?? ~/.local/share/opencode}/plugins/omniroute-<providerId>.json`. On a subsequent cold start where `/v1/models` throws (network down / IP whitelist drop / 5xx) the static block hydrates from the snapshot so OC's model picker survives offline. Soft-fail on read/write — never blocks publishing. |
| `geminiSanitization` | `boolean` | `true` | Strip `$schema`/`$ref`/`additionalProperties` from tool params when the model id matches `gemini` |
Expand Down
11 changes: 5 additions & 6 deletions @omniroute/opencode-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,15 +1225,15 @@ export interface OmniRouteEnrichmentEntry {
cacheWrite?: number;
};
/**
* Provider alias prefix seen in `/v1/models` ids (e.g. `cc`, `gemini-cli`).
* Provider alias prefix seen in `/v1/models` ids (e.g. `cc`, `gemini`).
* Populated by `defaultOmniRouteEnrichmentFetcher` from
* `/api/pricing/models` keys. Drives the `usableOnly` alias↔canonical
* resolution.
*/
providerAlias?: string;
/**
* Canonical provider id used by `/api/providers` connections (e.g.
* `claude`, `gemini-cli`, `kiro`). Populated from the per-provider
* `claude`, `gemini`, `kiro`). Populated from the per-provider
* `entry.id` field inside `/api/pricing/models`.
*/
providerCanonical?: string;
Expand Down Expand Up @@ -2046,7 +2046,7 @@ export function formatCompressionPipeline(pipeline: OmniRouteCompressionStep[]):
export interface OmniRouteProviderConnection {
/** Connection UUID. */
id: string;
/** Canonical provider id, e.g. `claude`, `gemini-cli`, `kiro`. Matches `entry.id` in `/api/pricing/models`. */
/** Canonical provider id, e.g. `claude`, `gemini`, `kiro`. Matches `entry.id` in `/api/pricing/models`. */
provider: string;
/** Connection auth flavor, e.g. `apikey`, `oauth`, `cookie`. */
authType?: string;
Expand Down Expand Up @@ -2125,7 +2125,7 @@ export const defaultOmniRouteProvidersFetcher: OmniRouteProvidersFetcher = async
* walk only the namespaced keys to derive the alias↔canonical mapping).
*
* Returns:
* - `aliases`: set of alias prefixes safe to keep (e.g. `cc`, `gemini-cli`).
* - `aliases`: set of alias prefixes safe to keep (e.g. `cc`, `gemini`).
* - `canonicals`: set of canonical provider ids (e.g. `claude`, `kiro`).
*
* Callers should treat membership in EITHER set as "usable" — raw model
Expand Down Expand Up @@ -2174,7 +2174,7 @@ export function usableProviderAliasSet(
}
// Always include every usable canonical as an alias too — handles the
// common case where `/v1/models` ids use the canonical id directly
// (e.g. `gemini-cli/gemini-1.5-pro`).
// (e.g. `gemini/gemini-1.5-pro`).
for (const canonical of usableCanonicals) aliases.add(canonical);
return { aliases, canonicals: usableCanonicals, knownAliases };
}
Expand Down Expand Up @@ -3174,7 +3174,6 @@ export function sanitizeGeminiToolSchemas(payload: unknown): unknown {
* `gemini-2.5-flash`, etc.)
* - `models/gemini-…` (Google Generative AI canonical id form)
* - `google-vertex/gemini-…` (OpenCode + AI-SDK Vertex routing prefix)
* - `gemini-cli/…` (real OmniRoute alias surfaced on b35 prod `/v1/models`)
*
* Liberal by design: a false positive (cleaning a payload that didn't
* need cleaning) costs only a structuredClone + one walk; a false negative
Expand Down
11 changes: 4 additions & 7 deletions @omniroute/opencode-plugin/tests/config-shim.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1311,9 +1311,9 @@ test("config: providerTag (default-on) prepends '<provider> - ' to enriched raw-
"gemini-3-flash",
{
name: "Gemini 3 Flash",
providerAlias: "gemini-cli",
providerCanonical: "gemini-cli",
providerDisplayName: "Gemini-cli",
providerAlias: "gemini",
providerCanonical: "gemini",
providerDisplayName: "Gemini",
},
],
])
Expand All @@ -1335,10 +1335,7 @@ test("config: providerTag (default-on) prepends '<provider> - ' to enriched raw-
entry.models["opencode-omniroute/claude-sonnet-4-6"].name,
"Claude - Claude Sonnet 4.6"
);
assert.equal(
entry.models["opencode-omniroute/gemini-3-flash"].name,
"Gemini-cli - Gemini 3 Flash"
);
assert.equal(entry.models["opencode-omniroute/gemini-3-flash"].name, "Gemini - Gemini 3 Flash");
// Combos stay untouched — `Combo: ` prefix already conveys multi-upstream.
assert.equal(entry.models["opencode-omniroute/claude-tier"].name, "Claude Tier");
});
Expand Down
4 changes: 2 additions & 2 deletions @omniroute/opencode-plugin/tests/gemini-sanitize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ test("shouldSanitizeForGemini: google-vertex/gemini-1.5-flash → true", () => {
assert.equal(shouldSanitizeForGemini({ model: "google-vertex/gemini-1.5-flash" }), true);
});

test("shouldSanitizeForGemini: gemini-cli/gemini-2.5-pro → true (real OmniRoute alias)", () => {
assert.equal(shouldSanitizeForGemini({ model: "gemini-cli/gemini-2.5-pro" }), true);
test("shouldSanitizeForGemini: gemini/gemini-2.5-pro → true", () => {
assert.equal(shouldSanitizeForGemini({ model: "gemini/gemini-2.5-pro" }), true);
});

test("shouldSanitizeForGemini: claude-sonnet-4 → false", () => {
Expand Down
Loading
Loading