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
@@ -0,0 +1,179 @@
|
|
1
|
+
"""
|
2
|
+
Direct AgentApp implementation for interacting with agents without proxies.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Dict, Optional, Union
|
6
|
+
|
7
|
+
from mcp_agent.agents.agent import Agent
|
8
|
+
from mcp_agent.core.interactive_prompt import InteractivePrompt
|
9
|
+
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
10
|
+
|
11
|
+
|
12
|
+
class DirectAgentApp:
|
13
|
+
"""
|
14
|
+
Container for active agents that provides a simple API for interacting with them.
|
15
|
+
This implementation works directly with Agent instances without proxies.
|
16
|
+
|
17
|
+
The DirectAgentApp provides both attribute-style access (app.agent_name)
|
18
|
+
and dictionary-style access (app["agent_name"]) to agents.
|
19
|
+
|
20
|
+
It also implements the AgentProtocol interface, automatically forwarding
|
21
|
+
calls to the default agent (the first agent in the container).
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, agents: Dict[str, Agent]) -> None:
|
25
|
+
"""
|
26
|
+
Initialize the DirectAgentApp.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
agents: Dictionary of agent instances keyed by name
|
30
|
+
"""
|
31
|
+
self._agents = agents
|
32
|
+
|
33
|
+
def __getitem__(self, key: str) -> Agent:
|
34
|
+
"""Allow access to agents using dictionary syntax."""
|
35
|
+
if key not in self._agents:
|
36
|
+
raise KeyError(f"Agent '{key}' not found")
|
37
|
+
return self._agents[key]
|
38
|
+
|
39
|
+
def __getattr__(self, name: str) -> Agent:
|
40
|
+
"""Allow access to agents using attribute syntax."""
|
41
|
+
if name in self._agents:
|
42
|
+
return self._agents[name]
|
43
|
+
raise AttributeError(f"Agent '{name}' not found")
|
44
|
+
|
45
|
+
async def __call__(
|
46
|
+
self,
|
47
|
+
message: Union[str, PromptMessageMultipart] | None = None,
|
48
|
+
agent_name: str | None = None,
|
49
|
+
default_prompt: str = "",
|
50
|
+
) -> str:
|
51
|
+
"""
|
52
|
+
Make the object callable to send messages or start interactive prompt.
|
53
|
+
This mirrors the FastAgent implementation that allowed agent("message").
|
54
|
+
|
55
|
+
Args:
|
56
|
+
message: The message to send
|
57
|
+
agent_name: Optional name of the agent to send to (defaults to first agent)
|
58
|
+
default: Default message to use in interactive prompt mode
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
The agent's response as a string or the result of the interactive session
|
62
|
+
"""
|
63
|
+
if message:
|
64
|
+
return await self._agent(agent_name).send(message)
|
65
|
+
|
66
|
+
return await self._agent(agent_name).prompt(default_prompt=default_prompt)
|
67
|
+
|
68
|
+
async def send(self, message: str, agent_name: Optional[str] = None) -> str:
|
69
|
+
"""
|
70
|
+
Send a message to the specified agent (or to all agents).
|
71
|
+
|
72
|
+
Args:
|
73
|
+
message: The message to send
|
74
|
+
agent_name: Optional name of the agent to send to
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
The agent's response as a string
|
78
|
+
"""
|
79
|
+
return await self._agent(agent_name).send(message)
|
80
|
+
|
81
|
+
def _agent(self, agent_name: str | None) -> Agent:
|
82
|
+
if agent_name:
|
83
|
+
if agent_name not in self._agents:
|
84
|
+
raise ValueError(f"Agent '{agent_name}' not found")
|
85
|
+
return self._agents[agent_name]
|
86
|
+
|
87
|
+
return next(iter(self._agents.values()))
|
88
|
+
|
89
|
+
async def apply_prompt(
|
90
|
+
self,
|
91
|
+
prompt_name: str,
|
92
|
+
arguments: Dict[str, str] | None = None,
|
93
|
+
agent_name: str | None = None,
|
94
|
+
) -> str:
|
95
|
+
"""
|
96
|
+
Apply a prompt template to an agent (default agent if not specified).
|
97
|
+
|
98
|
+
Args:
|
99
|
+
prompt_name: Name of the prompt template to apply
|
100
|
+
agent_name: Name of the agent to send to
|
101
|
+
arguments: Optional arguments for the prompt template
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
The agent's response as a string
|
105
|
+
"""
|
106
|
+
return await self._agent(agent_name).apply_prompt(prompt_name, arguments)
|
107
|
+
|
108
|
+
async def list_prompts(self, agent_name: str | None = None):
|
109
|
+
"""
|
110
|
+
List available prompts for an agent.
|
111
|
+
|
112
|
+
Args:
|
113
|
+
agent_name: Name of the agent to list prompts for
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
Dictionary mapping server names to lists of available prompts
|
117
|
+
"""
|
118
|
+
return await self._agent(agent_name).list_prompts()
|
119
|
+
|
120
|
+
async def with_resource(self, user_prompt: str, server_name: str, resource_name: str) -> str:
|
121
|
+
return await self._agent(None).with_resource(
|
122
|
+
prompt_content=user_prompt, server_name=server_name, resource_name=resource_name
|
123
|
+
)
|
124
|
+
|
125
|
+
async def prompt(self, agent_name: Optional[str] = None, default_prompt: str = "") -> str:
|
126
|
+
"""
|
127
|
+
Interactive prompt for sending messages with advanced features.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
agent_name: Optional target agent name (uses default if not specified)
|
131
|
+
default: Default message to use when user presses enter
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
The result of the interactive session
|
135
|
+
"""
|
136
|
+
|
137
|
+
# Get the default agent name if none specified
|
138
|
+
if agent_name:
|
139
|
+
# Validate that this agent exists
|
140
|
+
if agent_name not in self._agents:
|
141
|
+
raise ValueError(f"Agent '{agent_name}' not found")
|
142
|
+
target_name = agent_name
|
143
|
+
else:
|
144
|
+
# Use the first agent's name as default
|
145
|
+
target_name = next(iter(self._agents.keys()))
|
146
|
+
|
147
|
+
# Don't delegate to the agent's own prompt method - use our implementation
|
148
|
+
# The agent's prompt method doesn't fully support switching between agents
|
149
|
+
|
150
|
+
# Create agent_types dictionary mapping agent names to their types
|
151
|
+
agent_types = {}
|
152
|
+
for name, agent in self._agents.items():
|
153
|
+
# Determine agent type if possible
|
154
|
+
agent_type = "Agent" # Default type
|
155
|
+
|
156
|
+
# Try to get the type from the agent directly
|
157
|
+
if hasattr(agent, "agent_type"):
|
158
|
+
agent_type = agent.agent_type
|
159
|
+
elif hasattr(agent, "config") and hasattr(agent.config, "agent_type"):
|
160
|
+
agent_type = agent.config.agent_type
|
161
|
+
|
162
|
+
agent_types[name] = agent_type
|
163
|
+
|
164
|
+
# Create the interactive prompt
|
165
|
+
prompt = InteractivePrompt(agent_types=agent_types)
|
166
|
+
|
167
|
+
# Define the wrapper for send function
|
168
|
+
async def send_wrapper(message, agent_name):
|
169
|
+
return await self.send(message, agent_name)
|
170
|
+
|
171
|
+
# Start the prompt loop with the agent name (not the agent object)
|
172
|
+
return await prompt.prompt_loop(
|
173
|
+
send_func=send_wrapper,
|
174
|
+
default_agent=target_name, # Pass the agent name, not the agent object
|
175
|
+
available_agents=list(self._agents.keys()),
|
176
|
+
apply_prompt_func=self.apply_prompt,
|
177
|
+
list_prompts_func=self.list_prompts,
|
178
|
+
default=default_prompt,
|
179
|
+
)
|
@@ -0,0 +1,443 @@
|
|
1
|
+
"""
|
2
|
+
Type-safe decorators for DirectFastAgent applications.
|
3
|
+
These decorators provide type-safe function signatures and IDE support
|
4
|
+
for creating agents in the DirectFastAgent framework.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import inspect
|
8
|
+
from functools import wraps
|
9
|
+
from typing import (
|
10
|
+
Awaitable,
|
11
|
+
Callable,
|
12
|
+
List,
|
13
|
+
Literal,
|
14
|
+
Optional,
|
15
|
+
ParamSpec,
|
16
|
+
Protocol,
|
17
|
+
TypeVar,
|
18
|
+
Union,
|
19
|
+
cast,
|
20
|
+
)
|
21
|
+
|
22
|
+
from mcp_agent.agents.agent import AgentConfig
|
23
|
+
from mcp_agent.core.agent_types import AgentType
|
24
|
+
from mcp_agent.core.request_params import RequestParams
|
25
|
+
|
26
|
+
# Type variables for the decorated function
|
27
|
+
P = ParamSpec("P") # Parameters
|
28
|
+
R = TypeVar("R") # Return type
|
29
|
+
|
30
|
+
# Type for agent functions - can be either async or sync
|
31
|
+
AgentCallable = Callable[P, Union[Awaitable[R], R]]
|
32
|
+
|
33
|
+
|
34
|
+
# Protocol for decorated agent functions
|
35
|
+
class DecoratedAgentProtocol(Protocol[P, R]):
|
36
|
+
"""Protocol defining the interface of a decorated agent function."""
|
37
|
+
|
38
|
+
_agent_type: AgentType
|
39
|
+
_agent_config: AgentConfig
|
40
|
+
|
41
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Union[Awaitable[R], R]: ...
|
42
|
+
|
43
|
+
|
44
|
+
# Protocol for orchestrator functions
|
45
|
+
class DecoratedOrchestratorProtocol(DecoratedAgentProtocol[P, R], Protocol):
|
46
|
+
"""Protocol for decorated orchestrator functions with additional metadata."""
|
47
|
+
|
48
|
+
_child_agents: List[str]
|
49
|
+
_plan_type: Literal["full", "iterative"]
|
50
|
+
|
51
|
+
|
52
|
+
# Protocol for router functions
|
53
|
+
class DecoratedRouterProtocol(DecoratedAgentProtocol[P, R], Protocol):
|
54
|
+
"""Protocol for decorated router functions with additional metadata."""
|
55
|
+
|
56
|
+
_router_agents: List[str]
|
57
|
+
|
58
|
+
|
59
|
+
# Protocol for chain functions
|
60
|
+
class DecoratedChainProtocol(DecoratedAgentProtocol[P, R], Protocol):
|
61
|
+
"""Protocol for decorated chain functions with additional metadata."""
|
62
|
+
|
63
|
+
_chain_agents: List[str]
|
64
|
+
|
65
|
+
|
66
|
+
# Protocol for parallel functions
|
67
|
+
class DecoratedParallelProtocol(DecoratedAgentProtocol[P, R], Protocol):
|
68
|
+
"""Protocol for decorated parallel functions with additional metadata."""
|
69
|
+
|
70
|
+
_fan_out: List[str]
|
71
|
+
_fan_in: str
|
72
|
+
|
73
|
+
|
74
|
+
# Protocol for evaluator-optimizer functions
|
75
|
+
class DecoratedEvaluatorOptimizerProtocol(DecoratedAgentProtocol[P, R], Protocol):
|
76
|
+
"""Protocol for decorated evaluator-optimizer functions with additional metadata."""
|
77
|
+
|
78
|
+
_generator: str
|
79
|
+
_evaluator: str
|
80
|
+
|
81
|
+
|
82
|
+
def _decorator_impl(
|
83
|
+
self,
|
84
|
+
agent_type: AgentType,
|
85
|
+
name: str,
|
86
|
+
instruction: str,
|
87
|
+
*,
|
88
|
+
servers: List[str] = [],
|
89
|
+
model: Optional[str] = None,
|
90
|
+
use_history: bool = True,
|
91
|
+
request_params: RequestParams | None = None,
|
92
|
+
human_input: bool = False,
|
93
|
+
**extra_kwargs,
|
94
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedAgentProtocol[P, R]]:
|
95
|
+
"""
|
96
|
+
Core implementation for agent decorators with common behavior and type safety.
|
97
|
+
|
98
|
+
Args:
|
99
|
+
agent_type: Type of agent to create
|
100
|
+
name: Name of the agent
|
101
|
+
instruction: Base instruction for the agent
|
102
|
+
servers: List of server names the agent should connect to
|
103
|
+
model: Model specification string
|
104
|
+
use_history: Whether to maintain conversation history
|
105
|
+
request_params: Additional request parameters for the LLM
|
106
|
+
human_input: Whether to enable human input capabilities
|
107
|
+
**extra_kwargs: Additional agent/workflow-specific parameters
|
108
|
+
"""
|
109
|
+
|
110
|
+
def decorator(func: AgentCallable[P, R]) -> DecoratedAgentProtocol[P, R]:
|
111
|
+
is_async = inspect.iscoroutinefunction(func)
|
112
|
+
|
113
|
+
# Handle both async and sync functions consistently
|
114
|
+
if is_async:
|
115
|
+
|
116
|
+
@wraps(func)
|
117
|
+
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
118
|
+
# Call the original function
|
119
|
+
return await func(*args, **kwargs)
|
120
|
+
else:
|
121
|
+
|
122
|
+
@wraps(func)
|
123
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
124
|
+
# Call the original function
|
125
|
+
return func(*args, **kwargs)
|
126
|
+
|
127
|
+
# Create agent configuration
|
128
|
+
config = AgentConfig(
|
129
|
+
name=name,
|
130
|
+
instruction=instruction,
|
131
|
+
servers=servers,
|
132
|
+
model=model,
|
133
|
+
use_history=use_history,
|
134
|
+
human_input=human_input,
|
135
|
+
)
|
136
|
+
|
137
|
+
# Update request params if provided
|
138
|
+
if request_params:
|
139
|
+
config.default_request_params = request_params
|
140
|
+
|
141
|
+
# Store metadata on the wrapper function
|
142
|
+
agent_data = {
|
143
|
+
"config": config,
|
144
|
+
"type": agent_type.value,
|
145
|
+
"func": func,
|
146
|
+
}
|
147
|
+
|
148
|
+
# Add extra parameters specific to this agent type
|
149
|
+
for key, value in extra_kwargs.items():
|
150
|
+
agent_data[key] = value
|
151
|
+
|
152
|
+
# Store the configuration in the FastAgent instance
|
153
|
+
self.agents[name] = agent_data
|
154
|
+
|
155
|
+
# Store type information for IDE support
|
156
|
+
setattr(wrapper, "_agent_type", agent_type)
|
157
|
+
setattr(wrapper, "_agent_config", config)
|
158
|
+
for key, value in extra_kwargs.items():
|
159
|
+
setattr(wrapper, f"_{key}", value)
|
160
|
+
|
161
|
+
return cast("DecoratedAgentProtocol[P, R]", wrapper)
|
162
|
+
|
163
|
+
return decorator
|
164
|
+
|
165
|
+
|
166
|
+
def agent(
|
167
|
+
self,
|
168
|
+
name: str = "default",
|
169
|
+
instruction_or_kwarg: Optional[str] = None,
|
170
|
+
*,
|
171
|
+
instruction: str = "You are a helpful agent.",
|
172
|
+
servers: List[str] = [],
|
173
|
+
model: Optional[str] = None,
|
174
|
+
use_history: bool = True,
|
175
|
+
request_params: RequestParams | None = None,
|
176
|
+
human_input: bool = False,
|
177
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedAgentProtocol[P, R]]:
|
178
|
+
"""
|
179
|
+
Decorator to create and register a standard agent with type-safe signature.
|
180
|
+
|
181
|
+
Args:
|
182
|
+
name: Name of the agent
|
183
|
+
instruction_or_kwarg: Optional positional parameter for instruction
|
184
|
+
instruction: Base instruction for the agent (keyword arg)
|
185
|
+
servers: List of server names the agent should connect to
|
186
|
+
model: Model specification string
|
187
|
+
use_history: Whether to maintain conversation history
|
188
|
+
request_params: Additional request parameters for the LLM
|
189
|
+
human_input: Whether to enable human input capabilities
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
A decorator that registers the agent with proper type annotations
|
193
|
+
"""
|
194
|
+
final_instruction = instruction_or_kwarg if instruction_or_kwarg is not None else instruction
|
195
|
+
|
196
|
+
return _decorator_impl(
|
197
|
+
self,
|
198
|
+
AgentType.BASIC,
|
199
|
+
name=name,
|
200
|
+
instruction=final_instruction,
|
201
|
+
servers=servers,
|
202
|
+
model=model,
|
203
|
+
use_history=use_history,
|
204
|
+
request_params=request_params,
|
205
|
+
human_input=human_input,
|
206
|
+
)
|
207
|
+
|
208
|
+
|
209
|
+
def orchestrator(
|
210
|
+
self,
|
211
|
+
name: str,
|
212
|
+
*,
|
213
|
+
agents: List[str],
|
214
|
+
instruction: Optional[str] = None,
|
215
|
+
model: Optional[str] = None,
|
216
|
+
use_history: bool = False,
|
217
|
+
request_params: RequestParams | None = None,
|
218
|
+
human_input: bool = False,
|
219
|
+
plan_type: Literal["full", "iterative"] = "full",
|
220
|
+
max_iterations: int = 30,
|
221
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedOrchestratorProtocol[P, R]]:
|
222
|
+
"""
|
223
|
+
Decorator to create and register an orchestrator agent with type-safe signature.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
name: Name of the orchestrator
|
227
|
+
agents: List of agent names this orchestrator can use
|
228
|
+
instruction: Base instruction for the orchestrator
|
229
|
+
model: Model specification string
|
230
|
+
use_history: Whether to maintain conversation history
|
231
|
+
request_params: Additional request parameters for the LLM
|
232
|
+
human_input: Whether to enable human input capabilities
|
233
|
+
plan_type: Planning approach - "full" or "iterative"
|
234
|
+
max_iterations: Maximum number of planning iterations
|
235
|
+
|
236
|
+
Returns:
|
237
|
+
A decorator that registers the orchestrator with proper type annotations
|
238
|
+
"""
|
239
|
+
default_instruction = """
|
240
|
+
You are an expert planner. Given an objective task and a list of Agents
|
241
|
+
(which are collections of capabilities), your job is to break down the objective
|
242
|
+
into a series of steps, which can be performed by these agents.
|
243
|
+
"""
|
244
|
+
|
245
|
+
# Create final request params with max_iterations
|
246
|
+
|
247
|
+
return cast(
|
248
|
+
"Callable[[AgentCallable[P, R]], DecoratedOrchestratorProtocol[P, R]]",
|
249
|
+
_decorator_impl(
|
250
|
+
self,
|
251
|
+
AgentType.ORCHESTRATOR,
|
252
|
+
name=name,
|
253
|
+
instruction=instruction or default_instruction,
|
254
|
+
servers=[], # Orchestrators don't connect to servers directly
|
255
|
+
model=model,
|
256
|
+
use_history=use_history,
|
257
|
+
request_params=request_params,
|
258
|
+
human_input=human_input,
|
259
|
+
child_agents=agents,
|
260
|
+
plan_type=plan_type,
|
261
|
+
max_iterations=max_iterations,
|
262
|
+
),
|
263
|
+
)
|
264
|
+
|
265
|
+
|
266
|
+
def router(
|
267
|
+
self,
|
268
|
+
name: str,
|
269
|
+
*,
|
270
|
+
agents: List[str],
|
271
|
+
instruction: Optional[str] = None,
|
272
|
+
model: Optional[str] = None,
|
273
|
+
use_history: bool = False,
|
274
|
+
request_params: RequestParams | None = None,
|
275
|
+
human_input: bool = False,
|
276
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedRouterProtocol[P, R]]:
|
277
|
+
"""
|
278
|
+
Decorator to create and register a router agent with type-safe signature.
|
279
|
+
|
280
|
+
Args:
|
281
|
+
name: Name of the router
|
282
|
+
agents: List of agent names this router can route to
|
283
|
+
instruction: Base instruction for the router
|
284
|
+
model: Model specification string
|
285
|
+
use_history: Whether to maintain conversation history
|
286
|
+
request_params: Additional request parameters for the LLM
|
287
|
+
human_input: Whether to enable human input capabilities
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
A decorator that registers the router with proper type annotations
|
291
|
+
"""
|
292
|
+
default_instruction = """
|
293
|
+
You are a router that determines which specialized agent should handle a given query.
|
294
|
+
Analyze the query and select the most appropriate agent to handle it.
|
295
|
+
"""
|
296
|
+
|
297
|
+
return cast(
|
298
|
+
"Callable[[AgentCallable[P, R]], DecoratedRouterProtocol[P, R]]",
|
299
|
+
_decorator_impl(
|
300
|
+
self,
|
301
|
+
AgentType.ROUTER,
|
302
|
+
name=name,
|
303
|
+
instruction=instruction or default_instruction,
|
304
|
+
servers=[], # Routers don't connect to servers directly
|
305
|
+
model=model,
|
306
|
+
use_history=use_history,
|
307
|
+
request_params=request_params,
|
308
|
+
human_input=human_input,
|
309
|
+
router_agents=agents,
|
310
|
+
),
|
311
|
+
)
|
312
|
+
|
313
|
+
|
314
|
+
def chain(
|
315
|
+
self,
|
316
|
+
name: str,
|
317
|
+
*,
|
318
|
+
sequence: List[str],
|
319
|
+
instruction: Optional[str] = None,
|
320
|
+
cumulative: bool = False,
|
321
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedChainProtocol[P, R]]:
|
322
|
+
"""
|
323
|
+
Decorator to create and register a chain agent with type-safe signature.
|
324
|
+
|
325
|
+
Args:
|
326
|
+
name: Name of the chain
|
327
|
+
sequence: List of agent names in the chain, executed in sequence
|
328
|
+
instruction: Base instruction for the chain
|
329
|
+
cumulative: Whether to use cumulative mode (each agent sees all previous responses)
|
330
|
+
|
331
|
+
Returns:
|
332
|
+
A decorator that registers the chain with proper type annotations
|
333
|
+
"""
|
334
|
+
# Validate sequence is not empty
|
335
|
+
if not sequence:
|
336
|
+
from mcp_agent.core.exceptions import AgentConfigError
|
337
|
+
|
338
|
+
raise AgentConfigError(f"Chain '{name}' requires at least one agent in the sequence")
|
339
|
+
|
340
|
+
default_instruction = """
|
341
|
+
You are a chain that processes requests through a series of specialized agents in sequence.
|
342
|
+
Pass the output of each agent to the next agent in the chain.
|
343
|
+
"""
|
344
|
+
|
345
|
+
return cast(
|
346
|
+
"Callable[[AgentCallable[P, R]], DecoratedChainProtocol[P, R]]",
|
347
|
+
_decorator_impl(
|
348
|
+
self,
|
349
|
+
AgentType.CHAIN,
|
350
|
+
name=name,
|
351
|
+
instruction=instruction or default_instruction,
|
352
|
+
sequence=sequence,
|
353
|
+
cumulative=cumulative,
|
354
|
+
),
|
355
|
+
)
|
356
|
+
|
357
|
+
|
358
|
+
def parallel(
|
359
|
+
self,
|
360
|
+
name: str,
|
361
|
+
*,
|
362
|
+
fan_out: List[str],
|
363
|
+
fan_in: str | None = None,
|
364
|
+
instruction: Optional[str] = None,
|
365
|
+
include_request: bool = True,
|
366
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedParallelProtocol[P, R]]:
|
367
|
+
"""
|
368
|
+
Decorator to create and register a parallel agent with type-safe signature.
|
369
|
+
|
370
|
+
Args:
|
371
|
+
name: Name of the parallel agent
|
372
|
+
fan_out: List of agents to execute in parallel
|
373
|
+
fan_in: Agent to aggregate results
|
374
|
+
instruction: Base instruction for the parallel agent
|
375
|
+
include_request: Whether to include the original request when aggregating
|
376
|
+
|
377
|
+
Returns:
|
378
|
+
A decorator that registers the parallel agent with proper type annotations
|
379
|
+
"""
|
380
|
+
default_instruction = """
|
381
|
+
You are a parallel processor that executes multiple agents simultaneously
|
382
|
+
and aggregates their results.
|
383
|
+
"""
|
384
|
+
|
385
|
+
return cast(
|
386
|
+
"Callable[[AgentCallable[P, R]], DecoratedParallelProtocol[P, R]]",
|
387
|
+
_decorator_impl(
|
388
|
+
self,
|
389
|
+
AgentType.PARALLEL,
|
390
|
+
name=name,
|
391
|
+
instruction=instruction or default_instruction,
|
392
|
+
servers=[], # Parallel agents don't connect to servers directly
|
393
|
+
fan_in=fan_in,
|
394
|
+
fan_out=fan_out,
|
395
|
+
include_request=include_request,
|
396
|
+
),
|
397
|
+
)
|
398
|
+
|
399
|
+
|
400
|
+
def evaluator_optimizer(
|
401
|
+
self,
|
402
|
+
name: str,
|
403
|
+
*,
|
404
|
+
generator: str,
|
405
|
+
evaluator: str,
|
406
|
+
instruction: Optional[str] = None,
|
407
|
+
min_rating: str = "GOOD",
|
408
|
+
max_refinements: int = 3,
|
409
|
+
) -> Callable[[AgentCallable[P, R]], DecoratedEvaluatorOptimizerProtocol[P, R]]:
|
410
|
+
"""
|
411
|
+
Decorator to create and register an evaluator-optimizer agent with type-safe signature.
|
412
|
+
|
413
|
+
Args:
|
414
|
+
name: Name of the evaluator-optimizer agent
|
415
|
+
generator: Name of the agent that generates responses
|
416
|
+
evaluator: Name of the agent that evaluates responses
|
417
|
+
instruction: Base instruction for the evaluator-optimizer
|
418
|
+
min_rating: Minimum acceptable quality rating (EXCELLENT, GOOD, FAIR, POOR)
|
419
|
+
max_refinements: Maximum number of refinement iterations
|
420
|
+
|
421
|
+
Returns:
|
422
|
+
A decorator that registers the evaluator-optimizer with proper type annotations
|
423
|
+
"""
|
424
|
+
default_instruction = """
|
425
|
+
You implement an iterative refinement process where content is generated,
|
426
|
+
evaluated for quality, and then refined based on specific feedback until
|
427
|
+
it reaches an acceptable quality standard.
|
428
|
+
"""
|
429
|
+
|
430
|
+
return cast(
|
431
|
+
"Callable[[AgentCallable[P, R]], DecoratedEvaluatorOptimizerProtocol[P, R]]",
|
432
|
+
_decorator_impl(
|
433
|
+
self,
|
434
|
+
AgentType.EVALUATOR_OPTIMIZER,
|
435
|
+
name=name,
|
436
|
+
instruction=instruction or default_instruction,
|
437
|
+
servers=[], # Evaluator-optimizer doesn't connect to servers directly
|
438
|
+
generator=generator,
|
439
|
+
evaluator=evaluator,
|
440
|
+
min_rating=min_rating,
|
441
|
+
max_refinements=max_refinements,
|
442
|
+
),
|
443
|
+
)
|