Skip to content

feat: add TelecomJS provider support with configuration and catalog i…#4370

Open
baendlorel wants to merge 2 commits into
Hmbown:mainfrom
baendlorel:feat/provider-telecomjs
Open

feat: add TelecomJS provider support with configuration and catalog i…#4370
baendlorel wants to merge 2 commits into
Hmbown:mainfrom
baendlorel:feat/provider-telecomjs

Conversation

@baendlorel

Copy link
Copy Markdown

Problem

After registering the TelecomJS (Telecom JiangSu) in the custom provider, the model picker only shows 1 model (deepseek-v4-pro) instead of all models returned by the /v1/models endpoint.

Root Cause

refresh_catalog_cache/fetch_catalog_delta is never invoked in production — it only exists in test code. At startup, only the Models.dev catalog is refreshed, which has no entries for telecomjs. The picker therefore falls back to model_completion_names_for_provider(Telecomjs), which returns only the default model.

Fix

  1. provider_lake.rs — Add merge_live_offerings() that merges new offerings into the existing live snapshot by (provider, wire_model_id) identity rather than replacing it. This allows Models.dev rows and per-provider rows to coexist.

  2. client.rs — Add spawn_active_provider_catalog_refresh() associated function. When the active provider is Telecomjs, it spawns a background task that calls fetch_catalog_delta() (which already inherits metadata from the bundled catalog via case-insensitive matching) and merges all 52 models into the provider lake.

  3. main.rs — Call the new function at startup, after the existing models_dev_live::spawn_background_refresh().

  4. config.rs — Expand the model_completion_names_for_provider(Telecomjs) fallback list from 1 to 11 models, so the picker shows useful options even before the background refresh completes.

Testing

  • cargo check --workspace — pass
  • cargo test -p codewhale-config — 360 tests passed
  • cargo test -p codewhale-tui (provider_lake + client catalog) — 14 tests passed
  • cargo build --release — success

Final Result

codewhale增加江苏tokenhub

@baendlorel
baendlorel requested a review from Hmbown as a code owner July 15, 2026 03:05
@github-actions

Copy link
Copy Markdown
Contributor

Thanks @baendlorel for taking the time to contribute.

This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant recurring PR access by commenting /lgtm on a pull request.

@Hmbown Hmbown added this to the v0.9.1 milestone Jul 16, 2026 — with ChatGPT Codex Connector
@Hmbown Hmbown added v0.9.1 Targeting v0.9.1 enhancement New feature or request model-lab Model Lab open-model discovery, evaluation, routing, and export workflows reliability Reliability, flaky behavior, retries, fallbacks, and robustness labels Jul 16, 2026 — with ChatGPT Codex Connector
@Hmbown

Hmbown commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Thanks @baendlorel—this is a real v0.9.1 gap, and the PR is now in the v0.9.1 queue. Current main already supports TokenHub as an OpenAI-compatible custom route, but it does not make the provider's live /v1/models inventory available in the picker, so the problem you traced is valid.

I reviewed the current patch against main at 07b6422d. Before it is merge-ready, please rebase and address these two correctness boundaries:

  1. provider_lake still has a single replaceable live snapshot. spawn_background_refresh() and the new provider refresh race: if the TelecomJS merge completes first, a later Models.dev set_live_snapshot() erases those rows. Please make live data source-scoped or otherwise prove both completion orders preserve both sets; add deterministic tests for Models.dev→TelecomJS and TelecomJS→Models.dev.
  2. Matching the first bundled row solely by case-insensitive wire_model_id can copy capabilities and cost from an unrelated provider/version. Preserve unknown metadata unless there is an explicit canonical mapping, and test ambiguous IDs. A gateway exposing DeepSeek-R1 does not by itself prove identical limits, prices, reasoning controls, or tool support.

Please also:

  • amend the commit with a Signed-off-by trailer and force-push with lease;
  • rerun the current full CI after rebasing;
  • add a failure/race regression showing a catalog refresh never deletes previously published rows;
  • verify the reasoning request fields against actual TelecomJS behavior rather than assuming every gateway model accepts the same reasoning_effort plus thinking combination.

The provider wiring and production refresh direction are worth preserving. If you no longer have time to refresh the branch, say so here and we can harvest the commit onto current main while retaining your authorship and credit.

@Hmbown

Hmbown commented Jul 17, 2026

Copy link
Copy Markdown
Owner

The TelecomJS live-model gap is still real, but this branch is not safe to merge as written. It races the single replaceable live snapshot, so a later Models.dev refresh can erase TelecomJS rows; it also borrows metadata from the first case-insensitive model-ID match across unrelated providers. Please rebuild on current main with source-scoped snapshots, both refresh-order tests, conservative unknown metadata, actual TelecomJS request-shape proof, DCO, and current CI. Contributor credit will be preserved if harvested.

@Hmbown

Hmbown commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Thanks for digging into this — your root-cause analysis is confirmed correct: fetch_catalog_delta/refresh_catalog_cache (crates/tui/src/client.rs:1464, :1559) have no production call sites, so custom providers never load their live catalogs. That underlying defect is now tracked separately as #4462 with credit to you.

This PR can't merge in its current form, and we're retargeting it out of v0.9.1 to v0.9.2, for four concrete reasons:

  1. Single global snapshot. merge_live_offerings() merges into the one global LIVE_SNAPSHOT (crates/tui/src/provider_lake.rs:28). Once production actually calls per-provider refresh, Models.dev and provider-specific refreshes can overwrite each other's rows. The fix needs source-layered catalog state (Models.dev layer + scoped per-provider layers, merged at read time by (provider, wire_model_id)) — specified in Custom provider live catalog is never refreshed in production (scoped catalog state rewrite) #4462.
  2. Fabricated metadata. The PR copies price/capability facts from a home provider onto TelecomJS models whose IDs match. TelecomJS never supplied those facts; provider capability must stay route-effective and truthful. Custom-provider rows must carry only what that provider's own /v1/models returned, with unknown fields left unknown.
  3. Base URL and stale-catalog scope need review against the same contract.
  4. Authorship/DCO. The commit author email does not line up with a DCO sign-off we can accept as-is; please add a Signed-off-by trailer matching your GitHub identity (see CONTRIBUTING / the Check Signed-off-by CI job).

Path forward: the catalog-state rewrite lands via #4462 first; then this PR can be rebased down to just the TelecomJS provider preset (endpoints, default models, honest unknown metadata) on top of it. If you'd like to take the preset slice after #4462 lands, it's yours — say so and we'll assign it to you.

@Hmbown Hmbown modified the milestones: v0.9.1, v0.9.2 Jul 17, 2026
@Hmbown Hmbown added v0.9.2 Targeting v0.9.2 and removed v0.9.1 Targeting v0.9.1 labels Jul 18, 2026
@Hmbown Hmbown mentioned this pull request Jul 18, 2026
1 task
@baendlorel

baendlorel commented Jul 21, 2026

Copy link
Copy Markdown
Author

Thanks for digging into this — your root-cause analysis is confirmed correct: fetch_catalog_delta/refresh_catalog_cache (crates/tui/src/client.rs:1464, :1559) have no production call sites, so custom providers never load their live catalogs. That underlying defect is now tracked separately as #4462 with credit to you.

This PR can't merge in its current form, and we're retargeting it out of v0.9.1 to v0.9.2, for four concrete reasons:

1. **Single global snapshot.** `merge_live_offerings()` merges into the one global `LIVE_SNAPSHOT` (`crates/tui/src/provider_lake.rs:28`). Once production actually calls per-provider refresh, Models.dev and provider-specific refreshes can overwrite each other's rows. The fix needs source-layered catalog state (Models.dev layer + scoped per-provider layers, merged at read time by `(provider, wire_model_id)`) — specified in [Custom provider live catalog is never refreshed in production (scoped catalog state rewrite) #4462](https://github.com/Hmbown/CodeWhale/issues/4462).

2. **Fabricated metadata.** The PR copies price/capability facts from a home provider onto TelecomJS models whose IDs match. TelecomJS never supplied those facts; provider capability must stay route-effective and truthful. Custom-provider rows must carry only what that provider's own `/v1/models` returned, with unknown fields left unknown.

3. **Base URL and stale-catalog scope** need review against the same contract.

4. **Authorship/DCO.** The commit author email does not line up with a DCO sign-off we can accept as-is; please add a `Signed-off-by` trailer matching your GitHub identity (see CONTRIBUTING / the `Check Signed-off-by` CI job).

Path forward: the catalog-state rewrite lands via #4462 first; then this PR can be rebased down to just the TelecomJS provider preset (endpoints, default models, honest unknown metadata) on top of it. If you'd like to take the preset slice after #4462 lands, it's yours — say so and we'll assign it to you.
Thanks for the detailed feedback and for tracking the underlying defect in #4462.

I've worked through the changes requested in your first review and pushed them to this branch (commit 85f674c). Summary:

Source-scoped live snapshots: provider_lake.rs now partitions the live snapshot by source (ModelsDev and per_provider), so a later Models.dev refresh no longer overwrites TelecomJS rows. Added deterministic tests for both completion orders (Models.dev→TelecomJS and TelecomJS→Models.dev).
Conservative cross-provider metadata: fetch_catalog_delta now only inherits family (a name-derived safe field) for cross-provider wire_model_id matches; all other unknown fields stay None instead of being copied from an unrelated provider. Added tests for ambiguous and same-provider matches.
Catalog refresh regression: added a test verifying a catalog refresh never deletes previously published rows.
Reasoning fields: verified against the TelecomJS API docs — /v1/chat/completions does not accept reasoning_effort or thinking (the latter is Anthropic Messages-only). TelecomJS is now excluded from apply_reasoning_effort.
DCO: commit includes Signed-off-by.
Rebased onto 07b6422 and force-pushed with lease. GitGuardian check has passed.
Hope these changes help. Happy to rebase further into a preset-only slice once #4462 lands — just let me know.

…ire_model_id metadata + remove TelecomJS reasoning injection

- Partition LIVE_SNAPSHOT into Models.dev and per-provider partitions to
  prevent Models.dev refresh from clobbering TelecomJS rows (fix Hmbown#1).
- Two-tier wire_model_id matching: same-provider inherits full metadata,
  cross-provider inherits only family name derivation (fix Hmbown#2).
- Remove TelecomJS from apply_reasoning_effort branches; TokenHub API
  does not support reasoning_effort or thinking fields (fix Hmbown#6).
- Add tests: both completion orders, ambiguous wire_model_id, catalog
  refresh non-deletion, TelecomJS reasoning non-injection.

Signed-off-by: aldia_mechdream <futami16237@gmail.com>
@baendlorel
baendlorel force-pushed the feat/provider-telecomjs branch from bfa5d41 to 85f674c Compare July 21, 2026 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request model-lab Model Lab open-model discovery, evaluation, routing, and export workflows reliability Reliability, flaky behavior, retries, fallbacks, and robustness v0.9.2 Targeting v0.9.2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants