fast-agent-mcp 0.2.58__py3-none-any.whl → 0.3.1__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.
Potentially problematic release.
This version of fast-agent-mcp might be problematic. Click here for more details.
- fast_agent/__init__.py +127 -0
- fast_agent/agents/__init__.py +36 -0
- {mcp_agent/core → fast_agent/agents}/agent_types.py +2 -1
- fast_agent/agents/llm_agent.py +217 -0
- fast_agent/agents/llm_decorator.py +486 -0
- mcp_agent/agents/base_agent.py → fast_agent/agents/mcp_agent.py +377 -385
- fast_agent/agents/tool_agent.py +168 -0
- {mcp_agent → fast_agent}/agents/workflow/chain_agent.py +43 -33
- {mcp_agent → fast_agent}/agents/workflow/evaluator_optimizer.py +31 -35
- {mcp_agent → fast_agent}/agents/workflow/iterative_planner.py +56 -47
- {mcp_agent → fast_agent}/agents/workflow/orchestrator_models.py +4 -4
- {mcp_agent → fast_agent}/agents/workflow/parallel_agent.py +34 -41
- {mcp_agent → fast_agent}/agents/workflow/router_agent.py +54 -39
- {mcp_agent → fast_agent}/cli/__main__.py +5 -3
- {mcp_agent → fast_agent}/cli/commands/check_config.py +95 -66
- {mcp_agent → fast_agent}/cli/commands/go.py +20 -11
- {mcp_agent → fast_agent}/cli/commands/quickstart.py +4 -4
- {mcp_agent → fast_agent}/cli/commands/server_helpers.py +1 -1
- {mcp_agent → fast_agent}/cli/commands/setup.py +75 -134
- {mcp_agent → fast_agent}/cli/commands/url_parser.py +9 -8
- {mcp_agent → fast_agent}/cli/main.py +36 -16
- {mcp_agent → fast_agent}/cli/terminal.py +2 -2
- {mcp_agent → fast_agent}/config.py +10 -2
- fast_agent/constants.py +8 -0
- {mcp_agent → fast_agent}/context.py +24 -19
- {mcp_agent → fast_agent}/context_dependent.py +9 -5
- fast_agent/core/__init__.py +52 -0
- {mcp_agent → fast_agent}/core/agent_app.py +39 -36
- fast_agent/core/core_app.py +135 -0
- {mcp_agent → fast_agent}/core/direct_decorators.py +12 -26
- {mcp_agent → fast_agent}/core/direct_factory.py +95 -73
- {mcp_agent → fast_agent/core}/executor/executor.py +4 -5
- {mcp_agent → fast_agent}/core/fastagent.py +32 -32
- fast_agent/core/logging/__init__.py +5 -0
- {mcp_agent → fast_agent/core}/logging/events.py +3 -3
- {mcp_agent → fast_agent/core}/logging/json_serializer.py +1 -1
- {mcp_agent → fast_agent/core}/logging/listeners.py +85 -7
- {mcp_agent → fast_agent/core}/logging/logger.py +7 -7
- {mcp_agent → fast_agent/core}/logging/transport.py +10 -11
- fast_agent/core/prompt.py +9 -0
- {mcp_agent → fast_agent}/core/validation.py +4 -4
- fast_agent/event_progress.py +61 -0
- fast_agent/history/history_exporter.py +44 -0
- {mcp_agent → fast_agent}/human_input/__init__.py +9 -12
- {mcp_agent → fast_agent}/human_input/elicitation_handler.py +26 -8
- {mcp_agent → fast_agent}/human_input/elicitation_state.py +7 -7
- {mcp_agent → fast_agent}/human_input/simple_form.py +6 -4
- {mcp_agent → fast_agent}/human_input/types.py +1 -18
- fast_agent/interfaces.py +228 -0
- fast_agent/llm/__init__.py +9 -0
- mcp_agent/llm/augmented_llm.py → fast_agent/llm/fastagent_llm.py +127 -218
- fast_agent/llm/internal/passthrough.py +137 -0
- mcp_agent/llm/augmented_llm_playback.py → fast_agent/llm/internal/playback.py +29 -25
- mcp_agent/llm/augmented_llm_silent.py → fast_agent/llm/internal/silent.py +10 -17
- fast_agent/llm/internal/slow.py +38 -0
- {mcp_agent → fast_agent}/llm/memory.py +40 -30
- {mcp_agent → fast_agent}/llm/model_database.py +35 -2
- {mcp_agent → fast_agent}/llm/model_factory.py +103 -77
- fast_agent/llm/model_info.py +126 -0
- {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/anthropic_utils.py +7 -7
- fast_agent/llm/provider/anthropic/llm_anthropic.py +603 -0
- {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/multipart_converter_anthropic.py +79 -86
- {mcp_agent/llm/providers → fast_agent/llm/provider/bedrock}/bedrock_utils.py +3 -1
- mcp_agent/llm/providers/augmented_llm_bedrock.py → fast_agent/llm/provider/bedrock/llm_bedrock.py +833 -717
- {mcp_agent/llm/providers → fast_agent/llm/provider/google}/google_converter.py +66 -14
- fast_agent/llm/provider/google/llm_google_native.py +431 -0
- mcp_agent/llm/providers/augmented_llm_aliyun.py → fast_agent/llm/provider/openai/llm_aliyun.py +6 -7
- mcp_agent/llm/providers/augmented_llm_azure.py → fast_agent/llm/provider/openai/llm_azure.py +4 -4
- mcp_agent/llm/providers/augmented_llm_deepseek.py → fast_agent/llm/provider/openai/llm_deepseek.py +10 -11
- mcp_agent/llm/providers/augmented_llm_generic.py → fast_agent/llm/provider/openai/llm_generic.py +4 -4
- mcp_agent/llm/providers/augmented_llm_google_oai.py → fast_agent/llm/provider/openai/llm_google_oai.py +4 -4
- mcp_agent/llm/providers/augmented_llm_groq.py → fast_agent/llm/provider/openai/llm_groq.py +14 -16
- mcp_agent/llm/providers/augmented_llm_openai.py → fast_agent/llm/provider/openai/llm_openai.py +133 -207
- mcp_agent/llm/providers/augmented_llm_openrouter.py → fast_agent/llm/provider/openai/llm_openrouter.py +6 -6
- mcp_agent/llm/providers/augmented_llm_tensorzero_openai.py → fast_agent/llm/provider/openai/llm_tensorzero_openai.py +17 -16
- mcp_agent/llm/providers/augmented_llm_xai.py → fast_agent/llm/provider/openai/llm_xai.py +6 -6
- {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/multipart_converter_openai.py +125 -63
- {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_multipart.py +12 -12
- {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_utils.py +18 -16
- {mcp_agent → fast_agent}/llm/provider_key_manager.py +2 -2
- {mcp_agent → fast_agent}/llm/provider_types.py +2 -0
- {mcp_agent → fast_agent}/llm/sampling_converter.py +15 -12
- {mcp_agent → fast_agent}/llm/usage_tracking.py +23 -5
- fast_agent/mcp/__init__.py +54 -0
- {mcp_agent → fast_agent}/mcp/elicitation_factory.py +3 -3
- {mcp_agent → fast_agent}/mcp/elicitation_handlers.py +19 -10
- {mcp_agent → fast_agent}/mcp/gen_client.py +3 -3
- fast_agent/mcp/helpers/__init__.py +36 -0
- fast_agent/mcp/helpers/content_helpers.py +183 -0
- {mcp_agent → fast_agent}/mcp/helpers/server_config_helpers.py +8 -8
- {mcp_agent → fast_agent}/mcp/hf_auth.py +25 -23
- fast_agent/mcp/interfaces.py +93 -0
- {mcp_agent → fast_agent}/mcp/logger_textio.py +4 -4
- {mcp_agent → fast_agent}/mcp/mcp_agent_client_session.py +49 -44
- {mcp_agent → fast_agent}/mcp/mcp_aggregator.py +66 -115
- {mcp_agent → fast_agent}/mcp/mcp_connection_manager.py +16 -23
- {mcp_agent/core → fast_agent/mcp}/mcp_content.py +23 -15
- {mcp_agent → fast_agent}/mcp/mime_utils.py +39 -0
- fast_agent/mcp/prompt.py +159 -0
- mcp_agent/mcp/prompt_message_multipart.py → fast_agent/mcp/prompt_message_extended.py +27 -20
- {mcp_agent → fast_agent}/mcp/prompt_render.py +21 -19
- {mcp_agent → fast_agent}/mcp/prompt_serialization.py +46 -46
- fast_agent/mcp/prompts/__main__.py +7 -0
- {mcp_agent → fast_agent}/mcp/prompts/prompt_helpers.py +31 -30
- {mcp_agent → fast_agent}/mcp/prompts/prompt_load.py +8 -8
- {mcp_agent → fast_agent}/mcp/prompts/prompt_server.py +11 -19
- {mcp_agent → fast_agent}/mcp/prompts/prompt_template.py +18 -18
- {mcp_agent → fast_agent}/mcp/resource_utils.py +1 -1
- {mcp_agent → fast_agent}/mcp/sampling.py +31 -26
- {mcp_agent/mcp_server → fast_agent/mcp/server}/__init__.py +1 -1
- {mcp_agent/mcp_server → fast_agent/mcp/server}/agent_server.py +5 -6
- fast_agent/mcp/ui_agent.py +48 -0
- fast_agent/mcp/ui_mixin.py +209 -0
- fast_agent/mcp_server_registry.py +90 -0
- {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis-campaign.py +5 -4
- {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/forms_demo.py +3 -3
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character.py +2 -2
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character_handler.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/tool_call.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_one.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_two.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/researcher/researcher-eval.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/researcher/researcher-imp.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/researcher/researcher.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/tensorzero/agent.py +2 -2
- {mcp_agent → fast_agent}/resources/examples/tensorzero/image_demo.py +3 -3
- {mcp_agent → fast_agent}/resources/examples/tensorzero/simple_agent.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/workflows/chaining.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/workflows/evaluator.py +3 -3
- {mcp_agent → fast_agent}/resources/examples/workflows/human_input.py +5 -3
- {mcp_agent → fast_agent}/resources/examples/workflows/orchestrator.py +1 -1
- {mcp_agent → fast_agent}/resources/examples/workflows/parallel.py +2 -2
- {mcp_agent → fast_agent}/resources/examples/workflows/router.py +5 -2
- fast_agent/resources/setup/.gitignore +24 -0
- fast_agent/resources/setup/agent.py +18 -0
- fast_agent/resources/setup/fastagent.config.yaml +44 -0
- fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
- fast_agent/resources/setup/pyproject.toml.tmpl +17 -0
- fast_agent/tools/elicitation.py +369 -0
- fast_agent/types/__init__.py +32 -0
- fast_agent/types/llm_stop_reason.py +77 -0
- fast_agent/ui/__init__.py +38 -0
- fast_agent/ui/console_display.py +1005 -0
- {mcp_agent/human_input → fast_agent/ui}/elicitation_form.py +17 -12
- mcp_agent/human_input/elicitation_forms.py → fast_agent/ui/elicitation_style.py +1 -1
- {mcp_agent/core → fast_agent/ui}/enhanced_prompt.py +96 -25
- {mcp_agent/core → fast_agent/ui}/interactive_prompt.py +330 -125
- fast_agent/ui/mcp_ui_utils.py +224 -0
- {mcp_agent → fast_agent/ui}/progress_display.py +2 -2
- {mcp_agent/logging → fast_agent/ui}/rich_progress.py +4 -4
- {mcp_agent/core → fast_agent/ui}/usage_display.py +3 -8
- {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.1.dist-info}/METADATA +7 -7
- fast_agent_mcp-0.3.1.dist-info/RECORD +203 -0
- fast_agent_mcp-0.3.1.dist-info/entry_points.txt +5 -0
- fast_agent_mcp-0.2.58.dist-info/RECORD +0 -193
- fast_agent_mcp-0.2.58.dist-info/entry_points.txt +0 -6
- mcp_agent/__init__.py +0 -114
- mcp_agent/agents/agent.py +0 -92
- mcp_agent/agents/workflow/__init__.py +0 -1
- mcp_agent/agents/workflow/orchestrator_agent.py +0 -597
- mcp_agent/app.py +0 -175
- mcp_agent/core/__init__.py +0 -26
- mcp_agent/core/prompt.py +0 -191
- mcp_agent/event_progress.py +0 -134
- mcp_agent/human_input/handler.py +0 -81
- mcp_agent/llm/__init__.py +0 -2
- mcp_agent/llm/augmented_llm_passthrough.py +0 -232
- mcp_agent/llm/augmented_llm_slow.py +0 -53
- mcp_agent/llm/providers/__init__.py +0 -8
- mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -718
- mcp_agent/llm/providers/augmented_llm_google_native.py +0 -496
- mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -57
- mcp_agent/llm/providers/sampling_converter_openai.py +0 -26
- mcp_agent/llm/sampling_format_converter.py +0 -37
- mcp_agent/logging/__init__.py +0 -0
- mcp_agent/mcp/__init__.py +0 -50
- mcp_agent/mcp/helpers/__init__.py +0 -25
- mcp_agent/mcp/helpers/content_helpers.py +0 -187
- mcp_agent/mcp/interfaces.py +0 -266
- mcp_agent/mcp/prompts/__init__.py +0 -0
- mcp_agent/mcp/prompts/__main__.py +0 -10
- mcp_agent/mcp_server_registry.py +0 -343
- mcp_agent/tools/tool_definition.py +0 -14
- mcp_agent/ui/console_display.py +0 -790
- mcp_agent/ui/console_display_legacy.py +0 -401
- {mcp_agent → fast_agent}/agents/workflow/orchestrator_prompts.py +0 -0
- {mcp_agent/agents → fast_agent/cli}/__init__.py +0 -0
- {mcp_agent → fast_agent}/cli/constants.py +0 -0
- {mcp_agent → fast_agent}/core/error_handling.py +0 -0
- {mcp_agent → fast_agent}/core/exceptions.py +0 -0
- {mcp_agent/cli → fast_agent/core/executor}/__init__.py +0 -0
- {mcp_agent → fast_agent/core}/executor/task_registry.py +0 -0
- {mcp_agent → fast_agent/core}/executor/workflow_signal.py +0 -0
- {mcp_agent → fast_agent}/human_input/form_fields.py +0 -0
- {mcp_agent → fast_agent}/llm/prompt_utils.py +0 -0
- {mcp_agent/core → fast_agent/llm}/request_params.py +0 -0
- {mcp_agent → fast_agent}/mcp/common.py +0 -0
- {mcp_agent/executor → fast_agent/mcp/prompts}/__init__.py +0 -0
- {mcp_agent → fast_agent}/mcp/prompts/prompt_constants.py +0 -0
- {mcp_agent → fast_agent}/py.typed +0 -0
- {mcp_agent → fast_agent}/resources/examples/data-analysis/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_account_server.py +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_forms_server.py +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_game_server.py +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +0 -0
- {mcp_agent → fast_agent}/resources/examples/researcher/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/.env.sample +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/Makefile +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/README.md +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/crab.png +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/docker-compose.yml +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/Dockerfile +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/entrypoint.sh +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/mcp_server.py +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/pyproject.toml +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_schema.json +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +0 -0
- {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +0 -0
- {mcp_agent → fast_agent}/resources/examples/workflows/fastagent.config.yaml +0 -0
- {mcp_agent → fast_agent}/resources/examples/workflows/graded_report.md +0 -0
- {mcp_agent → fast_agent}/resources/examples/workflows/short_story.md +0 -0
- {mcp_agent → fast_agent}/resources/examples/workflows/short_story.txt +0 -0
- {mcp_agent → fast_agent/ui}/console.py +0 -0
- {mcp_agent/core → fast_agent/ui}/mermaid_utils.py +0 -0
- {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.1.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,11 +5,12 @@ Iterative Planner Agent - works towards an objective using sub-agents
|
|
|
5
5
|
import asyncio
|
|
6
6
|
from typing import Any, Dict, List, Optional, Tuple, Type
|
|
7
7
|
|
|
8
|
+
from mcp import Tool
|
|
8
9
|
from mcp.types import TextContent
|
|
9
10
|
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
11
|
+
from fast_agent.agents.agent_types import AgentConfig, AgentType
|
|
12
|
+
from fast_agent.agents.llm_agent import LlmAgent
|
|
13
|
+
from fast_agent.agents.workflow.orchestrator_models import (
|
|
13
14
|
Plan,
|
|
14
15
|
PlanningStep,
|
|
15
16
|
PlanResult,
|
|
@@ -18,13 +19,11 @@ from mcp_agent.agents.workflow.orchestrator_models import (
|
|
|
18
19
|
format_plan_result,
|
|
19
20
|
format_step_result_text,
|
|
20
21
|
)
|
|
21
|
-
from
|
|
22
|
-
from
|
|
23
|
-
from
|
|
24
|
-
from
|
|
25
|
-
from
|
|
26
|
-
from mcp_agent.mcp.interfaces import ModelT
|
|
27
|
-
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
|
22
|
+
from fast_agent.core.exceptions import AgentConfigError
|
|
23
|
+
from fast_agent.core.logging.logger import get_logger
|
|
24
|
+
from fast_agent.core.prompt import Prompt
|
|
25
|
+
from fast_agent.interfaces import AgentProtocol, ModelT
|
|
26
|
+
from fast_agent.types import PromptMessageExtended, RequestParams
|
|
28
27
|
|
|
29
28
|
logger = get_logger(__name__)
|
|
30
29
|
|
|
@@ -146,11 +145,11 @@ make sure to state clearly what was accomplished and what remains to be done.
|
|
|
146
145
|
|
|
147
146
|
|
|
148
147
|
Complete the plan by providing an appropriate answer for the original objective. Provide a Mermaid diagram
|
|
149
|
-
(in code fences) showing the plan steps and their relationships, if applicable.
|
|
148
|
+
(in code fences) showing the plan steps and their relationships, if applicable. Do not use parentheses in labels.
|
|
150
149
|
"""
|
|
151
150
|
|
|
152
151
|
|
|
153
|
-
class IterativePlanner(
|
|
152
|
+
class IterativePlanner(LlmAgent):
|
|
154
153
|
"""
|
|
155
154
|
An agent that implements the orchestrator workflow pattern.
|
|
156
155
|
|
|
@@ -167,7 +166,7 @@ class IterativePlanner(BaseAgent):
|
|
|
167
166
|
def __init__(
|
|
168
167
|
self,
|
|
169
168
|
config: AgentConfig,
|
|
170
|
-
agents: List[
|
|
169
|
+
agents: List[AgentProtocol],
|
|
171
170
|
plan_iterations: int = -1,
|
|
172
171
|
context: Optional[Any] = None,
|
|
173
172
|
**kwargs,
|
|
@@ -186,11 +185,13 @@ class IterativePlanner(BaseAgent):
|
|
|
186
185
|
raise AgentConfigError("At least one worker agent must be provided")
|
|
187
186
|
|
|
188
187
|
# Store agents by name for easier lookup
|
|
189
|
-
self.agents: Dict[str,
|
|
188
|
+
self.agents: Dict[str, AgentProtocol] = {}
|
|
190
189
|
for agent in agents:
|
|
191
190
|
agent_name = agent.name
|
|
192
191
|
self.agents[agent_name] = agent
|
|
193
192
|
|
|
193
|
+
# Extract plan_type from kwargs before passing to parent
|
|
194
|
+
kwargs.pop("plan_type", "full")
|
|
194
195
|
super().__init__(config, context=context, **kwargs)
|
|
195
196
|
|
|
196
197
|
self.plan_iterations = plan_iterations
|
|
@@ -200,7 +201,7 @@ class IterativePlanner(BaseAgent):
|
|
|
200
201
|
# Initialize all worker agents first if not already initialized
|
|
201
202
|
for agent_name, agent in self.agents.items():
|
|
202
203
|
if not getattr(agent, "initialized", False):
|
|
203
|
-
|
|
204
|
+
logger.debug(f"Initializing agent: {agent_name}")
|
|
204
205
|
await agent.initialize()
|
|
205
206
|
|
|
206
207
|
# Format agent information using agent cards with XML formatting
|
|
@@ -218,7 +219,6 @@ class IterativePlanner(BaseAgent):
|
|
|
218
219
|
|
|
219
220
|
# Update the config instruction with the formatted system prompt
|
|
220
221
|
self.instruction = system_prompt
|
|
221
|
-
|
|
222
222
|
# Initialize the base agent with the updated system prompt
|
|
223
223
|
await super().initialize()
|
|
224
224
|
|
|
@@ -233,44 +233,44 @@ class IterativePlanner(BaseAgent):
|
|
|
233
233
|
try:
|
|
234
234
|
await agent.shutdown()
|
|
235
235
|
except Exception as e:
|
|
236
|
-
|
|
236
|
+
logger.warning(f"Error shutting down agent {agent_name}: {str(e)}")
|
|
237
237
|
|
|
238
|
-
async def
|
|
238
|
+
async def generate_impl(
|
|
239
239
|
self,
|
|
240
|
-
|
|
241
|
-
request_params:
|
|
242
|
-
|
|
240
|
+
messages: List[PromptMessageExtended],
|
|
241
|
+
request_params: RequestParams | None = None,
|
|
242
|
+
tools: List[Tool] | None = None,
|
|
243
|
+
) -> PromptMessageExtended:
|
|
243
244
|
"""
|
|
244
245
|
Execute an orchestrated plan to process the input.
|
|
245
246
|
|
|
246
247
|
Args:
|
|
247
|
-
|
|
248
|
+
normalized_messages: Already normalized list of PromptMessageExtended
|
|
248
249
|
request_params: Optional request parameters
|
|
249
250
|
|
|
250
251
|
Returns:
|
|
251
252
|
The final synthesized response from the orchestration
|
|
252
253
|
"""
|
|
253
254
|
# Extract user request
|
|
254
|
-
objective =
|
|
255
|
+
objective = messages[-1].all_text() if messages else ""
|
|
255
256
|
plan_result = await self._execute_plan(objective, request_params)
|
|
256
|
-
|
|
257
257
|
# Return the result
|
|
258
|
-
return
|
|
258
|
+
return PromptMessageExtended(
|
|
259
259
|
role="assistant",
|
|
260
260
|
content=[TextContent(type="text", text=plan_result.result or "No result available")],
|
|
261
261
|
)
|
|
262
262
|
|
|
263
|
-
async def
|
|
263
|
+
async def structured_impl(
|
|
264
264
|
self,
|
|
265
|
-
|
|
265
|
+
messages: List[PromptMessageExtended],
|
|
266
266
|
model: Type[ModelT],
|
|
267
267
|
request_params: Optional[RequestParams] = None,
|
|
268
|
-
) -> Tuple[ModelT | None,
|
|
268
|
+
) -> Tuple[ModelT | None, PromptMessageExtended]:
|
|
269
269
|
"""
|
|
270
270
|
Execute an orchestration plan and parse the result into a structured format.
|
|
271
271
|
|
|
272
272
|
Args:
|
|
273
|
-
|
|
273
|
+
messages: List of messages to process
|
|
274
274
|
model: Pydantic model to parse the response into
|
|
275
275
|
request_params: Optional request parameters
|
|
276
276
|
|
|
@@ -278,18 +278,18 @@ class IterativePlanner(BaseAgent):
|
|
|
278
278
|
The parsed final response, or None if parsing fails
|
|
279
279
|
"""
|
|
280
280
|
# Generate orchestration result
|
|
281
|
-
response = await self.
|
|
281
|
+
response = await self.generate_impl(messages, request_params)
|
|
282
282
|
|
|
283
283
|
# Try to parse the response into the specified model
|
|
284
284
|
try:
|
|
285
|
-
result_text = response.last_text()
|
|
286
|
-
prompt_message =
|
|
285
|
+
result_text = response.last_text() or "<no text>"
|
|
286
|
+
prompt_message = PromptMessageExtended(
|
|
287
287
|
role="user", content=[TextContent(type="text", text=result_text)]
|
|
288
288
|
)
|
|
289
289
|
assert self._llm
|
|
290
290
|
return await self._llm.structured([prompt_message], model, request_params)
|
|
291
291
|
except Exception as e:
|
|
292
|
-
|
|
292
|
+
logger.warning(f"Failed to parse orchestration result: {str(e)}")
|
|
293
293
|
return None, Prompt.assistant(f"Failed to parse orchestration result: {str(e)}")
|
|
294
294
|
|
|
295
295
|
async def _execute_plan(
|
|
@@ -317,7 +317,7 @@ class IterativePlanner(BaseAgent):
|
|
|
317
317
|
|
|
318
318
|
if None is next_step:
|
|
319
319
|
terminate_plan = "Failed to generate plan, terminating early"
|
|
320
|
-
|
|
320
|
+
logger.error("Failed to generate next step, terminating plan early")
|
|
321
321
|
break
|
|
322
322
|
|
|
323
323
|
assert next_step # lets keep the indenting manageable!
|
|
@@ -330,7 +330,7 @@ class IterativePlanner(BaseAgent):
|
|
|
330
330
|
plan = Plan(steps=[next_step], is_complete=next_step.is_complete)
|
|
331
331
|
invalid_agents = self._validate_agent_names(plan)
|
|
332
332
|
if invalid_agents:
|
|
333
|
-
|
|
333
|
+
logger.error(f"Plan contains invalid agent names: {', '.join(invalid_agents)}")
|
|
334
334
|
terminate_plan = (
|
|
335
335
|
f"Invalid agent names found ({', '.join(invalid_agents)}), terminating plan"
|
|
336
336
|
)
|
|
@@ -354,7 +354,9 @@ class IterativePlanner(BaseAgent):
|
|
|
354
354
|
)
|
|
355
355
|
|
|
356
356
|
# Generate final synthesis
|
|
357
|
-
|
|
357
|
+
final_message = await self._planner_generate_str(result_prompt, request_params)
|
|
358
|
+
plan_result.result = final_message.last_text() or "No final message generated"
|
|
359
|
+
await self.show_assistant_message(final_message)
|
|
358
360
|
return plan_result
|
|
359
361
|
|
|
360
362
|
async def _execute_step(self, step: Step, previous_result: PlanResult) -> Any:
|
|
@@ -369,7 +371,7 @@ class IterativePlanner(BaseAgent):
|
|
|
369
371
|
Returns:
|
|
370
372
|
Result of executing the step
|
|
371
373
|
"""
|
|
372
|
-
from
|
|
374
|
+
from fast_agent.agents.workflow.orchestrator_models import StepResult
|
|
373
375
|
|
|
374
376
|
# Initialize step result
|
|
375
377
|
step_result = StepResult(step=step, task_results=[])
|
|
@@ -397,7 +399,7 @@ class IterativePlanner(BaseAgent):
|
|
|
397
399
|
)
|
|
398
400
|
result = await agent.generate(
|
|
399
401
|
[
|
|
400
|
-
|
|
402
|
+
PromptMessageExtended(
|
|
401
403
|
role="user",
|
|
402
404
|
content=[TextContent(type="text", text=task_description)],
|
|
403
405
|
)
|
|
@@ -409,11 +411,11 @@ class IterativePlanner(BaseAgent):
|
|
|
409
411
|
TaskWithResult(
|
|
410
412
|
description=task_model["description"],
|
|
411
413
|
agent=task_model["agent"],
|
|
412
|
-
result=result.last_text(),
|
|
414
|
+
result=result.last_text() or "<missing response>",
|
|
413
415
|
)
|
|
414
416
|
)
|
|
415
417
|
except Exception as e:
|
|
416
|
-
|
|
418
|
+
logger.error(f"Error executing task: {str(e)}")
|
|
417
419
|
task_model = task.model_dump()
|
|
418
420
|
results.append(
|
|
419
421
|
TaskWithResult(
|
|
@@ -484,16 +486,24 @@ class IterativePlanner(BaseAgent):
|
|
|
484
486
|
iterations_info=iterations_info,
|
|
485
487
|
)
|
|
486
488
|
|
|
489
|
+
request_params = self._merge_request_params(
|
|
490
|
+
request_params, RequestParams(systemPrompt=self.instruction)
|
|
491
|
+
)
|
|
492
|
+
|
|
487
493
|
# Get structured response from LLM
|
|
488
494
|
try:
|
|
489
|
-
plan_msg =
|
|
495
|
+
plan_msg = PromptMessageExtended(
|
|
490
496
|
role="user", content=[TextContent(type="text", text=prompt)]
|
|
491
497
|
)
|
|
492
498
|
assert self._llm
|
|
493
|
-
|
|
499
|
+
self.show_user_message(plan_msg)
|
|
500
|
+
next_step, raw_response = await self._llm.structured(
|
|
501
|
+
[plan_msg], PlanningStep, request_params
|
|
502
|
+
)
|
|
503
|
+
await self.show_assistant_message(raw_response)
|
|
494
504
|
return next_step
|
|
495
505
|
except Exception as e:
|
|
496
|
-
|
|
506
|
+
logger.error(f"Failed to parse next step: {str(e)}")
|
|
497
507
|
return None
|
|
498
508
|
|
|
499
509
|
def _validate_agent_names(self, plan: Plan) -> List[str]:
|
|
@@ -552,7 +562,7 @@ class IterativePlanner(BaseAgent):
|
|
|
552
562
|
|
|
553
563
|
async def _planner_generate_str(
|
|
554
564
|
self, message: str, request_params: RequestParams | None
|
|
555
|
-
) ->
|
|
565
|
+
) -> PromptMessageExtended:
|
|
556
566
|
"""
|
|
557
567
|
Generate string response from the orchestrator's own LLM.
|
|
558
568
|
|
|
@@ -564,9 +574,8 @@ class IterativePlanner(BaseAgent):
|
|
|
564
574
|
String response from the LLM
|
|
565
575
|
"""
|
|
566
576
|
# Create prompt message
|
|
567
|
-
prompt =
|
|
577
|
+
prompt = PromptMessageExtended(
|
|
568
578
|
role="user", content=[TextContent(type="text", text=message)]
|
|
569
579
|
)
|
|
570
580
|
assert self._llm, "LLM must be initialized before generating text"
|
|
571
|
-
|
|
572
|
-
return response.last_text()
|
|
581
|
+
return await self._llm.generate([prompt], request_params)
|
|
@@ -2,7 +2,7 @@ from typing import List
|
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, ConfigDict, Field
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from fast_agent.agents.workflow.orchestrator_prompts import (
|
|
6
6
|
PLAN_RESULT_TEMPLATE,
|
|
7
7
|
STEP_RESULT_TEMPLATE,
|
|
8
8
|
TASK_RESULT_TEMPLATE,
|
|
@@ -152,7 +152,7 @@ def format_plan_result_text(plan_result: PlanResult) -> str:
|
|
|
152
152
|
|
|
153
153
|
def format_task_result_xml(task_result: TaskWithResult) -> str:
|
|
154
154
|
"""Format a task result with XML tags for better semantic understanding"""
|
|
155
|
-
from
|
|
155
|
+
from fast_agent.llm.prompt_utils import format_fastagent_tag
|
|
156
156
|
|
|
157
157
|
return format_fastagent_tag(
|
|
158
158
|
"task-result",
|
|
@@ -168,7 +168,7 @@ def format_task_result_xml(task_result: TaskWithResult) -> str:
|
|
|
168
168
|
|
|
169
169
|
def format_step_result_xml(step_result: StepResult) -> str:
|
|
170
170
|
"""Format a step result with XML tags for better semantic understanding"""
|
|
171
|
-
from
|
|
171
|
+
from fast_agent.llm.prompt_utils import format_fastagent_tag
|
|
172
172
|
|
|
173
173
|
# Format each task result with XML
|
|
174
174
|
task_results = []
|
|
@@ -190,7 +190,7 @@ def format_step_result_xml(step_result: StepResult) -> str:
|
|
|
190
190
|
|
|
191
191
|
def format_plan_result(plan_result: PlanResult) -> str:
|
|
192
192
|
"""Format the full plan execution state with XML for better semantic understanding"""
|
|
193
|
-
from
|
|
193
|
+
from fast_agent.llm.prompt_utils import format_fastagent_tag
|
|
194
194
|
|
|
195
195
|
# Format objective
|
|
196
196
|
objective_tag = format_fastagent_tag("objective", plan_result.objective)
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import Any, List, Optional, Tuple
|
|
3
3
|
|
|
4
|
+
from mcp import Tool
|
|
4
5
|
from mcp.types import TextContent
|
|
5
6
|
from opentelemetry import trace
|
|
6
7
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
|
8
|
+
from fast_agent.agents.agent_types import AgentConfig, AgentType
|
|
9
|
+
from fast_agent.agents.llm_agent import LlmAgent
|
|
10
|
+
from fast_agent.core.logging.logger import get_logger
|
|
11
|
+
from fast_agent.interfaces import AgentProtocol, ModelT
|
|
12
|
+
from fast_agent.types import PromptMessageExtended, RequestParams
|
|
13
13
|
|
|
14
|
+
logger = get_logger(__name__)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
class ParallelAgent(LlmAgent):
|
|
16
18
|
"""
|
|
17
19
|
LLMs can sometimes work simultaneously on a task (fan-out)
|
|
18
20
|
and have their outputs aggregated programmatically (fan-in).
|
|
@@ -28,8 +30,8 @@ class ParallelAgent(BaseAgent):
|
|
|
28
30
|
def __init__(
|
|
29
31
|
self,
|
|
30
32
|
config: AgentConfig,
|
|
31
|
-
fan_in_agent:
|
|
32
|
-
fan_out_agents: List[
|
|
33
|
+
fan_in_agent: AgentProtocol,
|
|
34
|
+
fan_out_agents: List[AgentProtocol],
|
|
33
35
|
include_request: bool = True,
|
|
34
36
|
**kwargs,
|
|
35
37
|
) -> None:
|
|
@@ -48,16 +50,17 @@ class ParallelAgent(BaseAgent):
|
|
|
48
50
|
self.fan_out_agents = fan_out_agents
|
|
49
51
|
self.include_request = include_request
|
|
50
52
|
|
|
51
|
-
async def
|
|
53
|
+
async def generate_impl(
|
|
52
54
|
self,
|
|
53
|
-
|
|
55
|
+
messages: List[PromptMessageExtended],
|
|
54
56
|
request_params: Optional[RequestParams] = None,
|
|
55
|
-
|
|
57
|
+
tools: List[Tool] | None = None,
|
|
58
|
+
) -> PromptMessageExtended:
|
|
56
59
|
"""
|
|
57
60
|
Execute fan-out agents in parallel and aggregate their results with the fan-in agent.
|
|
58
61
|
|
|
59
62
|
Args:
|
|
60
|
-
|
|
63
|
+
normalized_messages: Already normalized list of PromptMessageExtended
|
|
61
64
|
request_params: Optional parameters to configure the request
|
|
62
65
|
|
|
63
66
|
Returns:
|
|
@@ -65,19 +68,14 @@ class ParallelAgent(BaseAgent):
|
|
|
65
68
|
"""
|
|
66
69
|
|
|
67
70
|
tracer = trace.get_tracer(__name__)
|
|
68
|
-
with tracer.start_as_current_span(f"Parallel: '{self.
|
|
71
|
+
with tracer.start_as_current_span(f"Parallel: '{self._name}' generate"):
|
|
69
72
|
# Execute all fan-out agents in parallel
|
|
70
|
-
responses: List[
|
|
71
|
-
*[
|
|
72
|
-
agent.generate(multipart_messages, request_params)
|
|
73
|
-
for agent in self.fan_out_agents
|
|
74
|
-
]
|
|
73
|
+
responses: List[PromptMessageExtended] = await asyncio.gather(
|
|
74
|
+
*[agent.generate(messages, request_params) for agent in self.fan_out_agents]
|
|
75
75
|
)
|
|
76
76
|
|
|
77
77
|
# Extract the received message from the input
|
|
78
|
-
received_message: Optional[str] = (
|
|
79
|
-
multipart_messages[-1].all_text() if multipart_messages else None
|
|
80
|
-
)
|
|
78
|
+
received_message: Optional[str] = messages[-1].all_text() if messages else None
|
|
81
79
|
|
|
82
80
|
# Convert responses to strings for aggregation
|
|
83
81
|
string_responses = []
|
|
@@ -88,7 +86,7 @@ class ParallelAgent(BaseAgent):
|
|
|
88
86
|
aggregated_prompt = self._format_responses(string_responses, received_message)
|
|
89
87
|
|
|
90
88
|
# Create a new multipart message with the formatted responses
|
|
91
|
-
formatted_prompt =
|
|
89
|
+
formatted_prompt = PromptMessageExtended(
|
|
92
90
|
role="user", content=[TextContent(type="text", text=aggregated_prompt)]
|
|
93
91
|
)
|
|
94
92
|
|
|
@@ -121,19 +119,19 @@ class ParallelAgent(BaseAgent):
|
|
|
121
119
|
)
|
|
122
120
|
return "\n\n".join(formatted)
|
|
123
121
|
|
|
124
|
-
async def
|
|
122
|
+
async def structured_impl(
|
|
125
123
|
self,
|
|
126
|
-
|
|
124
|
+
messages: List[PromptMessageExtended],
|
|
127
125
|
model: type[ModelT],
|
|
128
126
|
request_params: Optional[RequestParams] = None,
|
|
129
|
-
) -> Tuple[ModelT | None,
|
|
127
|
+
) -> Tuple[ModelT | None, PromptMessageExtended]:
|
|
130
128
|
"""
|
|
131
129
|
Apply the prompt and return the result as a Pydantic model.
|
|
132
130
|
|
|
133
131
|
This implementation delegates to the fan-in agent's structured method.
|
|
134
132
|
|
|
135
133
|
Args:
|
|
136
|
-
|
|
134
|
+
messages: List of PromptMessageExtended objects
|
|
137
135
|
model: The Pydantic model class to parse the result into
|
|
138
136
|
request_params: Optional parameters to configure the LLM request
|
|
139
137
|
|
|
@@ -142,19 +140,14 @@ class ParallelAgent(BaseAgent):
|
|
|
142
140
|
"""
|
|
143
141
|
|
|
144
142
|
tracer = trace.get_tracer(__name__)
|
|
145
|
-
with tracer.start_as_current_span(f"Parallel: '{self.
|
|
143
|
+
with tracer.start_as_current_span(f"Parallel: '{self._name}' generate"):
|
|
146
144
|
# Generate parallel responses first
|
|
147
|
-
responses: List[
|
|
148
|
-
*[
|
|
149
|
-
agent.generate(multipart_messages, request_params)
|
|
150
|
-
for agent in self.fan_out_agents
|
|
151
|
-
]
|
|
145
|
+
responses: List[PromptMessageExtended] = await asyncio.gather(
|
|
146
|
+
*[agent.generate(messages, request_params) for agent in self.fan_out_agents]
|
|
152
147
|
)
|
|
153
148
|
|
|
154
149
|
# Extract the received message
|
|
155
|
-
received_message: Optional[str] = (
|
|
156
|
-
multipart_messages[-1].all_text() if multipart_messages else None
|
|
157
|
-
)
|
|
150
|
+
received_message: Optional[str] = messages[-1].all_text() if messages else None
|
|
158
151
|
|
|
159
152
|
# Convert responses to strings
|
|
160
153
|
string_responses = [response.all_text() for response in responses]
|
|
@@ -163,7 +156,7 @@ class ParallelAgent(BaseAgent):
|
|
|
163
156
|
aggregated_prompt = self._format_responses(string_responses, received_message)
|
|
164
157
|
|
|
165
158
|
# Create a multipart message
|
|
166
|
-
formatted_prompt =
|
|
159
|
+
formatted_prompt = PromptMessageExtended(
|
|
167
160
|
role="user", content=[TextContent(type="text", text=aggregated_prompt)]
|
|
168
161
|
)
|
|
169
162
|
|
|
@@ -177,11 +170,11 @@ class ParallelAgent(BaseAgent):
|
|
|
177
170
|
await super().initialize()
|
|
178
171
|
|
|
179
172
|
# Initialize fan-in and fan-out agents if not already initialized
|
|
180
|
-
if not
|
|
173
|
+
if not self.fan_in_agent.initialized:
|
|
181
174
|
await self.fan_in_agent.initialize()
|
|
182
175
|
|
|
183
176
|
for agent in self.fan_out_agents:
|
|
184
|
-
if not
|
|
177
|
+
if not agent.initialized:
|
|
185
178
|
await agent.initialize()
|
|
186
179
|
|
|
187
180
|
async def shutdown(self) -> None:
|
|
@@ -194,10 +187,10 @@ class ParallelAgent(BaseAgent):
|
|
|
194
187
|
try:
|
|
195
188
|
await self.fan_in_agent.shutdown()
|
|
196
189
|
except Exception as e:
|
|
197
|
-
|
|
190
|
+
logger.warning(f"Error shutting down fan-in agent: {str(e)}")
|
|
198
191
|
|
|
199
192
|
for agent in self.fan_out_agents:
|
|
200
193
|
try:
|
|
201
194
|
await agent.shutdown()
|
|
202
195
|
except Exception as e:
|
|
203
|
-
|
|
196
|
+
logger.warning(f"Error shutting down fan-out agent {agent.name}: {str(e)}")
|