fast-agent-mcp 0.4.7__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/__init__.py +183 -0
- fast_agent/acp/__init__.py +19 -0
- fast_agent/acp/acp_aware_mixin.py +304 -0
- fast_agent/acp/acp_context.py +437 -0
- fast_agent/acp/content_conversion.py +136 -0
- fast_agent/acp/filesystem_runtime.py +427 -0
- fast_agent/acp/permission_store.py +269 -0
- fast_agent/acp/server/__init__.py +5 -0
- fast_agent/acp/server/agent_acp_server.py +1472 -0
- fast_agent/acp/slash_commands.py +1050 -0
- fast_agent/acp/terminal_runtime.py +408 -0
- fast_agent/acp/tool_permission_adapter.py +125 -0
- fast_agent/acp/tool_permissions.py +474 -0
- fast_agent/acp/tool_progress.py +814 -0
- fast_agent/agents/__init__.py +85 -0
- fast_agent/agents/agent_types.py +64 -0
- fast_agent/agents/llm_agent.py +350 -0
- fast_agent/agents/llm_decorator.py +1139 -0
- fast_agent/agents/mcp_agent.py +1337 -0
- fast_agent/agents/tool_agent.py +271 -0
- fast_agent/agents/workflow/agents_as_tools_agent.py +849 -0
- fast_agent/agents/workflow/chain_agent.py +212 -0
- fast_agent/agents/workflow/evaluator_optimizer.py +380 -0
- fast_agent/agents/workflow/iterative_planner.py +652 -0
- fast_agent/agents/workflow/maker_agent.py +379 -0
- fast_agent/agents/workflow/orchestrator_models.py +218 -0
- fast_agent/agents/workflow/orchestrator_prompts.py +248 -0
- fast_agent/agents/workflow/parallel_agent.py +250 -0
- fast_agent/agents/workflow/router_agent.py +353 -0
- fast_agent/cli/__init__.py +0 -0
- fast_agent/cli/__main__.py +73 -0
- fast_agent/cli/commands/acp.py +159 -0
- fast_agent/cli/commands/auth.py +404 -0
- fast_agent/cli/commands/check_config.py +783 -0
- fast_agent/cli/commands/go.py +514 -0
- fast_agent/cli/commands/quickstart.py +557 -0
- fast_agent/cli/commands/serve.py +143 -0
- fast_agent/cli/commands/server_helpers.py +114 -0
- fast_agent/cli/commands/setup.py +174 -0
- fast_agent/cli/commands/url_parser.py +190 -0
- fast_agent/cli/constants.py +40 -0
- fast_agent/cli/main.py +115 -0
- fast_agent/cli/terminal.py +24 -0
- fast_agent/config.py +798 -0
- fast_agent/constants.py +41 -0
- fast_agent/context.py +279 -0
- fast_agent/context_dependent.py +50 -0
- fast_agent/core/__init__.py +92 -0
- fast_agent/core/agent_app.py +448 -0
- fast_agent/core/core_app.py +137 -0
- fast_agent/core/direct_decorators.py +784 -0
- fast_agent/core/direct_factory.py +620 -0
- fast_agent/core/error_handling.py +27 -0
- fast_agent/core/exceptions.py +90 -0
- fast_agent/core/executor/__init__.py +0 -0
- fast_agent/core/executor/executor.py +280 -0
- fast_agent/core/executor/task_registry.py +32 -0
- fast_agent/core/executor/workflow_signal.py +324 -0
- fast_agent/core/fastagent.py +1186 -0
- fast_agent/core/logging/__init__.py +5 -0
- fast_agent/core/logging/events.py +138 -0
- fast_agent/core/logging/json_serializer.py +164 -0
- fast_agent/core/logging/listeners.py +309 -0
- fast_agent/core/logging/logger.py +278 -0
- fast_agent/core/logging/transport.py +481 -0
- fast_agent/core/prompt.py +9 -0
- fast_agent/core/prompt_templates.py +183 -0
- fast_agent/core/validation.py +326 -0
- fast_agent/event_progress.py +62 -0
- fast_agent/history/history_exporter.py +49 -0
- fast_agent/human_input/__init__.py +47 -0
- fast_agent/human_input/elicitation_handler.py +123 -0
- fast_agent/human_input/elicitation_state.py +33 -0
- fast_agent/human_input/form_elements.py +59 -0
- fast_agent/human_input/form_fields.py +256 -0
- fast_agent/human_input/simple_form.py +113 -0
- fast_agent/human_input/types.py +40 -0
- fast_agent/interfaces.py +310 -0
- fast_agent/llm/__init__.py +9 -0
- fast_agent/llm/cancellation.py +22 -0
- fast_agent/llm/fastagent_llm.py +931 -0
- fast_agent/llm/internal/passthrough.py +161 -0
- fast_agent/llm/internal/playback.py +129 -0
- fast_agent/llm/internal/silent.py +41 -0
- fast_agent/llm/internal/slow.py +38 -0
- fast_agent/llm/memory.py +275 -0
- fast_agent/llm/model_database.py +490 -0
- fast_agent/llm/model_factory.py +388 -0
- fast_agent/llm/model_info.py +102 -0
- fast_agent/llm/prompt_utils.py +155 -0
- fast_agent/llm/provider/anthropic/anthropic_utils.py +84 -0
- fast_agent/llm/provider/anthropic/cache_planner.py +56 -0
- fast_agent/llm/provider/anthropic/llm_anthropic.py +796 -0
- fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py +462 -0
- fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
- fast_agent/llm/provider/bedrock/llm_bedrock.py +2207 -0
- fast_agent/llm/provider/bedrock/multipart_converter_bedrock.py +84 -0
- fast_agent/llm/provider/google/google_converter.py +466 -0
- fast_agent/llm/provider/google/llm_google_native.py +681 -0
- fast_agent/llm/provider/openai/llm_aliyun.py +31 -0
- fast_agent/llm/provider/openai/llm_azure.py +143 -0
- fast_agent/llm/provider/openai/llm_deepseek.py +76 -0
- fast_agent/llm/provider/openai/llm_generic.py +35 -0
- fast_agent/llm/provider/openai/llm_google_oai.py +32 -0
- fast_agent/llm/provider/openai/llm_groq.py +42 -0
- fast_agent/llm/provider/openai/llm_huggingface.py +85 -0
- fast_agent/llm/provider/openai/llm_openai.py +1195 -0
- fast_agent/llm/provider/openai/llm_openai_compatible.py +138 -0
- fast_agent/llm/provider/openai/llm_openrouter.py +45 -0
- fast_agent/llm/provider/openai/llm_tensorzero_openai.py +128 -0
- fast_agent/llm/provider/openai/llm_xai.py +38 -0
- fast_agent/llm/provider/openai/multipart_converter_openai.py +561 -0
- fast_agent/llm/provider/openai/openai_multipart.py +169 -0
- fast_agent/llm/provider/openai/openai_utils.py +67 -0
- fast_agent/llm/provider/openai/responses.py +133 -0
- fast_agent/llm/provider_key_manager.py +139 -0
- fast_agent/llm/provider_types.py +34 -0
- fast_agent/llm/request_params.py +61 -0
- fast_agent/llm/sampling_converter.py +98 -0
- fast_agent/llm/stream_types.py +9 -0
- fast_agent/llm/usage_tracking.py +445 -0
- fast_agent/mcp/__init__.py +56 -0
- fast_agent/mcp/common.py +26 -0
- fast_agent/mcp/elicitation_factory.py +84 -0
- fast_agent/mcp/elicitation_handlers.py +164 -0
- fast_agent/mcp/gen_client.py +83 -0
- fast_agent/mcp/helpers/__init__.py +36 -0
- fast_agent/mcp/helpers/content_helpers.py +352 -0
- fast_agent/mcp/helpers/server_config_helpers.py +25 -0
- fast_agent/mcp/hf_auth.py +147 -0
- fast_agent/mcp/interfaces.py +92 -0
- fast_agent/mcp/logger_textio.py +108 -0
- fast_agent/mcp/mcp_agent_client_session.py +411 -0
- fast_agent/mcp/mcp_aggregator.py +2175 -0
- fast_agent/mcp/mcp_connection_manager.py +723 -0
- fast_agent/mcp/mcp_content.py +262 -0
- fast_agent/mcp/mime_utils.py +108 -0
- fast_agent/mcp/oauth_client.py +509 -0
- fast_agent/mcp/prompt.py +159 -0
- fast_agent/mcp/prompt_message_extended.py +155 -0
- fast_agent/mcp/prompt_render.py +84 -0
- fast_agent/mcp/prompt_serialization.py +580 -0
- fast_agent/mcp/prompts/__init__.py +0 -0
- fast_agent/mcp/prompts/__main__.py +7 -0
- fast_agent/mcp/prompts/prompt_constants.py +18 -0
- fast_agent/mcp/prompts/prompt_helpers.py +238 -0
- fast_agent/mcp/prompts/prompt_load.py +186 -0
- fast_agent/mcp/prompts/prompt_server.py +552 -0
- fast_agent/mcp/prompts/prompt_template.py +438 -0
- fast_agent/mcp/resource_utils.py +215 -0
- fast_agent/mcp/sampling.py +200 -0
- fast_agent/mcp/server/__init__.py +4 -0
- fast_agent/mcp/server/agent_server.py +613 -0
- fast_agent/mcp/skybridge.py +44 -0
- fast_agent/mcp/sse_tracking.py +287 -0
- fast_agent/mcp/stdio_tracking_simple.py +59 -0
- fast_agent/mcp/streamable_http_tracking.py +309 -0
- fast_agent/mcp/tool_execution_handler.py +137 -0
- fast_agent/mcp/tool_permission_handler.py +88 -0
- fast_agent/mcp/transport_tracking.py +634 -0
- fast_agent/mcp/types.py +24 -0
- fast_agent/mcp/ui_agent.py +48 -0
- fast_agent/mcp/ui_mixin.py +209 -0
- fast_agent/mcp_server_registry.py +89 -0
- fast_agent/py.typed +0 -0
- fast_agent/resources/examples/data-analysis/analysis-campaign.py +189 -0
- fast_agent/resources/examples/data-analysis/analysis.py +68 -0
- fast_agent/resources/examples/data-analysis/fastagent.config.yaml +41 -0
- fast_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_account_server.py +88 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_forms_server.py +297 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_game_server.py +164 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.config.yaml +35 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +17 -0
- fast_agent/resources/examples/mcp/elicitations/forms_demo.py +107 -0
- fast_agent/resources/examples/mcp/elicitations/game_character.py +65 -0
- fast_agent/resources/examples/mcp/elicitations/game_character_handler.py +256 -0
- fast_agent/resources/examples/mcp/elicitations/tool_call.py +21 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +15 -0
- fast_agent/resources/examples/researcher/fastagent.config.yaml +61 -0
- fast_agent/resources/examples/researcher/researcher-eval.py +53 -0
- fast_agent/resources/examples/researcher/researcher-imp.py +189 -0
- fast_agent/resources/examples/researcher/researcher.py +36 -0
- fast_agent/resources/examples/tensorzero/.env.sample +2 -0
- fast_agent/resources/examples/tensorzero/Makefile +31 -0
- fast_agent/resources/examples/tensorzero/README.md +56 -0
- fast_agent/resources/examples/tensorzero/agent.py +35 -0
- fast_agent/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/crab.png +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
- fast_agent/resources/examples/tensorzero/docker-compose.yml +105 -0
- fast_agent/resources/examples/tensorzero/fastagent.config.yaml +19 -0
- fast_agent/resources/examples/tensorzero/image_demo.py +67 -0
- fast_agent/resources/examples/tensorzero/mcp_server/Dockerfile +25 -0
- fast_agent/resources/examples/tensorzero/mcp_server/entrypoint.sh +35 -0
- fast_agent/resources/examples/tensorzero/mcp_server/mcp_server.py +31 -0
- fast_agent/resources/examples/tensorzero/mcp_server/pyproject.toml +11 -0
- fast_agent/resources/examples/tensorzero/simple_agent.py +25 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_schema.json +29 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +11 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +35 -0
- fast_agent/resources/examples/workflows/agents_as_tools_extended.py +73 -0
- fast_agent/resources/examples/workflows/agents_as_tools_simple.py +50 -0
- fast_agent/resources/examples/workflows/chaining.py +37 -0
- fast_agent/resources/examples/workflows/evaluator.py +77 -0
- fast_agent/resources/examples/workflows/fastagent.config.yaml +26 -0
- fast_agent/resources/examples/workflows/graded_report.md +89 -0
- fast_agent/resources/examples/workflows/human_input.py +28 -0
- fast_agent/resources/examples/workflows/maker.py +156 -0
- fast_agent/resources/examples/workflows/orchestrator.py +70 -0
- fast_agent/resources/examples/workflows/parallel.py +56 -0
- fast_agent/resources/examples/workflows/router.py +69 -0
- fast_agent/resources/examples/workflows/short_story.md +13 -0
- fast_agent/resources/examples/workflows/short_story.txt +19 -0
- fast_agent/resources/setup/.gitignore +30 -0
- fast_agent/resources/setup/agent.py +28 -0
- fast_agent/resources/setup/fastagent.config.yaml +65 -0
- fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
- fast_agent/resources/setup/pyproject.toml.tmpl +23 -0
- fast_agent/skills/__init__.py +9 -0
- fast_agent/skills/registry.py +235 -0
- fast_agent/tools/elicitation.py +369 -0
- fast_agent/tools/shell_runtime.py +402 -0
- fast_agent/types/__init__.py +59 -0
- fast_agent/types/conversation_summary.py +294 -0
- fast_agent/types/llm_stop_reason.py +78 -0
- fast_agent/types/message_search.py +249 -0
- fast_agent/ui/__init__.py +38 -0
- fast_agent/ui/console.py +59 -0
- fast_agent/ui/console_display.py +1080 -0
- fast_agent/ui/elicitation_form.py +946 -0
- fast_agent/ui/elicitation_style.py +59 -0
- fast_agent/ui/enhanced_prompt.py +1400 -0
- fast_agent/ui/history_display.py +734 -0
- fast_agent/ui/interactive_prompt.py +1199 -0
- fast_agent/ui/markdown_helpers.py +104 -0
- fast_agent/ui/markdown_truncator.py +1004 -0
- fast_agent/ui/mcp_display.py +857 -0
- fast_agent/ui/mcp_ui_utils.py +235 -0
- fast_agent/ui/mermaid_utils.py +169 -0
- fast_agent/ui/message_primitives.py +50 -0
- fast_agent/ui/notification_tracker.py +205 -0
- fast_agent/ui/plain_text_truncator.py +68 -0
- fast_agent/ui/progress_display.py +10 -0
- fast_agent/ui/rich_progress.py +195 -0
- fast_agent/ui/streaming.py +774 -0
- fast_agent/ui/streaming_buffer.py +449 -0
- fast_agent/ui/tool_display.py +422 -0
- fast_agent/ui/usage_display.py +204 -0
- fast_agent/utils/__init__.py +5 -0
- fast_agent/utils/reasoning_stream_parser.py +77 -0
- fast_agent/utils/time.py +22 -0
- fast_agent/workflow_telemetry.py +261 -0
- fast_agent_mcp-0.4.7.dist-info/METADATA +788 -0
- fast_agent_mcp-0.4.7.dist-info/RECORD +261 -0
- fast_agent_mcp-0.4.7.dist-info/WHEEL +4 -0
- fast_agent_mcp-0.4.7.dist-info/entry_points.txt +7 -0
- fast_agent_mcp-0.4.7.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Direct factory functions for creating agent and workflow instances without proxies.
|
|
3
|
+
Implements type-safe factories with improved error handling.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from functools import partial
|
|
8
|
+
from typing import Any, Protocol, TypeVar
|
|
9
|
+
|
|
10
|
+
from fast_agent.agents import McpAgent
|
|
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.evaluator_optimizer import (
|
|
14
|
+
EvaluatorOptimizerAgent,
|
|
15
|
+
QualityRating,
|
|
16
|
+
)
|
|
17
|
+
from fast_agent.agents.workflow.iterative_planner import IterativePlanner
|
|
18
|
+
from fast_agent.agents.workflow.parallel_agent import ParallelAgent
|
|
19
|
+
from fast_agent.agents.workflow.router_agent import RouterAgent
|
|
20
|
+
from fast_agent.core import Core
|
|
21
|
+
from fast_agent.core.exceptions import AgentConfigError
|
|
22
|
+
from fast_agent.core.logging.logger import get_logger
|
|
23
|
+
from fast_agent.core.validation import get_dependencies_groups
|
|
24
|
+
from fast_agent.event_progress import ProgressAction
|
|
25
|
+
from fast_agent.interfaces import (
|
|
26
|
+
AgentProtocol,
|
|
27
|
+
LLMFactoryProtocol,
|
|
28
|
+
ModelFactoryFunctionProtocol,
|
|
29
|
+
)
|
|
30
|
+
from fast_agent.llm.model_factory import ModelFactory
|
|
31
|
+
from fast_agent.mcp.ui_agent import McpAgentWithUI
|
|
32
|
+
from fast_agent.types import RequestParams
|
|
33
|
+
|
|
34
|
+
# Type aliases for improved readability and IDE support
|
|
35
|
+
AgentDict = dict[str, AgentProtocol]
|
|
36
|
+
AgentConfigDict = dict[str, dict[str, Any]]
|
|
37
|
+
T = TypeVar("T") # For generic types
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
logger = get_logger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _create_agent_with_ui_if_needed(
|
|
44
|
+
agent_class: type,
|
|
45
|
+
config: Any,
|
|
46
|
+
context: Any,
|
|
47
|
+
) -> Any:
|
|
48
|
+
"""
|
|
49
|
+
Create an agent with UI support if MCP UI mode is enabled.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
agent_class: The agent class to potentially enhance with UI
|
|
53
|
+
config: Agent configuration
|
|
54
|
+
context: Application context
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Either a UI-enhanced agent instance or the original agent instance
|
|
58
|
+
"""
|
|
59
|
+
# Check UI mode from settings
|
|
60
|
+
settings = context.config if hasattr(context, "config") else None
|
|
61
|
+
ui_mode = getattr(settings, "mcp_ui_mode", "auto") if settings else "auto"
|
|
62
|
+
|
|
63
|
+
if ui_mode != "disabled" and agent_class == McpAgent:
|
|
64
|
+
# Use the UI-enhanced agent class instead of the base class
|
|
65
|
+
return McpAgentWithUI(config=config, context=context, ui_mode=ui_mode)
|
|
66
|
+
else:
|
|
67
|
+
# Create the original agent instance
|
|
68
|
+
return agent_class(config=config, context=context)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AgentCreatorProtocol(Protocol):
|
|
72
|
+
"""Protocol for agent creator functions."""
|
|
73
|
+
|
|
74
|
+
async def __call__(
|
|
75
|
+
self,
|
|
76
|
+
app_instance: Core,
|
|
77
|
+
agents_dict: AgentConfigDict,
|
|
78
|
+
agent_type: AgentType,
|
|
79
|
+
active_agents: AgentDict | None = None,
|
|
80
|
+
model_factory_func: ModelFactoryFunctionProtocol | None = None,
|
|
81
|
+
**kwargs: Any,
|
|
82
|
+
) -> AgentDict: ...
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
HARDCODED_DEFAULT_MODEL = "gpt-5-mini.low"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_model_factory(
|
|
89
|
+
context,
|
|
90
|
+
model: str | None = None,
|
|
91
|
+
request_params: RequestParams | None = None,
|
|
92
|
+
default_model: str | None = None,
|
|
93
|
+
cli_model: str | None = None,
|
|
94
|
+
) -> LLMFactoryProtocol:
|
|
95
|
+
"""
|
|
96
|
+
Get model factory using specified or default model.
|
|
97
|
+
Model string is parsed by ModelFactory to determine provider and reasoning effort.
|
|
98
|
+
|
|
99
|
+
Precedence (lowest to highest):
|
|
100
|
+
1. Hardcoded default (gpt-5-mini.low)
|
|
101
|
+
2. FAST_AGENT_MODEL environment variable
|
|
102
|
+
3. Config file default_model
|
|
103
|
+
4. CLI --model argument
|
|
104
|
+
5. Decorator model parameter
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
context: Application context
|
|
108
|
+
model: Optional model specification string (highest precedence)
|
|
109
|
+
request_params: Optional RequestParams to configure LLM behavior
|
|
110
|
+
default_model: Default model from configuration
|
|
111
|
+
cli_model: Model specified via command line
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
ModelFactory instance for the specified or default model
|
|
115
|
+
"""
|
|
116
|
+
# Hardcoded default has lowest precedence
|
|
117
|
+
model_spec = HARDCODED_DEFAULT_MODEL
|
|
118
|
+
|
|
119
|
+
# Environment variable has next precedence
|
|
120
|
+
env_model = os.getenv("FAST_AGENT_MODEL")
|
|
121
|
+
if env_model:
|
|
122
|
+
model_spec = env_model
|
|
123
|
+
|
|
124
|
+
# Config has next precedence
|
|
125
|
+
if default_model or context.config.default_model:
|
|
126
|
+
model_spec = default_model or context.config.default_model
|
|
127
|
+
|
|
128
|
+
# Command line override has next precedence
|
|
129
|
+
if cli_model:
|
|
130
|
+
model_spec = cli_model
|
|
131
|
+
|
|
132
|
+
# Model from decorator has highest precedence
|
|
133
|
+
if model:
|
|
134
|
+
model_spec = model
|
|
135
|
+
|
|
136
|
+
# Update or create request_params with the final model choice
|
|
137
|
+
if request_params:
|
|
138
|
+
request_params = request_params.model_copy(update={"model": model_spec})
|
|
139
|
+
else:
|
|
140
|
+
request_params = RequestParams(model=model_spec)
|
|
141
|
+
|
|
142
|
+
# Let model factory handle the model string parsing and setup
|
|
143
|
+
return ModelFactory.create_factory(model_spec)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_default_model_source(
|
|
147
|
+
config_default_model: str | None = None,
|
|
148
|
+
cli_model: str | None = None,
|
|
149
|
+
) -> str | None:
|
|
150
|
+
"""
|
|
151
|
+
Determine the source of the default model selection.
|
|
152
|
+
Returns "environment variable", "config file", or None (if CLI or hardcoded default).
|
|
153
|
+
|
|
154
|
+
This is used to display informational messages about where the model
|
|
155
|
+
configuration is coming from. Only shows a message for env var or config file,
|
|
156
|
+
not for explicit CLI usage or the hardcoded system default.
|
|
157
|
+
"""
|
|
158
|
+
# CLI model is explicit - no message needed
|
|
159
|
+
if cli_model:
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
# Check if config file has a default model
|
|
163
|
+
if config_default_model:
|
|
164
|
+
return "config file"
|
|
165
|
+
|
|
166
|
+
# Check if environment variable is set
|
|
167
|
+
if os.getenv("FAST_AGENT_MODEL"):
|
|
168
|
+
return "environment variable"
|
|
169
|
+
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
async def create_agents_by_type(
|
|
174
|
+
app_instance: Core,
|
|
175
|
+
agents_dict: AgentConfigDict,
|
|
176
|
+
agent_type: AgentType,
|
|
177
|
+
model_factory_func: ModelFactoryFunctionProtocol,
|
|
178
|
+
active_agents: AgentDict | None = None,
|
|
179
|
+
**kwargs: Any,
|
|
180
|
+
) -> AgentDict:
|
|
181
|
+
"""
|
|
182
|
+
Generic method to create agents of a specific type without using proxies.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
app_instance: The main application instance
|
|
186
|
+
agents_dict: Dictionary of agent configurations
|
|
187
|
+
agent_type: Type of agents to create
|
|
188
|
+
active_agents: Dictionary of already created agents (for dependencies)
|
|
189
|
+
model_factory_func: Function for creating model factories
|
|
190
|
+
**kwargs: Additional type-specific parameters
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Dictionary of initialized agent instances
|
|
194
|
+
"""
|
|
195
|
+
if active_agents is None:
|
|
196
|
+
active_agents = {}
|
|
197
|
+
|
|
198
|
+
# Create a dictionary to store the initialized agents
|
|
199
|
+
result_agents: AgentDict = {}
|
|
200
|
+
|
|
201
|
+
# Get all agents of the specified type
|
|
202
|
+
for name, agent_data in agents_dict.items():
|
|
203
|
+
# Compare type string from config with Enum value
|
|
204
|
+
if agent_data["type"] == agent_type.value:
|
|
205
|
+
# Get common configuration
|
|
206
|
+
config = agent_data["config"]
|
|
207
|
+
|
|
208
|
+
# Type-specific initialization based on the Enum type
|
|
209
|
+
# Note: Above we compared string values from config, here we compare Enum objects directly
|
|
210
|
+
if agent_type == AgentType.BASIC:
|
|
211
|
+
# If BASIC agent declares child_agents, build an Agents-as-Tools wrapper
|
|
212
|
+
child_names = agent_data.get("child_agents", []) or []
|
|
213
|
+
if child_names:
|
|
214
|
+
# Ensure child agents are already created
|
|
215
|
+
child_agents: list[AgentProtocol] = []
|
|
216
|
+
for agent_name in child_names:
|
|
217
|
+
if agent_name not in active_agents:
|
|
218
|
+
raise AgentConfigError(f"Agent {agent_name} not found")
|
|
219
|
+
child_agents.append(active_agents[agent_name])
|
|
220
|
+
|
|
221
|
+
# Import here to avoid circulars at module import time
|
|
222
|
+
from fast_agent.agents.workflow.agents_as_tools_agent import (
|
|
223
|
+
AgentsAsToolsAgent,
|
|
224
|
+
AgentsAsToolsOptions,
|
|
225
|
+
)
|
|
226
|
+
raw_opts = agent_data.get("agents_as_tools_options") or {}
|
|
227
|
+
opt_kwargs = {k: v for k, v in raw_opts.items() if v is not None}
|
|
228
|
+
options = AgentsAsToolsOptions(**opt_kwargs)
|
|
229
|
+
|
|
230
|
+
agent = AgentsAsToolsAgent(
|
|
231
|
+
config=config,
|
|
232
|
+
context=app_instance.context,
|
|
233
|
+
agents=child_agents, # expose children as tools
|
|
234
|
+
options=options,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
await agent.initialize()
|
|
238
|
+
|
|
239
|
+
# Attach LLM to the agent
|
|
240
|
+
llm_factory = model_factory_func(model=config.model)
|
|
241
|
+
await agent.attach_llm(
|
|
242
|
+
llm_factory,
|
|
243
|
+
request_params=config.default_request_params,
|
|
244
|
+
api_key=config.api_key,
|
|
245
|
+
)
|
|
246
|
+
result_agents[name] = agent
|
|
247
|
+
|
|
248
|
+
# Log successful agent creation
|
|
249
|
+
logger.info(
|
|
250
|
+
f"Loaded {name}",
|
|
251
|
+
data={
|
|
252
|
+
"progress_action": ProgressAction.LOADED,
|
|
253
|
+
"agent_name": name,
|
|
254
|
+
"target": name,
|
|
255
|
+
},
|
|
256
|
+
)
|
|
257
|
+
else:
|
|
258
|
+
# Create agent with UI support if needed
|
|
259
|
+
agent = _create_agent_with_ui_if_needed(
|
|
260
|
+
McpAgent,
|
|
261
|
+
config,
|
|
262
|
+
app_instance.context,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
await agent.initialize()
|
|
266
|
+
|
|
267
|
+
# Attach LLM to the agent
|
|
268
|
+
llm_factory = model_factory_func(model=config.model)
|
|
269
|
+
await agent.attach_llm(
|
|
270
|
+
llm_factory,
|
|
271
|
+
request_params=config.default_request_params,
|
|
272
|
+
api_key=config.api_key,
|
|
273
|
+
)
|
|
274
|
+
result_agents[name] = agent
|
|
275
|
+
|
|
276
|
+
# Log successful agent creation
|
|
277
|
+
logger.info(
|
|
278
|
+
f"Loaded {name}",
|
|
279
|
+
data={
|
|
280
|
+
"progress_action": ProgressAction.LOADED,
|
|
281
|
+
"agent_name": name,
|
|
282
|
+
"target": name,
|
|
283
|
+
},
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
elif agent_type == AgentType.CUSTOM:
|
|
287
|
+
# Get the class to instantiate (support legacy 'agent_class' and new 'cls')
|
|
288
|
+
cls = agent_data.get("agent_class") or agent_data.get("cls")
|
|
289
|
+
if cls is None:
|
|
290
|
+
raise AgentConfigError(
|
|
291
|
+
f"Custom agent '{name}' missing class reference ('agent_class' or 'cls')"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Create agent with UI support if needed
|
|
295
|
+
agent = _create_agent_with_ui_if_needed(
|
|
296
|
+
cls,
|
|
297
|
+
config,
|
|
298
|
+
app_instance.context,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
await agent.initialize()
|
|
302
|
+
# Attach LLM to the agent
|
|
303
|
+
llm_factory = model_factory_func(model=config.model)
|
|
304
|
+
await agent.attach_llm(
|
|
305
|
+
llm_factory,
|
|
306
|
+
request_params=config.default_request_params,
|
|
307
|
+
api_key=config.api_key,
|
|
308
|
+
)
|
|
309
|
+
result_agents[name] = agent
|
|
310
|
+
|
|
311
|
+
# Log successful agent creation
|
|
312
|
+
logger.info(
|
|
313
|
+
f"Loaded {name}",
|
|
314
|
+
data={
|
|
315
|
+
"progress_action": ProgressAction.LOADED,
|
|
316
|
+
"agent_name": name,
|
|
317
|
+
"target": name,
|
|
318
|
+
},
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
elif agent_type == AgentType.ORCHESTRATOR or agent_type == AgentType.ITERATIVE_PLANNER:
|
|
322
|
+
# Get base params configured with model settings
|
|
323
|
+
base_params = (
|
|
324
|
+
config.default_request_params.model_copy()
|
|
325
|
+
if config.default_request_params
|
|
326
|
+
else RequestParams()
|
|
327
|
+
)
|
|
328
|
+
base_params.use_history = False # Force no history for orchestrator
|
|
329
|
+
|
|
330
|
+
# Get the child agents
|
|
331
|
+
child_agents = []
|
|
332
|
+
for agent_name in agent_data["child_agents"]:
|
|
333
|
+
if agent_name not in active_agents:
|
|
334
|
+
raise AgentConfigError(f"Agent {agent_name} not found")
|
|
335
|
+
agent = active_agents[agent_name]
|
|
336
|
+
child_agents.append(agent)
|
|
337
|
+
|
|
338
|
+
orchestrator = IterativePlanner(
|
|
339
|
+
config=config,
|
|
340
|
+
context=app_instance.context,
|
|
341
|
+
agents=child_agents,
|
|
342
|
+
plan_iterations=agent_data.get("plan_iterations", 5),
|
|
343
|
+
plan_type=agent_data.get("plan_type", "full"),
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
# Initialize the orchestrator
|
|
347
|
+
await orchestrator.initialize()
|
|
348
|
+
|
|
349
|
+
# Attach LLM to the orchestrator
|
|
350
|
+
llm_factory = model_factory_func(model=config.model)
|
|
351
|
+
|
|
352
|
+
await orchestrator.attach_llm(
|
|
353
|
+
llm_factory,
|
|
354
|
+
request_params=config.default_request_params,
|
|
355
|
+
api_key=config.api_key,
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
result_agents[name] = orchestrator
|
|
359
|
+
|
|
360
|
+
elif agent_type == AgentType.PARALLEL:
|
|
361
|
+
# Get the fan-out and fan-in agents
|
|
362
|
+
fan_in_name = agent_data.get("fan_in")
|
|
363
|
+
fan_out_names = agent_data["fan_out"]
|
|
364
|
+
|
|
365
|
+
# Create or retrieve the fan-in agent
|
|
366
|
+
if not fan_in_name:
|
|
367
|
+
# Create default fan-in agent with auto-generated name
|
|
368
|
+
fan_in_name = f"{name}_fan_in"
|
|
369
|
+
fan_in_agent = await _create_default_fan_in_agent(
|
|
370
|
+
fan_in_name, app_instance.context, model_factory_func
|
|
371
|
+
)
|
|
372
|
+
# Add to result_agents so it's registered properly
|
|
373
|
+
result_agents[fan_in_name] = fan_in_agent
|
|
374
|
+
elif fan_in_name not in active_agents:
|
|
375
|
+
raise AgentConfigError(f"Fan-in agent {fan_in_name} not found")
|
|
376
|
+
else:
|
|
377
|
+
fan_in_agent = active_agents[fan_in_name]
|
|
378
|
+
|
|
379
|
+
# Get the fan-out agents
|
|
380
|
+
fan_out_agents = []
|
|
381
|
+
for agent_name in fan_out_names:
|
|
382
|
+
if agent_name not in active_agents:
|
|
383
|
+
raise AgentConfigError(f"Fan-out agent {agent_name} not found")
|
|
384
|
+
fan_out_agents.append(active_agents[agent_name])
|
|
385
|
+
|
|
386
|
+
# Create the parallel agent
|
|
387
|
+
parallel = ParallelAgent(
|
|
388
|
+
config=config,
|
|
389
|
+
context=app_instance.context,
|
|
390
|
+
fan_in_agent=fan_in_agent,
|
|
391
|
+
fan_out_agents=fan_out_agents,
|
|
392
|
+
include_request=agent_data.get("include_request", True),
|
|
393
|
+
)
|
|
394
|
+
await parallel.initialize()
|
|
395
|
+
result_agents[name] = parallel
|
|
396
|
+
|
|
397
|
+
elif agent_type == AgentType.ROUTER:
|
|
398
|
+
# Get the router agents
|
|
399
|
+
router_agents = []
|
|
400
|
+
for agent_name in agent_data["router_agents"]:
|
|
401
|
+
if agent_name not in active_agents:
|
|
402
|
+
raise AgentConfigError(f"Router agent {agent_name} not found")
|
|
403
|
+
router_agents.append(active_agents[agent_name])
|
|
404
|
+
|
|
405
|
+
# Create the router agent
|
|
406
|
+
router = RouterAgent(
|
|
407
|
+
config=config,
|
|
408
|
+
context=app_instance.context,
|
|
409
|
+
agents=router_agents,
|
|
410
|
+
routing_instruction=agent_data.get("instruction"),
|
|
411
|
+
)
|
|
412
|
+
await router.initialize()
|
|
413
|
+
|
|
414
|
+
# Attach LLM to the router
|
|
415
|
+
llm_factory = model_factory_func(model=config.model)
|
|
416
|
+
await router.attach_llm(
|
|
417
|
+
llm_factory,
|
|
418
|
+
request_params=config.default_request_params,
|
|
419
|
+
api_key=config.api_key,
|
|
420
|
+
)
|
|
421
|
+
result_agents[name] = router
|
|
422
|
+
|
|
423
|
+
elif agent_type == AgentType.CHAIN:
|
|
424
|
+
# Get the chained agents
|
|
425
|
+
chain_agents = []
|
|
426
|
+
|
|
427
|
+
agent_names = agent_data["sequence"]
|
|
428
|
+
if 0 == len(agent_names):
|
|
429
|
+
raise AgentConfigError("No agents in the chain")
|
|
430
|
+
|
|
431
|
+
for agent_name in agent_data["sequence"]:
|
|
432
|
+
if agent_name not in active_agents:
|
|
433
|
+
raise AgentConfigError(f"Chain agent {agent_name} not found")
|
|
434
|
+
chain_agents.append(active_agents[agent_name])
|
|
435
|
+
|
|
436
|
+
from fast_agent.agents.workflow.chain_agent import ChainAgent
|
|
437
|
+
|
|
438
|
+
# Get the cumulative parameter
|
|
439
|
+
cumulative = agent_data.get("cumulative", False)
|
|
440
|
+
|
|
441
|
+
chain = ChainAgent(
|
|
442
|
+
config=config,
|
|
443
|
+
context=app_instance.context,
|
|
444
|
+
agents=chain_agents,
|
|
445
|
+
cumulative=cumulative,
|
|
446
|
+
)
|
|
447
|
+
await chain.initialize()
|
|
448
|
+
result_agents[name] = chain
|
|
449
|
+
|
|
450
|
+
elif agent_type == AgentType.EVALUATOR_OPTIMIZER:
|
|
451
|
+
# Get the generator and evaluator agents
|
|
452
|
+
generator_name = agent_data["generator"]
|
|
453
|
+
evaluator_name = agent_data["evaluator"]
|
|
454
|
+
|
|
455
|
+
if generator_name not in active_agents:
|
|
456
|
+
raise AgentConfigError(f"Generator agent {generator_name} not found")
|
|
457
|
+
|
|
458
|
+
if evaluator_name not in active_agents:
|
|
459
|
+
raise AgentConfigError(f"Evaluator agent {evaluator_name} not found")
|
|
460
|
+
|
|
461
|
+
generator_agent = active_agents[generator_name]
|
|
462
|
+
evaluator_agent = active_agents[evaluator_name]
|
|
463
|
+
|
|
464
|
+
# Get min_rating and max_refinements from agent_data
|
|
465
|
+
min_rating_str = agent_data.get("min_rating", "GOOD")
|
|
466
|
+
min_rating = QualityRating(min_rating_str)
|
|
467
|
+
max_refinements = agent_data.get("max_refinements", 3)
|
|
468
|
+
|
|
469
|
+
# Create the evaluator-optimizer agent
|
|
470
|
+
evaluator_optimizer = EvaluatorOptimizerAgent(
|
|
471
|
+
config=config,
|
|
472
|
+
context=app_instance.context,
|
|
473
|
+
generator_agent=generator_agent,
|
|
474
|
+
evaluator_agent=evaluator_agent,
|
|
475
|
+
min_rating=min_rating,
|
|
476
|
+
max_refinements=max_refinements,
|
|
477
|
+
refinement_instruction=agent_data.get("refinement_instruction"),
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
# Initialize the agent
|
|
481
|
+
await evaluator_optimizer.initialize()
|
|
482
|
+
result_agents[name] = evaluator_optimizer
|
|
483
|
+
|
|
484
|
+
elif agent_type == AgentType.MAKER:
|
|
485
|
+
# MAKER: Massively decomposed Agentic processes with K-voting Error Reduction
|
|
486
|
+
from fast_agent.agents.workflow.maker_agent import MakerAgent, MatchStrategy
|
|
487
|
+
|
|
488
|
+
worker_name = agent_data["worker"]
|
|
489
|
+
if worker_name not in active_agents:
|
|
490
|
+
raise AgentConfigError(f"Worker agent {worker_name} not found")
|
|
491
|
+
|
|
492
|
+
worker_agent = active_agents[worker_name]
|
|
493
|
+
|
|
494
|
+
# Parse match strategy
|
|
495
|
+
match_strategy_str = agent_data.get("match_strategy", "exact")
|
|
496
|
+
match_strategy = MatchStrategy(match_strategy_str)
|
|
497
|
+
|
|
498
|
+
# Create the MAKER agent
|
|
499
|
+
maker_agent = MakerAgent(
|
|
500
|
+
config=config,
|
|
501
|
+
context=app_instance.context,
|
|
502
|
+
worker_agent=worker_agent,
|
|
503
|
+
k=agent_data.get("k", 3),
|
|
504
|
+
max_samples=agent_data.get("max_samples", 50),
|
|
505
|
+
match_strategy=match_strategy,
|
|
506
|
+
red_flag_max_length=agent_data.get("red_flag_max_length"),
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Initialize the agent
|
|
510
|
+
await maker_agent.initialize()
|
|
511
|
+
result_agents[name] = maker_agent
|
|
512
|
+
|
|
513
|
+
else:
|
|
514
|
+
raise ValueError(f"Unknown agent type: {agent_type}")
|
|
515
|
+
|
|
516
|
+
return result_agents
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
async def active_agents_in_dependency_group(
|
|
520
|
+
app_instance: Core,
|
|
521
|
+
agents_dict: AgentConfigDict,
|
|
522
|
+
model_factory_func: ModelFactoryFunctionProtocol,
|
|
523
|
+
group: list[str],
|
|
524
|
+
active_agents: AgentDict,
|
|
525
|
+
):
|
|
526
|
+
"""
|
|
527
|
+
For each of the possible agent types, create agents and update the active agents dictionary.
|
|
528
|
+
|
|
529
|
+
Notice: This function modifies the active_agents dictionary in-place which is a feature (no copies).
|
|
530
|
+
"""
|
|
531
|
+
type_of_agents = list(map(lambda c: (c, c.value), AgentType))
|
|
532
|
+
for agent_type, agent_type_value in type_of_agents:
|
|
533
|
+
agents_dict_local = {
|
|
534
|
+
name: agents_dict[name]
|
|
535
|
+
for name in group
|
|
536
|
+
if agents_dict[name]["type"] == agent_type_value
|
|
537
|
+
}
|
|
538
|
+
agents = await create_agents_by_type(
|
|
539
|
+
app_instance,
|
|
540
|
+
agents_dict_local,
|
|
541
|
+
agent_type,
|
|
542
|
+
model_factory_func,
|
|
543
|
+
active_agents,
|
|
544
|
+
)
|
|
545
|
+
active_agents.update(agents)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
async def create_agents_in_dependency_order(
|
|
549
|
+
app_instance: Core,
|
|
550
|
+
agents_dict: AgentConfigDict,
|
|
551
|
+
model_factory_func: ModelFactoryFunctionProtocol,
|
|
552
|
+
allow_cycles: bool = False,
|
|
553
|
+
) -> AgentDict:
|
|
554
|
+
"""
|
|
555
|
+
Create agent instances in dependency order without proxies.
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
app_instance: The main application instance
|
|
559
|
+
agents_dict: Dictionary of agent configurations
|
|
560
|
+
model_factory_func: Function for creating model factories
|
|
561
|
+
allow_cycles: Whether to allow cyclic dependencies
|
|
562
|
+
|
|
563
|
+
Returns:
|
|
564
|
+
Dictionary of initialized agent instances
|
|
565
|
+
"""
|
|
566
|
+
# Get the dependencies between agents
|
|
567
|
+
dependencies = get_dependencies_groups(agents_dict, allow_cycles)
|
|
568
|
+
|
|
569
|
+
# Create a dictionary to store all active agents/workflows
|
|
570
|
+
active_agents: AgentDict = {}
|
|
571
|
+
|
|
572
|
+
active_agents_in_dependency_group_partial = partial(
|
|
573
|
+
active_agents_in_dependency_group,
|
|
574
|
+
app_instance,
|
|
575
|
+
agents_dict,
|
|
576
|
+
model_factory_func,
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Create agent proxies for each group in dependency order
|
|
580
|
+
for group in dependencies:
|
|
581
|
+
await active_agents_in_dependency_group_partial(group, active_agents)
|
|
582
|
+
|
|
583
|
+
return active_agents
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
async def _create_default_fan_in_agent(
|
|
587
|
+
fan_in_name: str,
|
|
588
|
+
context,
|
|
589
|
+
model_factory_func: ModelFactoryFunctionProtocol,
|
|
590
|
+
) -> AgentProtocol:
|
|
591
|
+
"""
|
|
592
|
+
Create a default fan-in agent for parallel workflows when none is specified.
|
|
593
|
+
|
|
594
|
+
Args:
|
|
595
|
+
fan_in_name: Name for the new fan-in agent
|
|
596
|
+
context: Application context
|
|
597
|
+
model_factory_func: Function for creating model factories
|
|
598
|
+
|
|
599
|
+
Returns:
|
|
600
|
+
Initialized Agent instance for fan-in operations
|
|
601
|
+
"""
|
|
602
|
+
# Create a simple config for the fan-in agent with passthrough model
|
|
603
|
+
default_config = AgentConfig(
|
|
604
|
+
name=fan_in_name,
|
|
605
|
+
model="passthrough",
|
|
606
|
+
instruction="You are a passthrough agent that combines outputs from parallel agents.",
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
# Create and initialize the default agent
|
|
610
|
+
fan_in_agent = LlmAgent(
|
|
611
|
+
config=default_config,
|
|
612
|
+
context=context,
|
|
613
|
+
)
|
|
614
|
+
await fan_in_agent.initialize()
|
|
615
|
+
|
|
616
|
+
# Attach LLM to the agent
|
|
617
|
+
llm_factory = model_factory_func(model="passthrough")
|
|
618
|
+
await fan_in_agent.attach_llm(llm_factory)
|
|
619
|
+
|
|
620
|
+
return fan_in_agent
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Error handling utilities for agent operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from rich import print
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def handle_error(e: Exception, error_type: str, suggestion: str | None = None) -> None:
|
|
11
|
+
"""
|
|
12
|
+
Handle errors with consistent formatting and messaging.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
e: The exception that was raised
|
|
16
|
+
error_type: Type of error to display
|
|
17
|
+
suggestion: Optional suggestion message to display
|
|
18
|
+
"""
|
|
19
|
+
print(f"\n[bold red]{error_type}:", file=sys.stderr)
|
|
20
|
+
print(getattr(e, "message", str(e)), file=sys.stderr)
|
|
21
|
+
if hasattr(e, "details") and e.details:
|
|
22
|
+
print("\nDetails:", file=sys.stderr)
|
|
23
|
+
print(e.details, file=sys.stderr)
|
|
24
|
+
if suggestion:
|
|
25
|
+
print(f"\n{suggestion}", file=sys.stderr)
|
|
26
|
+
print(file=sys.stderr)
|
|
27
|
+
print("Visit https://fast-agent.ai/ for more information", file=sys.stderr)
|