refactor(gateway+model): 拆 gateway/server.go 719→204 + 重构 scanSSE/processFrom 到 ≤80行
- server.go 204 + 新 routes.go(193,路由注册/Handler/withMiddleware)/deps.go(108)/contracts.go(231,17依赖接口)/broadcast.go(78,BroadcastPersisted/CapacityAwaken/Mood); 导出面不变; 74条路由pattern+RBAC门逐条比对一致 - model/openai_stream.go: scanSSE 138→25(parse/apply/finalize 对齐 anthropic_stream); openaiStreamState结构体 - channelbridge/inbound.go: processFrom 112→46(blacklistDrop/inboundTargetFor/runInboundTurn/deliverReply) - 纯行为等价; build/vet/test绿(56包)+win/darwin交叉编译
This commit is contained in:
1 parent
4c3c98d5d4
commit
4ea68d17f3
7 files changed
+844
-654
No files matched your search
@@ -115,14 +115,7 @@ func (b *Bridge) processFrom(ctx context.Context, msg adapter.UnifiedMessage, a
|
||||
// blacklisted/non-whitelisted group or user message never reaches the LLM. The
|
||||
// owner is always allowed (structural, via the resolved actor).
|
||||
actor := session.ResolveActor(msg, b.owner)
|
||||
if actor.IsOwner() {
|
||||
// fall through: owner messages are never blacklisted
|
||||
} else if denied, reason := b.blacklisted(msg, a); denied {
|
||||
b.log.Warn("inbound message blacklisted, dropped",
|
||||
"platform", msg.Platform, "channel", msg.ChannelID, "reason", reason)
|
||||
if b.onRejected != nil {
|
||||
b.onRejected(msg, reason)
|
||||
}
|
||||
if !actor.IsOwner() && b.blacklistDrop(msg, a) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -153,17 +146,56 @@ func (b *Bridge) processFrom(ctx context.Context, msg adapter.UnifiedMessage, a
|
||||
}
|
||||
}
|
||||
|
||||
// design/16 §4.4 + design/02 §3: an owner private chat is routed INTO the single
|
||||
// main web session (shared across platforms) and persisted to chat_messages with
|
||||
// the channel platform, so the Web client mirrors it; group chats and strangers
|
||||
// keep their isolated sess-xxx context and their own platform log.
|
||||
sessID := sess.SessionID
|
||||
isOwnerPrivate := !sess.IsGroup && sess.Owner
|
||||
platform := ""
|
||||
if isOwnerPrivate {
|
||||
sessID = history.MainSessionID
|
||||
platform = msg.Platform
|
||||
b.runInboundTurn(ctx, msg, a, text, actor, sess)
|
||||
}
|
||||
|
||||
// blacklistDrop applies the black-or-white list to a non-owner message, reporting
|
||||
// whether it must be dropped (design/16 §4.6 §6). A dropped message is audited
|
||||
// through the OnRejected hook so the decision is visible in the panel.
|
||||
func (b *Bridge) blacklistDrop(msg adapter.UnifiedMessage, a adapter.PlatformAdapter) bool {
|
||||
denied, reason := b.blacklisted(msg, a)
|
||||
if !denied {
|
||||
return false
|
||||
}
|
||||
b.log.Warn("inbound message blacklisted, dropped",
|
||||
"platform", msg.Platform, "channel", msg.ChannelID, "reason", reason)
|
||||
if b.onRejected != nil {
|
||||
b.onRejected(msg, reason)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// inboundTarget is where one admitted inbound message is persisted and mirrored
|
||||
// (design/16 §4.4 + design/02 §3): an owner private chat is routed into the single
|
||||
// main web session with the channel platform stamped so the Web client mirrors it,
|
||||
// while a restricted group/stranger conversation keeps its isolated sess-xxx
|
||||
// session and its own platform log.
|
||||
type inboundTarget struct {
|
||||
// sessionID is the session the turn runs in.
|
||||
sessionID string
|
||||
// private marks an owner private chat mirrored into the main web session.
|
||||
private bool
|
||||
// platform is the mirrored chat_messages platform tag (private only).
|
||||
platform string
|
||||
}
|
||||
|
||||
// inboundTargetFor resolves the routing target from the structurally resolved
|
||||
// session and the message's platform. Only a non-group owner conversation is
|
||||
// mirrored; everything else stays in its isolated session.
|
||||
func inboundTargetFor(sess session.Session, platform string) inboundTarget {
|
||||
if !sess.IsGroup && sess.Owner {
|
||||
return inboundTarget{sessionID: history.MainSessionID, private: true, platform: platform}
|
||||
}
|
||||
return inboundTarget{sessionID: sess.SessionID}
|
||||
}
|
||||
|
||||
// runInboundTurn drives the agent turn for an admitted message: it resolves the
|
||||
// routing target, builds the model-visible message list, persists the inbound user
|
||||
// message before the turn (so it is durable even if the channel reply fails), runs
|
||||
// the loop and hands the result to deliverReply.
|
||||
func (b *Bridge) runInboundTurn(ctx context.Context, msg adapter.UnifiedMessage, a adapter.PlatformAdapter,
|
||||
text string, actor adapter.Actor, sess session.Session) {
|
||||
target := inboundTargetFor(sess, msg.Platform)
|
||||
|
||||
// The third-party boundary only applies in a restricted (group/stranger)
|
||||
// context: memory is read-only (MemWritable=false), and the sender name is
|
||||
@@ -174,41 +206,48 @@ func (b *Bridge) processFrom(ctx context.Context, msg adapter.UnifiedMessage, a
|
||||
senderName := senderDisplayName(msg, actor)
|
||||
loopMsgs := b.buildLoopMessages(ctx, text, runEnv, actor, senderName, msg)
|
||||
|
||||
// Persist the inbound user message before the turn so it is durable even if the
|
||||
// channel reply fails. Owner-private messages land in the main web session and
|
||||
// are broadcast to the Web client; restricted messages land in their isolated
|
||||
// session (the adapter log page) and are broadcast as a `channel_persisted` event
|
||||
// (never into the main/`web` session or the web chat).
|
||||
if isOwnerPrivate {
|
||||
b.persistToMain(ctx, history.RoleUser, text, "", platform, deviceIDFor(msg), adapterName(a))
|
||||
// Owner-private messages land in the main web session and are broadcast to the
|
||||
// Web client; restricted messages land in their isolated session (the adapter log
|
||||
// page) and are broadcast as a `channel_persisted` event (never into the
|
||||
// main/`web` session or the web chat).
|
||||
if target.private {
|
||||
b.persistToMain(ctx, history.RoleUser, text, "", target.platform, deviceIDFor(msg), adapterName(a))
|
||||
} else {
|
||||
b.persistIsolated(ctx, history.RoleUser, text, deviceIDFor(msg), sess, msg.Platform, senderName, adapterName(a))
|
||||
}
|
||||
|
||||
res, err := b.run.Run(loop.WithSessionEnv(ctx, runEnv), sessID, loopMsgs)
|
||||
res, err := b.run.Run(loop.WithSessionEnv(ctx, runEnv), target.sessionID, loopMsgs)
|
||||
if err != nil {
|
||||
b.log.Warn("agent run failed", "platform", msg.Platform,
|
||||
"session", sessID, "error", err)
|
||||
"session", target.sessionID, "error", err)
|
||||
return
|
||||
}
|
||||
b.deliverReply(ctx, msg, a, sess, target, res)
|
||||
}
|
||||
|
||||
// deliverReply persists the assistant reply and sends it back through the adapter
|
||||
// that received the message. An adapter that does not support outbound text
|
||||
// (adapter.ErrUnsupported) is a debug-level skip, not a failure: the reply is
|
||||
// already durable in the history store.
|
||||
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", sessID)
|
||||
b.log.Debug("no reply produced", "platform", msg.Platform, "session", target.sessionID)
|
||||
return
|
||||
}
|
||||
// Persist the assistant reply (owner-private → main session + message_persisted
|
||||
// broadcast; restricted → isolated log + channel_persisted broadcast) then
|
||||
// deliver it back to the channel.
|
||||
if isOwnerPrivate {
|
||||
b.persistToMain(ctx, history.RoleAssistant, reply, res.Mood, platform, deviceIDFor(msg), adapterName(a))
|
||||
if target.private {
|
||||
b.persistToMain(ctx, history.RoleAssistant, reply, res.Mood, target.platform, deviceIDFor(msg), adapterName(a))
|
||||
} else {
|
||||
b.persistIsolated(ctx, history.RoleAssistant, reply, "", sess, msg.Platform, "", adapterName(a))
|
||||
}
|
||||
if err := b.sendReply(ctx, msg, a, reply); err != nil {
|
||||
if errors.Is(err, adapter.ErrUnsupported) {
|
||||
b.log.Debug("channel does not support outbound reply, skipped",
|
||||
"platform", msg.Platform, "session", sessID)
|
||||
"platform", msg.Platform, "session", target.sessionID)
|
||||
return
|
||||
}
|
||||
b.log.Warn("send reply failed", "platform", msg.Platform, "error", err)
|
||||
|
||||
Reference in new issue
Block a user