Documentation
¶
Index ¶
- Constants
- Variables
- func BuildTools(executor *ToolExecutor, chatID string, ...) []afk.Tool
- func CanCreateAgent(baseURL, apiKey, smartGuideProvider, smartGuideModel string) bool
- func DefaultGreeting() string
- func DefaultSystemPrompt() string
- func DetectHandoffCommand(text string) (agentboot.AgentType, bool, string)
- func DetectMediaType(path string) string
- func GetAgentTypeString(agentType agentboot.AgentType) string
- func HandoffToCCPrompt() string
- func HandoffToTBPrompt() string
- func LoadPrompt(name string) (string, error)
- func MustLoadPrompt(name string) string
- func SerializeState(state *HandoffState) ([]byte, error)
- type AgentConfig
- type ApprovalCallback
- type ApprovalRequest
- type Approver
- type BashTool
- type ChangeDirTool
- type CompletionResult
- type EditFileTool
- type GetStatusTool
- type HandoffManager
- type HandoffResult
- type HandoffState
- type ModelConfig
- type ReadFileTool
- type SendFileParams
- type SendFileTool
- type SessionStore
- type SmartGuideConfig
- type StatusInfo
- type StreamHandler
- type TinglyBoxAgent
- func (a *TinglyBoxAgent) ExecuteWithHandler(ctx context.Context, prompt string, toolCtx *ToolContext, ...) (*agentboot.Result, error)
- func (a *TinglyBoxAgent) GetConfig() *SmartGuideConfig
- func (a *TinglyBoxAgent) GetExecutor() *ToolExecutor
- func (a *TinglyBoxAgent) GetGreeting() string
- func (a *TinglyBoxAgent) History() []anthropic.BetaMessageParam
- func (a *TinglyBoxAgent) IsAvailable() bool
- func (a *TinglyBoxAgent) IsEnabled() bool
- func (a *TinglyBoxAgent) LastAssistantText() string
- func (a *TinglyBoxAgent) Steer(text string) bool
- func (a *TinglyBoxAgent) Type() agentboot.AgentType
- type ToolContext
- type ToolExecutor
- func (e *ToolExecutor) ExecuteBash(ctx context.Context, cmd string, args ...string) (string, error)
- func (e *ToolExecutor) GetAllowedCommands() []string
- func (e *ToolExecutor) GetWorkingDirectory() string
- func (e *ToolExecutor) HasApprovalCallback() bool
- func (e *ToolExecutor) ResolvePath(path string) string
- func (e *ToolExecutor) SetApprovalCallback(callback ApprovalCallback)
- func (e *ToolExecutor) SetApprovalTimeout(timeout time.Duration)
- func (e *ToolExecutor) SetWorkingDirectory(cwd string)
- type WriteFileTool
Constants ¶
const ( AgentTypeTinglyBox = "tingly-box" // @tb AgentTypeClaudeCode = "claude" // @cc AgentTypeMock = "mock" )
AgentType constants. Defined here (not in agentboot core) so Smart Guide can extend the agent-type space without modifying agentboot.
const SendFileMaxSize int64 = 50 * 1024 * 1024
SendFileMaxSize is the default maximum file size for outbound file sends (50MB).
Variables ¶
var DefaultBashAllowlist = []string{
"ls", "pwd", "cd", "cat", "tree",
"find", "grep", "head", "tail", "wc", "sort", "uniq",
"mkdir", "cp", "mv", "touch", "echo", "which",
"git", "go", "npm", "pnpm", "yarn",
"curl", "wget",
}
DefaultBashAllowlist defines the default allowed bash commands. Commands outside this list trigger the approval callback (if configured).
var PromptFS embed.FS
Functions ¶
func BuildTools ¶
func BuildTools( executor *ToolExecutor, chatID string, getStatusFunc func(chatID string) (*StatusInfo, error), updateProjectFunc func(chatID string, projectPath string) error, toolCtx *ToolContext, skills skill.Skills, ) []afk.Tool
BuildTools assembles the Smart Guide toolset for the ReAct engine.
The set mirrors the previous agentscope registration: bash, get_status, change_workdir, native read/write/edit, and (when a SendFile callback is available) send_file — plus activate_skill when any skills were discovered.
func CanCreateAgent ¶
CanCreateAgent reports whether a SmartGuide agent can be created with the given configuration.
func DefaultGreeting ¶
func DefaultGreeting() string
DefaultGreeting returns the default greeting for new users
func DefaultSystemPrompt ¶
func DefaultSystemPrompt() string
DefaultSystemPrompt returns the default system prompt for @tb
func DetectHandoffCommand ¶
DetectHandoffCommand detects if text is a handoff command. Returns the target agent type, whether it's a handoff, and any remaining text after the command. Examples:
- "@cc" -> (AgentTypeClaudeCode, true, "")
- "@cc help me" -> (AgentTypeClaudeCode, true, "help me")
- "hello" -> ("", false, "")
func DetectMediaType ¶
DetectMediaType returns "image" for image file extensions, "document" for all others.
func GetAgentTypeString ¶
GetAgentTypeString returns the string representation of an agent type
func HandoffToCCPrompt ¶
func HandoffToCCPrompt() string
HandoffToCCPrompt returns the handoff prompt when switching to Claude Code
func HandoffToTBPrompt ¶
func HandoffToTBPrompt() string
HandoffToTBPrompt returns the handoff prompt when returning to Smart Guide
func LoadPrompt ¶
LoadPrompt reads a prompt file from the embedded filesystem
func MustLoadPrompt ¶
MustLoadPrompt reads a prompt file or panics
func SerializeState ¶
func SerializeState(state *HandoffState) ([]byte, error)
SerializeState serializes handoff state to JSON
Types ¶
type AgentConfig ¶
type AgentConfig struct {
SmartGuideConfig *SmartGuideConfig
ToolExecutor *ToolExecutor
// HTTP endpoint configuration (resolved from TBClient by caller).
BaseURL string
APIKey string
Model string
// Callback functions for internal tools.
GetStatusFunc func(chatID string) (*StatusInfo, error)
GetProjectFunc func(chatID string) (string, bool, error)
UpdateProjectFunc func(chatID string, projectPath string) error
// Approval context for non-allowlisted commands.
Approver Approver
ChatID string
Platform string
BotUUID string
// ToolContext for file send capability and cross-path approval. If nil,
// the send_file tool is not registered.
ToolCtx *ToolContext
// SessionLog is the chat's append-only conversation log. When set, the run
// is checkpointed to it as each step completes, so an interrupted turn keeps
// the work it already did. Nil disables mid-run persistence.
SessionLog afk.Log
}
AgentConfig holds the configuration for creating a TinglyBoxAgent.
type ApprovalCallback ¶
type ApprovalCallback func(ctx context.Context, req ApprovalRequest) (approved bool, err error)
ApprovalCallback is called when a command requires user approval Returns (approved, error) - if error is non-nil, the approval process failed
type ApprovalRequest ¶
type ApprovalRequest struct {
Command string // Command to execute
Args []string // Command arguments
Reason string // Reason for approval request
}
ApprovalRequest represents a request for user approval
type Approver ¶
type Approver interface {
OnApproval(ctx context.Context, req agentboot.ApprovalRequestEvent) (agentboot.ApprovalResponse, error)
}
Approver answers a permission request for a non-whitelisted command. *imchannel.IMPrompter satisfies this via its OnApproval method.
type BashTool ¶
type BashTool struct {
Executor *ToolExecutor
AllowedCommands []string
}
BashTool executes shell commands with an allowlist + approval gate.
func NewBashTool ¶
func NewBashTool(executor *ToolExecutor, allowlist []string) *BashTool
NewBashTool creates a new bash tool bound to the given executor and allowlist.
func (*BashTool) Call ¶
Call runs a bash command, gating non-allowlisted base commands behind the approval callback. On approval (or for allowlisted commands) it executes the command and tracks any working-directory change so `cd` persists within the session.
func (*BashTool) Param ¶
func (t *BashTool) Param() anthropic.BetaToolParam
type ChangeDirTool ¶
type ChangeDirTool struct {
// contains filtered or unexported fields
}
ChangeDirTool changes the bound project directory and persists it.
func NewChangeDirTool ¶
func NewChangeDirTool(executor *ToolExecutor, chatID string, updateProjectFunc func(chatID string, projectPath string) error) *ChangeDirTool
NewChangeDirTool creates a new ChangeDirTool. chatID is injected from agent config (not taken from model input).
func (*ChangeDirTool) Call ¶
func (t *ChangeDirTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
func (*ChangeDirTool) Param ¶
func (t *ChangeDirTool) Param() anthropic.BetaToolParam
type CompletionResult ¶
CompletionResult reports the outcome of an ExecuteWithHandler run.
type EditFileTool ¶
type EditFileTool struct {
// contains filtered or unexported fields
}
EditFileTool replaces an exact, unique occurrence of old_text in a file.
func NewEditFileTool ¶
func NewEditFileTool(executor *ToolExecutor) *EditFileTool
NewEditFileTool constructs an EditFileTool bound to the given executor.
func (*EditFileTool) Call ¶
func (t *EditFileTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
func (*EditFileTool) Param ¶
func (t *EditFileTool) Param() anthropic.BetaToolParam
type GetStatusTool ¶
type GetStatusTool struct {
// contains filtered or unexported fields
}
GetStatusTool returns the current bot/session status.
func NewGetStatusTool ¶
func NewGetStatusTool(executor *ToolExecutor, chatID string, getStatusFunc func(chatID string) (*StatusInfo, error)) *GetStatusTool
NewGetStatusTool creates a new GetStatusTool. chatID is injected from agent config (not taken from model input).
func (*GetStatusTool) Call ¶
func (t *GetStatusTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
func (*GetStatusTool) Param ¶
func (t *GetStatusTool) Param() anthropic.BetaToolParam
type HandoffManager ¶
type HandoffManager struct {
}
HandoffManager handles handoff operations between agents
func NewHandoffManager ¶
func NewHandoffManager() *HandoffManager
NewHandoffManager creates a new handoff manager
func (*HandoffManager) ExecuteHandoff ¶
func (hm *HandoffManager) ExecuteHandoff(ctx context.Context, state *HandoffState) *HandoffResult
ExecuteHandoff performs a handoff from one agent to another
type HandoffResult ¶
type HandoffResult struct {
Success bool `json:"success"`
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Message string `json:"message"`
NextHint string `json:"next_hint"`
Error string `json:"error,omitempty"`
}
HandoffResult represents the result of a handoff operation
type HandoffState ¶
type HandoffState struct {
FromAgent string `json:"from_agent"`
ToAgent string `json:"to_agent"`
Timestamp time.Time `json:"timestamp"`
ProjectPath string `json:"project_path"`
SessionID string `json:"session_id"`
ChatID string `json:"chat_id"`
PreservedContext []byte `json:"preserved_context,omitempty"`
}
HandoffState represents the state during a handoff
func DeserializeState ¶
func DeserializeState(data []byte) (*HandoffState, error)
DeserializeState deserializes handoff state from JSON
type ModelConfig ¶
type ModelConfig struct {
Provider string `json:"provider"` // "openai", "anthropic", etc.
Model string `json:"model"`
APIKey string `json:"api_key"`
BaseURL string `json:"base_url,omitempty"`
}
ModelConfig holds the model configuration
type ReadFileTool ¶
type ReadFileTool struct {
// contains filtered or unexported fields
}
ReadFileTool reads the contents of a file, optionally limited to a line range.
func NewReadFileTool ¶
func NewReadFileTool(executor *ToolExecutor) *ReadFileTool
NewReadFileTool constructs a ReadFileTool bound to the given executor.
func (*ReadFileTool) Call ¶
func (t *ReadFileTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
func (*ReadFileTool) Param ¶
func (t *ReadFileTool) Param() anthropic.BetaToolParam
type SendFileParams ¶
type SendFileParams struct {
FilePath string `json:"file_path"`
Caption string `json:"caption,omitempty"`
}
SendFileParams defines the parameters for the send_file tool.
type SendFileTool ¶
type SendFileTool struct {
// contains filtered or unexported fields
}
SendFileTool sends a local file to the user via the IM bot.
func NewSendFileTool ¶
func NewSendFileTool(executor *ToolExecutor, toolCtx *ToolContext) *SendFileTool
NewSendFileTool creates a SendFileTool with the default 50MB limit.
func NewSendFileToolWithLimit ¶
func NewSendFileToolWithLimit(executor *ToolExecutor, toolCtx *ToolContext, maxSize int64) *SendFileTool
NewSendFileToolWithLimit creates a SendFileTool with a custom size limit (for testing).
func (*SendFileTool) Call ¶
func (t *SendFileTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
Call executes the send_file tool.
func (*SendFileTool) Param ¶
func (t *SendFileTool) Param() anthropic.BetaToolParam
Param describes the send_file tool to the model.
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore persists Smart Guide conversations as append-only logs, one file per chat. We are anthropic-first, so there is no neutral message type: the stored shape is exactly what the model API consumes.
The store owns the chatID-to-path mapping and the archive semantics; the log format and its durability live in afk/session.
func NewSessionStore ¶
func NewSessionStore(dataDir string) (*SessionStore, error)
NewSessionStore creates a session store rooted at dataDir. A blank dataDir disables persistence (returns nil, nil), mirroring the previous behavior.
func (*SessionStore) Clear ¶
func (s *SessionStore) Clear(chatID string) error
Clear ends a chat's current Smart Guide session: the live log is archived (renamed with a timestamp suffix) rather than deleted, so /clear deactivates the conversation instead of destroying it — the same "closed, not erased" semantics remote/session.Manager.Close gives @cc sessions. The next Open for chatID sees no file and starts fresh; the archived log is left on disk.
func (*SessionStore) Open ¶
func (s *SessionStore) Open(chatID string) (*session.Session, error)
Open returns a chat's live session log, importing a legacy whole-file session if this is the first time the chat has been opened since the format changed.
Callers that want a run to be checkpointed as it progresses hold on to this and hand it to the harness, instead of snapshotting the whole history at the end. A nil store yields a nil session, which the harness reads as "no durability wanted".
type SmartGuideConfig ¶
type SmartGuideConfig struct {
// Enabled determines if smart guide is active
Enabled bool `json:"enabled"`
// SystemPrompt is the custom system prompt (optional)
SystemPrompt string `json:"system_prompt,omitempty"`
// MaxIterations is the maximum number of tool use iterations
MaxIterations int `json:"max_iterations"`
// Temperature for LLM responses
Temperature float64 `json:"temperature"`
// Thinking selects the model's reasoning mode: "" (the model's own
// default), "visible", "hidden", or "off". See afk.ThinkingMode.
//
// "visible" is what makes @tb render 💭 lines: reasoning only comes back
// with content when it is asked for explicitly, and the streaming layer
// shows it in verbose mode.
Thinking string `json:"thinking,omitempty"`
// Effort is how hard the model works on a turn: "" (the model's own
// default), "low", "medium", "high", "xhigh", or "max". See
// afk.EffortLevel. Separate axis from Thinking — that one is whether the
// model reasons, this one is how much it spends overall.
Effort string `json:"effort,omitempty"`
// ToolsEnabled maps tool names to enabled state
ToolsEnabled map[string]bool `json:"tools_enabled"`
// HandoffCommands are the commands that trigger handoff
HandoffCommands []string `json:"handoff_commands"`
// Model configuration
Model ModelConfig `json:"model"`
// SessionTimeout is how long to remember context
SessionTimeout time.Duration `json:"session_timeout"`
}
SmartGuideConfig holds the configuration for the smart guide agent
func DefaultSmartGuideConfig ¶
func DefaultSmartGuideConfig() *SmartGuideConfig
DefaultSmartGuideConfig returns the default configuration
func LoadSmartGuideConfig ¶
func LoadSmartGuideConfig() *SmartGuideConfig
LoadSmartGuideConfig loads smart guide config with custom settings For now, returns default config - settings will be loaded externally
func (*SmartGuideConfig) GetSystemPrompt ¶
func (c *SmartGuideConfig) GetSystemPrompt() string
GetSystemPrompt returns the system prompt to use
func (*SmartGuideConfig) IsHandoffCommand ¶
func (c *SmartGuideConfig) IsHandoffCommand(text string) bool
IsHandoffCommand checks if text is a handoff command
func (*SmartGuideConfig) IsToolEnabled ¶
func (c *SmartGuideConfig) IsToolEnabled(toolName string) bool
IsToolEnabled checks if a tool is enabled
type StatusInfo ¶
type StatusInfo struct {
CurrentAgent string `json:"current_agent"`
SessionID string `json:"session_id"`
ProjectPath string `json:"project_path"`
WorkingDir string `json:"working_dir"`
HasRunningTask bool `json:"has_running_task"`
Whitelisted bool `json:"whitelisted"`
}
StatusInfo holds bot status information
type StreamHandler ¶
type StreamHandler interface {
OnMessage(msg any) error
OnError(err error)
OnComplete(result *CompletionResult)
}
StreamHandler receives streaming output and the completion signal from ExecuteWithHandler. The smart-guide agent runs an in-house ReAct loop on the Anthropic SDK (internal/afk.Engine), not agentboot's process pipeline, so it streams intermediate messages as plain maps via OnMessage and reports the final outcome via OnComplete.
type TinglyBoxAgent ¶
type TinglyBoxAgent struct {
// contains filtered or unexported fields
}
TinglyBoxAgent is the Smart Guide agent (@tb). It runs an in-house ReAct loop (internal/afk.Engine) on the official Anthropic SDK, replacing the former tingly-agentscope runtime.
func NewTinglyBoxAgent ¶
func NewTinglyBoxAgent(config *AgentConfig) (*TinglyBoxAgent, error)
NewTinglyBoxAgent creates a new Smart Guide agent.
func NewTinglyBoxAgentWithSession ¶
func NewTinglyBoxAgentWithSession(config *AgentConfig, history []anthropic.BetaMessageParam) (*TinglyBoxAgent, error)
NewTinglyBoxAgentWithSession creates a Smart Guide agent seeded with prior conversation history (native Anthropic beta message params from the session store).
func (*TinglyBoxAgent) ExecuteWithHandler ¶
func (a *TinglyBoxAgent) ExecuteWithHandler( ctx context.Context, prompt string, toolCtx *ToolContext, handler StreamHandler, ) (*agentboot.Result, error)
ExecuteWithHandler runs one user turn through the ReAct engine, streaming intermediate output to the handler and reporting completion. It returns an agentboot.Result for compatibility with the executor layer.
func (*TinglyBoxAgent) GetConfig ¶
func (a *TinglyBoxAgent) GetConfig() *SmartGuideConfig
GetConfig returns the agent's configuration.
func (*TinglyBoxAgent) GetExecutor ¶
func (a *TinglyBoxAgent) GetExecutor() *ToolExecutor
GetExecutor returns the tool executor.
func (*TinglyBoxAgent) GetGreeting ¶
func (a *TinglyBoxAgent) GetGreeting() string
GetGreeting returns the default greeting for new users.
func (*TinglyBoxAgent) History ¶
func (a *TinglyBoxAgent) History() []anthropic.BetaMessageParam
History returns the agent's current conversation history (native beta params).
func (*TinglyBoxAgent) IsAvailable ¶
func (a *TinglyBoxAgent) IsAvailable() bool
IsAvailable returns true if the agent is available for execution.
func (*TinglyBoxAgent) IsEnabled ¶
func (a *TinglyBoxAgent) IsEnabled() bool
IsEnabled returns whether the smart guide is enabled.
func (*TinglyBoxAgent) LastAssistantText ¶
func (a *TinglyBoxAgent) LastAssistantText() string
LastAssistantText returns the text of the most recent assistant message in history, used by the completion callback to capture the final response.
func (*TinglyBoxAgent) Steer ¶
func (a *TinglyBoxAgent) Steer(text string) bool
Steer delivers a message to the turn this agent is currently running, to be picked up at its next checkpoint. It reports whether there was a run to take it; false means the caller should start a normal turn.
func (*TinglyBoxAgent) Type ¶
func (a *TinglyBoxAgent) Type() agentboot.AgentType
Type returns the agent type used by the executor routing layer.
type ToolContext ¶
type ToolContext struct {
ChatID string
ProjectPath string
SessionID string
// SendFile sends a local file to the user via the IM bot.
// Injected by the bot layer; nil if file sending is not available.
SendFile func(ctx context.Context, filePath, caption string) error
// RequestApproval requests explicit user approval for sensitive operations
// (e.g. sending files outside the project path). This callback must NOT be
// bypassed by yolo mode — it is distinct from the bash approval callback.
// Returns (false, nil) if denied. Returns (false, err) on failure.
RequestApproval func(ctx context.Context, prompt string) (approved bool, err error)
}
ToolContext provides context for tool execution
type ToolExecutor ¶
type ToolExecutor struct {
BashAllowlist map[string]struct{}
BashCwd string // Per-execution working directory
// contains filtered or unexported fields
}
ToolExecutor handles tool execution with proper context
func NewToolExecutor ¶
func NewToolExecutor(allowlist []string) *ToolExecutor
NewToolExecutor creates a new tool executor
func (*ToolExecutor) ExecuteBash ¶
ExecuteBash executes a bash command with allowlist checking
func (*ToolExecutor) GetAllowedCommands ¶
func (e *ToolExecutor) GetAllowedCommands() []string
GetAllowedCommands returns the list of allowed commands
func (*ToolExecutor) GetWorkingDirectory ¶
func (e *ToolExecutor) GetWorkingDirectory() string
GetWorkingDirectory returns the current working directory
func (*ToolExecutor) HasApprovalCallback ¶
func (e *ToolExecutor) HasApprovalCallback() bool
HasApprovalCallback returns true if an approval callback is set
func (*ToolExecutor) ResolvePath ¶
func (e *ToolExecutor) ResolvePath(path string) string
ResolvePath resolves a path to an absolute path
func (*ToolExecutor) SetApprovalCallback ¶
func (e *ToolExecutor) SetApprovalCallback(callback ApprovalCallback)
SetApprovalCallback sets the approval callback for non-allowlisted commands
func (*ToolExecutor) SetApprovalTimeout ¶
func (e *ToolExecutor) SetApprovalTimeout(timeout time.Duration)
SetApprovalTimeout sets the timeout for approval requests
func (*ToolExecutor) SetWorkingDirectory ¶
func (e *ToolExecutor) SetWorkingDirectory(cwd string)
SetWorkingDirectory sets the current working directory
type WriteFileTool ¶
type WriteFileTool struct {
// contains filtered or unexported fields
}
WriteFileTool writes content to a file, creating parent directories as needed.
func NewWriteFileTool ¶
func NewWriteFileTool(executor *ToolExecutor) *WriteFileTool
NewWriteFileTool constructs a WriteFileTool bound to the given executor.
func (*WriteFileTool) Call ¶
func (t *WriteFileTool) Call(ctx context.Context, rawInput json.RawMessage) (string, error)
func (*WriteFileTool) Param ¶
func (t *WriteFileTool) Param() anthropic.BetaToolParam