diff options
Diffstat (limited to 'llamachat/providers.py')
| -rw-r--r-- | llamachat/providers.py | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/llamachat/providers.py b/llamachat/providers.py index 5874b32..0d2d9f7 100644 --- a/llamachat/providers.py +++ b/llamachat/providers.py @@ -76,6 +76,13 @@ def parse(values: dict) -> dict[str, Provider]: out: dict[str, Provider] = {} for name, entry in table.items(): entry = entry or {} + name = str(name) + if not name or ":" in name: + # The id scheme splits on the first colon, so a name containing + # one builds ids that split back to something else entirely, and + # an empty name builds ":model". Both route to local under a + # nonsense name, silently. Skipping is the only honest option. + continue base_url = str(entry.get("base_url") or "").rstrip("/") if not base_url: # ponytail: a provider with no URL is misconfigured, not a @@ -91,8 +98,8 @@ def parse(values: dict) -> dict[str, Provider]: if not isinstance(needles, (list, tuple)): needles = [needles] vision = entry.get("vision") - out[str(name)] = Provider( - name=str(name), + out[name] = Provider( + name=name, base_url=base_url, api_key=str(entry.get("api_key") or ""), filter=[str(f) for f in needles], @@ -117,6 +124,14 @@ def split(model_id: str, table: dict[str, Provider]) -> tuple[str, str]: A prefix that is not a configured provider is treated as part of the model name, which keeps a bare local model containing a colon working. """ + # ponytail: this is not injective, and cannot be while local ids stay + # bare. A local model actually named "together:x" is indistinguishable + # from together's model "x", so it resolves to local only until the user + # configures a provider called "together", at which point the stored + # session id rebinds to the cloud model and starts billing without a + # word. Unlikely, since local names are usually filenames, and the bare + # local id is the feature's premise. The upgrade path is to qualify local + # as "local:<model>" too and migrate the sessions.model column. prefix, sep, rest = model_id.partition(":") if sep and prefix in table and prefix != LOCAL: return prefix, rest @@ -129,8 +144,13 @@ def apply_filter(provider: Provider, listed: list[str]) -> list[str]: Case-insensitive, because provider ids capitalise inconsistently: "qwen" has to match "Qwen/Qwen2.5-72B-Instruct-Turbo". """ + # Every path returns a fresh list on purpose: callers hold onto the + # result, and handing back "listed" itself would let them mutate the + # caller's own list. Not a redundant copy, do not simplify it away. if provider.is_local or not provider.filter: return list(listed) + # An empty needle is a typo, not a request to hide every model, so a + # filter of only empty strings means no filter. needles = [f.lower() for f in provider.filter if f] if not needles: return list(listed) |
