Skip to content

feat(sync): add Merge Gateway model sync - #3249

Merged
rekram1-node merged 13 commits into
anomalyco:devfrom
MatthewFeroz:merge-model-sync
Jul 30, 2026
Merged

feat(sync): add Merge Gateway model sync#3249
rekram1-node merged 13 commits into
anomalyco:devfrom
MatthewFeroz:merge-model-sync

Conversation

@MatthewFeroz

@MatthewFeroz MatthewFeroz commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an authenticated Merge Gateway model sync using the paginated GET /v1/models catalog
  • map live pricing, limits, modalities, and capabilities while preserving curated provider-specific metadata
  • factor resolvable models through canonical base_model metadata
  • retain models missing from API-key-scoped responses and report models without canonical metadata
  • register Merge Gateway with the shared sync runner and hourly aggregator workflow
  • bootstrap the Merge Gateway catalog from the live API
  • preserve curated cache pricing while the public endpoint omits it, and ingest route-level prompt_caching / cache-price fields authoritatively when Merge exposes them
  • cross-check cache-capable routes against matching provider catalog entries, increasing cache-price coverage from 62 to 75 of 137 model files and correcting GPT-5.6 Sol to the route's $0.375/M cache-read rate
  • inherit canonical names when Merge returns an upstream org/model ID as display_name

The initial live sync created 43 model entries, updated 66, and deleted none.

Testing

  • bun models:sync merge-gateway --dry-run
    • 0 created, 0 updated, 0 removed; 137 unchanged after regeneration
  • bun test packages/core/test/sync.test.ts
    • 52 passed, 0 failed
  • bun validate
  • git diff --check
  • loaded the generated catalog through a local OpenCode checkout and confirmed merge-gateway/openai/gpt-5.6-sol, merge-gateway/anthropic/claude-fable-5, merge-gateway/xai/grok-4.5, etc.

Sources

Maintainer setup

The scheduled workflow requires a regular Merge Gateway API key configured as the repository Actions secret MERGE_GATEWAY_API_KEY. The credential is not included in this PR.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [low] [possible mistake] providers/merge-gateway/models/minimax/minimax-m2.toml:2 (also providers/merge-gateway/models/qwen/qwen3-coder-480b-a35b-instruct.toml:2, providers/merge-gateway/models/qwen/qwen3-next-80b-a3b-thinking.toml:2) - Check: name must be a human-readable display name, not a model ID. Why: These files set name = "MiniMaxAI/MiniMax-M2", name = "Qwen/Qwen3-Coder-480B-A35B-Instruct", and name = "Qwen/Qwen3-Next-80B-A3B-Thinking"org/model-slug strings that look like raw IDs and are inconsistent with sibling entries (e.g. minimax-m2.1 uses "MiniMax M2.1", and the canonical metadata names are clean). The sync writes model.display_name from the API, so these appear to be ID-shaped display names leaked from the catalog response; leaving them produces an ugly user-facing model name. Action: Verify the API display_name for these three models and either replace each with a proper display name or drop the name override so the clean models/ metadata name inherits.
  • [low] [possible mistake] packages/core/src/sync/index.ts:142 - Check: New sync providers should be added to a groups entry per sync.md "Adding A Provider" step 5. Why: merge-gateway is registered in providers but is absent from groups.aggregators, even though it is a multi-vendor gateway like llmgateway, kilo, and openrouter already in that group. bun models:sync aggregators will therefore not sync Merge Gateway, and the omission is not clearly covered by the "keep ambiguous sources out of shared groups" guidance (this source is a structured vendor catalog). Action: Add "merge-gateway" to the aggregators group, or confirm the omission is intentional.

@aakash-gupte

Copy link
Copy Markdown
Contributor

@rekram1-node can you take a look when you get a second?

@MatthewFeroz

Copy link
Copy Markdown
Contributor Author

Addressed the automated review and cache-pricing follow-up in 0ec6a52:

  • added merge-gateway to groups.aggregators
  • ID-shaped API display names now inherit clean canonical names; refreshed the affected TOMLs
  • added current route-backed cache prices for 14 Merge models
  • corrected GPT-5.6 Sol to Merge's 0.375 cache-read price and removed the unsupported cache-write price
  • added forward-compatible parsing for route-level prompt_caching/cache pricing, while preserving curated values until the public endpoint exposes those fields

Verification: 51 focused tests pass, bun validate passes, and a second live sync dry-run is clean (0/0/0, 137 unchanged).

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] providers/merge-gateway/models/openai/gpt-5-chat-latest.toml - Check: The merged catalog entry's limit.input must not exceed limit.context. Why: The sync adds [limit] context = 128_000, but the base model openai/gpt-5-chat-latest declares limit.input = 272_000. After base_model deep-merge, the generated entry will have input (272_000) greater than context (128_000), which is logically impossible and will mislead consumers. The shared baseModelOmit logic does not add ["limit.input"] here because limit.input is resolved from the existing (base-merged) TOML, so it is non-undefined and the omit condition never fires. Action: Verify the Merge Gateway API's context_window value for gpt-5-chat-latest (128K is below the 400K context documented in the base metadata, while the sibling gpt-5.1/5.2/5.3-chat-latest models do use 128K). If 128K is the correct provider context, add base_model_omit = ["limit.input"] so the stale 272K input limit is not inherited.

@MatthewFeroz

Copy link
Copy Markdown
Contributor Author

Fixed the follow-up reviewer finding in 31a3612: the Merge sync now distinguishes authored provider limits from base-model-resolved limits, so a smaller live context causes limit.input to be omitted instead of retaining an impossible inherited cap. Regeneration added base_model_omit = ["limit.input"] to gpt-5-chat-latest; the new regression test passes, the live dry-run is clean (137 unchanged), and full validation passes.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/merge-gateway/models/openai/gpt-5.6-luna.toml:2, gpt-5.6-terra.toml:2, gpt-oss-120b.toml:4, gpt-oss-20b.toml:2, anthropic/claude-3-7-sonnet-20250219.toml:4, claude-fable-5.toml:3, claude-sonnet-5.toml:3 - Check: reasoning_options on reasoning = true Merge Gateway models must reflect the controls that Merge Gateway's own routes expose, not default to []. Why: providers/merge-gateway/provider.toml documents that the OpenAI-compatible route passes through native reasoning_effort and the Anthropic-compatible route passes through thinking/output_config.effort. The same PR hand-curated openai/gpt-5.6-sol.toml with effort options (citing the OpenAI blog), and the provider's existing Anthropic entries (claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5, etc.) all declare toggle/budget_tokens/effort. OpenAI first-party, OpenRouter, Groq, and Cerebras declare the matching effort values for these exact models. Leaving these seven new entries at reasoning_options = [] claims "no verified caller control" on routes that the provider documentation and sibling entries show do expose one, so the published metadata understates Merge Gateway's API surface. Action: Apply the matching reasoning_options to these models (effort ["none","low","medium","high","xhigh","max"] for the GPT-5.6 pair, effort ["low","medium","high"] for the gpt-oss pair, and toggle/effort/budget_tokens matching the provider's other Anthropic entries for the three Claude models), or verify and document that those specific routes do not expose the documented reasoning controls.

  • [low] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts:260 - Check: mergeGatewayCachePricing preserves curated cache prices only when the API exposes no cache fields at all; when the API exposes prompt_caching or one cache price, it returns undefined for whichever side the API omits rather than falling back to the existing curated value. Why: sync.md states that exposed route-level cache values "authoritatively replace preserved cache prices," which reads as only the exposed values replacing — but the code also wipes the unexposed side. The syncs authoritative Merge Gateway cache pricing test confirms a curated cache_write of 6.25 is dropped when the API exposes prompt_caching + cache_read but no cache_write. If Merge ever partially populates cache pricing, future syncs will silently delete known cache prices. Action: Confirm the Merge API always populates cache_read and cache_write together (and never returns prompt_caching without prices), or fall back to existing?.cost?.cache_read/cache_write for whichever side the API omits.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts:495 - Check: mergeGatewayCachePricing should preserve curated cache prices for fields the API does not expose, per the sync.md documentation added in this PR. Why: The authoritative flag is true whenever a prompt_caching object exists or any cache pricing field is present, making replacement all-or-nothing. When the API exposes cache_read but not cache_write (as the test at sync.test.ts:601 explicitly verifies), the existing curated cache_write is silently dropped rather than preserved. The added sync.md states "Cache prices curated before that API support remain in provider TOMLs and survive syncs," which contradicts this behavior. If the API ever returns prompt_caching with only mode and no cost fields, all curated cache pricing would be dropped. Action: Either preserve non-exposed cache prices field-by-field (only replace fields the API actually provides) or update sync.md to document the all-or-nothing replacement behavior so the code and documentation agree.
  • [medium] [possible mistake] providers/merge-gateway/models/anthropic/claude-fable-5.toml:1 - Check: The reasoning value must match what the Merge Gateway route actually supports. Why: The leading comment states "the only available Anthropic route reports supports_reasoning = false," yet the model inherits reasoning = true from the base model (models/anthropic/claude-fable-5.toml has reasoning = true) and declares reasoning_options = []. The gpt-oss comments in this same PR distinguish supports_reasoning = false (no reasoning) from configurable = false (reasoning without caller control) as separate scenarios. If supports_reasoning = false means the route does not support reasoning at all, then reasoning = true is factually wrong for this provider model and reasoning_options must be removed (the schema forbids reasoning_options when reasoning = false). Action: Verify the Merge Gateway API semantics of supports_reasoning = false. If it means the model cannot reason through this route, override reasoning = false and remove reasoning_options = []. If it only means "no caller control," confirm that interpretation is consistent with how the gpt-oss comments use the same field.

@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@rekram1-node rekram1-node left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action items

  • [medium] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts:206 - Check: Apply the selected vendor route's supports_reasoning signal instead of always preserving resolved reasoning metadata. Why: The earlier reasoning findings corrected current TOMLs, but the sync still ignores the route-specific reasoning fields documented in provider.toml. If a route later reports supports_reasoning = false, or selection falls back to a vendor without reasoning, existing.reasoning / existing.reasoning_options survive and the generated model continues advertising unsupported controls. A conservative fix is to emit reasoning = false and remove reasoning_options when the selected route explicitly reports false, while continuing to preserve curated options for supported routes whose exact values are not exposed. Add a regression test for an existing reasoning model whose selected route reports false.

  • [medium] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts:261 - Check: Treat prompt_caching.mode = "none" as an explicit no-cache signal. Why: The previous cache-pricing discussion fixed preservation for fields the API omits, but mergeGatewayCachePricing ignores mode; with { mode: "none" } and no numeric fields, both ?? existing fallbacks retain curated cache prices. That publishes cache pricing for a route explicitly reporting no prompt caching. Return undefined read/write prices for mode = "none", and add a regression test distinct from the existing mode = "automatic" preservation test.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [possible mistake] providers/merge-gateway/models/deepseek/deepseek-r1.toml:3 - Check: reasoning must reflect the Merge route's actual behavior, and per AGENTS.md the prescribed representation when a model reasons but the route exposes no caller control is reasoning = true + reasoning_options = [], not reasoning = false. Why: This PR flips reasoning to false for ~30 models whose base metadata and own descriptions identify them as reasoning models — DeepSeek R1, Claude Opus 4.6/4.7/4.8, Sonnet 4.6, Haiku 4.5, GPT-oss-120b/20b, Nemotron Nano 9B v2, Gemma 4, many Qwen3.x thinking/instruct models, GLM-5.2, and Fugu Ultra — all driven by supports_reasoning === false in buildMergeGatewayModel (packages/core/src/sync/providers/merge-gateway.ts). The gpt-oss-120b/20b leading comments say the routes leave "callers [with] no reasoning control," which is exactly the no-control case AGENTS.md maps to reasoning = true + reasoning_options = []; yet those files set reasoning = false. The PR body cites the Merge API docs but documents no per-route evidence that supports_reasoning = false means the route emits no reasoning output rather than merely lacking a toggle. If the field means "no toggle," every one of these entries is wrong. Action: Verify with Merge Gateway that supports_reasoning = false definitively means the route produces no reasoning. If it only means "no caller control," restore reasoning = true and reasoning_options = [] on these models; either way, add a per-route citation/comment (deepseek-r1.toml currently has none) documenting the evidence.

  • [medium] [possible mistake] providers/merge-gateway/models/zai/glm-5.2.toml:2 - Check: interleaved reasoning output must not be advertised when reasoning = false. Why: The final file sets reasoning = false (line 2) while retaining [interleaved] field = "reasoning_content" (line 5) — internally inconsistent, since a route that does not reason cannot emit interleaved reasoning content. The sync preserves interleaved from the existing file even when supports_reasoning = false disables reasoning, so this contradiction is introduced by the PR. Action: Either drop the [interleaved] block when the selected route disables reasoning (and extend the sync to clear it), or confirm and document that this route still emits interleaved reasoning_content despite supports_reasoning = false.

  • [low] [possible mistake] providers/merge-gateway/models/qwen/qwen-flash.toml:9 - Check: Curated cache prices need a verifiable source when the public API does not expose them. Why: sync.md states the public Merge API "does not currently expose the full CMS metadata" and that cache prices are "curated from Gateway's route-level CMS," yet this PR adds cache_read/cache_write values across many new and updated models (e.g., qwen-flash cache_read = 0.0044, with a non-standard ~20% read ratio). The cited API docs do not contain these prices, so the values cannot be independently reviewed. Action: Provide or point to a verifiable source for the curated cache prices, and confirm a re-sync with the configured MERGE_GATEWAY_API_KEY is idempotent for these values.

base_model = "anthropic/claude-sonnet-4-5-20250929"
reasoning_options = [{ type = "toggle" }, { type = "budget_tokens", min = 1_024, max = 63_999 }]
name = "Claude Sonnet 4.5 (20250929)"
reasoning = false

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

????

This is plainly wrong this is a reasoning model, why are so many models marked incorrectly?

@rekram1-node

Copy link
Copy Markdown
Collaborator

Your api seems to incorrectly specify supports_reasoning, or the field is poorly named and shouldn't be abided by as much?

Maybe we need to talk through your changes this shouldn't be too difficult but I don't wanna keep reviewing it if we are gonna have so much invalid data

@MatthewFeroz

Copy link
Copy Markdown
Contributor Author

hey @rekram1-node, I'm getting the team on this. Will do my best to clear everything up before you need to review again

The public /v1/models schema does not document supports_reasoning, and the
live catalog populates it inconsistently across vendor routes: the same
model reports true on one route and false on another (claude-opus-4-6 is
false via anthropic, true via bedrock), and reasoning-only models such as
deepseek-r1 report false on their sole route. Flipping reasoning = false
from that field erased curated reasoning metadata on 42 models.

- only confirm reasoning when an available route reports
  supports_reasoning = true (always accompanied by route reasoning
  metadata), defaulting reasoning_options to [] when none are curated
- preserve curated reasoning metadata when routes report false or omit
  the field
- restore the 42 erased reasoning entries (claude, deepseek-r1, gpt-oss,
  gemma, qwen, glm, nemotron, fugu) from curated values
- re-sync against the live catalog: gemini-embedding-001 added, route
  cache_read prices and display names ingested, qwen3.5-27b limits and
  modalities updated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [low] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts (reasoning path in buildMergeGatewayModel) / packages/core/test/sync.test.ts "factors Merge Gateway GPT-5.6 Sol against canonical metadata" — Check: Brand-new factored models whose base metadata has reasoning = true must still emit a reasoning_options entry. Why: That test asserts buildMergeGatewayModel(mergeGatewayModel(), undefined) returns { base_model: "openai/gpt-5.6-sol", cost: { input: 5, output: 30 } } with no reasoning_options. models/openai/gpt-5.6-sol.toml has reasoning = true, so once resolved the factored model has reasoning = true with reasoning_options undefined, which fails the schema's "Must set reasoning_options when reasoning is true" refinement. The sync only defaults reasoning_options = [] when an available vendor route reports supports_reasoning = true; when no route confirms reasoning (the field is undocumented and inconsistently populated, per the patch 5 notes) and there is no existing file to preserve, a brand-new reasoning model is written without reasoning_options. The committed files are valid because options were hand-curated and then preserved, but the sync path itself can produce schema-invalid output for future automated syncs of new reasoning models. Action: Default reasoning_options = [] for brand-new factored models whose resolved base metadata has reasoning = true (or otherwise guarantee the sync never emits a factored reasoning model without reasoning_options), so future syncs of newly-added reasoning models don't fail validation.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] providers/merge-gateway/models/alibaba/qwen3.6-plus.toml / alibaba/qwen3.7-max.toml - Check: Stale alibaba/-namespaced provider model files must be removed when the sync now writes the same underlying models under qwen/. Why: The base revision still contains providers/merge-gateway/models/alibaba/qwen3.6-plus.toml and alibaba/qwen3.7-max.toml (each with base_model = "alibaba/qwen...", reasoning_options = [{toggle}, {budget_tokens ...}], and pricing 0.5/3 and 1.65/4.95 respectively). This PR creates providers/merge-gateway/models/qwen/qwen3.6-plus.toml and qwen/qwen3.7-max.toml referencing the same base_model values but with different pricing (0.276/1.651, 0.825/2.4755) and reasoning_options = [{toggle}]. Neither alibaba file appears in the diff, and deleteMissing = false retains them, so the generated catalog will publish two conflicting Merge Gateway entries for the same model (merge-gateway/alibaba/qwen3.6-plus vs merge-gateway/qwen/qwen3.6-plus). The PR already handled the analogous moonshotai/moonshot/ rename by deleting the old files, so the alibaba→qwen migration was missed. Action: Delete providers/merge-gateway/models/alibaba/qwen3.6-plus.toml and alibaba/qwen3.7-max.toml in this PR, or confirm and document that the gateway still independently serves alibaba/-prefixed IDs for these two models.
  • [low] [possible mistake] providers/merge-gateway/models/qwen/qwen3.5-27b.toml (patch 7 final state) - Check: attachment must be overridden to true when modalities.input is overridden to include a non-text modality. Why: The final file sets [modalities] input = ["text", "image"] but omits any attachment override, so the deep-merge inherits attachment = false from models/alibaba/qwen3.5-27b.toml (which has attachment = false, modalities.input = ["text"]). The sync code itself derives attachment = input.some(v => v !== "text"), and the same PR correctly emits attachment = true for the parallel qwen3.5-9b file with the same ["text", "image"] modalities, so this file's merged result (attachment = false with image input) is internally inconsistent with both the sync logic and neighboring entries. Action: Add attachment = true to qwen3.5-27b.toml, or verify the actual route's input modalities and correct the [modalities] override if image input is not actually exposed.

@github-actions

Copy link
Copy Markdown
Contributor

Based on my comprehensive review of the PR metadata, diff (all 10 patches), AGENTS.md, README.md, sync.md, the reasoning-options audit skill, schema code, and the base-revision files, I've verified the following:

  • The PR adds a well-structured Merge Gateway sync module with comprehensive tests covering pagination, duplicate detection, vendor selection, cache pricing, reasoning handling, and base-model factoring.
  • Stale alibaba/qwen3.6-plus.toml and alibaba/qwen3.7-max.toml files are deleted in patch 09, preventing duplicate provider entries.
  • Active moonshot models are renamed from moonshotai/ to moonshot/ (patch 04), with the deprecated kimi-k2-thinking retained in moonshotai/.
  • All models with matching models/ metadata use base_model; only bytedance and writer models use inline definitions (no matching metadata exists, verified via glob).
  • All models inheriting reasoning = true from base metadata have reasoning_options set (verified against base files for Claude, DeepSeek, Qwen, GLM, Grok, Meta models).
  • The gpt-5-chat-latest base_model_omit = ["limit.input"] is correctly derived (base has limit.input = 272_000 with context = 400_000, provider has context = 128_000).
  • Citations are present in the PR body and as leading comment blocks in TOML files.
  • The logo already exists and uses currentColor (pre-existing, not introduced by this PR).
  • No new third-party actions are added to the workflow (only an env var).
  • The supports_reasoning positive-only signal handling and disable_supported toggle derivation are well-documented in sync.md and tested.

No actionable findings.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] models/openai/gpt-5-chat-latest.toml:7 (and gpt-5.1-chat-latest.toml, gpt-5.2-chat-latest.toml) - Check: Upstream OpenAI model metadata is changed from reasoning = true to reasoning = false, and reasoning_options is removed from multiple provider entries that previously documented controls (providers/openai/models/gpt-5.1-chat-latest.toml had reasoning_options = [{ type = "effort", values = ["medium"] }], providers/requesty/models/openai/gpt-5.2-chat.toml had reasoning_options = [{ type = "effort", values = ["none", "low", "medium", "high", "max"] }, { type = "budget_tokens" }], plus providers/llmgateway and providers/orcarouter entries). Why: The PR title and body describe only the Merge Gateway sync, but this patch ("fix GPT chat reasoning capabilities") makes a material factual change to provider-agnostic OpenAI metadata that forces removal of previously-documented reasoning controls across five providers. None of the cited Sources (Merge Gateway docs, GPT-5.6 announcement) support the claim that gpt-5-chat-latest variants are non-reasoning, and AGENTS.md reminds that reasoning_options describe controls exposed by the inference provider, not merely the upstream model — so a provider serving the chat variant with reasoning effort would need a local reasoning = true override rather than silent removal. Action: Cite OpenAI documentation confirming that gpt-5-chat-latest, gpt-5.1-chat-latest, and gpt-5.2-chat-latest do not expose reasoning, and verify that no affected provider (especially Requesty, LLM Gateway, Orcarouter) serves these chat aliases with reasoning effort or budget controls; if any do, restore reasoning = true and the verified reasoning_options on those provider entries.

@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@aakash-gupte

Copy link
Copy Markdown
Contributor

Hey @rekram1-node, sorry for all the back and forth. We've reviewed our reasoning fields, and each of the model values that we're adding here and it looks good on our end. Can you do one more review when you have a moment? Thanks so much!

@MatthewFeroz

Copy link
Copy Markdown
Contributor Author

Hey @rekram1-node, just bumping this! Everything should be settled in terms of the model info

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [possible mistake] providers/merge-gateway/models/minimax/minimax-m2.1.toml:16 - Check: Provider limit.output must reflect the served route, not a default/cap that understates the model. Why: The sync writes output = 8_192 for MiniMax M2/M2.1/M2.5/M2.7 (and highspeed variants) and Nemotron Nano 9B, while canonical metadata is ~128k–131k output. That is an order-of-magnitude cut and will misconfigure clients. Action: Confirm Merge max_output_tokens for the selected vendor is a real generation cap; if it is a placeholder/default, stop publishing it (inherit canonical output or omit the override) and adjust buildMergeGatewayModel accordingly.
  • [medium] [possible mistake] providers/merge-gateway/models/openai/gpt-5.2-chat-latest.toml:5 - Check: reasoning / reasoning_options must match this provider’s OpenAI-compatible surface and same-model peers. Why: Patch 11 sets reasoning = false on gpt-5-chat-latest, gpt-5.1-chat-latest, and gpt-5.2-chat-latest. OpenAI’s first-party gpt-5.2-chat-latest is reasoning = true with effort = ["medium"]; LLM Gateway keeps that effort control; other gateways keep reasoning_options = [] (still reasoning). Claiming non-reasoning is a stronger denial than those peers and conflicts with native OpenAI for 5.2. Action: Verify Merge’s OpenAI route for these chat IDs; if they reason, restore reasoning_options ([] or the verified effort set)—do not use reasoning = false without route evidence.
  • [medium] [possible mistake] packages/core/src/sync/providers/openrouter.ts:33 - Check: Merge model namespaces must resolve to canonical models/ metadata the same way other aliases do. Why: The PR adds moonshot and sakana to CANONICAL_PROVIDER_PREFIXES but not mistral, while Merge IDs use mistral/... (not mistralai/...). New mistral/* catalog rows cannot auto-factor via resolveCanonicalBaseModel and are skipped until hand-authored. Action: Add mistral: { provider: "mistral", metadata: "mistral" } (or an equivalent Merge-local alias) and cover it in the alias resolution test.

@rekram1-node
rekram1-node merged commit e6d37bd into anomalyco:dev Jul 30, 2026
2 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] packages/core/src/sync/providers/merge-gateway.ts:230 - Check: Provider-authored reasoning = false must remain stable across syncs, and reasoning capability should match the same vendor route used for pricing/limits. Why: routeConfirmsReasoning treats supports_reasoning = true on any available vendor as authoritative (reasoning = routeConfirmsReasoning ? true : existing?.reasoning), while cost/limits come only from selectMergeGatewayVendor. That can (1) flip the new chat-latest overrides (reasoning = false on gpt-5-chat-latest / gpt-5.1-chat-latest / gpt-5.2-chat-latest) on the next sync if a secondary route reports true, and (2) advertise reasoning from a non-selected route while publishing another route’s prices. Action: Prefer explicit authored reasoning = false over the positive API signal, and/or scope the positive signal to the selected vendor (or document and test why cross-route confirmation must win).
  • [medium] [possible mistake] providers/merge-gateway/models/google/gemini-embedding-001.toml:9 - Check: Embedding models must not be published as normal text-generation entries with token output limits. Why: Sync only skips models whose vendor output lacks "text", then maps modalities through a text/audio/image/video/pdf allow-list (dropping embedding). This entry sets limit.output = 4_096, which contradicts canonical models/google/gemini-embedding-001 (output = 1) and Google’s own provider entry; even dimension-style peers use 1536, not 4096. Action: Skip embedding routes in buildMergeGatewayModel (or otherwise avoid creating chat-shaped rows), and remove or correct this model’s limits before merge.
  • [medium] [possible mistake] providers/merge-gateway/models/openai/gpt-oss-safeguard-120b.toml:12 - Check: Synced context/output limits should be plausible against canonical metadata for the same model. Why: This new entry sets context = 4_096 and output = 4_096, while models/openai/gpt-oss-safeguard-120b is 131_072 / 32_768, and also forces tool_call = false / structured_output = false against canonical true. That pattern looks like a bad route metadata mapping rather than a real 32× context cut. Action: Re-check the Merge GET /v1/models row for this ID and either fix the limit/capability mapping or cite why Merge intentionally serves a 4k safeguard variant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants