diff --git a/internal/app/app.go b/internal/app/app.go index ccb6477..547b314 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -707,10 +707,26 @@ func splitKeyPool(s string) []string { return out } -// busAdapter EXT-14:cmdbus.Bus 适配 runmgr.CommandSource(工具投影 + 命令分发)。 +// busAdapter EXT-14:cmdbus.Bus 适配 runmgr.CommandSource。视图类型转换在此收口 +// (runmgr 不依赖 cmdbus,边不进架构基线);Entrance 由 runmgr 固定为 agent。 type busAdapter struct{ bus *cmdbus.Bus } -func (a busAdapter) CommandTools() []cmdbus.CommandTool { return a.bus.CommandTools() } -func (a busAdapter) DispatchCommand(ctx context.Context, req cmdbus.Request) cmdbus.Response { - return a.bus.Dispatch(ctx, req) +func (a busAdapter) CommandTools() []runmgr.CommandTool { + src := a.bus.CommandTools() + out := make([]runmgr.CommandTool, len(src)) + for i, ct := range src { + out[i] = runmgr.CommandTool{ID: ct.ID, Description: ct.Description, Params: ct.Params, Risk: ct.Risk} + } + return out +} + +func (a busAdapter) DispatchCommand(ctx context.Context, req runmgr.CommandRequest) runmgr.CommandResponse { + resp := a.bus.Dispatch(ctx, cmdbus.Request{ + ID: req.ID, Params: req.Params, Entrance: req.Entrance, + Actor: req.Actor, Owner: req.Owner, ConversationID: req.ConversationID, + }) + return runmgr.CommandResponse{ + State: string(resp.Receipt.State), Reason: resp.Receipt.Reason, + Payload: resp.Payload, Card: resp.Card != nil, + } } diff --git a/internal/runmgr/command_tools_test.go b/internal/runmgr/command_tools_test.go index 11ed42d..9ea10e6 100644 --- a/internal/runmgr/command_tools_test.go +++ b/internal/runmgr/command_tools_test.go @@ -8,26 +8,21 @@ import ( "context" "testing" - agentcommand "agent-command" - "agent-system-backend/internal/cmdbus" "agent-system-backend/internal/tools" core "agent-system-core" ) -func agentcommandCommitted() agentcommand.ExecReceipt { - return agentcommand.ExecReceipt{State: agentcommand.StateCommitted} -} - -// fakeBusSource EXT-14 测试桩:命令清单 + 分发记录。 +// fakeBusSource EXT-14 测试桩:命令清单 + 分发记录(说话用 runmgr 视图类型, +// 与生产代码同口径——runmgr 不依赖 cmdbus)。 type fakeBusSource struct { - cmds []cmdbus.CommandTool - lastReq cmdbus.Request - resp cmdbus.Response + cmds []CommandTool + lastReq CommandRequest + resp CommandResponse } -func (f *fakeBusSource) CommandTools() []cmdbus.CommandTool { return f.cmds } +func (f *fakeBusSource) CommandTools() []CommandTool { return f.cmds } -func (f *fakeBusSource) DispatchCommand(ctx context.Context, req cmdbus.Request) cmdbus.Response { +func (f *fakeBusSource) DispatchCommand(ctx context.Context, req CommandRequest) CommandResponse { f.lastReq = req return f.resp } @@ -35,8 +30,8 @@ func (f *fakeBusSource) DispatchCommand(ctx context.Context, req cmdbus.Request) func TestCommandToolsProjected(t *testing.T) { rc0, _ := newExecEnv(t) m := rc0.mgr - src := &fakeBusSource{cmds: []cmdbus.CommandTool{ - {ID: "rdm.trace", Title: "追溯查询", Description: "查追溯网", Params: []byte(`{"type":"object"}`), Risk: "low"}, + src := &fakeBusSource{cmds: []CommandTool{ + {ID: "rdm.trace", Description: "查追溯网", Params: []byte(`{"type":"object"}`), Risk: "low"}, }} m.SetCommandSource(src) rc := rc0 @@ -57,8 +52,8 @@ func TestCommandToolDispatchesThroughBus(t *testing.T) { rc0, _ := newExecEnv(t) m := rc0.mgr src := &fakeBusSource{ - cmds: []cmdbus.CommandTool{{ID: "rdm.trace", Title: "追溯查询", Params: []byte(`{"type":"object"}`), Risk: "low"}}, - resp: cmdbus.Response{Receipt: agentcommandCommitted()}, + cmds: []CommandTool{{ID: "rdm.trace", Params: []byte(`{"type":"object"}`), Risk: "low"}}, + resp: CommandResponse{State: "committed"}, } m.SetCommandSource(src) rc := rc0 diff --git a/internal/runmgr/runmgr.go b/internal/runmgr/runmgr.go index 3492cab..6268be4 100644 --- a/internal/runmgr/runmgr.go +++ b/internal/runmgr/runmgr.go @@ -24,7 +24,6 @@ import ( "agent-system-backend/internal/bus" "agent-system-backend/internal/cardsvc" - "agent-system-backend/internal/cmdbus" "agent-system-backend/internal/ingest" "agent-system-backend/internal/intentgate" "agent-system-backend/internal/profiles" @@ -177,10 +176,38 @@ func (m *Manager) SetIndexer(i core.DocumentIndexer) { m.indexer = i } func (m *Manager) SetWorkspaceRoot(dir string) { m.workspaceRoot = dir } // CommandSource EXT-14:命令总线暴露给回合执行的两个面——工具投影清单与 -// 经命令总的分发(同审计信封与 HITL 收口)。组合根以 cmdbus.Bus 适配注入。 +// 经命令总的分发(同审计信封与 HITL 收口)。runmgr 只认本包视图类型, +// 组合根以 cmdbus.Bus 适配注入(app.busAdapter 负责转换),runmgr 不依赖总线包。 type CommandSource interface { - CommandTools() []cmdbus.CommandTool - DispatchCommand(ctx context.Context, req cmdbus.Request) cmdbus.Response + CommandTools() []CommandTool + DispatchCommand(ctx context.Context, req CommandRequest) CommandResponse +} + +// CommandTool EXT-14 工具投影视图:组合根从命令总线的投影清单转换注入。 +type CommandTool struct { + ID string + Description string + Params json.RawMessage + Risk string +} + +// CommandRequest 一次命令工具分发请求(runmgr 固定以 Entrance=agent 发起, +// Actor/Owner 绑定会话 owner、带会话上下文)。 +type CommandRequest struct { + ID string + Params map[string]any + Entrance string + Actor string + Owner string + ConversationID string +} + +// CommandResponse 分发结果视图:回执状态/原因 + 负载 + 是否挂起确认卡。 +type CommandResponse struct { + State string + Reason string + Payload any + Card bool } // sharedRetriever EXT-13:检索器具备共享通道(rag.Pipeline.RetrieveShared 同形)。 @@ -824,19 +851,18 @@ func (c *runCtx) ExecuteTool(call core.ToolCallRequest) core.ToolCallResult { if len(call.Arguments) > 0 { _ = json.Unmarshal(call.Arguments, ¶ms) } - resp := c.mgr.commands.DispatchCommand(c.ctx, cmdbus.Request{ + resp := c.mgr.commands.DispatchCommand(c.ctx, CommandRequest{ ID: call.Name, Params: params, Entrance: "agent", Actor: c.run.Owner, Owner: c.run.Owner, ConversationID: c.run.ConversationID, }) out, _ := json.Marshal(resp.Payload) - state := string(resp.Receipt.State) - if resp.Card != nil && state == "accepted" { + if resp.Card && resp.State == "accepted" { return core.ToolCallResult{CallID: call.CallID, Status: "ok", - Output: "已创建确认卡,等待用户确认后执行:" + resp.Receipt.Reason} + Output: "已创建确认卡,等待用户确认后执行:" + resp.Reason} } - if state != "committed" && state != "accepted" { + if resp.State != "committed" && resp.State != "accepted" { return core.ToolCallResult{CallID: call.CallID, Status: "error", - Output: "命令 " + call.Name + " " + state + ": " + resp.Receipt.Reason} + Output: "命令 " + call.Name + " " + resp.State + ": " + resp.Reason} } return core.ToolCallResult{CallID: call.CallID, Status: "ok", Output: string(out)} }