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.
- {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/METADATA +3 -4
- fast_agent_mcp-0.2.0.dist-info/RECORD +123 -0
- mcp_agent/__init__.py +75 -0
- mcp_agent/agents/agent.py +59 -371
- mcp_agent/agents/base_agent.py +522 -0
- mcp_agent/agents/workflow/__init__.py +1 -0
- mcp_agent/agents/workflow/chain_agent.py +173 -0
- mcp_agent/agents/workflow/evaluator_optimizer.py +362 -0
- mcp_agent/agents/workflow/orchestrator_agent.py +591 -0
- mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_models.py +27 -11
- mcp_agent/agents/workflow/parallel_agent.py +182 -0
- mcp_agent/agents/workflow/router_agent.py +307 -0
- mcp_agent/app.py +3 -1
- mcp_agent/cli/commands/bootstrap.py +18 -7
- mcp_agent/cli/commands/setup.py +12 -4
- mcp_agent/cli/main.py +1 -1
- mcp_agent/cli/terminal.py +1 -1
- mcp_agent/config.py +24 -35
- mcp_agent/context.py +3 -1
- mcp_agent/context_dependent.py +3 -1
- mcp_agent/core/agent_types.py +10 -7
- mcp_agent/core/direct_agent_app.py +179 -0
- mcp_agent/core/direct_decorators.py +443 -0
- mcp_agent/core/direct_factory.py +476 -0
- mcp_agent/core/enhanced_prompt.py +15 -20
- mcp_agent/core/fastagent.py +151 -337
- mcp_agent/core/interactive_prompt.py +424 -0
- mcp_agent/core/mcp_content.py +19 -11
- mcp_agent/core/prompt.py +6 -2
- mcp_agent/core/validation.py +89 -16
- mcp_agent/executor/decorator_registry.py +6 -2
- mcp_agent/executor/temporal.py +35 -11
- mcp_agent/executor/workflow_signal.py +8 -2
- mcp_agent/human_input/handler.py +3 -1
- mcp_agent/llm/__init__.py +2 -0
- mcp_agent/{workflows/llm → llm}/augmented_llm.py +131 -256
- mcp_agent/{workflows/llm → llm}/augmented_llm_passthrough.py +35 -107
- mcp_agent/llm/augmented_llm_playback.py +83 -0
- mcp_agent/{workflows/llm → llm}/model_factory.py +26 -8
- mcp_agent/llm/providers/__init__.py +8 -0
- mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +5 -1
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +37 -141
- mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +112 -148
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +78 -35
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +73 -44
- mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +18 -4
- mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +3 -3
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +3 -3
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +3 -3
- mcp_agent/{workflows/llm → llm}/sampling_converter.py +0 -21
- mcp_agent/{workflows/llm → llm}/sampling_format_converter.py +16 -1
- mcp_agent/logging/logger.py +2 -2
- mcp_agent/mcp/gen_client.py +9 -3
- mcp_agent/mcp/interfaces.py +67 -45
- mcp_agent/mcp/logger_textio.py +97 -0
- mcp_agent/mcp/mcp_agent_client_session.py +12 -4
- mcp_agent/mcp/mcp_agent_server.py +3 -1
- mcp_agent/mcp/mcp_aggregator.py +124 -93
- mcp_agent/mcp/mcp_connection_manager.py +21 -7
- mcp_agent/mcp/prompt_message_multipart.py +59 -1
- mcp_agent/mcp/prompt_render.py +77 -0
- mcp_agent/mcp/prompt_serialization.py +20 -13
- mcp_agent/mcp/prompts/prompt_constants.py +18 -0
- mcp_agent/mcp/prompts/prompt_helpers.py +327 -0
- mcp_agent/mcp/prompts/prompt_load.py +15 -5
- mcp_agent/mcp/prompts/prompt_server.py +154 -87
- mcp_agent/mcp/prompts/prompt_template.py +26 -35
- mcp_agent/mcp/resource_utils.py +3 -1
- mcp_agent/mcp/sampling.py +24 -15
- mcp_agent/mcp_server/agent_server.py +8 -5
- mcp_agent/mcp_server_registry.py +22 -9
- mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +1 -1
- mcp_agent/resources/examples/{data-analysis → in_dev}/slides.py +1 -1
- mcp_agent/resources/examples/internal/agent.py +4 -2
- mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
- mcp_agent/resources/examples/prompting/image_server.py +3 -1
- mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
- mcp_agent/ui/console_display.py +27 -7
- fast_agent_mcp-0.1.13.dist-info/RECORD +0 -164
- mcp_agent/core/agent_app.py +0 -570
- mcp_agent/core/agent_utils.py +0 -69
- mcp_agent/core/decorators.py +0 -448
- mcp_agent/core/factory.py +0 -422
- mcp_agent/core/proxies.py +0 -278
- mcp_agent/core/types.py +0 -22
- mcp_agent/eval/__init__.py +0 -0
- mcp_agent/mcp/stdio.py +0 -114
- mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -188
- mcp_agent/resources/examples/data-analysis/analysis.py +0 -65
- mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -41
- mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -1471
- mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +0 -53
- mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -66
- mcp_agent/resources/examples/researcher/researcher-eval.py +0 -53
- mcp_agent/resources/examples/researcher/researcher-imp.py +0 -189
- mcp_agent/resources/examples/researcher/researcher.py +0 -39
- mcp_agent/resources/examples/workflows/chaining.py +0 -45
- mcp_agent/resources/examples/workflows/evaluator.py +0 -79
- mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
- mcp_agent/resources/examples/workflows/human_input.py +0 -26
- mcp_agent/resources/examples/workflows/orchestrator.py +0 -74
- mcp_agent/resources/examples/workflows/parallel.py +0 -79
- mcp_agent/resources/examples/workflows/router.py +0 -54
- mcp_agent/resources/examples/workflows/sse.py +0 -23
- mcp_agent/telemetry/__init__.py +0 -0
- mcp_agent/telemetry/usage_tracking.py +0 -19
- mcp_agent/workflows/__init__.py +0 -0
- mcp_agent/workflows/embedding/__init__.py +0 -0
- mcp_agent/workflows/embedding/embedding_base.py +0 -58
- mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
- mcp_agent/workflows/embedding/embedding_openai.py +0 -37
- mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -447
- mcp_agent/workflows/intent_classifier/__init__.py +0 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -117
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -130
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -41
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -41
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -150
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -58
- mcp_agent/workflows/llm/__init__.py +0 -0
- mcp_agent/workflows/llm/augmented_llm_playback.py +0 -111
- mcp_agent/workflows/llm/providers/__init__.py +0 -8
- mcp_agent/workflows/orchestrator/__init__.py +0 -0
- mcp_agent/workflows/orchestrator/orchestrator.py +0 -535
- mcp_agent/workflows/parallel/__init__.py +0 -0
- mcp_agent/workflows/parallel/fan_in.py +0 -320
- mcp_agent/workflows/parallel/fan_out.py +0 -181
- mcp_agent/workflows/parallel/parallel_llm.py +0 -149
- mcp_agent/workflows/router/__init__.py +0 -0
- mcp_agent/workflows/router/router_base.py +0 -338
- mcp_agent/workflows/router/router_embedding.py +0 -226
- mcp_agent/workflows/router/router_embedding_cohere.py +0 -59
- mcp_agent/workflows/router/router_embedding_openai.py +0 -59
- mcp_agent/workflows/router/router_llm.py +0 -304
- mcp_agent/workflows/swarm/__init__.py +0 -0
- mcp_agent/workflows/swarm/swarm.py +0 -292
- mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
- mcp_agent/workflows/swarm/swarm_openai.py +0 -41
- {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.1.13.dist-info → fast_agent_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
- /mcp_agent/{workflows/orchestrator → agents/workflow}/orchestrator_prompts.py +0 -0
- /mcp_agent/{workflows/llm → llm}/memory.py +0 -0
- /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(
|
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" #
|
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(
|
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
|
-
|
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 (
|
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(
|
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
|
-
#
|
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]")
|