diff options
| author | Dax Raad <[email protected]> | 2025-06-05 14:59:07 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-06-05 14:59:16 -0400 |
| commit | db2bb32bcf0c3fdc8ede5530946e85a852448679 (patch) | |
| tree | 31f81b89cd8ed7b642a09e25fcb0a2a4b1c0e6bb /packages/tui | |
| parent | 1384a5e3e69522001571980f147a5aa0d985f895 (diff) | |
| download | opencode-db2bb32bcf0c3fdc8ede5530946e85a852448679.tar.gz opencode-db2bb32bcf0c3fdc8ede5530946e85a852448679.zip | |
integrate with models.dev
Diffstat (limited to 'packages/tui')
| -rw-r--r-- | packages/tui/cmd/opencode/main.go | 8 | ||||
| -rw-r--r-- | packages/tui/internal/app/app.go | 28 | ||||
| -rw-r--r-- | packages/tui/internal/components/core/status.go | 4 | ||||
| -rw-r--r-- | packages/tui/internal/components/dialog/models.go | 17 | ||||
| -rw-r--r-- | packages/tui/pkg/client/gen/openapi.json | 66 | ||||
| -rw-r--r-- | packages/tui/pkg/client/generated-client.go | 33 |
6 files changed, 98 insertions, 58 deletions
diff --git a/packages/tui/cmd/opencode/main.go b/packages/tui/cmd/opencode/main.go index 3d9dd2947..d2809aaea 100644 --- a/packages/tui/cmd/opencode/main.go +++ b/packages/tui/cmd/opencode/main.go @@ -23,7 +23,10 @@ func main() { slog.Error("Failed to create client", "error", err) os.Exit(1) } - paths, _ := httpClient.PostPathGetWithResponse(context.Background()) + paths, err := httpClient.PostPathGetWithResponse(context.Background()) + if err != nil { + panic(err) + } logfile := filepath.Join(paths.JSON200.Data, "log", "tui.log") if _, err := os.Stat(filepath.Dir(logfile)); os.IsNotExist(err) { @@ -48,8 +51,7 @@ func main() { app_, err := app.New(ctx, httpClient) if err != nil { - slog.Error("Failed to create app", "error", err) - // return err + panic(err) } // Set up the TUI diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go index d4b59c0b9..9ce5c2a66 100644 --- a/packages/tui/internal/app/app.go +++ b/packages/tui/internal/app/app.go @@ -43,18 +43,24 @@ func New(ctx context.Context, httpClient *client.ClientWithResponses) (*App, err appInfoResponse, _ := httpClient.PostAppInfoWithResponse(ctx) appInfo := appInfoResponse.JSON200 - providersResponse, _ := httpClient.PostProviderListWithResponse(ctx) + providersResponse, err := httpClient.PostProviderListWithResponse(ctx) + if err != nil { + return nil, err + } providers := []client.ProviderInfo{} var defaultProvider *client.ProviderInfo var defaultModel *client.ProviderModel - for _, provider := range *providersResponse.JSON200 { - if provider.Id == "anthropic" { - defaultProvider = &provider - - for _, model := range provider.Models { - if model.Id == "claude-sonnet-4-20250514" { + for i, provider := range providersResponse.JSON200.Providers { + if i == 0 || provider.Id == "anthropic" { + defaultProvider = &providersResponse.JSON200.Providers[i] + if match, ok := providersResponse.JSON200.Default[provider.Id]; ok { + model := defaultProvider.Models[match] + defaultModel = &model + } else { + for _, model := range provider.Models { defaultModel = &model + break } } } @@ -63,12 +69,6 @@ func New(ctx context.Context, httpClient *client.ClientWithResponses) (*App, err if len(providers) == 0 { return nil, fmt.Errorf("no providers found") } - if defaultProvider == nil { - defaultProvider = &providers[0] - } - if defaultModel == nil { - defaultModel = &defaultProvider.Models[0] - } appConfigPath := filepath.Join(appInfo.Path.Config, "tui.toml") appConfig, err := config.LoadConfig(appConfigPath) @@ -296,7 +296,7 @@ func (a *App) ListProviders(ctx context.Context) ([]client.ProviderInfo, error) } providers := *resp.JSON200 - return providers, nil + return providers.Providers, nil } // IsFilepickerOpen returns whether the filepicker is currently open diff --git a/packages/tui/internal/components/core/status.go b/packages/tui/internal/components/core/status.go index b631ce766..5c3e5eb3c 100644 --- a/packages/tui/internal/components/core/status.go +++ b/packages/tui/internal/components/core/status.go @@ -7,9 +7,9 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/pubsub" "github.com/sst/opencode/internal/status" - "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/theme" ) @@ -145,7 +145,7 @@ func (m statusCmp) View() string { if m.app.Session.Id != "" { tokens := float32(0) cost := float32(0) - contextWindow := m.app.Model.ContextWindow + contextWindow := m.app.Model.Limit.Context for _, message := range m.app.Messages { if message.Metadata.Assistant != nil { diff --git a/packages/tui/internal/components/dialog/models.go b/packages/tui/internal/components/dialog/models.go index a9dcb6f6c..5d0ee772b 100644 --- a/packages/tui/internal/components/dialog/models.go +++ b/packages/tui/internal/components/dialog/models.go @@ -3,6 +3,9 @@ package dialog import ( "context" "fmt" + "maps" + "slices" + "strings" "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" @@ -38,7 +41,6 @@ type modelDialogCmp struct { app *app.App availableProviders []client.ProviderInfo provider client.ProviderInfo - model *client.ProviderModel selectedIdx int width int @@ -144,7 +146,8 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.switchProvider(1) } case key.Matches(msg, modelKeys.Enter): - return m, util.CmdHandler(CloseModelDialogMsg{Provider: &m.provider, Model: &m.provider.Models[m.selectedIdx]}) + models := m.models() + return m, util.CmdHandler(CloseModelDialogMsg{Provider: &m.provider, Model: &models[m.selectedIdx]}) case key.Matches(msg, modelKeys.Escape): return m, util.CmdHandler(CloseModelDialogMsg{}) } @@ -156,6 +159,13 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } +func (m *modelDialogCmp) models() []client.ProviderModel { + models := slices.SortedFunc(maps.Values(m.provider.Models), func(a, b client.ProviderModel) int { + return strings.Compare(*a.Name, *b.Name) + }) + return models +} + // moveSelectionUp moves the selection up or wraps to bottom func (m *modelDialogCmp) moveSelectionUp() { if m.selectedIdx > 0 { @@ -218,13 +228,14 @@ func (m *modelDialogCmp) View() string { endIdx := min(m.scrollOffset+numVisibleModels, len(m.provider.Models)) modelItems := make([]string, 0, endIdx-m.scrollOffset) + models := m.models() for i := m.scrollOffset; i < endIdx; i++ { itemStyle := baseStyle.Width(maxDialogWidth) if i == m.selectedIdx { itemStyle = itemStyle.Background(t.Primary()). Foreground(t.Background()).Bold(true) } - modelItems = append(modelItems, itemStyle.Render(*m.provider.Models[i].Name)) + modelItems = append(modelItems, itemStyle.Render(*models[i].Name)) } scrollIndicator := m.getScrollIndicators(maxDialogWidth) diff --git a/packages/tui/pkg/client/gen/openapi.json b/packages/tui/pkg/client/gen/openapi.json index a9f19d4b3..f329b48b3 100644 --- a/packages/tui/pkg/client/gen/openapi.json +++ b/packages/tui/pkg/client/gen/openapi.json @@ -401,10 +401,25 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Provider.Info" - } + "type": "object", + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Provider.Info" + } + }, + "default": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "providers", + "default" + ] } } } @@ -1080,13 +1095,9 @@ "name": { "type": "string" }, - "options": { - "type": "object", - "additionalProperties": {} - }, "models": { - "type": "array", - "items": { + "type": "object", + "additionalProperties": { "$ref": "#/components/schemas/Provider.Model" } } @@ -1106,6 +1117,12 @@ "name": { "type": "string" }, + "attachment": { + "type": "boolean" + }, + "reasoning": { + "type": "boolean" + }, "cost": { "type": "object", "properties": { @@ -1129,24 +1146,27 @@ "outputCached" ] }, - "contextWindow": { - "type": "number" - }, - "maxOutputTokens": { - "type": "number" - }, - "attachment": { - "type": "boolean" - }, - "reasoning": { - "type": "boolean" + "limit": { + "type": "object", + "properties": { + "context": { + "type": "number" + }, + "output": { + "type": "number" + } + }, + "required": [ + "context", + "output" + ] } }, "required": [ "id", + "attachment", "cost", - "contextWindow", - "attachment" + "limit" ] } } diff --git a/packages/tui/pkg/client/generated-client.go b/packages/tui/pkg/client/generated-client.go index 1237685a9..247af33a7 100644 --- a/packages/tui/pkg/client/generated-client.go +++ b/packages/tui/pkg/client/generated-client.go @@ -203,26 +203,27 @@ type MessageToolInvocationToolResult struct { // ProviderInfo defines model for Provider.Info. type ProviderInfo struct { - Id string `json:"id"` - Models []ProviderModel `json:"models"` - Name string `json:"name"` - Options *map[string]interface{} `json:"options,omitempty"` + Id string `json:"id"` + Models map[string]ProviderModel `json:"models"` + Name string `json:"name"` } // ProviderModel defines model for Provider.Model. type ProviderModel struct { - Attachment bool `json:"attachment"` - ContextWindow float32 `json:"contextWindow"` - Cost struct { + Attachment bool `json:"attachment"` + Cost struct { Input float32 `json:"input"` InputCached float32 `json:"inputCached"` Output float32 `json:"output"` OutputCached float32 `json:"outputCached"` } `json:"cost"` - Id string `json:"id"` - MaxOutputTokens *float32 `json:"maxOutputTokens,omitempty"` - Name *string `json:"name,omitempty"` - Reasoning *bool `json:"reasoning,omitempty"` + Id string `json:"id"` + Limit struct { + Context float32 `json:"context"` + Output float32 `json:"output"` + } `json:"limit"` + Name *string `json:"name,omitempty"` + Reasoning *bool `json:"reasoning,omitempty"` } // PermissionInfo defines model for permission.info. @@ -1815,7 +1816,10 @@ func (r PostPathGetResponse) StatusCode() int { type PostProviderListResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]ProviderInfo + JSON200 *struct { + Default map[string]string `json:"default"` + Providers []ProviderInfo `json:"providers"` + } } // Status returns HTTPResponse.Status @@ -2299,7 +2303,10 @@ func ParsePostProviderListResponse(rsp *http.Response) (*PostProviderListRespons switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []ProviderInfo + var dest struct { + Default map[string]string `json:"default"` + Providers []ProviderInfo `json:"providers"` + } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } |
