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