channel

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2026 License: AGPL-3.0 Imports: 47 Imported by: 0

Documentation

Overview

Package channel provides a unified abstraction for multi-platform messaging channels. It defines types, interfaces, and a registry for channel adapters such as Telegram and Feishu.

Index

Constants

View Source
const (
	ProcessingStageStarted   = "processing_started"
	ProcessingStageRefresh   = "processing_refresh"
	ProcessingStageCompleted = "processing_completed"
	ProcessingStageFailed    = "processing_failed"
)

Processing status stages reported to ProcessingStatusErrorFunc.

View Source
const (
	ActionTypeToolApproval = "tool_approval"
	ActionApprove          = "approve"
	ActionReject           = "reject"
)
View Source
const (
	ConversationTypePrivate = "private"
	ConversationTypeGroup   = "group"
	ConversationTypeThread  = "thread"
)
View Source
const ExternalToolCallEmoji = "⚙️"

ExternalToolCallEmoji is the emoji used for any tool not in the built-in whitelist (including MCP and federation tools).

Variables

View Source
var (
	// ErrSendTargetRequired means a send named neither a target nor a channel identity.
	ErrSendTargetRequired = errors.New("target or channel_identity_id is required")
	// ErrChannelBindingRequired means the recipient identity has not linked this channel.
	ErrChannelBindingRequired = errors.New("channel binding required")
)
View Source
var (
	ErrWebhookEndpointUnsupported = errors.New("channel webhook endpoint update is not supported")
	ErrInvalidWebhookEndpoint     = errors.New("invalid webhook endpoint")
)
View Source
var ErrChannelConfigNotFound = errors.New("channel config not found")

ErrChannelConfigNotFound indicates the bot has no persisted config for the channel type.

View Source
var ErrChannelDiscoveryFailed = errors.New("channel identity discovery failed")

ErrChannelDiscoveryFailed indicates that a platform-side self identity check failed.

View Source
var ErrChannelIdentityConfigNotFound = errors.New("channel user config not found")

ErrChannelIdentityConfigNotFound indicates the channel identity has no binding for the channel type.

View Source
var ErrEnableChannelFailed = errors.New("enable channel failed")

ErrEnableChannelFailed indicates that enabling the channel (e.g. EnsureConnection) failed.

View Source
var ErrInboundQueueFull = errors.New("inbound queue full")

ErrInboundQueueFull indicates the synchronous inbound queue admission failed because all worker slots are saturated.

View Source
var ErrStopNotSupported = errors.New("channel connection stop not supported")

ErrStopNotSupported is returned when a connection does not support graceful shutdown.

Functions

func BundleFromAttachment

func BundleFromAttachment(att Attachment) attachmentpkg.Bundle

BundleFromAttachment converts a channel attachment to the shared internal bundle shape.

func ChunkMarkdownText

func ChunkMarkdownText(text string, limit int) []string

ChunkMarkdownText splits text at paragraph boundaries (double newlines), respecting the rune limit.

func ChunkText

func ChunkText(text string, limit int) []string

ChunkText splits text at newline boundaries, respecting the rune limit.

func CollapseMessagePartTextLine

func CollapseMessagePartTextLine(text string) string

CollapseMessagePartTextLine normalizes block part text into one visible line.

func ContainsMarkdown

func ContainsMarkdown(text string) bool

ContainsMarkdown returns true if the text contains common Markdown constructs.

func DecodeConfigMap

func DecodeConfigMap(raw []byte) (map[string]any, error)

DecodeConfigMap unmarshals a JSON byte slice into a string-keyed map.

func ErrorReplyText added in v0.21.0

func ErrorReplyText(errorCode, text string) string

ErrorReplyText is the text an adapter shows for a stream error. Copy rendered from an error code is a complete sentence and is shown as it is; a bare error text is labelled as an error.

func ErrorText added in v0.22.0

func ErrorText(t *i18n.Localizer, public *apperror.Error) string

ErrorText is the channel copy for a public error: errors.<code> from the channel locale with the error's args substituted, then the catalog detail. public is an answer of errs.Answer, so its code is in the catalog.

func EscapeMessagePartLinkURL

func EscapeMessagePartLinkURL(url string) string

EscapeMessagePartLinkURL percent-encodes characters that can break platform rich-link wrappers while preserving ordinary http(s), mailto, tel and platform-specific URL prefixes.

func GenerateRoutingKey

func GenerateRoutingKey(platform, botID, conversationID, conversationType, senderID string) string

GenerateRoutingKey builds a route key from platform, bot, conversation, and sender info. For group chats, the sender ID is appended to provide per-user context.

func IsDataPath

func IsDataPath(raw string) bool

IsDataPath reports whether raw is a container-internal data path (/data/...).

func IsDataURL

func IsDataURL(raw string) bool

IsDataURL reports whether raw is a data: URL (e.g. "data:image/png;base64,...").

func IsHTTPURL

func IsHTTPURL(raw string) bool

IsHTTPURL reports whether raw is an http:// or https:// URL.

func IsInboundQueueFull

func IsInboundQueueFull(err error) bool

IsInboundQueueFull reports whether err means the inbound queue rejected a message due to local capacity.

func IsPrivateConversationType

func IsPrivateConversationType(raw string) bool

IsPrivateConversationType reports whether the conversation is private.

func IsPublicHost

func IsPublicHost(host string) bool

IsPublicHost matches the browser-side validation in apps/web/src/utils/webhook-public-base.ts.

func NormalizeConversationType

func NormalizeConversationType(raw string) string

NormalizeConversationType normalizes conversation type values within the channel abstraction domain: private/group/thread.

func NormalizeMessagePartCodeLanguage

func NormalizeMessagePartCodeLanguage(language string) string

NormalizeMessagePartCodeLanguage returns a safe code-fence language hint.

func ParseActionValue

func ParseActionValue(value string) (decision, approvalID string, ok bool)

func ReadString

func ReadString(raw map[string]any, keys ...string) string

ReadString looks up the first matching key in a map and returns its string representation. It tries each key in order and converts non-string values using type-safe formatting.

func RejectReservedSkillMetadata

func RejectReservedSkillMetadata(msg Message) error

RejectReservedSkillMetadata rejects client-supplied reserved skill metadata anywhere it can ride on a message: top-level metadata, content parts, attachments, and reply attachments. This is a security boundary — reserved keys (requested_skills, skill_activation, user_message_kind, …) are trusted downstream as server-authored state. Single walker shared by every public inbound surface (web REST, web WS, channel inbound) so a future metadata-bearing location on Message only needs guarding once.

func RenderPartsAsMarkdown

func RenderPartsAsMarkdown(parts []MessagePart) string

RenderPartsAsMarkdown produces a GFM-flavored Markdown string from canonical MessageParts. It is the degradation path used by coerceFormatForCaps when a target channel supports Markdown but lacks RichText capability (e.g. DingTalk, Matrix), and is the reference output the per-platform renderers (Telegram HTML / Discord MD / Feishu lark_md / Slack mrkdwn) are tested against in the canonical-parts matrix.

Attacker-controllable text and URL fields are neutralised so they cannot forge masked links, escape style wrappers, or open autolinks. The escape set mirrors what the Discord renderer applies; channels with stricter syntax (Slack mrkdwn) bypass this function via the RichText gate and run their own renderer instead.

func RenderPartsAsPlain

func RenderPartsAsPlain(parts []MessagePart) string

RenderPartsAsPlain joins canonical MessageParts into a plain-text block with style markers, masked-link syntax, and code fences stripped. Used by coerceFormatForCaps as the final degradation when the target channel supports neither RichText nor Markdown.

func RenderToolCallMessage

func RenderToolCallMessage(p ToolCallPresentation) string

RenderToolCallMessage renders a plain-text single-message view of a tool call state. Links are rendered as two lines: the title on one line and the URL on the next. Adapters that want Markdown link syntax should use RenderToolCallMessageMarkdown instead.

func RenderToolCallMessageMarkdown

func RenderToolCallMessageMarkdown(p ToolCallPresentation) string

RenderToolCallMessageMarkdown renders a Markdown version of the tool call presentation. Links become [title](url), code blocks are fenced with triple backticks, and plain-text blocks are unchanged.

func ReplyText added in v0.22.0

func ReplyText(ctx context.Context, t *i18n.Localizer, err error, fallback string) string

ReplyText is the reply a flow sends for err. A specific public error is shown with its copy. An error errs.Answer answers with a generic code, internal or http.bad_request, is shown with fallback, the flow's own failure copy, or with the generic copy when fallback is empty. It is empty when the caller has canceled, and the flow then sends no reply.

func SplitMessagePartTextLines

func SplitMessagePartTextLines(text string) []string

SplitMessagePartTextLines normalizes block part text into trimmed display lines.

func StripInlineMarkup

func StripInlineMarkup(s string) string

StripInlineMarkup removes the inline Markdown markers (** and `) authored for capable channels, leaving clean text for plain-text-only channels.

Scope: only ** (bold) and ` (code) are stripped, because those are the only inline markers the command renderers emit (MdBold/MdCode/CmdRef). Other constructs ContainsMarkdown recognizes — links [a](b), headings, list bullets — are intentionally NOT stripped: the renderers never produce them, so any such characters in a body are literal user/content text and must be preserved verbatim rather than mangled. Extend this (and coerceFormatForCaps) if a renderer ever starts emitting those constructs.

func SummarizeToolInput

func SummarizeToolInput(_ string, input any) string

SummarizeToolInput returns a short human-readable representation of a tool call's input payload, prioritizing known key fields (path, command, query, url, target, to, id, cron, action) before falling back to a compact JSON projection.

func SummarizeToolResult

func SummarizeToolResult(_ string, result any) string

SummarizeToolResult returns a short representation of a tool call's result, surfacing status/error/count signals when present and otherwise falling back to trimmed text or a compact JSON projection.

func ToolCallEmoji

func ToolCallEmoji(toolName string) string

ToolCallEmoji returns the emoji mapped for a tool name. Unknown / external tools fall back to ExternalToolCallEmoji.

Types

type Action

type Action struct {
	Type  string `json:"type"`
	Label string `json:"label,omitempty"`
	Value string `json:"value,omitempty"`
	URL   string `json:"url,omitempty"`
	// Row groups buttons into keyboard rows for renderers that support grids
	// (e.g. Telegram inline keyboards). Buttons sharing a Row render together;
	// rows appear in ascending numeric order. Renderers without grid support
	// ignore this field. 0 is the default (single row, prior behavior).
	Row int `json:"row,omitempty"`
}

Action describes an interactive button or link in a message.

type Adapter

type Adapter interface {
	Type() ChannelType
	Descriptor() Descriptor
}

Adapter is the base interface every channel adapter must implement.

type Attachment

type Attachment struct {
	Type           AttachmentType `json:"type"`
	URL            string         `json:"url,omitempty"`  // HTTP(S) or data URL
	Path           string         `json:"path,omitempty"` // workspace-local filesystem path
	PlatformKey    string         `json:"platform_key,omitempty"`
	SourcePlatform string         `json:"source_platform,omitempty"`
	ContentHash    string         `json:"content_hash,omitempty"`
	Base64         string         `json:"base64,omitempty"` // data URL for agent delivery
	Name           string         `json:"name,omitempty"`
	Size           int64          `json:"size,omitempty"`
	Mime           string         `json:"mime,omitempty"`
	DurationMs     int64          `json:"duration_ms,omitempty"`
	Width          int            `json:"width,omitempty"`
	Height         int            `json:"height,omitempty"`
	ThumbnailURL   string         `json:"thumbnail_url,omitempty"`
	Caption        string         `json:"caption,omitempty"`
	Metadata       map[string]any `json:"metadata,omitempty"`
}

Attachment represents a binary file attached to a message.

func AttachmentFromBundle

func AttachmentFromBundle(bundle attachmentpkg.Bundle) Attachment

AttachmentFromBundle converts the shared internal bundle shape to a channel attachment. URL and Path are kept in their respective fields. Callers must guarantee bundle is already normalized (produced by BundleFromXxx or Normalize()).

func NormalizeInboundChannelAttachment

func NormalizeInboundChannelAttachment(att Attachment) Attachment

NormalizeInboundChannelAttachment normalizes a channel attachment at adapter boundary.

func (Attachment) HasReference

func (a Attachment) HasReference() bool

HasReference reports whether URL, Path, or platform key is available.

func (Attachment) Reference

func (a Attachment) Reference() string

Reference returns the strongest available attachment reference. URL is preferred for cross-platform portability, then local Path, then platform key.

type AttachmentPayload

type AttachmentPayload struct {
	Reader io.ReadCloser
	Mime   string
	Name   string
	Size   int64
}

AttachmentPayload contains resolved attachment bytes and optional metadata. Caller must close Reader.

type AttachmentResolver

type AttachmentResolver interface {
	ResolveAttachment(ctx context.Context, cfg ChannelConfig, attachment Attachment) (AttachmentPayload, error)
}

AttachmentResolver resolves attachment references (for example platform_key) into readable bytes for persistence or transformation pipelines.

type AttachmentType

type AttachmentType string

AttachmentType classifies the kind of binary attachment.

const (
	AttachmentImage AttachmentType = "image"
	AttachmentAudio AttachmentType = "audio"
	AttachmentVideo AttachmentType = "video"
	AttachmentVoice AttachmentType = "voice"
	AttachmentFile  AttachmentType = "file"
	AttachmentGIF   AttachmentType = "gif"
)

func InferAttachmentType

func InferAttachmentType(currentType AttachmentType, mime, name string) AttachmentType

InferAttachmentType infers a canonical attachment type from type/mime/name.

type BaseConnection

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

BaseConnection is a default Connection implementation backed by a stop function.

func NewConnection

func NewConnection(cfg ChannelConfig, stop func(ctx context.Context) error) *BaseConnection

NewConnection creates a BaseConnection for the given config and stop function.

func (*BaseConnection) BotID

func (c *BaseConnection) BotID() string

BotID returns the bot identifier that owns this connection.

func (*BaseConnection) ChannelType

func (c *BaseConnection) ChannelType() ChannelType

ChannelType returns the type of channel this connection serves.

func (*BaseConnection) ConfigID

func (c *BaseConnection) ConfigID() string

ConfigID returns the channel configuration identifier.

func (*BaseConnection) MarkStopped

func (c *BaseConnection) MarkStopped()

MarkStopped flags the connection as no longer running without invoking its stop function. Adapters call this from internal goroutines that have given up (terminal protocol error etc.) so the manager's Running() check reflects reality and reconciliation can act on it.

func (*BaseConnection) Running

func (c *BaseConnection) Running() bool

Running reports whether the connection is still active.

func (*BaseConnection) Stop

func (c *BaseConnection) Stop(ctx context.Context) error

Stop gracefully shuts down the connection.

type BindingCriteria

type BindingCriteria struct {
	SubjectID  string
	Attributes map[string]string
}

BindingCriteria specifies conditions for matching a user-channel binding.

func BindingCriteriaFromIdentity

func BindingCriteriaFromIdentity(identity Identity) BindingCriteria

BindingCriteriaFromIdentity creates BindingCriteria from a channel Identity.

func (BindingCriteria) Attribute

func (c BindingCriteria) Attribute(key string) string

Attribute returns the trimmed value for the given key, or empty string if absent.

type BindingMatcher

type BindingMatcher interface {
	MatchBinding(config map[string]any, criteria BindingCriteria) bool
	BuildUserConfig(identity Identity) map[string]any
}

BindingMatcher matches user-channel bindings and constructs binding configs from identities.

type BindingStore

type BindingStore interface {
	ResolveChannelIdentityBinding(ctx context.Context, channelType ChannelType, criteria BindingCriteria) (string, error)
}

BindingStore resolves channel-identity bindings. Used by identity resolution.

type ChannelCapabilities

type ChannelCapabilities struct {
	Text            bool     `json:"text"`
	Markdown        bool     `json:"markdown"`
	RichText        bool     `json:"rich_text"`
	Attachments     bool     `json:"attachments"`
	Media           bool     `json:"media"`
	Reactions       bool     `json:"reactions"`
	Buttons         bool     `json:"buttons"`
	URLButtons      bool     `json:"url_buttons"`
	Reply           bool     `json:"reply"`
	Threads         bool     `json:"threads"`
	Streaming       bool     `json:"streaming"`
	Polls           bool     `json:"polls"`
	Edit            bool     `json:"edit"`
	Unsend          bool     `json:"unsend"`
	NativeCommands  bool     `json:"native_commands"`
	NativeUserInput bool     `json:"native_user_input"`
	BlockStreaming  bool     `json:"block_streaming"`
	ChatTypes       []string `json:"chat_types,omitempty"`
}

ChannelCapabilities describes the feature matrix of a channel type. It is used by the outbound layer to validate message content before delivery.

type ChannelConfig

type ChannelConfig struct {
	ID               string         `json:"id"`
	TeamID           string         `json:"team_id"`
	BotID            string         `json:"bot_id"`
	ChannelType      ChannelType    `json:"channel_type"`
	Credentials      map[string]any `json:"credentials"`
	ExternalIdentity string         `json:"external_identity"`
	SelfIdentity     map[string]any `json:"self_identity"`
	Routing          map[string]any `json:"routing"`
	Disabled         bool           `json:"disabled"`
	VerifiedAt       time.Time      `json:"verified_at"`
	CreatedAt        time.Time      `json:"created_at"`
	UpdatedAt        time.Time      `json:"updated_at"`
}

ChannelConfig holds the configuration for a bot's channel integration. Disabled: true means the channel is stopped (not connected); false means enabled.

type ChannelDirectoryAdapter

type ChannelDirectoryAdapter interface {
	ListPeers(ctx context.Context, cfg ChannelConfig, query DirectoryQuery) ([]DirectoryEntry, error)
	ListGroups(ctx context.Context, cfg ChannelConfig, query DirectoryQuery) ([]DirectoryEntry, error)
	ListGroupMembers(ctx context.Context, cfg ChannelConfig, groupID string, query DirectoryQuery) ([]DirectoryEntry, error)
	ResolveEntry(ctx context.Context, cfg ChannelConfig, input string, kind DirectoryEntryKind) (DirectoryEntry, error)
}

ChannelDirectoryAdapter provides contact and group lookup for a channel platform.

type ChannelIdentityBinding

type ChannelIdentityBinding struct {
	ID                string         `json:"id"`
	ChannelType       ChannelType    `json:"channel_type"`
	ChannelIdentityID string         `json:"channel_identity_id"`
	Config            map[string]any `json:"config"`
	CreatedAt         time.Time      `json:"created_at"`
	UpdatedAt         time.Time      `json:"updated_at"`
}

ChannelIdentityBinding represents a channel identity's binding to a specific channel type.

type ChannelType

type ChannelType string

ChannelType identifies a messaging platform (e.g., "telegram", "feishu").

const (
	ChannelTypeTelegram ChannelType = "telegram"
	ChannelTypeFeishu   ChannelType = "feishu"
	ChannelTypeDingtalk ChannelType = "dingtalk"
	ChannelTypeMatrix   ChannelType = "matrix"
	ChannelTypeDiscord  ChannelType = "discord"
	ChannelTypeQQ       ChannelType = "qq"
	ChannelTypeWecom    ChannelType = "wecom"
	ChannelTypeWeixin   ChannelType = "weixin"
	ChannelTypeWeChatOA ChannelType = "wechatoa"
	ChannelTypeLocal    ChannelType = "local"
	ChannelTypeSlack    ChannelType = "slack"
	ChannelTypeLine     ChannelType = "line"
)

Well-known ChannelType values for platforms with special handling in the core channel package. Adapter packages define their own identical constant as their package-local Type.

func (ChannelType) String

func (c ChannelType) String() string

String returns the channel type as a plain string.

type Chunker

type Chunker func(text string, limit int) []string

Chunker splits text into pieces that respect a character limit.

func DefaultChunker

func DefaultChunker(mode ChunkerMode) Chunker

DefaultChunker returns the built-in Chunker for the given mode.

type ChunkerMode

type ChunkerMode string

ChunkerMode selects the text chunking strategy.

const (
	ChunkerModeText     ChunkerMode = "text"
	ChunkerModeMarkdown ChunkerMode = "markdown"
)

type ConfigLister

type ConfigLister interface {
	ListConfigsByType(ctx context.Context, channelType ChannelType) ([]ChannelConfig, error)
}

ConfigLister lists channel configs for periodic refresh. Used by connection lifecycle.

type ConfigNormalizer

type ConfigNormalizer interface {
	NormalizeConfig(raw map[string]any) (map[string]any, error)
	NormalizeUserConfig(raw map[string]any) (map[string]any, error)
}

ConfigNormalizer validates and normalizes channel and user-binding configurations.

type ConfigResolver

type ConfigResolver interface {
	ResolveEffectiveConfig(ctx context.Context, botID string, channelType ChannelType) (ChannelConfig, error)
	GetChannelIdentityConfig(ctx context.Context, channelIdentityID string, channelType ChannelType) (ChannelIdentityBinding, error)
}

ConfigResolver resolves effective configs and user bindings. Used for outbound sending.

type ConfigSchema

type ConfigSchema struct {
	Version int                    `json:"version"`
	Fields  map[string]FieldSchema `json:"fields"`
}

ConfigSchema describes the structure of a channel or user-binding configuration.

type ConfigStore

type ConfigStore interface {
	ConfigLister
	ConfigResolver
	BindingStore
	UpsertChannelIdentityConfig(ctx context.Context, channelIdentityID string, channelType ChannelType, req UpsertChannelIdentityConfigRequest) (ChannelIdentityBinding, error)
}

ConfigStore is the full persistence interface. Components should depend on smaller interfaces above; ConfigStore exists as a convenience for wiring.

type Connection

type Connection interface {
	ConfigID() string
	BotID() string
	ChannelType() ChannelType
	Stop(ctx context.Context) error
	Running() bool
}

Connection represents an active, long-lived link to a channel platform.

type ConnectionController

type ConnectionController interface {
	EnsureConnection(ctx context.Context, cfg ChannelConfig) error
	RemoveConnection(ctx context.Context, botID string, channelType ChannelType)
}

ConnectionController controls runtime channel connections.

type ConnectionStatus

type ConnectionStatus struct {
	ConfigID    string      `json:"config_id"`
	BotID       string      `json:"bot_id"`
	ChannelType ChannelType `json:"channel_type"`
	Running     bool        `json:"running"`
	LastError   string      `json:"last_error,omitempty"`
	UpdatedAt   time.Time   `json:"updated_at"`
}

ConnectionStatus describes runtime status for one configured channel connection.

type ContainerAttachmentIngester

type ContainerAttachmentIngester interface {
	IngestContainerFile(ctx context.Context, botID, containerPath string) (media.Asset, error)
}

ContainerAttachmentIngester is an optional extension of OutboundAttachmentStore for stores that can read files directly from a bot's container filesystem. Implementations must be safe for concurrent use.

type Conversation

type Conversation struct {
	ID       string
	Type     string
	Name     string
	ThreadID string
	Metadata map[string]any
}

Conversation holds metadata about the chat or group context.

type Descriptor

type Descriptor struct {
	Type               ChannelType
	DisplayName        string
	Configless         bool
	AckDisabledWebhook bool
	// OwnerOnly marks channels that no third party can ever reach (e.g.
	// personal-assistant channels living inside the activator's own
	// account). Every sender on these channels is treated as the operator:
	// an unlinked sender resolves to the bot owner's account (so gates keyed
	// on the account principal, such as workspace exec and external runtimes,
	// see the owner), and the gates keyed on the channel identity instead —
	// chat ACL and write-gated slash commands — skip their /link requirement.
	OwnerOnly        bool
	Capabilities     ChannelCapabilities
	OutboundPolicy   OutboundPolicy
	ConfigSchema     ConfigSchema
	UserConfigSchema ConfigSchema
	TargetSpec       TargetSpec
}

Descriptor holds read-only metadata and static policy flags for a registered channel type. Request handling and platform operations are expressed through optional interfaces.

type DirectoryEntry

type DirectoryEntry struct {
	Kind      DirectoryEntryKind `json:"kind"`
	ID        string             `json:"id"`
	Name      string             `json:"name,omitempty"`
	Handle    string             `json:"handle,omitempty"`
	AvatarURL string             `json:"avatar_url,omitempty"`
	Metadata  map[string]any     `json:"metadata,omitempty"`
}

DirectoryEntry represents a single user or group discovered through the channel's directory.

type DirectoryEntryKind

type DirectoryEntryKind string

DirectoryEntryKind classifies a directory entry as a user or a group.

const (
	DirectoryEntryUser  DirectoryEntryKind = "user"
	DirectoryEntryGroup DirectoryEntryKind = "group"
)

type DirectoryQuery

type DirectoryQuery struct {
	Query string             `json:"query,omitempty"`
	Limit int                `json:"limit,omitempty"`
	Kind  DirectoryEntryKind `json:"kind,omitempty"`
}

DirectoryQuery contains filters for directory listing operations.

type FieldSchema

type FieldSchema struct {
	Type        FieldType `json:"type"`
	Required    bool      `json:"required"`
	Order       int       `json:"order,omitempty"`
	Title       string    `json:"title,omitempty"`
	Description string    `json:"description,omitempty"`
	Enum        []string  `json:"enum,omitempty"`
	Example     any       `json:"example,omitempty"`
}

FieldSchema describes a single configuration field.

type FieldType

type FieldType string

FieldType enumerates the supported configuration field types.

const (
	FieldString FieldType = "string"
	FieldSecret FieldType = "secret"
	FieldBool   FieldType = "bool"
	FieldNumber FieldType = "number"
	FieldEnum   FieldType = "enum"
)

type ForwardRef

type ForwardRef struct {
	MessageID          string `json:"message_id,omitempty"`
	FromUserID         string `json:"from_user_id,omitempty"`
	FromConversationID string `json:"from_conversation_id,omitempty"`
	Sender             string `json:"sender,omitempty"`
	Date               int64  `json:"date,omitempty"`
	AttachmentsKnown   bool   `json:"attachments_known,omitempty"`
}

ForwardRef describes the structured origin of a forwarded message.

type Identity

type Identity struct {
	SubjectID   string
	DisplayName string
	Attributes  map[string]string
}

Identity represents a sender's identity on a channel.

func (Identity) Attribute

func (i Identity) Attribute(key string) string

Attribute returns the trimmed value for the given key, or empty string if absent.

type InboundHandler

type InboundHandler func(ctx context.Context, cfg ChannelConfig, msg InboundMessage) error

InboundHandler is a callback invoked when a message arrives from a channel.

type InboundMessage

type InboundMessage struct {
	Channel      ChannelType
	Message      Message
	BotID        string
	ReplyTarget  string
	RouteKey     string
	Sender       Identity
	Conversation Conversation
	ReceivedAt   time.Time
	Source       string
	Metadata     map[string]any
}

InboundMessage is a message received from an external channel.

func (InboundMessage) RoutingKey

func (m InboundMessage) RoutingKey() string

RoutingKey returns a stable identifier used for reply routing. Format: platform:bot_id:conversation_id[:sender_id].

type InboundProcessor

type InboundProcessor interface {
	HandleInbound(ctx context.Context, cfg ChannelConfig, msg InboundMessage, sender StreamReplySender) error
}

InboundProcessor handles inbound messages and replies through the given sender.

type Lifecycle

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

Lifecycle coordinates persisted config updates and runtime connection state.

func NewLifecycle

func NewLifecycle(store LifecycleStore, controller ConnectionController) *Lifecycle

NewLifecycle creates a lifecycle coordinator from storage and connection controller.

func (*Lifecycle) DeleteBotChannelConfig

func (s *Lifecycle) DeleteBotChannelConfig(ctx context.Context, botID string, channelType ChannelType) error

DeleteBotChannelConfig removes persisted config and stops active runtime connection.

func (*Lifecycle) ResolveBotChannelConfig added in v0.21.0

func (s *Lifecycle) ResolveBotChannelConfig(ctx context.Context, botID string, channelType ChannelType) (cfg ChannelConfig, found bool, err error)

ResolveBotChannelConfig reads the bot's stored config for channelType without touching its connection. found is false when the bot has none.

func (*Lifecycle) SetBotChannelStatus

func (s *Lifecycle) SetBotChannelStatus(ctx context.Context, botID string, channelType ChannelType, disabled bool) (ChannelConfig, error)

SetBotChannelStatus updates only the disabled status and applies runtime lifecycle.

func (*Lifecycle) UpsertBotChannelConfig

func (s *Lifecycle) UpsertBotChannelConfig(ctx context.Context, botID string, channelType ChannelType, req UpsertConfigRequest) (ChannelConfig, error)

UpsertBotChannelConfig updates config and applies connection lifecycle. For disabled=true, it stores config and stops any active connection. For disabled=false, it stores config then starts connection; on start failure it rolls back.

type LifecycleStore

type LifecycleStore interface {
	ResolveEffectiveConfig(ctx context.Context, botID string, channelType ChannelType) (ChannelConfig, error)
	UpsertConfig(ctx context.Context, botID string, channelType ChannelType, req UpsertConfigRequest) (ChannelConfig, error)
	UpdateConfigDisabled(ctx context.Context, botID string, channelType ChannelType, disabled bool) (ChannelConfig, error)
	DeleteConfig(ctx context.Context, botID string, channelType ChannelType) error
}

LifecycleStore persists channel configs for lifecycle orchestration.

type LocalRuntime

type LocalRuntime struct {
	Lifecycle *Lifecycle
	Store     *Store
	Manager   *Manager
}

func (*LocalRuntime) ConnectionStatusesByBot

func (r *LocalRuntime) ConnectionStatusesByBot(botID string) []ConnectionStatus

func (*LocalRuntime) DeleteBotChannelConfig

func (r *LocalRuntime) DeleteBotChannelConfig(ctx context.Context, botID string, typ ChannelType) error

func (*LocalRuntime) React

func (r *LocalRuntime) React(ctx context.Context, botID string, typ ChannelType, req ReactRequest) error

func (*LocalRuntime) Send

func (r *LocalRuntime) Send(ctx context.Context, botID string, typ ChannelType, req SendRequest) error

func (*LocalRuntime) SetBotChannelStatus

func (r *LocalRuntime) SetBotChannelStatus(ctx context.Context, botID string, typ ChannelType, disabled bool) (ChannelConfig, error)

func (*LocalRuntime) SetWebhookEndpoint

func (*LocalRuntime) UpsertBotChannelConfig

func (r *LocalRuntime) UpsertBotChannelConfig(ctx context.Context, botID string, typ ChannelType, req UpsertConfigRequest) (ChannelConfig, error)

type Manager

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

Manager coordinates channel adapters, connection lifecycle, and message dispatch. Connection lifecycle lives in connection.go, inbound dispatch in inbound.go, and outbound pipeline in outbound.go.

func NewManager

func NewManager(log *slog.Logger, registry *Registry, service ManagerStore, processor InboundProcessor, opts ...ManagerOption) *Manager

NewManager creates a Manager with the given logger, registry, config store, and inbound processor.

func (*Manager) AddAdapter

func (m *Manager) AddAdapter(ctx context.Context, adapter Adapter)

AddAdapter registers an adapter and triggers an immediate refresh for hot-plug support.

func (*Manager) ConnectionStatusesByBot

func (m *Manager) ConnectionStatusesByBot(botID string) []ConnectionStatus

ConnectionStatusesByBot returns observed channel connection statuses for a bot.

func (*Manager) EnsureConnection

func (m *Manager) EnsureConnection(ctx context.Context, cfg ChannelConfig) error

EnsureConnection starts, restarts, or stops the connection for the given config. Disabled configs are stopped and removed; enabled configs are started or restarted.

func (*Manager) HandleInbound

func (m *Manager) HandleInbound(ctx context.Context, cfg ChannelConfig, msg InboundMessage) error

HandleInbound enqueues an inbound message for asynchronous processing by the worker pool.

ctx is read for the identity of the request doing the enqueuing and is deliberately not kept: the work outlives it.

func (*Manager) React

func (m *Manager) React(ctx context.Context, botID string, channelType ChannelType, req ReactRequest) error

React adds or removes an emoji reaction on a channel message.

func (*Manager) Refresh

func (m *Manager) Refresh(ctx context.Context)

Refresh performs a full reconcile of all adapter connections against the DB. Prefer EnsureConnection / RemoveConnection for targeted changes after API operations. Refresh is mainly used at startup and as a periodic safety net.

func (*Manager) RegisterAdapter

func (m *Manager) RegisterAdapter(adapter Adapter)

RegisterAdapter adds an adapter to the registry and logs the registration.

func (*Manager) Registry

func (m *Manager) Registry() *Registry

Registry returns the adapter registry used by this manager.

func (*Manager) RemoveAdapter

func (m *Manager) RemoveAdapter(ctx context.Context, channelType ChannelType)

RemoveAdapter unregisters an adapter and stops all its active connections.

func (*Manager) RemoveConnection

func (m *Manager) RemoveConnection(ctx context.Context, botID string, channelType ChannelType)

RemoveConnection stops and removes connections matching the given bot and channel type.

func (*Manager) Send

func (m *Manager) Send(ctx context.Context, botID string, channelType ChannelType, req SendRequest) error

Send delivers an outbound message to the specified channel, resolving target and config automatically.

func (*Manager) SetAttachmentStore

func (m *Manager) SetAttachmentStore(store OutboundAttachmentStore)

SetAttachmentStore wires the shared outbound attachment store used by the prepared outbound layer.

func (*Manager) Shutdown

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

Shutdown cancels the inbound worker pool and stops all active connections.

func (*Manager) Start

func (m *Manager) Start(ctx context.Context)

Start begins the periodic config refresh loop and inbound worker pool.

func (*Manager) Stop

func (m *Manager) Stop(ctx context.Context, configID string) error

Stop terminates the connection identified by the given config ID.

func (*Manager) StopByBot

func (m *Manager) StopByBot(ctx context.Context, botID string) error

StopByBot terminates all connections belonging to the given bot.

func (*Manager) Use

func (m *Manager) Use(mw ...Middleware)

Use appends middleware to the inbound processing chain.

type ManagerOption

type ManagerOption func(*Manager)

ManagerOption configures a Manager during construction.

func WithInboundQueueSize

func WithInboundQueueSize(size int) ManagerOption

WithInboundQueueSize sets the capacity of the inbound message queue. The default is 256. Larger values trade memory for lower drop rate under burst load.

func WithInboundWorkers

func WithInboundWorkers(n int) ManagerOption

WithInboundWorkers sets the number of goroutines that process inbound messages concurrently. The default is 4.

func WithRefreshInterval

func WithRefreshInterval(d time.Duration) ManagerOption

WithRefreshInterval overrides the periodic connection reconcile interval. The default is 5 minutes.

type ManagerStore

type ManagerStore interface {
	ConfigLister
	ConfigResolver
}

ManagerStore is the minimal persistence interface required by Manager.

type Message

type Message struct {
	ID          string         `json:"id,omitempty"`
	Format      MessageFormat  `json:"format,omitempty"`
	Text        string         `json:"text,omitempty"`
	Parts       []MessagePart  `json:"parts,omitempty"`
	Attachments []Attachment   `json:"attachments,omitempty"`
	Actions     []Action       `json:"actions,omitempty"`
	Thread      *ThreadRef     `json:"thread,omitempty"`
	Reply       *ReplyRef      `json:"reply,omitempty"`
	Forward     *ForwardRef    `json:"forward,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
}

Message is the unified message structure used across all channels.

Thread routing should flow through Conversation.ThreadID at the envelope level. Thread remains for API compatibility with existing callers that still attach thread scope to the message body. Forward is populated inbound (Telegram, Misskey) and persisted to history but no adapter Send currently honors it on outbound — explicitly forwarding an existing message requires a dedicated future feature.

func BuildToolApprovalPrompt

func BuildToolApprovalPrompt(req approval.Request) Message

func ResolveMarkdownMessage added in v1.0.0

func ResolveMarkdownMessage(ctx context.Context, store OutboundAttachmentStore, botID string, channelType ChannelType, msg Message) Message

ResolveMarkdownMessage archives the media a message references, for an IM destination. The agent server calls it before handing a message to the Channel process, which may not reach the bot workspace.

func WithoutMarkdownMedia added in v1.0.0

func WithoutMarkdownMedia(msg Message) Message

WithoutMarkdownMedia drops publication metadata a caller supplied itself. Only the agent publishes media, from snapshots it archived; other senders deliver their Markdown as written.

func (Message) IsEmpty

func (m Message) IsEmpty() bool

IsEmpty reports whether the message carries no content.

func (Message) PlainText

func (m Message) PlainText() string

PlainText extracts the plain text representation of the message.

type MessageEditor

type MessageEditor interface {
	Update(ctx context.Context, cfg ChannelConfig, target string, messageID string, msg PreparedMessage) error
	Unsend(ctx context.Context, cfg ChannelConfig, target string, messageID string) error
}

MessageEditor updates and deletes already-sent messages when supported.

type MessageFormat

type MessageFormat string

MessageFormat indicates how the message text should be rendered.

const (
	MessageFormatPlain    MessageFormat = "plain"
	MessageFormatMarkdown MessageFormat = "markdown"
	MessageFormatRich     MessageFormat = "rich"
)

type MessagePart

type MessagePart struct {
	Type              MessagePartType    `json:"type"`
	Text              string             `json:"text,omitempty"`
	URL               string             `json:"url,omitempty"`
	Styles            []MessageTextStyle `json:"styles,omitempty"`
	Language          string             `json:"language,omitempty"`
	ChannelIdentityID string             `json:"channel_identity_id,omitempty"`
	Emoji             string             `json:"emoji,omitempty"`
	Metadata          map[string]any     `json:"metadata,omitempty"`
}

MessagePart is a single element within a rich-text message.

type MessagePartType

type MessagePartType string

MessagePartType identifies the kind of a rich-text message part.

const (
	MessagePartText       MessagePartType = "text"
	MessagePartLink       MessagePartType = "link"
	MessagePartCodeBlock  MessagePartType = "code_block"
	MessagePartMention    MessagePartType = "mention"
	MessagePartEmoji      MessagePartType = "emoji"
	MessagePartHeading    MessagePartType = "heading"
	MessagePartBlockquote MessagePartType = "blockquote"
	MessagePartListItem   MessagePartType = "list_item"
)

type MessageTextStyle

type MessageTextStyle string

MessageTextStyle describes inline formatting for a text part.

const (
	MessageStyleBold          MessageTextStyle = "bold"
	MessageStyleItalic        MessageTextStyle = "italic"
	MessageStyleStrikethrough MessageTextStyle = "strikethrough"
	MessageStyleCode          MessageTextStyle = "code"
	MessageStyleUnderline     MessageTextStyle = "underline"
	MessageStyleSpoiler       MessageTextStyle = "spoiler"
)

type Middleware

type Middleware func(next InboundHandler) InboundHandler

Middleware wraps an InboundHandler to add cross-cutting behavior.

type OutboundAttachmentStore

type OutboundAttachmentStore interface {
	// Stat returns asset metadata by content hash without opening the file.
	Stat(ctx context.Context, botID, contentHash string) (media.Asset, error)
	Open(ctx context.Context, botID, contentHash string) (io.ReadCloser, media.Asset, error)
	Ingest(ctx context.Context, input media.IngestInput) (media.Asset, error)
	GetByStorageKey(ctx context.Context, botID, storageKey string) (media.Asset, error)
	AccessPath(ctx context.Context, asset media.Asset) string
}

OutboundAttachmentStore provides the storage operations required by the outbound attachment preparer.

type OutboundCapabilityResolver

type OutboundCapabilityResolver interface {
	ResolveOutboundCapabilities(cfg ChannelConfig, target string, base ChannelCapabilities) ChannelCapabilities
}

OutboundCapabilityResolver can refine static descriptor capabilities for a specific outbound config and target when platform support is runtime-gated.

type OutboundMessage

type OutboundMessage struct {
	Target  string  `json:"target"`
	Message Message `json:"message"`
}

OutboundMessage pairs a delivery target with the message content.

type OutboundOrder

type OutboundOrder string

OutboundOrder controls the delivery order of text and media messages.

const (
	OutboundOrderMediaFirst OutboundOrder = "media_first"
	OutboundOrderTextFirst  OutboundOrder = "text_first"
)

type OutboundPolicy

type OutboundPolicy struct {
	TextChunkLimit      int           `json:"text_chunk_limit,omitempty"`
	RichTextChunkLimit  int           `json:"rich_text_chunk_limit,omitempty"`
	ChunkerMode         ChunkerMode   `json:"chunker_mode,omitempty"`
	Chunker             Chunker       `json:"-"`
	MediaOrder          OutboundOrder `json:"media_order,omitempty"`
	InlineTextWithMedia bool          `json:"inline_text_with_media,omitempty"`
	RetryMax            int           `json:"retry_max,omitempty"`
	RetryBackoffMs      int           `json:"retry_backoff_ms,omitempty"`
}

OutboundPolicy configures how outbound messages are chunked, ordered, and retried.

func NormalizeOutboundPolicy

func NormalizeOutboundPolicy(policy OutboundPolicy) OutboundPolicy

NormalizeOutboundPolicy fills zero-value fields with sensible defaults.

type OutboundStream

type OutboundStream interface {
	Push(ctx context.Context, event StreamEvent) error
	Close(ctx context.Context) error
}

OutboundStream is a live stream session for emitting outbound events. Implementations are not required to be safe for concurrent use; callers must serialize Push and Close calls within a single goroutine.

func NewTeeStream

func NewTeeStream(primary OutboundStream, observer StreamObserver, botID string, source ChannelType) OutboundStream

NewTeeStream wraps primary so that every Push also notifies observer.

func NewToolCallDroppingStream

func NewToolCallDroppingStream(primary OutboundStream) OutboundStream

NewToolCallDroppingStream wraps primary, replaces non-interactive tool_call_start events with segment_end and drops tool_call_end events. When primary is nil the function returns nil.

type OutboundTargetResolver

type OutboundTargetResolver interface {
	ResolveOutboundTarget(ctx context.Context, cfg ChannelConfig, target string) (string, error)
}

OutboundTargetResolver can resolve delivery aliases to the concrete platform target before outbound capability checks run.

type PreparedAttachment

type PreparedAttachment struct {
	Logical   Attachment
	Kind      PreparedAttachmentKind
	NativeRef string
	PublicURL string
	Name      string
	Mime      string
	Size      int64
	// Open must return a fresh reader each time so retries are safe.
	Open func(ctx context.Context) (io.ReadCloser, error)
}

PreparedAttachment is the adapter-facing attachment model after preparation.

type PreparedAttachmentKind

type PreparedAttachmentKind string

PreparedAttachmentKind identifies how an attachment should be delivered.

const (
	PreparedAttachmentNativeRef PreparedAttachmentKind = "native_ref"
	PreparedAttachmentPublicURL PreparedAttachmentKind = "public_url"
	PreparedAttachmentUpload    PreparedAttachmentKind = "upload"
)

type PreparedMessage

type PreparedMessage struct {
	Message     Message
	Attachments []PreparedAttachment
}

PreparedMessage is the adapter-facing form of a Message.

func (PreparedMessage) LogicalMessage

func (m PreparedMessage) LogicalMessage() Message

LogicalMessage converts the prepared message back to the logical channel message.

type PreparedOutboundMessage

type PreparedOutboundMessage struct {
	Target  string
	Message PreparedMessage
}

PreparedOutboundMessage is the adapter-facing form of OutboundMessage.

func PrepareOutboundMessage

func PrepareOutboundMessage(
	ctx context.Context,
	store OutboundAttachmentStore,
	cfg ChannelConfig,
	msg OutboundMessage,
) (PreparedOutboundMessage, error)

PrepareOutboundMessage resolves the logical outbound message into the adapter-facing prepared model.

func (PreparedOutboundMessage) LogicalMessage

func (m PreparedOutboundMessage) LogicalMessage() OutboundMessage

LogicalMessage converts the prepared outbound message back to the logical model.

type PreparedOutboundStream

type PreparedOutboundStream interface {
	Push(ctx context.Context, event PreparedStreamEvent) error
	Close(ctx context.Context) error
}

PreparedOutboundStream is the adapter-facing stream session.

type PreparedOutboundValidator

type PreparedOutboundValidator interface {
	ValidatePreparedOutbound(ctx context.Context, cfg ChannelConfig, target string, msg PreparedOutboundMessage) error
}

PreparedOutboundValidator lets adapters reject platform-invalid prepared messages before a batched/chunked send starts delivering earlier items.

type PreparedStreamEvent

type PreparedStreamEvent struct {
	Type        StreamEventType
	Status      StreamStatus
	Delta       string
	Final       *PreparedStreamFinalizePayload
	Error       string
	ErrorCode   string
	ToolCall    *StreamToolCall
	Phase       StreamPhase
	Attachments []PreparedAttachment
	Reactions   []ReactRequest
	Speeches    []SpeechRequest
	Metadata    map[string]any
}

PreparedStreamEvent is the adapter-facing form of StreamEvent.

func PrepareStreamEvent

func PrepareStreamEvent(
	ctx context.Context,
	store OutboundAttachmentStore,
	cfg ChannelConfig,
	event StreamEvent,
) (PreparedStreamEvent, error)

PrepareStreamEvent resolves logical stream payloads before they enter an adapter.

func (PreparedStreamEvent) LogicalEvent

func (e PreparedStreamEvent) LogicalEvent() StreamEvent

LogicalEvent converts the prepared stream event back to the logical model.

type PreparedStreamFinalizePayload

type PreparedStreamFinalizePayload struct {
	Message PreparedMessage
}

PreparedStreamFinalizePayload is the adapter-facing stream final payload.

type ProcessingStatus added in v0.22.0

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

ProcessingStatus drives the platform processing indicator for one turn: Started once, Refresh on the notifier's interval while the turn runs, then exactly one of Completed or Failed. Every call is best-effort; failures go to the error func and never fail the turn. A nil notifier yields an inert session, so callers need no nil checks.

func StartProcessingStatus added in v0.22.0

StartProcessingStatus reports Started and, when the notifier implements ProcessingStatusRefresher, keeps the indicator alive until StopRefresh, Complete or Fail. ctx scopes Started and the refreshes, and its cancellation ends refreshing.

func (*ProcessingStatus) Complete added in v0.22.0

func (s *ProcessingStatus) Complete(ctx context.Context)

Complete stops refreshing and reports Completed. Only the first Complete or Fail reports; later calls are no-ops.

func (*ProcessingStatus) Fail added in v0.22.0

func (s *ProcessingStatus) Fail(ctx context.Context, cause error)

Fail stops refreshing and reports Failed with cause. Only the first Complete or Fail reports; later calls are no-ops.

func (*ProcessingStatus) PauseRefresh added in v0.22.0

func (s *ProcessingStatus) PauseRefresh()

PauseRefresh holds the indicator while the turn waits on the user, such as a pending tool approval or ask_user question; the platform indicator then lapses on its own. ResumeRefresh re-sends it at once and restarts the interval.

func (*ProcessingStatus) ResumeRefresh added in v0.22.0

func (s *ProcessingStatus) ResumeRefresh()

ResumeRefresh undoes PauseRefresh. It is cheap to call when not paused.

func (*ProcessingStatus) StopRefresh added in v0.22.0

func (s *ProcessingStatus) StopRefresh()

StopRefresh ends refreshing and returns only after an in-flight refresh has returned, so no indicator is sent after the caller delivers its reply. An in-flight refresh is waited for rather than canceled: canceling a request already on the wire does not stop the platform from applying it.

type ProcessingStatusErrorFunc added in v0.22.0

type ProcessingStatusErrorFunc func(ctx context.Context, stage string, err error)

ProcessingStatusErrorFunc receives the best-effort failures of a ProcessingStatus, keyed by one of the ProcessingStage constants.

type ProcessingStatusHandle

type ProcessingStatusHandle struct {
	Token string
}

ProcessingStatusHandle stores channel-specific state between status callbacks.

type ProcessingStatusInfo

type ProcessingStatusInfo struct {
	BotID             string
	ChatID            string
	RouteID           string
	ChannelIdentityID string
	UserID            string
	Query             string
	ReplyTarget       string
	SourceMessageID   string
}

ProcessingStatusInfo carries context for channel-level processing status updates.

type ProcessingStatusNotifier

type ProcessingStatusNotifier interface {
	ProcessingStarted(ctx context.Context, cfg ChannelConfig, msg InboundMessage, info ProcessingStatusInfo) (ProcessingStatusHandle, error)
	ProcessingCompleted(ctx context.Context, cfg ChannelConfig, msg InboundMessage, info ProcessingStatusInfo, handle ProcessingStatusHandle) error
	ProcessingFailed(ctx context.Context, cfg ChannelConfig, msg InboundMessage, info ProcessingStatusInfo, handle ProcessingStatusHandle, cause error) error
}

ProcessingStatusNotifier reports processing lifecycle updates to channel platforms. Implementations should be best-effort and idempotent.

type ProcessingStatusRefresher added in v0.22.0

type ProcessingStatusRefresher interface {
	// ProcessingRefreshInterval is how often the indicator is re-sent. A
	// non-positive interval disables refreshing.
	ProcessingRefreshInterval() time.Duration
	ProcessingRefresh(ctx context.Context, cfg ChannelConfig, msg InboundMessage, info ProcessingStatusInfo, handle ProcessingStatusHandle) error
}

ProcessingStatusRefresher is implemented by notifiers whose platform indicator expires and must be re-sent while processing continues, such as the Telegram and Discord typing actions.

type ReactRequest

type ReactRequest struct {
	Target    string `json:"target"`
	MessageID string `json:"message_id"`
	Emoji     string `json:"emoji"`
	Remove    bool   `json:"remove,omitempty"`
}

ReactRequest is the input for adding or removing an emoji reaction on a message.

type Reactor

type Reactor interface {
	React(ctx context.Context, cfg ChannelConfig, target string, messageID string, emoji string) error
	Unreact(ctx context.Context, cfg ChannelConfig, target string, messageID string, emoji string) error
}

Reactor adds or removes emoji reactions on messages.

type Receiver

type Receiver interface {
	Connect(ctx context.Context, cfg ChannelConfig, handler InboundHandler) (Connection, error)
}

Receiver is an adapter capable of establishing a long-lived connection to receive messages.

type Registry

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

Registry holds all registered channel adapters and provides dispatch methods for configuration normalization, target resolution, and binding operations. It replaces the former global registry, and must be created via NewRegistry and passed explicitly to components that need it.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty Registry.

func (*Registry) BuildUserBindingConfig

func (r *Registry) BuildUserBindingConfig(channelType ChannelType, identity Identity) map[string]any

BuildUserBindingConfig constructs a user-channel binding config from an Identity.

func (*Registry) DirectoryAdapter

func (r *Registry) DirectoryAdapter(channelType ChannelType) (ChannelDirectoryAdapter, bool)

DirectoryAdapter returns the directory adapter for the given channel type if it implements ChannelDirectoryAdapter.

func (*Registry) DiscoverSelf

func (r *Registry) DiscoverSelf(ctx context.Context, channelType ChannelType, credentials map[string]any) (map[string]any, string, error)

DiscoverSelf calls the SelfDiscoverer for the given channel type if supported.

func (*Registry) Get

func (r *Registry) Get(channelType ChannelType) (Adapter, bool)

Get returns the adapter for the given channel type.

func (*Registry) GetAttachmentResolver

func (r *Registry) GetAttachmentResolver(channelType ChannelType) (AttachmentResolver, bool)

GetAttachmentResolver returns the AttachmentResolver for the given channel type, or nil if unsupported.

func (*Registry) GetCapabilities

func (r *Registry) GetCapabilities(channelType ChannelType) (ChannelCapabilities, bool)

GetCapabilities returns the capability matrix for the given channel type.

func (*Registry) GetConfigSchema

func (r *Registry) GetConfigSchema(channelType ChannelType) (ConfigSchema, bool)

GetConfigSchema returns the configuration schema for the given channel type.

func (*Registry) GetDescriptor

func (r *Registry) GetDescriptor(channelType ChannelType) (Descriptor, bool)

GetDescriptor returns the descriptor for the given channel type.

func (*Registry) GetMessageEditor

func (r *Registry) GetMessageEditor(channelType ChannelType) (MessageEditor, bool)

GetMessageEditor returns the MessageEditor for the given channel type, or nil if unsupported.

func (*Registry) GetOutboundCapabilities

func (r *Registry) GetOutboundCapabilities(channelType ChannelType, cfg ChannelConfig, target string) (ChannelCapabilities, bool)

GetOutboundCapabilities returns capabilities refined for one outbound target.

func (*Registry) GetOutboundPolicy

func (r *Registry) GetOutboundPolicy(channelType ChannelType) (OutboundPolicy, bool)

GetOutboundPolicy returns the outbound policy for the given channel type.

func (*Registry) GetProcessingStatusNotifier

func (r *Registry) GetProcessingStatusNotifier(channelType ChannelType) (ProcessingStatusNotifier, bool)

GetProcessingStatusNotifier returns the ProcessingStatusNotifier for the given channel type, or nil if unsupported.

func (*Registry) GetReactor

func (r *Registry) GetReactor(channelType ChannelType) (Reactor, bool)

GetReactor returns the Reactor for the given channel type, or nil if unsupported.

func (*Registry) GetReceiver

func (r *Registry) GetReceiver(channelType ChannelType) (Receiver, bool)

GetReceiver returns the Receiver for the given channel type, or nil if unsupported.

func (*Registry) GetSender

func (r *Registry) GetSender(channelType ChannelType) (Sender, bool)

GetSender returns the Sender for the given channel type, or nil if unsupported.

func (*Registry) GetStreamSender

func (r *Registry) GetStreamSender(channelType ChannelType) (StreamSender, bool)

GetStreamSender returns the StreamSender for the given channel type, or nil if unsupported.

func (*Registry) GetUserConfigSchema

func (r *Registry) GetUserConfigSchema(channelType ChannelType) (ConfigSchema, bool)

GetUserConfigSchema returns the user-binding configuration schema.

func (*Registry) GetWebhookEndpointSetter

func (r *Registry) GetWebhookEndpointSetter(channelType ChannelType) (WebhookEndpointSetter, bool)

GetWebhookEndpointSetter returns the platform webhook endpoint setter for the given channel.

func (*Registry) GetWebhookReceiver

func (r *Registry) GetWebhookReceiver(channelType ChannelType) (WebhookReceiver, bool)

GetWebhookReceiver returns the WebhookReceiver for the given channel type, or nil if unsupported.

func (*Registry) IsConfigless

func (r *Registry) IsConfigless(channelType ChannelType) bool

IsConfigless reports whether the channel type operates without per-bot configuration.

func (*Registry) IsOwnerOnly added in v0.21.0

func (r *Registry) IsOwnerOnly(channelType ChannelType) bool

IsOwnerOnly reports whether the given channel type is owner-only: no third party can ever become a sender there (see Descriptor.OwnerOnly).

func (*Registry) List

func (r *Registry) List() []Adapter

List returns all registered adapters.

func (*Registry) ListDescriptors

func (r *Registry) ListDescriptors() []Descriptor

ListDescriptors returns descriptors for all registered channel types.

func (*Registry) MatchUserBinding

func (r *Registry) MatchUserBinding(channelType ChannelType, config map[string]any, criteria BindingCriteria) bool

MatchUserBinding reports whether the given binding config matches the criteria.

func (*Registry) MustRegister

func (r *Registry) MustRegister(adapter Adapter)

MustRegister calls Register and panics on error.

func (*Registry) NormalizeConfig

func (r *Registry) NormalizeConfig(channelType ChannelType, raw map[string]any) (map[string]any, error)

NormalizeConfig validates and normalizes a channel configuration map.

func (*Registry) NormalizeTarget

func (r *Registry) NormalizeTarget(channelType ChannelType, raw string) (string, bool)

NormalizeTarget applies the channel-specific target normalization.

func (*Registry) NormalizeUserConfig

func (r *Registry) NormalizeUserConfig(channelType ChannelType, raw map[string]any) (map[string]any, error)

NormalizeUserConfig validates and normalizes a user-channel binding configuration.

func (*Registry) ParseChannelType

func (r *Registry) ParseChannelType(raw string) (ChannelType, error)

ParseChannelType validates and normalizes a raw string into a registered ChannelType.

func (*Registry) Register

func (r *Registry) Register(adapter Adapter) error

Register adds an adapter to the registry.

func (*Registry) ResolveOutboundTarget

func (r *Registry) ResolveOutboundTarget(ctx context.Context, channelType ChannelType, cfg ChannelConfig, target string) (string, bool, error)

ResolveOutboundTarget resolves runtime delivery aliases before outbound capability checks and adapter dispatch.

func (*Registry) ResolveTargetFromUserConfig

func (r *Registry) ResolveTargetFromUserConfig(channelType ChannelType, config map[string]any) (string, error)

ResolveTargetFromUserConfig derives a delivery target from a user-channel binding.

func (*Registry) SelfIdentityPolicy

func (r *Registry) SelfIdentityPolicy(channelType ChannelType) SelfIdentityPolicy

SelfIdentityPolicy returns adapter-specific persistence requirements for discovered platform bot identity. Most adapters use the zero-value best-effort policy; webhook adapters that cannot route safely without self identity can opt into stricter enable-time validation.

func (*Registry) Types

func (r *Registry) Types() []ChannelType

Types returns all registered channel types.

func (*Registry) Unregister

func (r *Registry) Unregister(channelType ChannelType) bool

Unregister removes a channel type from the registry.

type ReplyRef

type ReplyRef struct {
	Target           string       `json:"target,omitempty"`
	MessageID        string       `json:"message_id,omitempty"`
	Sender           string       `json:"sender,omitempty"`
	Preview          string       `json:"preview,omitempty"`
	Attachments      []Attachment `json:"attachments,omitempty"`
	AttachmentsKnown bool         `json:"attachments_known,omitempty"`
}

ReplyRef points to a message being replied to.

type Runtime

Runtime is the live Channel-process surface consumed by the Server. The in-process implementation is composed from Lifecycle, Store, and Manager; production Server wiring uses the authenticated RPC implementation.

type SelfDiscoverer

type SelfDiscoverer interface {
	DiscoverSelf(ctx context.Context, credentials map[string]any) (identity map[string]any, externalID string, err error)
}

SelfDiscoverer retrieves the adapter bot's own identity from the platform. The returned map is merged into ChannelConfig.SelfIdentity and persisted.

type SelfIdentityPolicy

type SelfIdentityPolicy struct {
	RefreshOnCredentialsChange       bool
	RequireDiscoveryOnEnable         bool
	RequiredSelfIdentityKey          string
	DiscoveryErrorMessage            string
	MissingIdentityMessage           string
	DuplicateExternalIdentityMessage string
}

SelfIdentityPolicy describes adapter-specific requirements for persisting a platform bot identity discovered from credentials.

type SelfIdentityPolicyProvider

type SelfIdentityPolicyProvider interface {
	SelfIdentityPolicy() SelfIdentityPolicy
}

SelfIdentityPolicyProvider lets adapters opt into stricter self-identity discovery semantics than the default best-effort behavior.

type SendRequest

type SendRequest struct {
	// ExcludedTarget is checked after platform target resolution, before publication.
	ExcludedTarget    string  `json:"excluded_target,omitempty"`
	Target            string  `json:"target,omitempty"`
	ChannelIdentityID string  `json:"channel_identity_id,omitempty"`
	Message           Message `json:"message"`
}

SendRequest is the input for sending an outbound message through a channel.

type Sender

type Sender interface {
	Send(ctx context.Context, cfg ChannelConfig, msg PreparedOutboundMessage) error
}

Sender is an adapter capable of sending outbound messages.

type SetWebhookEndpointRequest

type SetWebhookEndpointRequest struct {
	Endpoint string `json:"endpoint"`
}

type SetWebhookEndpointResponse

type SetWebhookEndpointResponse struct {
	Endpoint string `json:"endpoint"`
}

type SpeechRequest

type SpeechRequest struct {
	Text string `json:"text"`
}

SpeechRequest carries text-to-speech synthesis text from a speech_delta stream event.

type Store

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

Store provides CRUD operations for channel configurations, user bindings, and sessions.

func NewStore

func NewStore(queries dbstore.Queries, registry *Registry) *Store

NewStore creates a Store backed by the given database queries and adapter registry.

func (*Store) DeleteConfig

func (s *Store) DeleteConfig(ctx context.Context, botID string, channelType ChannelType) error

DeleteConfig removes a bot's channel configuration.

func (*Store) GetChannelIdentityConfig

func (s *Store) GetChannelIdentityConfig(ctx context.Context, channelIdentityID string, channelType ChannelType) (ChannelIdentityBinding, error)

GetChannelIdentityConfig returns the channel identity's channel binding for the given channel type.

func (*Store) ListBotConfigs

func (s *Store) ListBotConfigs(ctx context.Context, botID string) ([]ChannelConfig, error)

ListBotConfigs returns all registered channel configs for a bot. Missing configs are skipped so callers can enumerate platform state without knowing which integrations are currently configured.

func (*Store) ListChannelIdentityConfigsByType

func (s *Store) ListChannelIdentityConfigsByType(ctx context.Context, channelType ChannelType) ([]ChannelIdentityBinding, error)

ListChannelIdentityConfigsByType returns all channel identity bindings for the given channel type.

func (*Store) ListConfigs

func (s *Store) ListConfigs(ctx context.Context, botID string) ([]ChannelConfig, error)

ListConfigs returns all persisted channel configurations for a bot.

func (*Store) ListConfigsByType

func (s *Store) ListConfigsByType(ctx context.Context, channelType ChannelType) ([]ChannelConfig, error)

ListConfigsByType returns all channel configurations of the given type.

func (*Store) ResolveChannelIdentityBinding

func (s *Store) ResolveChannelIdentityBinding(ctx context.Context, channelType ChannelType, criteria BindingCriteria) (string, error)

ResolveChannelIdentityBinding finds the channel identity ID whose channel binding matches the given criteria.

func (*Store) ResolveEffectiveConfig

func (s *Store) ResolveEffectiveConfig(ctx context.Context, botID string, channelType ChannelType) (ChannelConfig, error)

ResolveEffectiveConfig returns the active channel configuration for a bot. For configless channel types, a synthetic config is returned.

func (*Store) SaveMatrixSyncSinceToken

func (s *Store) SaveMatrixSyncSinceToken(ctx context.Context, configID string, since string) error

SaveMatrixSyncSinceToken persists the Matrix /sync cursor without mutating channel config updated_at.

func (*Store) SetWebhookEndpoint

func (s *Store) SetWebhookEndpoint(ctx context.Context, botID string, channelType ChannelType, req SetWebhookEndpointRequest) (SetWebhookEndpointResponse, error)

func (*Store) UpdateConfigDisabled

func (s *Store) UpdateConfigDisabled(ctx context.Context, botID string, channelType ChannelType, disabled bool) (ChannelConfig, error)

UpdateConfigDisabled updates only the disabled flag for a bot channel config and returns latest config.

func (*Store) UpsertChannelIdentityConfig

func (s *Store) UpsertChannelIdentityConfig(ctx context.Context, channelIdentityID string, channelType ChannelType, req UpsertChannelIdentityConfigRequest) (ChannelIdentityBinding, error)

UpsertChannelIdentityConfig creates or updates a channel identity's channel binding.

func (*Store) UpsertConfig

func (s *Store) UpsertConfig(ctx context.Context, botID string, channelType ChannelType, req UpsertConfigRequest) (ChannelConfig, error)

UpsertConfig creates or updates a bot's channel configuration.

type StreamEvent

type StreamEvent struct {
	Type        StreamEventType        `json:"type"`
	Status      StreamStatus           `json:"status,omitempty"`
	Delta       string                 `json:"delta,omitempty"`
	Final       *StreamFinalizePayload `json:"final,omitempty"`
	Error       string                 `json:"error,omitempty"`
	ErrorCode   string                 `json:"error_code,omitempty"`
	ToolCall    *StreamToolCall        `json:"tool_call,omitempty"`
	Phase       StreamPhase            `json:"phase,omitempty"`
	Attachments []Attachment           `json:"attachments,omitempty"`
	Reactions   []ReactRequest         `json:"reactions,omitempty"`
	Speeches    []SpeechRequest        `json:"speeches,omitempty"`
	Metadata    map[string]any         `json:"metadata,omitempty"`
}

StreamEvent represents a unified stream event routed through the channel layer. ErrorCode names the catalog code Error was rendered from: with a code, Error is complete user-facing copy; without one it is a bare error text.

func CodeEvent added in v0.22.0

func CodeEvent(t *i18n.Localizer, code apperror.Code, args map[string]string) StreamEvent

CodeEvent is the stream error for a code that was recorded rather than returned: the code a failed run stored, or the code of a history event. It carries the copy for code, or the copy for runtime_run_failed when code is not in the catalog, so the text is always catalog copy and never an error's own text.

func ErrorEvent added in v0.21.0

func ErrorEvent(ctx context.Context, t *i18n.Localizer, err error) (StreamEvent, bool)

ErrorEvent is the stream error a channel shows for err, answered by errs.Answer as an HTTP response would be: the copy for the public error, carrying its code. The error's own text is never shown; the unit's result record reports it. It reports false when the caller has canceled, which is not answered.

type StreamEventType

type StreamEventType string

StreamEventType defines the kind of outbound stream event.

const (
	StreamEventStatus              StreamEventType = "status"
	StreamEventDelta               StreamEventType = "delta"
	StreamEventFinal               StreamEventType = "final"
	StreamEventError               StreamEventType = "error"
	StreamEventToolCallStart       StreamEventType = "tool_call_start"
	StreamEventToolCallEnd         StreamEventType = "tool_call_end"
	StreamEventPhaseStart          StreamEventType = "phase_start"
	StreamEventPhaseEnd            StreamEventType = "phase_end"
	StreamEventAttachment          StreamEventType = "attachment"
	StreamEventAgentStart          StreamEventType = "agent_start"
	StreamEventAgentEnd            StreamEventType = "agent_end"
	StreamEventReaction            StreamEventType = "reaction"
	StreamEventSpeech              StreamEventType = "speech"
	StreamEventProcessingStarted   StreamEventType = "processing_started"
	StreamEventProcessingCompleted StreamEventType = "processing_completed"
	// StreamEventReset discards the reply text streamed so far: the agent is
	// retrying and regenerates it from scratch, so the next delta starts a
	// fresh reply instead of extending the failed attempt's partial output.
	StreamEventReset StreamEventType = "reset"
	// StreamEventSegmentEnd marks that the current assistant text segment
	// ended at a tool call hidden from this channel. Adapters commit the
	// buffered text as its own message and reset per-message streaming
	// state, without rendering any tool-call UI, so the text that follows
	// the tool call starts a fresh message.
	StreamEventSegmentEnd StreamEventType = "segment_end"
)

type StreamFinalizePayload

type StreamFinalizePayload struct {
	Message Message `json:"message"`
}

StreamFinalizePayload carries the final reply message emitted by a stream.

type StreamObserver

type StreamObserver interface {
	// OnStreamEvent is called for every event pushed to an outbound stream.
	// botID identifies the bot that owns the conversation.
	// source is the channel type that originated the event (e.g. "telegram").
	OnStreamEvent(ctx context.Context, botID string, source ChannelType, event StreamEvent)
}

StreamObserver receives copies of stream events for cross-channel broadcasting or external notification (e.g. webhooks). Implementations must be safe for concurrent use and should not block.

type StreamOptions

type StreamOptions struct {
	Reply           *ReplyRef      `json:"reply,omitempty"`
	SourceMessageID string         `json:"source_message_id,omitempty"`
	Metadata        map[string]any `json:"metadata,omitempty"`
}

StreamOptions configures how an outbound stream is initialized.

type StreamPhase

type StreamPhase string

StreamPhase labels a processing stage within a stream (e.g., reasoning, text).

const (
	StreamPhaseReasoning StreamPhase = "reasoning"
	StreamPhaseText      StreamPhase = "text"
)

type StreamReplySender

type StreamReplySender interface {
	Send(ctx context.Context, msg OutboundMessage) error
	OpenStream(ctx context.Context, target string, opts StreamOptions) (OutboundStream, error)
}

StreamReplySender sends replies within a single inbound-processing scope. It supports both one-shot delivery and streaming sessions.

type StreamSender

type StreamSender interface {
	OpenStream(ctx context.Context, cfg ChannelConfig, target string, opts StreamOptions) (PreparedOutboundStream, error)
}

StreamSender is an adapter capable of opening outbound stream sessions.

type StreamStatus

type StreamStatus string

StreamStatus indicates the lifecycle state of a streaming reply.

const (
	StreamStatusStarted   StreamStatus = "started"
	StreamStatusCompleted StreamStatus = "completed"
	StreamStatusFailed    StreamStatus = "failed"
)

type StreamToolCall

type StreamToolCall struct {
	Name       string   `json:"name"`
	CallID     string   `json:"call_id,omitempty"`
	Locale     string   `json:"locale,omitempty"`
	Input      any      `json:"input,omitempty"`
	Result     any      `json:"result,omitempty"`
	ApprovalID string   `json:"approval_id,omitempty"`
	ShortID    int      `json:"short_id,omitempty"`
	Actions    []Action `json:"actions,omitempty"`
}

StreamToolCall carries tool invocation data for tool_call_start / tool_call_end events.

type TargetHint

type TargetHint struct {
	Example string `json:"example,omitempty"`
	Label   string `json:"label,omitempty"`
}

TargetHint provides a display label and example for a target format.

type TargetResolver

type TargetResolver interface {
	NormalizeTarget(raw string) string
	ResolveTarget(userConfig map[string]any) (string, error)
}

TargetResolver handles delivery target normalization and resolution from user bindings.

type TargetSpec

type TargetSpec struct {
	Format string       `json:"format"`
	Hints  []TargetHint `json:"hints,omitempty"`
}

TargetSpec describes the expected format of a delivery target for a channel type.

type ThreadRef

type ThreadRef struct {
	ID string `json:"id"`
}

ThreadRef references a conversation thread by ID.

type ToolCallBlock

type ToolCallBlock struct {
	Type  ToolCallBlockType
	Title string
	URL   string
	Desc  string
	Text  string
}

ToolCallBlock is one rich element inside ToolCallPresentation.Body. Fields not applicable to the Type are ignored.

type ToolCallBlockType

type ToolCallBlockType string

ToolCallBlockType distinguishes body block rendering semantics.

const (
	ToolCallBlockText ToolCallBlockType = "text" // free-form line or paragraph
	ToolCallBlockLink ToolCallBlockType = "link" // titled hyperlink, optional description
	ToolCallBlockCode ToolCallBlockType = "code" // preformatted / code block
)

type ToolCallPresentation

type ToolCallPresentation struct {
	Emoji    string
	ToolName string
	Status   ToolCallStatus
	// HideToolHeader is for user-facing interactions whose implementation as
	// a tool is not meaningful to the recipient, such as ask_user prompts.
	HideToolHeader bool

	Header string
	Body   []ToolCallBlock
	Footer string

	InputSummary  string
	ResultSummary string
}

ToolCallPresentation is the rendered single-message view of one tool call state. Adapters call RenderToolCallMessage (or their own renderer) against this struct to produce the final IM text body.

The preferred fields are Header / Body / Footer, populated either by per-tool formatters (see toolcall_formatters.go) or by the generic builder. InputSummary / ResultSummary are retained so existing callers that expect two flat strings keep working.

func BuildToolCallEnd

func BuildToolCallEnd(tc *StreamToolCall) ToolCallPresentation

BuildToolCallEnd builds a presentation for a tool_call_end event. The completed / failed status is inferred from the tool result payload (ok=false, error fields, non-zero exit codes, etc.).

func BuildToolCallStart

func BuildToolCallStart(tc *StreamToolCall) ToolCallPresentation

BuildToolCallStart builds a presentation for a tool_call_start event. Returns a zero-value presentation when the payload is nil.

type ToolCallStatus

type ToolCallStatus string

ToolCallStatus is the lifecycle state of a single tool call as surfaced in IM.

const (
	ToolCallStatusRunning          ToolCallStatus = "running"
	ToolCallStatusWaiting          ToolCallStatus = "waiting"
	ToolCallStatusApprovalRequired ToolCallStatus = "approval_required"
	ToolCallStatusCompleted        ToolCallStatus = "completed"
	ToolCallStatusFailed           ToolCallStatus = "failed"
)

type UpdateChannelStatusRequest

type UpdateChannelStatusRequest struct {
	Disabled bool `json:"disabled"`
}

UpdateChannelStatusRequest is the input for enabling/disabling a bot channel config.

type UpsertChannelIdentityConfigRequest

type UpsertChannelIdentityConfigRequest struct {
	Config map[string]any `json:"config"`
}

UpsertChannelIdentityConfigRequest is the input for creating or updating a channel-identity binding.

type UpsertConfigRequest

type UpsertConfigRequest struct {
	Credentials      map[string]any `json:"credentials"`
	ExternalIdentity string         `json:"external_identity,omitempty"`
	SelfIdentity     map[string]any `json:"self_identity,omitempty"`
	Routing          map[string]any `json:"routing,omitempty"`
	Disabled         *bool          `json:"disabled,omitempty"`
	VerifiedAt       *time.Time     `json:"verified_at,omitempty"`
}

UpsertConfigRequest is the input for creating or updating a channel configuration. Disabled: true to stop the channel, false to enable it. Omitted is treated as false (enabled).

type WebhookEndpointSetter

type WebhookEndpointSetter interface {
	SetWebhookEndpoint(ctx context.Context, credentials map[string]any, endpoint string) error
}

WebhookEndpointSetter updates the platform-side webhook endpoint.

type WebhookHandler

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

WebhookHandler dispatches public webhook callbacks to channel adapters.

func NewWebhookServerHandler

func NewWebhookServerHandler(log *slog.Logger, store *Store, manager *Manager) *WebhookHandler

NewWebhookServerHandler creates the generic channel webhook handler.

func (*WebhookHandler) Handle

func (h *WebhookHandler) Handle(c echo.Context) error

Handle resolves the channel config and delegates the request to the adapter.

func (*WebhookHandler) Register

func (h *WebhookHandler) Register(e *echo.Echo)

Register registers generic channel webhook routes.

type WebhookReceiver

type WebhookReceiver interface {
	HandleWebhook(ctx context.Context, cfg ChannelConfig, handler InboundHandler, r *http.Request, w http.ResponseWriter) error
}

WebhookReceiver handles inbound HTTP webhook callbacks for webhook-style channels. Implementations typically verify the request, parse the platform payload, and forward resulting inbound messages to the provided handler.

Directories

Path Synopsis
adapters
dingtalk
Package dingtalk implements the DingTalk channel adapter.
Package dingtalk implements the DingTalk channel adapter.
feishu
Package feishu implements the Feishu (Lark) channel adapter.
Package feishu implements the Feishu (Lark) channel adapter.
feishu/wsclient
Package wsclient is a Feishu/Lark long-connection websocket client.
Package wsclient is a Feishu/Lark long-connection websocket client.
local
Package local implements the CLI and Web channel adapters for local development.
Package local implements the CLI and Web channel adapters for local development.
misskey
Package misskey implements the Misskey channel adapter.
Package misskey implements the Misskey channel adapter.
qq
telegram
Package telegram implements the Telegram channel adapter.
Package telegram implements the Telegram channel adapter.
Package common provides shared utilities for channel adapters.
Package common provides shared utilities for channel adapters.
Package partsfixture exposes the canonical Message.Parts fixture used by the cross-platform rendering regression tests.
Package partsfixture exposes the canonical Message.Parts fixture used by the cross-platform rendering regression tests.
Package publicmedia defines signed public image media paths shared by channel adapters and HTTP handlers.
Package publicmedia defines signed public image media paths shared by channel adapters and HTTP handlers.

Jump to

Keyboard shortcuts

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