ACP / MCP 完善

This commit is contained in:
2026-06-11 12:43:18 +08:00
parent 1415d3b43b
commit 0561e126cd
22 changed files with 786 additions and 219 deletions
+69 -2
View File
@@ -281,9 +281,11 @@ func TestUpdateTitleAndDeleteConversation(t *testing.T) {
}
func TestSendMessage(t *testing.T) {
deps, _, msgSvc, _ := chatTestDeps()
deps, convSvc, msgSvc, _ := chatTestDeps()
cv := chat.Conversation{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), CreatedAt: time.Now(), UpdatedAt: time.Now()}
convSvc.items = []chat.Conversation{cv}
result, err := callTool(ctxWithAuth(Scope{}), deps, "send_message", map[string]any{
"conversation_id": uuid.New().String(), "content": "hello",
"conversation_id": cv.ID.String(), "content": "hello",
})
require.NoError(t, err)
require.False(t, result.IsError)
@@ -294,6 +296,71 @@ func TestSendMessage(t *testing.T) {
assert.Equal(t, "hello", msgSvc.sentContent)
}
// TestConversationTools_ScopeDenied 受限 token 直访 scope 外 project 挂载的会话 → 全部拒绝。
func TestConversationTools_ScopeDenied(t *testing.T) {
deps, convSvc, _, _ := chatTestDeps()
projB := uuid.New()
cvB := chat.Conversation{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), ProjectID: &projB, CreatedAt: time.Now(), UpdatedAt: time.Now()}
convSvc.items = []chat.Conversation{cvB}
// token 限定到 testPID,cvB 挂载在 projB 上 → 拒绝
ctx := ctxWithAuth(Scope{ProjectIDs: []uuid.UUID{testPID}})
cases := []struct {
tool string
args map[string]any
}{
{"list_recent_messages", map[string]any{"conversation_id": cvB.ID.String()}},
{"get_conversation", map[string]any{"conversation_id": cvB.ID.String()}},
{"update_conversation_title", map[string]any{"conversation_id": cvB.ID.String(), "title": "t"}},
{"delete_conversation", map[string]any{"conversation_id": cvB.ID.String()}},
{"send_message", map[string]any{"conversation_id": cvB.ID.String(), "content": "hi"}},
}
for _, tc := range cases {
result, err := callTool(ctx, deps, tc.tool, tc.args)
require.NoError(t, err, tc.tool)
assert.True(t, result.IsError, tc.tool)
}
// 被拒绝的 delete/update 不应实际生效
require.Len(t, convSvc.items, 1)
assert.Nil(t, convSvc.items[0].Title)
}
// TestConversationTools_PersonalNotScoped ProjectID 为 nil 的个人会话不受 project scope 约束。
func TestConversationTools_PersonalNotScoped(t *testing.T) {
deps, convSvc, _, _ := chatTestDeps()
cv := chat.Conversation{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), CreatedAt: time.Now(), UpdatedAt: time.Now()}
convSvc.items = []chat.Conversation{cv}
result, err := callTool(ctxWithAuth(Scope{ProjectIDs: []uuid.UUID{uuid.New()}}), deps,
"get_conversation", map[string]any{"conversation_id": cv.ID.String()})
require.NoError(t, err)
assert.False(t, result.IsError)
}
// TestListConversations_ScopeFiltered 无 project filter 时静默剔除 scope 外项目挂载的会话。
func TestListConversations_ScopeFiltered(t *testing.T) {
deps, convSvc, _, _ := chatTestDeps()
pidA := testPID
projB := uuid.New()
convSvc.items = []chat.Conversation{
{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), ProjectID: &pidA, CreatedAt: time.Now(), UpdatedAt: time.Now()},
{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), ProjectID: &projB, CreatedAt: time.Now(), UpdatedAt: time.Now()},
{ID: uuid.New(), UserID: testUID, ModelID: uuid.New(), CreatedAt: time.Now(), UpdatedAt: time.Now()},
}
result, err := callTool(ctxWithAuth(Scope{ProjectIDs: []uuid.UUID{pidA}}), deps,
"list_conversations", map[string]any{})
require.NoError(t, err)
require.False(t, result.IsError)
var out listConversationsOut
unmarshalStructured(t, result, &out)
// projA 挂载 + 无挂载的保留,projB 挂载的被剔除
require.Len(t, out.Conversations, 2)
for _, cv := range out.Conversations {
assert.NotEqual(t, projB.String(), cv.ProjectID)
}
}
func TestPromptTemplateCRUD(t *testing.T) {
deps, _, _, tplSvc := chatTestDeps()