From a5e89bdcadf9fdc10724b21ccb2640164ed1043e Mon Sep 17 00:00:00 2001 From: bitliu Date: Mon, 13 Oct 2025 19:34:43 +0800 Subject: [PATCH 1/2] refactor(config): move reasoning fields from Category to ModelScore Move ReasoningDescription and ReasoningEffort from Category level to ModelScore level to enable model-specific reasoning configuration. **What type of PR is this?** [Refactoring / Breaking Change] **What this PR does / why we need it**: This PR refactors the reasoning configuration structure by moving and fields from the Category level to the ModelScore level. This change enables more granular control over reasoning behavior at the model level rather than the category level. **Key Changes:** - Remove and from struct - These fields now exist in struct (model-level configuration) - Update to accept parameter - Update all configuration files to new format (9 files) - Update Python training scripts to generate new format - Update TypeScript dashboard to read from best model - Update all test files **Breaking Change:** This is a breaking change with no backward compatibility. Old configuration files must be migrated to the new format. **Migration:** Old format: ```yaml categories: - name: math reasoning_description: "..." reasoning_effort: high model_scores: - model: model-a use_reasoning: true ``` New format: ```yaml categories: - name: math model_scores: - model: model-a use_reasoning: true reasoning_description: "..." reasoning_effort: high ``` **Testing:** - All Go tests pass - All configuration files validated - TypeScript type checking passes Signed-off-by: Xunzhuo Signed-off-by: bitliu --- config/config.e2e.yaml | 50 +++++++----------- dashboard/frontend/src/pages/ConfigPage.tsx | 51 +++++++------------ src/semantic-router/pkg/config/config.go | 30 +++-------- .../pkg/extproc/reason_mode_config_test.go | 37 +++++++------- .../pkg/extproc/reason_mode_selector.go | 20 +++++--- .../pkg/extproc/reasoning_integration_test.go | 31 +++++------ .../pkg/extproc/request_handler.go | 2 +- src/training/model_eval/result_to_config.py | 21 +++++--- 8 files changed, 105 insertions(+), 137 deletions(-) diff --git a/config/config.e2e.yaml b/config/config.e2e.yaml index 1e2e5689d..c1e463f92 100644 --- a/config/config.e2e.yaml +++ b/config/config.e2e.yaml @@ -86,13 +86,12 @@ classifier: pii_mapping_path: "models/pii_classifier_modernbert-base_presidio_token_model/pii_type_mapping.json" categories: - name: business - use_reasoning: false - reasoning_description: "Business content is typically conversational" - reasoning_effort: low # Business conversations need low reasoning effort model_scores: - model: "Model-A" score: 0.8 use_reasoning: false + reasoning_description: "Business content is typically conversational" + reasoning_effort: low - model: "Model-B" score: 0.4 use_reasoning: false @@ -100,12 +99,11 @@ categories: score: 0.2 use_reasoning: false - name: law - use_reasoning: false - reasoning_description: "Legal content is typically explanatory" model_scores: - model: "Model-B" score: 0.8 use_reasoning: false + reasoning_description: "Legal content is typically explanatory" - model: "Model-A" score: 0.6 use_reasoning: false @@ -113,12 +111,11 @@ categories: score: 0.4 use_reasoning: false - name: psychology - use_reasoning: false - reasoning_description: "Psychology content is usually explanatory" model_scores: - model: "Model-A" score: 0.6 use_reasoning: false + reasoning_description: "Psychology content is usually explanatory" - model: "Model-B" score: 0.4 use_reasoning: false @@ -126,12 +123,11 @@ categories: score: 0.4 use_reasoning: false - name: biology - use_reasoning: true - reasoning_description: "Biological processes benefit from structured analysis" model_scores: - model: "Model-A" score: 0.8 use_reasoning: false + reasoning_description: "Biological processes benefit from structured analysis" - model: "Model-B" score: 0.6 use_reasoning: false @@ -139,13 +135,12 @@ categories: score: 0.2 use_reasoning: false - name: chemistry - use_reasoning: true - reasoning_description: "Chemical reactions and formulas require systematic thinking" - reasoning_effort: high # Chemistry requires high reasoning effort model_scores: - model: "Model-A" score: 0.8 use_reasoning: true + reasoning_description: "Chemical reactions and formulas require systematic thinking" + reasoning_effort: high - model: "Model-B" score: 0.6 use_reasoning: false @@ -153,12 +148,11 @@ categories: score: 0.6 use_reasoning: false - name: history - use_reasoning: false - reasoning_description: "Historical content is narrative-based" model_scores: - model: "Model-A" score: 0.8 use_reasoning: false + reasoning_description: "Historical content is narrative-based" - model: "Model-A" score: 0.6 use_reasoning: false @@ -166,12 +160,11 @@ categories: score: 0.4 use_reasoning: false - name: other - use_reasoning: false - reasoning_description: "General content doesn't require reasoning" model_scores: - model: "Model-B" score: 0.8 use_reasoning: false + reasoning_description: "General content doesn't require reasoning" - model: "Model-A" score: 0.6 use_reasoning: false @@ -179,12 +172,11 @@ categories: score: 0.6 use_reasoning: false - name: health - use_reasoning: false - reasoning_description: "Health information is typically informational" model_scores: - model: "Model-B" score: 0.8 use_reasoning: false + reasoning_description: "Health information is typically informational" - model: "Model-A" score: 0.8 use_reasoning: false @@ -192,12 +184,11 @@ categories: score: 0.6 use_reasoning: false - name: economics - use_reasoning: false - reasoning_description: "Economic discussions are usually explanatory" model_scores: - model: "Model-B" score: 0.8 use_reasoning: false + reasoning_description: "Economic discussions are usually explanatory" - model: "Model-A" score: 0.8 use_reasoning: false @@ -205,16 +196,17 @@ categories: score: 0.1 use_reasoning: false - name: math - use_reasoning: true - reasoning_description: "Mathematical problems require step-by-step reasoning" - reasoning_effort: high # Math problems need high reasoning effort model_scores: - model: "Model-B" score: 1.0 use_reasoning: true + reasoning_description: "Mathematical problems require step-by-step reasoning" + reasoning_effort: high - model: "Model-A" score: 0.9 use_reasoning: true + reasoning_description: "Mathematical problems require step-by-step reasoning" + reasoning_effort: high - model: "Model-A" score: 0.8 use_reasoning: false @@ -222,12 +214,11 @@ categories: score: 0.6 use_reasoning: false - name: physics - use_reasoning: true - reasoning_description: "Physics concepts need logical analysis" model_scores: - model: "Model-B" score: 0.4 use_reasoning: true + reasoning_description: "Physics concepts need logical analysis" - model: "Model-A" score: 0.4 use_reasoning: false @@ -235,12 +226,11 @@ categories: score: 0.4 use_reasoning: false - name: computer science - use_reasoning: true - reasoning_description: "Programming and algorithms need logical reasoning" model_scores: - model: "Model-B" score: 0.6 use_reasoning: false + reasoning_description: "Programming and algorithms need logical reasoning" - model: "Model-A" score: 0.6 use_reasoning: false @@ -248,12 +238,11 @@ categories: score: 0.1 use_reasoning: false - name: philosophy - use_reasoning: false - reasoning_description: "Philosophical discussions are conversational" model_scores: - model: "Model-A" score: 0.6 use_reasoning: false + reasoning_description: "Philosophical discussions are conversational" - model: "Model-B" score: 0.2 use_reasoning: false @@ -261,12 +250,11 @@ categories: score: 0.2 use_reasoning: false - name: engineering - use_reasoning: true - reasoning_description: "Engineering problems require systematic problem-solving" model_scores: - model: "Model-B" score: 0.6 use_reasoning: false + reasoning_description: "Engineering problems require systematic problem-solving" - model: "Model-A" score: 0.6 use_reasoning: false diff --git a/dashboard/frontend/src/pages/ConfigPage.tsx b/dashboard/frontend/src/pages/ConfigPage.tsx index 4e9695257..7a02226e2 100644 --- a/dashboard/frontend/src/pages/ConfigPage.tsx +++ b/dashboard/frontend/src/pages/ConfigPage.tsx @@ -38,14 +38,13 @@ interface ModelScore { model: string score: number use_reasoning: boolean + reasoning_description?: string + reasoning_effort?: string } interface Category { name: string system_prompt?: string - use_reasoning: boolean - reasoning_description: string - reasoning_effort: string model_scores: ModelScore[] } @@ -1408,14 +1407,21 @@ const ConfigPage: React.FC = ({ activeSection = 'models' }) => {config?.categories && config.categories.length > 0 ? (
- {config.categories.map((category, index) => ( + {config.categories.map((category, index) => { + // Get reasoning info from best model (first model score) + const bestModel = category.model_scores?.[0] + const useReasoning = bestModel?.use_reasoning || false + const reasoningEffort = bestModel?.reasoning_effort || 'medium' + const reasoningDescription = bestModel?.reasoning_description || '' + + return (
{category.name}
- {category.use_reasoning && ( - - ⚡ {category.reasoning_effort} + {useReasoning && ( + + ⚡ {reasoningEffort} )}
)} -

{category.reasoning_description}

+ {reasoningDescription && ( +

{reasoningDescription}

+ )}
@@ -1635,7 +1620,7 @@ const ConfigPage: React.FC = ({ activeSection = 'models' }) => )}
- ))} + )})}
) : (
No categories configured
diff --git a/src/semantic-router/pkg/config/config.go b/src/semantic-router/pkg/config/config.go index 49b32c465..e20632982 100644 --- a/src/semantic-router/pkg/config/config.go +++ b/src/semantic-router/pkg/config/config.go @@ -332,18 +332,18 @@ func (c *RouterConfig) GetCacheSimilarityThreshold() float32 { // ModelScore associates an LLM with its selection weight and reasoning flag within a category. type ModelScore struct { - Model string `yaml:"model"` - Score float64 `yaml:"score"` - UseReasoning *bool `yaml:"use_reasoning"` // Pointer to detect missing field + Model string `yaml:"model"` + Score float64 `yaml:"score"` + UseReasoning *bool `yaml:"use_reasoning"` // Pointer to detect missing field + ReasoningDescription string `yaml:"reasoning_description,omitempty"` // Model-specific reasoning description + ReasoningEffort string `yaml:"reasoning_effort,omitempty"` // Model-specific reasoning effort level (low, medium, high) } // Category represents a category for routing queries type Category struct { - Name string `yaml:"name"` - Description string `yaml:"description,omitempty"` - ReasoningDescription string `yaml:"reasoning_description,omitempty"` - ReasoningEffort string `yaml:"reasoning_effort,omitempty"` // Configurable reasoning effort level (low, medium, high) - ModelScores []ModelScore `yaml:"model_scores"` + Name string `yaml:"name"` + Description string `yaml:"description,omitempty"` + ModelScores []ModelScore `yaml:"model_scores"` // MMLUCategories optionally maps this generic category to one or more MMLU-Pro categories // used by the classifier model. When provided, classifier outputs will be translated // from these MMLU categories to this generic category name. @@ -359,8 +359,6 @@ type Category struct { SystemPromptMode string `yaml:"system_prompt_mode,omitempty"` } -// Legacy types - can be removed once migration is complete - // GetModelReasoningFamily returns the reasoning family configuration for a given model name func (rc *RouterConfig) GetModelReasoningFamily(modelName string) *ReasoningFamilyConfig { if rc == nil || rc.ModelConfig == nil || rc.ReasoningFamilies == nil { @@ -382,18 +380,6 @@ func (rc *RouterConfig) GetModelReasoningFamily(modelName string) *ReasoningFami return &familyConfig } -// Legacy functions - can be removed once migration is complete - -// contains checks if a slice contains a string -func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false -} - var ( config *RouterConfig configOnce sync.Once diff --git a/src/semantic-router/pkg/extproc/reason_mode_config_test.go b/src/semantic-router/pkg/extproc/reason_mode_config_test.go index 99b5639c4..e37c62343 100644 --- a/src/semantic-router/pkg/extproc/reason_mode_config_test.go +++ b/src/semantic-router/pkg/extproc/reason_mode_config_test.go @@ -17,24 +17,21 @@ func TestReasoningModeConfiguration(t *testing.T) { cfg := &config.RouterConfig{ Categories: []config.Category{ { - Name: "math", - ReasoningDescription: "Mathematical problems require step-by-step reasoning", + Name: "math", ModelScores: []config.ModelScore{ - {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true)}, + {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true), ReasoningDescription: "Mathematical problems require step-by-step reasoning"}, }, }, { - Name: "business", - ReasoningDescription: "Business content is typically conversational", + Name: "business", ModelScores: []config.ModelScore{ - {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false)}, + {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false), ReasoningDescription: "Business content is typically conversational"}, }, }, { - Name: "biology", - ReasoningDescription: "Biological processes benefit from structured analysis", + Name: "biology", ModelScores: []config.ModelScore{ - {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true)}, + {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true), ReasoningDescription: "Biological processes benefit from structured analysis"}, }, }, }, @@ -47,15 +44,17 @@ func TestReasoningModeConfiguration(t *testing.T) { for _, category := range cfg.Categories { reasoningStatus := "DISABLED" bestModel := "no-model" + reasoningDesc := "" if len(category.ModelScores) > 0 { bestModel = category.ModelScores[0].Model if category.ModelScores[0].UseReasoning != nil && *category.ModelScores[0].UseReasoning { reasoningStatus = "ENABLED" } + reasoningDesc = category.ModelScores[0].ReasoningDescription } fmt.Printf("Category: %-15s | Model: %-12s | Reasoning: %-8s | %s\n", - category.Name, bestModel, reasoningStatus, category.ReasoningDescription) + category.Name, bestModel, reasoningStatus, reasoningDesc) } // Test queries with expected categories @@ -82,10 +81,12 @@ func TestReasoningModeConfiguration(t *testing.T) { for _, category := range cfg.Categories { if strings.EqualFold(category.Name, test.category) { - if len(category.ModelScores) > 0 && category.ModelScores[0].UseReasoning != nil { - useReasoning = *category.ModelScores[0].UseReasoning + if len(category.ModelScores) > 0 { + if category.ModelScores[0].UseReasoning != nil { + useReasoning = *category.ModelScores[0].UseReasoning + } + reasoningDesc = category.ModelScores[0].ReasoningDescription } - reasoningDesc = category.ReasoningDescription found = true break } @@ -129,21 +130,22 @@ func TestReasoningModeConfiguration(t *testing.T) { fmt.Print(` categories: - name: math - reasoning_description: "Mathematical problems require step-by-step reasoning" model_scores: - model: deepseek-v31 score: 0.9 use_reasoning: true + reasoning_description: "Mathematical problems require step-by-step reasoning" + reasoning_effort: high - model: phi4 score: 0.7 use_reasoning: false - name: business - reasoning_description: "Business content is typically conversational" model_scores: - model: phi4 score: 0.8 use_reasoning: false + reasoning_description: "Business content is typically conversational" `) } @@ -190,21 +192,22 @@ func DemonstrateConfigurationUsage() { fmt.Print(` categories: - name: math - reasoning_description: "Mathematical problems require step-by-step reasoning" model_scores: - model: deepseek-v31 score: 0.9 use_reasoning: true + reasoning_description: "Mathematical problems require step-by-step reasoning" + reasoning_effort: high - model: phi4 score: 0.7 use_reasoning: false - name: creative_writing - reasoning_description: "Creative content flows better without structured reasoning" model_scores: - model: phi4 score: 0.8 use_reasoning: false + reasoning_description: "Creative content flows better without structured reasoning" `) fmt.Println("\n2. Use in Go code:") diff --git a/src/semantic-router/pkg/extproc/reason_mode_selector.go b/src/semantic-router/pkg/extproc/reason_mode_selector.go index f91cfad2a..10f5d8245 100644 --- a/src/semantic-router/pkg/extproc/reason_mode_selector.go +++ b/src/semantic-router/pkg/extproc/reason_mode_selector.go @@ -124,7 +124,7 @@ func (r *OpenAIRouter) buildReasoningRequestFields(model string, useReasoning bo } return map[string]interface{}{"chat_template_kwargs": kwargs}, "" case "reasoning_effort": - effort := r.getReasoningEffort(categoryName) + effort := r.getReasoningEffort(categoryName, model) return map[string]interface{}{"reasoning_effort": effort}, effort default: // Unknown reasoning syntax type - don't apply anything @@ -302,19 +302,25 @@ func (r *OpenAIRouter) LogReasoningConfigurationSummary() { observability.Infof("Reasoning mode summary: %d/%d categories have reasoning enabled (based on best model)", enabledCount, len(r.Config.Categories)) } -// getReasoningEffort returns the reasoning effort level for a given category -func (r *OpenAIRouter) getReasoningEffort(categoryName string) string { +// getReasoningEffort returns the reasoning effort level for a given category and model +func (r *OpenAIRouter) getReasoningEffort(categoryName string, modelName string) string { // Handle case where Config is nil (e.g., in tests) if r.Config == nil { return "medium" } - // Find the category configuration + // Find the category and model configuration for _, category := range r.Config.Categories { if category.Name == categoryName { - // Use category-specific effort if configured - if category.ReasoningEffort != "" { - return category.ReasoningEffort + // Find the specific model in the category's model scores + for _, modelScore := range category.ModelScores { + if modelScore.Model == modelName { + // Use model-specific effort if configured + if modelScore.ReasoningEffort != "" { + return modelScore.ReasoningEffort + } + break + } } break } diff --git a/src/semantic-router/pkg/extproc/reasoning_integration_test.go b/src/semantic-router/pkg/extproc/reasoning_integration_test.go index a45bec077..14445ce30 100644 --- a/src/semantic-router/pkg/extproc/reasoning_integration_test.go +++ b/src/semantic-router/pkg/extproc/reasoning_integration_test.go @@ -14,18 +14,16 @@ func TestReasoningModeIntegration(t *testing.T) { DefaultReasoningEffort: "medium", Categories: []config.Category{ { - Name: "math", - ReasoningDescription: "Mathematical problems require step-by-step reasoning", + Name: "math", ModelScores: []config.ModelScore{ - {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true)}, + {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true), ReasoningDescription: "Mathematical problems require step-by-step reasoning", ReasoningEffort: "high"}, {Model: "phi4", Score: 0.7, UseReasoning: config.BoolPtr(false)}, }, }, { - Name: "business", - ReasoningDescription: "Business content is typically conversational", + Name: "business", ModelScores: []config.ModelScore{ - {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false)}, + {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false), ReasoningDescription: "Business content is typically conversational"}, {Model: "deepseek-v31", Score: 0.6, UseReasoning: config.BoolPtr(false)}, }, }, @@ -286,10 +284,9 @@ func TestReasoningModeConfigurationValidation(t *testing.T) { { name: "Math category with reasoning enabled", category: config.Category{ - Name: "math", - ReasoningDescription: "Mathematical problems require step-by-step reasoning", + Name: "math", ModelScores: []config.ModelScore{ - {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true)}, + {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true), ReasoningDescription: "Mathematical problems require step-by-step reasoning"}, }, }, expected: true, @@ -297,10 +294,9 @@ func TestReasoningModeConfigurationValidation(t *testing.T) { { name: "Business category with reasoning disabled", category: config.Category{ - Name: "business", - ReasoningDescription: "Business content is typically conversational", + Name: "business", ModelScores: []config.ModelScore{ - {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false)}, + {Model: "phi4", Score: 0.8, UseReasoning: config.BoolPtr(false), ReasoningDescription: "Business content is typically conversational"}, }, }, expected: false, @@ -308,10 +304,9 @@ func TestReasoningModeConfigurationValidation(t *testing.T) { { name: "Science category with reasoning enabled", category: config.Category{ - Name: "science", - ReasoningDescription: "Scientific concepts benefit from structured analysis", + Name: "science", ModelScores: []config.ModelScore{ - {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true)}, + {Model: "deepseek-v31", Score: 0.9, UseReasoning: config.BoolPtr(true), ReasoningDescription: "Scientific concepts benefit from structured analysis"}, }, }, expected: true, @@ -331,9 +326,9 @@ func TestReasoningModeConfigurationValidation(t *testing.T) { tc.expected, tc.category.Name, bestModelReasoning) } - // Verify description is not empty - if tc.category.ReasoningDescription == "" { - t.Errorf("ReasoningDescription should not be empty for category %s", tc.category.Name) + // Verify description is not empty (now in ModelScore) + if len(tc.category.ModelScores) > 0 && tc.category.ModelScores[0].ReasoningDescription == "" { + t.Errorf("ReasoningDescription should not be empty for best model in category %s", tc.category.Name) } }) } diff --git a/src/semantic-router/pkg/extproc/request_handler.go b/src/semantic-router/pkg/extproc/request_handler.go index b4b9d94fe..bdd10a45f 100644 --- a/src/semantic-router/pkg/extproc/request_handler.go +++ b/src/semantic-router/pkg/extproc/request_handler.go @@ -673,7 +673,7 @@ func (r *OpenAIRouter) handleModelRouting(openAIRequest *openai.ChatCompletionNe observability.Infof("Entropy-based reasoning decision for this query: %v on [%s] model (confidence: %.3f, reason: %s)", useReasoning, matchedModel, reasoningDecision.Confidence, reasoningDecision.DecisionReason) // Record reasoning decision metric with the effort that will be applied if enabled - effortForMetrics := r.getReasoningEffort(categoryName) + effortForMetrics := r.getReasoningEffort(categoryName, matchedModel) metrics.RecordReasoningDecision(categoryName, matchedModel, useReasoning, effortForMetrics) // Set routing attributes on span diff --git a/src/training/model_eval/result_to_config.py b/src/training/model_eval/result_to_config.py index e5c5c2c30..635aa85ff 100644 --- a/src/training/model_eval/result_to_config.py +++ b/src/training/model_eval/result_to_config.py @@ -222,10 +222,6 @@ def generate_config_yaml(category_accuracies, similarity_threshold): for model, acc in sorted(models.items(), key=lambda x: x[1], reverse=True) if model.split(":")[0] != "auto" ] - # Build the model_scores list - model_scores = [ - {"model": model, "score": float(acc)} for model, acc in ranked_models - ] # Get reasoning settings for the category reasoning_settings = category_reasoning.get( category.lower(), @@ -235,13 +231,22 @@ def generate_config_yaml(category_accuracies, similarity_threshold): "reasoning_effort": "low", }, ) - # Add category to config with reasoning settings - config["categories"].append( - { - "name": category, + # Build the model_scores list with reasoning settings applied to each model + model_scores = [] + for model, acc in ranked_models: + model_score = { + "model": model, + "score": float(acc), "use_reasoning": reasoning_settings["use_reasoning"], "reasoning_description": reasoning_settings["reasoning_description"], "reasoning_effort": reasoning_settings["reasoning_effort"], + } + model_scores.append(model_score) + + # Add category to config + config["categories"].append( + { + "name": category, "model_scores": model_scores, } ) From 4b214a9bee7e9d6dc69f68a95a4da338b2dac606 Mon Sep 17 00:00:00 2001 From: bitliu Date: Mon, 13 Oct 2025 20:23:09 +0800 Subject: [PATCH 2/2] fix(test): move ReasoningEffort to ModelScore in classification test Update generic_category_mapping_test.go to use the new structure where reasoning_effort is a field of ModelScore instead of Category. Signed-off-by: Xunzhuo Signed-off-by: bitliu --- .../generic_category_mapping_test.go | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/semantic-router/pkg/utils/classification/generic_category_mapping_test.go b/src/semantic-router/pkg/utils/classification/generic_category_mapping_test.go index d58ac518a..faa4e5aa6 100644 --- a/src/semantic-router/pkg/utils/classification/generic_category_mapping_test.go +++ b/src/semantic-router/pkg/utils/classification/generic_category_mapping_test.go @@ -27,20 +27,32 @@ var _ = Describe("generic category mapping (MMLU-Pro -> generic)", func() { // Define generic categories with MMLU-Pro mappings cfg.Categories = []config.Category{ { - Name: "tech", - MMLUCategories: []string{"computer science", "engineering"}, - ModelScores: []config.ModelScore{{Model: "phi4", Score: 0.9, UseReasoning: config.BoolPtr(false)}}, - ReasoningEffort: "low", + Name: "tech", + MMLUCategories: []string{"computer science", "engineering"}, + ModelScores: []config.ModelScore{{ + Model: "phi4", + Score: 0.9, + UseReasoning: config.BoolPtr(false), + ReasoningEffort: "low", + }}, }, { Name: "finance", MMLUCategories: []string{"economics"}, - ModelScores: []config.ModelScore{{Model: "gemma3:27b", Score: 0.8, UseReasoning: config.BoolPtr(true)}}, + ModelScores: []config.ModelScore{{ + Model: "gemma3:27b", + Score: 0.8, + UseReasoning: config.BoolPtr(true), + }}, }, { Name: "politics", // No explicit mmlu_categories -> identity fallback when label exists in mapping - ModelScores: []config.ModelScore{{Model: "gemma3:27b", Score: 0.6, UseReasoning: config.BoolPtr(false)}}, + ModelScores: []config.ModelScore{{ + Model: "gemma3:27b", + Score: 0.6, + UseReasoning: config.BoolPtr(false), + }}, }, }