bot

package
v0.260507.1 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MPL-2.0 Imports: 39 Imported by: 0

Documentation

Overview

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

PairingManager and related types live in imbot/security so that any imbot application can reuse the TOFU pairing mechanism independently of the remote-control service. The aliases below keep existing code in this package unchanged.

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 (
	ErrPairCodeMissing  = security.ErrPairCodeMissing
	ErrPairCodeExpired  = security.ErrPairCodeExpired
	ErrPairCodeMismatch = security.ErrPairCodeMismatch
	ErrPairLocked       = security.ErrPairLocked
)

Error sentinels forwarded from imbot/security.

View Source
var (
	NewPairingManager   = security.NewPairingManager
	WithPairingTTL      = security.WithPairingTTL
	WithPairingCodeLen  = security.WithPairingCodeLength
	WithPairingMaxFails = security.WithPairingMaxFails
	WithPairingLockout  = security.WithPairingLockout
	WithPairingRand     = security.WithPairingRand
	WithPairingClock    = security.WithPairingClock
)

Constructor and option helpers forwarded from imbot/security.

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 BuildBindConfirmPrompt

func BuildBindConfirmPrompt(proposedPath string) string

BuildBindConfirmPrompt returns the text for bind confirmation prompt

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 EnsureContext added in v0.260507.1

func EnsureContext(t testing.TB) context.Context

EnsureContext provides a context that propagates either through t.Context() (Go 1.24+) or a fresh background context.

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 RegisterBuiltinCommands

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

RegisterBuiltinCommands registers all built-in commands to the registry.

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 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 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 *feature.DirectoryBrowser,
	manager *imbot.Manager,
	tbClient tbclient.TBClient,
	pairing *PairingManager,
	auditLog *audit.Logger,
	store SettingsStore,
) *BotHandler

func (*BotHandler) GetCommandRegistry

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

GetCommandRegistry returns the command registry.

func (*BotHandler) GetVerbose

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

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)

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)

func (*BotHandler) SetVerbose

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

SetVerbose sets the verbose mode for a chat

func (*BotHandler) VerifyAndPair added in v0.260507.1

func (h *BotHandler) VerifyAndPair(botUUID, chatID, senderID, platform, code string) error

VerifyAndPair runs the pairing-code check and, on success, persists the binding in the chat store. It is invoked by the /bind command handler.

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)

	// VerifyAndPair verifies a one-time pairing code and, on success, records
	// the chat as paired with the bot. Implementations should also emit the
	// matching audit events (success / failure).
	VerifyAndPair(botUUID, chatID, senderID, platform, code 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

	// RequirePairing enforces a TOFU pairing-code handshake before any DM is
	// processed. Nil is treated as false so legacy bots keep working until the
	// operator opts in. New bots created via the wizard set this to true.
	RequirePairing *bool `json:"require_pairing,omitempty"`

	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

func (BotSetting) IsRequirePairing added in v0.260507.1

func (b BotSetting) IsRequirePairing() bool

IsRequirePairing reports whether this bot requires per-chat pairing.

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"`

	// Pairing (TOFU) — applies to direct messages only. Group chats continue
	// to use the IsWhitelisted gate, but the operator who whitelisted the
	// group must themselves be paired in DM with the same bot.
	IsPaired       bool      `json:"is_paired,omitempty"`
	PairedBotUUID  string    `json:"paired_bot_uuid,omitempty"`
	PairedSenderID string    `json:"paired_sender_id,omitempty"`
	PairedAt       time.Time `json:"paired_at,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. Creates the chat
	// row if it doesn't yet exist so that @cc/@tb handoff state persists
	// even on fresh chats that haven't been bound (/cd) or paired (/bind)
	// yet. Pass an empty platform when the caller doesn't have one — the
	// field will be filled in later by BindProject/SetPaired.
	SetCurrentAgent(chatID, platform, 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)

	// SetPaired marks a chat as paired with a specific bot UUID and sender.
	// The chat is created if it does not yet exist.
	SetPaired(chatID, platform, botUUID, senderID string) error

	// ClearPaired removes the pairing on a chat. Other state on the chat is
	// preserved.
	ClearPaired(chatID string) error

	// IsChatPaired reports whether the chat is paired with the given bot UUID.
	IsChatPaired(chatID, botUUID string) bool
}

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

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) ClearPaired added in v0.260507.1

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

ClearPaired removes any pairing recorded on the chat.

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) IsChatPaired added in v0.260507.1

func (s *ChatStoreJSON) IsChatPaired(chatID, botUUID string) bool

IsChatPaired reports whether the chat is paired with the given bot UUID.

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, platform, agentType string) error

SetCurrentAgent sets the current agent for a chat, creating the chat row if it doesn't yet exist. Without the auto-create, UpdateChat silently no-ops on a missing chat, which silently dropped handoff persistence for any chat that hadn't been pre-bound or pre-paired.

func (*ChatStoreJSON) SetPaired added in v0.260507.1

func (s *ChatStoreJSON) SetPaired(chatID, platform, botUUID, senderID string) error

SetPaired marks the given chat as paired with botUUID/senderID.

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 the Claude Code agent.

It consumes the agentboot.ExecutionHandle returned by Agent.Execute directly, dispatching MessageEvents to the streaming chat writer and routing ApprovalRequestEvent / AskRequestEvent to IMPrompter.

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 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 {
	// GetBotSetting dynamically retrieves the current bot settings from the store.
	// This ensures that any configuration changes (provider, model, etc.) are reflected
	// immediately without requiring a bot restart.
	GetBotSetting func() (BotSetting, error)

	ChatStore                  ChatStoreInterface
	SessionMgr                 *SessionManager
	AgentBoot                  *agentboot.AgentBoot
	IMPrompter                 *imchannel.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) GetBotSettingOrCache added in v0.260507.1

func (d *ExecutorDependencies) GetBotSettingOrCache() BotSetting

GetBotSettingOrCache returns the current bot setting. If dynamic lookup fails, returns an empty setting.

func (*ExecutorDependencies) ResolveDefaultProjectPath

func (d *ExecutorDependencies) ResolveDefaultProjectPath() string

ResolveDefaultProjectPath returns the default project path from bot settings.

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 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) AuditLogger added in v0.260507.1

func (m *Manager) AuditLogger() *audit.Logger

AuditLogger returns the manager's audit logger.

func (*Manager) ChatStore added in v0.260507.1

func (m *Manager) ChatStore() (ChatStoreInterface, error)

ChatStore opens (and the caller must Close) a chat store backed by the manager's data path. Used by the CLI to read/clear pairings without touching a running bot's store.

func (*Manager) IsRunning

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

IsRunning checks if a bot is running

func (*Manager) PairingManager added in v0.260507.1

func (m *Manager) PairingManager() *PairingManager

PairingManager returns the manager's PairingManager instance. Used by CLI helpers that mint, rotate, or revoke pairing codes.

func (*Manager) SetChannelRegistry added in v0.260507.1

func (m *Manager) SetChannelRegistry(reg *channel.Registry)

SetChannelRegistry wires a remote channel registry so each running bot exposes itself as a remote.channel.Channel reachable from /tingly/:scenario scenario plugins. Safe to call once at startup before any bot is started.

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 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 PairingManager added in v0.260507.1

type PairingManager = security.PairingManager

Type aliases — fully transparent to callers.

type PairingManagerOption added in v0.260507.1

type PairingManagerOption = security.PairingManagerOption

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 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 TestBootOptions added in v0.260507.1

type TestBootOptions struct {
	// DataDir overrides the chat-store directory (default: t.TempDir()).
	DataDir string

	// FixtureScript, when non-nil, registers a Claude agent backed by a
	// fixture.Factory(script). The fixture replaces the legacy mockagent —
	// tests now drive the real claude.Driver + claude.Transport + Runner
	// pipeline against scripted wire-format output.
	//
	// When nil (default), no Claude agent is registered and tests that
	// depend on agent execution must register their own.
	FixtureScript fixture.Script
}

TestBootOptions tweaks BootForTest defaults. All fields are optional.

type TestHarness added in v0.260507.1

type TestHarness struct {
	Setting    BotSetting
	Handler    *BotHandler
	ChatStore  ChatStoreInterface
	SessionMgr *session.Manager
	AgentBoot  *agentboot.AgentBoot
	Pairing    *PairingManager
	Audit      *audit.Logger
	DataDir    string
	Manager    *imbot.Manager
	// contains filtered or unexported fields
}

TestHarness wires the production BotHandler against a test imbot.Manager (typically backed by the tingly platform). It owns the support infrastructure — chat store, session manager, agentboot, pairing — and exposes them so tests can drive state directly.

Construction:

env := testenv.NewTestEnv(t)
uuid := env.BotUUID() // creates a tingly bot in env.Manager()
harness := bot.BootForTest(t, env.Manager(), bot.BotSetting{
    UUID:     uuid,
    Platform: "tingly",
    Enabled:  true,
})
require.NoError(t, env.Manager().Start(env.Context()))

Tests then drive the bot through the testenv chat helpers.

func BootForTest added in v0.260507.1

func BootForTest(t *testing.T, manager *imbot.Manager, setting BotSetting, opts ...TestBootOptions) *TestHarness

BootForTest spins up a production BotHandler against the given imbot.Manager. It assumes the Manager already has a bot registered for setting.UUID (the tingly testenv arranges this via AddTinglyBotWithUUID when env.BotUUID() is called).

The harness registers the BotHandler.HandleMessage callback on the Manager. Callers must Start the Manager themselves — keeping that step in the test makes it explicit when inbound messages start flowing.

func (*TestHarness) MarkChatPaired added in v0.260507.1

func (h *TestHarness) MarkChatPaired(chatID, senderID string)

MarkChatPaired records a pairing for the harness's bot via the same production API path that VerifyAndPair uses. Tests focused on post-pairing behavior can skip the /bind handshake without bypassing the real persistence path — exercising any future bug in SetPaired.

func (*TestHarness) MintPairingCode added in v0.260507.1

func (h *TestHarness) MintPairingCode() (code string, expiresAt time.Time)

MintPairingCode mints a fresh pairing code for the harness's bot. Tests that exercise the pairing-required path use this to obtain the code the user must send via /bind.

func (*TestHarness) SetCurrentAgent added in v0.260507.1

func (h *TestHarness) SetCurrentAgent(chatID, agentType string)

SetCurrentAgent updates the current-agent binding for a chat through the same production path the @cc/@tb handoff uses. Going through chatStore.SetCurrentAgent (rather than mutating Chat directly) keeps the harness honest: any regression in the persistence path — e.g. a silent no-op on a missing chat row — surfaces as a test failure.

func (*TestHarness) WhitelistGroup added in v0.260507.1

func (h *TestHarness) WhitelistGroup(chatID, ownerID string)

WhitelistGroup adds a group chat to the bot's whitelist (required for the bot to respond to group messages).

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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