feat(concentrate): add Concentrate provider - #5049
Conversation
Action items
|
cf5ab7d to
1604c3b
Compare
|
Checking a few remaining peer cost values for consistency.One clear reasoning-options mismatch remains against lab and peer baselines.## Action items
|
1604c3b to
53c615a
Compare
Action items
|
|
Both of these look like false positives:
No changes for those two. Earlier findings are addressed: |
|
Checking the logo content more carefully and whether initial model files omit sync-derived limits that should be present. |
Register Concentrate as an OpenAI-compatible aggregator with an initial set of eight models. The remaining catalog follows in separate batches so each change stays small enough to review. The sync joins the public model list with each model's detail endpoint and derives pricing, limits, modalities, tool calling, structured output and attachment support from that data. Capabilities and limits come from the aggregate list/detail payloads rather than a single upstream route, so a capability-thin route cannot narrow what the gateway accepts, and output limits are capped by canonical models.dev metadata. Three rules encode the gateway's serving reality rather than its catalog: - Pricing defaults to the cheapest advertised route, but IDs whose live traffic is relayed elsewhere are pinned to the observed serving route, so published cost matches what callers are charged. - The gateway-level capability is authoritative for structured output. A route can advertise json_schema while the relay in front of it does not expose the feature. - Context pricing tiers at or above a model's own window are dropped, because such a band can never be entered. Reasoning controls are authored per model from the host's declared route metadata rather than inferred from the gateway's normalization enum, which silently accepts unsupported effort values. Every published effort value is backed by a route that declares it, and narrower or empty sets carry a leading comment with the API evidence. New remote models are reported instead of created automatically so each one gets that review first.
53c615a to
c605979
Compare
|
No actionable findings. |
fill="currentColor" was resolving to black in most contexts since nothing in this SVG's usage sets a text color to inherit. Concentrate's actual mark uses white dots; switched to an explicit fill="#ffffff" while keeping the background transparent, matching every other provider's backgroundless-icon convention on this site.
Action items
|
The repo's automated PR check flagged the previous commit: provider logos must use currentColor with no hardcoded colors, since a fixed fill breaks theming and can disappear on light backgrounds. Reverting to currentColor - this is the site's own enforced convention, not just an inferred one, so the earlier white-dots-with-transparent-bg attempt was wrong regardless of what the underlying brand mark looks like.
|
No actionable findings. |
| @@ -0,0 +1,5 @@ | |||
| name = "Concentrate" | |||
| env = ["CONCENTRATE_API_KEY"] | |||
| npm = "@ai-sdk/openai-compatible" | |||
There was a problem hiding this comment.
I dont see interleaved being set anywhere, normally it'd be reasoning_content
There was a problem hiding this comment.
Good catch ! it's optional so nothing flagged it missing. Fixed for all 7, plus added a test so a future sync can't silently drop it again.
rekram1-node flagged that none of the reasoning models had this set. Concentrate's own API docs (checked the live OpenAPI spec) show the message object returns both `reasoning` and `reasoning_content`, with reasoning_content documented as 'included for compatibility - reasoning will be returned rather than reasoning_content'. So Concentrate's real field is `reasoning`, which isn't a valid enum value for interleaved.field (only reasoning_content/reasoning_details are). Checked @ai-sdk/openai-compatible's actual source to make sure reasoning_content is still the right call: it already hardcodes `message.reasoning_content ?? message.reasoning` (and the streaming equivalent) unconditionally, so it picks up Concentrate's `reasoning` field via that fallback regardless of what's set here. reasoning_content is correct - deepseek-v3-0324 correctly left unset since it has no reasoning_options.
Action items
|
The bot flagged that buildConcentrateModel passes reasoning_options through from the existing TOML but never did the same for interleaved, so the next bun models:sync concentrate would silently wipe the [interleaved] blocks just added to the 7 reasoning models. Same pattern other aggregators (e.g. OpenRouter) already use for provider-only fields the API doesn't report. Added interleaved: existing?.interleaved next to reasoning_options in the factorBaseModel overrides, plus a positive/negative test pair in concentrate.test.ts mirroring the existing reasoning_options tests. Verified the new positive test actually catches the regression: reverted the source line, confirmed it goes red, restored it, confirmed green. Full package suite: 188 pass, 2 pre-existing failures (DeepInfra-related, confirmed present on the unmodified branch too, unrelated to this).
Action items
|
…thored fields
Two things from review:
1. interleaved was set to { field = "reasoning_content" } on all 7
reasoning models, but our own prior commit documented that Concentrate's
API actually returns reasoning on the `reasoning" key, not
`reasoning_content` (which is compatibility-only and never populated).
That mislabels the wire key for any catalog consumer that doesn't apply
the AI SDK's reasoning_content ?? reasoning fallback. Switched to bare
interleaved = true, the correct declaration when a model has a real
reasoning side channel that isn't one of the two named enum options.
Also moved it to match the generator's canonical position (before
[[reasoning_options]]) instead of appended at the end of the file.
2. buildConcentrateModel only preserved reasoning_options across syncs, not
status/provider/experimental - other ModelBase fields the API doesn't
own either. openrouter.ts and nano-gpt.ts already preserve all of these
for the same reason: a curator hand-setting one (e.g. marking a model
deprecated) would otherwise get silently wiped on the next sync. None of
our 8 models currently use these three, so this is preventive, not
fixing an active loss - closing the same gap class before it recurs.
Test changes: updated the interleaved test to assert true instead of the
old field-object shape, added a positive/negative pair for
status/provider/experimental mirroring the existing pattern. Verified
both new tests actually catch the regression (reverted the source lines,
confirmed red, restored, confirmed green) rather than just asserting
they pass. Also ran bun run validate (the real zod schema, not just TOML
parsing) - exit 0, and inspected the validated o3 output directly to
confirm interleaved: true survives validation. Full suite: 190 pass, 2
pre-existing DeepInfra failures unrelated to this and confirmed present
on the unmodified branch.
|
No actionable findings. |
Registers Concentrate as an OpenAI-compatible aggregator with an initial set of eight models. The remaining catalog follows in separate batches so each change stays small enough to review.
The sync joins the public model list with each model's detail endpoint and derives pricing, limits, modalities, tool calling, structured output and attachment support from that data. Capabilities and limits come from the aggregate list/detail payloads rather than a single upstream route, so a capability-thin route cannot narrow what the gateway accepts, and output limits are capped by canonical models.dev metadata.
Three rules encode the gateway's serving reality rather than its catalog:
Reasoning controls are authored per model from the host's declared route metadata rather than inferred from the gateway's normalization enum, which silently accepts unsupported effort values. Every published effort value is backed by a route that declares it, and narrower or empty sets carry a leading comment with the API evidence. New remote models are reported instead of created automatically so each one gets that review first.