ci / vet-and-test (pull_request) Successful in 42s
Why: Generative UI U3 - the agent needs a real submission path and the next turn needs to see prior pages: a built-in in-process plugin registers generative-ui.present (exposeAsTool) carrying the catalog (prompt=validation single source) with a schema-repair strategy measured against real MiniMax-M3 deviations; the command bus gains an owner-scoped tool gate so a disabled plugin stops injecting its tool (execution guard remains in surfacesvc); ctxasm projects saved surfaces back into context so the model can revise existing structure; doc-refs are authorized against the owner's real artifacts. Evidence: unit suites green (genui guards/epoch/doc-ref, gate fail-closed, projection content); full go test ./... green; cmdbus/ctxasm also green under AGENT_PG_TEST_DSN; real-model closed loop (env-gated TestRealModelSurfaceLoop) passes: task->spec->save->projection->revise with revision 1->2 and structure change, CNY 0.08 total. Impact: New internal/genui package; additive cmdbus/ctxasm/runmgr/ runtime hooks; no storage or contract changes (U2 layer untouched). Refs: Documents proposal r2 U3; Core PR #25/#26; Backend #143; Dev task feature/generative-ui-u3
85 lines
2.9 KiB
Go
85 lines
2.9 KiB
Go
package runmgr
|
|
|
|
// EXT-14 红测(提案 2026-10-09-ext-g1-b1-b3 §2):带 exposeAsTool 的命令投影为
|
|
// 回合内工具;模型调用经命令总分发(Entrance="agent"、同审计信封);不带字段的
|
|
// 命令不出现;高危命令在对话内弹内联确认卡(HITL 收口不变)。
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"agent-system-backend/internal/tools"
|
|
core "agent-system-core"
|
|
)
|
|
|
|
// fakeBusSource EXT-14 测试桩:命令清单 + 分发记录(说话用 runmgr 视图类型,
|
|
// 与生产代码同口径——runmgr 不依赖 cmdbus)。
|
|
type fakeBusSource struct {
|
|
cmds []CommandTool
|
|
lastReq CommandRequest
|
|
resp CommandResponse
|
|
}
|
|
|
|
func (f *fakeBusSource) CommandTools() []CommandTool { return f.cmds }
|
|
|
|
func (f *fakeBusSource) CommandToolsFor(owner string) []CommandTool { return f.cmds }
|
|
|
|
func (f *fakeBusSource) DispatchCommand(ctx context.Context, req CommandRequest) CommandResponse {
|
|
f.lastReq = req
|
|
return f.resp
|
|
}
|
|
|
|
func TestCommandToolsProjected(t *testing.T) {
|
|
rc0, _ := newExecEnv(t)
|
|
m := rc0.mgr
|
|
src := &fakeBusSource{cmds: []CommandTool{
|
|
{ID: "rdm.trace", Description: "查追溯网", Params: []byte(`{"type":"object"}`), Risk: "low"},
|
|
}}
|
|
m.SetCommandSource(src)
|
|
rc := rc0
|
|
tools := rc.Tools()
|
|
found := map[string]bool{}
|
|
for _, d := range tools {
|
|
found[d.Name] = true
|
|
}
|
|
if !found["rdm.trace"] {
|
|
t.Fatalf("exposeAsTool 命令未投影为工具: %+v", tools)
|
|
}
|
|
if found["rdm.hidden"] {
|
|
t.Fatal("命令源之外的工具不得出现")
|
|
}
|
|
}
|
|
|
|
func TestCommandToolDispatchesThroughBus(t *testing.T) {
|
|
rc0, _ := newExecEnv(t)
|
|
m := rc0.mgr
|
|
src := &fakeBusSource{
|
|
cmds: []CommandTool{{ID: "rdm.trace", Params: []byte(`{"type":"object"}`), Risk: "low"}},
|
|
resp: CommandResponse{State: "committed"},
|
|
}
|
|
m.SetCommandSource(src)
|
|
rc := rc0
|
|
|
|
res := rc.ExecuteTool(core.ToolCallRequest{CallID: "c1", Name: "rdm.trace", Arguments: []byte(`{"q":"x"}`)})
|
|
if res.Status != "ok" {
|
|
t.Fatalf("dispatch result = %s %s", res.Status, res.Output)
|
|
}
|
|
req := src.lastReq
|
|
if req.ID != "rdm.trace" || req.Entrance != "agent" || req.Actor != rc.run.Owner || req.Owner != rc.run.Owner || req.ConversationID != rc.run.ConversationID {
|
|
t.Fatalf("bus request = %+v(须 Entrance=agent、Actor/Owner=会话 owner、带会话)", req)
|
|
}
|
|
if req.Params["q"] != "x" {
|
|
t.Fatalf("params = %+v", req.Params)
|
|
}
|
|
// 未注册命令源时:调用按注册表口径报错(现状),不 panic。
|
|
reg2 := tools.NewRegistry()
|
|
if err := reg2.RegisterBuiltin(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m2 := New(nil, nil, reg2, nil, nil, nil, nil, nil, nil)
|
|
rc2 := &runCtx{mgr: m2, run: core.Run{Owner: "bob"}, prof: core.AgentProfile{Tools: core.ToolPolicy{Allow: []string{"*"}}}}
|
|
if res := rc2.ExecuteTool(core.ToolCallRequest{CallID: "c2", Name: "rdm.trace", Arguments: []byte(`{}`)}); res.Status != "error" {
|
|
t.Fatalf("no source: %s(须 registry miss 报错)", res.Status)
|
|
}
|
|
}
|