Merge pull request #2086 from majiayu000/fix/issue-2084-vendor-model-prefix-parsing

fix: parse vendor prefix from model name for vendor/model convention
This commit is contained in:
Kayvan Sylvan 2026-04-23 01:47:37 -07:00 committed by GitHub
commit d7cc49f25c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 4 deletions

View file

@ -0,0 +1,3 @@
### PR [#2086](https://github.com/danielmiessler/Fabric/pull/2086) by [majiayu000](https://github.com/majiayu000): fix: parse vendor prefix from model name for vendor/model convention
- **Fix:** Added fallback logic to parse the vendor prefix from a model name when no vendor is explicitly specified. When a model string such as `ollama/llama3` is passed, the lookup no longer fails with a "could not find vendor" error; instead, the first path segment is split and checked against known vendors, correctly resolving the model to `llama3` under the `Ollama` vendor group.

View file

@ -539,11 +539,29 @@ func (o *PluginRegistry) GetChatter(model string, modelContextLength int, vendor
return
}
} else {
availableVendors := models.FindGroupsByItem(model)
if len(availableVendors) > 1 {
debuglog.Log("Warning: multiple vendors provide model %s: %s. Using %s. Specify --vendor to select a vendor.\n", model, strings.Join(availableVendors, ", "), availableVendors[0])
// If the model wasn't found and contains a '/', try parsing the first
// segment as a vendor name (e.g. "ollama/llama3" -> vendor "ollama", model "llama3").
if actualModelName == "" {
if idx := strings.Index(model, "/"); idx > 0 {
prefix := model[:idx]
if v := vendorManager.FindByName(prefix); v != nil {
vendorName = prefix
model = model[idx+1:]
if normalized := models.FindModelNameCaseInsensitive(model); normalized != "" {
model = normalized
}
ret.vendor = v
}
}
}
if ret.vendor == nil {
availableVendors := models.FindGroupsByItem(model)
if len(availableVendors) > 1 {
debuglog.Log("Warning: multiple vendors provide model %s: %s. Using %s. Specify --vendor to select a vendor.\n", model, strings.Join(availableVendors, ", "), availableVendors[0])
}
ret.vendor = vendorManager.FindByName(models.FindGroupsByItemFirst(model))
}
ret.vendor = vendorManager.FindByName(models.FindGroupsByItemFirst(model))
}
ret.model = model

View file

@ -150,3 +150,63 @@ func TestGetChatter_RejectsExplicitCodexModelFromOtherVendor(t *testing.T) {
t.Fatal("expected GetChatter() to reject models that only belong to another vendor")
}
}
func TestGetChatter_ParsesVendorModelPrefix(t *testing.T) {
tempDir := t.TempDir()
db := fsdb.NewDb(tempDir)
ollamaVendor := &testVendor{name: "Ollama", models: []string{"some-namespace/model-name"}}
vm := ai.NewVendorsManager()
vm.AddVendors(ollamaVendor)
defaults := &tools.Defaults{
PluginBase: &plugins.PluginBase{},
Vendor: &plugins.Setting{Value: "Ollama"},
Model: &plugins.SetupQuestion{Setting: &plugins.Setting{Value: "some-namespace/model-name"}},
ModelContextLength: &plugins.SetupQuestion{Setting: &plugins.Setting{Value: "0"}},
}
registry := &PluginRegistry{Db: db, VendorManager: vm, Defaults: defaults}
chatter, err := registry.GetChatter("ollama/some-namespace/model-name", 0, "", false, false)
if err != nil {
t.Fatalf("GetChatter() error = %v", err)
}
if chatter.vendor.GetName() != "Ollama" {
t.Fatalf("expected Ollama vendor, got %s", chatter.vendor.GetName())
}
if chatter.model != "some-namespace/model-name" {
t.Fatalf("expected model 'some-namespace/model-name', got %s", chatter.model)
}
}
func TestGetChatter_VendorPrefixIgnoredWhenNotAVendor(t *testing.T) {
tempDir := t.TempDir()
db := fsdb.NewDb(tempDir)
vendorA := &testVendor{name: "VendorA", models: []string{"notavendor/model"}}
vm := ai.NewVendorsManager()
vm.AddVendors(vendorA)
defaults := &tools.Defaults{
PluginBase: &plugins.PluginBase{},
Vendor: &plugins.Setting{Value: "VendorA"},
Model: &plugins.SetupQuestion{Setting: &plugins.Setting{Value: "notavendor/model"}},
ModelContextLength: &plugins.SetupQuestion{Setting: &plugins.Setting{Value: "0"}},
}
registry := &PluginRegistry{Db: db, VendorManager: vm, Defaults: defaults}
chatter, err := registry.GetChatter("notavendor/model", 0, "", false, false)
if err != nil {
t.Fatalf("GetChatter() error = %v", err)
}
if chatter.vendor.GetName() != "VendorA" {
t.Fatalf("expected VendorA vendor, got %s", chatter.vendor.GetName())
}
if chatter.model != "notavendor/model" {
t.Fatalf("expected model 'notavendor/model', got %s", chatter.model)
}
}