summaryrefslogtreecommitdiffhomepage
path: root/packages/tui/internal/app
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-06-27 07:46:42 -0500
committeradamdottv <[email protected]>2025-06-27 14:26:25 -0500
commit79bbf90b727f35915e665b99ba13f260b0dc94fe (patch)
tree4ee5e4d79635429a45b9035955323e3e03078e78 /packages/tui/internal/app
parent226a4a7f3610860d437ddf8d7d8216e909297418 (diff)
downloadopencode-79bbf90b727f35915e665b99ba13f260b0dc94fe.tar.gz
opencode-79bbf90b727f35915e665b99ba13f260b0dc94fe.zip
chore: rework openapi spec and use stainless sdk
Diffstat (limited to 'packages/tui/internal/app')
-rw-r--r--packages/tui/internal/app/app.go235
1 files changed, 88 insertions, 147 deletions
diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go
index e8775921a..3bd48f02a 100644
--- a/packages/tui/internal/app/app.go
+++ b/packages/tui/internal/app/app.go
@@ -11,35 +11,35 @@ import (
"log/slog"
tea "github.com/charmbracelet/bubbletea/v2"
+ "github.com/sst/opencode-sdk-go"
"github.com/sst/opencode/internal/commands"
"github.com/sst/opencode/internal/components/toast"
"github.com/sst/opencode/internal/config"
"github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme"
"github.com/sst/opencode/internal/util"
- "github.com/sst/opencode/pkg/client"
)
var RootPath string
type App struct {
- Info client.AppInfo
+ Info opencode.App
Version string
StatePath string
- Config *client.ConfigInfo
- Client *client.ClientWithResponses
+ Config *opencode.Config
+ Client *opencode.Client
State *config.State
- Provider *client.ProviderInfo
- Model *client.ModelInfo
- Session *client.SessionInfo
- Messages []client.MessageInfo
+ Provider *opencode.Provider
+ Model *opencode.Model
+ Session *opencode.Session
+ Messages []opencode.Message
Commands commands.CommandRegistry
}
-type SessionSelectedMsg = *client.SessionInfo
+type SessionSelectedMsg = *opencode.Session
type ModelSelectedMsg struct {
- Provider client.ProviderInfo
- Model client.ModelInfo
+ Provider opencode.Provider
+ Model opencode.Model
}
type SessionClearedMsg struct{}
type CompactSessionMsg struct{}
@@ -51,31 +51,24 @@ type CompletionDialogTriggeredMsg struct {
InitialValue string
}
type OptimisticMessageAddedMsg struct {
- Message client.MessageInfo
+ Message opencode.Message
}
func New(
ctx context.Context,
version string,
- appInfo client.AppInfo,
- httpClient *client.ClientWithResponses,
+ appInfo opencode.App,
+ httpClient *opencode.Client,
) (*App, error) {
RootPath = appInfo.Path.Root
- configResponse, err := httpClient.PostConfigGetWithResponse(ctx)
+ configInfo, err := httpClient.Config.Get(ctx)
if err != nil {
return nil, err
}
- if configResponse.StatusCode() != 200 || configResponse.JSON200 == nil {
- return nil, fmt.Errorf("failed to get config: %d", configResponse.StatusCode())
- }
- configInfo := configResponse.JSON200
- if configInfo.Keybinds == nil {
- leader := "ctrl+x"
- keybinds := client.ConfigKeybinds{
- Leader: &leader,
- }
- configInfo.Keybinds = &keybinds
+
+ if configInfo.Keybinds.Leader == "" {
+ configInfo.Keybinds.Leader = "ctrl+x"
}
appStatePath := filepath.Join(appInfo.Path.State, "tui")
@@ -85,16 +78,16 @@ func New(
config.SaveState(appStatePath, appState)
}
- if configInfo.Theme != nil {
- appState.Theme = *configInfo.Theme
+ if configInfo.Theme != "" {
+ appState.Theme = configInfo.Theme
}
- if configInfo.Model != nil {
- splits := strings.Split(*configInfo.Model, "/")
+
+ if configInfo.Model != "" {
+ splits := strings.Split(configInfo.Model, "/")
appState.Provider = splits[0]
appState.Model = strings.Join(splits[1:], "/")
}
- // Load themes from all directories
if err := theme.LoadThemesFromDirectories(
appInfo.Path.Config,
appInfo.Path.Root,
@@ -122,8 +115,8 @@ func New(
Config: configInfo,
State: appState,
Client: httpClient,
- Session: &client.SessionInfo{},
- Messages: []client.MessageInfo{},
+ Session: &opencode.Session{},
+ Messages: []opencode.Message{},
Commands: commands.LoadFromConfig(configInfo),
}
@@ -132,23 +125,19 @@ func New(
func (a *App) InitializeProvider() tea.Cmd {
return func() tea.Msg {
- providersResponse, err := a.Client.PostProviderListWithResponse(context.Background())
+ providersResponse, err := a.Client.Config.Providers(context.Background())
if err != nil {
slog.Error("Failed to list providers", "error", err)
// TODO: notify user
return nil
}
- if providersResponse != nil && providersResponse.StatusCode() != 200 {
- slog.Error("failed to retrieve providers", "status", providersResponse.StatusCode(), "message", string(providersResponse.Body))
- return nil
- }
- providers := []client.ProviderInfo{}
- var defaultProvider *client.ProviderInfo
- var defaultModel *client.ModelInfo
+ providers := providersResponse.Providers
+ var defaultProvider *opencode.Provider
+ var defaultModel *opencode.Model
- var anthropic *client.ProviderInfo
- for _, provider := range providersResponse.JSON200.Providers {
- if provider.Id == "anthropic" {
+ var anthropic *opencode.Provider
+ for _, provider := range providers {
+ if provider.ID == "anthropic" {
anthropic = &provider
}
}
@@ -159,7 +148,7 @@ func (a *App) InitializeProvider() tea.Cmd {
defaultModel = getDefaultModel(providersResponse, *anthropic)
}
- for _, provider := range providersResponse.JSON200.Providers {
+ for _, provider := range providers {
if defaultProvider == nil || defaultModel == nil {
defaultProvider = &provider
defaultModel = getDefaultModel(providersResponse, provider)
@@ -171,14 +160,14 @@ func (a *App) InitializeProvider() tea.Cmd {
return nil
}
- var currentProvider *client.ProviderInfo
- var currentModel *client.ModelInfo
+ var currentProvider *opencode.Provider
+ var currentModel *opencode.Model
for _, provider := range providers {
- if provider.Id == a.State.Provider {
+ if provider.ID == a.State.Provider {
currentProvider = &provider
for _, model := range provider.Models {
- if model.Id == a.State.Model {
+ if model.ID == a.State.Model {
currentModel = &model
}
}
@@ -189,7 +178,6 @@ func (a *App) InitializeProvider() tea.Cmd {
currentModel = defaultModel
}
- // TODO: handle no provider or model setup, yet
return ModelSelectedMsg{
Provider: *currentProvider,
Model: *currentModel,
@@ -197,8 +185,8 @@ func (a *App) InitializeProvider() tea.Cmd {
}
}
-func getDefaultModel(response *client.PostProviderListResponse, provider client.ProviderInfo) *client.ModelInfo {
- if match, ok := response.JSON200.Default[provider.Id]; ok {
+func getDefaultModel(response *opencode.ConfigProvidersResponse, provider opencode.Provider) *opencode.Model {
+ if match, ok := response.Default[provider.ID]; ok {
model := provider.Models[match]
return &model
} else {
@@ -222,7 +210,7 @@ func (a *App) IsBusy() bool {
}
lastMessage := a.Messages[len(a.Messages)-1]
- return lastMessage.Metadata.Time.Completed == nil
+ return lastMessage.Metadata.Time.Completed == 0
}
func (a *App) SaveState() {
@@ -245,19 +233,14 @@ func (a *App) InitializeProject(ctx context.Context) tea.Cmd {
cmds = append(cmds, util.CmdHandler(SessionSelectedMsg(session)))
go func() {
- response, err := a.Client.PostSessionInitialize(ctx, client.PostSessionInitializeJSONRequestBody{
- SessionID: a.Session.Id,
- ProviderID: a.Provider.Id,
- ModelID: a.Model.Id,
+ _, err := a.Client.Session.Init(ctx, a.Session.ID, opencode.SessionInitParams{
+ ProviderID: opencode.F(a.Provider.ID),
+ ModelID: opencode.F(a.Model.ID),
})
if err != nil {
slog.Error("Failed to initialize project", "error", err)
// status.Error(err.Error())
}
- if response != nil && response.StatusCode != 200 {
- slog.Error("Failed to initialize project", "error", response.StatusCode)
- // status.Error(fmt.Sprintf("failed to initialize project: %d", response.StatusCode))
- }
}()
return tea.Batch(cmds...)
@@ -265,48 +248,37 @@ func (a *App) InitializeProject(ctx context.Context) tea.Cmd {
func (a *App) CompactSession(ctx context.Context) tea.Cmd {
go func() {
- response, err := a.Client.PostSessionSummarizeWithResponse(ctx, client.PostSessionSummarizeJSONRequestBody{
- SessionID: a.Session.Id,
- ProviderID: a.Provider.Id,
- ModelID: a.Model.Id,
+ _, err := a.Client.Session.Summarize(ctx, a.Session.ID, opencode.SessionSummarizeParams{
+ ProviderID: opencode.F(a.Provider.ID),
+ ModelID: opencode.F(a.Model.ID),
})
if err != nil {
slog.Error("Failed to compact session", "error", err)
}
- if response != nil && response.StatusCode() != 200 {
- slog.Error("Failed to compact session", "error", response.StatusCode)
- }
}()
return nil
}
func (a *App) MarkProjectInitialized(ctx context.Context) error {
- response, err := a.Client.PostAppInitialize(ctx)
+ _, err := a.Client.App.Init(ctx)
if err != nil {
slog.Error("Failed to mark project as initialized", "error", err)
return err
}
- if response != nil && response.StatusCode != 200 {
- return fmt.Errorf("failed to initialize project: %d", response.StatusCode)
- }
return nil
}
-func (a *App) CreateSession(ctx context.Context) (*client.SessionInfo, error) {
- resp, err := a.Client.PostSessionCreateWithResponse(ctx)
+func (a *App) CreateSession(ctx context.Context) (*opencode.Session, error) {
+ session, err := a.Client.Session.New(ctx)
if err != nil {
return nil, err
}
- if resp != nil && resp.StatusCode() != 200 {
- return nil, fmt.Errorf("failed to create session: %d", resp.StatusCode())
- }
- session := resp.JSON200
return session, nil
}
func (a *App) SendChatMessage(ctx context.Context, text string, attachments []Attachment) tea.Cmd {
var cmds []tea.Cmd
- if a.Session.Id == "" {
+ if a.Session.ID == "" {
session, err := a.CreateSession(ctx)
if err != nil {
return toast.NewErrorToast(err.Error())
@@ -315,26 +287,18 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
cmds = append(cmds, util.CmdHandler(SessionSelectedMsg(session)))
}
- part := client.MessagePart{}
- part.FromMessagePartText(client.MessagePartText{
- Type: "text",
- Text: text,
- })
- parts := []client.MessagePart{part}
-
- optimisticMessage := client.MessageInfo{
- Id: fmt.Sprintf("optimistic-%d", time.Now().UnixNano()),
- Role: client.User,
- Parts: parts,
- Metadata: client.MessageMetadata{
- SessionID: a.Session.Id,
- Time: struct {
- Completed *float32 `json:"completed,omitempty"`
- Created float32 `json:"created"`
- }{
- Created: float32(time.Now().Unix()),
+ optimisticMessage := opencode.Message{
+ ID: fmt.Sprintf("optimistic-%d", time.Now().UnixNano()),
+ Role: opencode.MessageRoleUser,
+ Parts: []opencode.MessagePart{{
+ Type: opencode.MessagePartTypeText,
+ Text: text,
+ }},
+ Metadata: opencode.MessageMetadata{
+ SessionID: a.Session.ID,
+ Time: opencode.MessageMetadataTime{
+ Created: float64(time.Now().Unix()),
},
- Tool: make(map[string]client.MessageMetadata_Tool_AdditionalProperties),
},
}
@@ -342,22 +306,21 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
cmds = append(cmds, util.CmdHandler(OptimisticMessageAddedMsg{Message: optimisticMessage}))
cmds = append(cmds, func() tea.Msg {
- response, err := a.Client.PostSessionChat(ctx, client.PostSessionChatJSONRequestBody{
- SessionID: a.Session.Id,
- Parts: parts,
- ProviderID: a.Provider.Id,
- ModelID: a.Model.Id,
+ _, err := a.Client.Session.Chat(ctx, a.Session.ID, opencode.SessionChatParams{
+ Parts: opencode.F([]opencode.MessagePartUnionParam{
+ opencode.TextPartParam{
+ Type: opencode.F(opencode.TextPartTypeText),
+ Text: opencode.F(text),
+ },
+ }),
+ ProviderID: opencode.F(a.Provider.ID),
+ ModelID: opencode.F(a.Model.ID),
})
if err != nil {
errormsg := fmt.Sprintf("failed to send message: %v", err)
slog.Error(errormsg)
return toast.NewErrorToast(errormsg)()
}
- if response != nil && response.StatusCode != 200 {
- errormsg := fmt.Sprintf("failed to send message: %d", response.StatusCode)
- slog.Error(errormsg)
- return toast.NewErrorToast(errormsg)()
- }
return nil
})
@@ -367,83 +330,61 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
}
func (a *App) Cancel(ctx context.Context, sessionID string) error {
- response, err := a.Client.PostSessionAbort(ctx, client.PostSessionAbortJSONRequestBody{
- SessionID: sessionID,
- })
+ _, err := a.Client.Session.Abort(ctx, sessionID)
if err != nil {
slog.Error("Failed to cancel session", "error", err)
// status.Error(err.Error())
return err
}
- if response != nil && response.StatusCode != 200 {
- slog.Error("Failed to cancel session", "error", fmt.Sprintf("failed to cancel session: %d", response.StatusCode))
- // status.Error(fmt.Sprintf("failed to cancel session: %d", response.StatusCode))
- return fmt.Errorf("failed to cancel session: %d", response.StatusCode)
- }
return nil
}
-func (a *App) ListSessions(ctx context.Context) ([]client.SessionInfo, error) {
- resp, err := a.Client.PostSessionListWithResponse(ctx)
+func (a *App) ListSessions(ctx context.Context) ([]opencode.Session, error) {
+ response, err := a.Client.Session.List(ctx)
if err != nil {
return nil, err
}
- if resp.StatusCode() != 200 {
- return nil, fmt.Errorf("failed to list sessions: %d", resp.StatusCode())
- }
- if resp.JSON200 == nil {
- return []client.SessionInfo{}, nil
+ if response == nil {
+ return []opencode.Session{}, nil
}
- sessions := *resp.JSON200
-
+ sessions := *response
sort.Slice(sessions, func(i, j int) bool {
return sessions[i].Time.Created-sessions[j].Time.Created > 0
})
-
return sessions, nil
}
func (a *App) DeleteSession(ctx context.Context, sessionID string) error {
- resp, err := a.Client.PostSessionDeleteWithResponse(ctx, client.PostSessionDeleteJSONRequestBody{
- SessionID: sessionID,
- })
+ _, err := a.Client.Session.Delete(ctx, sessionID)
if err != nil {
+ slog.Error("Failed to delete session", "error", err)
return err
}
- if resp.StatusCode() != 200 {
- return fmt.Errorf("failed to delete session: %d", resp.StatusCode())
- }
return nil
}
-func (a *App) ListMessages(ctx context.Context, sessionId string) ([]client.MessageInfo, error) {
- resp, err := a.Client.PostSessionMessagesWithResponse(ctx, client.PostSessionMessagesJSONRequestBody{SessionID: sessionId})
+func (a *App) ListMessages(ctx context.Context, sessionId string) ([]opencode.Message, error) {
+ response, err := a.Client.Session.Messages(ctx, sessionId)
if err != nil {
return nil, err
}
- if resp.StatusCode() != 200 {
- return nil, fmt.Errorf("failed to list messages: %d", resp.StatusCode())
- }
- if resp.JSON200 == nil {
- return []client.MessageInfo{}, nil
+ if response == nil {
+ return []opencode.Message{}, nil
}
- messages := *resp.JSON200
+ messages := *response
return messages, nil
}
-func (a *App) ListProviders(ctx context.Context) ([]client.ProviderInfo, error) {
- resp, err := a.Client.PostProviderListWithResponse(ctx)
+func (a *App) ListProviders(ctx context.Context) ([]opencode.Provider, error) {
+ response, err := a.Client.Config.Providers(ctx)
if err != nil {
return nil, err
}
- if resp.StatusCode() != 200 {
- return nil, fmt.Errorf("failed to list sessions: %d", resp.StatusCode())
- }
- if resp.JSON200 == nil {
- return []client.ProviderInfo{}, nil
+ if response == nil {
+ return []opencode.Provider{}, nil
}
- providers := *resp.JSON200
+ providers := *response
return providers.Providers, nil
}