签到工具新增检查功能:修复状态误判问题

问题:
- 用户询问'我今天签到了吗'时,AI基于对话历史判断而非查询数据库
- 导致明明没签到,AI却说已经签到了(误判)

解决方案:
- 新增 action=check 操作,专门用于检查当前节点今天是否已签到
- 直接调用 HasSignedOnDay 查询数据库,返回准确的签到状态
- AI 现在会强制调用工具查询,而不是根据记忆猜测

改动内容:
- 工具定义中添加 check 操作类型
- 实现 executeCheck 方法,查询数据库并返回明确状态
- 添加完整的单元测试(未签到/已签到两种场景)
- 更新文档说明 check 操作的使用

使用示例:
- 用户:'我今天签到了吗?'
- AI 调用:{"action": "check"}
- 返回:'XXX 今天还没有签到。' 或 'XXX 今天已经签到过了。'

测试:
-  未签到场景测试通过
-  已签到场景测试通过
-  所有签到工具测试通过
-  项目编译成功

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 21:37:44 +08:00
co-authored by Claude Fable 5
parent bd25b79724
commit 57cca6bb7a
3 changed files with 161 additions and 7 deletions
+97
View File
@@ -218,3 +218,100 @@ func TestSignTool_SignAction(t *testing.T) {
t.Errorf("Expected 1 sign record, got %d", len(store.signs))
}
}
func TestSignTool_CheckAction(t *testing.T) {
now := time.Date(2024, 6, 23, 12, 0, 0, 0, time.UTC)
// 测试场景1:今天未签到
t.Run("今天未签到", func(t *testing.T) {
store := &mockSignStore{
signs: []storepkg.SignRecord{},
nodeInfoMap: make(map[string]*storepkg.NodeInfoRecord),
}
tool := &Tool{
enabled: true,
store: store,
}
params := signParams{
Action: "check",
}
argsJSON, _ := json.Marshal(params)
nodeCtx := agenttool.NodeContext{
NodeID: "test_node_123",
LongName: "Test Node",
ShortName: "TN",
}
ctx := agenttool.WithNodeContext(context.Background(), nodeCtx)
runtime := agenttool.Runtime{Now: now}
result, err := tool.Execute(ctx, string(argsJSON), runtime)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
t.Logf("Check result (not signed): %s", result)
if !contains(result, "还没有签到") && !contains(result, "没有签到") {
t.Errorf("Expected result to indicate not signed yet")
}
})
// 测试场景2:今天已签到
t.Run("今天已签到", func(t *testing.T) {
store := &mockSignStore{
signs: []storepkg.SignRecord{
{
NodeID: "test_node_123",
SignText: "上海-TestUser-TestDevice签到",
SignTime: now,
},
},
nodeInfoMap: make(map[string]*storepkg.NodeInfoRecord),
}
tool := &Tool{
enabled: true,
store: store,
}
params := signParams{
Action: "check",
}
argsJSON, _ := json.Marshal(params)
nodeCtx := agenttool.NodeContext{
NodeID: "test_node_123",
LongName: "Test Node",
ShortName: "TN",
}
ctx := agenttool.WithNodeContext(context.Background(), nodeCtx)
runtime := agenttool.Runtime{Now: now}
result, err := tool.Execute(ctx, string(argsJSON), runtime)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
t.Logf("Check result (already signed): %s", result)
if !contains(result, "已经签到") {
t.Errorf("Expected result to indicate already signed")
}
})
}
func contains(s, substr string) bool {
return len(s) > 0 && len(substr) > 0 && (s == substr || len(s) >= len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || containsMiddle(s, substr)))
}
func containsMiddle(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}