diff options
| author | Dax <[email protected]> | 2025-08-07 16:32:12 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-07 16:32:12 -0400 |
| commit | c34aec060f2abb78486857b0e0d678cac52e2fab (patch) | |
| tree | 7d2b42a0c87ab016ffbc096e332b186ec4bce7ac /packages/sdk | |
| parent | 12f1ad521fef2e1fa6f1b0ce6ec939664d61899f (diff) | |
| download | opencode-c34aec060f2abb78486857b0e0d678cac52e2fab.tar.gz opencode-c34aec060f2abb78486857b0e0d678cac52e2fab.zip | |
Merge agent and mode into one (#1689)
The concept of mode has been deprecated, there is now only the agent field in the config.
An agent can be cycled through as your primary agent with <tab> or you can spawn a subagent by @ mentioning it. if you include a description of when to use it, the primary agent will try to automatically use it
Full docs here: https://opencode.ai/docs/agents/
Diffstat (limited to 'packages/sdk')
| -rw-r--r-- | packages/sdk/go/.stats.yml | 6 | ||||
| -rw-r--r-- | packages/sdk/go/api.md | 7 | ||||
| -rw-r--r-- | packages/sdk/go/app.go | 140 | ||||
| -rw-r--r-- | packages/sdk/go/app_test.go | 30 | ||||
| -rw-r--r-- | packages/sdk/go/config.go | 306 | ||||
| -rw-r--r-- | packages/sdk/go/internal/requestconfig/requestconfig.go | 8 | ||||
| -rw-r--r-- | packages/sdk/go/session.go | 146 | ||||
| -rw-r--r-- | packages/sdk/go/session_test.go | 2 | ||||
| -rw-r--r-- | packages/sdk/go/tui.go | 2 | ||||
| -rw-r--r-- | packages/sdk/stainless/stainless.yml | 6 |
10 files changed, 507 insertions, 146 deletions
diff --git a/packages/sdk/go/.stats.yml b/packages/sdk/go/.stats.yml index 013bb9ac2..a2023f0e4 100644 --- a/packages/sdk/go/.stats.yml +++ b/packages/sdk/go/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-52fd0b61e84fdc1cdd31ec12e1600510e9dd2f9d4fb20c2315b4975cb763ee98.yml -openapi_spec_hash: e851b8d5a2412f5fc9be82ab88ebdfde -config_hash: 11a6f0803eb407367c3f677d3e524c37 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-da1c340135c3dd6b1edb4e00e7039d2ac54d59271683a8b6ed528e51137ce41a.yml +openapi_spec_hash: 0cdd9b6273d72f5a6f484a2999ff0632 +config_hash: 7581d5948150d4ef7dd7b13d0845dbeb diff --git a/packages/sdk/go/api.md b/packages/sdk/go/api.md index 672460b99..d71951994 100644 --- a/packages/sdk/go/api.md +++ b/packages/sdk/go/api.md @@ -18,18 +18,18 @@ Methods: Response Types: +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a> -- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Model">Model</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Provider">Provider</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a> Methods: +- <code title="get /agent">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Agents">Agents</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="get /app">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /app/init">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /log">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Log">Log</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppLogParams">AppLogParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> -- <code title="get /mode">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Modes">Modes</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="get /config/providers">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Providers">Providers</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> # Find @@ -65,7 +65,6 @@ Response Types: - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#KeybindsConfig">KeybindsConfig</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpLocalConfig">McpLocalConfig</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpRemoteConfig">McpRemoteConfig</a> -- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ModeConfig">ModeConfig</a> Methods: @@ -75,6 +74,7 @@ Methods: Params Types: +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AgentPartInputParam">AgentPartInputParam</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePartInputParam">FilePartInputParam</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePartSourceUnionParam">FilePartSourceUnionParam</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePartSourceTextParam">FilePartSourceTextParam</a> @@ -84,6 +84,7 @@ Params Types: Response Types: +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AgentPart">AgentPart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePart">FilePart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePartSource">FilePartSource</a> diff --git a/packages/sdk/go/app.go b/packages/sdk/go/app.go index 0a7d14e72..3a0161a16 100644 --- a/packages/sdk/go/app.go +++ b/packages/sdk/go/app.go @@ -31,6 +31,14 @@ func NewAppService(opts ...option.RequestOption) (r *AppService) { return } +// List all agents +func (r *AppService) Agents(ctx context.Context, opts ...option.RequestOption) (res *[]Agent, err error) { + opts = append(r.Options[:], opts...) + path := "agent" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return +} + // Get app info func (r *AppService) Get(ctx context.Context, opts ...option.RequestOption) (res *App, err error) { opts = append(r.Options[:], opts...) @@ -55,14 +63,6 @@ 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 -} - // List all providers func (r *AppService) Providers(ctx context.Context, opts ...option.RequestOption) (res *AppProvidersResponse, err error) { opts = append(r.Options[:], opts...) @@ -71,6 +71,78 @@ func (r *AppService) Providers(ctx context.Context, opts ...option.RequestOption return } +type Agent struct { + Mode AgentMode `json:"mode,required"` + Name string `json:"name,required"` + Tools map[string]bool `json:"tools,required"` + Description string `json:"description"` + Model AgentModel `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + TopP float64 `json:"topP"` + JSON agentJSON `json:"-"` +} + +// agentJSON contains the JSON metadata for the struct [Agent] +type agentJSON struct { + Mode apijson.Field + Name apijson.Field + Tools apijson.Field + Description apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + TopP apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *Agent) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r agentJSON) RawJSON() string { + return r.raw +} + +type AgentMode string + +const ( + AgentModeSubagent AgentMode = "subagent" + AgentModePrimary AgentMode = "primary" + AgentModeAll AgentMode = "all" +) + +func (r AgentMode) IsKnown() bool { + switch r { + case AgentModeSubagent, AgentModePrimary, AgentModeAll: + return true + } + return false +} + +type AgentModel struct { + ModelID string `json:"modelID,required"` + ProviderID string `json:"providerID,required"` + JSON agentModelJSON `json:"-"` +} + +// agentModelJSON contains the JSON metadata for the struct [AgentModel] +type agentModelJSON struct { + ModelID apijson.Field + ProviderID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AgentModel) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r agentModelJSON) RawJSON() string { + return r.raw +} + type App struct { Git bool `json:"git,required"` Hostname string `json:"hostname,required"` @@ -145,58 +217,6 @@ func (r appTimeJSON) RawJSON() string { return r.raw } -type Mode struct { - Name string `json:"name,required"` - Tools map[string]bool `json:"tools,required"` - Model ModeModel `json:"model"` - Prompt string `json:"prompt"` - Temperature float64 `json:"temperature"` - TopP float64 `json:"topP"` - 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 - Temperature apijson.Field - TopP 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 Model struct { ID string `json:"id,required"` Attachment bool `json:"attachment,required"` diff --git a/packages/sdk/go/app_test.go b/packages/sdk/go/app_test.go index 16bb8ff88..2ade6c7ec 100644 --- a/packages/sdk/go/app_test.go +++ b/packages/sdk/go/app_test.go @@ -13,7 +13,7 @@ import ( "github.com/sst/opencode-sdk-go/option" ) -func TestAppGet(t *testing.T) { +func TestAppAgents(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 { @@ -25,7 +25,7 @@ func TestAppGet(t *testing.T) { client := opencode.NewClient( option.WithBaseURL(baseURL), ) - _, err := client.App.Get(context.TODO()) + _, err := client.App.Agents(context.TODO()) if err != nil { var apierr *opencode.Error if errors.As(err, &apierr) { @@ -35,7 +35,7 @@ func TestAppGet(t *testing.T) { } } -func TestAppInit(t *testing.T) { +func TestAppGet(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 { @@ -47,7 +47,7 @@ func TestAppInit(t *testing.T) { client := opencode.NewClient( option.WithBaseURL(baseURL), ) - _, err := client.App.Init(context.TODO()) + _, err := client.App.Get(context.TODO()) if err != nil { var apierr *opencode.Error if errors.As(err, &apierr) { @@ -57,7 +57,7 @@ func TestAppInit(t *testing.T) { } } -func TestAppLogWithOptionalParams(t *testing.T) { +func TestAppInit(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 { @@ -69,14 +69,7 @@ func TestAppLogWithOptionalParams(t *testing.T) { client := opencode.NewClient( option.WithBaseURL(baseURL), ) - _, err := client.App.Log(context.TODO(), opencode.AppLogParams{ - Level: opencode.F(opencode.AppLogParamsLevelDebug), - Message: opencode.F("message"), - Service: opencode.F("service"), - Extra: opencode.F(map[string]interface{}{ - "foo": "bar", - }), - }) + _, err := client.App.Init(context.TODO()) if err != nil { var apierr *opencode.Error if errors.As(err, &apierr) { @@ -86,7 +79,7 @@ func TestAppLogWithOptionalParams(t *testing.T) { } } -func TestAppModes(t *testing.T) { +func TestAppLogWithOptionalParams(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 { @@ -98,7 +91,14 @@ func TestAppModes(t *testing.T) { client := opencode.NewClient( option.WithBaseURL(baseURL), ) - _, err := client.App.Modes(context.TODO()) + _, err := client.App.Log(context.TODO(), opencode.AppLogParams{ + Level: opencode.F(opencode.AppLogParamsLevelDebug), + Message: opencode.F("message"), + Service: opencode.F("service"), + Extra: opencode.F(map[string]interface{}{ + "foo": "bar", + }), + }) if err != nil { var apierr *opencode.Error if errors.As(err, &apierr) { diff --git a/packages/sdk/go/config.go b/packages/sdk/go/config.go index 911bb2a30..a7b75a1bf 100644 --- a/packages/sdk/go/config.go +++ b/packages/sdk/go/config.go @@ -43,7 +43,7 @@ func (r *ConfigService) Get(ctx context.Context, opts ...option.RequestOption) ( type Config struct { // JSON schema reference for configuration validation Schema string `json:"$schema"` - // Modes configuration, see https://opencode.ai/docs/modes + // Agent configuration, see https://opencode.ai/docs/agent Agent ConfigAgent `json:"agent"` // @deprecated Use 'share' field instead. Share newly created sessions // automatically @@ -63,7 +63,7 @@ type Config struct { Lsp map[string]ConfigLsp `json:"lsp"` // MCP (Model Context Protocol) server configurations Mcp map[string]ConfigMcp `json:"mcp"` - // Modes configuration, see https://opencode.ai/docs/modes + // @deprecated Use `agent` field instead. Mode ConfigMode `json:"mode"` // Model to use in the format of provider/model, eg anthropic/claude-2 Model string `json:"model"` @@ -119,16 +119,20 @@ func (r configJSON) RawJSON() string { return r.raw } -// Modes configuration, see https://opencode.ai/docs/modes +// Agent configuration, see https://opencode.ai/docs/agent type ConfigAgent struct { + Build ConfigAgentBuild `json:"build"` General ConfigAgentGeneral `json:"general"` + Plan ConfigAgentPlan `json:"plan"` ExtraFields map[string]ConfigAgent `json:"-,extras"` JSON configAgentJSON `json:"-"` } // configAgentJSON contains the JSON metadata for the struct [ConfigAgent] type configAgentJSON struct { + Build apijson.Field General apijson.Field + Plan apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -141,16 +145,82 @@ func (r configAgentJSON) RawJSON() string { return r.raw } +type ConfigAgentBuild struct { + // Description of when to use the agent + Description string `json:"description"` + Disable bool `json:"disable"` + Mode ConfigAgentBuildMode `json:"mode"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + Tools map[string]bool `json:"tools"` + TopP float64 `json:"top_p"` + JSON configAgentBuildJSON `json:"-"` +} + +// configAgentBuildJSON contains the JSON metadata for the struct +// [ConfigAgentBuild] +type configAgentBuildJSON struct { + Description apijson.Field + Disable apijson.Field + Mode apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + Tools apijson.Field + TopP apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigAgentBuild) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configAgentBuildJSON) RawJSON() string { + return r.raw +} + +type ConfigAgentBuildMode string + +const ( + ConfigAgentBuildModeSubagent ConfigAgentBuildMode = "subagent" + ConfigAgentBuildModePrimary ConfigAgentBuildMode = "primary" + ConfigAgentBuildModeAll ConfigAgentBuildMode = "all" +) + +func (r ConfigAgentBuildMode) IsKnown() bool { + switch r { + case ConfigAgentBuildModeSubagent, ConfigAgentBuildModePrimary, ConfigAgentBuildModeAll: + return true + } + return false +} + type ConfigAgentGeneral struct { - Description string `json:"description,required"` + // Description of when to use the agent + Description string `json:"description"` + Disable bool `json:"disable"` + Mode ConfigAgentGeneralMode `json:"mode"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + Tools map[string]bool `json:"tools"` + TopP float64 `json:"top_p"` JSON configAgentGeneralJSON `json:"-"` - ModeConfig } // configAgentGeneralJSON contains the JSON metadata for the struct // [ConfigAgentGeneral] type configAgentGeneralJSON struct { Description apijson.Field + Disable apijson.Field + Mode apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + Tools apijson.Field + TopP apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -163,6 +233,73 @@ func (r configAgentGeneralJSON) RawJSON() string { return r.raw } +type ConfigAgentGeneralMode string + +const ( + ConfigAgentGeneralModeSubagent ConfigAgentGeneralMode = "subagent" + ConfigAgentGeneralModePrimary ConfigAgentGeneralMode = "primary" + ConfigAgentGeneralModeAll ConfigAgentGeneralMode = "all" +) + +func (r ConfigAgentGeneralMode) IsKnown() bool { + switch r { + case ConfigAgentGeneralModeSubagent, ConfigAgentGeneralModePrimary, ConfigAgentGeneralModeAll: + return true + } + return false +} + +type ConfigAgentPlan struct { + // Description of when to use the agent + Description string `json:"description"` + Disable bool `json:"disable"` + Mode ConfigAgentPlanMode `json:"mode"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + Tools map[string]bool `json:"tools"` + TopP float64 `json:"top_p"` + JSON configAgentPlanJSON `json:"-"` +} + +// configAgentPlanJSON contains the JSON metadata for the struct [ConfigAgentPlan] +type configAgentPlanJSON struct { + Description apijson.Field + Disable apijson.Field + Mode apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + Tools apijson.Field + TopP apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigAgentPlan) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configAgentPlanJSON) RawJSON() string { + return r.raw +} + +type ConfigAgentPlanMode string + +const ( + ConfigAgentPlanModeSubagent ConfigAgentPlanMode = "subagent" + ConfigAgentPlanModePrimary ConfigAgentPlanMode = "primary" + ConfigAgentPlanModeAll ConfigAgentPlanMode = "all" +) + +func (r ConfigAgentPlanMode) IsKnown() bool { + switch r { + case ConfigAgentPlanModeSubagent, ConfigAgentPlanModePrimary, ConfigAgentPlanModeAll: + return true + } + return false +} + type ConfigExperimental struct { Hook ConfigExperimentalHook `json:"hook"` JSON configExperimentalJSON `json:"-"` @@ -516,11 +653,11 @@ func (r ConfigMcpType) IsKnown() bool { return false } -// Modes configuration, see https://opencode.ai/docs/modes +// @deprecated Use `agent` field instead. type ConfigMode struct { - Build ModeConfig `json:"build"` - Plan ModeConfig `json:"plan"` - ExtraFields map[string]ModeConfig `json:"-,extras"` + Build ConfigModeBuild `json:"build"` + Plan ConfigModePlan `json:"plan"` + ExtraFields map[string]ConfigMode `json:"-,extras"` JSON configModeJSON `json:"-"` } @@ -540,6 +677,108 @@ func (r configModeJSON) RawJSON() string { return r.raw } +type ConfigModeBuild struct { + // Description of when to use the agent + Description string `json:"description"` + Disable bool `json:"disable"` + Mode ConfigModeBuildMode `json:"mode"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + Tools map[string]bool `json:"tools"` + TopP float64 `json:"top_p"` + JSON configModeBuildJSON `json:"-"` +} + +// configModeBuildJSON contains the JSON metadata for the struct [ConfigModeBuild] +type configModeBuildJSON struct { + Description apijson.Field + Disable apijson.Field + Mode apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + Tools apijson.Field + TopP 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 ConfigModeBuildMode string + +const ( + ConfigModeBuildModeSubagent ConfigModeBuildMode = "subagent" + ConfigModeBuildModePrimary ConfigModeBuildMode = "primary" + ConfigModeBuildModeAll ConfigModeBuildMode = "all" +) + +func (r ConfigModeBuildMode) IsKnown() bool { + switch r { + case ConfigModeBuildModeSubagent, ConfigModeBuildModePrimary, ConfigModeBuildModeAll: + return true + } + return false +} + +type ConfigModePlan struct { + // Description of when to use the agent + Description string `json:"description"` + Disable bool `json:"disable"` + Mode ConfigModePlanMode `json:"mode"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Temperature float64 `json:"temperature"` + Tools map[string]bool `json:"tools"` + TopP float64 `json:"top_p"` + JSON configModePlanJSON `json:"-"` +} + +// configModePlanJSON contains the JSON metadata for the struct [ConfigModePlan] +type configModePlanJSON struct { + Description apijson.Field + Disable apijson.Field + Mode apijson.Field + Model apijson.Field + Prompt apijson.Field + Temperature apijson.Field + Tools apijson.Field + TopP 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 ConfigModePlanMode string + +const ( + ConfigModePlanModeSubagent ConfigModePlanMode = "subagent" + ConfigModePlanModePrimary ConfigModePlanMode = "primary" + ConfigModePlanModeAll ConfigModePlanMode = "all" +) + +func (r ConfigModePlanMode) IsKnown() bool { + switch r { + case ConfigModePlanModeSubagent, ConfigModePlanModePrimary, ConfigModePlanModeAll: + return true + } + return false +} + type ConfigPermission struct { Bash ConfigPermissionBashUnion `json:"bash"` Edit ConfigPermissionEdit `json:"edit"` @@ -588,11 +827,12 @@ type ConfigPermissionBashString string const ( ConfigPermissionBashStringAsk ConfigPermissionBashString = "ask" ConfigPermissionBashStringAllow ConfigPermissionBashString = "allow" + ConfigPermissionBashStringDeny ConfigPermissionBashString = "deny" ) func (r ConfigPermissionBashString) IsKnown() bool { switch r { - case ConfigPermissionBashStringAsk, ConfigPermissionBashStringAllow: + case ConfigPermissionBashStringAsk, ConfigPermissionBashStringAllow, ConfigPermissionBashStringDeny: return true } return false @@ -609,11 +849,12 @@ type ConfigPermissionBashMapItem string const ( ConfigPermissionBashMapAsk ConfigPermissionBashMapItem = "ask" ConfigPermissionBashMapAllow ConfigPermissionBashMapItem = "allow" + ConfigPermissionBashMapDeny ConfigPermissionBashMapItem = "deny" ) func (r ConfigPermissionBashMapItem) IsKnown() bool { switch r { - case ConfigPermissionBashMapAsk, ConfigPermissionBashMapAllow: + case ConfigPermissionBashMapAsk, ConfigPermissionBashMapAllow, ConfigPermissionBashMapDeny: return true } return false @@ -624,11 +865,12 @@ type ConfigPermissionEdit string const ( ConfigPermissionEditAsk ConfigPermissionEdit = "ask" ConfigPermissionEditAllow ConfigPermissionEdit = "allow" + ConfigPermissionEditDeny ConfigPermissionEdit = "deny" ) func (r ConfigPermissionEdit) IsKnown() bool { switch r { - case ConfigPermissionEditAsk, ConfigPermissionEditAllow: + case ConfigPermissionEditAsk, ConfigPermissionEditAllow, ConfigPermissionEditDeny: return true } return false @@ -866,9 +1108,13 @@ type KeybindsConfig struct { SessionShare string `json:"session_share,required"` // Unshare current session SessionUnshare string `json:"session_unshare,required"` - // Next mode + // Next agent + SwitchAgent string `json:"switch_agent,required"` + // Previous agent + SwitchAgentReverse string `json:"switch_agent_reverse,required"` + // @deprecated use switch_agent. Next mode SwitchMode string `json:"switch_mode,required"` - // Previous Mode + // @deprecated use switch_agent_reverse. Previous mode SwitchModeReverse string `json:"switch_mode_reverse,required"` // List available themes ThemeList string `json:"theme_list,required"` @@ -913,6 +1159,8 @@ type keybindsConfigJSON struct { SessionNew apijson.Field SessionShare apijson.Field SessionUnshare apijson.Field + SwitchAgent apijson.Field + SwitchAgentReverse apijson.Field SwitchMode apijson.Field SwitchModeReverse apijson.Field ThemeList apijson.Field @@ -1022,33 +1270,3 @@ func (r McpRemoteConfigType) IsKnown() bool { } return false } - -type ModeConfig struct { - Disable bool `json:"disable"` - Model string `json:"model"` - Prompt string `json:"prompt"` - Temperature float64 `json:"temperature"` - Tools map[string]bool `json:"tools"` - TopP float64 `json:"top_p"` - JSON modeConfigJSON `json:"-"` -} - -// modeConfigJSON contains the JSON metadata for the struct [ModeConfig] -type modeConfigJSON struct { - Disable apijson.Field - Model apijson.Field - Prompt apijson.Field - Temperature apijson.Field - Tools apijson.Field - TopP apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ModeConfig) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r modeConfigJSON) RawJSON() string { - return r.raw -} diff --git a/packages/sdk/go/internal/requestconfig/requestconfig.go b/packages/sdk/go/internal/requestconfig/requestconfig.go index 91b70cca5..53bf9f58c 100644 --- a/packages/sdk/go/internal/requestconfig/requestconfig.go +++ b/packages/sdk/go/internal/requestconfig/requestconfig.go @@ -133,11 +133,13 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa // Fallback to json serialization if none of the serialization functions that we expect // to see is present. if body != nil && !hasSerializationFunc { - content, err := json.Marshal(body) - if err != nil { + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(true) + if err := enc.Encode(body); err != nil { return nil, err } - reader = bytes.NewBuffer(content) + reader = buf } req, err := http.NewRequestWithContext(ctx, method, u, nil) diff --git a/packages/sdk/go/session.go b/packages/sdk/go/session.go index d38c37e0e..bae17cf2a 100644 --- a/packages/sdk/go/session.go +++ b/packages/sdk/go/session.go @@ -190,6 +190,113 @@ func (r *SessionService) Unshare(ctx context.Context, id string, opts ...option. return } +type AgentPart struct { + ID string `json:"id,required"` + MessageID string `json:"messageID,required"` + Name string `json:"name,required"` + SessionID string `json:"sessionID,required"` + Type AgentPartType `json:"type,required"` + Source AgentPartSource `json:"source"` + JSON agentPartJSON `json:"-"` +} + +// agentPartJSON contains the JSON metadata for the struct [AgentPart] +type agentPartJSON struct { + ID apijson.Field + MessageID apijson.Field + Name apijson.Field + SessionID apijson.Field + Type apijson.Field + Source apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AgentPart) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r agentPartJSON) RawJSON() string { + return r.raw +} + +func (r AgentPart) implementsPart() {} + +type AgentPartType string + +const ( + AgentPartTypeAgent AgentPartType = "agent" +) + +func (r AgentPartType) IsKnown() bool { + switch r { + case AgentPartTypeAgent: + return true + } + return false +} + +type AgentPartSource struct { + End int64 `json:"end,required"` + Start int64 `json:"start,required"` + Value string `json:"value,required"` + JSON agentPartSourceJSON `json:"-"` +} + +// agentPartSourceJSON contains the JSON metadata for the struct [AgentPartSource] +type agentPartSourceJSON struct { + End apijson.Field + Start apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AgentPartSource) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r agentPartSourceJSON) RawJSON() string { + return r.raw +} + +type AgentPartInputParam struct { + Name param.Field[string] `json:"name,required"` + Type param.Field[AgentPartInputType] `json:"type,required"` + ID param.Field[string] `json:"id"` + Source param.Field[AgentPartInputSourceParam] `json:"source"` +} + +func (r AgentPartInputParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r AgentPartInputParam) implementsSessionChatParamsPartUnion() {} + +type AgentPartInputType string + +const ( + AgentPartInputTypeAgent AgentPartInputType = "agent" +) + +func (r AgentPartInputType) IsKnown() bool { + switch r { + case AgentPartInputTypeAgent: + return true + } + return false +} + +type AgentPartInputSourceParam struct { + End param.Field[int64] `json:"end,required"` + Start param.Field[int64] `json:"start,required"` + Value param.Field[string] `json:"value,required"` +} + +func (r AgentPartInputSourceParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + type AssistantMessage struct { ID string `json:"id,required"` Cost float64 `json:"cost,required"` @@ -855,11 +962,13 @@ type Part struct { Cost float64 `json:"cost"` Filename string `json:"filename"` // This field can have the runtime type of [[]string]. - Files interface{} `json:"files"` - Hash string `json:"hash"` - Mime string `json:"mime"` - Snapshot string `json:"snapshot"` - Source FilePartSource `json:"source"` + Files interface{} `json:"files"` + Hash string `json:"hash"` + Mime string `json:"mime"` + Name string `json:"name"` + Snapshot string `json:"snapshot"` + // This field can have the runtime type of [FilePartSource], [AgentPartSource]. + Source interface{} `json:"source"` // This field can have the runtime type of [ToolPartState]. State interface{} `json:"state"` Synthetic bool `json:"synthetic"` @@ -886,6 +995,7 @@ type partJSON struct { Files apijson.Field Hash apijson.Field Mime apijson.Field + Name apijson.Field Snapshot apijson.Field Source apijson.Field State apijson.Field @@ -916,13 +1026,13 @@ func (r *Part) UnmarshalJSON(data []byte) (err error) { // for more type safety. // // Possible runtime types of the union are [TextPart], [FilePart], [ToolPart], -// [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart]. +// [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart], [AgentPart]. func (r Part) AsUnion() PartUnion { return r.union } // Union satisfied by [TextPart], [FilePart], [ToolPart], [StepStartPart], -// [StepFinishPart], [SnapshotPart] or [PartPatchPart]. +// [StepFinishPart], [SnapshotPart], [PartPatchPart] or [AgentPart]. type PartUnion interface { implementsPart() } @@ -966,6 +1076,11 @@ func init() { Type: reflect.TypeOf(PartPatchPart{}), DiscriminatorValue: "patch", }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AgentPart{}), + DiscriminatorValue: "agent", + }, ) } @@ -1025,11 +1140,12 @@ const ( PartTypeStepFinish PartType = "step-finish" PartTypeSnapshot PartType = "snapshot" PartTypePatch PartType = "patch" + PartTypeAgent PartType = "agent" ) func (r PartType) IsKnown() bool { switch r { - case PartTypeText, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot, PartTypePatch: + case PartTypeText, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot, PartTypePatch, PartTypeAgent: return true } return false @@ -2080,8 +2196,8 @@ type SessionChatParams struct { ModelID param.Field[string] `json:"modelID,required"` Parts param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"` ProviderID param.Field[string] `json:"providerID,required"` + Agent param.Field[string] `json:"agent"` MessageID param.Field[string] `json:"messageID"` - Mode param.Field[string] `json:"mode"` System param.Field[string] `json:"system"` Tools param.Field[map[string]bool] `json:"tools"` } @@ -2095,7 +2211,8 @@ type SessionChatParamsPart struct { ID param.Field[string] `json:"id"` Filename param.Field[string] `json:"filename"` Mime param.Field[string] `json:"mime"` - Source param.Field[FilePartSourceUnionParam] `json:"source"` + Name param.Field[string] `json:"name"` + Source param.Field[interface{}] `json:"source"` Synthetic param.Field[bool] `json:"synthetic"` Text param.Field[string] `json:"text"` Time param.Field[interface{}] `json:"time"` @@ -2108,7 +2225,7 @@ func (r SessionChatParamsPart) MarshalJSON() (data []byte, err error) { func (r SessionChatParamsPart) implementsSessionChatParamsPartUnion() {} -// Satisfied by [TextPartInputParam], [FilePartInputParam], +// Satisfied by [TextPartInputParam], [FilePartInputParam], [AgentPartInputParam], // [SessionChatParamsPart]. type SessionChatParamsPartUnion interface { implementsSessionChatParamsPartUnion() @@ -2117,13 +2234,14 @@ type SessionChatParamsPartUnion interface { type SessionChatParamsPartsType string const ( - SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text" - SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file" + SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text" + SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file" + SessionChatParamsPartsTypeAgent SessionChatParamsPartsType = "agent" ) func (r SessionChatParamsPartsType) IsKnown() bool { switch r { - case SessionChatParamsPartsTypeText, SessionChatParamsPartsTypeFile: + case SessionChatParamsPartsTypeText, SessionChatParamsPartsTypeFile, SessionChatParamsPartsTypeAgent: return true } return false diff --git a/packages/sdk/go/session_test.go b/packages/sdk/go/session_test.go index ab9fbcf7b..b8158f099 100644 --- a/packages/sdk/go/session_test.go +++ b/packages/sdk/go/session_test.go @@ -129,8 +129,8 @@ func TestSessionChatWithOptionalParams(t *testing.T) { }), }}), ProviderID: opencode.F("providerID"), + Agent: opencode.F("agent"), MessageID: opencode.F("msg"), - Mode: opencode.F("mode"), System: opencode.F("system"), Tools: opencode.F(map[string]bool{ "foo": true, diff --git a/packages/sdk/go/tui.go b/packages/sdk/go/tui.go index 30657890d..986b73aa5 100644 --- a/packages/sdk/go/tui.go +++ b/packages/sdk/go/tui.go @@ -47,7 +47,7 @@ func (r *TuiService) ClearPrompt(ctx context.Context, opts ...option.RequestOpti return } -// Execute a TUI command (e.g. switch_mode) +// Execute a TUI command (e.g. switch_agent) func (r *TuiService) ExecuteCommand(ctx context.Context, body TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) { opts = append(r.Options[:], opts...) path := "tui/execute-command" diff --git a/packages/sdk/stainless/stainless.yml b/packages/sdk/stainless/stainless.yml index b9d69cdef..3a8da4061 100644 --- a/packages/sdk/stainless/stainless.yml +++ b/packages/sdk/stainless/stainless.yml @@ -51,12 +51,12 @@ resources: logLevel: LogLevel provider: Provider model: Model - mode: Mode + agent: Agent methods: get: get /app init: post /app/init log: post /log - modes: get /mode + agents: get /agent providers: get /config/providers find: @@ -99,6 +99,8 @@ resources: fileSource: FileSource symbolSource: SymbolSource toolPart: ToolPart + agentPart: AgentPart + agentPartInput: AgentPartInput stepStartPart: StepStartPart stepFinishPart: StepFinishPart snapshotPart: SnapshotPart |
