Explorar o código

feat: bash commands

adamdotdevin hai 6 meses
pai
achega
1357319f6f

+ 5 - 4
packages/opencode/src/session/index.ts

@@ -1050,14 +1050,15 @@ export namespace Session {
     }
     await updatePart(part)
     const app = App.info()
-    const process = exec(input.command, {
+    const proc = exec(input.command, {
       cwd: app.path.cwd,
       signal: abort.signal,
+      shell: process.env["SHELL"],
     })
 
     let output = ""
 
-    process.stdout?.on("data", (chunk) => {
+    proc.stdout?.on("data", (chunk) => {
       output += chunk.toString()
       if (part.state.status === "running") {
         part.state.metadata = {
@@ -1068,7 +1069,7 @@ export namespace Session {
       }
     })
 
-    process.stderr?.on("data", (chunk) => {
+    proc.stderr?.on("data", (chunk) => {
       output += chunk.toString()
       if (part.state.status === "running") {
         part.state.metadata = {
@@ -1080,7 +1081,7 @@ export namespace Session {
     })
 
     await new Promise<void>((resolve) => {
-      process.on("close", () => {
+      proc.on("close", () => {
         resolve()
       })
     })

+ 4 - 4
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-b86cf7bb8df4f60ebe8b8f51e281c8076cfdccc8554178c1b78beca4b025f0ff.yml
-openapi_spec_hash: 47633b7481d91708643ea7b43fffffe6
-config_hash: bd7f6435ed0c0005f373b5526c07a055
+configured_endpoints: 36
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-9031231386199b2baadcaaed5b8df17899f8bc82efef4a74d7a0646fc035268a.yml
+openapi_spec_hash: 8ef902a2a7039a4a6fde44ee7c26c87d
+config_hash: 2b388a88fa9da825b43cbc25c2b349b5

+ 2 - 0
packages/sdk/go/api.md

@@ -111,9 +111,11 @@ Response Types:
 Methods:
 
 - <code title="post /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.New">New</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#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
+- <code title="patch /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Update">Update</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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#SessionUpdateParams">SessionUpdateParams</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#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
 - <code title="get /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.List">List</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#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
 - <code title="delete /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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 /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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 /session/{id}/bash">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Bash">Bash</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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#SessionBashParams">SessionBashParams</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/builtin#error">error</a>)</code>
 - <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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#SessionChatParams">SessionChatParams</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/builtin#error">error</a>)</code>
 - <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</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#SessionInitParams">SessionInitParams</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 /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</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#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

+ 85 - 9
packages/sdk/go/app.go

@@ -72,21 +72,25 @@ func (r *AppService) Providers(ctx context.Context, opts ...option.RequestOption
 }
 
 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:"-"`
+	Mode        AgentMode              `json:"mode,required"`
+	Name        string                 `json:"name,required"`
+	Options     map[string]interface{} `json:"options,required"`
+	Permission  AgentPermission        `json:"permission,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
+	Options     apijson.Field
+	Permission  apijson.Field
 	Tools       apijson.Field
 	Description apijson.Field
 	Model       apijson.Field
@@ -121,6 +125,78 @@ func (r AgentMode) IsKnown() bool {
 	return false
 }
 
+type AgentPermission struct {
+	Bash     map[string]AgentPermissionBash `json:"bash,required"`
+	Edit     AgentPermissionEdit            `json:"edit,required"`
+	Webfetch AgentPermissionWebfetch        `json:"webfetch"`
+	JSON     agentPermissionJSON            `json:"-"`
+}
+
+// agentPermissionJSON contains the JSON metadata for the struct [AgentPermission]
+type agentPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *AgentPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r agentPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+type AgentPermissionBash string
+
+const (
+	AgentPermissionBashAsk   AgentPermissionBash = "ask"
+	AgentPermissionBashAllow AgentPermissionBash = "allow"
+	AgentPermissionBashDeny  AgentPermissionBash = "deny"
+)
+
+func (r AgentPermissionBash) IsKnown() bool {
+	switch r {
+	case AgentPermissionBashAsk, AgentPermissionBashAllow, AgentPermissionBashDeny:
+		return true
+	}
+	return false
+}
+
+type AgentPermissionEdit string
+
+const (
+	AgentPermissionEditAsk   AgentPermissionEdit = "ask"
+	AgentPermissionEditAllow AgentPermissionEdit = "allow"
+	AgentPermissionEditDeny  AgentPermissionEdit = "deny"
+)
+
+func (r AgentPermissionEdit) IsKnown() bool {
+	switch r {
+	case AgentPermissionEditAsk, AgentPermissionEditAllow, AgentPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type AgentPermissionWebfetch string
+
+const (
+	AgentPermissionWebfetchAsk   AgentPermissionWebfetch = "ask"
+	AgentPermissionWebfetchAllow AgentPermissionWebfetch = "allow"
+	AgentPermissionWebfetchDeny  AgentPermissionWebfetch = "deny"
+)
+
+func (r AgentPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case AgentPermissionWebfetchAsk, AgentPermissionWebfetchAllow, AgentPermissionWebfetchDeny:
+		return true
+	}
+	return false
+}
+
 type AgentModel struct {
 	ModelID    string         `json:"modelID,required"`
 	ProviderID string         `json:"providerID,required"`

+ 645 - 47
packages/sdk/go/config.go

@@ -149,15 +149,17 @@ func (r configAgentJSON) RawJSON() string {
 
 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:"-"`
+	Description string                     `json:"description"`
+	Disable     bool                       `json:"disable"`
+	Mode        ConfigAgentBuildMode       `json:"mode"`
+	Model       string                     `json:"model"`
+	Permission  ConfigAgentBuildPermission `json:"permission"`
+	Prompt      string                     `json:"prompt"`
+	Temperature float64                    `json:"temperature"`
+	Tools       map[string]bool            `json:"tools"`
+	TopP        float64                    `json:"top_p"`
+	ExtraFields map[string]interface{}     `json:"-,extras"`
+	JSON        configAgentBuildJSON       `json:"-"`
 }
 
 // configAgentBuildJSON contains the JSON metadata for the struct
@@ -167,6 +169,7 @@ type configAgentBuildJSON struct {
 	Disable     apijson.Field
 	Mode        apijson.Field
 	Model       apijson.Field
+	Permission  apijson.Field
 	Prompt      apijson.Field
 	Temperature apijson.Field
 	Tools       apijson.Field
@@ -199,17 +202,135 @@ func (r ConfigAgentBuildMode) IsKnown() bool {
 	return false
 }
 
+type ConfigAgentBuildPermission struct {
+	Bash     ConfigAgentBuildPermissionBashUnion `json:"bash"`
+	Edit     ConfigAgentBuildPermissionEdit      `json:"edit"`
+	Webfetch ConfigAgentBuildPermissionWebfetch  `json:"webfetch"`
+	JSON     configAgentBuildPermissionJSON      `json:"-"`
+}
+
+// configAgentBuildPermissionJSON contains the JSON metadata for the struct
+// [ConfigAgentBuildPermission]
+type configAgentBuildPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigAgentBuildPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configAgentBuildPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+// Union satisfied by [ConfigAgentBuildPermissionBashString] or
+// [ConfigAgentBuildPermissionBashMap].
+type ConfigAgentBuildPermissionBashUnion interface {
+	implementsConfigAgentBuildPermissionBashUnion()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*ConfigAgentBuildPermissionBashUnion)(nil)).Elem(),
+		"",
+		apijson.UnionVariant{
+			TypeFilter: gjson.String,
+			Type:       reflect.TypeOf(ConfigAgentBuildPermissionBashString("")),
+		},
+		apijson.UnionVariant{
+			TypeFilter: gjson.JSON,
+			Type:       reflect.TypeOf(ConfigAgentBuildPermissionBashMap{}),
+		},
+	)
+}
+
+type ConfigAgentBuildPermissionBashString string
+
+const (
+	ConfigAgentBuildPermissionBashStringAsk   ConfigAgentBuildPermissionBashString = "ask"
+	ConfigAgentBuildPermissionBashStringAllow ConfigAgentBuildPermissionBashString = "allow"
+	ConfigAgentBuildPermissionBashStringDeny  ConfigAgentBuildPermissionBashString = "deny"
+)
+
+func (r ConfigAgentBuildPermissionBashString) IsKnown() bool {
+	switch r {
+	case ConfigAgentBuildPermissionBashStringAsk, ConfigAgentBuildPermissionBashStringAllow, ConfigAgentBuildPermissionBashStringDeny:
+		return true
+	}
+	return false
+}
+
+func (r ConfigAgentBuildPermissionBashString) implementsConfigAgentBuildPermissionBashUnion() {}
+
+type ConfigAgentBuildPermissionBashMap map[string]ConfigAgentBuildPermissionBashMapItem
+
+func (r ConfigAgentBuildPermissionBashMap) implementsConfigAgentBuildPermissionBashUnion() {}
+
+type ConfigAgentBuildPermissionBashMapItem string
+
+const (
+	ConfigAgentBuildPermissionBashMapAsk   ConfigAgentBuildPermissionBashMapItem = "ask"
+	ConfigAgentBuildPermissionBashMapAllow ConfigAgentBuildPermissionBashMapItem = "allow"
+	ConfigAgentBuildPermissionBashMapDeny  ConfigAgentBuildPermissionBashMapItem = "deny"
+)
+
+func (r ConfigAgentBuildPermissionBashMapItem) IsKnown() bool {
+	switch r {
+	case ConfigAgentBuildPermissionBashMapAsk, ConfigAgentBuildPermissionBashMapAllow, ConfigAgentBuildPermissionBashMapDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentBuildPermissionEdit string
+
+const (
+	ConfigAgentBuildPermissionEditAsk   ConfigAgentBuildPermissionEdit = "ask"
+	ConfigAgentBuildPermissionEditAllow ConfigAgentBuildPermissionEdit = "allow"
+	ConfigAgentBuildPermissionEditDeny  ConfigAgentBuildPermissionEdit = "deny"
+)
+
+func (r ConfigAgentBuildPermissionEdit) IsKnown() bool {
+	switch r {
+	case ConfigAgentBuildPermissionEditAsk, ConfigAgentBuildPermissionEditAllow, ConfigAgentBuildPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentBuildPermissionWebfetch string
+
+const (
+	ConfigAgentBuildPermissionWebfetchAsk   ConfigAgentBuildPermissionWebfetch = "ask"
+	ConfigAgentBuildPermissionWebfetchAllow ConfigAgentBuildPermissionWebfetch = "allow"
+	ConfigAgentBuildPermissionWebfetchDeny  ConfigAgentBuildPermissionWebfetch = "deny"
+)
+
+func (r ConfigAgentBuildPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case ConfigAgentBuildPermissionWebfetchAsk, ConfigAgentBuildPermissionWebfetchAllow, ConfigAgentBuildPermissionWebfetchDeny:
+		return true
+	}
+	return false
+}
+
 type ConfigAgentGeneral struct {
 	// 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:"-"`
+	Description string                       `json:"description"`
+	Disable     bool                         `json:"disable"`
+	Mode        ConfigAgentGeneralMode       `json:"mode"`
+	Model       string                       `json:"model"`
+	Permission  ConfigAgentGeneralPermission `json:"permission"`
+	Prompt      string                       `json:"prompt"`
+	Temperature float64                      `json:"temperature"`
+	Tools       map[string]bool              `json:"tools"`
+	TopP        float64                      `json:"top_p"`
+	ExtraFields map[string]interface{}       `json:"-,extras"`
+	JSON        configAgentGeneralJSON       `json:"-"`
 }
 
 // configAgentGeneralJSON contains the JSON metadata for the struct
@@ -219,6 +340,7 @@ type configAgentGeneralJSON struct {
 	Disable     apijson.Field
 	Mode        apijson.Field
 	Model       apijson.Field
+	Permission  apijson.Field
 	Prompt      apijson.Field
 	Temperature apijson.Field
 	Tools       apijson.Field
@@ -251,17 +373,135 @@ func (r ConfigAgentGeneralMode) IsKnown() bool {
 	return false
 }
 
+type ConfigAgentGeneralPermission struct {
+	Bash     ConfigAgentGeneralPermissionBashUnion `json:"bash"`
+	Edit     ConfigAgentGeneralPermissionEdit      `json:"edit"`
+	Webfetch ConfigAgentGeneralPermissionWebfetch  `json:"webfetch"`
+	JSON     configAgentGeneralPermissionJSON      `json:"-"`
+}
+
+// configAgentGeneralPermissionJSON contains the JSON metadata for the struct
+// [ConfigAgentGeneralPermission]
+type configAgentGeneralPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigAgentGeneralPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configAgentGeneralPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+// Union satisfied by [ConfigAgentGeneralPermissionBashString] or
+// [ConfigAgentGeneralPermissionBashMap].
+type ConfigAgentGeneralPermissionBashUnion interface {
+	implementsConfigAgentGeneralPermissionBashUnion()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*ConfigAgentGeneralPermissionBashUnion)(nil)).Elem(),
+		"",
+		apijson.UnionVariant{
+			TypeFilter: gjson.String,
+			Type:       reflect.TypeOf(ConfigAgentGeneralPermissionBashString("")),
+		},
+		apijson.UnionVariant{
+			TypeFilter: gjson.JSON,
+			Type:       reflect.TypeOf(ConfigAgentGeneralPermissionBashMap{}),
+		},
+	)
+}
+
+type ConfigAgentGeneralPermissionBashString string
+
+const (
+	ConfigAgentGeneralPermissionBashStringAsk   ConfigAgentGeneralPermissionBashString = "ask"
+	ConfigAgentGeneralPermissionBashStringAllow ConfigAgentGeneralPermissionBashString = "allow"
+	ConfigAgentGeneralPermissionBashStringDeny  ConfigAgentGeneralPermissionBashString = "deny"
+)
+
+func (r ConfigAgentGeneralPermissionBashString) IsKnown() bool {
+	switch r {
+	case ConfigAgentGeneralPermissionBashStringAsk, ConfigAgentGeneralPermissionBashStringAllow, ConfigAgentGeneralPermissionBashStringDeny:
+		return true
+	}
+	return false
+}
+
+func (r ConfigAgentGeneralPermissionBashString) implementsConfigAgentGeneralPermissionBashUnion() {}
+
+type ConfigAgentGeneralPermissionBashMap map[string]ConfigAgentGeneralPermissionBashMapItem
+
+func (r ConfigAgentGeneralPermissionBashMap) implementsConfigAgentGeneralPermissionBashUnion() {}
+
+type ConfigAgentGeneralPermissionBashMapItem string
+
+const (
+	ConfigAgentGeneralPermissionBashMapAsk   ConfigAgentGeneralPermissionBashMapItem = "ask"
+	ConfigAgentGeneralPermissionBashMapAllow ConfigAgentGeneralPermissionBashMapItem = "allow"
+	ConfigAgentGeneralPermissionBashMapDeny  ConfigAgentGeneralPermissionBashMapItem = "deny"
+)
+
+func (r ConfigAgentGeneralPermissionBashMapItem) IsKnown() bool {
+	switch r {
+	case ConfigAgentGeneralPermissionBashMapAsk, ConfigAgentGeneralPermissionBashMapAllow, ConfigAgentGeneralPermissionBashMapDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentGeneralPermissionEdit string
+
+const (
+	ConfigAgentGeneralPermissionEditAsk   ConfigAgentGeneralPermissionEdit = "ask"
+	ConfigAgentGeneralPermissionEditAllow ConfigAgentGeneralPermissionEdit = "allow"
+	ConfigAgentGeneralPermissionEditDeny  ConfigAgentGeneralPermissionEdit = "deny"
+)
+
+func (r ConfigAgentGeneralPermissionEdit) IsKnown() bool {
+	switch r {
+	case ConfigAgentGeneralPermissionEditAsk, ConfigAgentGeneralPermissionEditAllow, ConfigAgentGeneralPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentGeneralPermissionWebfetch string
+
+const (
+	ConfigAgentGeneralPermissionWebfetchAsk   ConfigAgentGeneralPermissionWebfetch = "ask"
+	ConfigAgentGeneralPermissionWebfetchAllow ConfigAgentGeneralPermissionWebfetch = "allow"
+	ConfigAgentGeneralPermissionWebfetchDeny  ConfigAgentGeneralPermissionWebfetch = "deny"
+)
+
+func (r ConfigAgentGeneralPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case ConfigAgentGeneralPermissionWebfetchAsk, ConfigAgentGeneralPermissionWebfetchAllow, ConfigAgentGeneralPermissionWebfetchDeny:
+		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:"-"`
+	Description string                    `json:"description"`
+	Disable     bool                      `json:"disable"`
+	Mode        ConfigAgentPlanMode       `json:"mode"`
+	Model       string                    `json:"model"`
+	Permission  ConfigAgentPlanPermission `json:"permission"`
+	Prompt      string                    `json:"prompt"`
+	Temperature float64                   `json:"temperature"`
+	Tools       map[string]bool           `json:"tools"`
+	TopP        float64                   `json:"top_p"`
+	ExtraFields map[string]interface{}    `json:"-,extras"`
+	JSON        configAgentPlanJSON       `json:"-"`
 }
 
 // configAgentPlanJSON contains the JSON metadata for the struct [ConfigAgentPlan]
@@ -270,6 +510,7 @@ type configAgentPlanJSON struct {
 	Disable     apijson.Field
 	Mode        apijson.Field
 	Model       apijson.Field
+	Permission  apijson.Field
 	Prompt      apijson.Field
 	Temperature apijson.Field
 	Tools       apijson.Field
@@ -302,6 +543,122 @@ func (r ConfigAgentPlanMode) IsKnown() bool {
 	return false
 }
 
+type ConfigAgentPlanPermission struct {
+	Bash     ConfigAgentPlanPermissionBashUnion `json:"bash"`
+	Edit     ConfigAgentPlanPermissionEdit      `json:"edit"`
+	Webfetch ConfigAgentPlanPermissionWebfetch  `json:"webfetch"`
+	JSON     configAgentPlanPermissionJSON      `json:"-"`
+}
+
+// configAgentPlanPermissionJSON contains the JSON metadata for the struct
+// [ConfigAgentPlanPermission]
+type configAgentPlanPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigAgentPlanPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configAgentPlanPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+// Union satisfied by [ConfigAgentPlanPermissionBashString] or
+// [ConfigAgentPlanPermissionBashMap].
+type ConfigAgentPlanPermissionBashUnion interface {
+	implementsConfigAgentPlanPermissionBashUnion()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*ConfigAgentPlanPermissionBashUnion)(nil)).Elem(),
+		"",
+		apijson.UnionVariant{
+			TypeFilter: gjson.String,
+			Type:       reflect.TypeOf(ConfigAgentPlanPermissionBashString("")),
+		},
+		apijson.UnionVariant{
+			TypeFilter: gjson.JSON,
+			Type:       reflect.TypeOf(ConfigAgentPlanPermissionBashMap{}),
+		},
+	)
+}
+
+type ConfigAgentPlanPermissionBashString string
+
+const (
+	ConfigAgentPlanPermissionBashStringAsk   ConfigAgentPlanPermissionBashString = "ask"
+	ConfigAgentPlanPermissionBashStringAllow ConfigAgentPlanPermissionBashString = "allow"
+	ConfigAgentPlanPermissionBashStringDeny  ConfigAgentPlanPermissionBashString = "deny"
+)
+
+func (r ConfigAgentPlanPermissionBashString) IsKnown() bool {
+	switch r {
+	case ConfigAgentPlanPermissionBashStringAsk, ConfigAgentPlanPermissionBashStringAllow, ConfigAgentPlanPermissionBashStringDeny:
+		return true
+	}
+	return false
+}
+
+func (r ConfigAgentPlanPermissionBashString) implementsConfigAgentPlanPermissionBashUnion() {}
+
+type ConfigAgentPlanPermissionBashMap map[string]ConfigAgentPlanPermissionBashMapItem
+
+func (r ConfigAgentPlanPermissionBashMap) implementsConfigAgentPlanPermissionBashUnion() {}
+
+type ConfigAgentPlanPermissionBashMapItem string
+
+const (
+	ConfigAgentPlanPermissionBashMapAsk   ConfigAgentPlanPermissionBashMapItem = "ask"
+	ConfigAgentPlanPermissionBashMapAllow ConfigAgentPlanPermissionBashMapItem = "allow"
+	ConfigAgentPlanPermissionBashMapDeny  ConfigAgentPlanPermissionBashMapItem = "deny"
+)
+
+func (r ConfigAgentPlanPermissionBashMapItem) IsKnown() bool {
+	switch r {
+	case ConfigAgentPlanPermissionBashMapAsk, ConfigAgentPlanPermissionBashMapAllow, ConfigAgentPlanPermissionBashMapDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentPlanPermissionEdit string
+
+const (
+	ConfigAgentPlanPermissionEditAsk   ConfigAgentPlanPermissionEdit = "ask"
+	ConfigAgentPlanPermissionEditAllow ConfigAgentPlanPermissionEdit = "allow"
+	ConfigAgentPlanPermissionEditDeny  ConfigAgentPlanPermissionEdit = "deny"
+)
+
+func (r ConfigAgentPlanPermissionEdit) IsKnown() bool {
+	switch r {
+	case ConfigAgentPlanPermissionEditAsk, ConfigAgentPlanPermissionEditAllow, ConfigAgentPlanPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigAgentPlanPermissionWebfetch string
+
+const (
+	ConfigAgentPlanPermissionWebfetchAsk   ConfigAgentPlanPermissionWebfetch = "ask"
+	ConfigAgentPlanPermissionWebfetchAllow ConfigAgentPlanPermissionWebfetch = "allow"
+	ConfigAgentPlanPermissionWebfetchDeny  ConfigAgentPlanPermissionWebfetch = "deny"
+)
+
+func (r ConfigAgentPlanPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case ConfigAgentPlanPermissionWebfetchAsk, ConfigAgentPlanPermissionWebfetchAllow, ConfigAgentPlanPermissionWebfetchDeny:
+		return true
+	}
+	return false
+}
+
 type ConfigExperimental struct {
 	Hook ConfigExperimentalHook `json:"hook"`
 	JSON configExperimentalJSON `json:"-"`
@@ -681,15 +1038,17 @@ func (r configModeJSON) RawJSON() string {
 
 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:"-"`
+	Description string                    `json:"description"`
+	Disable     bool                      `json:"disable"`
+	Mode        ConfigModeBuildMode       `json:"mode"`
+	Model       string                    `json:"model"`
+	Permission  ConfigModeBuildPermission `json:"permission"`
+	Prompt      string                    `json:"prompt"`
+	Temperature float64                   `json:"temperature"`
+	Tools       map[string]bool           `json:"tools"`
+	TopP        float64                   `json:"top_p"`
+	ExtraFields map[string]interface{}    `json:"-,extras"`
+	JSON        configModeBuildJSON       `json:"-"`
 }
 
 // configModeBuildJSON contains the JSON metadata for the struct [ConfigModeBuild]
@@ -698,6 +1057,7 @@ type configModeBuildJSON struct {
 	Disable     apijson.Field
 	Mode        apijson.Field
 	Model       apijson.Field
+	Permission  apijson.Field
 	Prompt      apijson.Field
 	Temperature apijson.Field
 	Tools       apijson.Field
@@ -730,17 +1090,135 @@ func (r ConfigModeBuildMode) IsKnown() bool {
 	return false
 }
 
+type ConfigModeBuildPermission struct {
+	Bash     ConfigModeBuildPermissionBashUnion `json:"bash"`
+	Edit     ConfigModeBuildPermissionEdit      `json:"edit"`
+	Webfetch ConfigModeBuildPermissionWebfetch  `json:"webfetch"`
+	JSON     configModeBuildPermissionJSON      `json:"-"`
+}
+
+// configModeBuildPermissionJSON contains the JSON metadata for the struct
+// [ConfigModeBuildPermission]
+type configModeBuildPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigModeBuildPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configModeBuildPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+// Union satisfied by [ConfigModeBuildPermissionBashString] or
+// [ConfigModeBuildPermissionBashMap].
+type ConfigModeBuildPermissionBashUnion interface {
+	implementsConfigModeBuildPermissionBashUnion()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*ConfigModeBuildPermissionBashUnion)(nil)).Elem(),
+		"",
+		apijson.UnionVariant{
+			TypeFilter: gjson.String,
+			Type:       reflect.TypeOf(ConfigModeBuildPermissionBashString("")),
+		},
+		apijson.UnionVariant{
+			TypeFilter: gjson.JSON,
+			Type:       reflect.TypeOf(ConfigModeBuildPermissionBashMap{}),
+		},
+	)
+}
+
+type ConfigModeBuildPermissionBashString string
+
+const (
+	ConfigModeBuildPermissionBashStringAsk   ConfigModeBuildPermissionBashString = "ask"
+	ConfigModeBuildPermissionBashStringAllow ConfigModeBuildPermissionBashString = "allow"
+	ConfigModeBuildPermissionBashStringDeny  ConfigModeBuildPermissionBashString = "deny"
+)
+
+func (r ConfigModeBuildPermissionBashString) IsKnown() bool {
+	switch r {
+	case ConfigModeBuildPermissionBashStringAsk, ConfigModeBuildPermissionBashStringAllow, ConfigModeBuildPermissionBashStringDeny:
+		return true
+	}
+	return false
+}
+
+func (r ConfigModeBuildPermissionBashString) implementsConfigModeBuildPermissionBashUnion() {}
+
+type ConfigModeBuildPermissionBashMap map[string]ConfigModeBuildPermissionBashMapItem
+
+func (r ConfigModeBuildPermissionBashMap) implementsConfigModeBuildPermissionBashUnion() {}
+
+type ConfigModeBuildPermissionBashMapItem string
+
+const (
+	ConfigModeBuildPermissionBashMapAsk   ConfigModeBuildPermissionBashMapItem = "ask"
+	ConfigModeBuildPermissionBashMapAllow ConfigModeBuildPermissionBashMapItem = "allow"
+	ConfigModeBuildPermissionBashMapDeny  ConfigModeBuildPermissionBashMapItem = "deny"
+)
+
+func (r ConfigModeBuildPermissionBashMapItem) IsKnown() bool {
+	switch r {
+	case ConfigModeBuildPermissionBashMapAsk, ConfigModeBuildPermissionBashMapAllow, ConfigModeBuildPermissionBashMapDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigModeBuildPermissionEdit string
+
+const (
+	ConfigModeBuildPermissionEditAsk   ConfigModeBuildPermissionEdit = "ask"
+	ConfigModeBuildPermissionEditAllow ConfigModeBuildPermissionEdit = "allow"
+	ConfigModeBuildPermissionEditDeny  ConfigModeBuildPermissionEdit = "deny"
+)
+
+func (r ConfigModeBuildPermissionEdit) IsKnown() bool {
+	switch r {
+	case ConfigModeBuildPermissionEditAsk, ConfigModeBuildPermissionEditAllow, ConfigModeBuildPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigModeBuildPermissionWebfetch string
+
+const (
+	ConfigModeBuildPermissionWebfetchAsk   ConfigModeBuildPermissionWebfetch = "ask"
+	ConfigModeBuildPermissionWebfetchAllow ConfigModeBuildPermissionWebfetch = "allow"
+	ConfigModeBuildPermissionWebfetchDeny  ConfigModeBuildPermissionWebfetch = "deny"
+)
+
+func (r ConfigModeBuildPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case ConfigModeBuildPermissionWebfetchAsk, ConfigModeBuildPermissionWebfetchAllow, ConfigModeBuildPermissionWebfetchDeny:
+		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:"-"`
+	Description string                   `json:"description"`
+	Disable     bool                     `json:"disable"`
+	Mode        ConfigModePlanMode       `json:"mode"`
+	Model       string                   `json:"model"`
+	Permission  ConfigModePlanPermission `json:"permission"`
+	Prompt      string                   `json:"prompt"`
+	Temperature float64                  `json:"temperature"`
+	Tools       map[string]bool          `json:"tools"`
+	TopP        float64                  `json:"top_p"`
+	ExtraFields map[string]interface{}   `json:"-,extras"`
+	JSON        configModePlanJSON       `json:"-"`
 }
 
 // configModePlanJSON contains the JSON metadata for the struct [ConfigModePlan]
@@ -749,6 +1227,7 @@ type configModePlanJSON struct {
 	Disable     apijson.Field
 	Mode        apijson.Field
 	Model       apijson.Field
+	Permission  apijson.Field
 	Prompt      apijson.Field
 	Temperature apijson.Field
 	Tools       apijson.Field
@@ -781,6 +1260,122 @@ func (r ConfigModePlanMode) IsKnown() bool {
 	return false
 }
 
+type ConfigModePlanPermission struct {
+	Bash     ConfigModePlanPermissionBashUnion `json:"bash"`
+	Edit     ConfigModePlanPermissionEdit      `json:"edit"`
+	Webfetch ConfigModePlanPermissionWebfetch  `json:"webfetch"`
+	JSON     configModePlanPermissionJSON      `json:"-"`
+}
+
+// configModePlanPermissionJSON contains the JSON metadata for the struct
+// [ConfigModePlanPermission]
+type configModePlanPermissionJSON struct {
+	Bash        apijson.Field
+	Edit        apijson.Field
+	Webfetch    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigModePlanPermission) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configModePlanPermissionJSON) RawJSON() string {
+	return r.raw
+}
+
+// Union satisfied by [ConfigModePlanPermissionBashString] or
+// [ConfigModePlanPermissionBashMap].
+type ConfigModePlanPermissionBashUnion interface {
+	implementsConfigModePlanPermissionBashUnion()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*ConfigModePlanPermissionBashUnion)(nil)).Elem(),
+		"",
+		apijson.UnionVariant{
+			TypeFilter: gjson.String,
+			Type:       reflect.TypeOf(ConfigModePlanPermissionBashString("")),
+		},
+		apijson.UnionVariant{
+			TypeFilter: gjson.JSON,
+			Type:       reflect.TypeOf(ConfigModePlanPermissionBashMap{}),
+		},
+	)
+}
+
+type ConfigModePlanPermissionBashString string
+
+const (
+	ConfigModePlanPermissionBashStringAsk   ConfigModePlanPermissionBashString = "ask"
+	ConfigModePlanPermissionBashStringAllow ConfigModePlanPermissionBashString = "allow"
+	ConfigModePlanPermissionBashStringDeny  ConfigModePlanPermissionBashString = "deny"
+)
+
+func (r ConfigModePlanPermissionBashString) IsKnown() bool {
+	switch r {
+	case ConfigModePlanPermissionBashStringAsk, ConfigModePlanPermissionBashStringAllow, ConfigModePlanPermissionBashStringDeny:
+		return true
+	}
+	return false
+}
+
+func (r ConfigModePlanPermissionBashString) implementsConfigModePlanPermissionBashUnion() {}
+
+type ConfigModePlanPermissionBashMap map[string]ConfigModePlanPermissionBashMapItem
+
+func (r ConfigModePlanPermissionBashMap) implementsConfigModePlanPermissionBashUnion() {}
+
+type ConfigModePlanPermissionBashMapItem string
+
+const (
+	ConfigModePlanPermissionBashMapAsk   ConfigModePlanPermissionBashMapItem = "ask"
+	ConfigModePlanPermissionBashMapAllow ConfigModePlanPermissionBashMapItem = "allow"
+	ConfigModePlanPermissionBashMapDeny  ConfigModePlanPermissionBashMapItem = "deny"
+)
+
+func (r ConfigModePlanPermissionBashMapItem) IsKnown() bool {
+	switch r {
+	case ConfigModePlanPermissionBashMapAsk, ConfigModePlanPermissionBashMapAllow, ConfigModePlanPermissionBashMapDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigModePlanPermissionEdit string
+
+const (
+	ConfigModePlanPermissionEditAsk   ConfigModePlanPermissionEdit = "ask"
+	ConfigModePlanPermissionEditAllow ConfigModePlanPermissionEdit = "allow"
+	ConfigModePlanPermissionEditDeny  ConfigModePlanPermissionEdit = "deny"
+)
+
+func (r ConfigModePlanPermissionEdit) IsKnown() bool {
+	switch r {
+	case ConfigModePlanPermissionEditAsk, ConfigModePlanPermissionEditAllow, ConfigModePlanPermissionEditDeny:
+		return true
+	}
+	return false
+}
+
+type ConfigModePlanPermissionWebfetch string
+
+const (
+	ConfigModePlanPermissionWebfetchAsk   ConfigModePlanPermissionWebfetch = "ask"
+	ConfigModePlanPermissionWebfetchAllow ConfigModePlanPermissionWebfetch = "allow"
+	ConfigModePlanPermissionWebfetchDeny  ConfigModePlanPermissionWebfetch = "deny"
+)
+
+func (r ConfigModePlanPermissionWebfetch) IsKnown() bool {
+	switch r {
+	case ConfigModePlanPermissionWebfetchAsk, ConfigModePlanPermissionWebfetchAllow, ConfigModePlanPermissionWebfetchDeny:
+		return true
+	}
+	return false
+}
+
 type ConfigPermission struct {
 	Bash     ConfigPermissionBashUnion `json:"bash"`
 	Edit     ConfigPermissionEdit      `json:"edit"`
@@ -897,10 +1492,10 @@ func (r ConfigPermissionWebfetch) IsKnown() bool {
 }
 
 type ConfigProvider struct {
-	Models  map[string]ConfigProviderModel `json:"models,required"`
 	ID      string                         `json:"id"`
 	API     string                         `json:"api"`
 	Env     []string                       `json:"env"`
+	Models  map[string]ConfigProviderModel `json:"models"`
 	Name    string                         `json:"name"`
 	Npm     string                         `json:"npm"`
 	Options ConfigProviderOptions          `json:"options"`
@@ -909,10 +1504,10 @@ type ConfigProvider struct {
 
 // configProviderJSON contains the JSON metadata for the struct [ConfigProvider]
 type configProviderJSON struct {
-	Models      apijson.Field
 	ID          apijson.Field
 	API         apijson.Field
 	Env         apijson.Field
+	Models      apijson.Field
 	Name        apijson.Field
 	Npm         apijson.Field
 	Options     apijson.Field
@@ -1138,6 +1733,8 @@ type KeybindsConfig struct {
 	SwitchModeReverse string `json:"switch_mode_reverse,required"`
 	// List available themes
 	ThemeList string `json:"theme_list,required"`
+	// Toggle thinking blocks
+	ThinkingBlocks string `json:"thinking_blocks,required"`
 	// Toggle tool details
 	ToolDetails string             `json:"tool_details,required"`
 	JSON        keybindsConfigJSON `json:"-"`
@@ -1184,6 +1781,7 @@ type keybindsConfigJSON struct {
 	SwitchMode           apijson.Field
 	SwitchModeReverse    apijson.Field
 	ThemeList            apijson.Field
+	ThinkingBlocks       apijson.Field
 	ToolDetails          apijson.Field
 	raw                  string
 	ExtraFields          map[string]apijson.Field

+ 95 - 74
packages/sdk/go/session.go

@@ -46,6 +46,18 @@ func (r *SessionService) New(ctx context.Context, opts ...option.RequestOption)
 	return
 }
 
+// Update session properties
+func (r *SessionService) Update(ctx context.Context, id string, body SessionUpdateParams, opts ...option.RequestOption) (res *Session, err error) {
+	opts = append(r.Options[:], opts...)
+	if id == "" {
+		err = errors.New("missing required id parameter")
+		return
+	}
+	path := fmt.Sprintf("session/%s", id)
+	err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...)
+	return
+}
+
 // List all sessions
 func (r *SessionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]Session, err error) {
 	opts = append(r.Options[:], opts...)
@@ -66,27 +78,27 @@ func (r *SessionService) Delete(ctx context.Context, id string, opts ...option.R
 	return
 }
 
-// Update session properties
-func (r *SessionService) Update(ctx context.Context, id string, body SessionUpdateParams, opts ...option.RequestOption) (res *Session, err error) {
+// Abort a session
+func (r *SessionService) Abort(ctx context.Context, id string, opts ...option.RequestOption) (res *bool, err error) {
 	opts = append(r.Options[:], opts...)
 	if id == "" {
 		err = errors.New("missing required id parameter")
 		return
 	}
-	path := fmt.Sprintf("session/%s", id)
-	err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...)
+	path := fmt.Sprintf("session/%s/abort", id)
+	err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
 	return
 }
 
-// Abort a session
-func (r *SessionService) Abort(ctx context.Context, id string, opts ...option.RequestOption) (res *bool, err error) {
+// Run a bash command
+func (r *SessionService) Bash(ctx context.Context, id string, body SessionBashParams, opts ...option.RequestOption) (res *AssistantMessage, err error) {
 	opts = append(r.Options[:], opts...)
 	if id == "" {
 		err = errors.New("missing required id parameter")
 		return
 	}
-	path := fmt.Sprintf("session/%s/abort", id)
-	err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
+	path := fmt.Sprintf("session/%s/bash", id)
+	err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
 	return
 }
 
@@ -976,11 +988,11 @@ type Part struct {
 	// This field can have the runtime type of [[]string].
 	Files interface{} `json:"files"`
 	Hash  string      `json:"hash"`
-	Mime  string      `json:"mime"`
-	Name  string      `json:"name"`
 	// This field can have the runtime type of [map[string]interface{}].
-	ProviderMetadata interface{} `json:"providerMetadata"`
-	Snapshot         string      `json:"snapshot"`
+	Metadata interface{} `json:"metadata"`
+	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].
@@ -999,29 +1011,29 @@ type Part struct {
 
 // partJSON contains the JSON metadata for the struct [Part]
 type partJSON struct {
-	ID               apijson.Field
-	MessageID        apijson.Field
-	SessionID        apijson.Field
-	Type             apijson.Field
-	CallID           apijson.Field
-	Cost             apijson.Field
-	Filename         apijson.Field
-	Files            apijson.Field
-	Hash             apijson.Field
-	Mime             apijson.Field
-	Name             apijson.Field
-	ProviderMetadata apijson.Field
-	Snapshot         apijson.Field
-	Source           apijson.Field
-	State            apijson.Field
-	Synthetic        apijson.Field
-	Text             apijson.Field
-	Time             apijson.Field
-	Tokens           apijson.Field
-	Tool             apijson.Field
-	URL              apijson.Field
-	raw              string
-	ExtraFields      map[string]apijson.Field
+	ID          apijson.Field
+	MessageID   apijson.Field
+	SessionID   apijson.Field
+	Type        apijson.Field
+	CallID      apijson.Field
+	Cost        apijson.Field
+	Filename    apijson.Field
+	Files       apijson.Field
+	Hash        apijson.Field
+	Metadata    apijson.Field
+	Mime        apijson.Field
+	Name        apijson.Field
+	Snapshot    apijson.Field
+	Source      apijson.Field
+	State       apijson.Field
+	Synthetic   apijson.Field
+	Text        apijson.Field
+	Time        apijson.Field
+	Tokens      apijson.Field
+	Tool        apijson.Field
+	URL         apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
 }
 
 func (r partJSON) RawJSON() string {
@@ -1175,27 +1187,27 @@ func (r PartType) IsKnown() bool {
 }
 
 type ReasoningPart struct {
-	ID               string                 `json:"id,required"`
-	MessageID        string                 `json:"messageID,required"`
-	SessionID        string                 `json:"sessionID,required"`
-	Text             string                 `json:"text,required"`
-	Type             ReasoningPartType      `json:"type,required"`
-	ProviderMetadata map[string]interface{} `json:"providerMetadata"`
-	Time             ReasoningPartTime      `json:"time"`
-	JSON             reasoningPartJSON      `json:"-"`
+	ID        string                 `json:"id,required"`
+	MessageID string                 `json:"messageID,required"`
+	SessionID string                 `json:"sessionID,required"`
+	Text      string                 `json:"text,required"`
+	Time      ReasoningPartTime      `json:"time,required"`
+	Type      ReasoningPartType      `json:"type,required"`
+	Metadata  map[string]interface{} `json:"metadata"`
+	JSON      reasoningPartJSON      `json:"-"`
 }
 
 // reasoningPartJSON contains the JSON metadata for the struct [ReasoningPart]
 type reasoningPartJSON struct {
-	ID               apijson.Field
-	MessageID        apijson.Field
-	SessionID        apijson.Field
-	Text             apijson.Field
-	Type             apijson.Field
-	ProviderMetadata apijson.Field
-	Time             apijson.Field
-	raw              string
-	ExtraFields      map[string]apijson.Field
+	ID          apijson.Field
+	MessageID   apijson.Field
+	SessionID   apijson.Field
+	Text        apijson.Field
+	Time        apijson.Field
+	Type        apijson.Field
+	Metadata    apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
 }
 
 func (r *ReasoningPart) UnmarshalJSON(data []byte) (err error) {
@@ -1208,20 +1220,6 @@ func (r reasoningPartJSON) RawJSON() string {
 
 func (r ReasoningPart) implementsPart() {}
 
-type ReasoningPartType string
-
-const (
-	ReasoningPartTypeReasoning ReasoningPartType = "reasoning"
-)
-
-func (r ReasoningPartType) IsKnown() bool {
-	switch r {
-	case ReasoningPartTypeReasoning:
-		return true
-	}
-	return false
-}
-
 type ReasoningPartTime struct {
 	Start float64               `json:"start,required"`
 	End   float64               `json:"end"`
@@ -1245,6 +1243,20 @@ func (r reasoningPartTimeJSON) RawJSON() string {
 	return r.raw
 }
 
+type ReasoningPartType string
+
+const (
+	ReasoningPartTypeReasoning ReasoningPartType = "reasoning"
+)
+
+func (r ReasoningPartType) IsKnown() bool {
+	switch r {
+	case ReasoningPartTypeReasoning:
+		return true
+	}
+	return false
+}
+
 type Session struct {
 	ID       string        `json:"id,required"`
 	Time     SessionTime   `json:"time,required"`
@@ -2286,6 +2298,23 @@ func (r sessionMessagesResponseJSON) RawJSON() string {
 	return r.raw
 }
 
+type SessionUpdateParams struct {
+	Title param.Field[string] `json:"title"`
+}
+
+func (r SessionUpdateParams) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+type SessionBashParams struct {
+	Agent   param.Field[string] `json:"agent,required"`
+	Command param.Field[string] `json:"command,required"`
+}
+
+func (r SessionBashParams) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
 type SessionChatParams struct {
 	ModelID    param.Field[string]                       `json:"modelID,required"`
 	Parts      param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"`
@@ -2368,11 +2397,3 @@ type SessionSummarizeParams struct {
 func (r SessionSummarizeParams) MarshalJSON() (data []byte, err error) {
 	return apijson.MarshalRoot(r)
 }
-
-type SessionUpdateParams struct {
-	Title param.Field[string] `json:"title"`
-}
-
-func (r SessionUpdateParams) MarshalJSON() (data []byte, err error) {
-	return apijson.MarshalRoot(r)
-}

+ 57 - 0
packages/sdk/go/session_test.go

@@ -35,6 +35,34 @@ func TestSessionNew(t *testing.T) {
 	}
 }
 
+func TestSessionUpdateWithOptionalParams(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.Session.Update(
+		context.TODO(),
+		"id",
+		opencode.SessionUpdateParams{
+			Title: opencode.F("title"),
+		},
+	)
+	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())
+	}
+}
+
 func TestSessionList(t *testing.T) {
 	t.Skip("skipped: tests are disabled for the time being")
 	baseURL := "http://localhost:4010"
@@ -101,6 +129,35 @@ func TestSessionAbort(t *testing.T) {
 	}
 }
 
+func TestSessionBash(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.Session.Bash(
+		context.TODO(),
+		"id",
+		opencode.SessionBashParams{
+			Agent:   opencode.F("agent"),
+			Command: opencode.F("command"),
+		},
+	)
+	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())
+	}
+}
+
 func TestSessionChatWithOptionalParams(t *testing.T) {
 	t.Skip("skipped: tests are disabled for the time being")
 	baseURL := "http://localhost:4010"

+ 2 - 0
packages/sdk/stainless/stainless.yml

@@ -124,6 +124,8 @@ resources:
       message: get /session/{id}/message/{messageID}
       messages: get /session/{id}/message
       chat: post /session/{id}/message
+      bash: post /session/{id}/bash
+      update: patch /session/{id}
       revert: post /session/{id}/revert
       unrevert: post /session/{id}/unrevert
 

+ 71 - 8
packages/tui/internal/app/app.go

@@ -49,6 +49,7 @@ type App struct {
 	InitialSession    *string
 	compactCancel     context.CancelFunc
 	IsLeaderSequence  bool
+	IsBashMode        bool
 }
 
 func (a *App) Agent() *opencode.Agent {
@@ -79,6 +80,9 @@ type AgentSelectedMsg struct {
 type SessionClearedMsg struct{}
 type CompactSessionMsg struct{}
 type SendPrompt = Prompt
+type SendBash = struct {
+	Command string
+}
 type SetEditorContentMsg struct {
 	Text string
 }
@@ -296,23 +300,41 @@ func (a *App) CycleRecentModel() (*App, tea.Cmd) {
 	}
 	nextIndex := 0
 	for i, recentModel := range recentModels {
-		if a.Provider != nil && a.Model != nil && recentModel.ProviderID == a.Provider.ID && recentModel.ModelID == a.Model.ID {
+		if a.Provider != nil && a.Model != nil && recentModel.ProviderID == a.Provider.ID &&
+			recentModel.ModelID == a.Model.ID {
 			nextIndex = (i + 1) % len(recentModels)
 			break
 		}
 	}
 	for range recentModels {
 		currentRecentModel := recentModels[nextIndex%len(recentModels)]
-		provider, model := findModelByProviderAndModelID(a.Providers, currentRecentModel.ProviderID, currentRecentModel.ModelID)
+		provider, model := findModelByProviderAndModelID(
+			a.Providers,
+			currentRecentModel.ProviderID,
+			currentRecentModel.ModelID,
+		)
 		if provider != nil && model != nil {
 			a.Provider, a.Model = provider, model
-			a.State.AgentModel[a.Agent().Name] = AgentModel{ProviderID: provider.ID, ModelID: model.ID}
-			return a, tea.Sequence(a.SaveState(), toast.NewSuccessToast(fmt.Sprintf("Switched to %s (%s)", model.Name, provider.Name)))
+			a.State.AgentModel[a.Agent().Name] = AgentModel{
+				ProviderID: provider.ID,
+				ModelID:    model.ID,
+			}
+			return a, tea.Sequence(
+				a.SaveState(),
+				toast.NewSuccessToast(
+					fmt.Sprintf("Switched to %s (%s)", model.Name, provider.Name),
+				),
+			)
 		}
-		recentModels = append(recentModels[:nextIndex%len(recentModels)], recentModels[nextIndex%len(recentModels)+1:]...)
+		recentModels = append(
+			recentModels[:nextIndex%len(recentModels)],
+			recentModels[nextIndex%len(recentModels)+1:]...)
 		if len(recentModels) < 2 {
 			a.State.RecentlyUsedModels = recentModels
-			return a, tea.Sequence(a.SaveState(), toast.NewInfoToast("Not enough valid recent models to cycle"))
+			return a, tea.Sequence(
+				a.SaveState(),
+				toast.NewInfoToast("Not enough valid recent models to cycle"),
+			)
 		}
 	}
 	a.State.RecentlyUsedModels = recentModels
@@ -464,10 +486,19 @@ func (a *App) InitializeProvider() tea.Cmd {
 
 	// Priority 3: Current agent's preferred model
 	if selectedProvider == nil && a.Agent().Model.ModelID != "" {
-		if provider, model := findModelByProviderAndModelID(providers, a.Agent().Model.ProviderID, a.Agent().Model.ModelID); provider != nil && model != nil {
+		if provider, model := findModelByProviderAndModelID(providers, a.Agent().Model.ProviderID, a.Agent().Model.ModelID); provider != nil &&
+			model != nil {
 			selectedProvider = provider
 			selectedModel = model
-			slog.Debug("Selected model from current agent", "provider", provider.ID, "model", model.ID, "agent", a.Agent().Name)
+			slog.Debug(
+				"Selected model from current agent",
+				"provider",
+				provider.ID,
+				"model",
+				model.ID,
+				"agent",
+				a.Agent().Name,
+			)
 		} else {
 			slog.Debug("Agent model not found", "provider", a.Agent().Model.ProviderID, "model", a.Agent().Model.ModelID, "agent", a.Agent().Name)
 		}
@@ -724,6 +755,38 @@ func (a *App) SendPrompt(ctx context.Context, prompt Prompt) (*App, tea.Cmd) {
 	return a, tea.Batch(cmds...)
 }
 
+func (a *App) SendBash(ctx context.Context, command string) (*App, tea.Cmd) {
+	var cmds []tea.Cmd
+	if a.Session.ID == "" {
+		session, err := a.CreateSession(ctx)
+		if err != nil {
+			return a, toast.NewErrorToast(err.Error())
+		}
+		a.Session = session
+		cmds = append(cmds, util.CmdHandler(SessionCreatedMsg{Session: session}))
+	}
+
+	cmds = append(cmds, func() tea.Msg {
+		_, err := a.Client.Session.Bash(
+			context.Background(),
+			a.Session.ID,
+			opencode.SessionBashParams{
+				Agent:   opencode.F(a.Agent().Name),
+				Command: opencode.F(command),
+			},
+		)
+		if err != nil {
+			slog.Error("Failed to submit bash command", "error", err)
+			return toast.NewErrorToast("Failed to submit bash command")()
+		}
+		return nil
+	})
+
+	// The actual response will come through SSE
+	// For now, just return success
+	return a, tea.Batch(cmds...)
+}
+
 func (a *App) Cancel(ctx context.Context, sessionID string) error {
 	// Cancel any running compact operation
 	if a.compactCancel != nil {

+ 19 - 4
packages/tui/internal/components/chat/editor.go

@@ -39,6 +39,7 @@ type EditorComponent interface {
 	Focus() (tea.Model, tea.Cmd)
 	Blur()
 	Submit() (tea.Model, tea.Cmd)
+	SubmitBash() (tea.Model, tea.Cmd)
 	Clear() (tea.Model, tea.Cmd)
 	Paste() (tea.Model, tea.Cmd)
 	Newline() (tea.Model, tea.Cmd)
@@ -342,6 +343,14 @@ func (m *editorComponent) Content() string {
 		Padding(0, 0, 0, 1).
 		Bold(true)
 	prompt := promptStyle.Render(">")
+	borderForeground := t.Border()
+	if m.app.IsLeaderSequence {
+		borderForeground = t.Accent()
+	}
+	if m.app.IsBashMode {
+		borderForeground = t.Secondary()
+		prompt = promptStyle.Render("!")
+	}
 
 	m.textarea.SetWidth(width - 6)
 	textarea := lipgloss.JoinHorizontal(
@@ -349,10 +358,6 @@ func (m *editorComponent) Content() string {
 		prompt,
 		m.textarea.View(),
 	)
-	borderForeground := t.Border()
-	if m.app.IsLeaderSequence {
-		borderForeground = t.Accent()
-	}
 	textarea = styles.NewStyle().
 		Background(t.BackgroundElement()).
 		Width(width).
@@ -489,6 +494,16 @@ func (m *editorComponent) Submit() (tea.Model, tea.Cmd) {
 	return m, tea.Batch(cmds...)
 }
 
+func (m *editorComponent) SubmitBash() (tea.Model, tea.Cmd) {
+	command := m.textarea.Value()
+	var cmds []tea.Cmd
+	updated, cmd := m.Clear()
+	m = updated.(*editorComponent)
+	cmds = append(cmds, cmd)
+	cmds = append(cmds, util.CmdHandler(app.SendBash{Command: command}))
+	return m, tea.Batch(cmds...)
+}
+
 func (m *editorComponent) Clear() (tea.Model, tea.Cmd) {
 	m.textarea.Reset()
 	m.historyIndex = -1

+ 29 - 2
packages/tui/internal/tui/tui.go

@@ -151,6 +151,23 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			}
 		}
 
+		if a.app.IsBashMode {
+			if keyString == "backspace" && a.editor.Length() == 0 {
+				a.app.IsBashMode = false
+				return a, nil
+			}
+
+			if keyString == "enter" || keyString == "esc" || keyString == "ctrl+c" {
+				a.app.IsBashMode = false
+				if keyString == "enter" {
+					updated, cmd := a.editor.SubmitBash()
+					a.editor = updated.(chat.EditorComponent)
+					cmds = append(cmds, cmd)
+				}
+				return a, tea.Batch(cmds...)
+			}
+		}
+
 		// 1. Handle active modal
 		if a.modal != nil {
 			switch keyString {
@@ -189,7 +206,8 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		// 3. Handle completions trigger
 		if keyString == "/" &&
 			!a.showCompletionDialog &&
-			a.editor.Value() == "" {
+			a.editor.Value() == "" &&
+			!a.app.IsBashMode {
 			a.showCompletionDialog = true
 
 			updated, cmd := a.editor.Update(msg)
@@ -207,7 +225,8 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 
 		// Handle file completions trigger
 		if keyString == "@" &&
-			!a.showCompletionDialog {
+			!a.showCompletionDialog &&
+			!a.app.IsBashMode {
 			a.showCompletionDialog = true
 
 			updated, cmd := a.editor.Update(msg)
@@ -223,6 +242,11 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			return a, tea.Sequence(cmds...)
 		}
 
+		if keyString == "!" && a.editor.Value() == "" {
+			a.app.IsBashMode = true
+			return a, nil
+		}
+
 		if a.showCompletionDialog {
 			switch keyString {
 			case "tab", "enter", "esc", "ctrl+c", "up", "down", "ctrl+p", "ctrl+n":
@@ -378,6 +402,9 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		a.showCompletionDialog = false
 		a.app, cmd = a.app.SendPrompt(context.Background(), msg)
 		cmds = append(cmds, cmd)
+	case app.SendBash:
+		a.app, cmd = a.app.SendBash(context.Background(), msg.Command)
+		cmds = append(cmds, cmd)
 	case app.SetEditorContentMsg:
 		// Set the editor content without sending
 		a.editor.SetValueWithAttachments(msg.Text)