im

package
v1.3.35 Latest Latest
Warning

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

Go to latest
Published: May 25, 2026 License: MIT Imports: 75 Imported by: 0

Documentation

Overview

Package im contains the Feishu adapter.

Feishu Developer Console Setup

To enable interactive card callbacks (e.g. ask_user buttons), the following must be configured in the Feishu Developer Console (开发者后台):

  1. Under "Events & Callbacks" (事件与回调), set the connection mode to "Long Connection / WebSocket" (长连接).

  2. Under "Events & Callbacks" → "Callback Configuration" (回调配置), add the callback: card.action.trigger (卡片回传交互回调).

    IMPORTANT: This is in the "Callback Configuration" (回调配置) section, NOT in "Event Subscription" (事件订阅). Card callbacks and event subscriptions are separate sections. Without this step, card buttons will render but clicking them will produce error 200340 (card callback not configured).

The adapter uses the official Feishu Go SDK's larkws.NewClient for the WebSocket connection, which registers the callback capability with the Feishu platform so card.action.trigger events are delivered over the long connection.

Index

Constants

View Source
const PCInviteURIPrefix = "privateclaw://connect?payload="
View Source
const WechatDefaultOutputMode = "summary"

WechatDefaultOutputMode is the recommended output mode for WeChat IM channels. WeChat iLink passive reply has a ~5 second context_token expiry and a 5-message limit per inbound. Summary mode ensures only one combined reply is sent.

Variables

View Source
var (
	ErrNoSessionBound       = errors.New("no active session bound")
	ErrNoChannelBound       = errors.New("no channel bound for active workspace")
	ErrNoBridge             = errors.New("no IM bridge configured")
	ErrApprovalNotFound     = errors.New("approval not found")
	ErrAdapterAlreadyBound  = errors.New("adapter already bound to another workspace")
	ErrInboundChannelDenied = errors.New("inbound message does not match active binding")
	ErrNoPendingPairing     = errors.New("no pending pairing challenge")
)
View Source
var PlatformLimits = map[Platform]int{
	PlatformDiscord:  2000,
	PlatformSlack:    4000,
	PlatformDingTalk: 4000,
	PlatformTelegram: 4096,
	PlatformQQ:       3000,
	PlatformFeishu:   4000,
	PlatformDummy:    50000,
}

PlatformLimits defines the maximum message length for each IM platform. These limits are based on official API documentation as of 2025.

Functions

func BuildAskUserResponse added in v1.1.34

func BuildAskUserResponse(req toolpkg.AskUserRequest, parsed []ParsedQuestionAnswer) toolpkg.AskUserResponse

BuildAskUserResponse builds an AskUserResponse from parsed per-question answers. This is the shared implementation used by daemon (and can be used by TUI).

func CheckSignalDaemon added in v1.1.87

func CheckSignalDaemon(baseURL string) error

CheckSignalDaemon pings the signal-cli REST API at the given baseURL to check if the daemon is running. Returns nil if reachable.

func DefaultBindingsPath

func DefaultBindingsPath() (string, error)

func DefaultPCSessionStorePath added in v1.1.34

func DefaultPCSessionStorePath() (string, error)

func DefaultPairingStatePath

func DefaultPairingStatePath() (string, error)

func EscapeMarkdownV2 added in v1.1.34

func EscapeMarkdownV2(text string) string

EscapeMarkdownV2 converts plain or markdown text to Telegram MarkdownV2 safe text.

It preserves markdown formatting structures (bold, italic, strikethrough, code, code blocks, links, images) while escaping all other MarkdownV2 special characters.

func FetchSignalQRCode added in v1.1.87

func FetchSignalQRCode(baseURL, deviceName string) ([]byte, error)

FetchSignalQRCode fetches the QR code PNG from signal-cli-rest-api for device linking. Returns the raw PNG bytes.

func FormatAskUserPrompt added in v1.1.34

func FormatAskUserPrompt(lang string, req toolpkg.AskUserRequest) string

FormatAskUserPrompt formats an AskUserRequest into an IM-friendly prompt with per-question-type reply guidance. Shared by TUI and daemon modes.

func FormatIMStatus added in v1.1.34

func FormatIMStatus(lang ToolLanguage, activity, toolName, toolArg string) string

FormatIMStatus produces the final status string for IM delivery, mirroring the TUI's formatIMStatus pipeline:

describeTool → formatToolInline → localizeIMProgress

func FormatToolInline added in v1.1.34

func FormatToolInline(name, detail string) string

FormatToolInline formats a tool name and detail as an inline status string, e.g. "读 chart.html" or just "编辑" if detail is trivial.

func HasWechatAdapter added in v1.1.82

func HasWechatAdapter(mgr *Manager) bool

HasWechatAdapter returns true if the manager has any active WeChat adapter.

func IsLocalFilePath added in v1.1.34

func IsLocalFilePath(s string) bool

IsLocalFilePath checks if a string looks like a local file path.

func LastMessageID added in v1.1.34

func LastMessageID(b ChannelBinding) string

LastMessageID returns the most recent message ID for typing reaction targeting: prefers the bot's last outbound message so reactions stay near current progress, and falls back to the user's inbound message when no outbound message exists yet.

func LocalizeIMProgress added in v1.1.34

func LocalizeIMProgress(lang ToolLanguage, text string) string

LocalizeIMProgress applies language-specific localization to an IM progress string, mirroring the TUI's localizeIMProgress function.

func PCEncodeInviteToURI added in v1.1.34

func PCEncodeInviteToURI(invite PCInvite) (string, error)

PCEncodeInviteToURI encodes an invite into a privateclaw:// URI (exported for TUI).

func ParseRemoteQuestionnaireAnswer added in v1.1.34

func ParseRemoteQuestionnaireAnswer(raw string, question toolpkg.AskUserQuestion) (selected map[string]struct{}, freeform string, err error)

ParseRemoteQuestionnaireAnswer parses a raw IM text reply against a single question definition. It returns the selected choice IDs (for single/multi), a freeform text (for text or unmatched input), and whether parsing succeeded.

This is the shared implementation used by both TUI and daemon modes.

func SignalDaemonInstallCommand added in v1.1.87

func SignalDaemonInstallCommand() string

SignalDaemonInstallCommand returns a shell command string that installs signal-cli-rest-api via Docker.

func SplitMessage added in v1.1.45

func SplitMessage(text string, maxLen int) []string

SplitMessage splits a long message into chunks that fit within the platform's message length limit. It tries to split at line boundaries to preserve readability.

The splitting strategy:

  1. If the message fits within maxLen, return it as a single chunk.
  2. Otherwise, try to find the last newline before maxLen.
  3. If no newline found, split at maxLen (hard cut).
  4. Repeat until the entire message is processed.

Each chunk is guaranteed to be at most maxLen bytes long.

func SplitMessageForPlatform added in v1.1.45

func SplitMessageForPlatform(text string, p Platform) []string

SplitMessageForPlatform is a convenience wrapper that looks up the platform's limit and calls SplitMessage.

func SplitNonEmptyLines added in v1.1.34

func SplitNonEmptyLines(text string) []string

SplitNonEmptyLines splits text into non-empty trimmed lines.

func StartNamedAdapter

func StartNamedAdapter(parent context.Context, cfg config.IMConfig, name string, mgr *Manager) error

Types

type AdapterController

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

func StartConfiguredAdapters

func StartConfiguredAdapters(parent context.Context, cfg config.IMConfig, mgr *Manager) (*AdapterController, error)

func StartCurrentBindingAdapter

func StartCurrentBindingAdapter(parent context.Context, cfg config.IMConfig, mgr *Manager) (*AdapterController, error)

func StartPCAdapterOnly added in v1.1.34

func StartPCAdapterOnly(parent context.Context, cfg config.IMConfig, mgr *Manager) (*AdapterController, error)

StartPCAdapterOnly starts only the built-in PrivateClaw adapter. Used when IM is not explicitly enabled but PC should still be available.

func (*AdapterController) Stop

func (c *AdapterController) Stop()

type AdapterDescriptor

type AdapterDescriptor struct {
	Name         string
	Platform     Platform
	Capabilities []string
}

type AdapterState

type AdapterState struct {
	Name       string
	Platform   Platform
	Healthy    bool
	Status     string
	LastError  string
	ContactURI string // deep link to add/contact bot (e.g. https://t.me/botname)
	QRCode     string // ASCII art QR code (for WhatsApp pairing, etc.)
	UpdatedAt  time.Time
}

type ApprovalRequest

type ApprovalRequest struct {
	ID          string
	ToolName    string
	Input       string
	RequestedAt time.Time
	Source      string
}

type ApprovalResponse

type ApprovalResponse struct {
	ApprovalID  string
	Decision    permission.Decision
	RespondedBy string
	RespondedAt time.Time
}

type ApprovalResult

type ApprovalResult struct {
	Request     ApprovalRequest
	Decision    permission.Decision
	RespondedBy string
	RespondedAt time.Time
}

type ApprovalState

type ApprovalState struct {
	Request     ApprovalRequest
	Resolved    bool
	Decision    permission.Decision
	RespondedBy string
	RespondedAt time.Time
}

type Attachment

type Attachment struct {
	ID         string
	Kind       AttachmentKind
	Name       string
	MIME       string
	Path       string
	URL        string
	DataBase64 string
	Transcript string
	Metadata   map[string]string
}

type AttachmentKind

type AttachmentKind string
const (
	AttachmentImage AttachmentKind = "image"
	AttachmentVoice AttachmentKind = "voice"
	AttachmentAudio AttachmentKind = "audio"
	AttachmentFile  AttachmentKind = "file"
)

type BindingStore

type BindingStore interface {
	Save(binding ChannelBinding) error
	Delete(workspace, adapter string) error
	List() ([]ChannelBinding, error)
	ListByWorkspace(workspace string) ([]ChannelBinding, error)
	ListByAdapter(adapter string) ([]ChannelBinding, error)
}

BindingStore persists channel bindings keyed by (workspace, adapter).

type Bridge

type Bridge interface {
	SubmitInboundMessage(ctx context.Context, msg InboundMessage) error
}

type ChannelBinding

type ChannelBinding struct {
	Workspace             string
	Platform              Platform
	Adapter               string
	TargetID              string
	ChannelID             string
	ThreadID              string
	LastInboundMessageID  string
	LastOutboundMessageID string
	LastInboundAt         time.Time
	PassiveReplyCount     int
	PassiveReplyStartedAt time.Time
	BoundAt               time.Time
	Muted                 bool
	ContextToken          string    // WeChat iLink: latest context_token for reply routing
	ContextTokenUpdatedAt time.Time // When ContextToken was last refreshed by an inbound message
}

type Closer added in v1.1.45

type Closer interface {
	Close() error
}

Closer is an optional interface that adapters implement to close their underlying network connections. Called by Manager when an adapter is muted or disabled to physically disconnect.

type DaemonBridge added in v1.1.34

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

func NewDaemonBridge added in v1.1.34

func NewDaemonBridge(mgr *Manager, ag *agent.Agent, emitter *IMEmitter, store session.Store, sess *session.Session) *DaemonBridge

NewDaemonBridge creates a bridge that submits IM messages directly to the agent.

func (*DaemonBridge) ConsumeRestartDebug added in v1.1.51

func (b *DaemonBridge) ConsumeRestartDebug() bool

ConsumeRestartDebug returns whether /restart debug was requested and resets the flag.

func (*DaemonBridge) HandleAskUser added in v1.1.34

HandleAskUser is the AskUserHandler for daemon mode — sends questions to IM one at a time and collects answers interactively. For single-choice questions, it first attempts to send native interactive buttons. If the adapter supports it, the user clicks a button instead of typing a number. The answer is routed back through the same pendingAsk mechanism — either from a text reply or a button callback.

func (*DaemonBridge) Messages added in v1.1.51

func (b *DaemonBridge) Messages() []provider.Message

Messages returns the current agent conversation history.

func (*DaemonBridge) SendUserMessage added in v1.1.51

func (b *DaemonBridge) SendUserMessage(content []provider.ContentBlock)

SendUserMessage injects a user message into the agent conversation. If the agent is currently running, the message is queued as an interruption (same mechanism as IM mid-run messages). If the agent is idle, a new run is started.

func (*DaemonBridge) SetActivityHook added in v1.1.43

func (b *DaemonBridge) SetActivityHook(fn func())

SetActivityHook installs a callback fired when an inbound IM message counts as real user activity. Daemon mode uses this to keep Knight's idle timer honest.

func (*DaemonBridge) SetFollowSink added in v1.1.34

func (b *DaemonBridge) SetFollowSink(sink daemon.FollowSink)

SetFollowSink sets or clears the follow-mode display sink.

func (*DaemonBridge) SetHarnessConfig added in v1.1.66

func (b *DaemonBridge) SetHarnessConfig(mode string, autoInit bool, workingDir string)

SetHarnessConfig configures auto-run routing for daemon mode.

func (*DaemonBridge) SetProviderSwitchHook added in v1.1.82

func (b *DaemonBridge) SetProviderSwitchHook(fn func(vendor, endpoint, model string) (string, error))

SetProviderSwitchHook installs a callback to switch provider/model. The callback receives (vendor, endpoint, model) — any may be empty to mean "keep current". It returns a human-readable summary string.

func (*DaemonBridge) SetRestartHook added in v1.1.46

func (b *DaemonBridge) SetRestartHook(fn func())

SetRestartHook installs a callback to trigger daemon process restart.

func (*DaemonBridge) SubmitInboundMessage added in v1.1.34

func (b *DaemonBridge) SubmitInboundMessage(ctx context.Context, msg InboundMessage) error

SubmitInboundMessage handles an inbound IM message by submitting it to the agent.

func (*DaemonBridge) Subscribe added in v1.1.51

func (b *DaemonBridge) Subscribe(fn func(provider.StreamEvent)) func()

Subscribe registers a callback for agent streaming events. All events from the agent loop are forwarded to all subscribers via buffered channels to avoid blocking the agent. Returns an unsubscribe function.

type Envelope

type Envelope struct {
	Adapter    string
	Platform   Platform
	ChannelID  string
	ThreadID   string
	SenderID   string
	SenderName string
	MessageID  string
	ReceivedAt time.Time
}

type EvalMetrics added in v1.1.43

type EvalMetrics struct {
	SessionStart time.Time
	SessionEnd   time.Time

	UserMessages     int
	AskUserCount     int
	AskUserLatencyMs map[string]int64 // question_id → latency

	ToolCalls        map[string]int // tool_name → count
	TotalToolCalls   int
	ToolErrors       int
	ToolErrorsByTool map[string]int // tool_name → error count
	ReworkCount      int
	Rounds           int

	InputTokens  int
	OutputTokens int

	KnightReports int
	StagedSkills  int

	ElapsedMs int64
	// contains filtered or unexported fields
}

EvalMetrics collects quantitative metrics during an evaluation session.

func NewEvalMetrics added in v1.1.43

func NewEvalMetrics() *EvalMetrics

NewEvalMetrics creates a new metrics collector.

func (*EvalMetrics) RecordEvent added in v1.1.43

func (m *EvalMetrics) RecordEvent(event OutboundEvent)

RecordEvent updates metrics based on an outbound event.

func (*EvalMetrics) Reset added in v1.1.43

func (m *EvalMetrics) Reset()

Reset clears all per-task metrics while keeping session-level fields.

func (*EvalMetrics) Snapshot added in v1.1.43

func (m *EvalMetrics) Snapshot() map[string]interface{}

Snapshot returns a copy of current metrics as a map.

func (*EvalMetrics) WriteCSV added in v1.1.43

func (m *EvalMetrics) WriteCSV(path string, runID, phase, mode string) error

WriteCSV appends a metrics row to a CSV file.

func (*EvalMetrics) WriteJSON added in v1.1.43

func (m *EvalMetrics) WriteJSON(path string) error

WriteJSON writes the metrics snapshot to a JSON file.

type ExtractedImage added in v1.1.34

type ExtractedImage struct {
	Kind string // "url", "data_url", "local_path"
	Data string // URL, base64 data URL, or local file path
}

ExtractedImage represents an image found in message text.

func ExtractImagesFromText added in v1.1.34

func ExtractImagesFromText(text string) ([]ExtractedImage, string)

ExtractImagesFromText finds markdown images, bare image URLs, and data URLs in text. Returns extracted images and the text with image references replaced by their alt text (for markdown images) or removed (for bare URLs and data URLs). Line breaks are preserved.

type IMEmitter added in v1.1.34

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

IMEmitter handles asynchronous outbound IM event emission with typing keepalive. It is framework-agnostic and can be used by both TUI and daemon modes.

func NewIMEmitter added in v1.1.34

func NewIMEmitter(mgr *Manager, lang, workDir string) *IMEmitter

NewIMEmitter creates a new IM emitter for the given manager, language, and working directory.

func (*IMEmitter) EmitAskUser added in v1.1.34

func (e *IMEmitter) EmitAskUser(text string)

EmitAskUser sends an ask_user prompt to IM.

func (*IMEmitter) EmitAskUserInteractive added in v1.1.51

func (e *IMEmitter) EmitAskUserInteractive(title string, q toolpkg.AskUserQuestion, fallbackText string) map[string]string

EmitAskUserInteractive sends an ask_user question to IM, preferring interactive buttons for adapters that support them (Discord, Telegram, Feishu). Text fallback is only sent to adapters that did NOT receive an interactive message (e.g. QQ, DingDing). If the question has no choices, falls back to EmitAskUser for all adapters.

func (*IMEmitter) EmitEvent added in v1.1.34

func (e *IMEmitter) EmitEvent(event OutboundEvent)

EmitEvent sends a raw outbound event to all bound IM channels.

func (*IMEmitter) EmitKnightReport added in v1.1.43

func (e *IMEmitter) EmitKnightReport(report string)

EmitKnightReport sends a Knight status report to IM.

func (*IMEmitter) EmitRoundSummary added in v1.1.34

func (e *IMEmitter) EmitRoundSummary(text string, toolCalls, toolSuccesses, toolFailures int)

EmitRoundSummary sends the final round text to IM.

func (*IMEmitter) EmitStatus added in v1.1.34

func (e *IMEmitter) EmitStatus(status string)

EmitStatus sends a status update to IM. Duplicate consecutive statuses are suppressed.

func (*IMEmitter) EmitText added in v1.1.34

func (e *IMEmitter) EmitText(text string)

EmitText sends a text message to IM.

func (*IMEmitter) EmitToolStatus added in v1.1.34

func (e *IMEmitter) EmitToolStatus(toolName, rawArgs string)

EmitToolStatus formats and sends a tool execution status using the shared DescribeTool pipeline.

func (*IMEmitter) EmitUserText added in v1.1.34

func (e *IMEmitter) EmitUserText(text string)

EmitUserText sends a user echo message to IM.

func (*IMEmitter) EmitUserTextExcept added in v1.1.34

func (e *IMEmitter) EmitUserTextExcept(text, excludeAdapter string)

EmitUserTextExcept sends a user echo message to all bound IM channels except the originating adapter. This prevents the user from seeing their own message echoed back on the channel they sent from.

func (*IMEmitter) FormatAskUserPrompt added in v1.1.34

func (e *IMEmitter) FormatAskUserPrompt(rawArgs string) string

FormatAskUserPrompt formats an ask_user request as an IM-friendly prompt string. Delegates to the shared FormatAskUserPrompt in ask_user_format.go.

func (*IMEmitter) HasTargets added in v1.1.43

func (e *IMEmitter) HasTargets() bool

HasTargets returns true if at least one IM channel is bound. Uses a lightweight check that avoids copying the bindings list.

func (*IMEmitter) Language added in v1.1.34

func (e *IMEmitter) Language() string

Language returns the emitter's configured language.

func (*IMEmitter) Manager added in v1.1.51

func (e *IMEmitter) Manager() *Manager

Manager returns the underlying Manager. Returns nil if the emitter is nil.

func (*IMEmitter) OutputMode added in v1.1.45

func (e *IMEmitter) OutputMode() string

OutputMode returns the current output mode.

func (*IMEmitter) SetOutputMode added in v1.1.45

func (e *IMEmitter) SetOutputMode(mode string)

SetOutputMode sets the IM output mode: verbose, quiet, or summary.

func (*IMEmitter) TriggerTyping added in v1.1.34

func (e *IMEmitter) TriggerTyping()

TriggerTyping sends typing indicators to all bound adapters with keepalive throttling.

type InboundMessage

type InboundMessage struct {
	Envelope    Envelope
	Text        string
	Attachments []Attachment
	Metadata    map[string]string
}

func (InboundMessage) ProviderContent

func (m InboundMessage) ProviderContent() []provider.ContentBlock

type InstanceDetect added in v1.1.45

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

InstanceDetect manages per-directory instance registration and discovery. It uses PID files under .ggcode/instances/ to track running instances.

func NewInstanceDetect added in v1.1.45

func NewInstanceDetect(workspace string) *InstanceDetect

NewInstanceDetect creates a new instance detector for the given workspace. workspace is the project root directory (where .ggcode/ lives).

func (*InstanceDetect) Info added in v1.1.45

func (d *InstanceDetect) Info() InstanceInfo

Info returns this instance's info.

func (*InstanceDetect) IsPrimary added in v1.1.45

func (d *InstanceDetect) IsPrimary() bool

IsPrimary checks if this instance is the oldest among all running instances in the same directory. Must be called after Register().

func (*InstanceDetect) IsRegistered added in v1.1.45

func (d *InstanceDetect) IsRegistered() bool

IsRegistered returns whether Register() has been called successfully.

func (*InstanceDetect) ListInstances added in v1.1.45

func (d *InstanceDetect) ListInstances() []InstanceInfo

ListInstances returns all live instances in the directory, including self. Sorted by StartedAt ascending (oldest first).

func (*InstanceDetect) Register added in v1.1.45

func (d *InstanceDetect) Register() ([]InstanceInfo, error)

Register writes this instance's PID file and cleans up stale entries. Returns a list of other live instances (sorted by StartedAt ascending) and an error if file operations fail.

func (*InstanceDetect) Unregister added in v1.1.45

func (d *InstanceDetect) Unregister()

Unregister removes this instance's PID file. Call on graceful shutdown.

func (*InstanceDetect) UpdateHasActiveChannels added in v1.1.45

func (d *InstanceDetect) UpdateHasActiveChannels(active bool) error

UpdateHasActiveChannels updates the hasActiveChannels flag in the PID file.

type InstanceInfo added in v1.1.45

type InstanceInfo struct {
	PID               int       `json:"pid"`
	UUID              string    `json:"uuid"`
	StartedAt         time.Time `json:"startedAt"`
	HasActiveChannels bool      `json:"hasActiveChannels"`
}

InstanceInfo describes a running ggcode instance in the same directory.

type InteractiveButton added in v1.1.51

type InteractiveButton struct {
	// Label is the button text shown to the user.
	Label string
	// Value is the opaque value sent back when the button is clicked.
	// For ask_user, this is the choice number (e.g. "1", "2").
	Value string
	// Style hints (optional): "primary", "danger", "default".
	Style string
}

InteractiveButton represents a single clickable option.

type InteractiveCallback added in v1.1.51

type InteractiveCallback struct {
	// MessageID is the platform message ID of the original interactive message.
	MessageID string
	// Values are the selected button values (one for single, multiple for multi-select).
	Values []string
	// Adapter is the adapter name that received the callback.
	Adapter string
	// Envelope carries the standard sender/channel info.
	Envelope Envelope
}

InteractiveCallback represents a user's response to an interactive element. Adapters translate platform-specific callbacks into this common type.

type InteractiveMessage added in v1.1.51

type InteractiveMessage struct {
	// ID is a unique identifier for correlating callbacks.
	ID string
	// Text is the main message body (markdown).
	Text string
	// Buttons is a list of clickable options presented to the user.
	// Each button has a label and a value that gets sent back on click.
	Buttons []InteractiveButton
	// MultiSelect allows selecting multiple buttons (for multi-question ask_user).
	MultiSelect bool
	// Placeholder is shown in select menus (Slack, DingTalk).
	Placeholder string
}

InteractiveMessage describes a message with interactive elements. Used for ask_user questions with choices, approval actions, etc.

type InteractiveSender added in v1.1.51

type InteractiveSender interface {
	SendInteractive(ctx context.Context, binding ChannelBinding, msg InteractiveMessage) (string, error)
}

InteractiveSender is an optional interface that adapters implement to send messages with native interactive elements (buttons, select menus). Adapters that don't implement this fall back to text-based interaction.

type JSONFileBindingStore

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

JSONFileBindingStore persists bindings to a JSON file with atomic writes.

func NewJSONFileBindingStore

func NewJSONFileBindingStore(path string) (*JSONFileBindingStore, error)

func (*JSONFileBindingStore) Delete

func (s *JSONFileBindingStore) Delete(workspace, adapter string) error

func (*JSONFileBindingStore) List

func (s *JSONFileBindingStore) List() ([]ChannelBinding, error)

func (*JSONFileBindingStore) ListByAdapter added in v1.1.34

func (s *JSONFileBindingStore) ListByAdapter(adapter string) ([]ChannelBinding, error)

func (*JSONFileBindingStore) ListByWorkspace added in v1.1.34

func (s *JSONFileBindingStore) ListByWorkspace(workspace string) ([]ChannelBinding, error)

func (*JSONFileBindingStore) Save

func (s *JSONFileBindingStore) Save(binding ChannelBinding) error

type JSONFilePCSessionStore added in v1.1.34

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

JSONFilePCSessionStore persists PC sessions to a JSON file.

func NewJSONFilePCSessionStore added in v1.1.34

func NewJSONFilePCSessionStore(path string) (*JSONFilePCSessionStore, error)

func (*JSONFilePCSessionStore) LoadAll added in v1.1.34

func (s *JSONFilePCSessionStore) LoadAll() ([]pcPersistedSession, error)

func (*JSONFilePCSessionStore) SaveAll added in v1.1.34

func (s *JSONFilePCSessionStore) SaveAll(sessions []pcPersistedSession) error

type JSONFilePairingStore

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

func NewJSONFilePairingStore

func NewJSONFilePairingStore(path string) (*JSONFilePairingStore, error)

func (*JSONFilePairingStore) LoadAll

func (*JSONFilePairingStore) SaveAll

func (s *JSONFilePairingStore) SaveAll(states map[string]PairingChannelState) error

type Manager

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

func NewManager

func NewManager() *Manager

func (*Manager) ActiveSession

func (m *Manager) ActiveSession() *SessionBinding

func (*Manager) AllPersistedBindings added in v1.1.46

func (m *Manager) AllPersistedBindings() []ChannelBinding

AllPersistedBindings returns all persisted bindings from the store, including bindings for other workspaces not currently active.

func (*Manager) ApplyAdapterConfig added in v1.1.93

func (m *Manager) ApplyAdapterConfig(adapters map[string]bool)

ApplyAdapterConfig moves adapters marked as disabled in config from currentBindings to disabledBindings. Call this after BindSession and reloadBindingLocked during startup.

func (*Manager) BindChannel

func (m *Manager) BindChannel(binding ChannelBinding) (ChannelBinding, error)

func (*Manager) BindSession

func (m *Manager) BindSession(binding SessionBinding)

func (*Manager) ClearChannel

func (m *Manager) ClearChannel(workspace string) error

func (*Manager) ClearChannelByAdapter added in v1.1.34

func (m *Manager) ClearChannelByAdapter(adapterName string) error

func (*Manager) ClearReplyWindow

func (m *Manager) ClearReplyWindow(workspace string) error

func (*Manager) CurrentBinding

func (m *Manager) CurrentBinding() *ChannelBinding

func (*Manager) CurrentBindings added in v1.1.34

func (m *Manager) CurrentBindings() []ChannelBinding

func (*Manager) DeleteBinding added in v1.1.46

func (m *Manager) DeleteBinding(adapter, workspace string) error

DeleteBinding removes a specific persisted binding by adapter and workspace.

func (*Manager) DisableAll added in v1.1.45

func (m *Manager) DisableAll() (int, error)

DisableAll disables all active (non-muted, non-disabled) bindings.

func (*Manager) DisableBinding added in v1.1.35

func (m *Manager) DisableBinding(adapterName string) error

DisableBinding temporarily disables an adapter's binding for the current session. The binding is moved from currentBindings to disabledBindings, so it will no longer receive outbound messages and inbound messages will be rejected. The persistent binding is NOT deleted, so it can be re-enabled later.

func (*Manager) DisabledBindings added in v1.1.35

func (m *Manager) DisabledBindings() []ChannelBinding

DisabledBindings returns a snapshot of currently disabled bindings.

func (*Manager) Emit

func (m *Manager) Emit(ctx context.Context, event OutboundEvent) error

func (*Manager) EmitExcept added in v1.1.34

func (m *Manager) EmitExcept(ctx context.Context, event OutboundEvent, excludeAdapter string) error

EmitExcept sends an event to all bound channels except those matching excludeAdapter. This is used to suppress user mirror echo on the originating IM channel while still delivering it to other bound channels.

func (*Manager) EmitExceptAdapters added in v1.1.51

func (m *Manager) EmitExceptAdapters(ctx context.Context, event OutboundEvent, excludeSet map[string]bool) error

EmitExceptAdapters sends an event to all bound channels except those in excludeSet.

func (*Manager) EmitToNonInteractive added in v1.1.51

func (m *Manager) EmitToNonInteractive(ctx context.Context, event OutboundEvent) error

EmitToNonInteractive sends an event only to adapters that do NOT implement InteractiveSender. Used for ask_user text fallback — adapters that already received interactive buttons should not get the duplicate text version.

func (*Manager) EnableAll added in v1.1.45

func (m *Manager) EnableAll() (int, error)

EnableAll re-enables all disabled bindings.

func (*Manager) EnableBinding added in v1.1.35

func (m *Manager) EnableBinding(adapterName string) error

EnableBinding re-enables a previously disabled adapter binding. The binding is moved back to currentBindings so it resumes receiving messages.

func (m *Manager) GenerateShareLink(ctx context.Context, adapter, callbackData string) (string, error)

func (*Manager) GetBindingContextToken added in v1.1.83

func (m *Manager) GetBindingContextToken(adapter string) string

GetBindingContextToken returns the persisted ContextToken for the given adapter.

func (*Manager) HandleInbound

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

func (*Manager) HandleInteractiveCallback added in v1.1.51

func (m *Manager) HandleInteractiveCallback(cb InteractiveCallback)

HandleInteractiveCallback is called by adapters when a user clicks an interactive button. It dispatches to the registered callback handler.

func (*Manager) HandlePairingInbound

func (m *Manager) HandlePairingInbound(msg InboundMessage) (PairingResult, error)

HandlePairingInbound processes an inbound IM message for pairing. If the adapter has no binding with a ChannelID, it creates a pairing challenge (4-digit code displayed on screen). The user must enter the code in the IM channel to complete binding and obtain the ChannelID/TargetID.

func (*Manager) HasActiveBindings added in v1.1.43

func (m *Manager) HasActiveBindings() bool

HasActiveBindings returns true if there is at least one active channel binding. Lighter than ListBindings — no allocation or copying.

func (*Manager) HasNonInteractiveBindings added in v1.1.51

func (m *Manager) HasNonInteractiveBindings(sentAdapters map[string]string) bool

HasNonInteractiveBindings returns true if there is at least one bound adapter that did NOT receive an interactive message (i.e. doesn't implement InteractiveSender or wasn't in the sentAdapters set). Used to decide whether to send text fallback.

func (*Manager) InstanceDetect added in v1.1.45

func (m *Manager) InstanceDetect() *InstanceDetect

InstanceDetect returns the instance detector (nil if not registered).

func (*Manager) IsBindingDisabled added in v1.1.35

func (m *Manager) IsBindingDisabled(adapterName string) bool

IsBindingDisabled returns true if the given adapter's binding is currently disabled.

func (*Manager) IsBindingMuted added in v1.1.45

func (m *Manager) IsBindingMuted(adapterName string) bool

IsBindingMuted returns true if the given adapter's binding is currently muted.

func (*Manager) IsPrimary added in v1.1.45

func (m *Manager) IsPrimary() bool

IsPrimary returns true if this instance is the oldest running instance in the workspace (or no detector is set).

func (*Manager) ListBindings

func (m *Manager) ListBindings() ([]ChannelBinding, error)

func (*Manager) MuteAll added in v1.1.45

func (m *Manager) MuteAll() (int, error)

MuteAll mutes all currently active bindings for this process. Returns the number of adapters that were muted.

func (*Manager) MuteAllExcept added in v1.1.46

func (m *Manager) MuteAllExcept(exclude string) (int, error)

MuteAllExcept mutes all currently active bindings except the named adapter. If exclude is empty, all bindings are muted. Returns the number muted.

func (*Manager) MuteBinding added in v1.1.45

func (m *Manager) MuteBinding(adapterName string) error

MuteBinding mutes an adapter for this process only. The binding stays in currentBindings (so the UI still shows it as bound) but is marked Muted. The connection is dropped so inbound/outbound messages stop.

func (*Manager) MutedBindings added in v1.1.45

func (m *Manager) MutedBindings() []ChannelBinding

MutedBindings returns a snapshot of currently muted bindings.

func (*Manager) PCAdapter added in v1.1.34

func (m *Manager) PCAdapter() PCAdapterAPI

PCAdapter returns the first registered PrivateClaw adapter, or nil.

func (*Manager) PublishAdapterState

func (m *Manager) PublishAdapterState(state AdapterState)

func (*Manager) RecordOutboundMessage added in v1.1.34

func (m *Manager) RecordOutboundMessage(workspace, adapter, messageID string) error

RecordOutboundMessage records the message ID of a bot reply so that typing indicator reactions can target it when no inbound message exists.

func (*Manager) RecordPassiveReply

func (m *Manager) RecordPassiveReply(workspace, messageID string, sentAt time.Time) error

func (*Manager) RegisterAdapterCancel added in v1.1.45

func (m *Manager) RegisterAdapterCancel(adapterName string, cancel context.CancelFunc)

RegisterAdapterCancel registers a cancel function for an adapter. When the adapter is muted or disabled, the cancel is called to stop its goroutine and drop the connection.

func (*Manager) RegisterApproval

func (m *Manager) RegisterApproval(req ApprovalRequest) (ApprovalRequest, <-chan permission.Decision)

func (*Manager) RegisterInstance added in v1.1.45

func (m *Manager) RegisterInstance(workspace string) (*InstanceDetect, []InstanceInfo, error)

RegisterInstance creates an InstanceDetect for the given workspace, registers this process as a running instance, and stores it on the Manager. If other instances are already running in the same workspace, this instance is auto-muted (non-primary). Returns the detector and any other live instances.

func (*Manager) RegisterSink

func (m *Manager) RegisterSink(sink Sink)

func (*Manager) RejectPendingPairing

func (m *Manager) RejectPendingPairing() (*PairingChallenge, bool, error)

func (*Manager) ResolveApproval

func (m *Manager) ResolveApproval(resp ApprovalResponse) (ApprovalResult, bool, error)

func (*Manager) ResolveOutputMode added in v1.1.82

func (m *Manager) ResolveOutputMode(adapterName, globalMode string) string

ResolveOutputMode returns the effective output mode for the given adapter. If the adapter's platform has a recommended default (e.g. WeChat → summary), and the global mode is "verbose" (the default), the platform default is used.

func (*Manager) SendDirect

func (m *Manager) SendDirect(ctx context.Context, binding ChannelBinding, event OutboundEvent) error

func (*Manager) SendInteractive added in v1.1.51

func (m *Manager) SendInteractive(ctx context.Context, msg InteractiveMessage) map[string]string

SendInteractive sends an interactive message to all bound adapters that support it. Returns a map of adapter name → platform message ID for callback correlation. Adapters that don't support interactive messages are skipped (caller should fall back to text).

func (*Manager) SetBindingStore

func (m *Manager) SetBindingStore(store BindingStore) error

func (*Manager) SetBridge

func (m *Manager) SetBridge(bridge Bridge)

func (*Manager) SetInteractiveCallback added in v1.1.51

func (m *Manager) SetInteractiveCallback(fn func(InteractiveCallback))

SetInteractiveCallback registers a handler for interactive button/menu callbacks from adapters. When a user clicks a button, the adapter calls Manager.HandleInteractiveCallback which dispatches to this handler.

func (*Manager) SetOnRestart added in v1.1.45

func (m *Manager) SetOnRestart(fn func(adapterName string) error)

SetOnRestart sets a callback invoked by UnmuteBinding/EnableBinding to restart a previously stopped adapter. The caller (TUI/daemon) provides this because it has access to the IM config needed to start adapters.

func (*Manager) SetOnUpdate

func (m *Manager) SetOnUpdate(cb func(StatusSnapshot))

func (*Manager) SetPairingStore

func (m *Manager) SetPairingStore(store PairingStateStore) error

func (*Manager) Snapshot

func (m *Manager) Snapshot() StatusSnapshot

func (*Manager) StopAdapter added in v1.1.45

func (m *Manager) StopAdapter(adapterName string)

StopAdapter stops a running adapter by name. This is the public version of stopAdapter, used for hot-reloading config changes without altering binding state.

func (*Manager) SyncSessionHistory

func (m *Manager) SyncSessionHistory(ctx context.Context, binding ChannelBinding, messages []provider.Message) error

func (*Manager) TriggerTyping added in v1.1.34

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

TriggerTyping sends a typing indicator to all bound adapters that implement the TypingIndicator interface.

func (*Manager) UnbindAdapter added in v1.1.34

func (m *Manager) UnbindAdapter(adapterName string) error

UnbindAdapter removes the binding for whatever workspace has the given adapter name. This is needed when unbinding from a panel where the current session workspace may differ from the workspace that originally bound the adapter. Returns ErrNoChannelBound if no binding uses this adapter.

func (*Manager) UnbindChannel

func (m *Manager) UnbindChannel(workspace string) error

func (*Manager) UnbindSession

func (m *Manager) UnbindSession()

func (*Manager) UnmuteAll added in v1.1.45

func (m *Manager) UnmuteAll() (int, error)

UnmuteAll unmutes all muted bindings for this process. Returns the number of adapters that were unmuted.

func (*Manager) UnmuteBinding added in v1.1.45

func (m *Manager) UnmuteBinding(adapterName string) error

UnmuteBinding unmutes a previously muted adapter and restarts it.

func (*Manager) UnregisterInstance added in v1.1.45

func (m *Manager) UnregisterInstance()

UnregisterInstance removes this process's instance registration (PID file). Call on graceful shutdown.

func (*Manager) UnregisterSink

func (m *Manager) UnregisterSink(name string)

func (*Manager) UpdateBindingContextToken added in v1.1.83

func (m *Manager) UpdateBindingContextToken(adapter, token string)

UpdateBindingContextToken updates the ContextToken (and ContextTokenUpdatedAt) on the binding for the given adapter. The token is persisted to disk so it survives restarts. WeChat iLink requires context_token for every sendmessage; without it only ~2 messages succeed before the server stops responding. Tokens expire after ~24 hours.

func (*Manager) WechatAdapter added in v1.1.82

func (m *Manager) WechatAdapter() *WechatAdapter

WechatAdapter returns the first wechat adapter sink from the manager, or nil.

type MemoryBindingStore

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

MemoryBindingStore is an in-memory BindingStore for tests.

func NewMemoryBindingStore

func NewMemoryBindingStore() *MemoryBindingStore

func (*MemoryBindingStore) Delete

func (s *MemoryBindingStore) Delete(workspace, adapter string) error

func (*MemoryBindingStore) List

func (s *MemoryBindingStore) List() ([]ChannelBinding, error)

func (*MemoryBindingStore) ListByAdapter added in v1.1.34

func (s *MemoryBindingStore) ListByAdapter(adapter string) ([]ChannelBinding, error)

func (*MemoryBindingStore) ListByWorkspace added in v1.1.34

func (s *MemoryBindingStore) ListByWorkspace(workspace string) ([]ChannelBinding, error)

func (*MemoryBindingStore) Save

func (s *MemoryBindingStore) Save(binding ChannelBinding) error

type MemoryPCSessionStore added in v1.1.34

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

MemoryPCSessionStore is an in-memory PC session store for testing.

func NewMemoryPCSessionStore added in v1.1.34

func NewMemoryPCSessionStore() *MemoryPCSessionStore

func (*MemoryPCSessionStore) LoadAll added in v1.1.34

func (s *MemoryPCSessionStore) LoadAll() ([]pcPersistedSession, error)

func (*MemoryPCSessionStore) SaveAll added in v1.1.34

func (s *MemoryPCSessionStore) SaveAll(sessions []pcPersistedSession) error

type MemoryPairingStore

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

func NewMemoryPairingStore

func NewMemoryPairingStore() *MemoryPairingStore

func (*MemoryPairingStore) LoadAll

func (s *MemoryPairingStore) LoadAll() (map[string]PairingChannelState, error)

func (*MemoryPairingStore) SaveAll

func (s *MemoryPairingStore) SaveAll(states map[string]PairingChannelState) error

type OutboundEvent

type OutboundEvent struct {
	Kind      OutboundEventKind
	Text      string
	Status    string
	ToolCall  *ToolCallInfo
	ToolRes   *ToolResultInfo
	Approval  *ApprovalRequest
	Result    *ApprovalResult
	CreatedAt time.Time
}

func SessionHistoryEvents

func SessionHistoryEvents(messages []provider.Message) []OutboundEvent

type OutboundEventKind

type OutboundEventKind string
const (
	OutboundEventText            OutboundEventKind = "text"
	OutboundEventStatus          OutboundEventKind = "status"
	OutboundEventToolCall        OutboundEventKind = "tool_call"
	OutboundEventToolResult      OutboundEventKind = "tool_result"
	OutboundEventApprovalRequest OutboundEventKind = "approval_request"
	OutboundEventApprovalResult  OutboundEventKind = "approval_result"
)

type PCAdapterAPI added in v1.1.34

type PCAdapterAPI interface {
	CreateSession(ctx context.Context, label string, groupMode bool) (*PCInvite, string, error)
	ListSessions() []PCSessionInfo
	GetSession(sessionID string) (*pcSession, bool)
	CloseSession(sessionID string) error
	RenewSession(ctx context.Context, sessionID string) error
	GetInviteURI(sessionID string) (string, error)
	KickParticipant(sessionID, appID string) error
}

PCAdapterAPI is the exported interface for PrivateClaw adapter operations (used by TUI).

type PCInvite added in v1.1.34

type PCInvite struct {
	Version       int    `json:"version"`
	SessionID     string `json:"sessionId"`
	SessionKey    string `json:"sessionKey"`
	AppWsURL      string `json:"appWsUrl"`
	ExpiresAt     string `json:"expiresAt"`
	GroupMode     bool   `json:"groupMode,omitempty"`
	ProviderLabel string `json:"providerLabel,omitempty"`
	RelayLabel    string `json:"relayLabel,omitempty"`
}

type PCSessionInfo added in v1.1.34

type PCSessionInfo struct {
	SessionID        string
	State            string
	GroupMode        bool
	Label            string
	ParticipantCount int
	ExpiresAt        time.Time
}

PCSessionInfo is a summary of a session for TUI display.

type PCSessionStore added in v1.1.34

type PCSessionStore interface {
	LoadAll() ([]pcPersistedSession, error)
	SaveAll(sessions []pcPersistedSession) error
}

PCSessionStore persists PC session data across restarts.

type PairingChallenge

type PairingChallenge struct {
	Kind                 PairingKind
	Workspace            string
	Adapter              string
	Platform             Platform
	ChannelID            string
	ThreadID             string
	SenderID             string
	SenderName           string
	Code                 string
	RequestedAt          time.Time
	LastInboundMessageID string
	LastInboundAt        time.Time
	ExistingBinding      *ChannelBinding
}

func (PairingChallenge) ReplyBinding

func (c PairingChallenge) ReplyBinding() ChannelBinding

type PairingChannelState

type PairingChannelState struct {
	Adapter       string
	Platform      Platform
	ChannelID     string
	RejectCount   int
	BlacklistedAt time.Time
	UpdatedAt     time.Time
}

func (PairingChannelState) IsBlacklisted

func (s PairingChannelState) IsBlacklisted() bool

type PairingKind

type PairingKind string
const (
	PairingKindBind   PairingKind = "bind"
	PairingKindRebind PairingKind = "rebind"
)

type PairingResult

type PairingResult struct {
	Consumed        bool
	Kind            PairingKind
	ReplyText       string
	Bound           bool
	PreviousBinding *ChannelBinding
	NewBinding      *ChannelBinding
}

type PairingStateStore

type PairingStateStore interface {
	LoadAll() (map[string]PairingChannelState, error)
	SaveAll(map[string]PairingChannelState) error
}

type ParsedQuestionAnswer added in v1.1.34

type ParsedQuestionAnswer struct {
	QuestionIndex int
	Selected      map[string]struct{}
	Freeform      string
	Error         error
}

ParsedQuestionAnswer holds the result of parsing a single question's reply.

func ParseMultiQuestionReply added in v1.1.34

func ParseMultiQuestionReply(raw string, questions []toolpkg.AskUserQuestion) []ParsedQuestionAnswer

ParseMultiQuestionReply splits a multi-line IM reply into per-question answers and parses each one. It returns a slice of results in the same order as the questions slice. If there are fewer lines than questions, remaining questions are left unanswered (empty results).

This is the shared implementation used by both TUI and daemon modes.

type Platform

type Platform string
const (
	PlatformUnknown    Platform = ""
	PlatformQQ         Platform = "qq"
	PlatformTelegram   Platform = "telegram"
	PlatformDiscord    Platform = "discord"
	PlatformFeishu     Platform = "feishu"
	PlatformDingTalk   Platform = "dingtalk"
	PlatformSlack      Platform = "slack"
	PlatformDummy      Platform = "dummy"
	PlatformWechat     Platform = "wechat"
	PlatformWeCom      Platform = "wecom"
	PlatformMattermost Platform = "mattermost"
	PlatformMatrix     Platform = "matrix"
	PlatformSignal     Platform = "signal"
	PlatformIRC        Platform = "irc"
	PlatformNostr      Platform = "nostr"
	PlatformSynology   Platform = "synology"
	PlatformTwitch     Platform = "twitch"
	PlatformWhatsApp   Platform = "whatsapp"
)
const PlatformPrivateClaw Platform = "privateclaw"

type SessionBinding

type SessionBinding struct {
	SessionID string
	Workspace string
	BoundAt   time.Time
}

type ShareLinkProvider

type ShareLinkProvider interface {
	GenerateShareLink(context.Context, string) (string, error)
}

type Sink

type Sink interface {
	Name() string
	Send(context.Context, ChannelBinding, OutboundEvent) error
}

type StatusSnapshot

type StatusSnapshot struct {
	ActiveSession    *SessionBinding
	CurrentBindings  []ChannelBinding
	DisabledBindings []ChannelBinding
	MutedBindings    []ChannelBinding
	PendingPairing   *PairingChallenge
	Adapters         []AdapterState
	PendingApprovals []ApprovalState
}

func (StatusSnapshot) BindingByAdapter added in v1.1.82

func (s StatusSnapshot) BindingByAdapter(adapter string) *ChannelBinding

BindingByAdapter returns the first current binding matching the given adapter name.

type ToolCallInfo added in v1.1.34

type ToolCallInfo struct {
	ToolName string
	Args     string
	Detail   string
	Lang     string // "zh-CN" or "en", set by emitter
}

type ToolLanguage added in v1.1.34

type ToolLanguage string

ToolLanguage represents the language for tool status formatting.

const (
	ToolLangZhCN ToolLanguage = "zh-CN"
	ToolLangEn   ToolLanguage = "en"
)

type ToolPresentation added in v1.1.34

type ToolPresentation struct {
	DisplayName string // e.g. "读", "编辑", "执行"
	Detail      string // e.g. file path, command preview
	Activity    string // e.g. "读取 chart.html", "执行 npm test"
}

ToolPresentation holds the formatted display information for a tool call.

func DescribeTool added in v1.1.34

func DescribeTool(lang ToolLanguage, toolName, rawArgs string) ToolPresentation

DescribeTool produces a human-readable presentation of a tool call, mirroring the TUI's describeTool pipeline (tool_labels.go).

type ToolResultInfo added in v1.1.34

type ToolResultInfo struct {
	ToolName string
	Args     string
	Result   string
	IsError  bool
	Detail   string // display text for the tool call (e.g. command line)
	Lang     string // "zh-CN" or "en", set by emitter
}

type TypingIndicator added in v1.1.34

type TypingIndicator interface {
	TriggerTyping(ctx context.Context, binding ChannelBinding) error
}

TypingIndicator is an optional interface that adapters can implement to show a native "bot is typing" indicator on the IM platform.

type WechatAdapter added in v1.1.82

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

func (*WechatAdapter) AuthenticateQRCode added in v1.1.82

func (a *WechatAdapter) AuthenticateQRCode(ctx context.Context) (qrcode string, imgBase64 string, err error)

AuthenticateQRCode requests a QR code from iLink for the user to scan. Returns the qrcode token (for status polling) and base64-encoded PNG image.

func (*WechatAdapter) Close added in v1.1.82

func (a *WechatAdapter) Close() error

func (*WechatAdapter) GetState added in v1.1.82

func (a *WechatAdapter) GetState() AdapterState

GetAdapterState returns the current adapter state for the TUI panel.

func (*WechatAdapter) Name added in v1.1.82

func (a *WechatAdapter) Name() string

func (*WechatAdapter) PollQRCodeStatus added in v1.1.82

func (a *WechatAdapter) PollQRCodeStatus(ctx context.Context, qrcode string) (status string, botToken string, err error)

PollQRCodeStatus checks the QR code scan status. Returns status string and the bot_token when confirmed.

func (*WechatAdapter) Send added in v1.1.82

func (a *WechatAdapter) Send(ctx context.Context, binding ChannelBinding, event OutboundEvent) error

Send sends an outbound message to the bound WeChat channel. Per iLink protocol spec: context_token is NOT optional — every sendmessage must carry the latest context_token from an inbound message, keyed by userID. Without it, WeChat cannot route the reply to the correct conversation.

func (*WechatAdapter) SetBotToken added in v1.1.82

func (a *WechatAdapter) SetBotToken(token string)

SetBotToken updates the bot token (after QR scan) and starts the message loop.

func (*WechatAdapter) Start added in v1.1.82

func (a *WechatAdapter) Start(ctx context.Context)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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