From e0d77e410cd7e66f04d2f70f05a19fdf3fba0a56 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Wed, 4 Nov 2026 10:18:44 +0000 Subject: [PATCH] Report the mode of the built-in bash in the chat add-on list A chat with no add-on that runs commands could not tell a person whether the server's built-in bash was off or simply not selected. The add-on list now carries commands_host_exec (off, ask or on), a read-only copy of the chats_host_exec setting as it applies now. Assisted-by: Claude:claude-sonnet-5-5 --- core/http/endpoints/studio/addons.go | 8 ++++---- core/http/endpoints/studio/draft.go | 2 +- core/schema/chats.go | 4 ++++ core/services/studio/hostbash.go | 4 ++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/http/endpoints/studio/addons.go b/core/http/endpoints/studio/addons.go index bb641e3a0a..9f487a8662 100644 --- a/core/http/endpoints/studio/addons.go +++ b/core/http/endpoints/studio/addons.go @@ -17,13 +17,13 @@ func addonList(c echo.Context, h *Handlers) error { if err != nil { return failFor(c, err) } - return writeAddonList(c, list, cmds) + return writeAddonList(c, h, list, cmds) } -func writeAddonList(c echo.Context, list []studiosvc.AddonInfo, cmds studiosvc.Commands) error { +func writeAddonList(c echo.Context, h *Handlers, list []studiosvc.AddonInfo, cmds studiosvc.Commands) error { out := schema.ChatsAddonList{Addons: make([]schema.ChatsAddon, 0, len(list)), Commands: string(cmds.State), CommandsReason: cmds.Reason, CommandsIsolation: cmds.Isolation, CommandsProvider: cmds.Provider, CommandsConsent: cmds.Consent, - CommandsFallback: cmds.Fallback, CommandsFallbackReason: cmds.FallbackReason} + CommandsFallback: cmds.Fallback, CommandsFallbackReason: cmds.FallbackReason, CommandsHostExec: h.svc.HostExecMode()} if v := cmds.ExecutionStatus; v != nil { out.ExecutionStatus = &schema.ChatsExecutionStatus{Readiness: v.Readiness, Isolation: v.Isolation, Explanation: v.Explanation, UnknownReason: v.UnknownReason, Generation: v.Generation, Incarnation: v.Incarnation} } @@ -49,7 +49,7 @@ func addonOut(a studiosvc.AddonInfo) schema.ChatsAddon { // ListChatAddons lists the add-ons a chat can use. // @Summary List the add-ons a chat can use. -// @Description The add-ons whose tools the signed-in user may use now, each with the chat's switch, and whether the chat can run commands at its next turn (commands: available, off, unavailable, none, or switched_off when the chat switched the built-in group shell off). When commands is available, commands_provider says who serves bash (builtin: directly on this machine with no isolation and with its network, or the add-on's ID) and commands_isolation says isolated or host; commands_consent is ask when each command waits for a yes in the chat, and commands_fallback names an add-on that would serve but does not (commands_fallback_reason: off, or why it cannot run). Without the add-on host the list is empty. +// @Description The add-ons whose tools the signed-in user may use now, each with the chat's switch, and whether the chat can run commands at its next turn (commands: available, off, unavailable, none, or switched_off when the chat switched the built-in group shell off). When commands is available, commands_provider says who serves bash (builtin: directly on this machine with no isolation and with its network, or the add-on's ID) and commands_isolation says isolated or host; commands_consent is ask when each command waits for a yes in the chat, and commands_fallback names an add-on that would serve but does not (commands_fallback_reason: off, or why it cannot run). commands_host_exec is the mode of chats_host_exec now (off, ask or on), so a client can say that the built-in bash is off when commands is none. Without the add-on host the list is empty. // @Tags chats // @Param id path string true "conversation id" // @Success 200 {object} schema.ChatsAddonList "The add-ons and their switches" diff --git a/core/http/endpoints/studio/draft.go b/core/http/endpoints/studio/draft.go index c7bb92d0e1..427e38fc89 100644 --- a/core/http/endpoints/studio/draft.go +++ b/core/http/endpoints/studio/draft.go @@ -82,7 +82,7 @@ func (h *Handlers) DraftAddons(c echo.Context) error { if err != nil { return failFor(c, err) } - return writeAddonList(c, list, cmds) + return writeAddonList(c, h, list, cmds) } // draftSwitches reads the switches of a draft from the query: comma-separated diff --git a/core/schema/chats.go b/core/schema/chats.go index 92888bd74f..43f7a996ee 100644 --- a/core/schema/chats.go +++ b/core/schema/chats.go @@ -934,6 +934,10 @@ type ChatsAddonList struct { // CommandsFallbackReason says why: off, or the add-on's reason. CommandsFallback string `json:"commands_fallback,omitempty"` CommandsFallbackReason string `json:"commands_fallback_reason,omitempty"` + // CommandsHostExec is the mode of the setting chats_host_exec as it applies + // now (off, ask or on), so a client can say that the built-in bash is off + // when no add-on runs commands. Every signed-in user may read it. + CommandsHostExec string `json:"commands_host_exec,omitempty"` } // ChatsHostExecConsent answers the card that asks to run one command on this diff --git a/core/services/studio/hostbash.go b/core/services/studio/hostbash.go index b05fad3f25..a5c1e025b5 100644 --- a/core/services/studio/hostbash.go +++ b/core/services/studio/hostbash.go @@ -86,6 +86,10 @@ func (s *Service) hostExecMode() string { return hostexec.ModeOff } +// HostExecMode is the mode of chats_host_exec as it applies now: off, ask or +// on. A server with no such setting reads as off. +func (s *Service) HostExecMode() string { return s.hostExecMode() } + func (s *Service) isAdmin(ctx context.Context, user string) bool { if s.d.IsAdmin == nil { return true // no accounts: the one person is the administrator