improved tool debugging
This commit is contained in:
+121
-121
@@ -1,152 +1,152 @@
|
||||
package sidekick
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
)
|
||||
|
||||
func TestMCPServerQueryHandler(t *testing.T) {
|
||||
// 1. Setup Agent with mock LLM
|
||||
ac := AgentConfig{ID: "test-agent", Role: RoleSpecialist, MaxIterations: 2}
|
||||
mCfg := ModelConfig{}
|
||||
agent := NewSidekick(ac, mCfg, nil)
|
||||
// 1. Setup Agent with mock LLM
|
||||
ac := AgentConfig{ID: "test-agent", Role: RoleSpecialist, MaxIterations: 2}
|
||||
mCfg := ModelConfig{}
|
||||
agent := NewSidekick(ac, mCfg, nil)
|
||||
|
||||
mockLLM := &mockLLMClient{
|
||||
responses: []Message{
|
||||
{Content: `{"action": "RESPOND", "params": {"response": "I am Sidekick. How can I help?"}}`},
|
||||
},
|
||||
}
|
||||
SetLLMClient(mockLLM)
|
||||
mockLLM := &mockLLMClient{
|
||||
responses: []Message{
|
||||
{Content: `{"action": "RESPOND", "params": {"response": "I am Sidekick. How can I help?"}}`},
|
||||
},
|
||||
}
|
||||
SetLLMClient(mockLLM)
|
||||
|
||||
pool := map[string]*Sidekick{"test-agent": agent}
|
||||
pool := map[string]*Sidekick{"test-agent": agent}
|
||||
|
||||
// 2. Define the handler (mirrors logic in cmd/sidekick-mcp/main.go)
|
||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
msg, err := request.RequireString("message")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 2. Define the handler (mirrors logic in cmd/sidekick-mcp/main.go)
|
||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
msg, err := request.RequireString("message")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var inCtx []Message
|
||||
args := request.GetArguments()
|
||||
if histInter, ok := args["history"]; ok {
|
||||
if histList, ok := histInter.([]interface{}); ok {
|
||||
for _, h := range histList {
|
||||
if hMap, ok := h.(map[string]interface{}); ok {
|
||||
role, _ := hMap["role"].(string)
|
||||
content, _ := hMap["content"].(string)
|
||||
if role != "" && content != "" {
|
||||
inCtx = append(inCtx, Message{
|
||||
Role: MessageRole(role),
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var inCtx []Message
|
||||
args := request.GetArguments()
|
||||
if histInter, ok := args["history"]; ok {
|
||||
if histList, ok := histInter.([]interface{}); ok {
|
||||
for _, h := range histList {
|
||||
if hMap, ok := h.(map[string]interface{}); ok {
|
||||
role, _ := hMap["role"].(string)
|
||||
content, _ := hMap["content"].(string)
|
||||
if role != "" && content != "" {
|
||||
inCtx = append(inCtx, Message{
|
||||
Role: MessageRole(role),
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inCtx = append(inCtx, Message{
|
||||
Role: MessageRoleUser,
|
||||
Content: msg,
|
||||
})
|
||||
inCtx = append(inCtx, Message{
|
||||
Role: MessageRoleUser,
|
||||
Content: msg,
|
||||
})
|
||||
|
||||
responseStr, err := agent.Run(ctx, inCtx, pool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
responseStr, err := agent.Run(ctx, inCtx, pool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outHistory := append(inCtx, Message{
|
||||
Role: MessageRole("assistant"),
|
||||
Content: responseStr,
|
||||
})
|
||||
outHistory := append(inCtx, Message{
|
||||
Role: MessageRole("assistant"),
|
||||
Content: responseStr,
|
||||
})
|
||||
|
||||
resultObj := map[string]interface{}{
|
||||
"response": responseStr,
|
||||
"history": outHistory,
|
||||
}
|
||||
resultObj := map[string]interface{}{
|
||||
"response": responseStr,
|
||||
"history": outHistory,
|
||||
}
|
||||
|
||||
resultBytes, _ := json.Marshal(resultObj)
|
||||
resultBytes, _ := json.Marshal(resultObj)
|
||||
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.NewTextContent(string(resultBytes)),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.NewTextContent(string(resultBytes)),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 3. Test with simple message
|
||||
req := mcp.CallToolRequest{}
|
||||
req.Params.Name = "query"
|
||||
req.Params.Arguments = map[string]interface{}{
|
||||
"message": "Hello",
|
||||
}
|
||||
// 3. Test with simple message
|
||||
req := mcp.CallToolRequest{}
|
||||
req.Params.Name = "query"
|
||||
req.Params.Arguments = map[string]interface{}{
|
||||
"message": "Hello",
|
||||
}
|
||||
|
||||
res, err := handler(context.Background(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("handler failed: %v", err)
|
||||
}
|
||||
res, err := handler(context.Background(), req)
|
||||
if err != nil {
|
||||
t.Fatalf("handler failed: %v", err)
|
||||
}
|
||||
|
||||
if len(res.Content) != 1 {
|
||||
t.Fatalf("expected 1 content item, got %d", len(res.Content))
|
||||
}
|
||||
if len(res.Content) != 1 {
|
||||
t.Fatalf("expected 1 content item, got %d", len(res.Content))
|
||||
}
|
||||
|
||||
textContent, ok := res.Content[0].(mcp.TextContent)
|
||||
if !ok {
|
||||
t.Fatalf("expected TextContent")
|
||||
}
|
||||
textContent, ok := res.Content[0].(mcp.TextContent)
|
||||
if !ok {
|
||||
t.Fatalf("expected TextContent")
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(textContent.Text), &result); err != nil {
|
||||
t.Fatalf("failed to unmarshal result: %v", err)
|
||||
}
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(textContent.Text), &result); err != nil {
|
||||
t.Fatalf("failed to unmarshal result: %v", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(result["response"].(string), "How can I help?") {
|
||||
t.Errorf("unexpected response: %v", result["response"])
|
||||
}
|
||||
if !strings.Contains(result["response"].(string), "How can I help?") {
|
||||
t.Errorf("unexpected response: %v", result["response"])
|
||||
}
|
||||
|
||||
history, ok := result["history"].([]interface{})
|
||||
if !ok || len(history) != 2 {
|
||||
t.Errorf("expected history of length 2, got %v", len(history))
|
||||
}
|
||||
history, ok := result["history"].([]interface{})
|
||||
if !ok || len(history) != 2 {
|
||||
t.Errorf("expected history of length 2, got %v", len(history))
|
||||
}
|
||||
|
||||
// 4. Test with history
|
||||
reqWithHist := mcp.CallToolRequest{}
|
||||
reqWithHist.Params.Name = "query"
|
||||
reqWithHist.Params.Arguments = map[string]interface{}{
|
||||
"message": "What did I say?",
|
||||
"history": []interface{}{
|
||||
map[string]interface{}{"role": "user", "content": "I like cats"},
|
||||
map[string]interface{}{"role": "assistant", "content": "Me too"},
|
||||
},
|
||||
}
|
||||
// 4. Test with history
|
||||
reqWithHist := mcp.CallToolRequest{}
|
||||
reqWithHist.Params.Name = "query"
|
||||
reqWithHist.Params.Arguments = map[string]interface{}{
|
||||
"message": "What did I say?",
|
||||
"history": []interface{}{
|
||||
map[string]interface{}{"role": "user", "content": "I like cats"},
|
||||
map[string]interface{}{"role": "assistant", "content": "Me too"},
|
||||
},
|
||||
}
|
||||
|
||||
// Reset mock for next run
|
||||
mockLLM.calls = 0
|
||||
mockLLM.responses = []Message{
|
||||
{Content: `{"action": "RESPOND", "params": {"response": "You said you like cats."}}`},
|
||||
}
|
||||
// Reset mock for next run
|
||||
mockLLM.calls = 0
|
||||
mockLLM.responses = []Message{
|
||||
{Content: `{"action": "RESPOND", "params": {"response": "You said you like cats."}}`},
|
||||
}
|
||||
|
||||
resHist, err := handler(context.Background(), reqWithHist)
|
||||
if err != nil {
|
||||
t.Fatalf("handler with history failed: %v", err)
|
||||
}
|
||||
resHist, err := handler(context.Background(), reqWithHist)
|
||||
if err != nil {
|
||||
t.Fatalf("handler with history failed: %v", err)
|
||||
}
|
||||
|
||||
var resultHist map[string]interface{}
|
||||
textContentHist := resHist.Content[0].(mcp.TextContent)
|
||||
json.Unmarshal([]byte(textContentHist.Text), &resultHist)
|
||||
var resultHist map[string]interface{}
|
||||
textContentHist := resHist.Content[0].(mcp.TextContent)
|
||||
json.Unmarshal([]byte(textContentHist.Text), &resultHist)
|
||||
|
||||
historyFinal, ok := resultHist["history"].([]interface{})
|
||||
if !ok || len(historyFinal) != 4 { // 2 old + 1 new user + 1 assistant response
|
||||
t.Errorf("expected history of length 4, got %v", len(historyFinal))
|
||||
}
|
||||
historyFinal, ok := resultHist["history"].([]interface{})
|
||||
if !ok || len(historyFinal) != 4 { // 2 old + 1 new user + 1 assistant response
|
||||
t.Errorf("expected history of length 4, got %v", len(historyFinal))
|
||||
}
|
||||
|
||||
lastMsg := historyFinal[3].(map[string]interface{})
|
||||
if lastMsg["content"] != "You said you like cats." {
|
||||
t.Errorf("unexpected last message: %v", lastMsg["content"])
|
||||
}
|
||||
lastMsg := historyFinal[3].(map[string]interface{})
|
||||
if lastMsg["content"] != "You said you like cats." {
|
||||
t.Errorf("unexpected last message: %v", lastMsg["content"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user