feat(tui): modes

This commit is contained in:
adamdottv
2025-07-10 09:53:18 -05:00
parent ba5be6b625
commit ce4cb820f7
20 changed files with 430 additions and 87 deletions

View File

@@ -23,11 +23,15 @@ import (
type App struct {
Info opencode.App
Modes []opencode.Mode
Providers []opencode.Provider
Version string
StatePath string
Config *opencode.Config
Client *opencode.Client
State *config.State
ModeIndex int
Mode *opencode.Mode
Provider *opencode.Provider
Model *opencode.Model
Session *opencode.Session
@@ -64,6 +68,7 @@ func New(
ctx context.Context,
version string,
appInfo opencode.App,
modes []opencode.Mode,
httpClient *opencode.Client,
model *string,
prompt *string,
@@ -87,14 +92,33 @@ func New(
config.SaveState(appStatePath, appState)
}
if appState.ModeModel == nil {
appState.ModeModel = make(map[string]config.ModeModel)
}
if configInfo.Theme != "" {
appState.Theme = configInfo.Theme
}
if configInfo.Model != "" {
splits := strings.Split(configInfo.Model, "/")
appState.Provider = splits[0]
appState.Model = strings.Join(splits[1:], "/")
var modeIndex int
var mode *opencode.Mode
modeName := "build"
if appState.Mode != "" {
modeName = appState.Mode
}
for i, m := range modes {
if m.Name == modeName {
modeIndex = i
break
}
}
mode = &modes[modeIndex]
if mode.Model.ModelID != "" {
appState.ModeModel[mode.Name] = config.ModeModel{
ProviderID: mode.Model.ProviderID,
ModelID: mode.Model.ModelID,
}
}
if err := theme.LoadThemesFromDirectories(
@@ -119,11 +143,14 @@ func New(
app := &App{
Info: appInfo,
Modes: modes,
Version: version,
StatePath: appStatePath,
Config: configInfo,
State: appState,
Client: httpClient,
ModeIndex: modeIndex,
Mode: mode,
Session: &opencode.Session{},
Messages: []opencode.MessageUnion{},
Commands: commands.LoadFromConfig(configInfo),
@@ -162,6 +189,45 @@ func (a *App) SetClipboard(text string) tea.Cmd {
return tea.Sequence(cmds...)
}
func (a *App) SwitchMode() (*App, tea.Cmd) {
a.ModeIndex++
if a.ModeIndex >= len(a.Modes) {
a.ModeIndex = 0
}
a.Mode = &a.Modes[a.ModeIndex]
modelID := a.Mode.Model.ModelID
providerID := a.Mode.Model.ProviderID
if modelID == "" {
if model, ok := a.State.ModeModel[a.Mode.Name]; ok {
modelID = model.ModelID
providerID = model.ProviderID
}
}
if modelID != "" {
for _, provider := range a.Providers {
if provider.ID == providerID {
a.Provider = &provider
for _, model := range provider.Models {
if model.ID == modelID {
a.Model = &model
break
}
}
break
}
}
}
a.State.Mode = a.Mode.Name
return a, func() tea.Msg {
a.SaveState()
return nil
}
}
func (a *App) InitializeProvider() tea.Cmd {
providersResponse, err := a.Client.Config.Providers(context.Background())
if err != nil {
@@ -198,6 +264,14 @@ func (a *App) InitializeProvider() tea.Cmd {
return nil
}
a.Providers = providers
// retains backwards compatibility with old state format
if model, ok := a.State.ModeModel[a.State.Mode]; ok {
a.State.Provider = model.ProviderID
a.State.Model = model.ModelID
}
var currentProvider *opencode.Provider
var currentModel *opencode.Model
for _, provider := range providers {
@@ -322,10 +396,14 @@ func (a *App) CompactSession(ctx context.Context) tea.Cmd {
a.compactCancel = nil
}()
_, err := a.Client.Session.Summarize(compactCtx, a.Session.ID, opencode.SessionSummarizeParams{
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
})
_, err := a.Client.Session.Summarize(
compactCtx,
a.Session.ID,
opencode.SessionSummarizeParams{
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
},
)
if err != nil {
if compactCtx.Err() != context.Canceled {
slog.Error("Failed to compact session", "error", err)
@@ -417,6 +495,7 @@ func (a *App) SendChatMessage(
Parts: opencode.F(parts),
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
Mode: opencode.F(a.Mode.Name),
})
if err != nil {
errormsg := fmt.Sprintf("failed to send message: %v", err)