Skip to content

Commit ab97809

Browse files
Dev AgentRader
authored andcommitted
fix-tag-processor-same-name
1 parent b0882c0 commit ab97809

2 files changed

Lines changed: 69 additions & 7 deletions

File tree

component/tagparser/tag_processor.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,23 @@ func (p *tagProcessor) processTags(existingCategoryTagMap map[string]map[string]
124124
}
125125
for _, tagName := range tagNames {
126126
if tag, ok := existingTaskTags[tagName]; !ok {
127-
tagsToCreate = append(tagsToCreate, &database.Tag{
128-
Name: tagName,
129-
Category: category,
130-
Scope: p.tagScope,
131-
BuiltIn: false, // new tag is absolutely not built-in
132-
Group: "", // keep empty
133-
})
127+
// Before creating a new tag, search for an existing built-in tag with the
128+
// same name across all categories. This handles the case where a tag like
129+
// "jax" (framework) appears under the generic "tags" frontmatter key, which
130+
// gets mapped to the "task" category by formatCategoryName. Without this
131+
// lookup, the system would incorrectly create a new task-category tag
132+
// instead of reusing the existing built-in framework tag.
133+
if builtIn := findBuiltInTagByName(existingCategoryTagMap, tagName); builtIn != nil {
134+
tagsMatched = append(tagsMatched, builtIn)
135+
} else {
136+
tagsToCreate = append(tagsToCreate, &database.Tag{
137+
Name: tagName,
138+
Category: category,
139+
Scope: p.tagScope,
140+
BuiltIn: false, // new tag is absolutely not built-in
141+
Group: "", // keep empty
142+
})
143+
}
134144
} else {
135145
tagsMatched = append(tagsMatched, tag)
136146
}
@@ -141,6 +151,17 @@ func (p *tagProcessor) processTags(existingCategoryTagMap map[string]map[string]
141151
return tagsMatched, tagsToCreate
142152
}
143153

154+
// findBuiltInTagByName searches for a built-in tag with the given name across all categories.
155+
// Returns the first built-in tag found, or nil if none exists.
156+
func findBuiltInTagByName(existingCategoryTagMap map[string]map[string]*database.Tag, name string) *database.Tag {
157+
for _, tags := range existingCategoryTagMap {
158+
if tag, ok := tags[name]; ok && tag.BuiltIn {
159+
return tag
160+
}
161+
}
162+
return nil
163+
}
164+
144165
func (p *tagProcessor) mapCategoryTag(tags []*database.Tag) map[string]map[string]*database.Tag {
145166
predefinedCategoryTagMap := make(map[string]map[string]*database.Tag)
146167
for _, tag := range tags {

component/tagparser/tag_processor_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,47 @@ func Test_ProcessReadme(t *testing.T) {
6060
t.Fail()
6161
}
6262
}
63+
64+
// Test_processTags_BuiltInCrossCategory verifies that when a tag name appears under a
65+
// different category in the README frontmatter (e.g. "jax" under "tags" which maps to
66+
// "task"), the processor reuses the existing built-in tag from the correct category
67+
// ("framework") instead of creating a new tag with the wrong category.
68+
func Test_processTags_BuiltInCrossCategory(t *testing.T) {
69+
p := new(tagProcessor)
70+
p.tagScope = types.ModelTagScope
71+
72+
existingCategoryTagMap := make(map[string]map[string]*database.Tag)
73+
74+
existingCategoryTagMap[categoryNameTask] = make(map[string]*database.Tag)
75+
existingCategoryTagMap[categoryNameTask]["text-generation"] = &database.Tag{Name: "text-generation", Category: categoryNameTask, BuiltIn: true}
76+
77+
existingCategoryTagMap[categoryNameFramework] = make(map[string]*database.Tag)
78+
existingCategoryTagMap[categoryNameFramework]["jax"] = &database.Tag{Name: "jax", Category: categoryNameFramework, BuiltIn: true}
79+
80+
// "tags" key in frontmatter maps to "task" category, but "jax" is a framework tag
81+
categoryTagMap := make(map[string][]string)
82+
categoryTagMap[categoryNameTask] = []string{"text-generation", "jax"}
83+
84+
tagsMatched, tagsToCreate := p.processTags(existingCategoryTagMap, categoryTagMap)
85+
86+
if len(tagsToCreate) != 0 {
87+
t.Logf("expected no new tags, got %d: %+v", len(tagsToCreate), tagsToCreate)
88+
t.FailNow()
89+
}
90+
91+
if len(tagsMatched) != 2 {
92+
t.Logf("expected 2 matched tags, got %d", len(tagsMatched))
93+
t.FailNow()
94+
}
95+
96+
if !slices.ContainsFunc(tagsMatched, func(e *database.Tag) bool {
97+
return e.Name == "jax" && e.Category == categoryNameFramework
98+
}) {
99+
t.Logf("expected matched tag framework/jax, not found in matched: %+v", tagsMatched)
100+
t.FailNow()
101+
}
102+
}
103+
63104
func Test_processTags(t *testing.T) {
64105
p := new(tagProcessor)
65106
p.tagScope = types.DatasetTagScope

0 commit comments

Comments
 (0)