command

package
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: AGPL-3.0 Imports: 36 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotCommand         = commandsyntax.ErrNotCommand
	ErrCommandForOtherBot = commandsyntax.ErrCommandForOtherBot
)

Functions

func AccessDeniedMessage

func AccessDeniedMessage(t *i18n.Localizer, role string) string

AccessDeniedMessage is the reply sent when the chat ACL denies a sender. It doubles as the binding hint so a forgetful owner learns how to link in (/link) while a genuine outsider learns they aren't permitted. A manager gets a narrower message because Manage access does not imply Chat access.

func CmdRef

func CmdRef(cmd string) string

CmdRef renders a slash-command reference as a tap-to-copy code span: on Telegram a code span is tap-to-copy monospace, and on text-only channels the backticks strip cleanly. Accepts "schedule list" or "/schedule list".

func CommandText

func CommandText(cmd, botUsername string) string

CommandText renders a slash command and optionally addresses its first token to a bot username. Keeping the suffix next to the resource is required for Telegram's /command@bot grammar; any arguments remain after that token.

func DismissCallback

func DismissCallback() string

DismissCallback returns the callback_data that closes an interactive message.

func EncodeConfirmNewCallback

func EncodeConfirmNewCallback(mode string) string

EncodeConfirmNewCallback builds the callback_data for confirming a /new reset. Layout: "m~cn~{mode}" where mode is chat|discuss. Tapping re-dispatches "/new {mode} --confirm", which performs the actual session reset.

func EncodeListCallback

func EncodeListCallback(resource, action string, args []string, page int) string

EncodeListCallback builds the callback_data for a list-pagination button. Layout: "m~lp~{resource}~{action}~{page}~{argsToken}". When the encoded args would push the string past Telegram's 64-byte limit, the args are stashed in a bounded process-local table and referenced by a short token ("#<hash>").

func EncodeModelProviderCallback

func EncodeModelProviderCallback(providerIndex, page int) string

EncodeModelProviderCallback builds the callback_data for drilling into a provider's paginated model list. Layout: "m~mpl~{providerIndex}~{page}".

func EncodeModelSelectCallback

func EncodeModelSelectCallback(modelDBID string) string

EncodeModelSelectCallback builds the callback_data for selecting a model by its stable DB id. Layout: "m~ms~{modelDBID}". Using the stable id (not a positional/flat index) means a model-list change between render and tap can't silently resolve the tap to a different model. The id is a UUID (~36 bytes), so "m~ms~"+id stays well within Telegram's 64-byte callback_data limit.

func EncodeRangeCallback

func EncodeRangeCallback(resource, action, rangeKey string) string

EncodeRangeCallback builds the callback_data for a time-window preset button. Layout: "m~rg~{resource}~{action}~{rangeKey}".

func EncodeSkillActivateCallback

func EncodeSkillActivateCallback(name string) string

EncodeSkillActivateCallback builds the callback_data for a tap-to-activate skill row on /skill list. Layout: "m~sk~{name}". Tapping re-dispatches the canonical "/{name}" skill slash, so the activation runs through the exact same classify→resolve→activate pipeline as a typed slash — permissions and runtime-usability are judged at tap time, never baked into the keyboard. Names too long for Telegram's 64-byte limit are stashed like list args ("#<hash>"); a stash miss after restart/rollover simply invalidates the stale button (the user re-runs /skill list).

func ExtractCommandText

func ExtractCommandText(text string) string

func FallbackTrailer

func FallbackTrailer(iv *Interactive, t *i18n.Localizer) string

FallbackTrailer derives a human-readable list of typeable commands from an Interactive payload, intended for appending to Result.Text on channels that cannot render buttons. Returns "" when the payload offers no typeable affordance worth surfacing (display-only list with no extras, suppressed choices, nil view).

The returned string carries Markdown markup (backticks via MdCode); the renderer's applyMessageFormat strips it for plain-text channels.

func IsInteractiveCallback

func IsInteractiveCallback(data string) bool

IsInteractiveCallback reports whether data is one of our interactive callbacks (as opposed to a tool-approval callback or unrelated data).

func MdBold

func MdBold(s string) string

MdBold / MdCode author Markdown for capable channels. Telegram bold is **double-star** (single * is italic); backtick code spans are the safe path for dynamic values (escaped verbatim, never mis-parsed).

func MdCode

func MdCode(s string) string

func NoopCallback

func NoopCallback() string

NoopCallback returns the callback_data for inert buttons (e.g. the page indicator) that should be acknowledged but otherwise ignored.

func TelegramGroupCommandTip

func TelegramGroupCommandTip(t *i18n.Localizer, botUsername string) string

TelegramGroupCommandTip explains the one transport-specific rule users need when typing commands manually. Command lists stay visually clean; the bot username appears once in this complete, copyable example.

func UnknownCommandMessage

func UnknownCommandMessage(t *i18n.Localizer, text string) string

UnknownCommandMessage is the reply for slash-command-shaped input that is not a known command. It points the user at /commands and offers the no-slash escape.

Types

type AccessEvaluator

type AccessEvaluator interface {
	Evaluate(ctx context.Context, req acl.EvaluateRequest) (bool, error)
}

AccessEvaluator checks whether the current channel context may trigger chat.

type BotMemberRoleAdapter

type BotMemberRoleAdapter struct {
	BotService     *bots.Service
	ManageResolver ChannelManageResolver
}

BotMemberRoleAdapter adapts bots.Service to MemberRoleResolver.

func (*BotMemberRoleAdapter) GetMemberRole

func (a *BotMemberRoleAdapter) GetMemberRole(ctx context.Context, botID, channelIdentityID string) (string, error)

type ChannelManageResolver

type ChannelManageResolver interface {
	HasManageGrant(ctx context.Context, botID, channelIdentityID string) (bool, error)
}

ChannelManageResolver reports whether a channel identity has been granted the manage capability on a bot (Channel Access "Manage"). It lets an IM identity run owner-only slash commands without being the web owner.

type ChoicesView

type ChoicesView struct {
	Title                 string
	Choices               []ListItem
	Columns               int // optional keyboard columns; 0 lets renderers pick
	BodyEnumeratesChoices bool
}

ChoicesView is a flat set of selectable choices (no pagination).

BodyEnumeratesChoices asserts that the body Text already enumerates every typeable affordance (e.g. /help <group>'s Usage block lists every sub-command verbatim), so the no-button fallback trailer should skip this surface to avoid duplicating what the body already says.

This is a bool (not a HintVerb sentinel like ListView's HintVerb) because the question being answered is different: ChoicesView picks WHETHER to emit a trailer at all, ListView picks WHICH verb to use. See ListView.HintVerb.

type CommandContext

type CommandContext struct {
	Ctx               context.Context
	BotID             string
	Role              string // "owner", "admin", "member", or "" (guest)
	WriteAccess       bool
	Args              []string
	ChannelIdentityID string
	UserID            string
	ChannelType       string
	ConversationType  string
	ConversationID    string
	ThreadID          string
	RouteID           string
	SessionID         string
	Page              int    // zero-based page offset for paginated list commands
	Prov              int    // provider index for the model picker (-1 if absent)
	SelectID          string // stable model id for picker selection ("" if absent)
	Range             string // time-window key for time-series commands ("" = default)
	Locale            string // resolved command-UI locale ("en", "zh", …)
	L                 *i18n.Localizer
}

CommandContext carries execution context for a sub-command.

func (CommandContext) T

func (cc CommandContext) T(key string, params ...map[string]any) string

T localizes key for this context's command-UI locale, substituting named "{placeholder}" params. Safe on a nil Localizer (returns the key), so handlers and tests that omit L degrade gracefully.

type CommandGroup

type CommandGroup struct {
	Name          string
	Description   string
	DefaultAction string
	// contains filtered or unexported fields
}

CommandGroup groups sub-commands under a resource name.

func (*CommandGroup) ActionHelp

func (g *CommandGroup) ActionHelp(action string, localizers ...*i18n.Localizer) string

func (*CommandGroup) Register

func (g *CommandGroup) Register(sub SubCommand)

func (*CommandGroup) Usage

func (g *CommandGroup) Usage(localizers ...*i18n.Localizer) string

Usage returns the usage text for this resource group.

type CommandQueries

type CommandQueries interface {
	GetLatestSessionIDByBot(ctx context.Context, botID pgtype.UUID) (pgtype.UUID, error)
	CountMessagesBySession(ctx context.Context, sessionID pgtype.UUID) (int64, error)
	GetLatestAssistantUsage(ctx context.Context, sessionID pgtype.UUID) (int64, error)
	GetSessionCacheStats(ctx context.Context, sessionID pgtype.UUID) (dbsqlc.GetSessionCacheStatsRow, error)
	GetSessionUsedSkills(ctx context.Context, sessionID pgtype.UUID) ([]string, error)
	GetTokenUsageByDayAndType(ctx context.Context, arg dbsqlc.GetTokenUsageByDayAndTypeParams) ([]dbsqlc.GetTokenUsageByDayAndTypeRow, error)
	GetTokenUsageByModel(ctx context.Context, arg dbsqlc.GetTokenUsageByModelParams) ([]dbsqlc.GetTokenUsageByModelRow, error)
	// UpdateSessionModelPreference is the /model and /reasoning clear path
	// (issue #879, spec P11′): called with NULL fields to drop a web-pinned
	// pair so the session returns to the bot-default chain.
	UpdateSessionModelPreference(ctx context.Context, arg dbsqlc.UpdateSessionModelPreferenceParams) error
}

CommandQueries captures the sqlc methods used by slash commands. dbstore.Queries satisfies this interface directly.

type ContainerFS

type ContainerFS interface {
	ListDir(ctx context.Context, botID, path string) ([]FSEntry, error)
	ReadFile(ctx context.Context, botID, path string) (string, error)
}

ContainerFS provides read-only access to a bot's container filesystem.

type CurrentContext

type CurrentContext struct {
	ChatModel string
	// ReasoningEffort carries models.ReasoningEffortDisable when reasoning is off.
	ReasoningEffort string
	ContextWindow   string // resolved chat-model context window (e.g. "128.0K"), "" if unknown
}

CurrentContext is the resolved current-state summary used to enrich /new and bare /model output. All fields are display-ready strings.

type ExecuteInput

type ExecuteInput struct {
	BotID             string
	ChannelIdentityID string
	UserID            string
	Text              string
	// Invocation is the canonical channel parse. When present, command handling
	// must use it instead of interpreting Text again.
	Invocation       *Invocation
	ChannelType      string
	ConversationType string
	ConversationID   string
	ThreadID         string
	RouteID          string
	SessionID        string
	// CommandTarget optionally identifies the bot username for transport-specific
	// command guidance. Channel callers set it only for Telegram group messages.
	CommandTarget string
	// Locale optionally pins the command-UI locale. When empty, ExecuteResult
	// resolves it from the bot's command_ui_language setting (auto → en).
	Locale string
}

ExecuteInput carries the caller identity and channel context for command execution.

type FSEntry

type FSEntry struct {
	Name  string
	IsDir bool
	Size  int64
}

FSEntry represents a file or directory in a container filesystem.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler processes slash commands intercepted before they reach the LLM.

func NewHandler

func NewHandler(
	log *slog.Logger,
	roleResolver MemberRoleResolver,
	scheduleService *schedule.Service,
	settingsService *settings.Service,
	mcpConnService *mcp.ConnectionService,
	modelsService *models.Service,
	providersService *providers.Service,
	memProvService *memprovider.Service,
	searchProvService *searchproviders.Service,
	emailService *emailpkg.Service,
	emailOutboxService *emailpkg.OutboxService,
	queries CommandQueries,
	aclEvaluator AccessEvaluator,
	skillLoader SkillLoader,
	containerFS ContainerFS,
) *Handler

NewHandler creates a Handler with all required services.

func (*Handler) CommandAccess

func (h *Handler) CommandAccess(ctx context.Context, input ExecuteInput) (bool, error)

CommandAccess reports whether the caller may operate a command on the bot, applying the same policy as Execute's gate: /link is always allowed; owners and managers are always allowed; everyone else must pass the chat ACL. The channel processor uses it to gate the route-aware mode commands (/new, /stop, /status) that do not flow through Execute.

func (*Handler) CurrentContext

func (h *Handler) CurrentContext(ctx context.Context, botID string) (CurrentContext, error)

CurrentContext resolves the bot's current model/reasoning state for enriching command output (e.g. the /new confirmation). It is a read-only view over existing bot settings and makes no changes.

func (*Handler) Execute

func (h *Handler) Execute(ctx context.Context, botID, channelIdentityID, text string) (string, error)

Execute parses and runs a slash command, returning the text reply.

func (*Handler) ExecuteResult

func (h *Handler) ExecuteResult(ctx context.Context, input ExecuteInput) (res *Result, err error)

ExecuteResult parses and runs a slash command, returning a neutral Result. The Result always carries complete Text; Interactive is set only by commands that opt into rich rendering via SubCommand.ResultHandler.

func (*Handler) ExecuteWithInput

func (h *Handler) ExecuteWithInput(ctx context.Context, input ExecuteInput) (string, error)

ExecuteWithInput parses and runs a slash command with channel/session context, returning the plain-text reply. It delegates to ExecuteResult and flattens the structured result to its text form.

func (*Handler) HasCommandResource

func (h *Handler) HasCommandResource(resource string) bool

HasCommandResource checks registry membership for an already parsed command. Channel classification uses this form so it never reparses a synthetic string.

func (*Handler) IsCommand

func (h *Handler) IsCommand(text string) bool

IsCommand reports whether the text contains a slash command. Handles both direct commands ("/help") and mention-prefixed commands ("@bot /help").

func (*Handler) IsCommandShaped

func (*Handler) IsCommandShaped(text string) bool

IsCommandShaped reports whether text looks like a slash command (a leading slash followed by a command-name token), whether or not it is registered. It lets the channel layer reply with a helpful "unknown command" hint instead of forwarding a mistyped command to the model. Paths/URLs (e.g. "/a/b") are rejected so they are not mistaken for commands.

func (*Handler) MemberRole

func (h *Handler) MemberRole(ctx context.Context, botID, channelIdentityID string) (string, error)

MemberRole resolves the sender's bot role for presentation decisions outside command execution. Callers must not use it as an authorization shortcut.

func (*Handler) ResolveLocale

func (h *Handler) ResolveLocale(ctx context.Context, botID string) string

ResolveLocale resolves the command-UI locale for a bot from its command_ui_language setting (auto/unknown → server default). Any settings I/O error falls back to the default locale, so command rendering never blocks on it. Exported so the channel layer can localize its own renderer chrome and operational-failure messages with the same locale.

Uses the scoped GetCommandUILanguage (single DB query) rather than GetBot (which also fetches the ACL default-effect) — the locale is resolved per command and per interactive callback tap, so single-query matters for paginated lists where users tap Prev/Next repeatedly.

func (*Handler) SetCompactionService

func (h *Handler) SetCompactionService(s *compaction.Service, q dbstore.Queries)

SetCompactionService configures the compaction service for the /compact command.

func (*Handler) SetLinkConsumer

func (h *Handler) SetLinkConsumer(c LinkConsumer)

SetLinkConsumer wires the account-link consumer used by the /link command.

type HintVerb

type HintVerb string

HintVerb names the shape of a typeable affordance when rendering the no-button fallback trailer. Setting ListView.HintVerb to one of these overrides the automatic inference in FallbackTrailer.

The values double as the suffix of the i18n key (cmd.fallback.<verb>) so adding a verb is a two-step change: register the constant here and add the matching localized template in locales/*.json.

const (
	HintVerbSwitch  HintVerb = "switch"
	HintVerbPick    HintVerb = "pick"
	HintVerbToggle  HintVerb = "toggle"
	HintVerbOpen    HintVerb = "open"
	HintVerbDetails HintVerb = "details"
	HintVerbRange   HintVerb = "range"
	HintVerbMenu    HintVerb = "menu"
)

type Interactive

type Interactive struct {
	Kind    InteractiveKind
	List    *ListView
	Picker  *ModelPickerView
	Choices *ChoicesView
	Range   *RangeView
}

Interactive carries optional structured data for rich rendering. Exactly one of the typed views is set, selected by Kind.

type InteractiveKind

type InteractiveKind string

InteractiveKind discriminates the structured payload carried by a Result.

const (
	// InteractiveList is a generic, paginated list of display rows.
	InteractiveList InteractiveKind = "list"
	// InteractiveModelPicker is the two-level provider→model drill-down picker.
	InteractiveModelPicker InteractiveKind = "model_picker"
	// InteractiveChoices is a flat one-shot set of selectable choices.
	InteractiveChoices InteractiveKind = "choices"
	// InteractiveRange is a time-window selector for time-series commands.
	InteractiveRange InteractiveKind = "range"
)

type Invocation

type Invocation = commandsyntax.Invocation

ParsedCommand remains an alias so command handlers and callers can migrate to the shared syntax package without duplicating the parser implementation.

func ParseInvocation

func ParseInvocation(input InvocationInput) (Invocation, error)

type InvocationInput

type InvocationInput = commandsyntax.InvocationInput

ParsedCommand remains an alias so command handlers and callers can migrate to the shared syntax package without duplicating the parser implementation.

type ItemAction

type ItemAction struct {
	Resource string
	Action   string
	Args     []string
}

ItemAction triggers a command when a row is tapped.

func (*ItemAction) Typeable

func (a *ItemAction) Typeable() string

Typeable renders an ItemAction as the slash command a user would type to invoke it (e.g. "/memory set Alice"). Nil-safe.

Unlike ParsedCallback.SyntheticCommand, this is designed for display in hint text — it does not append --page artifacts and does not round-trip through the callback encoder.

Args containing whitespace are double-quoted so a copy-pasted hint round-trips through Parse()/tokenize() back to the same intent. Without quoting, `/memory set my provider` would tokenize as ["my", "provider"] and the handler would read only "my" — silently picking the wrong target.

type LinkConsumer

type LinkConsumer interface {
	ConsumeLinkCode(ctx context.Context, token, channelIdentityID string) (channelaccess.Binding, error)
}

LinkConsumer binds the calling channel identity to the web user that owns a one-time link code. It is satisfied by channelaccess.Service.

type ListItem

type ListItem struct {
	Label    string
	Detail   string
	Selected bool
	Action   *ItemAction
	Callback string
}

ListItem is one row in a ListView. Action is nil for display-only rows.

Callback optionally carries pre-encoded callback_data for button-capable renderers; when set it takes precedence over Action as the button value. Rows with only Callback stay out of the no-button fallback trailer (which derives typeable hints from Action), so such callers must carry the typeable form in the body text instead.

type ListView

type ListView struct {
	Title        string
	ButtonText   string   // optional compact text for button-capable channels
	Resource     string   // command resource (e.g. "mcp"), round-trips in callback data
	Action       string   // command action (e.g. "list")
	Args         []string // narrowing args (e.g. a provider filter) that round-trip
	Items        []ListItem
	Total        int        // total items across all pages
	Page         int        // zero-based page index of this view
	PageSize     int        // items per page
	ExtraActions []ListItem // contextual action buttons below the list rows (e.g. "All commands")
	HintVerb     HintVerb   // optional fallback-trailer verb override (HintVerb*)
}

ListView is a generic paginated list. It is re-derivable by re-running the originating command with a page offset, so Resource/Action/Args round-trip through the callback data of pagination buttons.

HintVerb is an optional explicit verb (one of HintVerb*) for trailer derivation on no-button channels — used when rows are display-only but the list has a paired typeable affordance (e.g. /mcp list rows are display-only but /mcp get <name> is the typeable next step). Empty = infer from structure.

Note the asymmetry with ChoicesView.BodyEnumeratesChoices: ListView needs to pick WHICH verb to emit, ChoicesView only needs to choose WHETHER to emit. Different questions, different mechanisms — kept that way rather than forcing them into one shape that fits neither cleanly.

type MemberRoleResolver

type MemberRoleResolver interface {
	GetMemberRole(ctx context.Context, botID, channelIdentityID string) (string, error)
}

MemberRoleResolver resolves a user's role within a bot.

type MenuCommand struct {
	Command     string // command name without the leading slash, lowercase
	Description string // short label shown beside the command in the menu
}

MenuCommand is one entry for a channel's native slash-command menu (e.g. Telegram's setMyCommands), so users discover and tap commands without typing.

func MenuCommands(t *i18n.Localizer) []MenuCommand

MenuCommands returns the curated slash-command list to advertise in a channel's native command menu, with descriptions localized via t. It is the single source for that menu; order roughly follows everyday usefulness. Only single-token commands belong here — the native menu cannot express sub-actions like "schedule list" (those are discovered via /help or in-message buttons).

A nil Localizer renders English (the safe default), which is what transport adapters that register the menu without per-bot locale context currently pass.

type ModelPickerView

type ModelPickerView struct {
	Level            PickerLevel
	Providers        []PickerProvider // populated at the provider level
	Models           []PickerModel    // populated at the model level
	ProviderIndex    int              // which provider we drilled into (model level)
	ProviderName     string           // name of that provider (model level), for the header
	Page             int
	PageSize         int
	Total            int
	CurrentModelDBID string // settings.ChatModelID, for ●/✓ marking
	CurrentDisplay   string // resolved current chat model "Name (Provider)", for the header
	Reasoning        string // current reasoning effort label, for the header
}

ModelPickerView is the two-level model picker (populated in the model-picker phase). Level selects whether Providers or Models is rendered.

type ParsedCallback

type ParsedCallback struct {
	Kind          string
	Resource      string
	Action        string
	Args          []string
	Page          int
	ProviderIndex int
	SelectID      string
	Range         string
}

ParsedCallback is the decoded form of an interactive callback_data string.

func DecodeCallback

func DecodeCallback(data string) (ParsedCallback, bool)

DecodeCallback parses an interactive callback_data string. The bool is false for data that is not one of our interactive callbacks.

func (ParsedCallback) IsDismiss

func (p ParsedCallback) IsDismiss() bool

IsDismiss reports whether the callback closes the interactive message.

func (ParsedCallback) IsNoop

func (p ParsedCallback) IsNoop() bool

IsNoop reports whether the callback is inert (e.g. the page indicator).

func (ParsedCallback) IsSkillActivation

func (p ParsedCallback) IsSkillActivation() bool

IsSkillActivation reports whether the callback activates a skill. Unlike pagination/selection callbacks, activation starts a fresh chat turn: adapters must dispatch it as a new directed message instead of editing the tapped card in place.

func (ParsedCallback) SyntheticCommand

func (p ParsedCallback) SyntheticCommand() string

SyntheticCommand returns the slash command text to re-dispatch for a parsed callback, or "" when the callback has no command (dismiss/noop).

type ParsedCommand

type ParsedCommand = commandsyntax.ParsedCommand

ParsedCommand remains an alias so command handlers and callers can migrate to the shared syntax package without duplicating the parser implementation.

func Parse

func Parse(text string) (ParsedCommand, error)

type PickerLevel

type PickerLevel string

PickerLevel is the drill-down level of a ModelPickerView.

const (
	// LevelProviders renders the provider grid.
	LevelProviders PickerLevel = "providers"
	// LevelModels renders the paginated model list for one provider.
	LevelModels PickerLevel = "models"
)

type PickerModel

type PickerModel struct {
	DBID     string
	Name     string
	Provider string
	Selected bool
}

PickerModel is one model button in the picker. Selected marks the active model (rendered with ✓). DBID is the model's stable id, carried in the selection callback so a list change between render and tap can't resolve the tap to a different model.

type PickerProvider

type PickerProvider struct {
	Index      int
	Name       string
	Count      int
	HasCurrent bool
}

PickerProvider is one provider button in the picker. HasCurrent marks the provider that holds the currently-selected model (rendered with ●). Count is the number of chat models the provider offers.

type RangeView

type RangeView struct {
	Resource string
	Action   string
	Current  string   // the active preset key (normalized), for the ● marker
	Presets  []string // ordered preset keys, e.g. ["24h","7d","30d","all"]
}

RangeView is a time-window selector for a time-series command. Selecting a preset re-runs "/{Resource} {Action} --range <preset>" in place.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds all registered command groups.

func (*Registry) ActionHelp

func (r *Registry) ActionHelp(groupName, action string, localizers ...*i18n.Localizer) string

func (*Registry) GlobalHelp

func (r *Registry) GlobalHelp(t *i18n.Localizer, commandTarget string) string

GlobalHelp returns the top-level help text listing all commands. Commands stay short, plain, and tap-to-send; Telegram's manual /command@bot rule appears once below the list instead of repeating the username on every row.

func (*Registry) GroupHelp

func (r *Registry) GroupHelp(name string, localizers ...*i18n.Localizer) string

func (*Registry) GroupHelpResult

func (r *Registry) GroupHelpResult(name string, localizers ...*i18n.Localizer) *Result

GroupHelpResult returns an interactive version of GroupHelp: each sub-action is a tappable button that dispatches "/{group} {action}" in place, plus a "◀ Back" button that returns to the group's default content view. Text-only channels fall back to the textual Usage listing.

func (*Registry) RegisterGroup

func (r *Registry) RegisterGroup(group *CommandGroup)

type Result

type Result struct {
	Text          string
	Interactive   *Interactive
	Locale        string
	FeedbackError *agentfeedback.Error
}

Result is the neutral, platform-independent output of a command.

Text is always a complete rendering usable by channels without rich UI. Interactive is optional structured data that capable renderers (e.g. the Telegram inline keyboard) may upgrade into buttons and pagination.

Locale is the resolved command-UI locale ("en", "zh", …) the Text/Interactive labels were rendered in. Channels use it to localize their own renderer chrome (Close/Prev/Next/…) so the whole reply stays in one language. Empty means the server default (English).

func WithButtons

func WithButtons(r *Result, buttons ...ListItem) *Result

WithButtons attaches tappable action buttons to any Result (including plain text / empty states). Button channels render a ChoicesView; text-only channels see only the text. Use this for empty-state guidance buttons ("All commands ▸") where there is no list to attach ExtraActions to.

func WithExtraActions

func WithExtraActions(r *Result, extras ...ListItem) *Result

WithExtraActions attaches contextual entry buttons below the list rows of a Result (e.g. "All commands", "Create new"). Only meaningful when the Result carries an InteractiveList. Nil/non-list Results pass through unchanged.

type RuntimeSkillLister

type RuntimeSkillLister interface {
	ListRuntimeSkills(ctx context.Context, botID string) ([]Skill, error)
}

RuntimeSkillLister lists the bot's runtime-usable skills — the same safe catalog the Web slash picker shows (unique, enabled, loadable as model context). Optional capability of SkillLoader implementations: when present, /skill list renders these entries with tap-to-activate buttons instead of the raw full listing, so IM and Web expose one identical skill surface.

type Skill

type Skill struct {
	Name        string
	Description string
}

Skill represents a single skill loaded from a bot's container.

type SkillLoader

type SkillLoader interface {
	LoadSkills(ctx context.Context, botID string) ([]Skill, error)
}

SkillLoader loads skills for a bot.

type SubCommand

type SubCommand struct {
	Name          string
	Usage         string
	IsWrite       bool
	Handler       func(cc CommandContext) (string, error)
	ResultHandler func(cc CommandContext) (*Result, error)
}

SubCommand describes a single sub-command within a resource group.

A sub-command provides either Handler (plain text) or ResultHandler (structured Result for rich rendering). When both are set, ResultHandler takes precedence.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL