From 00de810310aceef0d8c461ba396aad4f1f9c4afc Mon Sep 17 00:00:00 2001 From: Christopher Schleiden Date: Wed, 16 Jul 2025 14:32:20 -0700 Subject: [PATCH 1/3] Add launch profile for 'models view' command --- .vscode/launch.json | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 2bfd6f88..4c6d7e5e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,16 +1,25 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Run models list", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/main.go", - "args": ["list"] - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Run models list", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/main.go", + "args": ["list"] + }, + { + "name": "Run models view", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/main.go", + "args": ["view"], + "console": "integratedTerminal" + } + ] +} From 1d5ff3f45c68b8992f4dc08755b755200509a714 Mon Sep 17 00:00:00 2001 From: Christopher Schleiden Date: Wed, 16 Jul 2025 14:39:41 -0700 Subject: [PATCH 2/3] Use GitHub Models catalog --- cmd/list/list.go | 2 +- cmd/list/list_test.go | 5 +- cmd/run/run.go | 5 +- cmd/run/run_test.go | 15 +++-- cmd/view/view.go | 5 +- cmd/view/view_test.go | 5 +- internal/azuremodels/azure_client.go | 48 +++++++--------- internal/azuremodels/azure_client_test.go | 67 +++++++++++----------- internal/azuremodels/model_details.go | 7 --- internal/azuremodels/model_details_test.go | 8 --- internal/azuremodels/model_summary.go | 10 ++-- internal/azuremodels/model_summary_test.go | 10 ++-- internal/azuremodels/types.go | 31 +++++----- 13 files changed, 100 insertions(+), 118 deletions(-) diff --git a/cmd/list/list.go b/cmd/list/list.go index e1da8ab9..88388f56 100644 --- a/cmd/list/list.go +++ b/cmd/list/list.go @@ -53,7 +53,7 @@ func NewListCommand(cfg *command.Config) *cobra.Command { printer.EndRow() for _, model := range models { - printer.AddField(azuremodels.FormatIdentifier(model.Publisher, model.Name)) + printer.AddField(model.ID) printer.AddField(model.FriendlyName) printer.EndRow() } diff --git a/cmd/list/list_test.go b/cmd/list/list_test.go index 1068092d..b9860df8 100644 --- a/cmd/list/list_test.go +++ b/cmd/list/list_test.go @@ -14,14 +14,13 @@ func TestList(t *testing.T) { t.Run("NewListCommand happy path", func(t *testing.T) { client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ - ID: "test-id-1", + ID: "openai/test-id-1", Name: "test-model-1", FriendlyName: "Test Model 1", Task: "chat-completion", Publisher: "OpenAI", Summary: "This is a test model", Version: "1.0", - RegistryName: "azure-openai", } listModelsCallCount := 0 client.MockListModels = func(ctx context.Context) ([]*azuremodels.ModelSummary, error) { @@ -41,7 +40,7 @@ func TestList(t *testing.T) { require.Contains(t, output, "DISPLAY NAME") require.Contains(t, output, "ID") require.Contains(t, output, modelSummary.FriendlyName) - require.Contains(t, output, azuremodels.FormatIdentifier(modelSummary.Publisher, modelSummary.Name)) + require.Contains(t, output, modelSummary.ID) }) t.Run("--help prints usage info", func(t *testing.T) { diff --git a/cmd/run/run.go b/cmd/run/run.go index 134b9140..d0f58991 100644 --- a/cmd/run/run.go +++ b/cmd/run/run.go @@ -500,7 +500,8 @@ func (h *runCommandHandler) getModelNameFromArgs(models []*azuremodels.ModelSumm if !model.IsChatModel() { continue } - prompt.Options = append(prompt.Options, azuremodels.FormatIdentifier(model.Publisher, model.Name)) + + prompt.Options = append(prompt.Options, model.ID) } err := survey.AskOne(prompt, &modelName, survey.WithPageSize(10)) @@ -533,7 +534,7 @@ func validateModelName(modelName string, models []*azuremodels.ModelSummary) (st } // For non-custom providers, validate the model exists - expectedModelID := azuremodels.FormatIdentifier(parsedModel.Publisher, parsedModel.ModelName) + expectedModelID := parsedModel.String() foundMatch := false for _, model := range models { if model.HasName(expectedModelID) { diff --git a/cmd/run/run_test.go b/cmd/run/run_test.go index a1802a16..072a212e 100644 --- a/cmd/run/run_test.go +++ b/cmd/run/run_test.go @@ -19,14 +19,13 @@ func TestRun(t *testing.T) { t.Run("NewRunCommand happy path", func(t *testing.T) { client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ - ID: "test-id-1", + ID: "openai/test-model-1", Name: "test-model-1", FriendlyName: "Test Model 1", Task: "chat-completion", Publisher: "OpenAI", Summary: "This is a test model", Version: "1.0", - RegistryName: "azure-openai", } listModelsCallCount := 0 client.MockListModels = func(ctx context.Context) ([]*azuremodels.ModelSummary, error) { @@ -52,7 +51,7 @@ func TestRun(t *testing.T) { buf := new(bytes.Buffer) cfg := command.NewConfig(buf, buf, client, true, 80) runCmd := NewRunCommand(cfg) - runCmd.SetArgs([]string{azuremodels.FormatIdentifier(modelSummary.Publisher, modelSummary.Name), "this is my prompt"}) + runCmd.SetArgs([]string{modelSummary.ID, "this is my prompt"}) _, err := runCmd.ExecuteC() @@ -104,6 +103,7 @@ messages: client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ + ID: "openai/test-model", Name: "test-model", Publisher: "openai", Task: "chat-completion", @@ -134,7 +134,7 @@ messages: runCmd := NewRunCommand(cfg) runCmd.SetArgs([]string{ "--file", tmp.Name(), - azuremodels.FormatIdentifier("openai", "test-model"), + "openai/test-model", }) _, err = runCmd.ExecuteC() @@ -170,6 +170,7 @@ messages: client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ + ID: "openai/test-model", Name: "test-model", Publisher: "openai", Task: "chat-completion", @@ -214,7 +215,7 @@ messages: runCmd := NewRunCommand(cfg) runCmd.SetArgs([]string{ "--file", tmp.Name(), - azuremodels.FormatIdentifier("openai", "test-model"), + "openai/test-model", initialPrompt, }) @@ -252,11 +253,13 @@ messages: client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ + ID: "openai/example-model", Name: "example-model", Publisher: "openai", Task: "chat-completion", } modelSummary2 := &azuremodels.ModelSummary{ + ID: "openai/example-model-4o-mini-plus", Name: "example-model-4o-mini-plus", Publisher: "openai", Task: "chat-completion", @@ -369,6 +372,7 @@ messages: client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ + ID: "openai/test-model", Name: "test-model", Publisher: "openai", Task: "chat-completion", @@ -533,6 +537,7 @@ func TestValidateModelName(t *testing.T) { // Create a mock model for testing mockModel := &azuremodels.ModelSummary{ + ID: "openai/gpt-4", Name: "gpt-4", Publisher: "openai", Task: "chat-completion", diff --git a/cmd/view/view.go b/cmd/view/view.go index bec37f73..dad1e402 100644 --- a/cmd/view/view.go +++ b/cmd/view/view.go @@ -50,7 +50,7 @@ func NewViewCommand(cfg *command.Config) *cobra.Command { if !model.IsChatModel() { continue } - prompt.Options = append(prompt.Options, azuremodels.FormatIdentifier(model.Publisher, model.Name)) + prompt.Options = append(prompt.Options, model.ID) } err = survey.AskOne(prompt, &modelName, survey.WithPageSize(10)) @@ -61,13 +61,12 @@ func NewViewCommand(cfg *command.Config) *cobra.Command { case len(args) >= 1: modelName = args[0] } - modelSummary, err := getModelByName(modelName, models) if err != nil { return err } - modelDetails, err := client.GetModelDetails(ctx, modelSummary.RegistryName, modelSummary.Name, modelSummary.Version) + modelDetails, err := client.GetModelDetails(ctx, modelSummary.Registry, modelSummary.Name, modelSummary.Version) if err != nil { return err } diff --git a/cmd/view/view_test.go b/cmd/view/view_test.go index cde08747..2d53e528 100644 --- a/cmd/view/view_test.go +++ b/cmd/view/view_test.go @@ -14,14 +14,13 @@ func TestView(t *testing.T) { t.Run("NewViewCommand happy path", func(t *testing.T) { client := azuremodels.NewMockClient() modelSummary := &azuremodels.ModelSummary{ - ID: "test-id-1", + ID: "openai/test-model-1", Name: "test-model-1", FriendlyName: "Test Model 1", Task: "chat-completion", Publisher: "OpenAI", Summary: "This is a test model", Version: "1.0", - RegistryName: "azure-openai", } listModelsCallCount := 0 client.MockListModels = func(ctx context.Context) ([]*azuremodels.ModelSummary, error) { @@ -49,7 +48,7 @@ func TestView(t *testing.T) { buf := new(bytes.Buffer) cfg := command.NewConfig(buf, buf, client, true, 80) viewCmd := NewViewCommand(cfg) - viewCmd.SetArgs([]string{azuremodels.FormatIdentifier(modelSummary.Publisher, modelSummary.Name)}) + viewCmd.SetArgs([]string{modelSummary.ID}) _, err := viewCmd.ExecuteC() diff --git a/internal/azuremodels/azure_client.go b/internal/azuremodels/azure_client.go index bf747134..76eb537d 100644 --- a/internal/azuremodels/azure_client.go +++ b/internal/azuremodels/azure_client.go @@ -9,9 +9,11 @@ import ( "fmt" "io" "net/http" + "slices" "strings" "github.com/cli/go-gh/v2/pkg/api" + "github.com/github/gh-models/internal/modelkey" "github.com/github/gh-models/internal/sse" "golang.org/x/text/language" "golang.org/x/text/language/display" @@ -185,19 +187,7 @@ func lowercaseStrings(input []string) []string { // ListModels returns a list of available models. func (c *AzureClient) ListModels(ctx context.Context) ([]*ModelSummary, error) { - body := bytes.NewReader([]byte(` - { - "filters": [ - { "field": "freePlayground", "values": ["true"], "operator": "eq"}, - { "field": "labels", "values": ["latest"], "operator": "eq"} - ], - "order": [ - { "field": "displayName", "direction": "asc" } - ] - } - `)) - - httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.cfg.ModelsURL, body) + httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, c.cfg.ModelsURL, nil) if err != nil { return nil, err } @@ -218,28 +208,34 @@ func (c *AzureClient) ListModels(ctx context.Context) ([]*ModelSummary, error) { decoder := json.NewDecoder(resp.Body) decoder.UseNumber() - var searchResponse modelCatalogSearchResponse - err = decoder.Decode(&searchResponse) + var catalog githubModelCatalogResponse + err = decoder.Decode(&catalog) if err != nil { return nil, err } - models := make([]*ModelSummary, 0, len(searchResponse.Summaries)) - for _, summary := range searchResponse.Summaries { + models := make([]*ModelSummary, 0, len(catalog)) + for _, catalogModel := range catalog { + // Determine task from supported modalities - if it supports text input/output, it's likely a chat model inferenceTask := "" - if len(summary.InferenceTasks) > 0 { - inferenceTask = summary.InferenceTasks[0] + if slices.Contains(catalogModel.SupportedInputModalities, "text") && slices.Contains(catalogModel.SupportedOutputModalities, "text") { + inferenceTask = "chat-completion" + } + + modelKey, err := modelkey.ParseModelKey(catalogModel.ID) + if err != nil { + return nil, fmt.Errorf("parsing model key %q: %w", catalogModel.ID, err) } models = append(models, &ModelSummary{ - ID: summary.AssetID, - Name: summary.Name, - FriendlyName: summary.DisplayName, + ID: catalogModel.ID, + Name: modelKey.ModelName, + Registry: catalogModel.Registry, + FriendlyName: catalogModel.Name, Task: inferenceTask, - Publisher: summary.Publisher, - Summary: summary.Summary, - Version: summary.Version, - RegistryName: summary.RegistryName, + Publisher: catalogModel.Publisher, + Summary: catalogModel.Summary, + Version: catalogModel.Version, }) } diff --git a/internal/azuremodels/azure_client_test.go b/internal/azuremodels/azure_client_test.go index 8d84e302..a8b6bf23 100644 --- a/internal/azuremodels/azure_client_test.go +++ b/internal/azuremodels/azure_client_test.go @@ -194,38 +194,39 @@ func TestAzureClient(t *testing.T) { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, "application/json", r.Header.Get("Content-Type")) require.Equal(t, "/", r.URL.Path) - require.Equal(t, http.MethodPost, r.Method) + require.Equal(t, http.MethodGet, r.Method) handlerFn(w, r) })) } t.Run("happy path", func(t *testing.T) { - summary1 := modelCatalogSearchSummary{ - AssetID: "test-id-1", - Name: "test-model-1", - DisplayName: "I Can't Believe It's Not a Real Model", - InferenceTasks: []string{"this model has an inference task but the other model will not"}, - Publisher: "OpenAI", - Summary: "This is a test model", - Version: "1.0", - RegistryName: "azure-openai", - } - summary2 := modelCatalogSearchSummary{ - AssetID: "test-id-2", - Name: "test-model-2", - DisplayName: "Down the Rabbit-Hole", - Publisher: "Project Gutenberg", - Summary: "The first chapter of Alice's Adventures in Wonderland by Lewis Carroll.", - Version: "THE MILLENNIUM FULCRUM EDITION 3.0", - RegistryName: "proj-gutenberg-website", + summary1 := githubModelSummary{ + ID: "openai/gpt-4.1", + Name: "OpenAI GPT-4.1", + Publisher: "OpenAI", + Summary: "gpt-4.1 outperforms gpt-4o across the board", + Version: "1", + RateLimitTier: "high", + SupportedInputModalities: []string{"text", "image"}, + SupportedOutputModalities: []string{"text"}, + Tags: []string{"multipurpose", "multilingual", "multimodal"}, } - searchResponse := &modelCatalogSearchResponse{ - Summaries: []modelCatalogSearchSummary{summary1, summary2}, + summary2 := githubModelSummary{ + ID: "openai/gpt-4.1-mini", + Name: "OpenAI GPT-4.1-mini", + Publisher: "OpenAI", + Summary: "gpt-4.1-mini outperform gpt-4o-mini across the board", + Version: "2", + RateLimitTier: "low", + SupportedInputModalities: []string{"text", "image"}, + SupportedOutputModalities: []string{"text"}, + Tags: []string{"multipurpose", "multilingual", "multimodal"}, } + githubResponse := githubModelCatalogResponse{summary1, summary2} testServer := newTestServerForListModels(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - err := json.NewEncoder(w).Encode(searchResponse) + err := json.NewEncoder(w).Encode(githubResponse) require.NoError(t, err) })) defer testServer.Close() @@ -238,22 +239,20 @@ func TestAzureClient(t *testing.T) { require.NoError(t, err) require.NotNil(t, models) require.Equal(t, 2, len(models)) - require.Equal(t, summary1.AssetID, models[0].ID) - require.Equal(t, summary2.AssetID, models[1].ID) - require.Equal(t, summary1.Name, models[0].Name) - require.Equal(t, summary2.Name, models[1].Name) - require.Equal(t, summary1.DisplayName, models[0].FriendlyName) - require.Equal(t, summary2.DisplayName, models[1].FriendlyName) - require.Equal(t, summary1.InferenceTasks[0], models[0].Task) - require.Empty(t, models[1].Task) + require.Equal(t, summary1.ID, models[0].ID) + require.Equal(t, summary2.ID, models[1].ID) + require.Equal(t, "gpt-4.1", models[0].Name) + require.Equal(t, "gpt-4.1-mini", models[1].Name) + require.Equal(t, summary1.Name, models[0].FriendlyName) + require.Equal(t, summary2.Name, models[1].FriendlyName) + require.Equal(t, "chat-completion", models[0].Task) + require.Equal(t, "chat-completion", models[1].Task) require.Equal(t, summary1.Publisher, models[0].Publisher) require.Equal(t, summary2.Publisher, models[1].Publisher) require.Equal(t, summary1.Summary, models[0].Summary) require.Equal(t, summary2.Summary, models[1].Summary) - require.Equal(t, summary1.Version, models[0].Version) - require.Equal(t, summary2.Version, models[1].Version) - require.Equal(t, summary1.RegistryName, models[0].RegistryName) - require.Equal(t, summary2.RegistryName, models[1].RegistryName) + require.Equal(t, "1", models[0].Version) + require.Equal(t, "2", models[1].Version) }) t.Run("handles non-OK status", func(t *testing.T) { diff --git a/internal/azuremodels/model_details.go b/internal/azuremodels/model_details.go index 53289cf0..ba715f76 100644 --- a/internal/azuremodels/model_details.go +++ b/internal/azuremodels/model_details.go @@ -2,8 +2,6 @@ package azuremodels import ( "fmt" - - "github.com/github/gh-models/internal/modelkey" ) // ModelDetails includes detailed information about a model. @@ -26,8 +24,3 @@ type ModelDetails struct { func (m *ModelDetails) ContextLimits() string { return fmt.Sprintf("up to %d input tokens and %d output tokens", m.MaxInputTokens, m.MaxOutputTokens) } - -// FormatIdentifier formats the model identifier based on the publisher and model name. -func FormatIdentifier(publisher, name string) string { - return modelkey.FormatIdentifier("azureml", publisher, name) -} diff --git a/internal/azuremodels/model_details_test.go b/internal/azuremodels/model_details_test.go index ae795327..8a41f062 100644 --- a/internal/azuremodels/model_details_test.go +++ b/internal/azuremodels/model_details_test.go @@ -12,12 +12,4 @@ func TestModelDetails(t *testing.T) { result := details.ContextLimits() require.Equal(t, "up to 123 input tokens and 456 output tokens", result) }) - - t.Run("FormatIdentifier", func(t *testing.T) { - publisher := "Open AI" - name := "GPT 3" - expected := "open-ai/gpt-3" - result := FormatIdentifier(publisher, name) - require.Equal(t, expected, result) - }) } diff --git a/internal/azuremodels/model_summary.go b/internal/azuremodels/model_summary.go index 53076654..4872b37c 100644 --- a/internal/azuremodels/model_summary.go +++ b/internal/azuremodels/model_summary.go @@ -1,6 +1,7 @@ package azuremodels import ( + "fmt" "slices" "sort" "strings" @@ -10,12 +11,12 @@ import ( type ModelSummary struct { ID string `json:"id"` Name string `json:"name"` + Registry string `json:"registry"` FriendlyName string `json:"friendly_name"` Task string `json:"task"` Publisher string `json:"publisher"` Summary string `json:"summary"` Version string `json:"version"` - RegistryName string `json:"registry_name"` } // IsChatModel returns true if the model is for chat completions. @@ -25,8 +26,7 @@ func (m *ModelSummary) IsChatModel() bool { // HasName checks if the model has the given name. func (m *ModelSummary) HasName(name string) bool { - modelID := FormatIdentifier(m.Publisher, m.Name) - return strings.EqualFold(modelID, name) + return strings.EqualFold(m.ID, name) } var ( @@ -50,8 +50,8 @@ func SortModels(models []*ModelSummary) { // Otherwise, sort by friendly name // Note: sometimes the casing returned by the API is inconsistent, so sort using lowercase values. - idI := FormatIdentifier(models[i].Publisher, models[i].Name) - idJ := FormatIdentifier(models[j].Publisher, models[j].Name) + idI := strings.ToLower(fmt.Sprintf("%s/%s", models[i].Publisher, models[i].Name)) + idJ := strings.ToLower(fmt.Sprintf("%s/%s", models[j].Publisher, models[j].Name)) return idI < idJ }) diff --git a/internal/azuremodels/model_summary_test.go b/internal/azuremodels/model_summary_test.go index 978da7ee..2d122640 100644 --- a/internal/azuremodels/model_summary_test.go +++ b/internal/azuremodels/model_summary_test.go @@ -18,9 +18,9 @@ func TestModelSummary(t *testing.T) { }) t.Run("HasName", func(t *testing.T) { - model := &ModelSummary{Name: "foo123", Publisher: "bar"} + model := &ModelSummary{ID: "bar/foo123", Name: "foo123", Publisher: "bar"} - require.True(t, model.HasName(FormatIdentifier(model.Publisher, model.Name))) + require.True(t, model.HasName(model.ID)) require.True(t, model.HasName("BaR/foO123")) require.False(t, model.HasName("completely different value")) require.False(t, model.HasName("foo")) @@ -28,9 +28,9 @@ func TestModelSummary(t *testing.T) { }) t.Run("SortModels sorts given slice in-place by publisher/name", func(t *testing.T) { - modelA := &ModelSummary{Publisher: "a", Name: "z"} - modelB := &ModelSummary{Publisher: "a", Name: "Y"} - modelC := &ModelSummary{Publisher: "b", Name: "x"} + modelA := &ModelSummary{ID: "a/z", Publisher: "a", Name: "z", FriendlyName: "z"} + modelB := &ModelSummary{ID: "a/Y", Publisher: "a", Name: "Y", FriendlyName: "Y"} + modelC := &ModelSummary{ID: "b/x", Publisher: "b", Name: "x", FriendlyName: "x"} models := []*ModelSummary{modelC, modelB, modelA} SortModels(models) diff --git a/internal/azuremodels/types.go b/internal/azuremodels/types.go index 32a93096..c2221ee3 100644 --- a/internal/azuremodels/types.go +++ b/internal/azuremodels/types.go @@ -1,8 +1,6 @@ package azuremodels import ( - "encoding/json" - "github.com/github/gh-models/internal/sse" ) @@ -70,20 +68,21 @@ type ChatCompletionResponse struct { Reader sse.Reader[ChatCompletion] } -type modelCatalogSearchResponse struct { - Summaries []modelCatalogSearchSummary `json:"summaries"` -} - -type modelCatalogSearchSummary struct { - AssetID string `json:"assetId"` - DisplayName string `json:"displayName"` - InferenceTasks []string `json:"inferenceTasks"` - Name string `json:"name"` - Popularity json.Number `json:"popularity"` - Publisher string `json:"publisher"` - RegistryName string `json:"registryName"` - Version string `json:"version"` - Summary string `json:"summary"` +// GitHub Models API response types +type githubModelCatalogResponse []githubModelSummary + +type githubModelSummary struct { + ID string `json:"id"` + Name string `json:"name"` + Version string `json:"version"` + Publisher string `json:"publisher"` + Registry string `json:"registry"` + HtmlURL string `json:"html_url"` + Summary string `json:"summary"` + RateLimitTier string `json:"rate_limit_tier"` + SupportedInputModalities []string `json:"supported_input_modalities"` + SupportedOutputModalities []string `json:"supported_output_modalities"` + Tags []string `json:"tags"` } type modelCatalogTextLimits struct { From f560a7f73d8939cbbab04dcdf67fe01cbfcfd108 Mon Sep 17 00:00:00 2001 From: Christopher Schleiden Date: Thu, 17 Jul 2025 14:43:55 -0700 Subject: [PATCH 3/3] Use updated catalog url --- internal/azuremodels/azure_client_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/azuremodels/azure_client_config.go b/internal/azuremodels/azure_client_config.go index da8eae04..cbc8fa6f 100644 --- a/internal/azuremodels/azure_client_config.go +++ b/internal/azuremodels/azure_client_config.go @@ -4,7 +4,7 @@ const ( defaultInferenceRoot = "https://models.github.ai" defaultInferencePath = "inference/chat/completions" defaultAzureAiStudioURL = "https://api.catalog.azureml.ms" - defaultModelsURL = defaultAzureAiStudioURL + "/asset-gallery/v1.0/models" + defaultModelsURL = "https://models.github.ai/catalog/models" ) // AzureClientConfig represents configurable settings for the Azure client.