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.
Files changed (261) hide show
  1. fast_agent/__init__.py +183 -0
  2. fast_agent/acp/__init__.py +19 -0
  3. fast_agent/acp/acp_aware_mixin.py +304 -0
  4. fast_agent/acp/acp_context.py +437 -0
  5. fast_agent/acp/content_conversion.py +136 -0
  6. fast_agent/acp/filesystem_runtime.py +427 -0
  7. fast_agent/acp/permission_store.py +269 -0
  8. fast_agent/acp/server/__init__.py +5 -0
  9. fast_agent/acp/server/agent_acp_server.py +1472 -0
  10. fast_agent/acp/slash_commands.py +1050 -0
  11. fast_agent/acp/terminal_runtime.py +408 -0
  12. fast_agent/acp/tool_permission_adapter.py +125 -0
  13. fast_agent/acp/tool_permissions.py +474 -0
  14. fast_agent/acp/tool_progress.py +814 -0
  15. fast_agent/agents/__init__.py +85 -0
  16. fast_agent/agents/agent_types.py +64 -0
  17. fast_agent/agents/llm_agent.py +350 -0
  18. fast_agent/agents/llm_decorator.py +1139 -0
  19. fast_agent/agents/mcp_agent.py +1337 -0
  20. fast_agent/agents/tool_agent.py +271 -0
  21. fast_agent/agents/workflow/agents_as_tools_agent.py +849 -0
  22. fast_agent/agents/workflow/chain_agent.py +212 -0
  23. fast_agent/agents/workflow/evaluator_optimizer.py +380 -0
  24. fast_agent/agents/workflow/iterative_planner.py +652 -0
  25. fast_agent/agents/workflow/maker_agent.py +379 -0
  26. fast_agent/agents/workflow/orchestrator_models.py +218 -0
  27. fast_agent/agents/workflow/orchestrator_prompts.py +248 -0
  28. fast_agent/agents/workflow/parallel_agent.py +250 -0
  29. fast_agent/agents/workflow/router_agent.py +353 -0
  30. fast_agent/cli/__init__.py +0 -0
  31. fast_agent/cli/__main__.py +73 -0
  32. fast_agent/cli/commands/acp.py +159 -0
  33. fast_agent/cli/commands/auth.py +404 -0
  34. fast_agent/cli/commands/check_config.py +783 -0
  35. fast_agent/cli/commands/go.py +514 -0
  36. fast_agent/cli/commands/quickstart.py +557 -0
  37. fast_agent/cli/commands/serve.py +143 -0
  38. fast_agent/cli/commands/server_helpers.py +114 -0
  39. fast_agent/cli/commands/setup.py +174 -0
  40. fast_agent/cli/commands/url_parser.py +190 -0
  41. fast_agent/cli/constants.py +40 -0
  42. fast_agent/cli/main.py +115 -0
  43. fast_agent/cli/terminal.py +24 -0
  44. fast_agent/config.py +798 -0
  45. fast_agent/constants.py +41 -0
  46. fast_agent/context.py +279 -0
  47. fast_agent/context_dependent.py +50 -0
  48. fast_agent/core/__init__.py +92 -0
  49. fast_agent/core/agent_app.py +448 -0
  50. fast_agent/core/core_app.py +137 -0
  51. fast_agent/core/direct_decorators.py +784 -0
  52. fast_agent/core/direct_factory.py +620 -0
  53. fast_agent/core/error_handling.py +27 -0
  54. fast_agent/core/exceptions.py +90 -0
  55. fast_agent/core/executor/__init__.py +0 -0
  56. fast_agent/core/executor/executor.py +280 -0
  57. fast_agent/core/executor/task_registry.py +32 -0
  58. fast_agent/core/executor/workflow_signal.py +324 -0
  59. fast_agent/core/fastagent.py +1186 -0
  60. fast_agent/core/logging/__init__.py +5 -0
  61. fast_agent/core/logging/events.py +138 -0
  62. fast_agent/core/logging/json_serializer.py +164 -0
  63. fast_agent/core/logging/listeners.py +309 -0
  64. fast_agent/core/logging/logger.py +278 -0
  65. fast_agent/core/logging/transport.py +481 -0
  66. fast_agent/core/prompt.py +9 -0
  67. fast_agent/core/prompt_templates.py +183 -0
  68. fast_agent/core/validation.py +326 -0
  69. fast_agent/event_progress.py +62 -0
  70. fast_agent/history/history_exporter.py +49 -0
  71. fast_agent/human_input/__init__.py +47 -0
  72. fast_agent/human_input/elicitation_handler.py +123 -0
  73. fast_agent/human_input/elicitation_state.py +33 -0
  74. fast_agent/human_input/form_elements.py +59 -0
  75. fast_agent/human_input/form_fields.py +256 -0
  76. fast_agent/human_input/simple_form.py +113 -0
  77. fast_agent/human_input/types.py +40 -0
  78. fast_agent/interfaces.py +310 -0
  79. fast_agent/llm/__init__.py +9 -0
  80. fast_agent/llm/cancellation.py +22 -0
  81. fast_agent/llm/fastagent_llm.py +931 -0
  82. fast_agent/llm/internal/passthrough.py +161 -0
  83. fast_agent/llm/internal/playback.py +129 -0
  84. fast_agent/llm/internal/silent.py +41 -0
  85. fast_agent/llm/internal/slow.py +38 -0
  86. fast_agent/llm/memory.py +275 -0
  87. fast_agent/llm/model_database.py +490 -0
  88. fast_agent/llm/model_factory.py +388 -0
  89. fast_agent/llm/model_info.py +102 -0
  90. fast_agent/llm/prompt_utils.py +155 -0
  91. fast_agent/llm/provider/anthropic/anthropic_utils.py +84 -0
  92. fast_agent/llm/provider/anthropic/cache_planner.py +56 -0
  93. fast_agent/llm/provider/anthropic/llm_anthropic.py +796 -0
  94. fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py +462 -0
  95. fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
  96. fast_agent/llm/provider/bedrock/llm_bedrock.py +2207 -0
  97. fast_agent/llm/provider/bedrock/multipart_converter_bedrock.py +84 -0
  98. fast_agent/llm/provider/google/google_converter.py +466 -0
  99. fast_agent/llm/provider/google/llm_google_native.py +681 -0
  100. fast_agent/llm/provider/openai/llm_aliyun.py +31 -0
  101. fast_agent/llm/provider/openai/llm_azure.py +143 -0
  102. fast_agent/llm/provider/openai/llm_deepseek.py +76 -0
  103. fast_agent/llm/provider/openai/llm_generic.py +35 -0
  104. fast_agent/llm/provider/openai/llm_google_oai.py +32 -0
  105. fast_agent/llm/provider/openai/llm_groq.py +42 -0
  106. fast_agent/llm/provider/openai/llm_huggingface.py +85 -0
  107. fast_agent/llm/provider/openai/llm_openai.py +1195 -0
  108. fast_agent/llm/provider/openai/llm_openai_compatible.py +138 -0
  109. fast_agent/llm/provider/openai/llm_openrouter.py +45 -0
  110. fast_agent/llm/provider/openai/llm_tensorzero_openai.py +128 -0
  111. fast_agent/llm/provider/openai/llm_xai.py +38 -0
  112. fast_agent/llm/provider/openai/multipart_converter_openai.py +561 -0
  113. fast_agent/llm/provider/openai/openai_multipart.py +169 -0
  114. fast_agent/llm/provider/openai/openai_utils.py +67 -0
  115. fast_agent/llm/provider/openai/responses.py +133 -0
  116. fast_agent/llm/provider_key_manager.py +139 -0
  117. fast_agent/llm/provider_types.py +34 -0
  118. fast_agent/llm/request_params.py +61 -0
  119. fast_agent/llm/sampling_converter.py +98 -0
  120. fast_agent/llm/stream_types.py +9 -0
  121. fast_agent/llm/usage_tracking.py +445 -0
  122. fast_agent/mcp/__init__.py +56 -0
  123. fast_agent/mcp/common.py +26 -0
  124. fast_agent/mcp/elicitation_factory.py +84 -0
  125. fast_agent/mcp/elicitation_handlers.py +164 -0
  126. fast_agent/mcp/gen_client.py +83 -0
  127. fast_agent/mcp/helpers/__init__.py +36 -0
  128. fast_agent/mcp/helpers/content_helpers.py +352 -0
  129. fast_agent/mcp/helpers/server_config_helpers.py +25 -0
  130. fast_agent/mcp/hf_auth.py +147 -0
  131. fast_agent/mcp/interfaces.py +92 -0
  132. fast_agent/mcp/logger_textio.py +108 -0
  133. fast_agent/mcp/mcp_agent_client_session.py +411 -0
  134. fast_agent/mcp/mcp_aggregator.py +2175 -0
  135. fast_agent/mcp/mcp_connection_manager.py +723 -0
  136. fast_agent/mcp/mcp_content.py +262 -0
  137. fast_agent/mcp/mime_utils.py +108 -0
  138. fast_agent/mcp/oauth_client.py +509 -0
  139. fast_agent/mcp/prompt.py +159 -0
  140. fast_agent/mcp/prompt_message_extended.py +155 -0
  141. fast_agent/mcp/prompt_render.py +84 -0
  142. fast_agent/mcp/prompt_serialization.py +580 -0
  143. fast_agent/mcp/prompts/__init__.py +0 -0
  144. fast_agent/mcp/prompts/__main__.py +7 -0
  145. fast_agent/mcp/prompts/prompt_constants.py +18 -0
  146. fast_agent/mcp/prompts/prompt_helpers.py +238 -0
  147. fast_agent/mcp/prompts/prompt_load.py +186 -0
  148. fast_agent/mcp/prompts/prompt_server.py +552 -0
  149. fast_agent/mcp/prompts/prompt_template.py +438 -0
  150. fast_agent/mcp/resource_utils.py +215 -0
  151. fast_agent/mcp/sampling.py +200 -0
  152. fast_agent/mcp/server/__init__.py +4 -0
  153. fast_agent/mcp/server/agent_server.py +613 -0
  154. fast_agent/mcp/skybridge.py +44 -0
  155. fast_agent/mcp/sse_tracking.py +287 -0
  156. fast_agent/mcp/stdio_tracking_simple.py +59 -0
  157. fast_agent/mcp/streamable_http_tracking.py +309 -0
  158. fast_agent/mcp/tool_execution_handler.py +137 -0
  159. fast_agent/mcp/tool_permission_handler.py +88 -0
  160. fast_agent/mcp/transport_tracking.py +634 -0
  161. fast_agent/mcp/types.py +24 -0
  162. fast_agent/mcp/ui_agent.py +48 -0
  163. fast_agent/mcp/ui_mixin.py +209 -0
  164. fast_agent/mcp_server_registry.py +89 -0
  165. fast_agent/py.typed +0 -0
  166. fast_agent/resources/examples/data-analysis/analysis-campaign.py +189 -0
  167. fast_agent/resources/examples/data-analysis/analysis.py +68 -0
  168. fast_agent/resources/examples/data-analysis/fastagent.config.yaml +41 -0
  169. fast_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
  170. fast_agent/resources/examples/mcp/elicitations/elicitation_account_server.py +88 -0
  171. fast_agent/resources/examples/mcp/elicitations/elicitation_forms_server.py +297 -0
  172. fast_agent/resources/examples/mcp/elicitations/elicitation_game_server.py +164 -0
  173. fast_agent/resources/examples/mcp/elicitations/fastagent.config.yaml +35 -0
  174. fast_agent/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +17 -0
  175. fast_agent/resources/examples/mcp/elicitations/forms_demo.py +107 -0
  176. fast_agent/resources/examples/mcp/elicitations/game_character.py +65 -0
  177. fast_agent/resources/examples/mcp/elicitations/game_character_handler.py +256 -0
  178. fast_agent/resources/examples/mcp/elicitations/tool_call.py +21 -0
  179. fast_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
  180. fast_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
  181. fast_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
  182. fast_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +15 -0
  183. fast_agent/resources/examples/researcher/fastagent.config.yaml +61 -0
  184. fast_agent/resources/examples/researcher/researcher-eval.py +53 -0
  185. fast_agent/resources/examples/researcher/researcher-imp.py +189 -0
  186. fast_agent/resources/examples/researcher/researcher.py +36 -0
  187. fast_agent/resources/examples/tensorzero/.env.sample +2 -0
  188. fast_agent/resources/examples/tensorzero/Makefile +31 -0
  189. fast_agent/resources/examples/tensorzero/README.md +56 -0
  190. fast_agent/resources/examples/tensorzero/agent.py +35 -0
  191. fast_agent/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
  192. fast_agent/resources/examples/tensorzero/demo_images/crab.png +0 -0
  193. fast_agent/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
  194. fast_agent/resources/examples/tensorzero/docker-compose.yml +105 -0
  195. fast_agent/resources/examples/tensorzero/fastagent.config.yaml +19 -0
  196. fast_agent/resources/examples/tensorzero/image_demo.py +67 -0
  197. fast_agent/resources/examples/tensorzero/mcp_server/Dockerfile +25 -0
  198. fast_agent/resources/examples/tensorzero/mcp_server/entrypoint.sh +35 -0
  199. fast_agent/resources/examples/tensorzero/mcp_server/mcp_server.py +31 -0
  200. fast_agent/resources/examples/tensorzero/mcp_server/pyproject.toml +11 -0
  201. fast_agent/resources/examples/tensorzero/simple_agent.py +25 -0
  202. fast_agent/resources/examples/tensorzero/tensorzero_config/system_schema.json +29 -0
  203. fast_agent/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +11 -0
  204. fast_agent/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +35 -0
  205. fast_agent/resources/examples/workflows/agents_as_tools_extended.py +73 -0
  206. fast_agent/resources/examples/workflows/agents_as_tools_simple.py +50 -0
  207. fast_agent/resources/examples/workflows/chaining.py +37 -0
  208. fast_agent/resources/examples/workflows/evaluator.py +77 -0
  209. fast_agent/resources/examples/workflows/fastagent.config.yaml +26 -0
  210. fast_agent/resources/examples/workflows/graded_report.md +89 -0
  211. fast_agent/resources/examples/workflows/human_input.py +28 -0
  212. fast_agent/resources/examples/workflows/maker.py +156 -0
  213. fast_agent/resources/examples/workflows/orchestrator.py +70 -0
  214. fast_agent/resources/examples/workflows/parallel.py +56 -0
  215. fast_agent/resources/examples/workflows/router.py +69 -0
  216. fast_agent/resources/examples/workflows/short_story.md +13 -0
  217. fast_agent/resources/examples/workflows/short_story.txt +19 -0
  218. fast_agent/resources/setup/.gitignore +30 -0
  219. fast_agent/resources/setup/agent.py +28 -0
  220. fast_agent/resources/setup/fastagent.config.yaml +65 -0
  221. fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
  222. fast_agent/resources/setup/pyproject.toml.tmpl +23 -0
  223. fast_agent/skills/__init__.py +9 -0
  224. fast_agent/skills/registry.py +235 -0
  225. fast_agent/tools/elicitation.py +369 -0
  226. fast_agent/tools/shell_runtime.py +402 -0
  227. fast_agent/types/__init__.py +59 -0
  228. fast_agent/types/conversation_summary.py +294 -0
  229. fast_agent/types/llm_stop_reason.py +78 -0
  230. fast_agent/types/message_search.py +249 -0
  231. fast_agent/ui/__init__.py +38 -0
  232. fast_agent/ui/console.py +59 -0
  233. fast_agent/ui/console_display.py +1080 -0
  234. fast_agent/ui/elicitation_form.py +946 -0
  235. fast_agent/ui/elicitation_style.py +59 -0
  236. fast_agent/ui/enhanced_prompt.py +1400 -0
  237. fast_agent/ui/history_display.py +734 -0
  238. fast_agent/ui/interactive_prompt.py +1199 -0
  239. fast_agent/ui/markdown_helpers.py +104 -0
  240. fast_agent/ui/markdown_truncator.py +1004 -0
  241. fast_agent/ui/mcp_display.py +857 -0
  242. fast_agent/ui/mcp_ui_utils.py +235 -0
  243. fast_agent/ui/mermaid_utils.py +169 -0
  244. fast_agent/ui/message_primitives.py +50 -0
  245. fast_agent/ui/notification_tracker.py +205 -0
  246. fast_agent/ui/plain_text_truncator.py +68 -0
  247. fast_agent/ui/progress_display.py +10 -0
  248. fast_agent/ui/rich_progress.py +195 -0
  249. fast_agent/ui/streaming.py +774 -0
  250. fast_agent/ui/streaming_buffer.py +449 -0
  251. fast_agent/ui/tool_display.py +422 -0
  252. fast_agent/ui/usage_display.py +204 -0
  253. fast_agent/utils/__init__.py +5 -0
  254. fast_agent/utils/reasoning_stream_parser.py +77 -0
  255. fast_agent/utils/time.py +22 -0
  256. fast_agent/workflow_telemetry.py +261 -0
  257. fast_agent_mcp-0.4.7.dist-info/METADATA +788 -0
  258. fast_agent_mcp-0.4.7.dist-info/RECORD +261 -0
  259. fast_agent_mcp-0.4.7.dist-info/WHEEL +4 -0
  260. fast_agent_mcp-0.4.7.dist-info/entry_points.txt +7 -0
  261. 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)