fast-agent-mcp 0.1.12__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/METADATA +3 -4
  2. fast_agent_mcp-0.2.0.dist-info/RECORD +123 -0
  3. mcp_agent/__init__.py +75 -0
  4. mcp_agent/agents/agent.py +61 -415
  5. mcp_agent/agents/base_agent.py +522 -0
  6. mcp_agent/agents/workflow/__init__.py +1 -0
  7. mcp_agent/agents/workflow/chain_agent.py +173 -0
  8. mcp_agent/agents/workflow/evaluator_optimizer.py +362 -0
  9. mcp_agent/agents/workflow/orchestrator_agent.py +591 -0
  10. mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_models.py +11 -21
  11. mcp_agent/agents/workflow/parallel_agent.py +182 -0
  12. mcp_agent/agents/workflow/router_agent.py +307 -0
  13. mcp_agent/app.py +15 -19
  14. mcp_agent/cli/commands/bootstrap.py +19 -38
  15. mcp_agent/cli/commands/config.py +4 -4
  16. mcp_agent/cli/commands/setup.py +7 -14
  17. mcp_agent/cli/main.py +7 -10
  18. mcp_agent/cli/terminal.py +3 -3
  19. mcp_agent/config.py +25 -40
  20. mcp_agent/context.py +12 -21
  21. mcp_agent/context_dependent.py +3 -5
  22. mcp_agent/core/agent_types.py +10 -7
  23. mcp_agent/core/direct_agent_app.py +179 -0
  24. mcp_agent/core/direct_decorators.py +443 -0
  25. mcp_agent/core/direct_factory.py +476 -0
  26. mcp_agent/core/enhanced_prompt.py +23 -55
  27. mcp_agent/core/exceptions.py +8 -8
  28. mcp_agent/core/fastagent.py +145 -371
  29. mcp_agent/core/interactive_prompt.py +424 -0
  30. mcp_agent/core/mcp_content.py +17 -17
  31. mcp_agent/core/prompt.py +6 -9
  32. mcp_agent/core/request_params.py +6 -3
  33. mcp_agent/core/validation.py +92 -18
  34. mcp_agent/executor/decorator_registry.py +9 -17
  35. mcp_agent/executor/executor.py +8 -17
  36. mcp_agent/executor/task_registry.py +2 -4
  37. mcp_agent/executor/temporal.py +19 -41
  38. mcp_agent/executor/workflow.py +3 -5
  39. mcp_agent/executor/workflow_signal.py +15 -21
  40. mcp_agent/human_input/handler.py +4 -7
  41. mcp_agent/human_input/types.py +2 -3
  42. mcp_agent/llm/__init__.py +2 -0
  43. mcp_agent/llm/augmented_llm.py +450 -0
  44. mcp_agent/llm/augmented_llm_passthrough.py +162 -0
  45. mcp_agent/llm/augmented_llm_playback.py +83 -0
  46. mcp_agent/llm/memory.py +103 -0
  47. mcp_agent/{workflows/llm → llm}/model_factory.py +22 -16
  48. mcp_agent/{workflows/llm → llm}/prompt_utils.py +1 -3
  49. mcp_agent/llm/providers/__init__.py +8 -0
  50. mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +8 -25
  51. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +56 -194
  52. mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
  53. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +99 -190
  54. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +72 -71
  55. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +65 -71
  56. mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +16 -44
  57. mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +4 -4
  58. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +9 -11
  59. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +8 -12
  60. mcp_agent/{workflows/llm → llm}/sampling_converter.py +3 -31
  61. mcp_agent/llm/sampling_format_converter.py +37 -0
  62. mcp_agent/logging/events.py +1 -5
  63. mcp_agent/logging/json_serializer.py +7 -6
  64. mcp_agent/logging/listeners.py +20 -23
  65. mcp_agent/logging/logger.py +17 -19
  66. mcp_agent/logging/rich_progress.py +10 -8
  67. mcp_agent/logging/tracing.py +4 -6
  68. mcp_agent/logging/transport.py +22 -22
  69. mcp_agent/mcp/gen_client.py +1 -3
  70. mcp_agent/mcp/interfaces.py +117 -110
  71. mcp_agent/mcp/logger_textio.py +97 -0
  72. mcp_agent/mcp/mcp_agent_client_session.py +7 -7
  73. mcp_agent/mcp/mcp_agent_server.py +8 -8
  74. mcp_agent/mcp/mcp_aggregator.py +102 -143
  75. mcp_agent/mcp/mcp_connection_manager.py +20 -27
  76. mcp_agent/mcp/prompt_message_multipart.py +68 -16
  77. mcp_agent/mcp/prompt_render.py +77 -0
  78. mcp_agent/mcp/prompt_serialization.py +30 -48
  79. mcp_agent/mcp/prompts/prompt_constants.py +18 -0
  80. mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
  81. mcp_agent/mcp/prompts/prompt_load.py +109 -0
  82. mcp_agent/mcp/prompts/prompt_server.py +155 -195
  83. mcp_agent/mcp/prompts/prompt_template.py +35 -66
  84. mcp_agent/mcp/resource_utils.py +7 -14
  85. mcp_agent/mcp/sampling.py +17 -17
  86. mcp_agent/mcp_server/agent_server.py +13 -17
  87. mcp_agent/mcp_server_registry.py +13 -22
  88. mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +3 -2
  89. mcp_agent/resources/examples/in_dev/slides.py +110 -0
  90. mcp_agent/resources/examples/internal/agent.py +6 -3
  91. mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
  92. mcp_agent/resources/examples/internal/job.py +2 -1
  93. mcp_agent/resources/examples/internal/prompt_category.py +1 -1
  94. mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
  95. mcp_agent/resources/examples/internal/sizer.py +2 -1
  96. mcp_agent/resources/examples/internal/social.py +2 -1
  97. mcp_agent/resources/examples/prompting/agent.py +2 -1
  98. mcp_agent/resources/examples/prompting/image_server.py +4 -8
  99. mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
  100. mcp_agent/ui/console_display.py +16 -20
  101. fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
  102. mcp_agent/core/agent_app.py +0 -646
  103. mcp_agent/core/agent_utils.py +0 -71
  104. mcp_agent/core/decorators.py +0 -455
  105. mcp_agent/core/factory.py +0 -463
  106. mcp_agent/core/proxies.py +0 -269
  107. mcp_agent/core/types.py +0 -24
  108. mcp_agent/eval/__init__.py +0 -0
  109. mcp_agent/mcp/stdio.py +0 -111
  110. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
  111. mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
  112. mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
  113. mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
  114. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
  115. mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
  116. mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
  117. mcp_agent/resources/examples/researcher/researcher-imp.py +0 -190
  118. mcp_agent/resources/examples/researcher/researcher.py +0 -38
  119. mcp_agent/resources/examples/workflows/chaining.py +0 -44
  120. mcp_agent/resources/examples/workflows/evaluator.py +0 -78
  121. mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
  122. mcp_agent/resources/examples/workflows/human_input.py +0 -25
  123. mcp_agent/resources/examples/workflows/orchestrator.py +0 -73
  124. mcp_agent/resources/examples/workflows/parallel.py +0 -78
  125. mcp_agent/resources/examples/workflows/router.py +0 -53
  126. mcp_agent/resources/examples/workflows/sse.py +0 -23
  127. mcp_agent/telemetry/__init__.py +0 -0
  128. mcp_agent/telemetry/usage_tracking.py +0 -18
  129. mcp_agent/workflows/__init__.py +0 -0
  130. mcp_agent/workflows/embedding/__init__.py +0 -0
  131. mcp_agent/workflows/embedding/embedding_base.py +0 -61
  132. mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
  133. mcp_agent/workflows/embedding/embedding_openai.py +0 -46
  134. mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
  135. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -481
  136. mcp_agent/workflows/intent_classifier/__init__.py +0 -0
  137. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -120
  138. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -134
  139. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -45
  140. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -45
  141. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -161
  142. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
  143. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -60
  144. mcp_agent/workflows/llm/__init__.py +0 -0
  145. mcp_agent/workflows/llm/augmented_llm.py +0 -753
  146. mcp_agent/workflows/llm/augmented_llm_passthrough.py +0 -241
  147. mcp_agent/workflows/llm/augmented_llm_playback.py +0 -109
  148. mcp_agent/workflows/llm/providers/__init__.py +0 -8
  149. mcp_agent/workflows/llm/sampling_format_converter.py +0 -22
  150. mcp_agent/workflows/orchestrator/__init__.py +0 -0
  151. mcp_agent/workflows/orchestrator/orchestrator.py +0 -578
  152. mcp_agent/workflows/parallel/__init__.py +0 -0
  153. mcp_agent/workflows/parallel/fan_in.py +0 -350
  154. mcp_agent/workflows/parallel/fan_out.py +0 -187
  155. mcp_agent/workflows/parallel/parallel_llm.py +0 -166
  156. mcp_agent/workflows/router/__init__.py +0 -0
  157. mcp_agent/workflows/router/router_base.py +0 -368
  158. mcp_agent/workflows/router/router_embedding.py +0 -240
  159. mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
  160. mcp_agent/workflows/router/router_embedding_openai.py +0 -59
  161. mcp_agent/workflows/router/router_llm.py +0 -320
  162. mcp_agent/workflows/swarm/__init__.py +0 -0
  163. mcp_agent/workflows/swarm/swarm.py +0 -320
  164. mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
  165. mcp_agent/workflows/swarm/swarm_openai.py +0 -41
  166. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
  167. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
  168. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
  169. /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
@@ -1,646 +0,0 @@
1
- """
2
- Main application wrapper for interacting with agents.
3
- """
4
-
5
- from typing import Optional, Dict, Union, TYPE_CHECKING
6
-
7
- from mcp_agent.app import MCPApp
8
- from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
9
- from mcp_agent.progress_display import progress_display
10
- from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator
11
- from mcp_agent.workflows.parallel.parallel_llm import ParallelLLM
12
- from mcp_agent.workflows.evaluator_optimizer.evaluator_optimizer import (
13
- EvaluatorOptimizerLLM,
14
- )
15
-
16
- # Import proxies directly - they handle their own circular imports
17
- from mcp_agent.core.proxies import (
18
- BaseAgentProxy,
19
- LLMAgentProxy,
20
- RouterProxy,
21
- ChainProxy,
22
- WorkflowProxy,
23
- )
24
-
25
- # Handle possible circular imports with types
26
- if TYPE_CHECKING:
27
- from mcp_agent.core.types import ProxyDict
28
- else:
29
- ProxyDict = Dict[str, BaseAgentProxy]
30
-
31
-
32
- class AgentApp:
33
- """Main application wrapper"""
34
-
35
- def __init__(self, app: MCPApp, agents: ProxyDict):
36
- self._app = app
37
- self._agents = agents
38
- # Optional: set default agent for direct calls
39
- self._default = next(iter(agents)) if agents else None
40
-
41
- async def send_prompt(
42
- self, prompt: PromptMessageMultipart, agent_name: Optional[str] = None
43
- ) -> str:
44
- """
45
- Send a PromptMessageMultipart to an agent
46
-
47
- Args:
48
- prompt: The PromptMessageMultipart to send
49
- agent_name: The name of the agent to send to (uses default if None)
50
-
51
- Returns:
52
- The agent's response as a string
53
- """
54
- target = agent_name or self._default
55
- if not target:
56
- raise ValueError("No default agent available")
57
-
58
- if target not in self._agents:
59
- raise ValueError(f"No agent named '{target}'")
60
-
61
- proxy = self._agents[target]
62
- return await proxy.send_prompt(prompt)
63
-
64
- async def send(
65
- self,
66
- message: Union[str, PromptMessageMultipart] = None,
67
- agent_name: Optional[str] = None,
68
- ) -> str:
69
- """
70
- Send a message to the default agent or specified agent
71
-
72
- Args:
73
- message: Either a string message or a PromptMessageMultipart object
74
- agent_name: The name of the agent to send to (uses default if None)
75
-
76
- Returns:
77
- The agent's response as a string
78
- """
79
- target = agent_name or self._default
80
- if not target:
81
- raise ValueError("No default agent available")
82
-
83
- if target not in self._agents:
84
- raise ValueError(f"No agent named '{target}'")
85
-
86
- proxy = self._agents[target]
87
- return await proxy.send(message)
88
-
89
- async def apply_prompt(
90
- self,
91
- prompt_name: str,
92
- arguments: Optional[dict[str, str]] = None,
93
- agent_name: Optional[str] = None,
94
- ) -> str:
95
- """
96
- Apply an MCP Server Prompt by name and return the assistant's response
97
-
98
- Args:
99
- prompt_name: The name of the prompt to apply
100
- arguments: Optional dictionary of string arguments to pass to the prompt template
101
- agent_name: The name of the agent to use (uses default if None)
102
-
103
- Returns:
104
- The assistant's response as a string
105
- """
106
- target = agent_name or self._default
107
- if not target:
108
- raise ValueError("No default agent available")
109
-
110
- if target not in self._agents:
111
- raise ValueError(f"No agent named '{target}'")
112
-
113
- proxy = self._agents[target]
114
- return await proxy.apply_prompt(prompt_name, arguments)
115
-
116
- async def with_resource(
117
- self,
118
- prompt_content: Union[str, PromptMessageMultipart],
119
- server_name: str,
120
- resource_name: str,
121
- agent_name: Optional[str] = None,
122
- ) -> str:
123
- """
124
- Create a prompt with the given content and resource, then send it to the agent.
125
-
126
- Args:
127
- prompt_content: Either a string message or an existing PromptMessageMultipart
128
- server_name: Name of the MCP server to retrieve the resource from
129
- resource_name: Name or URI of the resource to retrieve
130
- agent_name: The name of the agent to use (uses default if None)
131
-
132
- Returns:
133
- The agent's response as a string
134
- """
135
- target = agent_name or self._default
136
- if not target:
137
- raise ValueError("No default agent available")
138
-
139
- if target not in self._agents:
140
- raise ValueError(f"No agent named '{target}'")
141
-
142
- proxy = self._agents[target]
143
- return await proxy.with_resource(prompt_content, server_name, resource_name)
144
-
145
- async def prompt(self, agent_name: Optional[str] = None, default: str = "") -> str:
146
- """
147
- Interactive prompt for sending messages with advanced features.
148
-
149
- Args:
150
- agent_name: Optional target agent name (uses default if not specified)
151
- default: Default message to use when user presses enter
152
- """
153
- from mcp_agent.core.enhanced_prompt import (
154
- get_enhanced_input,
155
- handle_special_commands,
156
- )
157
-
158
- agent = agent_name or self._default
159
-
160
- if agent not in self._agents:
161
- raise ValueError(f"No agent named '{agent}'")
162
-
163
- # Pass all available agent names for auto-completion
164
- available_agents = list(self._agents.keys())
165
-
166
- # Create agent_types dictionary mapping agent names to their types
167
- agent_types = {}
168
- for name, proxy in self._agents.items():
169
- # Determine agent type based on the proxy type
170
- if isinstance(proxy, LLMAgentProxy):
171
- # Convert AgentType.BASIC.value ("agent") to "Agent"
172
- agent_types[name] = "Agent"
173
- elif isinstance(proxy, RouterProxy):
174
- agent_types[name] = "Router"
175
- elif isinstance(proxy, ChainProxy):
176
- agent_types[name] = "Chain"
177
- elif isinstance(proxy, WorkflowProxy):
178
- # For workflow proxies, check the workflow type
179
- workflow = proxy._workflow
180
- if isinstance(workflow, Orchestrator):
181
- agent_types[name] = "Orchestrator"
182
- elif isinstance(workflow, ParallelLLM):
183
- agent_types[name] = "Parallel"
184
- elif isinstance(workflow, EvaluatorOptimizerLLM):
185
- agent_types[name] = "Evaluator"
186
- else:
187
- agent_types[name] = "Workflow"
188
-
189
- result = ""
190
- while True:
191
- with progress_display.paused():
192
- # Use the enhanced input method with advanced features
193
- user_input = await get_enhanced_input(
194
- agent_name=agent,
195
- default=default,
196
- show_default=(default != ""),
197
- show_stop_hint=True,
198
- multiline=False, # Default to single-line mode
199
- available_agent_names=available_agents,
200
- syntax=None, # Can enable syntax highlighting for code input
201
- agent_types=agent_types, # Pass agent types for display
202
- )
203
-
204
- # Handle special commands
205
- command_result = await handle_special_commands(user_input, self)
206
-
207
- # Check if we should switch agents
208
- if isinstance(command_result, dict):
209
- if "switch_agent" in command_result:
210
- agent = command_result["switch_agent"]
211
- continue
212
- elif "list_prompts" in command_result:
213
- # Handle listing of prompts
214
- from rich import print as rich_print
215
-
216
- try:
217
- # Check if we have any agents with aggregator capabilities
218
- found_prompts = False
219
- for agent_name, agent_proxy in self._agents.items():
220
- # Check if agent has an mcp_aggregator (agent instance)
221
- if hasattr(agent_proxy, "_agent") and hasattr(
222
- agent_proxy._agent, "list_prompts"
223
- ):
224
- rich_print(
225
- f"\n[bold]Fetching prompts for agent [cyan]{agent_name}[/cyan]...[/bold]"
226
- )
227
- prompt_servers = (
228
- await agent_proxy._agent.list_prompts()
229
- )
230
-
231
- if prompt_servers:
232
- found_prompts = True
233
- for (
234
- server_name,
235
- prompts_info,
236
- ) in prompt_servers.items():
237
- if (
238
- prompts_info
239
- and hasattr(prompts_info, "prompts")
240
- and prompts_info.prompts
241
- ):
242
- rich_print(
243
- f"\n[bold cyan]{server_name}:[/bold cyan]"
244
- )
245
- for prompt in prompts_info.prompts:
246
- rich_print(f" {prompt.name}")
247
- elif (
248
- isinstance(prompts_info, list)
249
- and prompts_info
250
- ):
251
- rich_print(
252
- f"\n[bold cyan]{server_name}:[/bold cyan]"
253
- )
254
- for prompt in prompts_info:
255
- if (
256
- isinstance(prompt, dict)
257
- and "name" in prompt
258
- ):
259
- rich_print(
260
- f" {prompt['name']}"
261
- )
262
- else:
263
- rich_print(f" {prompt}")
264
-
265
- if not found_prompts:
266
- rich_print("[yellow]No prompts available[/yellow]")
267
- except Exception as e:
268
- rich_print(f"[red]Error listing prompts: {e}[/red]")
269
- continue
270
- elif "select_prompt" in command_result:
271
- from rich import print as rich_print
272
- from rich.table import Table
273
- from rich.console import Console
274
-
275
- console = Console()
276
-
277
- # Get the current agent proxy
278
- current_proxy = self._agents[agent]
279
-
280
- # Check if the agent has prompt capabilities
281
- if not hasattr(current_proxy, "_agent") or not hasattr(
282
- current_proxy._agent, "list_prompts"
283
- ):
284
- rich_print(
285
- f"[red]Current agent '{agent}' does not support prompts[/red]"
286
- )
287
- continue
288
-
289
- try:
290
- # Create a list to store prompt data for selection
291
- all_prompts = []
292
-
293
- # Get prompts from the current agent
294
- rich_print(
295
- f"\n[bold]Fetching prompts for agent [cyan]{agent}[/cyan]...[/bold]"
296
- )
297
- prompt_servers = await current_proxy._agent.list_prompts()
298
-
299
- if not prompt_servers:
300
- rich_print(
301
- "[yellow]No prompts available for this agent[/yellow]"
302
- )
303
- continue
304
-
305
- # Process retrieved prompts
306
- for server_name, prompts_info in prompt_servers.items():
307
- # Skip servers with no prompts
308
- if not prompts_info:
309
- continue
310
-
311
- # Extract prompts from the response
312
- prompts = []
313
- if hasattr(prompts_info, "prompts"):
314
- prompts = prompts_info.prompts
315
- elif isinstance(prompts_info, list):
316
- prompts = prompts_info
317
-
318
- # Process each prompt
319
- for prompt in prompts:
320
- # Basic prompt information
321
- prompt_name = getattr(prompt, "name", "Unknown")
322
- description = getattr(
323
- prompt, "description", "No description"
324
- )
325
-
326
- # Extract argument information
327
- arg_names = []
328
- required_args = []
329
- optional_args = []
330
- arg_descriptions = {}
331
-
332
- # Get arguments list from prompt (MCP SDK Prompt.arguments)
333
- arguments = getattr(prompt, "arguments", None)
334
- if arguments:
335
- for arg in arguments:
336
- # Each arg is a PromptArgument with name and required fields
337
- name = getattr(arg, "name", None)
338
- if name:
339
- arg_names.append(name)
340
-
341
- # Store description if available
342
- description = getattr(
343
- arg, "description", None
344
- )
345
- if description:
346
- arg_descriptions[name] = description
347
-
348
- # Check if required (default to False per MCP spec)
349
- if getattr(arg, "required", False):
350
- required_args.append(name)
351
- else:
352
- optional_args.append(name)
353
-
354
- # Create a namespaced version with the server
355
- namespaced_name = f"{server_name}-{prompt_name}"
356
-
357
- # Add to our collection
358
- all_prompts.append(
359
- {
360
- "server": server_name,
361
- "name": prompt_name,
362
- "namespaced_name": namespaced_name,
363
- "description": description,
364
- "arg_count": len(arg_names),
365
- "arg_names": arg_names,
366
- "required_args": required_args,
367
- "optional_args": optional_args,
368
- "arg_descriptions": arg_descriptions,
369
- }
370
- )
371
-
372
- # If no prompts were found
373
- if not all_prompts:
374
- rich_print(
375
- "[yellow]No prompts available for this agent[/yellow]"
376
- )
377
- continue
378
-
379
- # Sort prompts by server then name
380
- all_prompts.sort(key=lambda p: (p["server"], p["name"]))
381
-
382
- # Check if a specific prompt was requested
383
- if (
384
- "prompt_name" in command_result
385
- and command_result["prompt_name"]
386
- ):
387
- requested_name = command_result["prompt_name"]
388
- # Find the prompt in our list (either by name or namespaced name)
389
- matching_prompts = [
390
- p
391
- for p in all_prompts
392
- if p["name"] == requested_name
393
- or p["namespaced_name"] == requested_name
394
- ]
395
-
396
- if not matching_prompts:
397
- rich_print(
398
- f"[red]Prompt '{requested_name}' not found[/red]"
399
- )
400
- rich_print("[yellow]Available prompts:[/yellow]")
401
- for p in all_prompts:
402
- rich_print(f" {p['namespaced_name']}")
403
- continue
404
-
405
- # If we found exactly one match, use it
406
- if len(matching_prompts) == 1:
407
- selected_prompt = matching_prompts[0]
408
- else:
409
- # If multiple matches, show them and ask user to be more specific
410
- rich_print(
411
- f"[yellow]Multiple prompts match '{requested_name}':[/yellow]"
412
- )
413
- for i, p in enumerate(matching_prompts):
414
- rich_print(
415
- f" {i + 1}. {p['namespaced_name']} - {p['description']}"
416
- )
417
-
418
- # Ask user to select one
419
- from mcp_agent.core.enhanced_prompt import (
420
- get_selection_input,
421
- )
422
-
423
- selection = await get_selection_input(
424
- "Enter prompt number to select: ", default="1"
425
- )
426
-
427
- try:
428
- idx = int(selection) - 1
429
- if 0 <= idx < len(matching_prompts):
430
- selected_prompt = matching_prompts[idx]
431
- else:
432
- rich_print("[red]Invalid selection[/red]")
433
- continue
434
- except ValueError:
435
- rich_print(
436
- "[red]Invalid input, please enter a number[/red]"
437
- )
438
- continue
439
- else:
440
- # Display prompt selection UI
441
- table = Table(title="Available MCP Prompts")
442
- table.add_column("#", justify="right", style="cyan")
443
- table.add_column("Server", style="green")
444
- table.add_column("Prompt Name", style="bright_blue")
445
- table.add_column("Description")
446
- table.add_column("Args", justify="center")
447
-
448
- # Add all prompts to the table
449
- for i, prompt in enumerate(all_prompts):
450
- # Get argument counts
451
- required_args = prompt["required_args"]
452
- optional_args = prompt["optional_args"]
453
-
454
- # Format args column nicely
455
- if required_args and optional_args:
456
- args_display = f"[bold]{len(required_args)}[/bold]+{len(optional_args)}"
457
- elif required_args:
458
- args_display = (
459
- f"[bold]{len(required_args)}[/bold]"
460
- )
461
- elif optional_args:
462
- args_display = f"{len(optional_args)} opt"
463
- else:
464
- args_display = "0"
465
-
466
- table.add_row(
467
- str(i + 1),
468
- prompt["server"],
469
- prompt["name"],
470
- prompt["description"] or "No description",
471
- args_display,
472
- )
473
-
474
- console.print(table)
475
- prompt_names = [
476
- str(i + 1) for i in range(len(all_prompts))
477
- ]
478
-
479
- # Ask user to select a prompt
480
- from mcp_agent.core.enhanced_prompt import (
481
- get_selection_input,
482
- )
483
-
484
- selection = await get_selection_input(
485
- "Enter prompt number to select (or press Enter to cancel): ",
486
- options=prompt_names,
487
- allow_cancel=True,
488
- )
489
-
490
- # Make cancellation easier
491
- if not selection or selection.strip() == "":
492
- rich_print(
493
- "[yellow]Prompt selection cancelled[/yellow]"
494
- )
495
- continue
496
-
497
- try:
498
- idx = int(selection) - 1
499
- if 0 <= idx < len(all_prompts):
500
- selected_prompt = all_prompts[idx]
501
- else:
502
- rich_print("[red]Invalid selection[/red]")
503
- continue
504
- except ValueError:
505
- rich_print(
506
- "[red]Invalid input, please enter a number[/red]"
507
- )
508
- continue
509
-
510
- # Get our prompt arguments
511
- required_args = selected_prompt["required_args"]
512
- optional_args = selected_prompt["optional_args"]
513
- arg_descriptions = selected_prompt.get(
514
- "arg_descriptions", {}
515
- )
516
-
517
- # Always initialize arg_values
518
- arg_values = {}
519
-
520
- # Show argument info if we have any
521
- if required_args or optional_args:
522
- # Display information about the arguments
523
- if required_args and optional_args:
524
- rich_print(
525
- f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] requires {len(required_args)} arguments and has {len(optional_args)} optional arguments:[/bold]"
526
- )
527
- elif required_args:
528
- rich_print(
529
- f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] requires {len(required_args)} arguments:[/bold]"
530
- )
531
- elif optional_args:
532
- rich_print(
533
- f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] has {len(optional_args)} optional arguments:[/bold]"
534
- )
535
-
536
- # Collect required arguments
537
- for arg_name in required_args:
538
- # Get description if available
539
- description = arg_descriptions.get(arg_name, "")
540
-
541
- # Collect required argument value
542
- from mcp_agent.core.enhanced_prompt import (
543
- get_argument_input,
544
- )
545
-
546
- arg_value = await get_argument_input(
547
- arg_name=arg_name,
548
- description=description,
549
- required=True,
550
- )
551
- # Add to arg_values if a value was provided
552
- if arg_value is not None:
553
- arg_values[arg_name] = arg_value
554
-
555
- # Only include non-empty values for optional arguments
556
- if optional_args:
557
- # Collect optional arguments
558
- for arg_name in optional_args:
559
- # Get description if available
560
- description = arg_descriptions.get(arg_name, "")
561
-
562
- from mcp_agent.core.enhanced_prompt import (
563
- get_argument_input,
564
- )
565
-
566
- arg_value = await get_argument_input(
567
- arg_name=arg_name,
568
- description=description,
569
- required=False,
570
- )
571
- # Only include non-empty values for optional arguments
572
- if arg_value:
573
- arg_values[arg_name] = arg_value
574
-
575
- # Apply the prompt with or without arguments
576
- rich_print(
577
- f"\n[bold]Applying prompt [cyan]{selected_prompt['namespaced_name']}[/cyan]...[/bold]"
578
- )
579
-
580
- # Call apply_prompt on the agent - always pass arg_values (empty dict if no args)
581
- await current_proxy._agent.apply_prompt(
582
- selected_prompt["namespaced_name"], arg_values
583
- )
584
-
585
- except Exception as e:
586
- import traceback
587
-
588
- rich_print(
589
- f"[red]Error selecting or applying prompt: {e}[/red]"
590
- )
591
- rich_print(f"[dim]{traceback.format_exc()}[/dim]")
592
- continue
593
-
594
- # Skip further processing if command was handled
595
- if command_result:
596
- continue
597
-
598
- if user_input.upper() == "STOP":
599
- return result
600
- if user_input == "":
601
- continue
602
-
603
- result = await self.send(user_input, agent)
604
-
605
- # Check if current agent is a chain that should continue with final agent
606
- if agent_types.get(agent) == "Chain":
607
- proxy = self._agents[agent]
608
- if isinstance(proxy, ChainProxy) and proxy._continue_with_final:
609
- # Get the last agent in the sequence
610
- last_agent = proxy._sequence[-1]
611
- # Switch to that agent for the next iteration
612
- agent = last_agent
613
-
614
- return result
615
-
616
- def __getattr__(self, name: str) -> BaseAgentProxy:
617
- """Support: agent.researcher"""
618
- if name not in self._agents:
619
- raise AttributeError(f"No agent named '{name}'")
620
- return self._agents[name]
621
-
622
- def __getitem__(self, name: str) -> BaseAgentProxy:
623
- """Support: agent['researcher']"""
624
- if name not in self._agents:
625
- raise KeyError(f"No agent named '{name}'")
626
- return self._agents[name]
627
-
628
- async def __call__(
629
- self,
630
- message: Optional[Union[str, PromptMessageMultipart]] = None,
631
- agent_name: Optional[str] = None,
632
- ) -> str:
633
- """
634
- Support: agent('message') or agent(Prompt.user('message'))
635
-
636
- Args:
637
- message: Either a string message or a PromptMessageMultipart object
638
- agent_name: The name of the agent to use (uses default if None)
639
-
640
- Returns:
641
- The agent's response as a string
642
- """
643
- target = agent_name or self._default
644
- if not target:
645
- raise ValueError("No default agent available")
646
- return await self.send(message, target)