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
mcp_agent/core/factory.py DELETED
@@ -1,422 +0,0 @@
1
- """
2
- Factory functions for creating agent and workflow instances.
3
- """
4
-
5
- from typing import Any, Callable, Dict, Optional, TypeVar
6
-
7
- from mcp_agent.agents.agent import Agent
8
- from mcp_agent.app import MCPApp
9
- from mcp_agent.core.agent_types import AgentConfig, AgentType
10
- from mcp_agent.core.agent_utils import get_agent_instances, log_agent_load, unwrap_proxy
11
- from mcp_agent.core.exceptions import AgentConfigError
12
- from mcp_agent.core.proxies import (
13
- BaseAgentProxy,
14
- ChainProxy,
15
- LLMAgentProxy,
16
- RouterProxy,
17
- WorkflowProxy,
18
- )
19
- from mcp_agent.core.types import AgentOrWorkflow, ProxyDict
20
- from mcp_agent.core.validation import get_dependencies
21
- from mcp_agent.event_progress import ProgressAction
22
- from mcp_agent.workflows.evaluator_optimizer.evaluator_optimizer import (
23
- EvaluatorOptimizerLLM,
24
- QualityRating,
25
- )
26
- from mcp_agent.workflows.llm.augmented_llm import RequestParams
27
- from mcp_agent.workflows.llm.model_factory import ModelFactory
28
- from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator
29
- from mcp_agent.workflows.parallel.parallel_llm import ParallelLLM
30
- from mcp_agent.workflows.router.router_llm import LLMRouter
31
-
32
- T = TypeVar("T") # For the wrapper classes
33
-
34
-
35
- def create_proxy(app: MCPApp, name: str, instance: AgentOrWorkflow, agent_type: str) -> BaseAgentProxy:
36
- """Create appropriate proxy type based on agent type and validate instance type
37
-
38
- Args:
39
- app: The MCPApp instance
40
- name: Name of the agent/workflow
41
- instance: The agent or workflow instance
42
- agent_type: Type from AgentType enum values
43
-
44
- Returns:
45
- Appropriate proxy type wrapping the instance
46
-
47
- Raises:
48
- TypeError: If instance type doesn't match expected type for agent_type
49
- """
50
- if agent_type not in [
51
- AgentType.PARALLEL.value,
52
- AgentType.EVALUATOR_OPTIMIZER.value,
53
- AgentType.CHAIN.value,
54
- ]:
55
- log_agent_load(app, name)
56
- if agent_type == AgentType.BASIC.value:
57
- if not isinstance(instance, Agent):
58
- raise TypeError(f"Expected Agent instance for {name}, got {type(instance)}")
59
- return LLMAgentProxy(app, name, instance)
60
- elif agent_type == AgentType.ORCHESTRATOR.value:
61
- if not isinstance(instance, Orchestrator):
62
- raise TypeError(f"Expected Orchestrator instance for {name}, got {type(instance)}")
63
- return WorkflowProxy(app, name, instance)
64
- elif agent_type == AgentType.PARALLEL.value:
65
- if not isinstance(instance, ParallelLLM):
66
- raise TypeError(f"Expected ParallelLLM instance for {name}, got {type(instance)}")
67
- return WorkflowProxy(app, name, instance)
68
- elif agent_type == AgentType.EVALUATOR_OPTIMIZER.value:
69
- if not isinstance(instance, EvaluatorOptimizerLLM):
70
- raise TypeError(f"Expected EvaluatorOptimizerLLM instance for {name}, got {type(instance)}")
71
- return WorkflowProxy(app, name, instance)
72
- elif agent_type == AgentType.ROUTER.value:
73
- if not isinstance(instance, LLMRouter):
74
- raise TypeError(f"Expected LLMRouter instance for {name}, got {type(instance)}")
75
- return RouterProxy(app, name, instance)
76
- elif agent_type == AgentType.CHAIN.value:
77
- # Chain proxy is directly returned from _create_agents_by_type
78
- # No need for type checking as it's already a ChainProxy
79
- return instance
80
- else:
81
- raise ValueError(f"Unknown agent type: {agent_type}")
82
-
83
-
84
- def get_model_factory(
85
- context,
86
- model: Optional[str] = None,
87
- request_params: Optional[RequestParams] = None,
88
- default_model: Optional[str] = None,
89
- cli_model: Optional[str] = None,
90
- ) -> Any:
91
- """
92
- Get model factory using specified or default model.
93
- Model string is parsed by ModelFactory to determine provider and reasoning effort.
94
-
95
- Args:
96
- context: Application context
97
- model: Optional model specification string (highest precedence)
98
- request_params: Optional RequestParams to configure LLM behavior
99
- default_model: Default model from configuration
100
- cli_model: Model specified via command line
101
-
102
- Returns:
103
- ModelFactory instance for the specified or default model
104
- """
105
- # Config has lowest precedence
106
- model_spec = default_model or context.config.default_model
107
-
108
- # Command line override has next precedence
109
- if cli_model:
110
- model_spec = cli_model
111
-
112
- # Model from decorator has highest precedence
113
- if model:
114
- model_spec = model
115
-
116
- # Update or create request_params with the final model choice
117
- if request_params:
118
- request_params = request_params.model_copy(update={"model": model_spec})
119
- else:
120
- request_params = RequestParams(model=model_spec)
121
-
122
- # Let model factory handle the model string parsing and setup
123
- return ModelFactory.create_factory(model_spec, request_params=request_params)
124
-
125
-
126
- async def create_agents_by_type(
127
- app_instance: MCPApp,
128
- agents_dict: Dict[str, Dict[str, Any]],
129
- agent_type: AgentType,
130
- active_agents: ProxyDict = None,
131
- model_factory_func: Callable = None,
132
- **kwargs,
133
- ) -> ProxyDict:
134
- """
135
- Generic method to create agents of a specific type.
136
-
137
- Args:
138
- app_instance: The main application instance
139
- agents_dict: Dictionary of agent configurations
140
- agent_type: Type of agents to create
141
- active_agents: Dictionary of already created agents/proxies (for dependencies)
142
- model_factory_func: Function for creating model factories
143
- **kwargs: Additional type-specific parameters
144
-
145
- Returns:
146
- Dictionary of initialized agents wrapped in appropriate proxies
147
- """
148
- if active_agents is None:
149
- active_agents = {}
150
-
151
- # Create a dictionary to store the initialized agents
152
- result_agents = {}
153
-
154
- # Get all agents of the specified type
155
- for name, agent_data in agents_dict.items():
156
- if agent_data["type"] == agent_type.value:
157
- # Get common configuration
158
- config = agent_data["config"]
159
-
160
- # Type-specific initialization
161
- if agent_type == AgentType.BASIC:
162
- # Get the agent name for special handling
163
- agent_name = agent_data["config"].name
164
- agent = Agent(
165
- config=config,
166
- context=app_instance.context,
167
- )
168
- await agent.initialize()
169
-
170
- llm_factory = model_factory_func(
171
- model=config.model,
172
- request_params=config.default_request_params,
173
- )
174
- agent._llm = await agent.attach_llm(llm_factory)
175
- # Store the agent
176
- instance = agent
177
-
178
- elif agent_type == AgentType.ORCHESTRATOR:
179
- # Get base params configured with model settings
180
- base_params = config.default_request_params.model_copy() if config.default_request_params else RequestParams()
181
- base_params.use_history = False # Force no history for orchestrator
182
-
183
- # Get the child agents - need to unwrap proxies and validate LLM config
184
- child_agents = []
185
- for agent_name in agent_data["child_agents"]:
186
- proxy = active_agents[agent_name]
187
- instance = unwrap_proxy(proxy)
188
- # Validate basic agents have LLM
189
- if isinstance(instance, Agent):
190
- if not hasattr(instance, "_llm") or not instance._llm:
191
- raise AgentConfigError(
192
- f"Agent '{agent_name}' used by orchestrator '{name}' missing LLM configuration",
193
- "All agents must be fully configured with LLMs before being used in an orchestrator",
194
- )
195
- child_agents.append(instance)
196
-
197
- # Create a properly configured planner agent
198
- planner_config = AgentConfig(
199
- name=f"{name}", # Use orchestrator name as prefix
200
- instruction=config.instruction
201
- or """
202
- You are an expert planner. Given an objective task and a list of MCP servers (which are collections of tools)
203
- or Agents (which are collections of servers), your job is to break down the objective into a series of steps,
204
- which can be performed by LLMs with access to the servers or agents.
205
- """,
206
- servers=[], # Planner doesn't need server access
207
- model=config.model,
208
- default_request_params=base_params,
209
- )
210
- planner_agent = Agent(
211
- config=planner_config,
212
- context=app_instance.context,
213
- )
214
- planner_factory = model_factory_func(
215
- model=config.model,
216
- request_params=config.default_request_params,
217
- )
218
-
219
- planner = await planner_agent.attach_llm(planner_factory)
220
- # Create the orchestrator with pre-configured planner
221
- instance = Orchestrator(
222
- name=config.name,
223
- planner=planner, # Pass pre-configured planner
224
- available_agents=child_agents,
225
- context=app_instance.context,
226
- request_params=planner.default_request_params, # Base params already include model settings
227
- plan_type=agent_data.get("plan_type", "full"), # Get plan_type from agent_data
228
- verb=ProgressAction.PLANNING,
229
- )
230
-
231
- elif agent_type == AgentType.EVALUATOR_OPTIMIZER:
232
- # Get the referenced agents - unwrap from proxies
233
- generator = unwrap_proxy(active_agents[agent_data["generator"]])
234
- evaluator = unwrap_proxy(active_agents[agent_data["evaluator"]])
235
-
236
- if not generator or not evaluator:
237
- raise ValueError(f"Missing agents for workflow {name}: generator={agent_data['generator']}, evaluator={agent_data['evaluator']}")
238
-
239
- # Get model from generator if it's an Agent, or from config otherwise
240
- optimizer_model = None
241
- if isinstance(generator, Agent):
242
- optimizer_model = generator.config.model
243
- elif hasattr(generator, "_sequence") and hasattr(generator, "_agent_proxies"):
244
- # For ChainProxy, use the config model directly
245
- optimizer_model = config.model
246
-
247
- instance = EvaluatorOptimizerLLM(
248
- name=config.name, # Pass name from config
249
- generator=generator,
250
- evaluator=evaluator,
251
- min_rating=QualityRating[agent_data["min_rating"]],
252
- max_refinements=agent_data["max_refinements"],
253
- llm_factory=model_factory_func(model=optimizer_model),
254
- context=app_instance.context,
255
- instruction=config.instruction, # Pass any custom instruction
256
- )
257
-
258
- elif agent_type == AgentType.ROUTER:
259
- # Get the router's agents - unwrap proxies
260
- router_agents = get_agent_instances(agent_data["agents"], active_agents)
261
-
262
- # Create the router with proper configuration
263
- llm_factory = model_factory_func(
264
- model=config.model,
265
- request_params=config.default_request_params,
266
- )
267
-
268
- instance = LLMRouter(
269
- name=config.name,
270
- llm_factory=llm_factory,
271
- agents=router_agents,
272
- server_names=config.servers,
273
- context=app_instance.context,
274
- default_request_params=config.default_request_params,
275
- verb=ProgressAction.ROUTING, # Set verb for progress display
276
- )
277
-
278
- elif agent_type == AgentType.CHAIN:
279
- # Get the sequence from either parameter
280
- sequence = agent_data.get("sequence", agent_data.get("agents", []))
281
-
282
- # Auto-generate instruction if not provided or if it's just the default
283
- default_instruction = f"Chain of agents: {', '.join(sequence)}"
284
-
285
- # If user provided a custom instruction, use that
286
- # Otherwise, generate a description based on the sequence and their servers
287
- if config.instruction == default_instruction:
288
- # Get all agent names in the sequence
289
- agent_names = []
290
- all_servers = set()
291
-
292
- # Collect information about the agents and their servers
293
- for agent_name in sequence:
294
- if agent_name in active_agents:
295
- agent_proxy = active_agents[agent_name]
296
- if hasattr(agent_proxy, "_agent"):
297
- # For LLMAgentProxy
298
- agent_instance = agent_proxy._agent
299
- agent_names.append(agent_name)
300
- if hasattr(agent_instance, "server_names"):
301
- all_servers.update(agent_instance.server_names)
302
- elif hasattr(agent_proxy, "_workflow"):
303
- # For WorkflowProxy
304
- agent_names.append(agent_name)
305
-
306
- # Generate a better description
307
- if agent_names:
308
- server_part = f" with access to servers: {', '.join(sorted(all_servers))}" if all_servers else ""
309
- config.instruction = f"Sequence of agents: {', '.join(agent_names)}{server_part}."
310
-
311
- # Create a ChainProxy without needing a new instance
312
- # Just pass the agent proxies and sequence
313
- instance = ChainProxy(app_instance, name, sequence, active_agents)
314
- # Set continue_with_final behavior from configuration
315
- instance._continue_with_final = agent_data.get("continue_with_final", True)
316
- # Set cumulative behavior from configuration
317
- instance._cumulative = agent_data.get("cumulative", False)
318
-
319
- elif agent_type == AgentType.PARALLEL:
320
- fan_out_agents = get_agent_instances(agent_data["fan_out"], active_agents)
321
-
322
- # Get fan-in agent - unwrap proxy
323
- fan_in_agent = unwrap_proxy(active_agents[agent_data["fan_in"]])
324
-
325
- # Create the parallel workflow
326
- llm_factory = model_factory_func(config.model)
327
- instance = ParallelLLM(
328
- name=config.name,
329
- instruction=config.instruction,
330
- fan_out_agents=fan_out_agents,
331
- fan_in_agent=fan_in_agent,
332
- context=app_instance.context,
333
- llm_factory=llm_factory,
334
- default_request_params=config.default_request_params,
335
- include_request=agent_data.get("include_request", True),
336
- )
337
-
338
- else:
339
- raise ValueError(f"Unsupported agent type: {agent_type}")
340
-
341
- # Create the appropriate proxy and store in results
342
- result_agents[name] = create_proxy(app_instance, name, instance, agent_type.value)
343
-
344
- return result_agents
345
-
346
-
347
- async def create_basic_agents(
348
- app_instance: MCPApp,
349
- agents_dict: Dict[str, Dict[str, Any]],
350
- model_factory_func: Callable,
351
- ) -> ProxyDict:
352
- """
353
- Create and initialize basic agents with their configurations.
354
-
355
- Args:
356
- app_instance: The main application instance
357
- agents_dict: Dictionary of agent configurations
358
- model_factory_func: Function for creating model factories
359
-
360
- Returns:
361
- Dictionary of initialized basic agents wrapped in appropriate proxies
362
- """
363
- return await create_agents_by_type(
364
- app_instance,
365
- agents_dict,
366
- AgentType.BASIC,
367
- model_factory_func=model_factory_func,
368
- )
369
-
370
-
371
- async def create_agents_in_dependency_order(
372
- app_instance: MCPApp,
373
- agents_dict: Dict[str, Dict[str, Any]],
374
- active_agents: ProxyDict,
375
- agent_type: AgentType,
376
- model_factory_func: Callable,
377
- ) -> ProxyDict:
378
- """
379
- Create agents in dependency order to avoid circular references.
380
- Works for both Parallel and Chain workflows.
381
-
382
- Args:
383
- app_instance: The main application instance
384
- agents_dict: Dictionary of agent configurations
385
- active_agents: Dictionary of already created agents/proxies
386
- agent_type: Type of agents to create (AgentType.PARALLEL or AgentType.CHAIN)
387
- model_factory_func: Function for creating model factories
388
-
389
- Returns:
390
- Dictionary of initialized agents
391
- """
392
- result_agents = {}
393
- visited = set()
394
-
395
- # Get all agents of the specified type
396
- agent_names = [name for name, agent_data in agents_dict.items() if agent_data["type"] == agent_type.value]
397
-
398
- # Create agents in dependency order
399
- for name in agent_names:
400
- # Get ordered dependencies if not already processed
401
- if name not in visited:
402
- try:
403
- ordered_agents = get_dependencies(name, agents_dict, visited, set(), agent_type)
404
- except ValueError as e:
405
- raise ValueError(f"Error creating {agent_type.name.lower()} agent {name}: {str(e)}")
406
-
407
- # Create each agent in order
408
- for agent_name in ordered_agents:
409
- if agent_name not in result_agents:
410
- # Create one agent at a time using the generic method
411
- agent_result = await create_agents_by_type(
412
- app_instance,
413
- agents_dict,
414
- agent_type,
415
- active_agents,
416
- model_factory_func=model_factory_func,
417
- agent_name=agent_name,
418
- )
419
- if agent_name in agent_result:
420
- result_agents[agent_name] = agent_result[agent_name]
421
-
422
- return result_agents