feat(channels): IM 入站图片接线(纯图片不再被丢 / data URI 进模型视图 / 诚实提示 / 来源白名单)

This commit is contained in:
AskaEth committed 2026-10-05 11:22:26 +08:00
1 parent 0cbc9ff886
commit b73a1276c6
18 files changed
+1224 -121

No files matched your search

@@ -0,0 +1,65 @@
package channelbridge
// 本文件承载入站内容的**共享制品与挂载点**:文档路(inbound_documents.go)与图片路
// (inbound_images.go)各产出一份 `inboundContent`(要挂到用户回合上的部件 + 「读不到」的
// 诚实提示行),由 attachInboundContent 逐组挂到**同一条 RoleUser 消息**上。
//
// 为什么两条路共用一个制品类型而不是各写一份挂载循环:两者的产物形状逐字相同
// (部件 + 提示行),差别只在部件怎么来(文档:落库引用;图片:data: URI)与落哪一列
// (`document` / `image`)。写第二份循环只会让「挂在哪条消息上」「空文本部件绝不塞」
// 这类口径开始漂移 —— 而用户内容只进用户角色消息是项目红线,这份逻辑只该有一处。
import (
"strings"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
// inboundContent 是一次入站内容摄取/内联的产物。
type inboundContent struct {
// parts 是要挂到 RoleUser 消息上的内容部件(文档部件,或 data: URI 图片部件)。
parts []model.Content
// notices 是「读不到」的诚实提示行,顺序与消息里的媒体顺序一致。
notices []string
}
// noticeText 把提示行拼成一段文本;没有提示时返回空串(调用方据此不塞空文本部件)。
func (c inboundContent) noticeText() string {
return strings.Join(c.notices, "\n")
}
// attachInboundContent 把入站内容制品挂到消息列表里的**用户回合**上(design/24 §3/§4.4):
// 部件与「读不到」的诚实提示行都只进 `RoleUser`,且挂在那条已构建好的用户消息上 ——
// 来源系统行、第三方边界、SenderName 等既有装配因此逐字不变(本切片不重排消息,只追加
// 部件)。
//
// groups 按给出顺序逐组追加(文档路先、图片路后),空组是空操作 —— 两条路互不影响:
// 同一条消息既带文档又带图片时,两条都挂得上,各自只贡献自己的部件与自己的提示行。
// 一个回合只有一条用户消息(buildLoopMessages 的既有形状),因此挂载点只有一处。
// 文本部件为空且既有文本也为空时**不塞空文本部件**(provider 会拒):部件本身或提示行
// 就是这条消息的内容。
func attachInboundContent(msgs []model.Message, groups ...inboundContent) {
idx := userTurnIndex(msgs)
if idx < 0 {
return
}
for _, g := range groups {
if len(g.parts) == 0 && len(g.notices) == 0 {
continue
}
msgs[idx].Content = append(msgs[idx].Content, g.parts...)
if notice := g.noticeText(); notice != "" {
msgs[idx].Content = append(msgs[idx].Content, model.Content{Type: model.ContentTypeText, Text: notice})
}
}
}
// userTurnIndex 返回消息列表里第一条 RoleUser 消息的下标(没有则 -1)。
func userTurnIndex(msgs []model.Message) int {
for i := range msgs {
if msgs[i].Role == model.RoleUser {
return i
}
}
return -1
}