feat: KOOK自动获取bot身份 + action/narration剥出气泡 + 渠道配置表单回填
agent-116 KOOK token即用+自动获取:
- kook/identity.go: Connect 调 GET /user/me 拿 bot 身份(bot_id/bot_username/bot_nickname), 失败容错
- 渠道列表 enrichAccountsWithBot 附 bot 身份; base_url空用默认/receive_mode默认ws(只填token可跑)
agent-117 action/narration 剥出气泡(主人需求: 动作/旁白不进气泡,按位置上/下):
- parseContent.splitBubble(content)->{body,head,tail}: body=纯文本(去标签), head=开头/中间action/narr(气泡上), tail=结尾(气泡下)
- renderContent 只渲染text(去内联灰斜体); chat.tsx BubbleNotes 泡外 *动作/旁白* 灰斜体小字(气泡外依附), SplitChatBubble 先剥splitBubble再splitParagraphs(body), <p>/\n\n/毛玻璃/SourceLabel不破坏
- 注: 非chat mode renderContent 现在丢弃action/narr(可接受)
Channels 配置表单回填(修save后输入框空):
- openConfig 从 data.accounts[0].config 回填 token(掩码提示)/base_url/平台字段/黑白名单/限流, 不再硬清空
全仓 build/vet/test绿+前端build绿
This commit is contained in:
1 parent
bdd9d752e1
commit
65091f6497
15 files changed
+571
-83
No files matched your search
@@ -75,6 +75,11 @@ type Adapter struct {
|
||||
|
||||
chatsMu sync.RWMutex
|
||||
chats map[string]adapter.ChannelInfo
|
||||
|
||||
botMu sync.RWMutex
|
||||
botID string
|
||||
botUsername string
|
||||
botNickname string
|
||||
}
|
||||
|
||||
// Compile-time assertion that Adapter satisfies the shared contract.
|
||||
@@ -117,6 +122,7 @@ func (a *Adapter) Name() string { return platformName }
|
||||
// this map must treat them as secrets (the admin read path masks these keys via
|
||||
// the "token"/"key" substring rules).
|
||||
func (a *Adapter) Config() map[string]any {
|
||||
id, username, nickname := a.botIdentitySnapshot()
|
||||
return map[string]any{
|
||||
"bot_token": a.cfg.BotToken,
|
||||
"base_url": a.baseURL,
|
||||
@@ -124,6 +130,9 @@ func (a *Adapter) Config() map[string]any {
|
||||
"webhook_path": a.cfg.WebhookPath,
|
||||
"webhook_verify_token": a.cfg.WebhookVerifyToken,
|
||||
"webhook_encrypt_key": a.cfg.WebhookEncryptKey,
|
||||
"bot_id": id,
|
||||
"bot_username": username,
|
||||
"bot_nickname": nickname,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +158,12 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
||||
|
||||
// Webhook mode: the Cyrene gateway mounts InboundHandler to receive KOOK
|
||||
// callbacks (KOOK posts to the configured route). No gateway WebSocket is
|
||||
// dialed — webhook and websocket are mutually exclusive. Mark connected so the
|
||||
// REST reply path and HealthCheck see a live session.
|
||||
// dialed — webhook and websocket are mutually exclusive. The bot identity
|
||||
// lookup is best-effort (a bad token or network hiccup logs a warning and
|
||||
// leaves the identity empty, never aborting the connect), and Mark connected
|
||||
// so the REST reply path and HealthCheck see a live session.
|
||||
if mode == modeWebhook {
|
||||
a.refreshBotIdentity(ctx)
|
||||
a.mu.Lock()
|
||||
a.connected = true
|
||||
a.mu.Unlock()
|
||||
@@ -163,6 +175,10 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
||||
return fmt.Errorf("kook: connect: %w", err)
|
||||
}
|
||||
|
||||
// Best-effort bot identity (user/me) so the admin list shows who the bot is.
|
||||
// Failure here is non-fatal: the gateway URL above already validated the token.
|
||||
a.refreshBotIdentity(ctx)
|
||||
|
||||
lifeCtx, cancel := context.WithCancel(context.Background())
|
||||
a.mu.Lock()
|
||||
a.cancel = cancel
|
||||
|
||||
Reference in new issue
Block a user