|
1 | 1 | package standard |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "encoding/json" |
5 | 6 | "fmt" |
6 | 7 | "strings" |
7 | 8 |
|
| 9 | + "github.com/yaoapp/gou/mcp" |
| 10 | + "github.com/yaoapp/yao/agent/assistant" |
8 | 11 | agentcontext "github.com/yaoapp/yao/agent/context" |
| 12 | + "github.com/yaoapp/yao/agent/i18n" |
9 | 13 | robottypes "github.com/yaoapp/yao/agent/robot/types" |
10 | 14 | ) |
11 | 15 |
|
@@ -39,47 +43,62 @@ func (f *InputFormatter) FormatClockContext(clock *robottypes.ClockContext, robo |
39 | 43 | sb.WriteString(fmt.Sprintf("- **Day**: %s\n", clock.DayOfWeek)) |
40 | 44 | sb.WriteString(fmt.Sprintf("- **Date**: %d/%d/%d\n", clock.Year, clock.Month, clock.DayOfMonth)) |
41 | 45 | sb.WriteString(fmt.Sprintf("- **Week**: %d of year\n", clock.WeekOfYear)) |
| 46 | + sb.WriteString(fmt.Sprintf("- **Hour**: %d\n", clock.Hour)) |
42 | 47 | sb.WriteString(fmt.Sprintf("- **Timezone**: %s\n", clock.TZ)) |
43 | 48 |
|
44 | | - // Time markers |
| 49 | + // Time markers - show all markers with check/cross for context awareness |
45 | 50 | sb.WriteString("\n### Time Markers\n") |
46 | | - if clock.IsWeekend { |
47 | | - sb.WriteString("- ✓ Weekend\n") |
48 | | - } |
49 | | - if clock.IsMonthStart { |
50 | | - sb.WriteString("- ✓ Month Start (1st-3rd)\n") |
51 | | - } |
52 | | - if clock.IsMonthEnd { |
53 | | - sb.WriteString("- ✓ Month End (last 3 days)\n") |
54 | | - } |
55 | | - if clock.IsQuarterEnd { |
56 | | - sb.WriteString("- ✓ Quarter End\n") |
57 | | - } |
58 | | - if clock.IsYearEnd { |
59 | | - sb.WriteString("- ✓ Year End\n") |
60 | | - } |
61 | | - |
62 | | - // Robot identity section (if available) |
63 | | - if robot != nil && robot.Config != nil && robot.Config.Identity != nil { |
64 | | - sb.WriteString("\n## Robot Identity\n\n") |
65 | | - sb.WriteString(fmt.Sprintf("- **Role**: %s\n", robot.Config.Identity.Role)) |
66 | | - if len(robot.Config.Identity.Duties) > 0 { |
67 | | - sb.WriteString("- **Duties**:\n") |
68 | | - for _, duty := range robot.Config.Identity.Duties { |
69 | | - sb.WriteString(fmt.Sprintf(" - %s\n", duty)) |
| 51 | + sb.WriteString(fmt.Sprintf("- %s Weekend\n", boolMark(clock.IsWeekend))) |
| 52 | + sb.WriteString(fmt.Sprintf("- %s Month Start (1st-3rd)\n", boolMark(clock.IsMonthStart))) |
| 53 | + sb.WriteString(fmt.Sprintf("- %s Month End (last 3 days)\n", boolMark(clock.IsMonthEnd))) |
| 54 | + sb.WriteString(fmt.Sprintf("- %s Quarter End\n", boolMark(clock.IsQuarterEnd))) |
| 55 | + sb.WriteString(fmt.Sprintf("- %s Year End\n", boolMark(clock.IsYearEnd))) |
| 56 | + |
| 57 | + // Robot identity section |
| 58 | + // Priority: Config.Identity > Robot fields (DisplayName, Bio, SystemPrompt) |
| 59 | + if robot != nil { |
| 60 | + if robot.Config != nil && robot.Config.Identity != nil { |
| 61 | + // Use structured identity from config |
| 62 | + sb.WriteString("\n## Robot Identity\n\n") |
| 63 | + sb.WriteString(fmt.Sprintf("- **Role**: %s\n", robot.Config.Identity.Role)) |
| 64 | + if len(robot.Config.Identity.Duties) > 0 { |
| 65 | + sb.WriteString("- **Duties**:\n") |
| 66 | + for _, duty := range robot.Config.Identity.Duties { |
| 67 | + sb.WriteString(fmt.Sprintf(" - %s\n", duty)) |
| 68 | + } |
70 | 69 | } |
71 | | - } |
72 | | - if len(robot.Config.Identity.Rules) > 0 { |
73 | | - sb.WriteString("- **Rules**:\n") |
74 | | - for _, rule := range robot.Config.Identity.Rules { |
75 | | - sb.WriteString(fmt.Sprintf(" - %s\n", rule)) |
| 70 | + if len(robot.Config.Identity.Rules) > 0 { |
| 71 | + sb.WriteString("- **Rules**:\n") |
| 72 | + for _, rule := range robot.Config.Identity.Rules { |
| 73 | + sb.WriteString(fmt.Sprintf(" - %s\n", rule)) |
| 74 | + } |
| 75 | + } |
| 76 | + } else if robot.DisplayName != "" || robot.Bio != "" || robot.SystemPrompt != "" { |
| 77 | + // Fallback: build identity from Robot fields (from __yao.member table) |
| 78 | + sb.WriteString("\n## Robot Identity\n\n") |
| 79 | + if robot.DisplayName != "" { |
| 80 | + sb.WriteString(fmt.Sprintf("- **Role**: %s\n", robot.DisplayName)) |
| 81 | + } |
| 82 | + if robot.Bio != "" { |
| 83 | + sb.WriteString(fmt.Sprintf("- **Description**: %s\n", robot.Bio)) |
| 84 | + } |
| 85 | + if robot.SystemPrompt != "" { |
| 86 | + sb.WriteString(fmt.Sprintf("- **Instructions**:\n%s\n", robot.SystemPrompt)) |
76 | 87 | } |
77 | 88 | } |
78 | 89 | } |
79 | 90 |
|
80 | 91 | return sb.String() |
81 | 92 | } |
82 | 93 |
|
| 94 | +// boolMark returns ✓ for true and ✗ for false |
| 95 | +func boolMark(v bool) string { |
| 96 | + if v { |
| 97 | + return "✓" |
| 98 | + } |
| 99 | + return "✗" |
| 100 | +} |
| 101 | + |
83 | 102 | // FormatRobotIdentity formats robot identity as user message content |
84 | 103 | // Used to provide context about the robot's role and duties |
85 | 104 | func (f *InputFormatter) FormatRobotIdentity(robot *robottypes.Robot) string { |
@@ -115,43 +134,168 @@ func (f *InputFormatter) FormatRobotIdentity(robot *robottypes.Robot) string { |
115 | 134 | // This is critical for generating achievable goals - without knowing available tools, |
116 | 135 | // the agent might generate goals that cannot be accomplished |
117 | 136 | func (f *InputFormatter) FormatAvailableResources(robot *robottypes.Robot) string { |
| 137 | + locale := "en" // default locale |
| 138 | + if robot != nil && robot.Config != nil { |
| 139 | + locale = robot.Config.GetDefaultLocale() |
| 140 | + } |
| 141 | + return f.FormatAvailableResourcesWithLocale(robot, locale) |
| 142 | +} |
| 143 | + |
| 144 | +// FormatAvailableResourcesWithLocale formats available resources with specific locale for i18n support |
| 145 | +func (f *InputFormatter) FormatAvailableResourcesWithLocale(robot *robottypes.Robot, locale string) string { |
118 | 146 | if robot == nil || robot.Config == nil { |
119 | 147 | return "" |
120 | 148 | } |
121 | 149 |
|
122 | 150 | var sb strings.Builder |
123 | 151 | hasContent := false |
124 | 152 |
|
125 | | - // Available Agents |
| 153 | + // Available Agents - with detailed information (name, description) |
126 | 154 | if robot.Config.Resources != nil && len(robot.Config.Resources.Agents) > 0 { |
127 | 155 | if !hasContent { |
128 | 156 | sb.WriteString("## Available Resources\n\n") |
129 | 157 | hasContent = true |
130 | 158 | } |
131 | 159 | sb.WriteString("### Agents\n") |
132 | | - sb.WriteString("These are the AI assistants you can delegate tasks to:\n") |
133 | | - for _, agent := range robot.Config.Resources.Agents { |
134 | | - sb.WriteString(fmt.Sprintf("- **%s**\n", agent)) |
| 160 | + sb.WriteString("These are the AI assistants you can delegate tasks to:\n\n") |
| 161 | + for _, agentID := range robot.Config.Resources.Agents { |
| 162 | + // Try to get agent details |
| 163 | + ast, err := assistant.Get(agentID) |
| 164 | + if err != nil { |
| 165 | + // Fallback to just ID if agent not found |
| 166 | + sb.WriteString(fmt.Sprintf("- **%s**\n", agentID)) |
| 167 | + continue |
| 168 | + } |
| 169 | + |
| 170 | + // Get localized name and description |
| 171 | + name := i18n.Translate(agentID, locale, ast.Name).(string) |
| 172 | + description := "" |
| 173 | + if ast.Description != "" { |
| 174 | + description = i18n.Translate(agentID, locale, ast.Description).(string) |
| 175 | + } |
| 176 | + |
| 177 | + // Format agent info |
| 178 | + sb.WriteString(fmt.Sprintf("- **%s** (`%s`)\n", name, agentID)) |
| 179 | + if description != "" { |
| 180 | + sb.WriteString(fmt.Sprintf(" - %s\n", description)) |
| 181 | + } |
135 | 182 | } |
136 | 183 | sb.WriteString("\n") |
137 | 184 | } |
138 | 185 |
|
139 | | - // Available MCP Tools |
| 186 | + // Available MCP Tools - with detailed tool information |
140 | 187 | if robot.Config.Resources != nil && len(robot.Config.Resources.MCP) > 0 { |
141 | 188 | if !hasContent { |
142 | 189 | sb.WriteString("## Available Resources\n\n") |
143 | 190 | hasContent = true |
144 | 191 | } |
145 | 192 | sb.WriteString("### MCP Tools\n") |
146 | | - sb.WriteString("These are the external tools and services you can use:\n") |
147 | | - for _, mcp := range robot.Config.Resources.MCP { |
148 | | - if len(mcp.Tools) > 0 { |
149 | | - sb.WriteString(fmt.Sprintf("- **%s**: %s\n", mcp.ID, strings.Join(mcp.Tools, ", "))) |
| 193 | + sb.WriteString("These are the external tools and services you can use:\n\n") |
| 194 | + for _, mcpConfig := range robot.Config.Resources.MCP { |
| 195 | + // Try to get MCP client and list tools |
| 196 | + client, err := mcp.Select(mcpConfig.ID) |
| 197 | + if err != nil { |
| 198 | + // Fallback to basic info if client not found |
| 199 | + if len(mcpConfig.Tools) > 0 { |
| 200 | + sb.WriteString(fmt.Sprintf("- **%s**: %s\n", mcpConfig.ID, strings.Join(mcpConfig.Tools, ", "))) |
| 201 | + } else { |
| 202 | + sb.WriteString(fmt.Sprintf("- **%s**: all tools available\n", mcpConfig.ID)) |
| 203 | + } |
| 204 | + continue |
| 205 | + } |
| 206 | + |
| 207 | + // Get client info for name and description |
| 208 | + clientInfo := client.Info() |
| 209 | + clientName := mcpConfig.ID |
| 210 | + clientDesc := "" |
| 211 | + if clientInfo != nil { |
| 212 | + if clientInfo.Name != "" { |
| 213 | + clientName = clientInfo.Name |
| 214 | + } |
| 215 | + if clientInfo.Description != "" { |
| 216 | + clientDesc = clientInfo.Description |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + // Write MCP header |
| 221 | + if clientDesc != "" { |
| 222 | + sb.WriteString(fmt.Sprintf("#### %s (`%s`)\n", clientName, mcpConfig.ID)) |
| 223 | + sb.WriteString(fmt.Sprintf("%s\n\n", clientDesc)) |
| 224 | + } else { |
| 225 | + sb.WriteString(fmt.Sprintf("#### %s (`%s`)\n\n", clientName, mcpConfig.ID)) |
| 226 | + } |
| 227 | + |
| 228 | + // Try to list tools with context |
| 229 | + ctx := context.Background() |
| 230 | + toolsResp, err := client.ListTools(ctx, "") |
| 231 | + if err != nil || toolsResp == nil { |
| 232 | + // Fallback to configured tools |
| 233 | + if len(mcpConfig.Tools) > 0 { |
| 234 | + sb.WriteString("Available tools: ") |
| 235 | + sb.WriteString(strings.Join(mcpConfig.Tools, ", ")) |
| 236 | + sb.WriteString("\n\n") |
| 237 | + } else { |
| 238 | + sb.WriteString("All tools available\n\n") |
| 239 | + } |
| 240 | + continue |
| 241 | + } |
| 242 | + |
| 243 | + // Filter tools if specific tools are configured |
| 244 | + toolsToShow := toolsResp.Tools |
| 245 | + if len(mcpConfig.Tools) > 0 { |
| 246 | + // Create a map for quick lookup |
| 247 | + allowedTools := make(map[string]bool) |
| 248 | + for _, t := range mcpConfig.Tools { |
| 249 | + allowedTools[t] = true |
| 250 | + } |
| 251 | + // Filter tools |
| 252 | + var filteredTools []struct { |
| 253 | + Name string |
| 254 | + Description string |
| 255 | + } |
| 256 | + for _, tool := range toolsResp.Tools { |
| 257 | + if allowedTools[tool.Name] { |
| 258 | + filteredTools = append(filteredTools, struct { |
| 259 | + Name string |
| 260 | + Description string |
| 261 | + }{tool.Name, tool.Description}) |
| 262 | + } |
| 263 | + } |
| 264 | + // Write filtered tools |
| 265 | + if len(filteredTools) > 0 { |
| 266 | + sb.WriteString("| Tool | Description |\n") |
| 267 | + sb.WriteString("|------|-------------|\n") |
| 268 | + for _, tool := range filteredTools { |
| 269 | + desc := tool.Description |
| 270 | + if len(desc) > 100 { |
| 271 | + desc = desc[:97] + "..." |
| 272 | + } |
| 273 | + // Escape pipe characters in description |
| 274 | + desc = strings.ReplaceAll(desc, "|", "\\|") |
| 275 | + sb.WriteString(fmt.Sprintf("| `%s` | %s |\n", tool.Name, desc)) |
| 276 | + } |
| 277 | + } else { |
| 278 | + sb.WriteString("Configured tools: ") |
| 279 | + sb.WriteString(strings.Join(mcpConfig.Tools, ", ")) |
| 280 | + } |
| 281 | + } else if len(toolsToShow) > 0 { |
| 282 | + // Show all available tools |
| 283 | + sb.WriteString("| Tool | Description |\n") |
| 284 | + sb.WriteString("|------|-------------|\n") |
| 285 | + for _, tool := range toolsToShow { |
| 286 | + desc := tool.Description |
| 287 | + if len(desc) > 100 { |
| 288 | + desc = desc[:97] + "..." |
| 289 | + } |
| 290 | + // Escape pipe characters in description |
| 291 | + desc = strings.ReplaceAll(desc, "|", "\\|") |
| 292 | + sb.WriteString(fmt.Sprintf("| `%s` | %s |\n", tool.Name, desc)) |
| 293 | + } |
150 | 294 | } else { |
151 | | - sb.WriteString(fmt.Sprintf("- **%s**: all tools available\n", mcp.ID)) |
| 295 | + sb.WriteString("No tools available\n") |
152 | 296 | } |
| 297 | + sb.WriteString("\n") |
153 | 298 | } |
154 | | - sb.WriteString("\n") |
155 | 299 | } |
156 | 300 |
|
157 | 301 | // Available Knowledge Base |
|
0 commit comments