From ce4cb820f72591d58ea78d1c0d955a7ca50a0217 Mon Sep 17 00:00:00 2001 From: adamdottv <2363879+adamdottv@users.noreply.github.com> Date: Thu, 10 Jul 2025 09:53:18 -0500 Subject: feat(tui): modes --- packages/tui/sdk/.stats.yml | 8 ++--- packages/tui/sdk/api.md | 2 ++ packages/tui/sdk/app.go | 56 +++++++++++++++++++++++++++++ packages/tui/sdk/app_test.go | 22 ++++++++++++ packages/tui/sdk/config.go | 78 +++++++++++++++++++++++++++++++++++++++- packages/tui/sdk/session.go | 53 +++++++++++++++------------ packages/tui/sdk/session_test.go | 6 ++-- 7 files changed, 196 insertions(+), 29 deletions(-) (limited to 'packages/tui/sdk') diff --git a/packages/tui/sdk/.stats.yml b/packages/tui/sdk/.stats.yml index e3d985793..225a0e490 100644 --- a/packages/tui/sdk/.stats.yml +++ b/packages/tui/sdk/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 21 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-879570c29c56e0a73a0624a84662b7f7c319a3c790c78ec6ac4cf62a7b1a5bd0.yml -openapi_spec_hash: 2432e2dfed22193a0c6b3dfe0f82ec7d -config_hash: 53e3aeb355f3b2e0d10985d6d7635a7e +configured_endpoints: 22 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-37247433660e125f9a79ff173d8007f13192d28a40f4e599e002446a6ed0c128.yml +openapi_spec_hash: 8095ebe2d88259381a58e7b0c87244c4 +config_hash: 589ec6a935a43a3c49a325ece86cbda2 diff --git a/packages/tui/sdk/api.md b/packages/tui/sdk/api.md index c0304614a..15bdcfa93 100644 --- a/packages/tui/sdk/api.md +++ b/packages/tui/sdk/api.md @@ -20,12 +20,14 @@ Response Types: - opencode.App - opencode.LogLevel +- opencode.Mode Methods: - client.App.Get(ctx context.Context) (opencode.App, error) - client.App.Init(ctx context.Context) (bool, error) - client.App.Log(ctx context.Context, body opencode.AppLogParams) (bool, error) +- client.App.Modes(ctx context.Context) ([]opencode.Mode, error) # Find diff --git a/packages/tui/sdk/app.go b/packages/tui/sdk/app.go index ba9303c80..09d8cbf39 100644 --- a/packages/tui/sdk/app.go +++ b/packages/tui/sdk/app.go @@ -55,6 +55,14 @@ func (r *AppService) Log(ctx context.Context, body AppLogParams, opts ...option. return } +// List all modes +func (r *AppService) Modes(ctx context.Context, opts ...option.RequestOption) (res *[]Mode, err error) { + opts = append(r.Options[:], opts...) + path := "mode" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return +} + type App struct { Git bool `json:"git,required"` Hostname string `json:"hostname,required"` @@ -149,6 +157,54 @@ func (r LogLevel) IsKnown() bool { return false } +type Mode struct { + Name string `json:"name,required"` + Tools map[string]bool `json:"tools,required"` + Model ModeModel `json:"model"` + Prompt string `json:"prompt"` + JSON modeJSON `json:"-"` +} + +// modeJSON contains the JSON metadata for the struct [Mode] +type modeJSON struct { + Name apijson.Field + Tools apijson.Field + Model apijson.Field + Prompt apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *Mode) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r modeJSON) RawJSON() string { + return r.raw +} + +type ModeModel struct { + ModelID string `json:"modelID,required"` + ProviderID string `json:"providerID,required"` + JSON modeModelJSON `json:"-"` +} + +// modeModelJSON contains the JSON metadata for the struct [ModeModel] +type modeModelJSON struct { + ModelID apijson.Field + ProviderID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ModeModel) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r modeModelJSON) RawJSON() string { + return r.raw +} + type AppLogParams struct { // Log level Level param.Field[AppLogParamsLevel] `json:"level,required"` diff --git a/packages/tui/sdk/app_test.go b/packages/tui/sdk/app_test.go index 15f531ad4..8028f2c53 100644 --- a/packages/tui/sdk/app_test.go +++ b/packages/tui/sdk/app_test.go @@ -85,3 +85,25 @@ func TestAppLogWithOptionalParams(t *testing.T) { t.Fatalf("err should be nil: %s", err.Error()) } } + +func TestAppModes(t *testing.T) { + t.Skip("skipped: tests are disabled for the time being") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := opencode.NewClient( + option.WithBaseURL(baseURL), + ) + _, err := client.App.Modes(context.TODO()) + if err != nil { + var apierr *opencode.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/packages/tui/sdk/config.go b/packages/tui/sdk/config.go index d6dc65f25..59c4e62cf 100644 --- a/packages/tui/sdk/config.go +++ b/packages/tui/sdk/config.go @@ -65,7 +65,8 @@ type Config struct { // Minimum log level to write to log files LogLevel LogLevel `json:"log_level"` // MCP (Model Context Protocol) server configurations - Mcp map[string]ConfigMcp `json:"mcp"` + Mcp map[string]ConfigMcp `json:"mcp"` + Mode ConfigMode `json:"mode"` // Model to use in the format of provider/model, eg anthropic/claude-2 Model string `json:"model"` // Custom provider configurations and model overrides @@ -86,6 +87,7 @@ type configJSON struct { Keybinds apijson.Field LogLevel apijson.Field Mcp apijson.Field + Mode apijson.Field Model apijson.Field Provider apijson.Field Theme apijson.Field @@ -276,6 +278,77 @@ func (r ConfigMcpType) IsKnown() bool { return false } +type ConfigMode struct { + Build ConfigModeBuild `json:"build"` + Plan ConfigModePlan `json:"plan"` + ExtraFields map[string]ConfigMode `json:"-,extras"` + JSON configModeJSON `json:"-"` +} + +// configModeJSON contains the JSON metadata for the struct [ConfigMode] +type configModeJSON struct { + Build apijson.Field + Plan apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigMode) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configModeJSON) RawJSON() string { + return r.raw +} + +type ConfigModeBuild struct { + Model string `json:"model"` + Prompt string `json:"prompt"` + Tools map[string]bool `json:"tools"` + JSON configModeBuildJSON `json:"-"` +} + +// configModeBuildJSON contains the JSON metadata for the struct [ConfigModeBuild] +type configModeBuildJSON struct { + Model apijson.Field + Prompt apijson.Field + Tools apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigModeBuild) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configModeBuildJSON) RawJSON() string { + return r.raw +} + +type ConfigModePlan struct { + Model string `json:"model"` + Prompt string `json:"prompt"` + Tools map[string]bool `json:"tools"` + JSON configModePlanJSON `json:"-"` +} + +// configModePlanJSON contains the JSON metadata for the struct [ConfigModePlan] +type configModePlanJSON struct { + Model apijson.Field + Prompt apijson.Field + Tools apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigModePlan) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configModePlanJSON) RawJSON() string { + return r.raw +} + type ConfigProvider struct { Models map[string]ConfigProviderModel `json:"models,required"` ID string `json:"id"` @@ -460,6 +533,8 @@ type Keybinds struct { SessionShare string `json:"session_share,required"` // Unshare current session SessionUnshare string `json:"session_unshare,required"` + // Switch mode + SwitchMode string `json:"switch_mode,required"` // List available themes ThemeList string `json:"theme_list,required"` // Toggle tool details @@ -500,6 +575,7 @@ type keybindsJSON struct { SessionNew apijson.Field SessionShare apijson.Field SessionUnshare apijson.Field + SwitchMode apijson.Field ThemeList apijson.Field ToolDetails apijson.Field raw string diff --git a/packages/tui/sdk/session.go b/packages/tui/sdk/session.go index fc55c6912..1f19b97f5 100644 --- a/packages/tui/sdk/session.go +++ b/packages/tui/sdk/session.go @@ -439,11 +439,12 @@ type AssistantMessagePart struct { Type AssistantMessagePartType `json:"type,required"` ID string `json:"id"` // This field can have the runtime type of [ToolPartState]. - State interface{} `json:"state"` - Text string `json:"text"` - Tool string `json:"tool"` - JSON assistantMessagePartJSON `json:"-"` - union AssistantMessagePartUnion + State interface{} `json:"state"` + Synthetic bool `json:"synthetic"` + Text string `json:"text"` + Tool string `json:"tool"` + JSON assistantMessagePartJSON `json:"-"` + union AssistantMessagePartUnion } // assistantMessagePartJSON contains the JSON metadata for the struct @@ -452,6 +453,7 @@ type assistantMessagePartJSON struct { Type apijson.Field ID apijson.Field State apijson.Field + Synthetic apijson.Field Text apijson.Field Tool apijson.Field raw string @@ -815,15 +817,17 @@ func (r StepStartPartType) IsKnown() bool { } type TextPart struct { - Text string `json:"text,required"` - Type TextPartType `json:"type,required"` - JSON textPartJSON `json:"-"` + Text string `json:"text,required"` + Type TextPartType `json:"type,required"` + Synthetic bool `json:"synthetic"` + JSON textPartJSON `json:"-"` } // textPartJSON contains the JSON metadata for the struct [TextPart] type textPartJSON struct { Text apijson.Field Type apijson.Field + Synthetic apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -855,8 +859,9 @@ func (r TextPartType) IsKnown() bool { } type TextPartParam struct { - Text param.Field[string] `json:"text,required"` - Type param.Field[TextPartType] `json:"type,required"` + Text param.Field[string] `json:"text,required"` + Type param.Field[TextPartType] `json:"type,required"` + Synthetic param.Field[bool] `json:"synthetic"` } func (r TextPartParam) MarshalJSON() (data []byte, err error) { @@ -1311,13 +1316,14 @@ func (r userMessageTimeJSON) RawJSON() string { } type UserMessagePart struct { - Type UserMessagePartType `json:"type,required"` - Filename string `json:"filename"` - Mime string `json:"mime"` - Text string `json:"text"` - URL string `json:"url"` - JSON userMessagePartJSON `json:"-"` - union UserMessagePartUnion + Type UserMessagePartType `json:"type,required"` + Filename string `json:"filename"` + Mime string `json:"mime"` + Synthetic bool `json:"synthetic"` + Text string `json:"text"` + URL string `json:"url"` + JSON userMessagePartJSON `json:"-"` + union UserMessagePartUnion } // userMessagePartJSON contains the JSON metadata for the struct [UserMessagePart] @@ -1325,6 +1331,7 @@ type userMessagePartJSON struct { Type apijson.Field Filename apijson.Field Mime apijson.Field + Synthetic apijson.Field Text apijson.Field URL apijson.Field raw string @@ -1390,11 +1397,12 @@ func (r UserMessagePartType) IsKnown() bool { } type UserMessagePartParam struct { - Type param.Field[UserMessagePartType] `json:"type,required"` - Filename param.Field[string] `json:"filename"` - Mime param.Field[string] `json:"mime"` - Text param.Field[string] `json:"text"` - URL param.Field[string] `json:"url"` + Type param.Field[UserMessagePartType] `json:"type,required"` + Filename param.Field[string] `json:"filename"` + Mime param.Field[string] `json:"mime"` + Synthetic param.Field[bool] `json:"synthetic"` + Text param.Field[string] `json:"text"` + URL param.Field[string] `json:"url"` } func (r UserMessagePartParam) MarshalJSON() (data []byte, err error) { @@ -1409,6 +1417,7 @@ type UserMessagePartUnionParam interface { } type SessionChatParams struct { + Mode param.Field[string] `json:"mode,required"` ModelID param.Field[string] `json:"modelID,required"` Parts param.Field[[]UserMessagePartUnionParam] `json:"parts,required"` ProviderID param.Field[string] `json:"providerID,required"` diff --git a/packages/tui/sdk/session_test.go b/packages/tui/sdk/session_test.go index 15137e62c..4ff2818c5 100644 --- a/packages/tui/sdk/session_test.go +++ b/packages/tui/sdk/session_test.go @@ -117,10 +117,12 @@ func TestSessionChat(t *testing.T) { context.TODO(), "id", opencode.SessionChatParams{ + Mode: opencode.F("mode"), ModelID: opencode.F("modelID"), Parts: opencode.F([]opencode.UserMessagePartUnionParam{opencode.TextPartParam{ - Text: opencode.F("text"), - Type: opencode.F(opencode.TextPartTypeText), + Text: opencode.F("text"), + Type: opencode.F(opencode.TextPartTypeText), + Synthetic: opencode.F(true), }}), ProviderID: opencode.F("providerID"), }, -- cgit v1.2.3