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