fast-agent-mcp 0.2.58__py3-none-any.whl → 0.3.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.
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 +64 -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 +17 -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 +43 -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/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.0.dist-info}/METADATA +7 -7
- fast_agent_mcp-0.3.0.dist-info/RECORD +202 -0
- fast_agent_mcp-0.3.0.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.0.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,25 +5,24 @@ This provides a simplified implementation that routes messages to agents
|
|
|
5
5
|
by determining the best agent for a request and dispatching to it.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import TYPE_CHECKING,
|
|
8
|
+
from typing import TYPE_CHECKING, List, Optional, Tuple, Type
|
|
9
9
|
|
|
10
|
+
from mcp import Tool
|
|
10
11
|
from opentelemetry import trace
|
|
11
12
|
from pydantic import BaseModel
|
|
12
13
|
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
from
|
|
20
|
-
from mcp_agent.mcp.interfaces import AugmentedLLMProtocol, ModelT
|
|
21
|
-
from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
|
|
14
|
+
from fast_agent.agents.agent_types import AgentConfig, AgentType
|
|
15
|
+
from fast_agent.agents.llm_agent import LlmAgent
|
|
16
|
+
from fast_agent.core.exceptions import AgentConfigError
|
|
17
|
+
from fast_agent.core.logging.logger import get_logger
|
|
18
|
+
from fast_agent.core.prompt import Prompt
|
|
19
|
+
from fast_agent.interfaces import FastAgentLLMProtocol, LLMFactoryProtocol, ModelT
|
|
20
|
+
from fast_agent.types import PromptMessageExtended, RequestParams
|
|
22
21
|
|
|
23
22
|
if TYPE_CHECKING:
|
|
24
23
|
from a2a.types import AgentCard
|
|
25
24
|
|
|
26
|
-
from
|
|
25
|
+
from fast_agent.context import Context
|
|
27
26
|
|
|
28
27
|
logger = get_logger(__name__)
|
|
29
28
|
|
|
@@ -60,7 +59,7 @@ class RoutingResponse(BaseModel):
|
|
|
60
59
|
reasoning: str | None = None
|
|
61
60
|
|
|
62
61
|
|
|
63
|
-
class RouterAgent(
|
|
62
|
+
class RouterAgent(LlmAgent):
|
|
64
63
|
"""
|
|
65
64
|
A simplified router that uses an LLM to determine the best agent for a request,
|
|
66
65
|
then dispatches the request to that agent and returns the response.
|
|
@@ -74,10 +73,10 @@ class RouterAgent(BaseAgent):
|
|
|
74
73
|
def __init__(
|
|
75
74
|
self,
|
|
76
75
|
config: AgentConfig,
|
|
77
|
-
agents: List[
|
|
78
|
-
routing_instruction:
|
|
79
|
-
context:
|
|
80
|
-
default_request_params:
|
|
76
|
+
agents: List[LlmAgent],
|
|
77
|
+
routing_instruction: str | None = None,
|
|
78
|
+
context: "Context | None" = None,
|
|
79
|
+
default_request_params: RequestParams | None = None,
|
|
81
80
|
**kwargs,
|
|
82
81
|
) -> None:
|
|
83
82
|
"""
|
|
@@ -117,7 +116,7 @@ class RouterAgent(BaseAgent):
|
|
|
117
116
|
|
|
118
117
|
# Initialize all agents if not already initialized
|
|
119
118
|
for agent in self.agents:
|
|
120
|
-
if not
|
|
119
|
+
if not agent.initialized:
|
|
121
120
|
await agent.initialize()
|
|
122
121
|
|
|
123
122
|
complete_routing_instruction = await self._generate_routing_instruction(
|
|
@@ -130,9 +129,6 @@ class RouterAgent(BaseAgent):
|
|
|
130
129
|
)
|
|
131
130
|
self._default_request_params.systemPrompt = combined_system_prompt
|
|
132
131
|
self.instruction = combined_system_prompt
|
|
133
|
-
self._routing_instruction_generated = True
|
|
134
|
-
|
|
135
|
-
self.initialized = True
|
|
136
132
|
|
|
137
133
|
async def shutdown(self) -> None:
|
|
138
134
|
"""Shutdown the router and all agents."""
|
|
@@ -147,7 +143,7 @@ class RouterAgent(BaseAgent):
|
|
|
147
143
|
|
|
148
144
|
@staticmethod
|
|
149
145
|
async def _generate_routing_instruction(
|
|
150
|
-
agents: List[
|
|
146
|
+
agents: List[LlmAgent], routing_instruction: Optional[str] = None
|
|
151
147
|
) -> str:
|
|
152
148
|
"""
|
|
153
149
|
Generate the complete routing instruction with agent cards.
|
|
@@ -177,54 +173,59 @@ class RouterAgent(BaseAgent):
|
|
|
177
173
|
|
|
178
174
|
async def attach_llm(
|
|
179
175
|
self,
|
|
180
|
-
llm_factory:
|
|
176
|
+
llm_factory: LLMFactoryProtocol,
|
|
181
177
|
model: str | None = None,
|
|
182
178
|
request_params: RequestParams | None = None,
|
|
183
179
|
**additional_kwargs,
|
|
184
|
-
) ->
|
|
180
|
+
) -> FastAgentLLMProtocol:
|
|
185
181
|
return await super().attach_llm(
|
|
186
182
|
llm_factory, model, request_params, verb="Routing", **additional_kwargs
|
|
187
183
|
)
|
|
188
184
|
|
|
189
|
-
async def
|
|
185
|
+
async def generate_impl(
|
|
190
186
|
self,
|
|
191
|
-
|
|
187
|
+
messages: List[PromptMessageExtended],
|
|
192
188
|
request_params: Optional[RequestParams] = None,
|
|
193
|
-
|
|
189
|
+
tools: List[Tool] | None = None,
|
|
190
|
+
) -> PromptMessageExtended:
|
|
194
191
|
"""
|
|
195
192
|
Route the request to the most appropriate agent and return its response.
|
|
196
193
|
|
|
197
194
|
Args:
|
|
198
|
-
|
|
195
|
+
normalized_messages: Already normalized list of PromptMessageExtended
|
|
199
196
|
request_params: Optional request parameters
|
|
200
197
|
|
|
201
198
|
Returns:
|
|
202
199
|
The response from the selected agent
|
|
203
200
|
"""
|
|
201
|
+
|
|
202
|
+
# implementation note. the duplication between generated and structured
|
|
203
|
+
# is probably the most readable. alt could be a _get_route_agent or
|
|
204
|
+
# some form of dynamic dispatch.. but only if this gets more complex
|
|
204
205
|
tracer = trace.get_tracer(__name__)
|
|
205
206
|
with tracer.start_as_current_span(f"Routing: '{self.name}' generate"):
|
|
206
|
-
route, warn = await self._route_request(
|
|
207
|
+
route, warn = await self._route_request(messages[-1])
|
|
207
208
|
|
|
208
209
|
if not route:
|
|
209
210
|
return Prompt.assistant(warn or "No routing result or warning received")
|
|
210
211
|
|
|
211
212
|
# Get the selected agent
|
|
212
|
-
agent:
|
|
213
|
+
agent: LlmAgent = self.agent_map[route.agent]
|
|
213
214
|
|
|
214
215
|
# Dispatch the request to the selected agent
|
|
215
|
-
return await agent.
|
|
216
|
+
return await agent.generate_impl(messages, request_params)
|
|
216
217
|
|
|
217
|
-
async def
|
|
218
|
+
async def structured_impl(
|
|
218
219
|
self,
|
|
219
|
-
|
|
220
|
+
messages: List[PromptMessageExtended],
|
|
220
221
|
model: Type[ModelT],
|
|
221
222
|
request_params: Optional[RequestParams] = None,
|
|
222
|
-
) -> Tuple[ModelT | None,
|
|
223
|
+
) -> Tuple[ModelT | None, PromptMessageExtended]:
|
|
223
224
|
"""
|
|
224
225
|
Route the request to the most appropriate agent and parse its response.
|
|
225
226
|
|
|
226
227
|
Args:
|
|
227
|
-
|
|
228
|
+
messages: Messages to route
|
|
228
229
|
model: Pydantic model to parse the response into
|
|
229
230
|
request_params: Optional request parameters
|
|
230
231
|
|
|
@@ -234,7 +235,7 @@ class RouterAgent(BaseAgent):
|
|
|
234
235
|
|
|
235
236
|
tracer = trace.get_tracer(__name__)
|
|
236
237
|
with tracer.start_as_current_span(f"Routing: '{self.name}' structured"):
|
|
237
|
-
route, warn = await self._route_request(
|
|
238
|
+
route, warn = await self._route_request(messages[-1])
|
|
238
239
|
|
|
239
240
|
if not route:
|
|
240
241
|
return None, Prompt.assistant(
|
|
@@ -242,13 +243,13 @@ class RouterAgent(BaseAgent):
|
|
|
242
243
|
)
|
|
243
244
|
|
|
244
245
|
# Get the selected agent
|
|
245
|
-
agent:
|
|
246
|
+
agent: LlmAgent = self.agent_map[route.agent]
|
|
246
247
|
|
|
247
248
|
# Dispatch the request to the selected agent
|
|
248
|
-
return await agent.
|
|
249
|
+
return await agent.structured_impl(messages, model, request_params)
|
|
249
250
|
|
|
250
251
|
async def _route_request(
|
|
251
|
-
self, message:
|
|
252
|
+
self, message: PromptMessageExtended
|
|
252
253
|
) -> Tuple[RoutingResponse | None, str | None]:
|
|
253
254
|
"""
|
|
254
255
|
Determine which agent to route the request to.
|
|
@@ -263,13 +264,16 @@ class RouterAgent(BaseAgent):
|
|
|
263
264
|
logger.error("No agents available for routing")
|
|
264
265
|
raise AgentConfigError("No agents available for routing - fatal error")
|
|
265
266
|
|
|
266
|
-
#
|
|
267
|
+
# go straight to agent if only one available
|
|
267
268
|
if len(self.agents) == 1:
|
|
268
269
|
return RoutingResponse(
|
|
269
270
|
agent=self.agents[0].name, confidence="high", reasoning="Only one agent available"
|
|
270
271
|
), None
|
|
271
272
|
|
|
272
273
|
assert self._llm
|
|
274
|
+
# Display the user's routing request
|
|
275
|
+
self.display.show_user_message(message.first_text(), name=self.name)
|
|
276
|
+
|
|
273
277
|
# No need to add routing instruction here - it's already in the system prompt
|
|
274
278
|
response, _ = await self._llm.structured(
|
|
275
279
|
[message],
|
|
@@ -292,4 +296,15 @@ class RouterAgent(BaseAgent):
|
|
|
292
296
|
f"Routing structured request to agent: {response.agent or 'error'} (confidence: {response.confidence or ''})"
|
|
293
297
|
)
|
|
294
298
|
|
|
299
|
+
routing_message = f"Routing to: {response.agent}"
|
|
300
|
+
if response.reasoning:
|
|
301
|
+
routing_message += f" ({response.reasoning})"
|
|
302
|
+
|
|
303
|
+
await self.display.show_assistant_message(
|
|
304
|
+
routing_message,
|
|
305
|
+
bottom_items=list(self.agent_map.keys()),
|
|
306
|
+
highlight_items=[response.agent],
|
|
307
|
+
name=self.name,
|
|
308
|
+
)
|
|
309
|
+
|
|
295
310
|
return response, None
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
3
|
+
from fast_agent.cli.constants import GO_SPECIFIC_OPTIONS, KNOWN_SUBCOMMANDS
|
|
4
|
+
from fast_agent.cli.main import app
|
|
5
5
|
|
|
6
6
|
# if the arguments would work with "go" we'll just route to it
|
|
7
7
|
|
|
@@ -20,7 +20,9 @@ def main():
|
|
|
20
20
|
# Find where to insert 'go' - before the first go-specific option
|
|
21
21
|
insert_pos = 1
|
|
22
22
|
for i, arg in enumerate(sys.argv[1:], 1):
|
|
23
|
-
if arg in GO_SPECIFIC_OPTIONS or any(
|
|
23
|
+
if arg in GO_SPECIFIC_OPTIONS or any(
|
|
24
|
+
arg.startswith(opt + "=") for opt in GO_SPECIFIC_OPTIONS
|
|
25
|
+
):
|
|
24
26
|
insert_pos = i
|
|
25
27
|
break
|
|
26
28
|
# Auto-route to go command
|
|
@@ -9,11 +9,11 @@ from typing import Optional
|
|
|
9
9
|
import typer
|
|
10
10
|
import yaml
|
|
11
11
|
from rich.console import Console
|
|
12
|
-
from rich.panel import Panel
|
|
13
12
|
from rich.table import Table
|
|
13
|
+
from rich.text import Text
|
|
14
14
|
|
|
15
|
-
from
|
|
16
|
-
from
|
|
15
|
+
from fast_agent.llm.provider_key_manager import API_KEY_HINT_TEXT, ProviderKeyManager
|
|
16
|
+
from fast_agent.llm.provider_types import Provider
|
|
17
17
|
|
|
18
18
|
app = typer.Typer(
|
|
19
19
|
help="Check and diagnose FastAgent configuration",
|
|
@@ -24,7 +24,7 @@ console = Console()
|
|
|
24
24
|
|
|
25
25
|
def find_config_files(start_path: Path) -> dict[str, Optional[Path]]:
|
|
26
26
|
"""Find FastAgent configuration files, preferring secrets file next to config file."""
|
|
27
|
-
from
|
|
27
|
+
from fast_agent.config import find_fastagent_config_files
|
|
28
28
|
|
|
29
29
|
config_path, secrets_path = find_fastagent_config_files(start_path)
|
|
30
30
|
return {
|
|
@@ -145,7 +145,7 @@ def get_fastagent_version() -> str:
|
|
|
145
145
|
|
|
146
146
|
def get_config_summary(config_path: Optional[Path]) -> dict:
|
|
147
147
|
"""Extract key information from the configuration file."""
|
|
148
|
-
from
|
|
148
|
+
from fast_agent.config import Settings
|
|
149
149
|
|
|
150
150
|
# Get actual defaults from Settings class
|
|
151
151
|
default_settings = Settings()
|
|
@@ -163,6 +163,7 @@ def get_config_summary(config_path: Optional[Path]) -> dict:
|
|
|
163
163
|
"truncate_tools": default_settings.logger.truncate_tools,
|
|
164
164
|
"enable_markup": default_settings.logger.enable_markup,
|
|
165
165
|
},
|
|
166
|
+
"mcp_ui_mode": default_settings.mcp_ui_mode,
|
|
166
167
|
"mcp_servers": [],
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -207,6 +208,10 @@ def get_config_summary(config_path: Optional[Path]) -> dict:
|
|
|
207
208
|
),
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
# Get MCP UI mode
|
|
212
|
+
if "mcp_ui_mode" in config:
|
|
213
|
+
result["mcp_ui_mode"] = config["mcp_ui_mode"]
|
|
214
|
+
|
|
210
215
|
# Get MCP server info
|
|
211
216
|
if "mcp" in config and "servers" in config["mcp"]:
|
|
212
217
|
for server_name, server_config in config["mcp"]["servers"].items():
|
|
@@ -272,76 +277,93 @@ def show_check_summary() -> None:
|
|
|
272
277
|
api_keys = check_api_keys(secrets_summary, config_summary)
|
|
273
278
|
fastagent_version = get_fastagent_version()
|
|
274
279
|
|
|
275
|
-
#
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
280
|
+
# Helper to print section headers using the new console_display style
|
|
281
|
+
def _print_section_header(title: str, color: str = "blue") -> None:
|
|
282
|
+
width = console.size.width
|
|
283
|
+
left = f"[{color}]▎[/{color}][dim {color}]▶[/dim {color}] [{color}]{title}[/{color}]"
|
|
284
|
+
left_text = Text.from_markup(left)
|
|
285
|
+
separator_count = max(1, width - left_text.cell_len - 1)
|
|
279
286
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
287
|
+
combined = Text()
|
|
288
|
+
combined.append_text(left_text)
|
|
289
|
+
combined.append(" ")
|
|
290
|
+
combined.append("─" * separator_count, style="dim")
|
|
284
291
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
292
|
+
console.print()
|
|
293
|
+
console.print(combined)
|
|
294
|
+
console.print()
|
|
295
|
+
|
|
296
|
+
# Environment and configuration section (merged)
|
|
297
|
+
# Header shows version and platform for a concise overview
|
|
298
|
+
header_title = f"fast-agent v{fastagent_version} ({system_info['platform']})"
|
|
299
|
+
_print_section_header(header_title, color="blue")
|
|
288
300
|
|
|
289
|
-
# Configuration files panel
|
|
290
301
|
config_path = config_files["config"]
|
|
291
302
|
secrets_path = config_files["secrets"]
|
|
292
303
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
304
|
+
env_table = Table(show_header=False, box=None)
|
|
305
|
+
env_table.add_column("Setting", style="white")
|
|
306
|
+
env_table.add_column("Value")
|
|
296
307
|
|
|
297
|
-
#
|
|
308
|
+
# Python info (highlight version and path in green)
|
|
309
|
+
env_table.add_row(
|
|
310
|
+
"Python Version", f"[green]{'.'.join(system_info['python_version'].split('.')[:3])}[/green]"
|
|
311
|
+
)
|
|
312
|
+
env_table.add_row("Python Path", f"[green]{system_info['python_path']}[/green]")
|
|
313
|
+
|
|
314
|
+
# Secrets file status
|
|
298
315
|
secrets_status = secrets_summary.get("status", "not_found")
|
|
299
316
|
if secrets_status == "not_found":
|
|
300
|
-
|
|
317
|
+
env_table.add_row("Secrets File", "[yellow]Not found[/yellow]")
|
|
301
318
|
elif secrets_status == "error":
|
|
302
|
-
|
|
303
|
-
|
|
319
|
+
env_table.add_row("Secrets File", f"[orange_red1]Errors[/orange_red1] ({secrets_path})")
|
|
320
|
+
env_table.add_row(
|
|
304
321
|
"Secrets Error",
|
|
305
322
|
f"[orange_red1]{secrets_summary.get('error', 'Unknown error')}[/orange_red1]",
|
|
306
323
|
)
|
|
307
324
|
else: # parsed successfully
|
|
308
|
-
|
|
325
|
+
env_table.add_row("Secrets File", f"[green]Found[/green] ({secrets_path})")
|
|
309
326
|
|
|
310
|
-
#
|
|
327
|
+
# Config file status
|
|
311
328
|
config_status = config_summary.get("status", "not_found")
|
|
312
329
|
if config_status == "not_found":
|
|
313
|
-
|
|
330
|
+
env_table.add_row("Config File", "[red]Not found[/red]")
|
|
314
331
|
elif config_status == "error":
|
|
315
|
-
|
|
316
|
-
|
|
332
|
+
env_table.add_row("Config File", f"[orange_red1]Errors[/orange_red1] ({config_path})")
|
|
333
|
+
env_table.add_row(
|
|
317
334
|
"Config Error",
|
|
318
335
|
f"[orange_red1]{config_summary.get('error', 'Unknown error')}[/orange_red1]",
|
|
319
336
|
)
|
|
320
337
|
else: # parsed successfully
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
)
|
|
338
|
+
env_table.add_row("Config File", f"[green]Found[/green] ({config_path})")
|
|
339
|
+
default_model_value = config_summary.get("default_model", "haiku (system default)")
|
|
340
|
+
env_table.add_row("Default Model", f"[green]{default_model_value}[/green]")
|
|
325
341
|
|
|
326
|
-
console.print(
|
|
327
|
-
Panel(files_table, title="Configuration Files", title_align="left", border_style="blue")
|
|
328
|
-
)
|
|
342
|
+
console.print(env_table)
|
|
329
343
|
|
|
330
344
|
# Logger Settings panel with two-column layout
|
|
331
345
|
logger = config_summary.get("logger", {})
|
|
332
346
|
logger_table = Table(show_header=True, box=None)
|
|
333
|
-
logger_table.add_column("Setting", style="
|
|
334
|
-
logger_table.add_column("Value")
|
|
335
|
-
logger_table.add_column("Setting", style="
|
|
336
|
-
logger_table.add_column("Value")
|
|
347
|
+
logger_table.add_column("Setting", style="white", header_style="bold bright_white")
|
|
348
|
+
logger_table.add_column("Value", header_style="bold bright_white")
|
|
349
|
+
logger_table.add_column("Setting", style="white", header_style="bold bright_white")
|
|
350
|
+
logger_table.add_column("Value", header_style="bold bright_white")
|
|
337
351
|
|
|
338
352
|
def bool_to_symbol(value):
|
|
339
353
|
return "[bold green]✓[/bold green]" if value else "[bold red]✗[/bold red]"
|
|
340
354
|
|
|
355
|
+
# Format MCP-UI mode value
|
|
356
|
+
mcp_ui_mode = config_summary.get("mcp_ui_mode", "auto")
|
|
357
|
+
if mcp_ui_mode == "disabled":
|
|
358
|
+
mcp_ui_display = "[dim]disabled[/dim]"
|
|
359
|
+
else:
|
|
360
|
+
mcp_ui_display = f"[green]{mcp_ui_mode}[/green]"
|
|
361
|
+
|
|
341
362
|
# Prepare all settings as pairs
|
|
342
363
|
settings_data = [
|
|
343
|
-
("
|
|
344
|
-
("
|
|
364
|
+
("Log Level", logger.get("level", "warning (default)")),
|
|
365
|
+
("Log Type", logger.get("type", "file (default)")),
|
|
366
|
+
("MCP-UI", mcp_ui_display),
|
|
345
367
|
("Progress Display", bool_to_symbol(logger.get("progress_display", True))),
|
|
346
368
|
("Show Chat", bool_to_symbol(logger.get("show_chat", True))),
|
|
347
369
|
("Show Tools", bool_to_symbol(logger.get("show_tools", True))),
|
|
@@ -349,30 +371,34 @@ def show_check_summary() -> None:
|
|
|
349
371
|
("Enable Markup", bool_to_symbol(logger.get("enable_markup", True))),
|
|
350
372
|
]
|
|
351
373
|
|
|
352
|
-
# Add rows in two-column layout
|
|
374
|
+
# Add rows in two-column layout, styling some values in green
|
|
353
375
|
for i in range(0, len(settings_data), 2):
|
|
354
376
|
left_setting, left_value = settings_data[i]
|
|
377
|
+
# Style certain values in green (MCP-UI is already pre-styled)
|
|
378
|
+
if left_setting in ("Log Level", "Log Type"):
|
|
379
|
+
left_value = f"[green]{left_value}[/green]"
|
|
355
380
|
if i + 1 < len(settings_data):
|
|
356
381
|
right_setting, right_value = settings_data[i + 1]
|
|
382
|
+
if right_setting in ("Log Level", "Log Type"):
|
|
383
|
+
right_value = f"[green]{right_value}[/green]"
|
|
357
384
|
logger_table.add_row(left_setting, left_value, right_setting, right_value)
|
|
358
385
|
else:
|
|
359
386
|
# Odd number of settings - fill right column with empty strings
|
|
360
387
|
logger_table.add_row(left_setting, left_value, "", "")
|
|
361
388
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
)
|
|
389
|
+
_print_section_header("Application Settings", color="blue")
|
|
390
|
+
console.print(logger_table)
|
|
365
391
|
|
|
366
392
|
# API keys panel with two-column layout
|
|
367
393
|
keys_table = Table(show_header=True, box=None)
|
|
368
|
-
keys_table.add_column("Provider", style="
|
|
369
|
-
keys_table.add_column("Env", justify="center")
|
|
370
|
-
keys_table.add_column("Config", justify="center")
|
|
371
|
-
keys_table.add_column("Active Key", style="green")
|
|
372
|
-
keys_table.add_column("Provider", style="
|
|
373
|
-
keys_table.add_column("Env", justify="center")
|
|
374
|
-
keys_table.add_column("Config", justify="center")
|
|
375
|
-
keys_table.add_column("Active Key", style="green")
|
|
394
|
+
keys_table.add_column("Provider", style="white", header_style="bold bright_white")
|
|
395
|
+
keys_table.add_column("Env", justify="center", header_style="bold bright_white")
|
|
396
|
+
keys_table.add_column("Config", justify="center", header_style="bold bright_white")
|
|
397
|
+
keys_table.add_column("Active Key", style="green", header_style="bold bright_white")
|
|
398
|
+
keys_table.add_column("Provider", style="white", header_style="bold bright_white")
|
|
399
|
+
keys_table.add_column("Env", justify="center", header_style="bold bright_white")
|
|
400
|
+
keys_table.add_column("Config", justify="center", header_style="bold bright_white")
|
|
401
|
+
keys_table.add_column("Active Key", style="green", header_style="bold bright_white")
|
|
376
402
|
|
|
377
403
|
def format_provider_row(provider, status):
|
|
378
404
|
"""Format a single provider's status for display."""
|
|
@@ -410,7 +436,7 @@ def show_check_summary() -> None:
|
|
|
410
436
|
active = "[dim]Not configured[/dim]"
|
|
411
437
|
|
|
412
438
|
# Get the proper display name for the provider
|
|
413
|
-
from
|
|
439
|
+
from fast_agent.llm.provider_types import Provider
|
|
414
440
|
|
|
415
441
|
provider_enum = Provider(provider)
|
|
416
442
|
display_name = provider_enum.display_name
|
|
@@ -436,18 +462,18 @@ def show_check_summary() -> None:
|
|
|
436
462
|
# Add row with only left column (right column empty)
|
|
437
463
|
keys_table.add_row(*left_data, "", "", "", "")
|
|
438
464
|
|
|
439
|
-
#
|
|
440
|
-
|
|
441
|
-
console.print(
|
|
465
|
+
# API Keys section
|
|
466
|
+
_print_section_header("API Keys", color="blue")
|
|
467
|
+
console.print(keys_table)
|
|
442
468
|
|
|
443
469
|
# MCP Servers panel (shown after API Keys)
|
|
444
470
|
if config_summary.get("status") == "parsed":
|
|
445
471
|
mcp_servers = config_summary.get("mcp_servers", [])
|
|
446
472
|
if mcp_servers:
|
|
447
473
|
servers_table = Table(show_header=True, box=None)
|
|
448
|
-
servers_table.add_column("Name", style="
|
|
449
|
-
servers_table.add_column("Transport", style="
|
|
450
|
-
servers_table.add_column("Command/URL")
|
|
474
|
+
servers_table.add_column("Name", style="white", header_style="bold bright_white")
|
|
475
|
+
servers_table.add_column("Transport", style="white", header_style="bold bright_white")
|
|
476
|
+
servers_table.add_column("Command/URL", header_style="bold bright_white")
|
|
451
477
|
|
|
452
478
|
for server in mcp_servers:
|
|
453
479
|
name = server["name"]
|
|
@@ -456,14 +482,17 @@ def show_check_summary() -> None:
|
|
|
456
482
|
# Show either command or URL based on transport type
|
|
457
483
|
if transport == "STDIO":
|
|
458
484
|
command_url = server["command"] or "[dim]Not configured[/dim]"
|
|
459
|
-
servers_table.add_row(name, transport, command_url)
|
|
460
485
|
else: # SSE
|
|
461
486
|
command_url = server["url"] or "[dim]Not configured[/dim]"
|
|
462
|
-
servers_table.add_row(name, transport, command_url)
|
|
463
487
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
488
|
+
# Style configured command/url in green (keep "Not configured" dim)
|
|
489
|
+
if "Not configured" not in command_url:
|
|
490
|
+
command_url = f"[green]{command_url}[/green]"
|
|
491
|
+
|
|
492
|
+
servers_table.add_row(name, transport, command_url)
|
|
493
|
+
|
|
494
|
+
_print_section_header("MCP Servers", color="blue")
|
|
495
|
+
console.print(servers_table)
|
|
467
496
|
|
|
468
497
|
# Show help tips
|
|
469
498
|
if config_status == "not_found" or secrets_status == "not_found":
|
|
@@ -7,10 +7,11 @@ from typing import Dict, List, Optional
|
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
10
|
+
from fast_agent.agents.llm_agent import LlmAgent
|
|
11
|
+
from fast_agent.cli.commands.server_helpers import add_servers_to_config, generate_server_name
|
|
12
|
+
from fast_agent.cli.commands.url_parser import generate_server_configs, parse_server_urls
|
|
13
|
+
from fast_agent.core.fastagent import FastAgent
|
|
14
|
+
from fast_agent.ui.console_display import ConsoleDisplay
|
|
14
15
|
|
|
15
16
|
app = typer.Typer(
|
|
16
17
|
help="Run an interactive agent directly from the command line without creating an agent.py file",
|
|
@@ -33,7 +34,7 @@ async def _run_agent(
|
|
|
33
34
|
"""Async implementation to run an interactive agent."""
|
|
34
35
|
from pathlib import Path
|
|
35
36
|
|
|
36
|
-
from
|
|
37
|
+
from fast_agent.mcp.prompts.prompt_load import load_prompt_multipart
|
|
37
38
|
|
|
38
39
|
# Create the FastAgent instance
|
|
39
40
|
|
|
@@ -72,13 +73,21 @@ async def _run_agent(
|
|
|
72
73
|
|
|
73
74
|
fan_out_agents.append(agent_name)
|
|
74
75
|
|
|
75
|
-
# Create a silent fan-in agent
|
|
76
|
-
|
|
76
|
+
# Create a silent fan-in agent (suppresses display output)
|
|
77
|
+
class SilentFanInAgent(LlmAgent):
|
|
78
|
+
async def show_assistant_message(self, *args, **kwargs): # type: ignore[override]
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
def show_user_message(self, *args, **kwargs): # type: ignore[override]
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
@fast.custom(
|
|
85
|
+
SilentFanInAgent,
|
|
77
86
|
name="aggregate",
|
|
78
|
-
model="
|
|
79
|
-
instruction="You
|
|
87
|
+
model="passthrough",
|
|
88
|
+
instruction="You aggregate parallel outputs without displaying intermediate messages.",
|
|
80
89
|
)
|
|
81
|
-
async def
|
|
90
|
+
async def aggregate():
|
|
82
91
|
pass
|
|
83
92
|
|
|
84
93
|
# Create a parallel agent with silent fan_in
|
|
@@ -352,7 +361,7 @@ def go(
|
|
|
352
361
|
|
|
353
362
|
from pydantic import AnyUrl
|
|
354
363
|
|
|
355
|
-
from
|
|
364
|
+
from fast_agent.core.direct_decorators import _resolve_instruction
|
|
356
365
|
|
|
357
366
|
# Check if it's a URL
|
|
358
367
|
if instruction.startswith(("http://", "https://")):
|
|
@@ -126,7 +126,7 @@ def copy_example_files(example_type: str, target_dir: Path, force: bool = False)
|
|
|
126
126
|
if example_type == "state-transfer":
|
|
127
127
|
# The state-transfer example is in the mcp subdirectory
|
|
128
128
|
source_dir = (
|
|
129
|
-
files("
|
|
129
|
+
files("fast_agent")
|
|
130
130
|
.joinpath("resources")
|
|
131
131
|
.joinpath("examples")
|
|
132
132
|
.joinpath("mcp")
|
|
@@ -135,7 +135,7 @@ def copy_example_files(example_type: str, target_dir: Path, force: bool = False)
|
|
|
135
135
|
elif example_type == "elicitations":
|
|
136
136
|
# The elicitations example is in the mcp subdirectory
|
|
137
137
|
source_dir = (
|
|
138
|
-
files("
|
|
138
|
+
files("fast_agent")
|
|
139
139
|
.joinpath("resources")
|
|
140
140
|
.joinpath("examples")
|
|
141
141
|
.joinpath("mcp")
|
|
@@ -144,7 +144,7 @@ def copy_example_files(example_type: str, target_dir: Path, force: bool = False)
|
|
|
144
144
|
else:
|
|
145
145
|
# Other examples are at the top level of examples
|
|
146
146
|
source_dir = (
|
|
147
|
-
files("
|
|
147
|
+
files("fast_agent")
|
|
148
148
|
.joinpath("resources")
|
|
149
149
|
.joinpath("examples")
|
|
150
150
|
.joinpath("workflows" if example_type == "workflow" else f"{example_type}")
|
|
@@ -454,7 +454,7 @@ def tensorzero(
|
|
|
454
454
|
from importlib.resources import files
|
|
455
455
|
try:
|
|
456
456
|
# This path MUST match the "to" path from hatch_build.py
|
|
457
|
-
source_dir = files("
|
|
457
|
+
source_dir = files("fast_agent").joinpath("resources").joinpath("examples").joinpath("tensorzero")
|
|
458
458
|
if not source_dir.is_dir():
|
|
459
459
|
raise FileNotFoundError # Fallback to dev mode if resource isn't a dir
|
|
460
460
|
except (ImportError, ModuleNotFoundError, FileNotFoundError):
|
|
@@ -73,7 +73,7 @@ async def add_servers_to_config(fast_app: Any, servers: Dict[str, Dict[str, Any]
|
|
|
73
73
|
if not servers:
|
|
74
74
|
return
|
|
75
75
|
|
|
76
|
-
from
|
|
76
|
+
from fast_agent.config import MCPServerSettings, MCPSettings
|
|
77
77
|
|
|
78
78
|
# Initialize the app to ensure context is ready
|
|
79
79
|
await fast_app.app.initialize()
|