Documentation
¶
Overview ¶
Package channel defines the public contract for channel plugins. Channel plugins are thin platform adapters (Telegram, QQ, Feishu, Weixin) that normalise incoming messages, delegate business logic to a MessageHandler, and render streamed responses back to the platform.
Index ¶
- Constants
- Variables
- func CloneConfigMap(src map[string]any) map[string]any
- func DecodePluginConfig[T any](raw map[string]any, label string) (T, error)
- func EmojiFor(tool string) string
- func FormatAgentList(agents []IndexedAgent, currentAgentID string) string
- func FormatDuration(d time.Duration) string
- func FormatModelList(models []IndexedModel, query string) string
- func FormatNumberedModelList(models []IndexedModel, query string) string
- func HandleAgentCommand(cfg AgentCommandHandler)
- func HandleModelCommand(cfg ModelCommandHandler)
- func NotificationAgentIDFromContext(ctx context.Context) string
- func ParseCommandArgs(text, cmd string) string
- func ParseModelArgs(args string) string
- func ParseSlashCommand(text string) (string, string)
- func RenderToolRecord(rec ToolRecord) string
- func SplitMessage(text string, maxLen int) []string
- func TextContent(text string) []ai.ContentBlock
- func ToolLine(t *ToolUseEvent) string
- func Truncate(s string, maxLen int) string
- func WithNotificationAgentID(ctx context.Context, agentID string) context.Context
- type AgentCommandHandler
- type AgentInfo
- type AgentManager
- type Channel
- type ChatStream
- type Event
- type FeishuConfig
- type FeishuGroup
- type Handler
- type ImageEvent
- type IncomingMessage
- type IndexedAgent
- type IndexedModel
- type MessageHandler
- type ModelCommandHandler
- type ModelManager
- type ModelOption
- type Notification
- type QQConfig
- type TelegramConfig
- type ToolRecord
- type ToolTracker
- func (tt *ToolTracker) Finish(t *ToolUseEvent)
- func (tt *ToolTracker) Handle(t *ToolUseEvent) bool
- func (tt *ToolTracker) HasHistory() bool
- func (tt *ToolTracker) IsDisplaying() bool
- func (tt *ToolTracker) Render() string
- func (tt *ToolTracker) RenderFinal() string
- func (tt *ToolTracker) Start(t *ToolUseEvent)
- type ToolUseEvent
- type WeixinConfig
Constants ¶
const ( PlatformTelegram = "telegram" PlatformQQ = "qq" PlatformFeishu = "feishu" PlatformWeixin = "weixin" PlatformCLI = "cli" )
Platform identifiers for each messaging channel.
const WelcomeMessage = "Hi! I'm Anna -- your local AI assistant.\n\n" +
"Commands:\n" +
"/new -- Start a fresh session\n" +
"/compact -- Compress conversation history\n" +
"/abort -- Cancel the in-progress response\n" +
"/model -- Switch between models\n" +
"/agent -- List or switch agents\n" +
"/whoami -- Show your user ID\n\n" +
"Just send me a message to get started."
WelcomeMessage is the shared welcome/help text for all channels.
Variables ¶
var ToolEmoji = map[string]string{
"bash": "⚡",
"read": "📖",
"write": "✏️",
"edit": "🔧",
"search": "🔍",
"default": "🔧",
}
ToolEmoji maps known tool names to display emoji.
Functions ¶
func DecodePluginConfig ¶
func FormatAgentList ¶
func FormatAgentList(agents []IndexedAgent, currentAgentID string) string
FormatAgentList builds a text-based agent list, marking the current agent.
func FormatDuration ¶
FormatDuration formats a duration as a human-friendly string.
func FormatModelList ¶
func FormatModelList(models []IndexedModel, query string) string
FormatModelList builds a text-based model list with bullet points.
func FormatNumberedModelList ¶
func FormatNumberedModelList(models []IndexedModel, query string) string
FormatNumberedModelList builds a text-based model list with numbered entries.
func HandleAgentCommand ¶
func HandleAgentCommand(cfg AgentCommandHandler)
HandleAgentCommand runs the shared /agent flow for text-based channels.
func HandleModelCommand ¶
func HandleModelCommand(cfg ModelCommandHandler)
HandleModelCommand runs the shared /model flow for text-based channels.
func NotificationAgentIDFromContext ¶ added in v0.10.0
NotificationAgentIDFromContext returns the agent ID associated with a notification-producing tool call, if present.
func ParseCommandArgs ¶
ParseCommandArgs extracts arguments after the command token. Example: ParseCommandArgs("/agent foo", "/agent") returns "foo".
func ParseModelArgs ¶
ParseModelArgs parses /model arguments as a query string. Returns empty string when no arguments are provided.
func ParseSlashCommand ¶
ParseSlashCommand extracts a slash command and its arguments. The returned command is always lowercased.
func RenderToolRecord ¶
func RenderToolRecord(rec ToolRecord) string
RenderToolRecord formats a single completed tool record.
func SplitMessage ¶
SplitMessage splits text into chunks that fit within maxLen. It tries to split at newline boundaries and avoids cutting multi-byte UTF-8 characters.
func TextContent ¶
func TextContent(text string) []ai.ContentBlock
TextContent wraps a plain string as a single-element []ai.ContentBlock.
func ToolLine ¶
func ToolLine(t *ToolUseEvent) string
ToolLine returns a short status line for a tool-use event. Used by channels with simple tool display (no full tracker).
Types ¶
type AgentCommandHandler ¶
type AgentCommandHandler struct {
Ctx context.Context
Incoming IncomingMessage
Args string
Reply func(string)
ListAgents func(context.Context, IncomingMessage) ([]AgentInfo, string, error)
SwitchAgent func(context.Context, IncomingMessage, string) error
FormatList func([]IndexedAgent, string) string
OnSwitched func(string)
}
AgentCommandHandler provides the callbacks needed to serve /agent in text UIs.
type AgentManager ¶
type AgentManager interface {
// ListAgents returns enabled agents the user can access and the current agent ID.
ListAgents(ctx context.Context, msg IncomingMessage) ([]AgentInfo, string, error)
// SwitchAgent switches the active agent for this chat context.
SwitchAgent(ctx context.Context, msg IncomingMessage, agentSlug string) error
}
AgentManager provides agent listing and switching for channel plugins that support the /agent command.
type Channel ¶
type Channel interface {
// Name returns a unique identifier (e.g. "telegram", "qq").
Name() string
// Start begins listening for messages. Blocks until ctx is cancelled.
Start(ctx context.Context) error
// Stop gracefully shuts down the channel.
Stop()
// Notify sends a push notification to a target within this channel.
Notify(ctx context.Context, n Notification) error
}
Channel is a messaging platform adapter.
type ChatStream ¶
ChatStream holds the event channel and session metadata returned by HandleMessage.
type Event ¶
type Event struct {
Text string
Image *ImageEvent
ToolUse *ToolUseEvent
Err error
}
Event is a stream event from the agent, consumed by channel plugins to render responses on the platform.
type FeishuConfig ¶
type FeishuConfig struct {
InstanceID string `json:"-"`
AppID string `json:"app_id"`
AppSecret string `json:"app_secret"`
EncryptKey string `json:"encrypt_key"`
VerificationToken string `json:"verification_token"`
GroupMode string `json:"group_mode"`
Groups map[string]FeishuGroup `json:"groups"`
EnableNotify bool `json:"enable_notify"`
}
FeishuConfig is the persisted Feishu channel plugin configuration.
type FeishuGroup ¶
type FeishuGroup struct {
GroupMode string `json:"group_mode"`
SystemPrompt string `json:"system_prompt"`
ToolAllow []string `json:"tool_allow"`
ToolDeny []string `json:"tool_deny"`
}
FeishuGroup is a per-chat override in the persisted Feishu channel config.
type Handler ¶
type Handler interface {
MessageHandler
ModelManager
AgentManager
}
Handler combines message routing with model and agent management. Channel plugins typically need all three capabilities.
type ImageEvent ¶
ImageEvent carries a base64-encoded image.
type IncomingMessage ¶
type IncomingMessage struct {
Platform string // "telegram", "qq", etc.
ChannelID string // configured channel instance ID; defaults to Platform.
SenderID string // preferred platform-specific user ID
SenderIDs []string // ordered candidate sender IDs, most stable first
SenderName string // display name
ChatID string // group/channel ID (empty for DMs)
IsGroup bool
Content []ai.ContentBlock
}
IncomingMessage is the normalised input from any platform.
type IndexedAgent ¶
IndexedAgent pairs an AgentInfo with its 1-based global index.
func IndexAgents ¶
func IndexAgents(agents []AgentInfo) []IndexedAgent
IndexAgents wraps a full agent list with sequential 1-based indices.
type IndexedModel ¶
type IndexedModel struct {
ModelOption
GlobalIdx int
}
IndexedModel pairs a ModelOption with its 1-based global index.
func FilterModels ¶
func FilterModels(models []ModelOption, query string) []IndexedModel
FilterModels returns indexed models matching the query, preserving their 1-based global indices from the full list.
func IndexModels ¶
func IndexModels(models []ModelOption) []IndexedModel
IndexModels wraps a full model list with sequential 1-based indices.
type MessageHandler ¶
type MessageHandler interface {
// HandleIncoming resolves the user once, tries command handling, and if the
// command is not handled, streams a chat response.
// Returns (commandResponse, handled, stream, err).
// If handled is true, commandResponse contains the reply and stream is nil.
// If handled is false, stream contains the chat response.
HandleIncoming(ctx context.Context, msg IncomingMessage, command, args string) (string, bool, *ChatStream, error)
}
MessageHandler is the core coordinator interface injected into channel plugins. It owns user resolution, agent routing, session management, and command handling. The single HandleIncoming entry point resolves the user once, tries command handling, and falls through to chat streaming — eliminating double resolution.
type ModelCommandHandler ¶
type ModelCommandHandler struct {
Args string
Reply func(string)
ListModels func() []ModelOption
SwitchModel func(provider, model string) error
FormatList func([]IndexedModel, string) string
AllowIndexSelection bool
OnSwitched func(ModelOption)
}
ModelCommandHandler provides the callbacks needed to serve /model in text UIs.
type ModelManager ¶
type ModelManager interface {
// ListModels returns available models.
ListModels() []ModelOption
// SwitchModel switches the active model.
SwitchModel(provider, model string) error
}
ModelManager provides model listing and switching for channel plugins that support the /model command.
type ModelOption ¶
ModelOption represents a selectable provider/model combination.
func FindModelByName ¶
func FindModelByName(models []ModelOption, name string) (ModelOption, bool)
FindModelByName looks up a model by "provider/model" name (case-insensitive). Returns the model and true if found, zero value and false otherwise.
type Notification ¶
type Notification struct {
Channel string // optional: route to a specific backend
ChatID string // target chat/channel within the backend
AgentID string // optional: agent that produced the notification
Text string // markdown content
Silent bool // send without notification sound
}
Notification is a push message to send to a chat.
type QQConfig ¶
type QQConfig struct {
InstanceID string `json:"-"`
AppID string `json:"app_id"`
AppSecret string `json:"app_secret"`
GroupMode string `json:"group_mode"`
EnableNotify bool `json:"enable_notify"`
}
QQConfig is the persisted QQ channel plugin configuration.
type TelegramConfig ¶
type TelegramConfig struct {
InstanceID string `json:"-"`
Token string `json:"token"`
ChannelID string `json:"channel_id"`
GroupMode string `json:"group_mode"`
EnableNotify bool `json:"enable_notify"`
}
TelegramConfig is the persisted Telegram channel plugin configuration.
type ToolRecord ¶
type ToolRecord struct {
Tool string
Input string
Status string // "done" or "error"
Detail string
Duration time.Duration
}
ToolRecord holds a completed tool invocation for summary display.
type ToolTracker ¶
type ToolTracker struct {
History []ToolRecord
ActiveTool string
ActiveInput string
ActiveStart time.Time
DisplayUntil time.Time // minimum time to keep showing the last-finished tool
// MinDisplayDuration controls how long a finished tool stays visible.
// Zero means no minimum.
MinDisplayDuration time.Duration
}
ToolTracker tracks active and completed tool invocations during streaming.
func (*ToolTracker) Finish ¶
func (tt *ToolTracker) Finish(t *ToolUseEvent)
Finish records the active tool as completed.
func (*ToolTracker) Handle ¶
func (tt *ToolTracker) Handle(t *ToolUseEvent) bool
Handle processes a tool event, returning true if a display refresh is needed.
func (*ToolTracker) HasHistory ¶
func (tt *ToolTracker) HasHistory() bool
HasHistory returns true if any tools were tracked.
func (*ToolTracker) IsDisplaying ¶
func (tt *ToolTracker) IsDisplaying() bool
IsDisplaying returns true if there is an active tool or the minimum display duration for the last finished tool has not yet elapsed.
func (*ToolTracker) Render ¶
func (tt *ToolTracker) Render() string
Render builds the tool section for real-time streaming display, showing completed tools and the active tool with elapsed time.
func (*ToolTracker) RenderFinal ¶
func (tt *ToolTracker) RenderFinal() string
RenderFinal builds a compact tool summary for the final message. Shows a one-liner with tool counts and total time, plus individual lines for any failed tool calls.
func (*ToolTracker) Start ¶
func (tt *ToolTracker) Start(t *ToolUseEvent)
Start registers a new tool as running.
type ToolUseEvent ¶
type ToolUseEvent struct {
Tool string // tool name, e.g. "bash", "read"
Status string // "running", "done", "error"
Input string // short summary of the tool input
Detail string // error detail or result summary
}
ToolUseEvent describes a tool invocation in progress or completed.
type WeixinConfig ¶
type WeixinConfig struct {
InstanceID string `json:"-"`
BotToken string `json:"bot_token"`
BaseURL string `json:"base_url"`
BotID string `json:"bot_id"`
UserID string `json:"user_id"`
EnableNotify bool `json:"enable_notify"`
}
WeixinConfig is the persisted Weixin channel plugin configuration.