Compare commits

...
Author SHA1 Message Date
CodeWhale BotandClaude Opus 5.5 1c25cd0448 Merge origin/main into fix/7096-opencode-go-context-window
Maintainer merge so the required checks run against current main
(main was red when this branch last ran CI; CW-7525).

Signed-off-by: CodeWhale Bot <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 15:19:50 -07:00
CodeWhale BotandClaude Opus 5.5 c8d0e14de1 fix(catalog): inherit model facts across a provider's host move (#7096)
OpenCode Go's roster still lives at https://opencode.ai/zen/go/v1 while
models.dev now publishes its api as https://opencode.ai/inference/go/openai/v1.
complete_from required the lower row's published base to fingerprint-match
the live roster before copying anything, so the models.dev limit for
deepseek-v4.1-flash (context 1,000,000) was discarded and the window fell
back to LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS (128K).

A context window belongs to the model, not the host serving it. For a live
row completed from a model-describing layer (bundled, models.dev, cloud
facts, Codewhale corrections), the configured base must still match the
live roster, but the published-base match now gates only endpoint-scoped
facts: transport, provider_api, provider_npm, status and cost. Limits,
modalities, reasoning and the other model facts are inherited. Live-to-live
and override arms are unchanged; complete_facts_from (signed cloud patch)
still copies everything.

Not in this slice: moving the opencode-go descriptor to the inference/
host. The new docs split the chat base (/inference/go/openai/v1), the
Anthropic base (/inference/go/anthropic/v1) and the models base
(/inference/go/v1), which the single model-aware base_url cannot express;
zen/go/v1 still answers /models with 200 (checked 2026-10-26).

Verified:
- scripts/dev-test.sh config: 806 run, 806 passed, 1 skipped
- scripts/dev-test.sh tui provider_lake catalog context_window opencode:
  365 run, 365 passed
- Throwaway reproduction (not committed): live opencode-go row at zen/go/v1
  plus models.dev row with api inference/go/openai/v1 and limit 1M.
  Without fix: FAILED (context stays None). With fix: passed; context is
  1,000,000, provider_api and cost not inherited, and a mismatched
  configured base still returns false.
- cargo fmt -p codewhale-config --check clean

Fixes #7096

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 22:26:41 -07:00
+26 -12
View File
@@ -312,7 +312,7 @@ impl CatalogOffering {
.filter(|provider| *provider != crate::ProviderKind::Custom)
.map(|provider| provider.provider().default_base_url())
});
match (&self.source, &lower.source) {
let endpoint_facts = match (&self.source, &lower.source) {
(
CatalogSource::Live {
base_url_fingerprint: current,
@@ -323,7 +323,10 @@ impl CatalogOffering {
..
},
) if current == prior
&& base_url.is_none_or(|url| base_url_fingerprint(url) == *current) => {}
&& base_url.is_none_or(|url| base_url_fingerprint(url) == *current) =>
{
true
}
(
CatalogSource::Live {
base_url_fingerprint: current,
@@ -333,8 +336,9 @@ impl CatalogOffering {
| CatalogSource::ModelsDevLive { .. }
| CatalogSource::CloudFacts { .. }
| CatalogSource::CodewhaleBundled { .. },
) if published_base.is_some_and(|url| base_url_fingerprint(url) == *current)
&& base_url.is_none_or(|url| base_url_fingerprint(url) == *current) => {}
) if base_url.is_none_or(|url| base_url_fingerprint(url) == *current) => {
published_base.is_some_and(|url| base_url_fingerprint(url) == *current)
}
(
CatalogSource::ConfigOverride | CatalogSource::UserOverride,
CatalogSource::Bundled
@@ -345,13 +349,20 @@ impl CatalogOffering {
.zip(published_base)
.is_some_and(|(current, prior)| {
base_url_fingerprint(current) == base_url_fingerprint(prior)
}) => {}
}) =>
{
true
}
_ => return false,
}
self.complete_facts_from(lower)
};
self.complete_facts(lower, endpoint_facts)
}
pub(crate) fn complete_facts_from(&mut self, lower: &Self) -> bool {
self.complete_facts(lower, true)
}
fn complete_facts(&mut self, lower: &Self, endpoint_facts: bool) -> bool {
let mut changed = false;
macro_rules! fill {
($field:ident) => {
@@ -376,10 +387,12 @@ impl CatalogOffering {
fill!(temperature);
fill!(open_weights);
fill!(interleaved);
fill!(transport);
fill!(provider_api);
fill!(provider_npm);
fill!(status);
if endpoint_facts {
fill!(transport);
fill!(provider_api);
fill!(provider_npm);
fill!(status);
}
fill!(experimental);
fill!(license);
fill!(links);
@@ -407,7 +420,8 @@ impl CatalogOffering {
self.limit = Some(limit);
}
}
if self.cost.is_none()
if endpoint_facts
&& self.cost.is_none()
&& self.cost_source.is_none()
&& (lower.cost.is_some() || lower.cost_source.is_some())
{