fast-agent-mcp 0.1.13__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 (147) hide show
  1. {fast_agent_mcp-0.1.13.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 +59 -371
  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 +27 -11
  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 +3 -1
  14. mcp_agent/cli/commands/bootstrap.py +18 -7
  15. mcp_agent/cli/commands/setup.py +12 -4
  16. mcp_agent/cli/main.py +1 -1
  17. mcp_agent/cli/terminal.py +1 -1
  18. mcp_agent/config.py +24 -35
  19. mcp_agent/context.py +3 -1
  20. mcp_agent/context_dependent.py +3 -1
  21. mcp_agent/core/agent_types.py +10 -7
  22. mcp_agent/core/direct_agent_app.py +179 -0
  23. mcp_agent/core/direct_decorators.py +443 -0
  24. mcp_agent/core/direct_factory.py +476 -0
  25. mcp_agent/core/enhanced_prompt.py +15 -20
  26. mcp_agent/core/fastagent.py +151 -337
  27. mcp_agent/core/interactive_prompt.py +424 -0
  28. mcp_agent/core/mcp_content.py +19 -11
  29. mcp_agent/core/prompt.py +6 -2
  30. mcp_agent/core/validation.py +89 -16
  31. mcp_agent/executor/decorator_registry.py +6 -2
  32. mcp_agent/executor/temporal.py +35 -11
  33. mcp_agent/executor/workflow_signal.py +8 -2
  34. mcp_agent/human_input/handler.py +3 -1
  35. mcp_agent/llm/__init__.py +2 -0
  36. mcp_agent/{workflows/llm → llm}/augmented_llm.py +131 -256
  37. mcp_agent/{workflows/llm → llm}/augmented_llm_passthrough.py +35 -107
  38. mcp_agent/llm/augmented_llm_playback.py +83 -0
  39. mcp_agent/{workflows/llm → llm}/model_factory.py +26 -8
  40. mcp_agent/llm/providers/__init__.py +8 -0
  41. mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +5 -1
  42. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +37 -141
  43. mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
  44. mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +112 -148
  45. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +78 -35
  46. mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +73 -44
  47. mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +18 -4
  48. mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +3 -3
  49. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +3 -3
  50. mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +3 -3
  51. mcp_agent/{workflows/llm → llm}/sampling_converter.py +0 -21
  52. mcp_agent/{workflows/llm → llm}/sampling_format_converter.py +16 -1
  53. mcp_agent/logging/logger.py +2 -2
  54. mcp_agent/mcp/gen_client.py +9 -3
  55. mcp_agent/mcp/interfaces.py +67 -45
  56. mcp_agent/mcp/logger_textio.py +97 -0
  57. mcp_agent/mcp/mcp_agent_client_session.py +12 -4
  58. mcp_agent/mcp/mcp_agent_server.py +3 -1
  59. mcp_agent/mcp/mcp_aggregator.py +124 -93
  60. mcp_agent/mcp/mcp_connection_manager.py +21 -7
  61. mcp_agent/mcp/prompt_message_multipart.py +59 -1
  62. mcp_agent/mcp/prompt_render.py +77 -0
  63. mcp_agent/mcp/prompt_serialization.py +20 -13
  64. mcp_agent/mcp/prompts/prompt_constants.py +18 -0
  65. mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
  66. mcp_agent/mcp/prompts/prompt_load.py +15 -5
  67. mcp_agent/mcp/prompts/prompt_server.py +154 -87
  68. mcp_agent/mcp/prompts/prompt_template.py +26 -35
  69. mcp_agent/mcp/resource_utils.py +3 -1
  70. mcp_agent/mcp/sampling.py +24 -15
  71. mcp_agent/mcp_server/agent_server.py +8 -5
  72. mcp_agent/mcp_server_registry.py +22 -9
  73. mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +1 -1
  74. mcp_agent/resources/examples/{data-analysis → in_dev}/slides.py +1 -1
  75. mcp_agent/resources/examples/internal/agent.py +4 -2
  76. mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
  77. mcp_agent/resources/examples/prompting/image_server.py +3 -1
  78. mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
  79. mcp_agent/ui/console_display.py +27 -7
  80. fast_agent_mcp-0.1.13.dist-info/RECORD +0 -164
  81. mcp_agent/core/agent_app.py +0 -570
  82. mcp_agent/core/agent_utils.py +0 -69
  83. mcp_agent/core/decorators.py +0 -448
  84. mcp_agent/core/factory.py +0 -422
  85. mcp_agent/core/proxies.py +0 -278
  86. mcp_agent/core/types.py +0 -22
  87. mcp_agent/eval/__init__.py +0 -0
  88. mcp_agent/mcp/stdio.py +0 -114
  89. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
  90. mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
  91. mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
  92. mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
  93. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
  94. mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
  95. mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
  96. mcp_agent/resources/examples/researcher/researcher-imp.py +0 -189
  97. mcp_agent/resources/examples/researcher/researcher.py +0 -39
  98. mcp_agent/resources/examples/workflows/chaining.py +0 -45
  99. mcp_agent/resources/examples/workflows/evaluator.py +0 -79
  100. mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
  101. mcp_agent/resources/examples/workflows/human_input.py +0 -26
  102. mcp_agent/resources/examples/workflows/orchestrator.py +0 -74
  103. mcp_agent/resources/examples/workflows/parallel.py +0 -79
  104. mcp_agent/resources/examples/workflows/router.py +0 -54
  105. mcp_agent/resources/examples/workflows/sse.py +0 -23
  106. mcp_agent/telemetry/__init__.py +0 -0
  107. mcp_agent/telemetry/usage_tracking.py +0 -19
  108. mcp_agent/workflows/__init__.py +0 -0
  109. mcp_agent/workflows/embedding/__init__.py +0 -0
  110. mcp_agent/workflows/embedding/embedding_base.py +0 -58
  111. mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
  112. mcp_agent/workflows/embedding/embedding_openai.py +0 -37
  113. mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
  114. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -447
  115. mcp_agent/workflows/intent_classifier/__init__.py +0 -0
  116. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -117
  117. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -130
  118. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -41
  119. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -41
  120. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -150
  121. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
  122. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -58
  123. mcp_agent/workflows/llm/__init__.py +0 -0
  124. mcp_agent/workflows/llm/augmented_llm_playback.py +0 -111
  125. mcp_agent/workflows/llm/providers/__init__.py +0 -8
  126. mcp_agent/workflows/orchestrator/__init__.py +0 -0
  127. mcp_agent/workflows/orchestrator/orchestrator.py +0 -535
  128. mcp_agent/workflows/parallel/__init__.py +0 -0
  129. mcp_agent/workflows/parallel/fan_in.py +0 -320
  130. mcp_agent/workflows/parallel/fan_out.py +0 -181
  131. mcp_agent/workflows/parallel/parallel_llm.py +0 -149
  132. mcp_agent/workflows/router/__init__.py +0 -0
  133. mcp_agent/workflows/router/router_base.py +0 -338
  134. mcp_agent/workflows/router/router_embedding.py +0 -226
  135. mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
  136. mcp_agent/workflows/router/router_embedding_openai.py +0 -59
  137. mcp_agent/workflows/router/router_llm.py +0 -304
  138. mcp_agent/workflows/swarm/__init__.py +0 -0
  139. mcp_agent/workflows/swarm/swarm.py +0 -292
  140. mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
  141. mcp_agent/workflows/swarm/swarm_openai.py +0 -41
  142. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
  143. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
  144. {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
  145. /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
  146. /mcp_agent/{workflows/llm → llm}/memory.py +0 -0
  147. /mcp_agent/{workflows/llm → llm}/prompt_utils.py +0 -0
@@ -0,0 +1,476 @@
1
+ """
2
+ Direct factory functions for creating agent and workflow instances without proxies.
3
+ Implements type-safe factories with improved error handling.
4
+ """
5
+
6
+ from typing import Any, Callable, Dict, Optional, Protocol, TypeVar
7
+
8
+ from mcp_agent.agents.agent import Agent, AgentConfig
9
+ from mcp_agent.agents.workflow.evaluator_optimizer import (
10
+ EvaluatorOptimizerAgent,
11
+ QualityRating,
12
+ )
13
+ from mcp_agent.agents.workflow.orchestrator_agent import OrchestratorAgent
14
+ from mcp_agent.agents.workflow.parallel_agent import ParallelAgent
15
+ from mcp_agent.agents.workflow.router_agent import RouterAgent
16
+ from mcp_agent.app import MCPApp
17
+ from mcp_agent.core.agent_types import AgentType
18
+ from mcp_agent.core.exceptions import AgentConfigError
19
+ from mcp_agent.core.validation import get_dependencies_groups
20
+ from mcp_agent.event_progress import ProgressAction
21
+ from mcp_agent.llm.augmented_llm import RequestParams
22
+ from mcp_agent.llm.model_factory import ModelFactory
23
+ from mcp_agent.logging.logger import get_logger
24
+
25
+ # Type aliases for improved readability and IDE support
26
+ AgentDict = Dict[str, Agent]
27
+ AgentConfigDict = Dict[str, Dict[str, Any]]
28
+ T = TypeVar("T") # For generic types
29
+
30
+ # Type for model factory functions
31
+ ModelFactoryFn = Callable[[Optional[str], Optional[RequestParams]], Callable[[], Any]]
32
+
33
+
34
+ logger = get_logger(__name__)
35
+
36
+
37
+ class AgentCreatorProtocol(Protocol):
38
+ """Protocol for agent creator functions."""
39
+
40
+ async def __call__(
41
+ self,
42
+ app_instance: MCPApp,
43
+ agents_dict: AgentConfigDict,
44
+ agent_type: AgentType,
45
+ active_agents: Optional[AgentDict] = None,
46
+ model_factory_func: Optional[ModelFactoryFn] = None,
47
+ **kwargs: Any,
48
+ ) -> AgentDict: ...
49
+
50
+
51
+ def get_model_factory(
52
+ context,
53
+ model: Optional[str] = None,
54
+ request_params: Optional[RequestParams] = None,
55
+ default_model: Optional[str] = None,
56
+ cli_model: Optional[str] = None,
57
+ ) -> Callable:
58
+ """
59
+ Get model factory using specified or default model.
60
+ Model string is parsed by ModelFactory to determine provider and reasoning effort.
61
+
62
+ Args:
63
+ context: Application context
64
+ model: Optional model specification string (highest precedence)
65
+ request_params: Optional RequestParams to configure LLM behavior
66
+ default_model: Default model from configuration
67
+ cli_model: Model specified via command line
68
+
69
+ Returns:
70
+ ModelFactory instance for the specified or default model
71
+ """
72
+ # Config has lowest precedence
73
+ model_spec = default_model or context.config.default_model
74
+
75
+ # Command line override has next precedence
76
+ if cli_model:
77
+ model_spec = cli_model
78
+
79
+ # Model from decorator has highest precedence
80
+ if model:
81
+ model_spec = model
82
+
83
+ # Update or create request_params with the final model choice
84
+ if request_params:
85
+ request_params = request_params.model_copy(update={"model": model_spec})
86
+ else:
87
+ request_params = RequestParams(model=model_spec)
88
+
89
+ # Let model factory handle the model string parsing and setup
90
+ return ModelFactory.create_factory(model_spec, request_params=request_params)
91
+
92
+
93
+ async def create_agents_by_type(
94
+ app_instance: MCPApp,
95
+ agents_dict: AgentConfigDict,
96
+ agent_type: AgentType,
97
+ active_agents: Optional[AgentDict] = None,
98
+ model_factory_func: Optional[ModelFactoryFn] = None,
99
+ **kwargs: Any,
100
+ ) -> AgentDict:
101
+ """
102
+ Generic method to create agents of a specific type without using proxies.
103
+
104
+ Args:
105
+ app_instance: The main application instance
106
+ agents_dict: Dictionary of agent configurations
107
+ agent_type: Type of agents to create
108
+ active_agents: Dictionary of already created agents (for dependencies)
109
+ model_factory_func: Function for creating model factories
110
+ **kwargs: Additional type-specific parameters
111
+
112
+ Returns:
113
+ Dictionary of initialized agent instances
114
+ """
115
+ if active_agents is None:
116
+ active_agents = {}
117
+
118
+ if model_factory_func is None:
119
+ # Default factory that just returns the inputs - should be overridden
120
+ def model_factory_func(model=None, request_params=None):
121
+ return lambda: None
122
+
123
+ # Create a dictionary to store the initialized agents
124
+ result_agents: AgentDict = {}
125
+
126
+ # Get all agents of the specified type
127
+ for name, agent_data in agents_dict.items():
128
+ logger.info(
129
+ f"Loaded {name}",
130
+ data={
131
+ "progress_action": ProgressAction.LOADED,
132
+ "agent_name": name,
133
+ },
134
+ )
135
+
136
+ if agent_data["type"] == agent_type.value:
137
+ # Get common configuration
138
+ config = agent_data["config"]
139
+
140
+ # Type-specific initialization
141
+ if agent_type == AgentType.BASIC:
142
+ # Create a basic agent
143
+ agent = Agent(
144
+ config=config,
145
+ context=app_instance.context,
146
+ )
147
+ await agent.initialize()
148
+
149
+ # Attach LLM to the agent
150
+ llm_factory = model_factory_func(
151
+ model=config.model,
152
+ request_params=config.default_request_params,
153
+ )
154
+ await agent.attach_llm(llm_factory)
155
+ result_agents[name] = agent
156
+
157
+ elif agent_type == AgentType.ORCHESTRATOR:
158
+ # Get base params configured with model settings
159
+ base_params = (
160
+ config.default_request_params.model_copy()
161
+ if config.default_request_params
162
+ else RequestParams()
163
+ )
164
+ base_params.use_history = False # Force no history for orchestrator
165
+
166
+ # Get the child agents
167
+ child_agents = []
168
+ for agent_name in agent_data["child_agents"]:
169
+ if agent_name not in active_agents:
170
+ raise AgentConfigError(f"Agent {agent_name} not found")
171
+ agent = active_agents[agent_name]
172
+ child_agents.append(agent)
173
+
174
+ # Create the orchestrator
175
+ orchestrator = OrchestratorAgent(
176
+ config=config,
177
+ context=app_instance.context,
178
+ agents=child_agents,
179
+ plan_type=agent_data.get("plan_type", "full"),
180
+ )
181
+
182
+ # Initialize the orchestrator
183
+ await orchestrator.initialize()
184
+
185
+ # Attach LLM to the orchestrator
186
+ llm_factory = model_factory_func(
187
+ model=config.model,
188
+ request_params=config.default_request_params,
189
+ )
190
+ await orchestrator.attach_llm(llm_factory)
191
+
192
+ result_agents[name] = orchestrator
193
+
194
+ elif agent_type == AgentType.PARALLEL:
195
+ # Get the fan-out and fan-in agents
196
+ fan_in_name = agent_data.get("fan_in")
197
+ fan_out_names = agent_data["fan_out"]
198
+
199
+ # Create or retrieve the fan-in agent
200
+ if not fan_in_name:
201
+ # Create default fan-in agent with auto-generated name
202
+ fan_in_name = f"{name}_fan_in"
203
+ fan_in_agent = await _create_default_fan_in_agent(
204
+ fan_in_name,
205
+ app_instance.context,
206
+ model_factory_func
207
+ )
208
+ # Add to result_agents so it's registered properly
209
+ result_agents[fan_in_name] = fan_in_agent
210
+ elif fan_in_name not in active_agents:
211
+ raise AgentConfigError(f"Fan-in agent {fan_in_name} not found")
212
+ else:
213
+ fan_in_agent = active_agents[fan_in_name]
214
+
215
+ # Get the fan-out agents
216
+ fan_out_agents = []
217
+ for agent_name in fan_out_names:
218
+ if agent_name not in active_agents:
219
+ raise AgentConfigError(f"Fan-out agent {agent_name} not found")
220
+ fan_out_agents.append(active_agents[agent_name])
221
+
222
+ # Create the parallel agent
223
+ parallel = ParallelAgent(
224
+ config=config,
225
+ context=app_instance.context,
226
+ fan_in_agent=fan_in_agent,
227
+ fan_out_agents=fan_out_agents,
228
+ )
229
+ await parallel.initialize()
230
+ result_agents[name] = parallel
231
+
232
+ elif agent_type == AgentType.ROUTER:
233
+ # Get the router agents
234
+ router_agents = []
235
+ for agent_name in agent_data["router_agents"]:
236
+ if agent_name not in active_agents:
237
+ raise AgentConfigError(f"Router agent {agent_name} not found")
238
+ router_agents.append(active_agents[agent_name])
239
+
240
+ # Create the router agent
241
+ router = RouterAgent(
242
+ config=config,
243
+ context=app_instance.context,
244
+ agents=router_agents,
245
+ routing_instruction=agent_data.get("routing_instruction"),
246
+ )
247
+ await router.initialize()
248
+
249
+ # Attach LLM to the router
250
+ llm_factory = model_factory_func(
251
+ model=config.model,
252
+ request_params=config.default_request_params,
253
+ )
254
+ await router.attach_llm(llm_factory)
255
+ result_agents[name] = router
256
+
257
+ elif agent_type == AgentType.CHAIN:
258
+ # Get the chained agents
259
+ chain_agents = []
260
+
261
+ agent_names = agent_data["sequence"]
262
+ if 0 == len(agent_names):
263
+ raise AgentConfigError("No agents in the chain")
264
+
265
+ for agent_name in agent_data["sequence"]:
266
+ if agent_name not in active_agents:
267
+ raise AgentConfigError(f"Chain agent {agent_name} not found")
268
+ chain_agents.append(active_agents[agent_name])
269
+
270
+ from mcp_agent.agents.workflow.chain_agent import ChainAgent
271
+
272
+ # Get the cumulative parameter
273
+ cumulative = agent_data.get("cumulative", False)
274
+
275
+ chain = ChainAgent(
276
+ config=config,
277
+ context=app_instance.context,
278
+ agents=chain_agents,
279
+ cumulative=cumulative,
280
+ )
281
+ await chain.initialize()
282
+ result_agents[name] = chain
283
+
284
+ elif agent_type == AgentType.EVALUATOR_OPTIMIZER:
285
+ # Get the generator and evaluator agents
286
+ generator_name = agent_data["generator"]
287
+ evaluator_name = agent_data["evaluator"]
288
+
289
+ if generator_name not in active_agents:
290
+ raise AgentConfigError(f"Generator agent {generator_name} not found")
291
+
292
+ if evaluator_name not in active_agents:
293
+ raise AgentConfigError(f"Evaluator agent {evaluator_name} not found")
294
+
295
+ generator_agent = active_agents[generator_name]
296
+ evaluator_agent = active_agents[evaluator_name]
297
+
298
+ # Get min_rating and max_refinements from agent_data
299
+ min_rating_str = agent_data.get("min_rating", "GOOD")
300
+ min_rating = QualityRating(min_rating_str)
301
+ max_refinements = agent_data.get("max_refinements", 3)
302
+
303
+ # Create the evaluator-optimizer agent
304
+ evaluator_optimizer = EvaluatorOptimizerAgent(
305
+ config=config,
306
+ context=app_instance.context,
307
+ generator_agent=generator_agent,
308
+ evaluator_agent=evaluator_agent,
309
+ min_rating=min_rating,
310
+ max_refinements=max_refinements,
311
+ )
312
+
313
+ # Initialize the agent
314
+ await evaluator_optimizer.initialize()
315
+ result_agents[name] = evaluator_optimizer
316
+
317
+ else:
318
+ raise ValueError(f"Unknown agent type: {agent_type}")
319
+
320
+ return result_agents
321
+
322
+
323
+ async def create_agents_in_dependency_order(
324
+ app_instance: MCPApp,
325
+ agents_dict: AgentConfigDict,
326
+ model_factory_func: ModelFactoryFn,
327
+ allow_cycles: bool = False,
328
+ ) -> AgentDict:
329
+ """
330
+ Create agent instances in dependency order without proxies.
331
+
332
+ Args:
333
+ app_instance: The main application instance
334
+ agents_dict: Dictionary of agent configurations
335
+ model_factory_func: Function for creating model factories
336
+ allow_cycles: Whether to allow cyclic dependencies
337
+
338
+ Returns:
339
+ Dictionary of initialized agent instances
340
+ """
341
+ # Get the dependencies between agents
342
+ dependencies = get_dependencies_groups(agents_dict, allow_cycles)
343
+
344
+ # Create a dictionary to store all active agents/workflows
345
+ active_agents: AgentDict = {}
346
+
347
+ # Create agent proxies for each group in dependency order
348
+ for group in dependencies:
349
+ # Create basic agents first
350
+ if AgentType.BASIC.value in [agents_dict[name]["type"] for name in group]:
351
+ basic_agents = await create_agents_by_type(
352
+ app_instance,
353
+ {
354
+ name: agents_dict[name]
355
+ for name in group
356
+ if agents_dict[name]["type"] == AgentType.BASIC.value
357
+ },
358
+ AgentType.BASIC,
359
+ active_agents,
360
+ model_factory_func,
361
+ )
362
+ active_agents.update(basic_agents)
363
+
364
+ # Create parallel agents
365
+ if AgentType.PARALLEL.value in [agents_dict[name]["type"] for name in group]:
366
+ parallel_agents = await create_agents_by_type(
367
+ app_instance,
368
+ {
369
+ name: agents_dict[name]
370
+ for name in group
371
+ if agents_dict[name]["type"] == AgentType.PARALLEL.value
372
+ },
373
+ AgentType.PARALLEL,
374
+ active_agents,
375
+ model_factory_func,
376
+ )
377
+ active_agents.update(parallel_agents)
378
+
379
+ # Create router agents
380
+ if AgentType.ROUTER.value in [agents_dict[name]["type"] for name in group]:
381
+ router_agents = await create_agents_by_type(
382
+ app_instance,
383
+ {
384
+ name: agents_dict[name]
385
+ for name in group
386
+ if agents_dict[name]["type"] == AgentType.ROUTER.value
387
+ },
388
+ AgentType.ROUTER,
389
+ active_agents,
390
+ model_factory_func,
391
+ )
392
+ active_agents.update(router_agents)
393
+
394
+ # Create chain agents
395
+ if AgentType.CHAIN.value in [agents_dict[name]["type"] for name in group]:
396
+ chain_agents = await create_agents_by_type(
397
+ app_instance,
398
+ {
399
+ name: agents_dict[name]
400
+ for name in group
401
+ if agents_dict[name]["type"] == AgentType.CHAIN.value
402
+ },
403
+ AgentType.CHAIN,
404
+ active_agents,
405
+ model_factory_func,
406
+ )
407
+ active_agents.update(chain_agents)
408
+
409
+ # Create evaluator-optimizer agents
410
+ if AgentType.EVALUATOR_OPTIMIZER.value in [agents_dict[name]["type"] for name in group]:
411
+ evaluator_agents = await create_agents_by_type(
412
+ app_instance,
413
+ {
414
+ name: agents_dict[name]
415
+ for name in group
416
+ if agents_dict[name]["type"] == AgentType.EVALUATOR_OPTIMIZER.value
417
+ },
418
+ AgentType.EVALUATOR_OPTIMIZER,
419
+ active_agents,
420
+ model_factory_func,
421
+ )
422
+ active_agents.update(evaluator_agents)
423
+
424
+ # Create orchestrator agents last since they might depend on other agents
425
+ if AgentType.ORCHESTRATOR.value in [agents_dict[name]["type"] for name in group]:
426
+ orchestrator_agents = await create_agents_by_type(
427
+ app_instance,
428
+ {
429
+ name: agents_dict[name]
430
+ for name in group
431
+ if agents_dict[name]["type"] == AgentType.ORCHESTRATOR.value
432
+ },
433
+ AgentType.ORCHESTRATOR,
434
+ active_agents,
435
+ model_factory_func,
436
+ )
437
+ active_agents.update(orchestrator_agents)
438
+
439
+ return active_agents
440
+
441
+
442
+ async def _create_default_fan_in_agent(
443
+ fan_in_name: str,
444
+ context,
445
+ model_factory_func: ModelFactoryFn,
446
+ ) -> Agent:
447
+ """
448
+ Create a default fan-in agent for parallel workflows when none is specified.
449
+
450
+ Args:
451
+ fan_in_name: Name for the new fan-in agent
452
+ context: Application context
453
+ model_factory_func: Function for creating model factories
454
+
455
+ Returns:
456
+ Initialized Agent instance for fan-in operations
457
+ """
458
+ # Create a simple config for the fan-in agent with passthrough model
459
+ default_config = AgentConfig(
460
+ name=fan_in_name,
461
+ model="passthrough",
462
+ instruction="You are a passthrough agent that combines outputs from parallel agents."
463
+ )
464
+
465
+ # Create and initialize the default agent
466
+ fan_in_agent = Agent(
467
+ config=default_config,
468
+ context=context,
469
+ )
470
+ await fan_in_agent.initialize()
471
+
472
+ # Attach LLM to the agent
473
+ llm_factory = model_factory_func(model="passthrough")
474
+ await fan_in_agent.attach_llm(llm_factory)
475
+
476
+ return fan_in_agent
@@ -11,9 +11,7 @@ from prompt_toolkit.filters import Condition
11
11
  from prompt_toolkit.formatted_text import HTML
12
12
  from prompt_toolkit.history import InMemoryHistory
13
13
  from prompt_toolkit.key_binding import KeyBindings
14
- from prompt_toolkit.lexers import PygmentsLexer
15
14
  from prompt_toolkit.styles import Style
16
- from pygments.lexers.python import PythonLexer
17
15
  from rich import print as rich_print
18
16
 
19
17
  from mcp_agent.core.exceptions import PromptExitError
@@ -151,7 +149,6 @@ async def get_enhanced_input(
151
149
  show_stop_hint: bool = False,
152
150
  multiline: bool = False,
153
151
  available_agent_names: List[str] = None,
154
- syntax: str = None,
155
152
  agent_types: dict = None,
156
153
  is_human_input: bool = False,
157
154
  toolbar_color: str = "ansiblue",
@@ -166,7 +163,6 @@ async def get_enhanced_input(
166
163
  show_stop_hint: Whether to show the STOP hint
167
164
  multiline: Start in multiline mode
168
165
  available_agent_names: List of agent names for auto-completion
169
- syntax: Syntax highlighting (e.g., 'python', 'sql')
170
166
  agent_types: Dictionary mapping agent names to their types for display
171
167
  is_human_input: Whether this is a human input request (disables agent selection features)
172
168
  toolbar_color: Color to use for the agent name in the toolbar (default: "ansiblue")
@@ -238,7 +234,6 @@ async def get_enhanced_input(
238
234
  is_human_input=is_human_input,
239
235
  ),
240
236
  complete_while_typing=True,
241
- lexer=PygmentsLexer(PythonLexer) if syntax == "python" else None,
242
237
  multiline=Condition(lambda: in_multiline_mode),
243
238
  complete_in_thread=True,
244
239
  mouse_support=False,
@@ -269,7 +264,9 @@ async def get_enhanced_input(
269
264
  if is_human_input:
270
265
  rich_print("[dim]Type /help for commands. Ctrl+T toggles multiline mode.[/dim]")
271
266
  else:
272
- rich_print("[dim]Type /help for commands, @agent to switch agent. Ctrl+T toggles multiline mode.[/dim]")
267
+ rich_print(
268
+ "[dim]Type /help for commands, @agent to switch agent. Ctrl+T toggles multiline mode.[/dim]"
269
+ )
273
270
  rich_print()
274
271
  help_message_shown = True
275
272
 
@@ -288,7 +285,7 @@ async def get_enhanced_input(
288
285
  elif cmd == "agents":
289
286
  return "LIST_AGENTS"
290
287
  elif cmd == "prompts":
291
- return "SELECT_PROMPT" # Changed from LIST_PROMPTS to directly launch selection UI
288
+ return "SELECT_PROMPT" # Directly launch prompt selection UI
292
289
  elif cmd == "prompt" and len(cmd_parts) > 1:
293
290
  # Direct prompt selection with name
294
291
  return f"SELECT_PROMPT:{cmd_parts[1].strip()}"
@@ -396,7 +393,9 @@ async def get_argument_input(
396
393
  if description:
397
394
  rich_print(f" [dim]{arg_name}: {description}[/dim]")
398
395
 
399
- prompt_text = HTML(f"Enter value for <ansibrightcyan>{arg_name}</ansibrightcyan> {required_text}: ")
396
+ prompt_text = HTML(
397
+ f"Enter value for <ansibrightcyan>{arg_name}</ansibrightcyan> {required_text}: "
398
+ )
400
399
 
401
400
  # Create prompt session
402
401
  prompt_session = PromptSession()
@@ -463,17 +462,11 @@ async def handle_special_commands(command, agent_app=None):
463
462
  rich_print("[yellow]No agents available[/yellow]")
464
463
  return True
465
464
 
466
- elif command == "LIST_PROMPTS":
467
- # Return a dictionary with a list_prompts action to be handled by the caller
468
- # The actual prompt listing is implemented in the AgentApp class
469
- if agent_app:
470
- rich_print("\n[bold]Fetching available MCP prompts...[/bold]")
471
- return {"list_prompts": True}
472
- else:
473
- rich_print("[yellow]Prompt listing is not available outside of an agent context[/yellow]")
474
- return True
465
+ # Removed LIST_PROMPTS handling as it's now covered by SELECT_PROMPT
475
466
 
476
- elif command == "SELECT_PROMPT" or (isinstance(command, str) and command.startswith("SELECT_PROMPT:")):
467
+ elif command == "SELECT_PROMPT" or (
468
+ isinstance(command, str) and command.startswith("SELECT_PROMPT:")
469
+ ):
477
470
  # Handle prompt selection UI
478
471
  if agent_app:
479
472
  # If it's a specific prompt, extract the name
@@ -484,14 +477,16 @@ async def handle_special_commands(command, agent_app=None):
484
477
  # Return a dictionary with a select_prompt action to be handled by the caller
485
478
  return {"select_prompt": True, "prompt_name": prompt_name}
486
479
  else:
487
- rich_print("[yellow]Prompt selection is not available outside of an agent context[/yellow]")
480
+ rich_print(
481
+ "[yellow]Prompt selection is not available outside of an agent context[/yellow]"
482
+ )
488
483
  return True
489
484
 
490
485
  elif isinstance(command, str) and command.startswith("SWITCH:"):
491
486
  agent_name = command.split(":", 1)[1]
492
487
  if agent_name in available_agents:
493
488
  if agent_app:
494
- # rich_print(f"[green]Switching to agent: {agent_name}[/green]")
489
+ # The parameter can be the actual agent_app or just True to enable switching
495
490
  return {"switch_agent": agent_name}
496
491
  else:
497
492
  rich_print("[yellow]Agent switching not available in this context[/yellow]")