Pull and serve model info automatically where possible #3

Open
opened 2026-10-26 18:41:02 +00:00 by bo · 3 comments

Problems.

  1. The info that LiteLLM serves about the available models through gateway.inference.coop/v1/models/ or /model_group/info/ is sometimes incomplete or incorrect (see appendix). For example: context length, capabilities.
  2. That info currently will need to be manually updated when upstream changes their options.

Proposal.

  1. Automatically pull full model info from upstreams that provide it over API (currently Tinfoil, Regolo)
  2. Maintain a manual file for other upstreams (currently GreenPT)
  3. Ensure all of this info is served from our own endpoint /v1/models and perhaps /model/info

Not changed. How pricing information is set.

--> Thoughts? If it sounds good, I'll start working on a PR for this.


Appendix

Warning: LLM-researched and generated.

1) Missing from LiteLLM discovery

# Missing Where it is absent Effect on OMP
1 Prompt/context and output caps max_input_tokens, max_output_tokens are null on 11/11 groups in both /model_group/info and /v2/model/info Limits are substituted locally: bundled-reference rows supply 1M for the GreenPT/Tinfoil DeepSeek and GLM rows, 131K for gpt-oss-120b; both Regolo rows fall to the generic 128K context / 32K output defaults (apertus-70b actually serves 65K, qwen3.5-122b 262K)
2 Reasoning effort ladder supported_reasoning_efforts: null on 11/11 The real ladders differ and are only discoverable by brute force: DeepSeek minimal…xhigh; glm-5.3 minimal…high (xhigh → 400); gpt-oss-120b low…high (minimal → 400); apertus-70b accepts every value including xhigh. off → 400 everywhere, so thinking cannot be disabled on any group
3 Task-mode classification mode: null on 6/11 groups — every GreenPT and Tinfoil chat row OMP's mode filter can only classify the 5 rows that carry mode (chat, image_generation, audio_transcription, audio_speech); the remaining 6 are assumed to be chat (correct today, unverified by the proxy)
4 One model entirely tinfoil/nomic-embed-text (mode embedding) appears only in /v2/model/info — 12 rows there vs 11 in /model_group/info and /v1/models Because the first usable roster wins, the embedding model is undiscoverable regardless of OMP configuration
5 Display names No name / display_name field on any surface; ids only OMP synthesizes names ("DeepSeek V4.1 Flash"); human/marketing names and multi-word aliases are lost
6 Real upstream attribution providers: ["openai"] on every group; owned_by: "openai" on every /v1/models row. The true hosts (api.greenpt.ai, 127.0.0.1:3301, api.regolo.ai) exist only in /v2/model/info → litellm_params.api_base, on the surface OMP never reaches OMP reads providers to choose the wire and therefore assigns openai-responses to all 8 discovered chat rows. It works, but the field describes the LiteLLM adapter, not the backend
7 Quotas and health tpm, rpm, itpm, otpm, health_status, health_response_time, health_checked_at are null on 11/11 No rate-limit awareness, no health signal in listings
8 Tiered / batch / peak pricing Every *_above_*k_tokens, *_flex, *_priority, *_batches cost field is null Only flat per-token prices are representable; a long-context tier or off-peak tariff would be invisible
9 Cache-write price cache_creation_input_token_cost is null on 11/11; only cache_read_input_token_cost is populated OMP's cacheWrite estimate is 0 for every model
10 Audio and image specifics No voice list (valid speakers — ar_male, casual_female, casual_male, cheerful_female, de_female, …, neutral_male — surface only inside a 400 body), no output-format list, no pixel or duration caps. TTS cost is entirely null (tinfoil/voxtral-tts: both input and output null); the image row carries a per-pixel price (1.5e-08) that OMP's cost model cannot express TTS is priced at $0, image generation is priced at $0, and the speech role has no way to select a valid voice
11 Identity and tokenizer No canonical id, alias, or tokenizer field. The same weights appear as deepseek-v4.1-flash (GreenPT) and deepseek-v4-1-flash (Tinfoil) Reference-metadata matching and token accounting are guesswork

2) Wrong in LiteLLM discovery

Capability flags as reported (false for all four, all models) versus what the endpoint does.
Probe: a 64×64 red PNG for vision, a get_weather function for tool calling, a two-city request
with parallel_tool_calls: true, and a plain 17*23 prompt with no reasoning_effort
parameter for reasoning.

model function calling vision reasoning parallel FC
greenpt/deepseek-v4.1-flash false → tool_calls returned false → answers "Red" false → reasoning_content present false → 2 calls
tinfoil/deepseek-v4-1-flash false → tool_calls returned false → answers "Red" false → reasoning_content present false → 2 calls
greenpt/glm-5.3 false → tool_calls returned false → 200, but "I don't see an image attached" false → reasoning_content present false → **2
calls**
tinfoil/glm-5.3 false → tool_calls returned false → 400 "not a multimodal model" (correct) false → reasoning_content present false → **2
calls**
greenpt/glm-5.3-flash false → tool_calls returned false → answers "Red" false → reasoning_content present false → 2 calls
tinfoil/gpt-oss-120b false → tool_calls returned false → 200, but "I can't view images" false → reasoning_content present false → 1 call
(inconclusive)
regolo/qwen3.5-122b false → tool_calls returned false → answers "Red" false → none (correct) not probed
regolo/apertus-70b false → tool_calls returned false → answers "Red" false → none (correct) not probed
  1. supports_function_calling: false on 11/11 — wrong for at least 8. Every chat model returns
    a valid tool_calls payload. OMP's tool use works only because it advertises tools regardless;
    the metadata asserts the opposite.
  2. supports_parallel_function_calling: false on 11/11 — wrong for 5 of 5 measured. One request
    asking for Paris and Tokyo returned two tool_calls on both DeepSeek rows, both glm-5.3 rows,
    and glm-5.3-flash.
  3. supports_vision: false on 11/11 — wrong for 5 of 8 chat models.
    greenpt/deepseek-v4.1-flash, tinfoil/deepseek-v4-1-flash, greenpt/glm-5.3-flash,
    regolo/qwen3.5-122b and regolo/apertus-70b all identify the red square. The flag is correct
    only for tinfoil/glm-5.3 (hard 400). greenpt/glm-5.3 is effectively text-only (200, image
    dropped). Note: the cooperative's own published note lists greenpt/glm-5.3-flash as
    vision: false; that is also wrong.
  4. supports_reasoning: false on 11/11 — wrong for 6 of 8. With no reasoning_effort supplied,
    both DeepSeek rows, both glm-5.3 rows, glm-5.3-flash and gpt-oss-120b all return non-empty
    reasoning_content, i.e. thinking is on by default. Only the two Regolo rows are genuinely
    non-thinking.
  5. supported_openai_params is byte-identical across all 11 groups. The same 32-entry chat list
    (tools, tool_choice, logprobs, audio, prediction, service_tier,
    prompt_cache_retention, …) is attached to tinfoil/voxtral-tts,
    tinfoil/whisper-large-v3-turbo and regolo/qwen-image, which are not chat endpoints. On four
    chat models the list holds up under spot checks (n=2, logprobs, store all accepted), so the
    defect is structural rather than per-model.
  6. /v1/models is false on two fields for every row. created: 1677610602 (2023-02-28) for all
    11 models, and owned_by: "openai" for all 11 — Tinfoil, GreenPT and Regolo models are reported
    as OpenAI's. Every OpenAI-SDK consumer and OMP's generic openai-models-list path inherits both.
  7. Two groups accept images and silently drop them. greenpt/glm-5.3 ("I don't see an image
    attached") and tinfoil/gpt-oss-120b ("I can't view images") return 200 with the image discarded.
    Capability probing by HTTP status therefore yields false positives; only checking the answer text
    reveals it. (Proxy behaviour, not a discovery field — but it defeats discovery-by-probe.)
**Problems.** 1. The info that LiteLLM serves about the available models through `gateway.inference.coop/v1/models/` or `/model_group/info/` is sometimes incomplete or incorrect (see appendix). For example: context length, capabilities. 2. That info currently will need to be manually updated when upstream changes their options. **Proposal.** 1. Automatically pull full model info from upstreams that provide it over API (currently Tinfoil, Regolo) 2. Maintain a manual file for other upstreams (currently GreenPT) 3. Ensure all of this info is served from our own endpoint /v1/models and perhaps /model/info *Not changed.* How pricing information is set. --> Thoughts? If it sounds good, I'll start working on a PR for this. ---- # Appendix Warning: LLM-researched and generated. ## 1) Missing from LiteLLM discovery | # | Missing | Where it is absent | Effect on OMP | |---|---------|--------------------|---------------| | 1 | Prompt/context and output caps | `max_input_tokens`, `max_output_tokens` are `null` on **11/11** groups in both `/model_group/info` and `/v2/model/info` | Limits are substituted locally: bundled-reference rows supply 1M for the GreenPT/Tinfoil DeepSeek and GLM rows, 131K for `gpt-oss-120b`; both Regolo rows fall to the generic 128K context / 32K output defaults (`apertus-70b` actually serves 65K, `qwen3.5-122b` 262K) | | 2 | Reasoning effort ladder | `supported_reasoning_efforts: null` on 11/11 | The real ladders differ and are only discoverable by brute force: DeepSeek `minimal…xhigh`; `glm-5.3` `minimal…high` (`xhigh` → 400); `gpt-oss-120b` `low…high` (`minimal` → 400); `apertus-70b` accepts every value including `xhigh`. `off` → 400 everywhere, so thinking cannot be disabled on any group | | 3 | Task-mode classification | `mode: null` on **6/11** groups — every GreenPT and Tinfoil chat row | OMP's mode filter can only classify the 5 rows that carry `mode` (`chat`, `image_generation`, `audio_transcription`, `audio_speech`); the remaining 6 are assumed to be chat (correct today, unverified by the proxy) | | 4 | One model entirely | `tinfoil/nomic-embed-text` (mode `embedding`) appears **only** in `/v2/model/info` — 12 rows there vs 11 in `/model_group/info` and `/v1/models` | Because the first usable roster wins, the embedding model is undiscoverable regardless of OMP configuration | | 5 | Display names | No `name` / `display_name` field on any surface; ids only | OMP synthesizes names ("DeepSeek V4.1 Flash"); human/marketing names and multi-word aliases are lost | | 6 | Real upstream attribution | `providers: ["openai"]` on every group; `owned_by: "openai"` on every `/v1/models` row. The true hosts (`api.greenpt.ai`, `127.0.0.1:3301`, `api.regolo.ai`) exist only in `/v2/model/info` → `litellm_params.api_base`, on the surface OMP never reaches | OMP reads `providers` to choose the wire and therefore assigns `openai-responses` to all 8 discovered chat rows. It works, but the field describes the LiteLLM adapter, not the backend | | 7 | Quotas and health | `tpm`, `rpm`, `itpm`, `otpm`, `health_status`, `health_response_time`, `health_checked_at` are `null` on 11/11 | No rate-limit awareness, no health signal in listings | | 8 | Tiered / batch / peak pricing | Every `*_above_*k_tokens`, `*_flex`, `*_priority`, `*_batches` cost field is `null` | Only flat per-token prices are representable; a long-context tier or off-peak tariff would be invisible | | 9 | Cache-write price | `cache_creation_input_token_cost` is `null` on 11/11; only `cache_read_input_token_cost` is populated | OMP's `cacheWrite` estimate is 0 for every model | | 10 | Audio and image specifics | No voice list (valid speakers — `ar_male`, `casual_female`, `casual_male`, `cheerful_female`, `de_female`, …, `neutral_male` — surface only inside a 400 body), no output-format list, no pixel or duration caps. TTS cost is entirely `null` (`tinfoil/voxtral-tts`: both input and output null); the image row carries a per-pixel price (`1.5e-08`) that OMP's cost model cannot express | TTS is priced at $0, image generation is priced at $0, and the `speech` role has no way to select a valid voice | | 11 | Identity and tokenizer | No canonical id, alias, or tokenizer field. The same weights appear as `deepseek-v4.1-flash` (GreenPT) and `deepseek-v4-1-flash` (Tinfoil) | Reference-metadata matching and token accounting are guesswork | --- ## 2) Wrong in LiteLLM discovery Capability flags as reported (`false` for all four, all models) versus what the endpoint does. Probe: a 64×64 red PNG for vision, a `get_weather` function for tool calling, a two-city request with `parallel_tool_calls: true`, and a plain `17*23` prompt with **no** `reasoning_effort` parameter for reasoning. | model | function calling | vision | reasoning | parallel FC | |---|---|---|---|---| | `greenpt/deepseek-v4.1-flash` | false → **tool_calls returned** | false → **answers "Red"** | false → **`reasoning_content` present** | false → **2 calls** | | `tinfoil/deepseek-v4-1-flash` | false → **tool_calls returned** | false → **answers "Red"** | false → **`reasoning_content` present** | false → **2 calls** | | `greenpt/glm-5.3` | false → **tool_calls returned** | false → 200, but "I don't see an image attached" | false → **`reasoning_content` present** | false → **2 calls** | | `tinfoil/glm-5.3` | false → **tool_calls returned** | false → 400 "not a multimodal model" (correct) | false → **`reasoning_content` present** | false → **2 calls** | | `greenpt/glm-5.3-flash` | false → **tool_calls returned** | false → **answers "Red"** | false → **`reasoning_content` present** | false → **2 calls** | | `tinfoil/gpt-oss-120b` | false → **tool_calls returned** | false → 200, but "I can't view images" | false → **`reasoning_content` present** | false → 1 call (inconclusive) | | `regolo/qwen3.5-122b` | false → **tool_calls returned** | false → **answers "Red"** | false → none (correct) | not probed | | `regolo/apertus-70b` | false → **tool_calls returned** | false → **answers "Red"** | false → none (correct) | not probed | 1. **`supports_function_calling: false` on 11/11 — wrong for at least 8.** Every chat model returns a valid `tool_calls` payload. OMP's tool use works only because it advertises tools regardless; the metadata asserts the opposite. 2. **`supports_parallel_function_calling: false` on 11/11 — wrong for 5 of 5 measured.** One request asking for Paris and Tokyo returned two `tool_calls` on both DeepSeek rows, both `glm-5.3` rows, and `glm-5.3-flash`. 3. **`supports_vision: false` on 11/11 — wrong for 5 of 8 chat models.** `greenpt/deepseek-v4.1-flash`, `tinfoil/deepseek-v4-1-flash`, `greenpt/glm-5.3-flash`, `regolo/qwen3.5-122b` and `regolo/apertus-70b` all identify the red square. The flag is correct only for `tinfoil/glm-5.3` (hard 400). `greenpt/glm-5.3` is effectively text-only (200, image dropped). Note: the cooperative's own published note lists `greenpt/glm-5.3-flash` as `vision: false`; that is also wrong. 4. **`supports_reasoning: false` on 11/11 — wrong for 6 of 8.** With no `reasoning_effort` supplied, both DeepSeek rows, both `glm-5.3` rows, `glm-5.3-flash` and `gpt-oss-120b` all return non-empty `reasoning_content`, i.e. thinking is on by default. Only the two Regolo rows are genuinely non-thinking. 5. **`supported_openai_params` is byte-identical across all 11 groups.** The same 32-entry chat list (`tools`, `tool_choice`, `logprobs`, `audio`, `prediction`, `service_tier`, `prompt_cache_retention`, …) is attached to `tinfoil/voxtral-tts`, `tinfoil/whisper-large-v3-turbo` and `regolo/qwen-image`, which are not chat endpoints. On four chat models the list holds up under spot checks (`n=2`, `logprobs`, `store` all accepted), so the defect is structural rather than per-model. 6. **`/v1/models` is false on two fields for every row.** `created: 1677610602` (2023-02-28) for all 11 models, and `owned_by: "openai"` for all 11 — Tinfoil, GreenPT and Regolo models are reported as OpenAI's. Every OpenAI-SDK consumer and OMP's generic `openai-models-list` path inherits both. 7. **Two groups accept images and silently drop them.** `greenpt/glm-5.3` ("I don't see an image attached") and `tinfoil/gpt-oss-120b` ("I can't view images") return 200 with the image discarded. Capability probing by HTTP status therefore yields false positives; only checking the answer text reveals it. (Proxy behaviour, not a discovery field — but it defeats discovery-by-probe.)
Owner

Thanks Bo — I reproduced all of it against the live gateway just now, and I think the diagnosis points somewhere a bit different than the proposal does. Numbers from gateway.inference.coop (LiteLLM 1.103.2, admin key, 2026-10-26):

  • /v1/models: 11 rows, owned_by: "openai" and created: 1677610602 on every one.
  • /model_group/info: max_input_tokens, max_output_tokens, supported_reasoning_efforts, display_name null on 11/11; supports_function_calling, supports_vision, supports_reasoning false on 11/11; mode null on 6/11 (present: chat x2, image_generation, audio_transcription, audio_speech).
  • /v2/model/info: 12 rows against 11 elsewhere.

Root cause: our config declares only pricing

Every entry in this repo's config.yaml has a model_info: block, and those blocks contain input_cost_per_token, output_cost_per_token, cache_read_input_token_cost and, on the image row, input_cost_per_pixel — pricing and nothing else. mode appears on five entries only.

LiteLLM serves what it is told. With no max_input_tokens, no mode, no supports_*, and no registry entry for custom vendor names like greenpt/deepseek-v4.1-flash, nulls and false are the honest answer. So the missing fields in section 1 — and much of section 2 — are a declaration gap in our own config, closable now without any upstream integration. The auto-pull you propose is the right hygiene for keeping the values fresh afterwards; it isn't the fix for what is absent today.

Three cautions before the PR

  1. No generator may touch pricing. Cost keys live in the same model_info block as the discovery fields. LiteLLM computes member spend, allowance consumption and budget caps from them, so a generated file that rewrites model_info wholesale would silently reprice every model and drift every member's budget. Keep the generator strictly additive — discovery fields only, never a cost key — and add a test asserting the pricing keys are unchanged before/after generation. That test is the thing that makes this safe to automate.
  2. Upstream APIs cannot supply what you measured. Tools, vision, reasoning and the effort ladders came from your probes, not vendor metadata — and status codes lie: greenpt/glm-5.3 and tinfoil/gpt-oss-120b return 200 with the image quietly discarded. So the shape is auto-pull for what upstreams publish plus a maintained empirical layer for capabilities. That is a larger manual surface than "GreenPT only" implies — worth deciding deliberately rather than discovering halfway.
  3. Shipping it means a gateway restart. This repo's config.yaml mirrors the live deployment, so a new field is only served after the app restarts. That's a member-facing inference blip: batch it, don't slip it in.

Two notes

  • Section 2 corroborates an earlier investigation of ours (co-op/docs#8): supports_function_calling: false is served while tool calls return normally — 6/6 modes pass on greenpt/glm-5.3-flash, with the call arriving in tool_calls and an empty content.
  • The published models note claims greenpt/glm-5.3-flash is vision: false; your probe contradicts it. I'll correct the docs either way.

Suggested split

  1. Declare the missing fields in config.yaml now — unblocks the client, no automation, and the pricing invariant is untouched by construction.
  2. Then the pull/generate step as a follow-up, with the pricing guard and the empirical capability layer.

Happy to review the PR when it lands, and I'll keep an eye on this thread.

Thanks Bo — I reproduced all of it against the live gateway just now, and I think the diagnosis points somewhere a bit different than the proposal does. Numbers from `gateway.inference.coop` (LiteLLM 1.103.2, admin key, 2026-10-26): - `/v1/models`: 11 rows, `owned_by: "openai"` and `created: 1677610602` on every one. - `/model_group/info`: `max_input_tokens`, `max_output_tokens`, `supported_reasoning_efforts`, `display_name` null on **11/11**; `supports_function_calling`, `supports_vision`, `supports_reasoning` **false on 11/11**; `mode` null on **6/11** (present: chat x2, image_generation, audio_transcription, audio_speech). - `/v2/model/info`: 12 rows against 11 elsewhere. ## Root cause: our config declares only pricing Every entry in this repo's `config.yaml` has a `model_info:` block, and those blocks contain `input_cost_per_token`, `output_cost_per_token`, `cache_read_input_token_cost` and, on the image row, `input_cost_per_pixel` — pricing and nothing else. `mode` appears on five entries only. LiteLLM serves what it is told. With no `max_input_tokens`, no `mode`, no `supports_*`, and no registry entry for custom vendor names like `greenpt/deepseek-v4.1-flash`, nulls and `false` are the honest answer. So the missing fields in section 1 — and much of section 2 — are a **declaration gap in our own config**, closable now without any upstream integration. The auto-pull you propose is the right *hygiene* for keeping the values fresh afterwards; it isn't the fix for what is absent today. ## Three cautions before the PR 1. **No generator may touch pricing.** Cost keys live in the same `model_info` block as the discovery fields. LiteLLM computes member spend, allowance consumption and budget caps from them, so a generated file that rewrites `model_info` wholesale would silently reprice every model and drift every member's budget. Keep the generator strictly additive — discovery fields only, never a cost key — and add a test asserting the pricing keys are unchanged before/after generation. That test is the thing that makes this safe to automate. 2. **Upstream APIs cannot supply what you measured.** Tools, vision, reasoning and the effort ladders came from your probes, not vendor metadata — and status codes lie: `greenpt/glm-5.3` and `tinfoil/gpt-oss-120b` return 200 with the image quietly discarded. So the shape is auto-pull for what upstreams publish *plus* a maintained empirical layer for capabilities. That is a larger manual surface than "GreenPT only" implies — worth deciding deliberately rather than discovering halfway. 3. **Shipping it means a gateway restart.** This repo's `config.yaml` mirrors the live deployment, so a new field is only served after the app restarts. That's a member-facing inference blip: batch it, don't slip it in. ## Two notes - Section 2 corroborates an earlier investigation of ours (co-op/docs#8): `supports_function_calling: false` is served while tool calls return normally — 6/6 modes pass on `greenpt/glm-5.3-flash`, with the call arriving in `tool_calls` and an empty `content`. - The published models note claims `greenpt/glm-5.3-flash` is `vision: false`; your probe contradicts it. I'll correct the docs either way. ## Suggested split 1. Declare the missing fields in `config.yaml` now — unblocks the client, no automation, and the pricing invariant is untouched by construction. 2. Then the pull/generate step as a follow-up, with the pricing guard and the empirical capability layer. Happy to review the PR when it lands, and I'll keep an eye on this thread.
Author

We could declare the missing fields now, but it's a one-time fix. We'd need to manually update config.yaml any time an upstream provider changes what models they offer or we add a new provider.

We could declare the missing fields now, but it's a one-time fix. We'd need to manually update config.yaml any time an upstream provider changes what models they offer or we add a new provider.
Owner

Checking in on this, since Bo asked whether it is ready to go.

Where it stands — measured against the live gateway just now, via /model_group/info (11 entries):

  • max_input_tokens null: 11/11
  • max_output_tokens null: 11/11
  • mode null: 6/11
  • supports_function_calling true: 0/11
  • supports_vision true: 0/11

So nothing has changed since the measurements above: the fields are still simply absent, which is why clients substitute their own numbers for us rather than reading ours.

On the proposal — the shape is right, and the split you suggest is the correct one: pull from upstreams that expose it (Tinfoil, Regolo), keep a manual file for GreenPT. Two things I can hand over so you do not have to rediscover them:

  1. Read Tinfoil the way our traffic does. Our model-info watcher authenticates to Tinfoil through the in-TEE proxy inside the gateway container, not a side door. If the sync reads Tinfoil directly, it can report a model list that does not match what we actually serve.

  2. Key the GreenPT file on model_group, not model. Our spend logs carry the upstream name (openai/deepseek-v4.1-flash) while everything member-facing is keyed on our alias (greenpt/deepseek-v4.1-flash). Matching on the wrong one fails silently — it just matches nothing. I lost an afternoon to exactly that mistake in a different script.

Bar for "done", in my view: every served group reports real caps and capabilities, and a re-run after an upstream change needs no hand editing. Pricing stays as-is, per your "not changed".

I am not taking this from you — it is your proposal and your PR. But when it lands I will extend the existing watcher to verify it: assert every served group has non-null caps, and alert when one goes null again. That is the part that keeps it fixed, and it is squarely mine.

Checking in on this, since Bo asked whether it is ready to go. **Where it stands** — measured against the live gateway just now, via `/model_group/info` (11 entries): - `max_input_tokens` null: **11/11** - `max_output_tokens` null: **11/11** - `mode` null: **6/11** - `supports_function_calling` true: **0/11** - `supports_vision` true: **0/11** So nothing has changed since the measurements above: the fields are still simply absent, which is why clients substitute their own numbers for us rather than reading ours. **On the proposal** — the shape is right, and the split you suggest is the correct one: pull from upstreams that expose it (Tinfoil, Regolo), keep a manual file for GreenPT. Two things I can hand over so you do not have to rediscover them: 1. **Read Tinfoil the way our traffic does.** Our model-info watcher authenticates to Tinfoil through the in-TEE proxy inside the gateway container, not a side door. If the sync reads Tinfoil directly, it can report a model list that does not match what we actually serve. 2. **Key the GreenPT file on `model_group`, not `model`.** Our spend logs carry the upstream name (`openai/deepseek-v4.1-flash`) while everything member-facing is keyed on our alias (`greenpt/deepseek-v4.1-flash`). Matching on the wrong one fails *silently* — it just matches nothing. I lost an afternoon to exactly that mistake in a different script. **Bar for "done", in my view:** every served group reports real caps and capabilities, and a re-run after an upstream change needs no hand editing. Pricing stays as-is, per your "not changed". I am not taking this from you — it is your proposal and your PR. But when it lands I will extend the existing watcher to *verify* it: assert every served group has non-null caps, and alert when one goes null again. That is the part that keeps it fixed, and it is squarely mine.
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: code/litellm#3