bot

package
v0.260414.2000 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2026 License: MPL-2.0 Imports: 33 Imported by: 0

Documentation

Overview

Package command provides built-in command definitions for the remote control bot.

Index

Constants

View Source
const (
	DefaultMaxImageSize = 25 * 1024 * 1024 // 25MB
	DefaultMaxDocSize   = 50 * 1024 * 1024 // 50MB
)
View Source
const (
	// Icons
	IconProject = "📁"  // Project/folder
	IconChat    = "💬"  // Chat/conversation
	IconUser    = "👤"  // User
	IconSession = "🔄"  // Session
	IconAgentTB = "🎯"  // Tingly-Box agent (@tb)
	IconAgentCC = "💬"  // Claude Code agent (@cc)
	IconDone    = "✅"  // Task completed
	IconError   = "❌"  // Error
	IconWarning = "⚠️" // Warning
	IconStop    = "🛑"  // Stopped
	IconProcess = "⏳"  // Processing
	IconMock    = "🧪"  // Mock agent
)

Output format constants for bot messages Centralized for easy customization and i18n support

View Source
const (
	AgentNameTB        = "@tb" // Tingly-Box short name
	AgentNameCC        = "@cc" // Claude Code short name
	AgentNameTinglyBox = "tingly-box"
	AgentNameClaude    = "claude"
)

Agent display names

View Source
const (
	SeparatorLine = "───────────────"
	SeparatorFull = "━━━━━━━━━━━━━━━━━━━━"
)

Separator line for message formatting

View Source
const (
	MsgProcessing     = "Processing..."
	MsgTaskDone       = "Task done"
	MsgTaskStopped    = "Task stopped"
	MsgContinueOrHelp = "Continue or /help."
	MsgNoRunningTask  = "No running task to stop."
)

Status messages

View Source
const (
	// Status line formats
	FormatProjectLine = "%s %s\n" // icon + path
	FormatAgentLine   = "%s %s\n" // icon + agent name
	FormatDebugLine   = "%s %s\n" // icon + id value

	// Footer format (separator + agent + path)
	FormatFooter = "\n%s\n%s %s\n📁 %s" // separator + icon + agent + path
)

Format templates (use with fmt.Sprintf)

Variables

View Source
var (
	ErrStoreNotInitialized = errors.New("chat store not initialized")
	ErrChatNotFound        = errors.New("chat not found")
)

Error definitions

View Source
var AllowedMIMETypes = map[string]string{

	"image/jpeg": "image",
	"image/png":  "image",
	"image/gif":  "image",
	"image/webp": "image",

	"application/pdf": "document",
	"text/plain":      "document",
	"text/markdown":   "document",
	"text/csv":        "document",

	"application/msword": "document",
	"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "document",

	"application/vnd.ms-excel": "document",
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "document",
}

AllowedMIMETypes lists supported file types

Functions

func BuildActionKeyboard

func BuildActionKeyboard() *imbot.KeyboardBuilder

BuildActionKeyboard builds the inline keyboard for actions (Clear/Bind)

func BuildBindConfirmKeyboard

func BuildBindConfirmKeyboard() *imbot.KeyboardBuilder

BuildBindConfirmKeyboard builds the confirmation keyboard for binding to current directory

func BuildBindConfirmPrompt

func BuildBindConfirmPrompt(proposedPath string) string

BuildBindConfirmPrompt returns the text for bind confirmation prompt

func BuildCancelKeyboard

func BuildCancelKeyboard() *imbot.KeyboardBuilder

BuildCancelKeyboard builds a simple cancel keyboard

func BuildCreateConfirmKeyboard

func BuildCreateConfirmKeyboard(path string) (*imbot.KeyboardBuilder, string)

BuildCreateConfirmKeyboard builds the confirmation keyboard for creating a directory

func BuildCustomPathPrompt

func BuildCustomPathPrompt() string

BuildCustomPathPrompt returns the text for custom path input prompt

func BuildFooter

func BuildFooter(agentType, projectPath string) string

BuildFooter creates a compact footer line with agent and path info Format: separator + "📁 path · icon agent" Path is always present (defaults are resolved before calling this)

func ExpandPath

func ExpandPath(path string) (string, error)

ExpandPath expands ~ and environment variables in a path

func GetAgentDisplayName

func GetAgentDisplayName(agentType string) string

GetAgentDisplayName returns the short display name for an agent type

func GetAgentIcon

func GetAgentIcon(agentType string) string

GetAgentIcon returns the icon for an agent type

func IsLowFrequencyPlatform

func IsLowFrequencyPlatform(platform string) bool

IsLowFrequencyPlatform checks if the platform has low-frequency sending limitations Some platforms (e.g., Weixin) need rate limiting for message sending

func ParseTextResponse

func ParseTextResponse(text string) (approved bool, remember bool, isValid bool)

ParseTextResponse parses user text input as a permission response Returns: (approved, remember, isValid)

func RegisterBuiltinCommands

func RegisterBuiltinCommands(registry *imbot.CommandRegistry, botHandler BotHandlerAdapter) error

RegisterBuiltinCommands registers all built-in commands to the registry.

func RegisterMenu

func RegisterMenu(config MenuButtonConfig)

RegisterMenu registers a menu in the default registry

func SendDirectoryBrowser

func SendDirectoryBrowser(ctx context.Context, bot imbot.Bot, browser *DirectoryBrowser, chatID string, editMessageID string) (string, error)

SendDirectoryBrowser sends or updates the directory browser message

func SetupMenuButtonForBot

func SetupMenuButtonForBot(manager *imbot.Manager, uuid string, cmdRegistry *imbot.CommandRegistry) error

SetupMenuButtonForBot configures the menu button for a bot This should be called when the bot starts or when settings change

func ShortenID

func ShortenID(id string, maxLen int) string

ShortenID truncates an ID to a readable length e.g., "a1b2c3d4e5f6g7h8" -> "a1b2c3d4"

func ShortenPath

func ShortenPath(path string) string

ShortenPath shortens a path for display

func SupportsVerboseMode

func SupportsVerboseMode(platform string) bool

SupportsVerboseMode checks if the platform supports verbose mode Some platforms (e.g., Weixin) can only receive final messages, not intermediate ones

func ValidateProjectPath

func ValidateProjectPath(path string) error

ValidateProjectPath validates that a path is a valid project directory

Types

type AgentExecutor

type AgentExecutor interface {
	// Execute processes a prepared request and returns the result.
	Execute(ctx context.Context, req PreparedRequest) (*ExecutionResult, error)

	// GetAgentType returns the agent type identifier
	GetAgentType() agentboot.AgentType
}

AgentExecutor defines the interface for executing agent requests. Each agent type (Claude Code, Smart Guide, Mock) implements this interface.

type AgentRouter

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

AgentRouter routes execution requests to the appropriate agent executor. It resolves common concerns (project path, session, meta, cancel context) once, then delegates to the specific executor.

func NewAgentRouter

func NewAgentRouter(deps *ExecutorDependencies) *AgentRouter

NewAgentRouter creates a new agent router with the given dependencies

func (*AgentRouter) Execute

Execute routes the execution request to the appropriate agent executor. It resolves project path, session, and builds shared *ResponseMeta before delegating.

func (*AgentRouter) GetExecutor

func (r *AgentRouter) GetExecutor(agentType agentboot.AgentType) (AgentExecutor, bool)

GetExecutor returns the executor for a given agent type

func (*AgentRouter) ListExecutors

func (r *AgentRouter) ListExecutors() []agentboot.AgentType

ListExecutors returns all registered agent types

func (*AgentRouter) RegisterExecutor

func (r *AgentRouter) RegisterExecutor(executor AgentExecutor)

RegisterExecutor registers an agent executor

type BindFlowState

type BindFlowState struct {
	ChatID       string
	CurrentPath  string
	Page         int
	TotalDirs    int
	PageSize     int
	MessageID    string // Message ID to edit
	ExpiresAt    time.Time
	WaitingInput bool     // Waiting for custom path input
	PromptMsgID  string   // Prompt message ID for cleanup
	Dirs         []string // Current directory list (for navigation by index)
}

BindFlowState represents the state of an ongoing bind flow

type BotHandler

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

BotHandler encapsulates all bot message handling logic and dependencies

func NewBotHandler

func NewBotHandler(
	ctx context.Context,
	botSetting BotSetting,
	chatStore ChatStoreInterface,
	sessionMgr *session.Manager,
	agentBoot *agentboot.AgentBoot,
	directoryBrowser *DirectoryBrowser,
	manager *imbot.Manager,
	tbClient tbclient.TBClient,
) *BotHandler

NewBotHandler creates a new bot handler with all dependencies

func (*BotHandler) GetCommandRegistry

func (h *BotHandler) GetCommandRegistry() *imbot.CommandRegistry

GetCommandRegistry returns the command registry.

func (*BotHandler) GetVerbose

func (h *BotHandler) GetVerbose(chatID string) bool

GetVerbose returns the current verbose mode setting for a chat Checks chat store first, then bot setting default Returns false for platforms that don't support verbose mode (e.g., Weixin)

func (*BotHandler) HandleCommandViaRegistry

func (h *BotHandler) HandleCommandViaRegistry(hCtx HandlerContext, cmdName string, args []string) error

HandleCommandViaRegistry handles a command using the new command registry.

func (*BotHandler) HandleMessage

func (h *BotHandler) HandleMessage(msg imbot.Message, platform imbot.Platform, botUUID string)

HandleMessage is the main entry point for handling bot messages

func (*BotHandler) InitCommandRegistry

func (h *BotHandler) InitCommandRegistry() error

InitCommandRegistry initializes the command registry with built-in commands.

func (*BotHandler) RequestConfirmation

func (h *BotHandler) RequestConfirmation(ctx context.Context, hCtx HandlerContext, message, requestID string) (bool, error)

RequestConfirmation requests a yes/no confirmation from the user Uses the new interaction system with platform-agnostic UI

func (*BotHandler) RequestInteraction

RequestInteraction sends an interaction request using the new interaction system This is a convenience method for BotHandler to request platform-agnostic interactions

func (*BotHandler) RequestOptionSelection

func (h *BotHandler) RequestOptionSelection(ctx context.Context, hCtx HandlerContext, message, requestID string, options []imbot.Option) (int, *imbot.Interaction, error)

RequestOptionSelection requests the user to select from a list of options Uses the new interaction system with platform-agnostic UI

func (*BotHandler) SendFile added in v0.260414.2000

func (h *BotHandler) SendFile(ctx context.Context, hCtx HandlerContext, filePath, caption string) error

SendFile sends a local file to the user via the IM bot. The file is read from disk and sent as a MediaAttachment. caption may be empty.

func (*BotHandler) SendText

func (h *BotHandler) SendText(hCtx HandlerContext, text string)

SendText sends a plain text message Note: Platform handles chunking internally via BaseBot.ChunkText()

func (*BotHandler) SetVerbose

func (h *BotHandler) SetVerbose(chatID string, verbose bool)

SetVerbose sets the verbose mode for a chat

type BotHandlerAdapter

type BotHandlerAdapter interface {
	// SendText sends a text message to a chat
	SendText(chatID, text string) error

	// GetProjectPath gets the current project path for a chat
	GetProjectPath(chatID string) (string, error)

	// SetProjectPath sets the project path for a chat
	SetProjectPath(chatID, path string) error

	// GetProjectPathForGroup gets project path with group fallback
	GetProjectPathForGroup(chatID, platform string) (string, bool)

	// GetSession gets session info
	GetSession(chatID, agentType, projectPath string) (*SessionInfo, error)

	// FindOrCreateSession finds an existing session or creates a new one
	FindOrCreateSession(chatID, agentType, projectPath string) (*SessionInfo, error)

	// UpdatePermissionMode updates the permission mode for a session
	UpdatePermissionMode(sessionID, mode string) error

	// ClearSession clears a session
	ClearSession(chatID, agentType string) error

	// StopExecution cancels a running execution, returns true if one was running
	StopExecution(chatID string) bool

	// GetCurrentAgent gets the current agent for a chat
	GetCurrentAgent(chatID string) (string, error)

	// SetVerbose sets verbose mode for a chat
	SetVerbose(chatID string, enabled bool)

	// GetVerbose gets verbose mode for a chat
	GetVerbose(chatID string) bool

	// IsWhitelisted checks if a group is whitelisted
	IsWhitelisted(groupID string) bool

	// AddToWhitelist adds a group to whitelist
	AddToWhitelist(groupID, platform, userID string) error

	// GetBashCwd gets the bash working directory
	GetBashCwd(chatID string) (string, error)

	// SetBashCwd sets the bash working directory
	SetBashCwd(chatID, path string) error

	// ResolveChatID resolves a chat ID (for Telegram join command)
	ResolveChatID(input string) (string, error)

	// GetDefaultProjectPath returns the default project path
	GetDefaultProjectPath() string

	// GetBashAllowlist returns the configured bash allowlist
	GetBashAllowlist() map[string]struct{}

	// ListProjectPaths lists all project paths for a user
	ListProjectPaths(ownerID, platform string) ([]string, error)
}

BotHandlerAdapter provides methods needed by command handlers. This allows commands to interact with the bot without direct coupling.

func NewBotHandlerAdapter

func NewBotHandlerAdapter(handler *BotHandler) BotHandlerAdapter

NewBotHandlerAdapter creates a new adapter for the given handler.

type BotSetting

type BotSetting struct {
	UUID          string            `json:"uuid,omitempty"`           // UUID for bot identification
	Name          string            `json:"name,omitempty"`           // User-defined name for the bot
	Token         string            `json:"token,omitempty"`          // Legacy: for backward compatibility
	Platform      string            `json:"platform"`                 // Platform identifier
	AuthType      string            `json:"auth_type"`                // Auth type: token, oauth, qr
	Auth          map[string]string `json:"auth"`                     // Dynamic auth fields based on platform
	ProxyURL      string            `json:"proxy_url,omitempty"`      // Optional proxy URL
	ChatIDLock    string            `json:"chat_id,omitempty"`        // Optional chat ID lock
	BashAllowlist []string          `json:"bash_allowlist,omitempty"` // Optional bash command allowlist
	DefaultCwd    string            `json:"default_cwd,omitempty"`    // Default working directory if no project bound
	Enabled       bool              `json:"enabled"`                  // Whether this bot is enabled

	// Output behavior settings
	Verbose *bool `json:"verbose,omitempty"` // Send intermediate messages (nil = true default)

	// SmartGuide model configuration (required for @tb agent)
	SmartGuideProvider string `json:"smartguide_provider,omitempty"` // Provider UUID
	SmartGuideModel    string `json:"smartguide_model,omitempty"`    // Model identifier

	CreatedAt string `json:"created_at,omitempty"`
	UpdatedAt string `json:"updated_at,omitempty"`
}

BotSetting represents bot configuration with platform-specific auth

func (BotSetting) GetOutputBehavior

func (s BotSetting) GetOutputBehavior() OutputBehavior

GetOutputBehavior extracts output behavior from bot setting

type Chat

type Chat struct {
	ChatID      string `json:"chat_id"`
	Platform    string `json:"platform"`
	ProjectPath string `json:"project_path,omitempty"`
	OwnerID     string `json:"owner_id,omitempty"`

	// Group-specific
	IsWhitelisted bool   `json:"is_whitelisted"`
	WhitelistedBy string `json:"whitelisted_by,omitempty"`

	// Bash state
	BashCwd string `json:"bash_cwd,omitempty"`

	// Agent state (for smart guide handoff)
	CurrentAgent string `json:"current_agent,omitempty"` // "tingly-box" or "claude"
	AgentState   []byte `json:"agent_state,omitempty"`   // JSON-encoded agent-specific state

	// Chat-level settings
	Verbose *bool `json:"verbose,omitempty"` // Verbose mode: nil=use bot default, true=verbose, false=quiet

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Chat represents all state associated with a chat (direct or group)

type ChatStoreInterface

type ChatStoreInterface interface {
	// Close ensures data is persisted before closing
	Close() error

	// GetChat retrieves a chat by ID
	GetChat(chatID string) (*Chat, error)

	// GetOrCreateChat gets a chat or creates it if not exists
	GetOrCreateChat(chatID, platform string) (*Chat, error)

	// UpsertChat creates or updates a chat
	UpsertChat(chat *Chat) error

	// UpdateChat updates specific fields of a chat
	UpdateChat(chatID string, fn func(*Chat)) error

	// BindProject binds a project to a chat
	BindProject(chatID, platform, projectPath, ownerID string) error

	// GetProjectPath retrieves the project path for a chat
	GetProjectPath(chatID string) (string, bool, error)

	// ListChatsByOwner lists all chats owned by a user
	ListChatsByOwner(ownerID, platform string) ([]*Chat, error)

	// AddToWhitelist adds a chat to the whitelist
	AddToWhitelist(chatID, platform, addedBy string) error

	// RemoveFromWhitelist removes a chat from the whitelist
	RemoveFromWhitelist(chatID string) error

	// IsWhitelisted checks if a chat is whitelisted
	IsWhitelisted(chatID string) bool

	// SetBashCwd sets the bash working directory for a chat
	SetBashCwd(chatID, cwd string) error

	// GetBashCwd retrieves the bash working directory for a chat
	GetBashCwd(chatID string) (string, bool, error)

	// SetCurrentAgent sets the current agent for a chat
	SetCurrentAgent(chatID, agentType string) error

	// GetCurrentAgent retrieves the current agent for a chat
	GetCurrentAgent(chatID string) (string, error)

	// SetAgentState sets the agent-specific state for a chat
	SetAgentState(chatID string, state []byte) error

	// GetAgentState retrieves the agent-specific state for a chat
	GetAgentState(chatID string) ([]byte, error)

	// ListWhitelistedGroups returns all whitelisted groups
	ListWhitelistedGroups() ([]struct {
		GroupID   string
		Platform  string
		AddedBy   string
		CreatedAt string
	}, error)
}

ChatStoreInterface defines the interface for chat persistence This allows both SQLite-based ChatStore and JSON-based ChatStoreJSON to be used interchangeably

type ChatStoreJSON

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

ChatStoreJSON handles unified chat persistence using JSON file storage This is the new implementation replacing the SQLite-based ChatStore

func NewChatStoreJSON

func NewChatStoreJSON(filePath string) (*ChatStoreJSON, error)

NewChatStoreJSON creates a new JSON-based chat store

func (*ChatStoreJSON) AddToWhitelist

func (s *ChatStoreJSON) AddToWhitelist(chatID, platform, addedBy string) error

AddToWhitelist adds a chat to the whitelist

func (*ChatStoreJSON) BindProject

func (s *ChatStoreJSON) BindProject(chatID, platform, projectPath, ownerID string) error

BindProject binds a project to a chat (creates chat if not exists)

func (*ChatStoreJSON) Close

func (s *ChatStoreJSON) Close() error

Close ensures data is persisted before closing

func (*ChatStoreJSON) GetAgentState

func (s *ChatStoreJSON) GetAgentState(chatID string) ([]byte, error)

GetAgentState retrieves the agent-specific state for a chat

func (*ChatStoreJSON) GetBashCwd

func (s *ChatStoreJSON) GetBashCwd(chatID string) (string, bool, error)

GetBashCwd retrieves the bash working directory for a chat

func (*ChatStoreJSON) GetChat

func (s *ChatStoreJSON) GetChat(chatID string) (*Chat, error)

GetChat retrieves a chat by ID

func (*ChatStoreJSON) GetCurrentAgent

func (s *ChatStoreJSON) GetCurrentAgent(chatID string) (string, error)

GetCurrentAgent retrieves the current agent for a chat Returns "tingly-box" as default (Smart Guide is the entry point)

func (*ChatStoreJSON) GetOrCreateChat

func (s *ChatStoreJSON) GetOrCreateChat(chatID, platform string) (*Chat, error)

GetOrCreateChat gets a chat or creates it if not exists

func (*ChatStoreJSON) GetProjectPath

func (s *ChatStoreJSON) GetProjectPath(chatID string) (string, bool, error)

GetProjectPath retrieves the project path for a chat

func (*ChatStoreJSON) IsWhitelisted

func (s *ChatStoreJSON) IsWhitelisted(chatID string) bool

IsWhitelisted checks if a chat is whitelisted

func (*ChatStoreJSON) ListChatsByOwner

func (s *ChatStoreJSON) ListChatsByOwner(ownerID, platform string) ([]*Chat, error)

ListChatsByOwner lists all chats owned by a user

func (*ChatStoreJSON) ListWhitelistedGroups

func (s *ChatStoreJSON) ListWhitelistedGroups() ([]struct {
	GroupID   string
	Platform  string
	AddedBy   string
	CreatedAt string
}, error)

ListWhitelistedGroups returns all whitelisted groups

func (*ChatStoreJSON) RemoveFromWhitelist

func (s *ChatStoreJSON) RemoveFromWhitelist(chatID string) error

RemoveFromWhitelist removes a chat from the whitelist

func (*ChatStoreJSON) SetAgentState

func (s *ChatStoreJSON) SetAgentState(chatID string, state []byte) error

SetAgentState sets the agent-specific state for a chat

func (*ChatStoreJSON) SetBashCwd

func (s *ChatStoreJSON) SetBashCwd(chatID, cwd string) error

SetBashCwd sets the bash working directory for a chat

func (*ChatStoreJSON) SetCurrentAgent

func (s *ChatStoreJSON) SetCurrentAgent(chatID, agentType string) error

SetCurrentAgent sets the current agent for a chat

func (*ChatStoreJSON) UpdateChat

func (s *ChatStoreJSON) UpdateChat(chatID string, fn func(*Chat)) error

UpdateChat updates specific fields of a chat

func (*ChatStoreJSON) UpsertChat

func (s *ChatStoreJSON) UpsertChat(chat *Chat) error

UpsertChat creates or updates a chat

type ClaudeCodeExecutor

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

ClaudeCodeExecutor executes messages through Claude Code agent

func NewClaudeCodeExecutor

func NewClaudeCodeExecutor(deps *ExecutorDependencies) *ClaudeCodeExecutor

NewClaudeCodeExecutor creates a new Claude Code executor

func (*ClaudeCodeExecutor) Execute

Execute processes a user message through Claude Code

func (*ClaudeCodeExecutor) GetAgentType

func (e *ClaudeCodeExecutor) GetAgentType() agentboot.AgentType

GetAgentType returns the agent type identifier

type CompletionCallback

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

func (*CompletionCallback) OnComplete

func (c *CompletionCallback) OnComplete(result *agentboot.CompletionResult)

type DirectoryBrowser

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

DirectoryBrowser manages directory navigation for bind flow

func NewDirectoryBrowser

func NewDirectoryBrowser() *DirectoryBrowser

NewDirectoryBrowser creates a new directory browser

func (*DirectoryBrowser) BuildKeyboard

func (b *DirectoryBrowser) BuildKeyboard(chatID string) (*BindFlowState, *imbot.KeyboardBuilder, string, error)

BuildKeyboard builds the inline keyboard for directory browsing

func (*DirectoryBrowser) Clear

func (b *DirectoryBrowser) Clear(chatID string)

Clear removes the state for a chat

func (*DirectoryBrowser) GetCurrentPath

func (b *DirectoryBrowser) GetCurrentPath(chatID string) string

GetCurrentPath returns the current path for a chat

func (*DirectoryBrowser) GetState

func (b *DirectoryBrowser) GetState(chatID string) *BindFlowState

GetState returns the current state for a chat

func (*DirectoryBrowser) IsWaitingInput

func (b *DirectoryBrowser) IsWaitingInput(chatID string) bool

IsWaitingInput checks if the chat is waiting for custom path input

func (*DirectoryBrowser) Navigate

func (b *DirectoryBrowser) Navigate(chatID string, path string) error

Navigate navigates to a subdirectory

func (*DirectoryBrowser) NavigateByIndex

func (b *DirectoryBrowser) NavigateByIndex(chatID string, index int) error

NavigateByIndex navigates to a subdirectory by index (stored in state.Dirs)

func (*DirectoryBrowser) NavigateUp

func (b *DirectoryBrowser) NavigateUp(chatID string) error

NavigateUp navigates to the parent directory

func (*DirectoryBrowser) NextPage

func (b *DirectoryBrowser) NextPage(chatID string) error

NextPage moves to the next page of directories

func (*DirectoryBrowser) PrevPage

func (b *DirectoryBrowser) PrevPage(chatID string) error

PrevPage moves to the previous page of directories

func (*DirectoryBrowser) SetMessageID

func (b *DirectoryBrowser) SetMessageID(chatID string, messageID string)

SetMessageID sets the message ID for editing

func (*DirectoryBrowser) SetWaitingInput

func (b *DirectoryBrowser) SetWaitingInput(chatID string, waiting bool, promptMsgID string)

SetWaitingInput sets the waiting for input state

func (*DirectoryBrowser) Start

func (b *DirectoryBrowser) Start(chatID string) (*BindFlowState, error)

Start begins a new bind flow for a chat

type ExecutionRequest

type ExecutionRequest struct {
	HCtx             HandlerContext
	Text             string
	ProjectPath      string // optional override
	ReplyToMessageID string
}

ExecutionRequest contains caller-provided parameters (from bot handler layer).

type ExecutionResult

type ExecutionResult struct {
	Response     string
	SessionID    string
	Success      bool
	Error        error
	Meta         *ResponseMeta
	IsNewSession bool
	Duration     time.Duration
}

ExecutionResult contains the outcome of agent execution

type ExecutorDependencies

type ExecutorDependencies struct {
	BotSetting                 BotSetting
	ChatStore                  ChatStoreInterface
	SessionMgr                 *SessionManager
	AgentBoot                  *agentboot.AgentBoot
	IMPrompter                 *IMPrompter
	FileStore                  *FileStore
	TBClient                   TBClient
	TBSessionStore             *SmartGuideSessionStore
	HandoffManager             *smart_guide.HandoffManager
	RunningCancel              map[string]context.CancelFunc
	RunningCancelMu            *sync.RWMutex
	GetVerbose                 func(chatID string) bool
	FormatResponse             func(meta ResponseMeta, response string, showMeta bool) string
	FormatResponseWithFooter   func(meta ResponseMeta, response string) string
	SendText                   func(hCtx HandlerContext, text string)
	SendTextWithReply          func(hCtx HandlerContext, text string, replyTo string)
	SendTextWithActionKeyboard func(hCtx HandlerContext, text string, replyTo string)
	SendFile                   func(hCtx HandlerContext, filePath, caption string) error
	NewStreamingMessageHandler func(hCtx HandlerContext, meta *ResponseMeta) *streamingMessageHandler
}

ExecutorDependencies holds shared dependencies for agent executors and router.

func (*ExecutorDependencies) ResolveDefaultProjectPath

func (d *ExecutorDependencies) ResolveDefaultProjectPath() string

ResolveDefaultProjectPath returns the default project path. Priority: 1. DefaultCwd from bot setting, 2. Current working directory, 3. User home directory

type FileStore

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

FileStore handles project-based file storage for bot media

func NewFileStore

func NewFileStore() *FileStore

NewFileStore creates a new file store with default limits

func NewFileStoreWithLimits

func NewFileStoreWithLimits(maxImageSize, maxDocSize int64) *FileStore

NewFileStoreWithLimits creates a new file store with custom limits

func NewFileStoreWithProxy

func NewFileStoreWithProxy(proxyURL string) (*FileStore, error)

NewFileStoreWithProxy creates a new file store with proxy support

func (*FileStore) DownloadFile

func (s *FileStore) DownloadFile(ctx context.Context, projectPath, url, mimeType string) (*StoredFile, error)

DownloadFile downloads a file from a URL to the project's .download directory Returns an error if file size exceeds limits

func (*FileStore) GetDownloadDir

func (s *FileStore) GetDownloadDir(projectPath string) string

GetDownloadDir returns the .download directory for a project

func (*FileStore) IsAllowedSize

func (s *FileStore) IsAllowedSize(mimeType string, size int64) bool

IsAllowedSize checks if the size is within limits for the mime type

func (*FileStore) IsAllowedType

func (s *FileStore) IsAllowedType(mimeType string) bool

IsAllowedType checks if the mime type is allowed

func (*FileStore) SetTelegramToken

func (s *FileStore) SetTelegramToken(token string)

SetTelegramToken sets the Telegram bot token for resolving file URLs

func (*FileStore) StoreFile

func (s *FileStore) StoreFile(ctx context.Context, projectPath string, reader io.Reader, filename, mimeType string) (*StoredFile, error)

StoreFile stores a file from a reader to the project's .download directory

type HandlerContext

type HandlerContext struct {
	Bot       imbot.Bot
	BotUUID   string
	ChatID    string
	SenderID  string
	MessageID string
	Platform  imbot.Platform
	Message   imbot.Message
}

HandlerContext contains per-message context data

func (*HandlerContext) IsDirect

func (c *HandlerContext) IsDirect() bool

func (*HandlerContext) IsGroup

func (c *HandlerContext) IsGroup() bool

func (*HandlerContext) Text

func (c *HandlerContext) Text() string

type IMPrompter

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

IMPrompter implements ask.Prompter using IM (Telegram, etc.) for user interaction

func NewIMPrompter

func NewIMPrompter(manager *imbot.Manager) *IMPrompter

NewIMPrompter creates a new IM-based prompter

func (*IMPrompter) AddToWhitelist

func (p *IMPrompter) AddToWhitelist(toolName string)

AddToWhitelist adds a tool to the whitelist

func (*IMPrompter) ClearWhitelist

func (p *IMPrompter) ClearWhitelist()

ClearWhitelist clears all tools from the whitelist

func (*IMPrompter) GetPendingRequest

func (p *IMPrompter) GetPendingRequest(requestID string) (*ask.Request, bool)

GetPendingRequest returns a pending request by ID

func (*IMPrompter) GetPendingRequestsForChat

func (p *IMPrompter) GetPendingRequestsForChat(chatID string) []ask.Request

GetPendingRequestsForChat returns all pending requests for a specific chat

func (*IMPrompter) GetWhitelist

func (p *IMPrompter) GetWhitelist() []string

GetWhitelist returns the list of whitelisted tools

func (*IMPrompter) IsWhitelisted

func (p *IMPrompter) IsWhitelisted(toolName string) bool

IsWhitelisted checks if a tool is in the whitelist

func (*IMPrompter) OnApproval

OnApproval implements agentboot.ApprovalHandler. It handles permission confirmation requests via IM.

func (*IMPrompter) OnAsk

OnAsk implements agentboot.AskHandler. It handles user questions/selections via IM.

func (*IMPrompter) Prompt

func (p *IMPrompter) Prompt(ctx context.Context, req ask.Request) (ask.Result, error)

Prompt prompts the user via IM for response This implements the ask.Prompter interface

func (*IMPrompter) PromptPermission

PromptPermission implements the legacy agentboot.UserPrompter interface

func (*IMPrompter) RemoveFromWhitelist

func (p *IMPrompter) RemoveFromWhitelist(toolName string)

RemoveFromWhitelist removes a tool from the whitelist

func (*IMPrompter) SetDefaultTimeout

func (p *IMPrompter) SetDefaultTimeout(timeout time.Duration)

SetDefaultTimeout sets the default timeout for requests

func (*IMPrompter) SubmitDecision

func (p *IMPrompter) SubmitDecision(requestID string, approved bool, remember bool, reason string) error

SubmitDecision submits a user's decision for a pending request

func (*IMPrompter) SubmitPartialAnswer added in v0.260414.2000

func (p *IMPrompter) SubmitPartialAnswer(requestID, questionText, label string) (bool, error)

SubmitPartialAnswer records the answer for one question of an AskUserQuestion request. Returns (true, nil) when all questions are answered and the result has been submitted. Returns (false, nil) when more questions remain.

func (*IMPrompter) SubmitResult

func (p *IMPrompter) SubmitResult(requestID string, result ask.Result) error

SubmitResult submits a result for a pending request

func (*IMPrompter) SubmitUserResponse

func (p *IMPrompter) SubmitUserResponse(requestID string, response ask.Response) error

SubmitUserResponse submits a user response for a pending request This parses the response using the appropriate tool handler

type Lifecycle

type Lifecycle interface {
	// Start starts a bot by UUID
	Start(ctx context.Context, uuid string) error
	// Stop stops a bot by UUID
	Stop(uuid string)
	// IsRunning checks if a bot is running
	IsRunning(uuid string) bool
	// Sync ensures running bots match the enabled settings
	Sync(ctx context.Context) error
}

Lifecycle defines the interface for controlling bot lifecycle This allows the API layer to control bot startup/shutdown without direct dependency on the Manager type

type Manager

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

Manager manages the lifecycle of running bot instances

func NewManager

func NewManager(store SettingsStore, sessionMgr *session.Manager, agentBoot *agentboot.AgentBoot,
) *Manager

NewManager creates a new bot manager with a settings store

func (*Manager) IsRunning

func (m *Manager) IsRunning(uuid string) bool

IsRunning checks if a bot is running

func (*Manager) SetDataPath

func (m *Manager) SetDataPath(dataPath string)

SetDataPath sets the data path for JSON chat store operations

func (*Manager) SetTBClient

func (m *Manager) SetTBClient(tbClient tbclient.TBClient)

SetTBClient sets the TBClient for SmartGuide configuration

func (*Manager) Start

func (m *Manager) Start(parentCtx context.Context, uuid string) error

Start starts a bot by UUID

func (*Manager) StartEnabled

func (m *Manager) StartEnabled(ctx context.Context) error

StartEnabled starts all enabled bots

func (*Manager) StartEnabledStopDisabled

func (m *Manager) StartEnabledStopDisabled(ctx context.Context) error

StartEnabledStopDisabled is a convenience method that ensures running bots match enabled settings. It's an alias for Sync() with clearer naming for specific use cases.

func (*Manager) Stop

func (m *Manager) Stop(uuid string)

Stop stops a bot by UUID

func (*Manager) StopAll

func (m *Manager) StopAll()

StopAll stops all running bots

func (*Manager) Sync

func (m *Manager) Sync(ctx context.Context) error

Sync ensures the running bots match the enabled settings in the store. It starts bots that are enabled but not running, and stops bots that are running but disabled.

func (*Manager) WaitForStop

func (m *Manager) WaitForStop(uuid string, timeout time.Duration) bool

WaitForStop waits for a bot to finish stopping (with timeout)

type MenuButtonConfig struct {
	// ID identifies this menu configuration
	ID string

	// Type determines what kind of menu this is
	Type MenuButtonType

	// ButtonText is the label shown on the menu button itself
	// e.g., "Menu", "Commands", "Actions"
	ButtonText string

	// Items are the menu items to show when button is tapped
	Items []MenuItemConfig

	// Platforms where this menu is available
	// If empty, shows on all platforms
	Platforms []imbot.Platform

	// Priority determines which config to use if multiple are registered
	// Higher priority wins. If 0, uses default priority.
	Priority int

	// Context filters when this menu should be shown
	Context *MenuContext
}

MenuButtonConfig configures the menu button for different platforms The menu button appears near the message input field and provides quick access to commands

Platform support: - Telegram: Menu Button (Commands / Web App) - Feishu/Lark: Quick Actions / Card Menu - Slack: App Shortcut / Slash Commands

func DefaultActionMenu

func DefaultActionMenu() MenuButtonConfig

DefaultActionMenu returns the default action menu (with callback buttons)

func DefaultCommandMenu

func DefaultCommandMenu() MenuButtonConfig

DefaultCommandMenu returns the default command menu configuration

func GetMenuForPlatform

func GetMenuForPlatform(platform imbot.Platform, context *MenuContext) *MenuButtonConfig

GetMenuForPlatform returns the best menu for a platform

type MenuButtonType string

MenuButtonType defines the type of menu button

const (
	// MenuTypeCommands shows a list of bot commands
	MenuTypeCommands MenuButtonType = "commands"

	// MenuTypeWebApp opens a Mini App / Web App
	MenuTypeWebApp MenuButtonType = "webapp"

	// MenuTypeCallbacks shows custom callback buttons
	MenuTypeCallbacks MenuButtonType = "callbacks"

	// MenuTypeDefault uses the platform default menu
	MenuTypeDefault MenuButtonType = "default"
)
type MenuContext struct {
	// ChatType restricts to specific chat types
	// "direct", "group", "channel", "all"
	ChatType string

	// UserIDs restricts to specific users (for personalization)
	UserIDs []string

	// ChatIDs restricts to specific chats
	ChatIDs []string

	// LanguageCode for localized menus (e.g., "en", "zh", "es")
	LanguageCode string
}

MenuContext filters when a menu should be shown

type MenuItemConfig struct {
	// ID is the unique identifier for this item
	ID string

	// Label is the display text
	Label string

	// Description is optional helper text (shown below label on some platforms)
	Description string

	// Value is the callback value or command to execute
	// For commands: "/help"
	// For callbacks: "action:confirm"
	Value string

	// URL opens a URL instead of executing a command (webapp buttons)
	URL string

	// Icon for platforms that support it (Feishu/Lark)
	Icon string

	// Group related items together (optional)
	Group string

	// Hidden skips this item but keeps it in registry
	Hidden bool
}

MenuItemConfig defines a single item in the menu

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

MenuRegistry manages menu button configurations

func GetMenuRegistry

func GetMenuRegistry() *MenuRegistry

GetMenuRegistry returns the default menu registry

func NewMenuRegistry

func NewMenuRegistry() *MenuRegistry

NewMenuRegistry creates a new menu registry

func (r *MenuRegistry) BuildForFeishu(context *MenuContext) map[string]interface{}

BuildForFeishu returns the Feishu/Lark configuration for quick actions

func (r *MenuRegistry) BuildForSlack(context *MenuContext) map[string]interface{}

BuildForSlack returns the Slack configuration for app shortcuts

func (r *MenuRegistry) BuildForTelegram(context *MenuContext) map[string]interface{}

BuildForTelegram returns the Telegram Bot API configuration for the menu button

func (r *MenuRegistry) GetForPlatform(platform imbot.Platform, context *MenuContext) *MenuButtonConfig

GetForPlatform returns the best menu configuration for a platform Uses priority to select the highest priority config that matches the context

func (r *MenuRegistry) Register(config MenuButtonConfig)

Register adds a menu configuration to the registry

type MockAgentExecutor

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

MockAgentExecutor executes messages through Mock Agent (for testing)

func NewMockAgentExecutor

func NewMockAgentExecutor(deps *ExecutorDependencies) *MockAgentExecutor

NewMockAgentExecutor creates a new Mock Agent executor

func (*MockAgentExecutor) Execute

Execute processes a user message through Mock Agent

func (*MockAgentExecutor) GetAgentType

func (e *MockAgentExecutor) GetAgentType() agentboot.AgentType

GetAgentType returns the agent type identifier

type OutputBehavior

type OutputBehavior struct {
	Verbose bool // Send intermediate processing messages
}

OutputBehavior controls what is shown in bot messages

func DefaultOutputBehavior

func DefaultOutputBehavior() OutputBehavior

DefaultOutputBehavior returns the default output behavior

type PendingBind

type PendingBind struct {
	OriginalMessage string
	ProposedPath    string
	ExpiresAt       time.Time
}

PendingBind represents a pending bind confirmation request

type PreparedRequest

type PreparedRequest struct {
	HCtx           HandlerContext
	Text           string
	ProjectPath    string        // fully resolved: override > ChatStore > default
	Meta           *ResponseMeta // shared pointer, created by router
	SessionID      string        // resolved session ID (chatID for SmartGuide)
	IsNewSession   bool          // whether session was just created
	PermissionMode string        // resolved from session (Claude Code / Mock)
	ReplyTo        string
}

PreparedRequest is the fully-resolved request built by AgentRouter. All executors receive this — shared *ResponseMeta ensures path changes propagate.

type QRCodeResponse

type QRCodeResponse struct {
	Qrcode           string `json:"qrcode,omitempty"`
	QrcodeImgContent string `json:"qrcode_img_content,omitempty"`
}

QRCodeResponse represents the QR code response from Weixin API

type QRStatusResponse

type QRStatusResponse struct {
	Status      string `json:"status,omitempty"` // wait, scaned, confirmed, expired
	BotToken    string `json:"bot_token,omitempty"`
	IlinkBotID  string `json:"ilink_bot_id,omitempty"`
	BaseURL     string `json:"baseurl,omitempty"`
	IlinkUserID string `json:"ilink_user_id,omitempty"`
}

QRStatusResponse represents the QR status response from Weixin API

func PollQRStatus

func PollQRStatus(ctx context.Context, client *WeChatQRClient, qrID string, pollInterval time.Duration) (*QRStatusResponse, error)

PollQRStatus polls the QR status until confirmed or expired Returns the confirmed credentials or error

type ResponseMeta

type ResponseMeta struct {
	ProjectPath string
	ChatID      string
	UserID      string
	SessionID   string
	AgentType   string // Current agent identifier (e.g., "tingly-box", "claude")
}

ResponseMeta contains metadata for response formatting

type SessionInfo

type SessionInfo struct {
	ID             string
	Status         string
	Project        string
	Request        string
	Error          string
	PermissionMode string
	LastActivity   time.Time
}

SessionInfo holds session information.

type SessionManager

type SessionManager = session.Manager

Type aliases to avoid import cycles

type SettingsStore

type SettingsStore interface {
	// GetSettingsByUUIDInterface returns settings by UUID as interface{}
	GetSettingsByUUIDInterface(uuid string) (interface{}, error)
	// ListEnabledSettingsInterface returns all enabled settings as interface{}
	ListEnabledSettingsInterface() (interface{}, error)
}

SettingsStore defines the interface for bot settings storage This allows both the legacy bot.Store and the new db.ImBotSettingsStore to be used

type SmartGuideCompletionCallback

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

SmartGuideCompletionCallback handles completion events for SmartGuide agent It saves messages to session, updates project path if changed, and sends response + action keyboard

func (*SmartGuideCompletionCallback) OnComplete

OnComplete implements agentboot.CompletionCallback

type SmartGuideExecutor

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

SmartGuideExecutor executes messages through Smart Guide (Tingly Box) agent

func NewSmartGuideExecutor

func NewSmartGuideExecutor(deps *ExecutorDependencies) *SmartGuideExecutor

NewSmartGuideExecutor creates a new Smart Guide executor

func (*SmartGuideExecutor) Execute

Execute processes a user message through Smart Guide

func (*SmartGuideExecutor) GetAgentType

func (e *SmartGuideExecutor) GetAgentType() agentboot.AgentType

GetAgentType returns the agent type identifier

type SmartGuideSessionStore

type SmartGuideSessionStore = smart_guide.SessionStore

type StoredFile

type StoredFile struct {
	Path     string // Full path: {projectPath}/.agent/{filename}
	RelPath  string // Relative path for agent: .agent/{filename}
	URL      string // Original URL
	Filename string
	Size     int64
	MimeType string
}

StoredFile represents a stored file

type TBClient

type TBClient = tbclient.TBClient

type TelegramFile

type TelegramFile struct {
	Ok     bool `json:"ok"`
	Result struct {
		FileID   string `json:"file_id"`
		FileSize int    `json:"file_size"`
		FilePath string `json:"file_path"`
	} `json:"result"`
}

TelegramFile represents the response from Telegram's getFile API

type WeChatQRClient

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

WeChatQRClient is a CLI-friendly wrapper for Weixin QR authentication

func NewWeChatQRClient

func NewWeChatQRClient(baseURL string) *WeChatQRClient

NewWeChatQRClient creates a new Weixin QR client

func (*WeChatQRClient) GetBotQRCode

func (c *WeChatQRClient) GetBotQRCode(ctx context.Context, botType string) (*QRCodeResponse, error)

GetBotQRCode fetches a QR code for Weixin bot login

func (*WeChatQRClient) GetQRStatus

func (c *WeChatQRClient) GetQRStatus(ctx context.Context, qrcode string) (*QRStatusResponse, error)

GetQRStatus polls the QR code status

Jump to

Keyboard shortcuts

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