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