yao/agent/robot/executor/standard/input_integration_test.go
Max 6e68b42128 Enhance Agent Documentation and Add Extract Command Functionality
- Updated README files to include new commands for running tests and extracting results for review.
- Introduced the `yao agent extract` command to facilitate extraction of test results from JSONL files into Markdown or JSON formats.
- Enhanced the `FormatAvailableResources` function to support localization and detailed information for agents and MCP tools.
- Improved output formatting for better readability and usability in test result documentation.
2026-01-27 10:57:27 +08:00

372 lines
10 KiB
Go

package standard_test
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/yaoapp/yao/agent/robot/executor/standard"
"github.com/yaoapp/yao/agent/robot/types"
"github.com/yaoapp/yao/agent/testutils"
)
// ============================================================================
// InputFormatter Integration Tests with Real Data
// These tests use the yao-dev-app environment with real assistants and MCPs
// ============================================================================
func TestFormatAvailableResourcesIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test")
}
testutils.Prepare(t)
defer testutils.Clean(t)
formatter := standard.NewInputFormatter()
t.Run("formats_real_agents_with_details", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-agents",
Config: &types.Config{
Identity: &types.Identity{
Role: "Test Robot",
Duties: []string{"Testing agent formatting"},
},
DefaultLocale: "en",
Resources: &types.Resources{
// Use real agents from yao-dev-app/assistants
Agents: []string{
"experts.data-analyst",
"experts.text-writer",
"experts.summarizer",
},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Verify structure
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### Agents")
assert.Contains(t, result, "These are the AI assistants you can delegate tasks to:")
// Verify real agent details are included
// experts.data-analyst should show name and description
assert.Contains(t, result, "experts.data-analyst")
assert.Contains(t, result, "Data Analyst Expert") // Name from package.yao
// experts.text-writer
assert.Contains(t, result, "experts.text-writer")
// experts.summarizer
assert.Contains(t, result, "experts.summarizer")
// Verify important note is present
assert.Contains(t, result, "Only plan goals and tasks that can be accomplished")
t.Logf("Formatted agents result:\n%s", result)
})
t.Run("formats_real_mcp_with_tool_details", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-mcp",
Config: &types.Config{
Identity: &types.Identity{
Role: "Test Robot",
Duties: []string{"Testing MCP formatting"},
},
DefaultLocale: "en",
Resources: &types.Resources{
// Use real MCPs from yao-dev-app/mcps
MCP: []types.MCPConfig{
{ID: "echo", Tools: []string{"ping", "status"}}, // Specific tools
{ID: "echo"}, // All tools
},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Verify structure
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### MCP Tools")
assert.Contains(t, result, "These are the external tools and services you can use:")
// Verify MCP details
assert.Contains(t, result, "echo")
// Verify important note is present
assert.Contains(t, result, "Only plan goals and tasks that can be accomplished")
t.Logf("Formatted MCP result:\n%s", result)
})
t.Run("formats_combined_resources", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-combined",
Config: &types.Config{
Identity: &types.Identity{
Role: "Sales Analyst Robot",
Duties: []string{"Analyze sales data", "Generate reports"},
Rules: []string{"Be accurate", "Be concise"},
},
DefaultLocale: "en",
Resources: &types.Resources{
Agents: []string{
"experts.data-analyst",
"experts.summarizer",
},
MCP: []types.MCPConfig{
{ID: "echo", Tools: []string{"ping", "echo"}},
},
},
KB: &types.KB{
Collections: []string{"sales-policies", "product-catalog"},
},
DB: &types.DB{
Models: []string{"sales", "customers", "orders"},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Verify all sections are present
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### Agents")
assert.Contains(t, result, "### MCP Tools")
assert.Contains(t, result, "### Knowledge Base")
assert.Contains(t, result, "### Database")
// Verify agents
assert.Contains(t, result, "experts.data-analyst")
assert.Contains(t, result, "experts.summarizer")
// Verify MCP
assert.Contains(t, result, "echo")
// Verify KB
assert.Contains(t, result, "sales-policies")
assert.Contains(t, result, "product-catalog")
// Verify DB
assert.Contains(t, result, "sales")
assert.Contains(t, result, "customers")
assert.Contains(t, result, "orders")
t.Logf("Formatted combined resources result:\n%s", result)
})
t.Run("handles_locale_zh", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-zh",
Config: &types.Config{
Identity: &types.Identity{
Role: "测试机器人",
Duties: []string{"测试国际化"},
},
DefaultLocale: "zh-cn",
Resources: &types.Resources{
// Use agents that have zh-cn locales
Agents: []string{
"hello", // This agent has locales/zh-cn.yml
"mohe", // This agent also has locales/zh-cn.yml
},
},
},
}
result := formatter.FormatAvailableResourcesWithLocale(robot, "zh-cn")
// Verify structure
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### Agents")
// Verify agents are listed
assert.Contains(t, result, "hello")
assert.Contains(t, result, "mohe")
t.Logf("Formatted zh-cn result:\n%s", result)
})
t.Run("gracefully_handles_missing_agents", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-missing",
Config: &types.Config{
Identity: &types.Identity{
Role: "Test Robot",
},
Resources: &types.Resources{
Agents: []string{
"non-existent-agent",
"experts.data-analyst", // This one exists
"another-missing-agent",
},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Should not panic, should include fallback for missing agents
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### Agents")
// Missing agents should still be listed with just ID
assert.Contains(t, result, "non-existent-agent")
assert.Contains(t, result, "another-missing-agent")
// Existing agent should have full details
assert.Contains(t, result, "experts.data-analyst")
assert.Contains(t, result, "Data Analyst Expert")
t.Logf("Formatted with missing agents:\n%s", result)
})
t.Run("gracefully_handles_missing_mcp", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-missing-mcp",
Config: &types.Config{
Identity: &types.Identity{
Role: "Test Robot",
},
Resources: &types.Resources{
MCP: []types.MCPConfig{
{ID: "non-existent-mcp", Tools: []string{"tool1", "tool2"}},
{ID: "echo"}, // This one exists
},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Should not panic, should include fallback for missing MCP
assert.Contains(t, result, "## Available Resources")
assert.Contains(t, result, "### MCP Tools")
// Missing MCP should still be listed with fallback
assert.Contains(t, result, "non-existent-mcp")
assert.Contains(t, result, "tool1, tool2")
// Existing MCP should have details
assert.Contains(t, result, "echo")
t.Logf("Formatted with missing MCP:\n%s", result)
})
}
func TestFormatAvailableResourcesTableFormat(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test")
}
testutils.Prepare(t)
defer testutils.Clean(t)
formatter := standard.NewInputFormatter()
t.Run("mcp_tools_in_table_format", func(t *testing.T) {
robot := &types.Robot{
MemberID: "test-robot-table",
Config: &types.Config{
Identity: &types.Identity{
Role: "Test Robot",
},
Resources: &types.Resources{
MCP: []types.MCPConfig{
{ID: "echo"}, // All tools - should show table
},
},
},
}
result := formatter.FormatAvailableResources(robot)
// Check if table format is used when tools are available
// Table headers: | Tool | Description |
if strings.Contains(result, "| Tool | Description |") {
assert.Contains(t, result, "|------|-------------|")
t.Logf("MCP tools displayed in table format:\n%s", result)
} else {
// Fallback format
t.Logf("MCP tools displayed in fallback format:\n%s", result)
}
})
}
func TestFormatClockContextWithRobotIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test")
}
testutils.Prepare(t)
defer testutils.Clean(t)
formatter := standard.NewInputFormatter()
t.Run("full_context_for_inspiration", func(t *testing.T) {
// Create a realistic robot configuration
robot := &types.Robot{
MemberID: "sales-robot-001",
TeamID: "team-001",
DisplayName: "Sales Analyst Robot",
AutonomousMode: true,
Config: &types.Config{
Identity: &types.Identity{
Role: "Sales Analyst",
Duties: []string{"Monitor sales performance", "Generate daily reports", "Alert on anomalies"},
Rules: []string{"Only use approved data sources", "Maintain confidentiality"},
},
DefaultLocale: "en",
Resources: &types.Resources{
Agents: []string{
"experts.data-analyst",
"experts.summarizer",
},
MCP: []types.MCPConfig{
{ID: "echo", Tools: []string{"ping"}},
},
},
},
}
// Create clock context
clock := types.NewClockContext(time.Now(), "UTC")
// Format clock context (includes robot identity)
clockContent := formatter.FormatClockContext(clock, robot)
// Format available resources
resourcesContent := formatter.FormatAvailableResources(robot)
// Combine for full context (as done in inspiration.go)
fullContext := clockContent + "\n\n" + resourcesContent
// Verify full context contains all necessary information
require.NotEmpty(t, fullContext)
// Time context
assert.Contains(t, fullContext, "## Current Time Context")
assert.Contains(t, fullContext, "### Time Markers")
// Robot identity
assert.Contains(t, fullContext, "## Robot Identity")
assert.Contains(t, fullContext, "Sales Analyst")
assert.Contains(t, fullContext, "Monitor sales performance")
assert.Contains(t, fullContext, "Only use approved data sources")
// Available resources
assert.Contains(t, fullContext, "## Available Resources")
assert.Contains(t, fullContext, "### Agents")
assert.Contains(t, fullContext, "experts.data-analyst")
assert.Contains(t, fullContext, "### MCP Tools")
t.Logf("Full context for inspiration:\n%s", fullContext)
})
}