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.
- {fast_agent_mcp-0.1.12.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 +61 -415
- 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 +11 -21
- mcp_agent/agents/workflow/parallel_agent.py +182 -0
- mcp_agent/agents/workflow/router_agent.py +307 -0
- mcp_agent/app.py +15 -19
- mcp_agent/cli/commands/bootstrap.py +19 -38
- mcp_agent/cli/commands/config.py +4 -4
- mcp_agent/cli/commands/setup.py +7 -14
- mcp_agent/cli/main.py +7 -10
- mcp_agent/cli/terminal.py +3 -3
- mcp_agent/config.py +25 -40
- mcp_agent/context.py +12 -21
- mcp_agent/context_dependent.py +3 -5
- 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 +23 -55
- mcp_agent/core/exceptions.py +8 -8
- mcp_agent/core/fastagent.py +145 -371
- mcp_agent/core/interactive_prompt.py +424 -0
- mcp_agent/core/mcp_content.py +17 -17
- mcp_agent/core/prompt.py +6 -9
- mcp_agent/core/request_params.py +6 -3
- mcp_agent/core/validation.py +92 -18
- mcp_agent/executor/decorator_registry.py +9 -17
- mcp_agent/executor/executor.py +8 -17
- mcp_agent/executor/task_registry.py +2 -4
- mcp_agent/executor/temporal.py +19 -41
- mcp_agent/executor/workflow.py +3 -5
- mcp_agent/executor/workflow_signal.py +15 -21
- mcp_agent/human_input/handler.py +4 -7
- mcp_agent/human_input/types.py +2 -3
- mcp_agent/llm/__init__.py +2 -0
- mcp_agent/llm/augmented_llm.py +450 -0
- mcp_agent/llm/augmented_llm_passthrough.py +162 -0
- mcp_agent/llm/augmented_llm_playback.py +83 -0
- mcp_agent/llm/memory.py +103 -0
- mcp_agent/{workflows/llm → llm}/model_factory.py +22 -16
- mcp_agent/{workflows/llm → llm}/prompt_utils.py +1 -3
- mcp_agent/llm/providers/__init__.py +8 -0
- mcp_agent/{workflows/llm → llm/providers}/anthropic_utils.py +8 -25
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_anthropic.py +56 -194
- mcp_agent/llm/providers/augmented_llm_deepseek.py +53 -0
- mcp_agent/{workflows/llm → llm/providers}/augmented_llm_openai.py +99 -190
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_anthropic.py +72 -71
- mcp_agent/{workflows/llm → llm}/providers/multipart_converter_openai.py +65 -71
- mcp_agent/{workflows/llm → llm}/providers/openai_multipart.py +16 -44
- mcp_agent/{workflows/llm → llm/providers}/openai_utils.py +4 -4
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_anthropic.py +9 -11
- mcp_agent/{workflows/llm → llm}/providers/sampling_converter_openai.py +8 -12
- mcp_agent/{workflows/llm → llm}/sampling_converter.py +3 -31
- mcp_agent/llm/sampling_format_converter.py +37 -0
- mcp_agent/logging/events.py +1 -5
- mcp_agent/logging/json_serializer.py +7 -6
- mcp_agent/logging/listeners.py +20 -23
- mcp_agent/logging/logger.py +17 -19
- mcp_agent/logging/rich_progress.py +10 -8
- mcp_agent/logging/tracing.py +4 -6
- mcp_agent/logging/transport.py +22 -22
- mcp_agent/mcp/gen_client.py +1 -3
- mcp_agent/mcp/interfaces.py +117 -110
- mcp_agent/mcp/logger_textio.py +97 -0
- mcp_agent/mcp/mcp_agent_client_session.py +7 -7
- mcp_agent/mcp/mcp_agent_server.py +8 -8
- mcp_agent/mcp/mcp_aggregator.py +102 -143
- mcp_agent/mcp/mcp_connection_manager.py +20 -27
- mcp_agent/mcp/prompt_message_multipart.py +68 -16
- mcp_agent/mcp/prompt_render.py +77 -0
- mcp_agent/mcp/prompt_serialization.py +30 -48
- 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 +109 -0
- mcp_agent/mcp/prompts/prompt_server.py +155 -195
- mcp_agent/mcp/prompts/prompt_template.py +35 -66
- mcp_agent/mcp/resource_utils.py +7 -14
- mcp_agent/mcp/sampling.py +17 -17
- mcp_agent/mcp_server/agent_server.py +13 -17
- mcp_agent/mcp_server_registry.py +13 -22
- mcp_agent/resources/examples/{workflows → in_dev}/agent_build.py +3 -2
- mcp_agent/resources/examples/in_dev/slides.py +110 -0
- mcp_agent/resources/examples/internal/agent.py +6 -3
- mcp_agent/resources/examples/internal/fastagent.config.yaml +8 -2
- mcp_agent/resources/examples/internal/job.py +2 -1
- mcp_agent/resources/examples/internal/prompt_category.py +1 -1
- mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
- mcp_agent/resources/examples/internal/sizer.py +2 -1
- mcp_agent/resources/examples/internal/social.py +2 -1
- mcp_agent/resources/examples/prompting/agent.py +2 -1
- mcp_agent/resources/examples/prompting/image_server.py +4 -8
- mcp_agent/resources/examples/prompting/work_with_image.py +19 -0
- mcp_agent/ui/console_display.py +16 -20
- fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
- mcp_agent/core/agent_app.py +0 -646
- mcp_agent/core/agent_utils.py +0 -71
- mcp_agent/core/decorators.py +0 -455
- mcp_agent/core/factory.py +0 -463
- mcp_agent/core/proxies.py +0 -269
- mcp_agent/core/types.py +0 -24
- mcp_agent/eval/__init__.py +0 -0
- mcp_agent/mcp/stdio.py +0 -111
- 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 -190
- mcp_agent/resources/examples/researcher/researcher.py +0 -38
- mcp_agent/resources/examples/workflows/chaining.py +0 -44
- mcp_agent/resources/examples/workflows/evaluator.py +0 -78
- mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -24
- mcp_agent/resources/examples/workflows/human_input.py +0 -25
- mcp_agent/resources/examples/workflows/orchestrator.py +0 -73
- mcp_agent/resources/examples/workflows/parallel.py +0 -78
- mcp_agent/resources/examples/workflows/router.py +0 -53
- mcp_agent/resources/examples/workflows/sse.py +0 -23
- mcp_agent/telemetry/__init__.py +0 -0
- mcp_agent/telemetry/usage_tracking.py +0 -18
- mcp_agent/workflows/__init__.py +0 -0
- mcp_agent/workflows/embedding/__init__.py +0 -0
- mcp_agent/workflows/embedding/embedding_base.py +0 -61
- mcp_agent/workflows/embedding/embedding_cohere.py +0 -49
- mcp_agent/workflows/embedding/embedding_openai.py +0 -46
- mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +0 -481
- mcp_agent/workflows/intent_classifier/__init__.py +0 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +0 -120
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +0 -134
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +0 -45
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +0 -45
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +0 -161
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +0 -60
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +0 -60
- mcp_agent/workflows/llm/__init__.py +0 -0
- mcp_agent/workflows/llm/augmented_llm.py +0 -753
- mcp_agent/workflows/llm/augmented_llm_passthrough.py +0 -241
- mcp_agent/workflows/llm/augmented_llm_playback.py +0 -109
- mcp_agent/workflows/llm/providers/__init__.py +0 -8
- mcp_agent/workflows/llm/sampling_format_converter.py +0 -22
- mcp_agent/workflows/orchestrator/__init__.py +0 -0
- mcp_agent/workflows/orchestrator/orchestrator.py +0 -578
- mcp_agent/workflows/parallel/__init__.py +0 -0
- mcp_agent/workflows/parallel/fan_in.py +0 -350
- mcp_agent/workflows/parallel/fan_out.py +0 -187
- mcp_agent/workflows/parallel/parallel_llm.py +0 -166
- mcp_agent/workflows/router/__init__.py +0 -0
- mcp_agent/workflows/router/router_base.py +0 -368
- mcp_agent/workflows/router/router_embedding.py +0 -240
- 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 -320
- mcp_agent/workflows/swarm/__init__.py +0 -0
- mcp_agent/workflows/swarm/swarm.py +0 -320
- mcp_agent/workflows/swarm/swarm_anthropic.py +0 -42
- mcp_agent/workflows/swarm/swarm_openai.py +0 -41
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.1.12.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/core/fastagent.py
CHANGED
@@ -1,72 +1,70 @@
|
|
1
1
|
"""
|
2
|
-
|
3
|
-
|
2
|
+
Direct FastAgent implementation that uses the simplified Agent architecture.
|
3
|
+
This replaces the traditional FastAgent with a more streamlined approach that
|
4
|
+
directly creates Agent instances without proxies.
|
4
5
|
"""
|
5
6
|
|
6
|
-
import asyncio
|
7
|
-
from typing import (
|
8
|
-
Optional,
|
9
|
-
Dict,
|
10
|
-
TypeVar,
|
11
|
-
Any,
|
12
|
-
)
|
13
|
-
import yaml
|
14
7
|
import argparse
|
8
|
+
import asyncio
|
9
|
+
import os
|
15
10
|
from contextlib import asynccontextmanager
|
16
|
-
from
|
11
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar
|
12
|
+
|
13
|
+
import yaml
|
17
14
|
|
18
15
|
from mcp_agent.app import MCPApp
|
19
16
|
from mcp_agent.config import Settings
|
20
|
-
|
21
|
-
from mcp_agent.core.
|
22
|
-
from mcp_agent.core.
|
17
|
+
from mcp_agent.context import Context
|
18
|
+
from mcp_agent.core.direct_agent_app import DirectAgentApp
|
19
|
+
from mcp_agent.core.direct_decorators import (
|
20
|
+
agent as agent_decorator,
|
21
|
+
)
|
22
|
+
from mcp_agent.core.direct_decorators import (
|
23
|
+
chain as chain_decorator,
|
24
|
+
)
|
25
|
+
from mcp_agent.core.direct_decorators import (
|
26
|
+
evaluator_optimizer as evaluator_optimizer_decorator,
|
27
|
+
)
|
28
|
+
from mcp_agent.core.direct_decorators import (
|
29
|
+
orchestrator as orchestrator_decorator,
|
30
|
+
)
|
31
|
+
from mcp_agent.core.direct_decorators import (
|
32
|
+
parallel as parallel_decorator,
|
33
|
+
)
|
34
|
+
from mcp_agent.core.direct_decorators import (
|
35
|
+
router as router_decorator,
|
36
|
+
)
|
37
|
+
from mcp_agent.core.direct_factory import (
|
38
|
+
create_agents_in_dependency_order,
|
39
|
+
get_model_factory,
|
40
|
+
)
|
23
41
|
from mcp_agent.core.error_handling import handle_error
|
24
|
-
from mcp_agent.core.proxies import LLMAgentProxy
|
25
|
-
from mcp_agent.core.types import ProxyDict
|
26
42
|
from mcp_agent.core.exceptions import (
|
27
43
|
AgentConfigError,
|
28
44
|
CircularDependencyError,
|
29
45
|
ModelConfigError,
|
30
46
|
PromptExitError,
|
31
|
-
ServerConfigError,
|
32
47
|
ProviderKeyError,
|
48
|
+
ServerConfigError,
|
33
49
|
ServerInitializationError,
|
34
50
|
)
|
35
|
-
from mcp_agent.core.decorators import (
|
36
|
-
_create_decorator,
|
37
|
-
agent,
|
38
|
-
orchestrator,
|
39
|
-
parallel,
|
40
|
-
evaluator_optimizer,
|
41
|
-
router,
|
42
|
-
chain,
|
43
|
-
passthrough,
|
44
|
-
)
|
45
51
|
from mcp_agent.core.validation import (
|
46
52
|
validate_server_references,
|
47
53
|
validate_workflow_references,
|
48
54
|
)
|
49
|
-
from mcp_agent.
|
50
|
-
get_model_factory,
|
51
|
-
create_basic_agents,
|
52
|
-
create_agents_in_dependency_order,
|
53
|
-
create_agents_by_type,
|
54
|
-
)
|
55
|
-
|
56
|
-
# TODO -- reinstate once Windows&Python 3.13 platform issues are fixed
|
57
|
-
# import readline # noqa: F401
|
58
|
-
|
59
|
-
from rich import print
|
55
|
+
from mcp_agent.logging.logger import get_logger
|
60
56
|
|
61
|
-
|
57
|
+
if TYPE_CHECKING:
|
58
|
+
from mcp_agent.agents.agent import Agent
|
62
59
|
|
63
|
-
|
60
|
+
F = TypeVar("F", bound=Callable[..., Any]) # For decorated functions
|
61
|
+
logger = get_logger(__name__)
|
64
62
|
|
65
63
|
|
66
64
|
class FastAgent:
|
67
65
|
"""
|
68
|
-
A
|
69
|
-
|
66
|
+
A simplified FastAgent implementation that directly creates Agent instances
|
67
|
+
without using proxies.
|
70
68
|
"""
|
71
69
|
|
72
70
|
def __init__(
|
@@ -74,22 +72,20 @@ class FastAgent:
|
|
74
72
|
name: str,
|
75
73
|
config_path: Optional[str] = None,
|
76
74
|
ignore_unknown_args: bool = False,
|
77
|
-
):
|
75
|
+
) -> None:
|
78
76
|
"""
|
79
|
-
Initialize the
|
77
|
+
Initialize the DirectFastAgent application.
|
80
78
|
|
81
79
|
Args:
|
82
80
|
name: Name of the application
|
83
81
|
config_path: Optional path to config file
|
82
|
+
ignore_unknown_args: Whether to ignore unknown command line arguments
|
84
83
|
"""
|
85
|
-
# Initialize ContextDependent
|
86
|
-
super().__init__()
|
87
|
-
|
88
84
|
# Setup command line argument parsing
|
89
|
-
parser = argparse.ArgumentParser(description="
|
85
|
+
parser = argparse.ArgumentParser(description="DirectFastAgent Application")
|
90
86
|
parser.add_argument(
|
91
87
|
"--model",
|
92
|
-
help="Override the default model for all agents
|
88
|
+
help="Override the default model for all agents",
|
93
89
|
)
|
94
90
|
parser.add_argument(
|
95
91
|
"--agent",
|
@@ -112,8 +108,6 @@ class FastAgent:
|
|
112
108
|
else:
|
113
109
|
self.args = parser.parse_args()
|
114
110
|
|
115
|
-
# Quiet mode will be handled in _load_config()
|
116
|
-
|
117
111
|
self.name = name
|
118
112
|
self.config_path = config_path
|
119
113
|
self._load_config()
|
@@ -123,216 +117,55 @@ class FastAgent:
|
|
123
117
|
name=name,
|
124
118
|
settings=Settings(**self.config) if hasattr(self, "config") else None,
|
125
119
|
)
|
126
|
-
self.agents: Dict[str, Dict[str, Any]] = {}
|
127
|
-
|
128
|
-
# Bind decorator methods to this instance
|
129
|
-
self._create_decorator = _create_decorator.__get__(self)
|
130
|
-
self.agent = agent.__get__(self)
|
131
|
-
self.orchestrator = orchestrator.__get__(self)
|
132
|
-
self.parallel = parallel.__get__(self)
|
133
|
-
self.evaluator_optimizer = evaluator_optimizer.__get__(self)
|
134
|
-
self.router = router.__get__(self)
|
135
|
-
self.chain = chain.__get__(self)
|
136
|
-
self.passthrough = passthrough.__get__(self)
|
137
120
|
|
138
|
-
|
139
|
-
|
140
|
-
@property
|
141
|
-
def context(self):
|
142
|
-
"""Access the application context"""
|
143
|
-
return self.app.context
|
121
|
+
# Dictionary to store agent configurations from decorators
|
122
|
+
self.agents: Dict[str, Dict[str, Any]] = {}
|
144
123
|
|
145
124
|
def _load_config(self) -> None:
|
146
|
-
"""Load configuration from YAML file
|
125
|
+
"""Load configuration from YAML file"""
|
147
126
|
if self.config_path:
|
148
127
|
with open(self.config_path) as f:
|
149
128
|
self.config = yaml.safe_load(f) or {}
|
129
|
+
elif os.path.exists("fastagent.config.yaml"):
|
130
|
+
with open("fastagent.config.yaml") as f:
|
131
|
+
self.config = yaml.safe_load(f) or {}
|
132
|
+
else:
|
133
|
+
self.config = {}
|
150
134
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
self
|
155
|
-
model: Optional[str] = None,
|
156
|
-
request_params: Optional[Any] = None,
|
157
|
-
) -> Any:
|
158
|
-
"""
|
159
|
-
Get model factory using specified or default model.
|
160
|
-
Model string is parsed by ModelFactory to determine provider and reasoning effort.
|
161
|
-
|
162
|
-
Args:
|
163
|
-
model: Optional model specification string
|
164
|
-
request_params: Optional RequestParams to configure LLM behavior
|
165
|
-
|
166
|
-
Returns:
|
167
|
-
ModelFactory instance for the specified or default model
|
168
|
-
"""
|
169
|
-
# Wrap the factory function to use our context and CLI model
|
170
|
-
return get_model_factory(
|
171
|
-
self.context,
|
172
|
-
model=model,
|
173
|
-
request_params=request_params,
|
174
|
-
cli_model=self.args.model if hasattr(self, "args") else None,
|
175
|
-
)
|
176
|
-
|
177
|
-
async def _create_agents_by_type(
|
178
|
-
self,
|
179
|
-
agent_app: MCPApp,
|
180
|
-
agent_type: AgentType,
|
181
|
-
active_agents: ProxyDict = None,
|
182
|
-
**kwargs,
|
183
|
-
) -> ProxyDict:
|
184
|
-
"""
|
185
|
-
Generic method to create agents of a specific type.
|
186
|
-
|
187
|
-
Args:
|
188
|
-
agent_app: The main application instance
|
189
|
-
agent_type: Type of agents to create
|
190
|
-
active_agents: Dictionary of already created agents/proxies (for dependencies)
|
191
|
-
**kwargs: Additional type-specific parameters
|
192
|
-
|
193
|
-
Returns:
|
194
|
-
Dictionary of initialized agents wrapped in appropriate proxies
|
195
|
-
"""
|
196
|
-
# Create a model factory function that we can pass to the factory module
|
197
|
-
model_factory_func = partial(self._get_model_factory)
|
198
|
-
|
199
|
-
return await create_agents_by_type(
|
200
|
-
agent_app,
|
201
|
-
self.agents,
|
202
|
-
agent_type,
|
203
|
-
active_agents,
|
204
|
-
model_factory_func=model_factory_func,
|
205
|
-
**kwargs,
|
206
|
-
)
|
207
|
-
|
208
|
-
async def _create_basic_agents(self, agent_app: MCPApp) -> ProxyDict:
|
209
|
-
"""
|
210
|
-
Create and initialize basic agents with their configurations.
|
211
|
-
|
212
|
-
Args:
|
213
|
-
agent_app: The main application instance
|
214
|
-
|
215
|
-
Returns:
|
216
|
-
Dictionary of initialized basic agents wrapped in appropriate proxies
|
217
|
-
"""
|
218
|
-
model_factory_func = partial(self._get_model_factory)
|
219
|
-
return await create_basic_agents(agent_app, self.agents, model_factory_func)
|
220
|
-
|
221
|
-
async def _create_orchestrators(
|
222
|
-
self, agent_app: MCPApp, active_agents: ProxyDict
|
223
|
-
) -> ProxyDict:
|
224
|
-
"""
|
225
|
-
Create orchestrator agents.
|
226
|
-
|
227
|
-
Args:
|
228
|
-
agent_app: The main application instance
|
229
|
-
active_agents: Dictionary of already created agents/proxies
|
230
|
-
|
231
|
-
Returns:
|
232
|
-
Dictionary of initialized orchestrator agents wrapped in appropriate proxies
|
233
|
-
"""
|
234
|
-
return await self._create_agents_by_type(
|
235
|
-
agent_app, AgentType.ORCHESTRATOR, active_agents
|
236
|
-
)
|
237
|
-
|
238
|
-
async def _create_evaluator_optimizers(
|
239
|
-
self, agent_app: MCPApp, active_agents: ProxyDict
|
240
|
-
) -> ProxyDict:
|
241
|
-
"""
|
242
|
-
Create evaluator-optimizer workflows.
|
243
|
-
|
244
|
-
Args:
|
245
|
-
agent_app: The main application instance
|
246
|
-
active_agents: Dictionary of already created agents/proxies
|
247
|
-
|
248
|
-
Returns:
|
249
|
-
Dictionary of initialized evaluator-optimizer workflows
|
250
|
-
"""
|
251
|
-
return await self._create_agents_by_type(
|
252
|
-
agent_app, AgentType.EVALUATOR_OPTIMIZER, active_agents
|
253
|
-
)
|
254
|
-
|
255
|
-
async def _create_parallel_agents(
|
256
|
-
self, agent_app: MCPApp, active_agents: ProxyDict
|
257
|
-
) -> ProxyDict:
|
258
|
-
"""
|
259
|
-
Create parallel execution agents in dependency order.
|
260
|
-
|
261
|
-
Args:
|
262
|
-
agent_app: The main application instance
|
263
|
-
active_agents: Dictionary of already created agents/proxies
|
264
|
-
|
265
|
-
Returns:
|
266
|
-
Dictionary of initialized parallel agents
|
267
|
-
"""
|
268
|
-
model_factory_func = partial(self._get_model_factory)
|
269
|
-
return await create_agents_in_dependency_order(
|
270
|
-
agent_app,
|
271
|
-
self.agents,
|
272
|
-
active_agents,
|
273
|
-
AgentType.PARALLEL,
|
274
|
-
model_factory_func,
|
275
|
-
)
|
276
|
-
|
277
|
-
async def _create_agents_in_dependency_order(
|
278
|
-
self, agent_app: MCPApp, active_agents: ProxyDict, agent_type: AgentType
|
279
|
-
) -> ProxyDict:
|
280
|
-
"""
|
281
|
-
Create agents in dependency order to avoid circular references.
|
282
|
-
Works for both Parallel and Chain workflows.
|
283
|
-
|
284
|
-
Args:
|
285
|
-
agent_app: The main application instance
|
286
|
-
active_agents: Dictionary of already created agents/proxies
|
287
|
-
agent_type: Type of agents to create (AgentType.PARALLEL or AgentType.CHAIN)
|
288
|
-
|
289
|
-
Returns:
|
290
|
-
Dictionary of initialized agents
|
291
|
-
"""
|
292
|
-
model_factory_func = partial(self._get_model_factory)
|
293
|
-
return await create_agents_in_dependency_order(
|
294
|
-
agent_app, self.agents, active_agents, agent_type, model_factory_func
|
295
|
-
)
|
296
|
-
|
297
|
-
async def _create_routers(
|
298
|
-
self, agent_app: MCPApp, active_agents: ProxyDict
|
299
|
-
) -> ProxyDict:
|
300
|
-
"""
|
301
|
-
Create router agents.
|
302
|
-
|
303
|
-
Args:
|
304
|
-
agent_app: The main application instance
|
305
|
-
active_agents: Dictionary of already created agents
|
135
|
+
@property
|
136
|
+
def context(self) -> Context:
|
137
|
+
"""Access the application context"""
|
138
|
+
return self.app.context
|
306
139
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
140
|
+
# Decorator methods with type-safe implementations
|
141
|
+
agent = agent_decorator
|
142
|
+
orchestrator = orchestrator_decorator
|
143
|
+
router = router_decorator
|
144
|
+
chain = chain_decorator
|
145
|
+
parallel = parallel_decorator
|
146
|
+
evaluator_optimizer = evaluator_optimizer_decorator
|
313
147
|
|
314
148
|
@asynccontextmanager
|
315
149
|
async def run(self):
|
316
150
|
"""
|
317
151
|
Context manager for running the application.
|
318
|
-
|
152
|
+
Initializes all registered agents.
|
319
153
|
"""
|
320
|
-
active_agents = {}
|
154
|
+
active_agents: Dict[str, Agent] = {}
|
321
155
|
had_error = False
|
322
156
|
await self.app.initialize()
|
323
157
|
|
324
|
-
# Handle quiet mode
|
158
|
+
# Handle quiet mode
|
325
159
|
quiet_mode = hasattr(self, "args") and self.args.quiet
|
326
160
|
|
327
161
|
try:
|
328
162
|
async with self.app.run() as agent_app:
|
329
|
-
# Apply quiet mode
|
163
|
+
# Apply quiet mode if requested
|
330
164
|
if (
|
331
165
|
quiet_mode
|
332
166
|
and hasattr(agent_app.context, "config")
|
333
167
|
and hasattr(agent_app.context.config, "logger")
|
334
168
|
):
|
335
|
-
# Apply after initialization but before agents are created
|
336
169
|
agent_app.context.config.logger.progress_display = False
|
337
170
|
agent_app.context.config.logger.show_chat = False
|
338
171
|
agent_app.context.config.logger.show_tools = False
|
@@ -340,54 +173,33 @@ class FastAgent:
|
|
340
173
|
# Directly disable the progress display singleton
|
341
174
|
from mcp_agent.progress_display import progress_display
|
342
175
|
|
343
|
-
progress_display.stop()
|
176
|
+
progress_display.stop()
|
344
177
|
|
345
178
|
# Pre-flight validation
|
346
179
|
validate_server_references(self.context, self.agents)
|
347
180
|
validate_workflow_references(self.agents)
|
348
181
|
|
349
|
-
#
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
# Create chains next - MOVED UP because evaluator-optimizers might depend on chains
|
364
|
-
chains = await self._create_agents_in_dependency_order(
|
365
|
-
agent_app, active_agents, AgentType.CHAIN
|
182
|
+
# Get a model factory function
|
183
|
+
def model_factory_func(model=None, request_params=None):
|
184
|
+
return get_model_factory(
|
185
|
+
self.context,
|
186
|
+
model=model,
|
187
|
+
request_params=request_params,
|
188
|
+
cli_model=self.args.model if hasattr(self, "args") else None,
|
189
|
+
)
|
190
|
+
|
191
|
+
# Create all agents in dependency order
|
192
|
+
active_agents = await create_agents_in_dependency_order(
|
193
|
+
self.app,
|
194
|
+
self.agents,
|
195
|
+
model_factory_func,
|
366
196
|
)
|
367
|
-
active_agents.update(chains)
|
368
197
|
|
369
|
-
#
|
370
|
-
|
371
|
-
agent_app, active_agents
|
372
|
-
)
|
373
|
-
active_agents.update(evaluator_optimizers)
|
374
|
-
|
375
|
-
# Create orchestrators last as they might depend on any other agent type
|
376
|
-
orchestrators = await self._create_orchestrators(
|
377
|
-
agent_app, active_agents
|
378
|
-
)
|
379
|
-
|
380
|
-
# Add orchestrators to active_agents (other types were already added)
|
381
|
-
active_agents.update(orchestrators)
|
382
|
-
|
383
|
-
# Create wrapper with all agents
|
384
|
-
wrapper = AgentApp(agent_app, active_agents)
|
385
|
-
|
386
|
-
# Store reference to AgentApp in MCPApp for proxies to access
|
387
|
-
agent_app._agent_app = wrapper
|
198
|
+
# Create a wrapper with all agents for simplified access
|
199
|
+
wrapper = DirectAgentApp(active_agents)
|
388
200
|
|
389
201
|
# Handle direct message sending if --agent and --message are provided
|
390
|
-
if self.args.agent and self.args.message:
|
202
|
+
if hasattr(self, "args") and self.args.agent and self.args.message:
|
391
203
|
agent_name = self.args.agent
|
392
204
|
message = self.args.message
|
393
205
|
|
@@ -399,145 +211,105 @@ class FastAgent:
|
|
399
211
|
raise SystemExit(1)
|
400
212
|
|
401
213
|
try:
|
402
|
-
# Get response
|
403
|
-
|
214
|
+
# Get response from the agent
|
215
|
+
agent = active_agents[agent_name]
|
216
|
+
response = await agent.send(message)
|
404
217
|
|
405
|
-
#
|
218
|
+
# Print the response in quiet mode
|
406
219
|
if self.args.quiet:
|
407
220
|
print(f"{response}")
|
408
221
|
|
409
222
|
raise SystemExit(0)
|
410
223
|
except Exception as e:
|
411
|
-
print(
|
412
|
-
f"\n\nError sending message to agent '{agent_name}': {str(e)}"
|
413
|
-
)
|
224
|
+
print(f"\n\nError sending message to agent '{agent_name}': {str(e)}")
|
414
225
|
raise SystemExit(1)
|
415
226
|
|
416
227
|
yield wrapper
|
417
228
|
|
418
|
-
except
|
229
|
+
except (
|
230
|
+
ServerConfigError,
|
231
|
+
ProviderKeyError,
|
232
|
+
AgentConfigError,
|
233
|
+
ServerInitializationError,
|
234
|
+
ModelConfigError,
|
235
|
+
CircularDependencyError,
|
236
|
+
PromptExitError,
|
237
|
+
) as e:
|
419
238
|
had_error = True
|
420
|
-
self._handle_error(
|
239
|
+
self._handle_error(e)
|
240
|
+
raise SystemExit(1)
|
241
|
+
|
242
|
+
finally:
|
243
|
+
# Clean up any active agents
|
244
|
+
if active_agents and not had_error:
|
245
|
+
for agent in active_agents.values():
|
246
|
+
try:
|
247
|
+
await agent.shutdown()
|
248
|
+
except Exception:
|
249
|
+
pass
|
250
|
+
|
251
|
+
def _handle_error(self, e: Exception, error_type: Optional[str] = None) -> None:
|
252
|
+
"""
|
253
|
+
Handle errors with consistent formatting and messaging.
|
254
|
+
|
255
|
+
Args:
|
256
|
+
e: The exception that was raised
|
257
|
+
error_type: Optional explicit error type
|
258
|
+
"""
|
259
|
+
if isinstance(e, ServerConfigError):
|
260
|
+
handle_error(
|
421
261
|
e,
|
422
262
|
"Server Configuration Error",
|
423
263
|
"Please check your 'fastagent.config.yaml' configuration file and add the missing server definitions.",
|
424
264
|
)
|
425
|
-
|
426
|
-
|
427
|
-
except ProviderKeyError as e:
|
428
|
-
had_error = True
|
429
|
-
self._handle_error(
|
265
|
+
elif isinstance(e, ProviderKeyError):
|
266
|
+
handle_error(
|
430
267
|
e,
|
431
268
|
"Provider Configuration Error",
|
432
269
|
"Please check your 'fastagent.secrets.yaml' configuration file and ensure all required API keys are set.",
|
433
270
|
)
|
434
|
-
|
435
|
-
|
436
|
-
except AgentConfigError as e:
|
437
|
-
had_error = True
|
438
|
-
self._handle_error(
|
271
|
+
elif isinstance(e, AgentConfigError):
|
272
|
+
handle_error(
|
439
273
|
e,
|
440
274
|
"Workflow or Agent Configuration Error",
|
441
275
|
"Please check your agent definition and ensure names and references are correct.",
|
442
276
|
)
|
443
|
-
|
444
|
-
|
445
|
-
except ServerInitializationError as e:
|
446
|
-
had_error = True
|
447
|
-
self._handle_error(
|
277
|
+
elif isinstance(e, ServerInitializationError):
|
278
|
+
handle_error(
|
448
279
|
e,
|
449
280
|
"MCP Server Startup Error",
|
450
281
|
"There was an error starting up the MCP Server.",
|
451
282
|
)
|
452
|
-
|
453
|
-
|
454
|
-
except ModelConfigError as e:
|
455
|
-
had_error = True
|
456
|
-
self._handle_error(
|
283
|
+
elif isinstance(e, ModelConfigError):
|
284
|
+
handle_error(
|
457
285
|
e,
|
458
286
|
"Model Configuration Error",
|
459
287
|
"Common models: gpt-4o, o3-mini, sonnet, haiku. for o3, set reasoning effort with o3-mini.high",
|
460
288
|
)
|
461
|
-
|
462
|
-
|
463
|
-
except CircularDependencyError as e:
|
464
|
-
had_error = True
|
465
|
-
self._handle_error(
|
289
|
+
elif isinstance(e, CircularDependencyError):
|
290
|
+
handle_error(
|
466
291
|
e,
|
467
292
|
"Circular Dependency Detected",
|
468
293
|
"Check your agent configuration for circular dependencies.",
|
469
294
|
)
|
470
|
-
|
471
|
-
|
472
|
-
except PromptExitError as e:
|
473
|
-
had_error = True
|
474
|
-
self._handle_error(
|
295
|
+
elif isinstance(e, PromptExitError):
|
296
|
+
handle_error(
|
475
297
|
e,
|
476
298
|
"User requested exit",
|
477
299
|
)
|
478
|
-
|
479
|
-
|
480
|
-
finally:
|
481
|
-
# Clean up any active agents without re-raising errors
|
482
|
-
if active_agents and not had_error:
|
483
|
-
for name, proxy in active_agents.items():
|
484
|
-
if isinstance(proxy, LLMAgentProxy):
|
485
|
-
try:
|
486
|
-
await proxy._agent.__aexit__(None, None, None)
|
487
|
-
except Exception as e:
|
488
|
-
print(f"DEBUG {e.message}")
|
489
|
-
pass # Ignore cleanup errors
|
490
|
-
|
491
|
-
def _handle_error(
|
492
|
-
self, e: Exception, error_type: str, suggestion: str = None
|
493
|
-
) -> None:
|
494
|
-
"""
|
495
|
-
Handle errors with consistent formatting and messaging.
|
496
|
-
|
497
|
-
Args:
|
498
|
-
e: The exception that was raised
|
499
|
-
error_type: Type of error to display
|
500
|
-
suggestion: Optional suggestion message to display
|
501
|
-
"""
|
502
|
-
handle_error(e, error_type, suggestion)
|
503
|
-
|
504
|
-
def _log_agent_load(self, agent_name: str) -> None:
|
505
|
-
# This function is no longer needed - agent loading is now handled in factory.py
|
506
|
-
pass
|
507
|
-
|
508
|
-
def create_mcp_server(
|
509
|
-
self,
|
510
|
-
agent_app_instance: AgentApp,
|
511
|
-
server_name: str = None,
|
512
|
-
server_description: str = None,
|
513
|
-
) -> AgentMCPServer:
|
514
|
-
"""
|
515
|
-
Create an MCP server that exposes the agents as tools.
|
516
|
-
|
517
|
-
Args:
|
518
|
-
agent_app_instance: The AgentApp instance with initialized agents
|
519
|
-
server_name: Optional custom name for the MCP server
|
520
|
-
server_description: Optional description for the MCP server
|
521
|
-
|
522
|
-
Returns:
|
523
|
-
An AgentMCPServer instance ready to be run
|
524
|
-
"""
|
525
|
-
return AgentMCPServer(
|
526
|
-
agent_app=agent_app_instance,
|
527
|
-
server_name=server_name or f"{self.name}-MCP-Server",
|
528
|
-
server_description=server_description,
|
529
|
-
)
|
300
|
+
else:
|
301
|
+
handle_error(e, error_type or "Error", "An unexpected error occurred.")
|
530
302
|
|
531
303
|
async def run_with_mcp_server(
|
532
304
|
self,
|
533
305
|
transport: str = "sse",
|
534
306
|
host: str = "0.0.0.0",
|
535
307
|
port: int = 8000,
|
536
|
-
server_name: str = None,
|
537
|
-
server_description: str = None,
|
538
|
-
):
|
308
|
+
server_name: Optional[str] = None,
|
309
|
+
server_description: Optional[str] = None,
|
310
|
+
) -> None:
|
539
311
|
"""
|
540
|
-
Run the
|
312
|
+
Run the application and expose agents through an MCP server.
|
541
313
|
|
542
314
|
Args:
|
543
315
|
transport: Transport protocol to use ("stdio" or "sse")
|
@@ -546,11 +318,13 @@ class FastAgent:
|
|
546
318
|
server_name: Optional custom name for the MCP server
|
547
319
|
server_description: Optional description for the MCP server
|
548
320
|
"""
|
321
|
+
from mcp_agent.mcp_server import AgentMCPServer
|
322
|
+
|
549
323
|
async with self.run() as agent_app:
|
550
324
|
# Create the MCP server
|
551
|
-
mcp_server =
|
552
|
-
|
553
|
-
server_name=server_name,
|
325
|
+
mcp_server = AgentMCPServer(
|
326
|
+
agent_app=agent_app,
|
327
|
+
server_name=server_name or f"{self.name}-MCP-Server",
|
554
328
|
server_description=server_description,
|
555
329
|
)
|
556
330
|
|