feat(channels): add human-like chat behavior

Squash merge PR #99 after resolving conflicts with current dev. PR CI run 26703381807 passed release-versioning, go, and web.
This commit is contained in:
Duy /zuey/ authored and GitHub committed 2026-05-31 11:44:56 +07:00
1 parent 3569f8d681
commit f0f39ce31f
51 files changed
+1786 -205

No files matched your search

+25 -22
View File
@@ -21,28 +21,29 @@ type feishuCreds struct {
// feishuInstanceConfig maps the non-secret config JSONB from the channel_instances table.
type feishuInstanceConfig struct {
Domain string `json:"domain,omitempty"`
ConnectionMode string `json:"connection_mode,omitempty"`
WebhookPort int `json:"webhook_port,omitempty"`
WebhookPath string `json:"webhook_path,omitempty"`
AllowFrom []string `json:"allow_from,omitempty"`
DMPolicy string `json:"dm_policy,omitempty"`
GroupPolicy string `json:"group_policy,omitempty"`
GroupAllowFrom []string `json:"group_allow_from,omitempty"`
RequireMention *bool `json:"require_mention,omitempty"`
TopicSessionMode string `json:"topic_session_mode,omitempty"`
TextChunkLimit int `json:"text_chunk_limit,omitempty"`
MediaMaxMB int `json:"media_max_mb,omitempty"`
RenderMode string `json:"render_mode,omitempty"`
Streaming *bool `json:"streaming,omitempty"`
ReactionLevel string `json:"reaction_level,omitempty"`
HistoryLimit int `json:"history_limit,omitempty"`
BlockReply *bool `json:"block_reply,omitempty"`
STTProxyURL string `json:"stt_proxy_url,omitempty"`
STTAPIKey string `json:"stt_api_key,omitempty"`
STTTenantID string `json:"stt_tenant_id,omitempty"`
STTTimeoutSeconds int `json:"stt_timeout_seconds,omitempty"`
VoiceAgentID string `json:"voice_agent_id,omitempty"`
Domain string `json:"domain,omitempty"`
ConnectionMode string `json:"connection_mode,omitempty"`
WebhookPort int `json:"webhook_port,omitempty"`
WebhookPath string `json:"webhook_path,omitempty"`
AllowFrom []string `json:"allow_from,omitempty"`
DMPolicy string `json:"dm_policy,omitempty"`
GroupPolicy string `json:"group_policy,omitempty"`
GroupAllowFrom []string `json:"group_allow_from,omitempty"`
RequireMention *bool `json:"require_mention,omitempty"`
TopicSessionMode string `json:"topic_session_mode,omitempty"`
TextChunkLimit int `json:"text_chunk_limit,omitempty"`
MediaMaxMB int `json:"media_max_mb,omitempty"`
RenderMode string `json:"render_mode,omitempty"`
Streaming *bool `json:"streaming,omitempty"`
ReactionLevel string `json:"reaction_level,omitempty"`
HistoryLimit int `json:"history_limit,omitempty"`
BlockReply *bool `json:"block_reply,omitempty"`
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
STTProxyURL string `json:"stt_proxy_url,omitempty"`
STTAPIKey string `json:"stt_api_key,omitempty"`
STTTenantID string `json:"stt_tenant_id,omitempty"`
STTTimeoutSeconds int `json:"stt_timeout_seconds,omitempty"`
VoiceAgentID string `json:"voice_agent_id,omitempty"`
}
// Factory creates a Feishu/Lark channel from DB instance data.
@@ -89,6 +90,7 @@ func Factory(name string, creds json.RawMessage, cfg json.RawMessage,
ReactionLevel: ic.ReactionLevel,
HistoryLimit: ic.HistoryLimit,
BlockReply: ic.BlockReply,
ChatBehavior: ic.ChatBehavior,
STTProxyURL: ic.STTProxyURL,
STTAPIKey: ic.STTAPIKey,
STTTenantID: ic.STTTenantID,
@@ -160,6 +162,7 @@ func FactoryWithPendingStoreAndAudio(pendingStore store.PendingMessageStore, aud
ReactionLevel: ic.ReactionLevel,
HistoryLimit: ic.HistoryLimit,
BlockReply: ic.BlockReply,
ChatBehavior: ic.ChatBehavior,
STTProxyURL: ic.STTProxyURL,
STTAPIKey: ic.STTAPIKey,
STTTenantID: ic.STTTenantID,
+7 -4
View File
@@ -40,10 +40,10 @@ type Channel struct {
cfg config.FeishuConfig
client *LarkClient
botOpenID string
senderCache sync.Map // open_id → *senderCacheEntry
dedup sync.Map // message_id → struct{}
reactions sync.Map // chatID → *reactionState
docCache *docCache // LRU+TTL cache for Lark docx raw_content lookups
senderCache sync.Map // open_id → *senderCacheEntry
dedup sync.Map // message_id → struct{}
reactions sync.Map // chatID → *reactionState
docCache *docCache // LRU+TTL cache for Lark docx raw_content lookups
agentStore store.AgentStore // optional — agent key → UUID lookup for writer commands
configPermStore store.ConfigPermissionStore // optional — group file writer ACL for /addwriter et al.
groupAllowList []string // Feishu-specific: per-group sender allowlist (separate from BaseChannel allowList)
@@ -160,6 +160,9 @@ func (c *Channel) Start(ctx context.Context) error {
// BlockReplyEnabled returns the per-channel block_reply override (nil = inherit gateway default).
func (c *Channel) BlockReplyEnabled() *bool { return c.cfg.BlockReply }
// ChatBehaviorConfig returns the per-channel chat_behavior override.
func (c *Channel) ChatBehaviorConfig() *config.ChatBehaviorConfig { return c.cfg.ChatBehavior }
// SetPendingCompaction configures LLM-based auto-compaction for pending messages.
func (c *Channel) SetPendingCompaction(cfg *channels.CompactionConfig) {
if gh := c.GroupHistory(); gh != nil {