1515]#
1616
1717import std/ [algorithm, hashes, json, os, sequtils, strutils]
18- import types, util
18+ import types, util, modelname
1919
2020# this is expected to be overridden by a more useful value in config.nims
2121const Version * {.strdefine .} = " devel"
@@ -2706,6 +2706,14 @@ input:
27062706 @path inline file contents (e.g. @src/foo.nim)
27072707"""
27082708
2709+ func matchesKnownGoodModel * (comboModel, model: string ): bool =
2710+ # # Exact match on the raw wire id, or match on the normalized pretty
2711+ # # form. The wire id ("zai-org/GLM-5.1") stays the ground truth for
2712+ # # cases the normalizer can't see; the normalized form is what
2713+ # # config files and `Profile.model` carry now.
2714+ let m = model.toLowerAscii
2715+ comboModel.toLowerAscii == m or normalizeModelName (comboModel) == m
2716+
27092717proc canonicalKnownGoodProvider * (provider: string ): string =
27102718 # # Map config provider names onto the KnownGoodCombos provider key.
27112719 # # `supergrok` is the SuperGrok/OAuth twin of first-party `xai` (same
@@ -2724,25 +2732,23 @@ proc knownGoodFamily*(p: Profile): string =
27242732 let dot = p.name.find ('.' )
27252733 if dot < 0 : return " "
27262734 let provider = canonicalKnownGoodProvider (p.name[0 ..< dot])
2727- let model = p.model.toLowerAscii
27282735 for combo in KnownGoodCombos :
27292736 if combo.provider.toLowerAscii == provider and
2730- combo.model.toLowerAscii == model: return combo.family
2737+ matchesKnownGoodModel ( combo.model, p. model) : return combo.family
27312738 " "
27322739
27332740proc isKnownGood * (p: Profile ): bool =
2734- # # True when (provider name, `modelPrefix & model`) exactly matches
2735- # # an entry in `KnownGoodCombos` (case-insensitive on both parts) .
2741+ # # True when (provider name, model) matches an entry in
2742+ # # `KnownGoodCombos` — by exact wire id or by normalized pretty name .
27362743 # # Empty profiles return false — caller decides what that means.
27372744 knownGoodFamily (p) != " "
27382745
27392746proc knownGoodFamily * (provider, model: string ): string =
27402747 # # Convenience overload for the wizard, where we have a candidate
27412748 # # (provider name, full model id) but no Profile.
27422749 let p = canonicalKnownGoodProvider (provider)
2743- let m = model.toLowerAscii
27442750 for combo in KnownGoodCombos :
2745- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2751+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
27462752 return combo.family
27472753 " "
27482754
@@ -2751,18 +2757,16 @@ proc knownGoodTags*(provider, model: string): (string, string, string) =
27512757 # # strings when no match. Used at profile-build time to populate the
27522758 # # informational tags on `Profile`.
27532759 let p = canonicalKnownGoodProvider (provider)
2754- let m = model.toLowerAscii
27552760 for combo in KnownGoodCombos :
2756- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2761+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
27572762 return (combo.family, combo.version, combo.variant)
27582763 (" " , " " , " " )
27592764
27602765proc knownGoodReasoning * (provider, model: string ): string =
27612766 # # Default reasoning level for a known-good combo, "" if not on the list.
27622767 let p = canonicalKnownGoodProvider (provider)
2763- let m = model.toLowerAscii
27642768 for combo in KnownGoodCombos :
2765- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2769+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
27662770 return combo.reasoning
27672771 " "
27682772
@@ -2792,9 +2796,8 @@ proc knownGoodGeneration*(provider, model: string): GenerationDefaults =
27922796 # # Hardcoded generation defaults for a known-good combo. Experimental
27932797 # # combos return the zero object, which callers treat as "omit".
27942798 let p = canonicalKnownGoodProvider (provider)
2795- let m = model.toLowerAscii
27962799 for combo in KnownGoodCombos :
2797- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2800+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
27982801 return GenerationDefaults (temperature: combo.temperature, maxTokens: combo.maxTokens)
27992802 GenerationDefaults (temperature: - 1.0 , maxTokens: 0 )
28002803
@@ -2815,9 +2818,9 @@ proc xmlToolCallsFallback*(p: Profile): bool =
28152818 let dot = p.name.find ('.' )
28162819 if dot < 0 : return false
28172820 let provider = canonicalKnownGoodProvider (p.name[0 ..< dot])
2818- let model = p.model.toLowerAscii
28192821 for combo in KnownGoodCombos :
2820- if combo.provider.toLowerAscii == provider and combo.model.toLowerAscii == model:
2822+ if combo.provider.toLowerAscii == provider and
2823+ matchesKnownGoodModel (combo.model, p.model):
28212824 return combo.xmlToolCalls
28222825 false
28232826
@@ -2839,9 +2842,8 @@ proc knownGoodContextWindow*(provider, model: string): int =
28392842 # # substring heuristic). The value comes straight from the
28402843 # # `contextWindow` field of the matching entry in `KnownGoodCombos`.
28412844 let p = canonicalKnownGoodProvider (provider)
2842- let m = model.toLowerAscii
28432845 for combo in KnownGoodCombos :
2844- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2846+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
28452847 return combo.contextWindow
28462848 0
28472849
@@ -2889,9 +2891,8 @@ proc knownGoodReasonings*(provider, model: string): seq[string] =
28892891 # # `@ReasoningLevels` for the level-based families (gpt-oss, deepseek),
28902892 # # and `@[]` when the pair is off the table.
28912893 let p = canonicalKnownGoodProvider (provider)
2892- let m = model.toLowerAscii
28932894 for combo in KnownGoodCombos :
2894- if combo.provider.toLowerAscii == p and combo.model.toLowerAscii == m :
2895+ if combo.provider.toLowerAscii == p and matchesKnownGoodModel ( combo.model, model) :
28952896 let fam = combo.family
28962897 if fam == " gpt" :
28972898 # Effort ladder from OpenAI's per-model docs, keyed off the
0 commit comments