fix(channelbridge): IM 渠道也走「回合必落可见回复」(与网关同口径)
根因(agent-194,文件:行): - inbound.go 的 deliverReply 对空回复直接 return(静默)⇒ 只剩 user 消息; - runInboundTurn 报错直接 return ⇒ 失败回合连说明都没有。 修法:抽共享**纯函数**包 internal/runtime/turnreply(从网关逐字搬运、零语义改动)+ channelbridge/turnreply.go 的 turnVisibleReply(与网关 persistTurnReply 同构); 取消边界在 IM 用 context.Canceled / ctx 取消表达(渠道桥无代次概念,如实登记差异)。 测试 6 条:空回复/纯空白/轮次用尽/安全网/回合报错/取消不落库/正常逐字不变。 变异:还原旧静默行为 ⇒ 4 条红(含「出站 0 条,want 1」与英文内部诊断外泄)。
This commit is contained in:
1 parent
be38651ba4
commit
fbbbb4ea64
6 files changed
+380
-73
No files matched your search
@@ -266,27 +266,38 @@ func (b *Bridge) runInboundTurn(ctx context.Context, msg adapter.UnifiedMessage,
|
||||
if err != nil {
|
||||
b.log.Warn("agent run failed", "platform", msg.Platform,
|
||||
"session", target.sessionID, "error", err)
|
||||
return
|
||||
}
|
||||
b.deliverReply(ctx, msg, a, sess, target, res)
|
||||
// 出错也交给 deliverReply:回合不能因为「模型那边出了问题」就对用户静默
|
||||
// (空回复 / 轮次用尽 / 内部报错都落一条诚实的可见回复;被取消的回合除外,
|
||||
// 见 turnreply.go)。
|
||||
b.deliverReply(ctx, msg, a, sess, target, res, err)
|
||||
}
|
||||
|
||||
// deliverReply 持久化助手回复,并经接收该消息的适配器
|
||||
// 送回去。不支持出站文本的适配器
|
||||
// deliverReply 解析本回合的可见回复、持久化并经接收该消息的适配器
|
||||
// 送回去。可见回复由 turnVisibleReply 给出(turnreply.go):真实文本逐字,
|
||||
// 空回复 / 轮次用尽 / 安全网终止 / 内部报错则是按原因区分的中文诚实说明 ——
|
||||
// IM 回合因此绝不会「没声了」;被取消的回合刻意不交付。不支持出站文本的适配器
|
||||
// (adapter.ErrUnsupported)只按 debug 级跳过,不算失败:回复
|
||||
// 已在历史存储中落地。
|
||||
func (b *Bridge) deliverReply(ctx context.Context, msg adapter.UnifiedMessage, a adapter.PlatformAdapter,
|
||||
sess session.Session, target inboundTarget, res *loop.Result) {
|
||||
reply := strings.TrimSpace(res.Text)
|
||||
if reply == "" {
|
||||
b.log.Debug("no reply produced", "platform", msg.Platform, "session", target.sessionID)
|
||||
sess session.Session, target inboundTarget, res *loop.Result, runErr error) {
|
||||
reply, ok := turnVisibleReply(ctx, res, runErr)
|
||||
if !ok {
|
||||
b.log.Debug("turn reply canceled, nothing delivered",
|
||||
"platform", msg.Platform, "session", target.sessionID)
|
||||
return
|
||||
}
|
||||
// mood 只挂在助手回复上(design/16 §3.3),且只有真实结果才带得回来
|
||||
// (回合报错时 res 为 nil)。
|
||||
mood := ""
|
||||
if res != nil {
|
||||
mood = res.Mood
|
||||
}
|
||||
// 持久化助手回复(主人私聊 → 主会话 + message_persisted
|
||||
// 广播;受限 → 隔离日志 + channel_persisted 广播),随后
|
||||
// 送回渠道。
|
||||
if target.private {
|
||||
b.persistToMain(ctx, history.RoleAssistant, reply, res.Mood, target.platform, deviceIDFor(msg), adapterName(a))
|
||||
b.persistToMain(ctx, history.RoleAssistant, reply, mood, target.platform, deviceIDFor(msg), adapterName(a))
|
||||
} else {
|
||||
b.persistIsolated(ctx, history.RoleAssistant, reply, "", sess, msg.Platform, "", adapterName(a))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user