Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 500
Add multi-model support for Copilot engine with wildcard matching and CLI-based selection#5663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
e5525b8960a43c41a6864bc471600e4d95c1f642efFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| name: Test Multi-Model Selection | ||
| description: Test workflow to verify multi-model selection with wildcards works correctly | ||
| on: workflow_dispatch | ||
| engine: | ||
| id: copilot | ||
| model: | ||
| - "gpt-5" | ||
| - "gpt-4o" | ||
| - "gpt-*-mini" | ||
| --- | ||
| # Test Multi-Model Selection | ||
| This is a simple test workflow to verify that multi-model selection works correctly. | ||
| The workflow should: | ||
| 1. Validate secrets | ||
| 2. Select the first available model from the list (gpt-5, gpt-4o, or any gpt-*-mini model) | ||
| 3. Use the selected model for execution | ||
| Please respond with a simple message confirming which model was selected. |
| Original file line number | Diff line number | Diff line change | |||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | |||||||||||||||||||||||||||||||||||||||||
| package workflow | |||||||||||||||||||||||||||||||||||||||||
| import ( | |||||||||||||||||||||||||||||||||||||||||
| "encoding/json" | |||||||||||||||||||||||||||||||||||||||||
| "fmt" | |||||||||||||||||||||||||||||||||||||||||
| "sort" | |||||||||||||||||||||||||||||||||||||||||
| "strings" | |||||||||||||||||||||||||||||||||||||||||
| @@ -41,6 +42,44 @@ | |||||||||||||||||||||||||||||||||||||||||
| return constants.DefaultCopilotDetectionModel | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| // GetModelSelectionStep returns a step that validates and selects a compatible model | |||||||||||||||||||||||||||||||||||||||||
| // Returns nil if no model selection is needed (single model or no models specified) | |||||||||||||||||||||||||||||||||||||||||
| func (e *CopilotEngine) GetModelSelectionStep(workflowData *WorkflowData) GitHubActionStep { | |||||||||||||||||||||||||||||||||||||||||
| // Only generate model selection step if multiple models are specified | |||||||||||||||||||||||||||||||||||||||||
| if workflowData.EngineConfig == nil || len(workflowData.EngineConfig.Models) <= 1 { | |||||||||||||||||||||||||||||||||||||||||
| return nil | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Printf("Generating model selection step for %d models", len(workflowData.EngineConfig.Models)) | |||||||||||||||||||||||||||||||||||||||||
| // Convert models array to JSON | |||||||||||||||||||||||||||||||||||||||||
| requestedModelsJSON, err := json.Marshal(workflowData.EngineConfig.Models) | |||||||||||||||||||||||||||||||||||||||||
| if err != nil { | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Printf("Error marshaling requested models: %v", err) | |||||||||||||||||||||||||||||||||||||||||
| return nil | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| script := getSelectModelWithCLIScript() | |||||||||||||||||||||||||||||||||||||||||
| stepLines := []string{ | |||||||||||||||||||||||||||||||||||||||||
| " - name: Select Compatible Model", | |||||||||||||||||||||||||||||||||||||||||
| " id: select_model", | |||||||||||||||||||||||||||||||||||||||||
| fmt.Sprintf(" uses: %s", GetActionPin("actions/github-script")), | |||||||||||||||||||||||||||||||||||||||||
| " with:", | |||||||||||||||||||||||||||||||||||||||||
| " script: |", | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| // Inline the JavaScript code with proper indentation | |||||||||||||||||||||||||||||||||||||||||
| scriptLines := FormatJavaScriptForYAML(script) | |||||||||||||||||||||||||||||||||||||||||
| stepLines = append(stepLines, scriptLines...) | |||||||||||||||||||||||||||||||||||||||||
| // Add inputs section | |||||||||||||||||||||||||||||||||||||||||
| stepLines = append(stepLines, " inputs:", | |||||||||||||||||||||||||||||||||||||||||
| fmt.Sprintf(" requested_models: '%s'", string(requestedModelsJSON))) | |||||||||||||||||||||||||||||||||||||||||
Check failureCode scanning / CodeQL Potentially unsafe quoting Critical
If this JSON value Error loading related location LoadingUh oh!There was an error while loading. Please reload this page.
Show autofix suggestionHide autofix suggestion Copilot AutofixAI 9 months ago The best way to fix this issue is to ensure user-supplied data cannot break out of the enclosing single quotes in the YAML string. This can be accomplished by escaping any single quotes and backslashes in Changes are needed only for the string interpolation line:
You'll need to import
Suggested changeset
1 pkg/workflow/copilot_engine.go
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again. | |||||||||||||||||||||||||||||||||||||||||
| return GitHubActionStep(stepLines) | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| func (e *CopilotEngine) GetInstallationSteps(workflowData *WorkflowData) []GitHubActionStep { | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Printf("Generating installation steps for Copilot engine: workflow=%s", workflowData.Name) | |||||||||||||||||||||||||||||||||||||||||
| @@ -65,6 +104,13 @@ | |||||||||||||||||||||||||||||||||||||||||
| ) | |||||||||||||||||||||||||||||||||||||||||
| steps = append(steps, secretValidation) | |||||||||||||||||||||||||||||||||||||||||
| // Add model selection step if multiple models are specified | |||||||||||||||||||||||||||||||||||||||||
| modelSelectionStep := e.GetModelSelectionStep(workflowData) | |||||||||||||||||||||||||||||||||||||||||
| if modelSelectionStep != nil { | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Print("Adding model selection step") | |||||||||||||||||||||||||||||||||||||||||
| steps = append(steps, modelSelectionStep) | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| // Determine Copilot version | |||||||||||||||||||||||||||||||||||||||||
| copilotVersion := config.Version | |||||||||||||||||||||||||||||||||||||||||
| if workflowData.EngineConfig != nil && workflowData.EngineConfig.Version != "" { | |||||||||||||||||||||||||||||||||||||||||
| @@ -195,9 +241,22 @@ | |||||||||||||||||||||||||||||||||||||||||
| copilotArgs = append(copilotArgs, "--disable-builtin-mcps") | |||||||||||||||||||||||||||||||||||||||||
| // Add model if specified (check if Copilot CLI supports this) | |||||||||||||||||||||||||||||||||||||||||
| if workflowData.EngineConfig != nil && workflowData.EngineConfig.Model != "" { | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Printf("Using custom model: %s", workflowData.EngineConfig.Model) | |||||||||||||||||||||||||||||||||||||||||
| copilotArgs = append(copilotArgs, "--model", workflowData.EngineConfig.Model) | |||||||||||||||||||||||||||||||||||||||||
| if workflowData.EngineConfig != nil { | |||||||||||||||||||||||||||||||||||||||||
| if len(workflowData.EngineConfig.Models) > 1 { | |||||||||||||||||||||||||||||||||||||||||
| // Multiple models specified - use the selected model from the selection step | |||||||||||||||||||||||||||||||||||||||||
| // Only add --model if selected_model is not empty (empty means "*" wildcard was matched) | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Print("Using model from selection step if not empty: ${{ steps.select_model.outputs.selected_model }}") | |||||||||||||||||||||||||||||||||||||||||
| // Use shell conditional to only add --model if selected_model is not empty | |||||||||||||||||||||||||||||||||||||||||
| // This will be evaluated at runtime in the workflow | |||||||||||||||||||||||||||||||||||||||||
| modelArg := "${{ steps.select_model.outputs.selected_model && format('--model {0}', steps.select_model.outputs.selected_model) || '' }}" | |||||||||||||||||||||||||||||||||||||||||
| if modelArg != "" { | |||||||||||||||||||||||||||||||||||||||||
| copilotArgs = append(copilotArgs, modelArg) | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| } else if workflowData.EngineConfig.Model != "" { | |||||||||||||||||||||||||||||||||||||||||
| // Single model specified directly | |||||||||||||||||||||||||||||||||||||||||
| copilotLog.Printf("Using custom model: %s", workflowData.EngineConfig.Model) | |||||||||||||||||||||||||||||||||||||||||
| copilotArgs = append(copilotArgs, "--model", workflowData.EngineConfig.Model) | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||||||||||||||
| // Add --agent flag if custom agent file is specified (via imports) | |||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot move script to JavaScript file, add tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved inline JavaScript to
select_model_with_cli.cjswith CLI integration and added comprehensive tests inselect_model_with_cli.test.cjs(14 test cases covering wildcard patterns, CLI fallback, and special*wildcard). Commit 1f642ef.