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,784 @@
1
+ """
2
+ Type-safe decorators for DirectFastAgent applications.
3
+ These decorators provide type-safe function signatures and IDE support
4
+ for creating agents in the DirectFastAgent framework.
5
+ """
6
+
7
+ from collections.abc import Coroutine
8
+ from pathlib import Path
9
+ from typing import (
10
+ Any,
11
+ Awaitable,
12
+ Callable,
13
+ Literal,
14
+ ParamSpec,
15
+ Protocol,
16
+ TypeVar,
17
+ )
18
+
19
+ from mcp.client.session import ElicitationFnT
20
+ from pydantic import AnyUrl
21
+
22
+ from fast_agent.agents.agent_types import AgentConfig, AgentType
23
+ from fast_agent.agents.workflow.iterative_planner import ITERATIVE_PLAN_SYSTEM_PROMPT_TEMPLATE
24
+ from fast_agent.agents.workflow.router_agent import (
25
+ ROUTING_SYSTEM_INSTRUCTION,
26
+ )
27
+ from fast_agent.constants import DEFAULT_AGENT_INSTRUCTION
28
+ from fast_agent.skills import SkillManifest, SkillRegistry
29
+ from fast_agent.types import RequestParams
30
+
31
+ # Type variables for the decorated function
32
+ P = ParamSpec("P") # Parameters
33
+ R = TypeVar("R", covariant=True) # Return type
34
+
35
+
36
+ # Protocol for decorated agent functions
37
+ class DecoratedAgentProtocol(Protocol[P, R]):
38
+ """Protocol defining the interface of a decorated agent function."""
39
+
40
+ _agent_type: AgentType
41
+ _agent_config: AgentConfig
42
+
43
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Awaitable[R]: ...
44
+
45
+
46
+ # Protocol for orchestrator functions
47
+ class DecoratedOrchestratorProtocol(DecoratedAgentProtocol[P, R], Protocol):
48
+ """Protocol for decorated orchestrator functions with additional metadata."""
49
+
50
+ _child_agents: list[str]
51
+ _plan_type: Literal["full", "iterative"]
52
+
53
+
54
+ # Protocol for router functions
55
+ class DecoratedRouterProtocol(DecoratedAgentProtocol[P, R], Protocol):
56
+ """Protocol for decorated router functions with additional metadata."""
57
+
58
+ _router_agents: list[str]
59
+
60
+
61
+ # Protocol for chain functions
62
+ class DecoratedChainProtocol(DecoratedAgentProtocol[P, R], Protocol):
63
+ """Protocol for decorated chain functions with additional metadata."""
64
+
65
+ _chain_agents: list[str]
66
+
67
+
68
+ # Protocol for parallel functions
69
+ class DecoratedParallelProtocol(DecoratedAgentProtocol[P, R], Protocol):
70
+ """Protocol for decorated parallel functions with additional metadata."""
71
+
72
+ _fan_out: list[str]
73
+ _fan_in: str
74
+
75
+
76
+ # Protocol for evaluator-optimizer functions
77
+ class DecoratedEvaluatorOptimizerProtocol(DecoratedAgentProtocol[P, R], Protocol):
78
+ """Protocol for decorated evaluator-optimizer functions with additional metadata."""
79
+
80
+ _generator: str
81
+ _evaluator: str
82
+
83
+
84
+ # Protocol for maker functions
85
+ class DecoratedMakerProtocol(DecoratedAgentProtocol[P, R], Protocol):
86
+ """Protocol for decorated MAKER functions with additional metadata."""
87
+
88
+ _worker: str
89
+ _k: int
90
+ _max_samples: int
91
+
92
+
93
+ def _fetch_url_content(url: str) -> str:
94
+ """
95
+ Fetch content from a URL.
96
+
97
+ Args:
98
+ url: The URL to fetch content from
99
+
100
+ Returns:
101
+ The text content from the URL
102
+
103
+ Raises:
104
+ requests.RequestException: If the URL cannot be fetched
105
+ UnicodeDecodeError: If the content cannot be decoded as UTF-8
106
+ """
107
+ import requests
108
+
109
+ response = requests.get(url, timeout=10)
110
+ response.raise_for_status() # Raise exception for HTTP errors
111
+ return response.text
112
+
113
+
114
+ def _apply_templates(text: str) -> str:
115
+ """
116
+ Apply template substitutions to instruction text.
117
+
118
+ Supported templates:
119
+ {{currentDate}} - Current date in format "24 July 2025"
120
+ {{url:https://...}} - Content fetched from the specified URL
121
+
122
+ Note: File templates ({{file:...}} and {{file_silent:...}}) are resolved later
123
+ during runtime to ensure they're relative to the workspaceRoot.
124
+
125
+ Args:
126
+ text: The text to process
127
+
128
+ Returns:
129
+ Text with template substitutions applied
130
+
131
+ Raises:
132
+ requests.RequestException: If a URL in {{url:...}} cannot be fetched
133
+ UnicodeDecodeError: If URL content cannot be decoded as UTF-8
134
+ """
135
+ import re
136
+ from datetime import datetime
137
+
138
+ # Apply {{currentDate}} template
139
+ current_date = datetime.now().strftime("%d %B %Y")
140
+ text = text.replace("{{currentDate}}", current_date)
141
+
142
+ # Apply {{url:...}} templates
143
+ url_pattern = re.compile(r"\{\{url:(https?://[^}]+)\}\}")
144
+
145
+ def replace_url(match):
146
+ url = match.group(1)
147
+ return _fetch_url_content(url)
148
+
149
+ text = url_pattern.sub(replace_url, text)
150
+
151
+ return text
152
+
153
+
154
+ def _resolve_instruction(instruction: str | Path | AnyUrl) -> str:
155
+ """
156
+ Resolve instruction from either a string, Path, or URL with template support.
157
+
158
+ Args:
159
+ instruction: Either a string instruction, Path to a file, or URL containing the instruction
160
+
161
+ Returns:
162
+ The resolved instruction string with templates applied
163
+
164
+ Raises:
165
+ FileNotFoundError: If the Path doesn't exist
166
+ PermissionError: If the Path can't be read
167
+ UnicodeDecodeError: If the file/URL content can't be decoded as UTF-8
168
+ requests.RequestException: If the URL cannot be fetched
169
+ """
170
+ if isinstance(instruction, Path):
171
+ text = instruction.read_text(encoding="utf-8")
172
+ elif isinstance(instruction, AnyUrl):
173
+ text = _fetch_url_content(str(instruction))
174
+ else:
175
+ text = instruction
176
+
177
+ # Apply template substitutions
178
+ return _apply_templates(text)
179
+
180
+
181
+ def _decorator_impl(
182
+ self,
183
+ agent_type: AgentType,
184
+ name: str,
185
+ instruction: str,
186
+ *,
187
+ servers: list[str] = [],
188
+ model: str | None = None,
189
+ use_history: bool = True,
190
+ request_params: RequestParams | None = None,
191
+ human_input: bool = False,
192
+ default: bool = False,
193
+ tools: dict[str, list[str]] | None = None,
194
+ resources: dict[str, list[str]] | None = None,
195
+ prompts: dict[str, list[str]] | None = None,
196
+ skills: SkillManifest
197
+ | SkillRegistry
198
+ | Path
199
+ | str
200
+ | list[SkillManifest | SkillRegistry | Path | str | None]
201
+ | None = None,
202
+ **extra_kwargs,
203
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
204
+ """
205
+ Core implementation for agent decorators with common behavior and type safety.
206
+
207
+ Args:
208
+ agent_type: Type of agent to create
209
+ name: Name of the agent
210
+ instruction: Base instruction for the agent
211
+ servers: List of server names the agent should connect to
212
+ model: Model specification string
213
+ use_history: Whether to maintain conversation history
214
+ request_params: Additional request parameters for the LLM
215
+ human_input: Whether to enable human input capabilities
216
+ default: Whether to mark this as the default agent
217
+ **extra_kwargs: Additional agent/workflow-specific parameters
218
+ """
219
+
220
+ def decorator(func: Callable[P, Coroutine[Any, Any, R]]) -> Callable[P, Coroutine[Any, Any, R]]:
221
+ # Create agent configuration
222
+ config = AgentConfig(
223
+ name=name,
224
+ instruction=instruction,
225
+ servers=servers,
226
+ tools=tools,
227
+ resources=resources,
228
+ prompts=prompts,
229
+ skills=skills,
230
+ model=model,
231
+ use_history=use_history,
232
+ human_input=human_input,
233
+ default=default,
234
+ elicitation_handler=extra_kwargs.get("elicitation_handler"),
235
+ api_key=extra_kwargs.get("api_key"),
236
+ )
237
+
238
+ # Update request params if provided
239
+ if request_params:
240
+ config.default_request_params = request_params
241
+
242
+ # Store metadata in the registry
243
+ agent_data = {
244
+ "config": config,
245
+ "type": agent_type.value,
246
+ "func": func,
247
+ }
248
+
249
+ # Add extra parameters specific to this agent type
250
+ for key, value in extra_kwargs.items():
251
+ agent_data[key] = value
252
+
253
+ # Store the configuration in the FastAgent instance
254
+ self.agents[name] = agent_data
255
+
256
+ # Store type information on the function for IDE support
257
+ setattr(func, "_agent_type", agent_type)
258
+ setattr(func, "_agent_config", config)
259
+ for key, value in extra_kwargs.items():
260
+ setattr(func, f"_{key}", value)
261
+
262
+ return func
263
+
264
+ return decorator
265
+
266
+
267
+ def agent(
268
+ self,
269
+ name: str = "default",
270
+ instruction_or_kwarg: str | Path | AnyUrl | None = None,
271
+ *,
272
+ instruction: str | Path | AnyUrl = DEFAULT_AGENT_INSTRUCTION,
273
+ agents: list[str] | None = None,
274
+ servers: list[str] = [],
275
+ tools: dict[str, list[str]] | None = None,
276
+ resources: dict[str, list[str]] | None = None,
277
+ prompts: dict[str, list[str]] | None = None,
278
+ skills: SkillManifest | SkillRegistry | Path | str | None = None,
279
+ model: str | None = None,
280
+ use_history: bool = True,
281
+ request_params: RequestParams | None = None,
282
+ human_input: bool = False,
283
+ default: bool = False,
284
+ elicitation_handler: ElicitationFnT | None = None,
285
+ api_key: str | None = None,
286
+ history_mode: Any | None = None,
287
+ max_parallel: int | None = None,
288
+ child_timeout_sec: int | None = None,
289
+ max_display_instances: int | None = None,
290
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
291
+ """
292
+ Decorator to create and register a standard agent with type-safe signature.
293
+
294
+ Args:
295
+ name: Name of the agent
296
+ instruction_or_kwarg: Optional positional parameter for instruction
297
+ instruction: Base instruction for the agent (keyword arg)
298
+ servers: List of server names the agent should connect to
299
+ tools: Optional list of tool names or patterns to include
300
+ resources: Optional list of resource names or patterns to include
301
+ prompts: Optional list of prompt names or patterns to include
302
+ model: Model specification string
303
+ use_history: Whether to maintain conversation history
304
+ request_params: Additional request parameters for the LLM
305
+ human_input: Whether to enable human input capabilities
306
+ default: Whether to mark this as the default agent
307
+ elicitation_handler: Custom elicitation handler function (ElicitationFnT)
308
+ api_key: Optional API key for the LLM provider
309
+
310
+ Returns:
311
+ A decorator that registers the agent with proper type annotations
312
+ """
313
+ final_instruction_raw = (
314
+ instruction_or_kwarg if instruction_or_kwarg is not None else instruction
315
+ )
316
+ final_instruction = _resolve_instruction(final_instruction_raw)
317
+
318
+ return _decorator_impl(
319
+ self,
320
+ AgentType.BASIC,
321
+ name=name,
322
+ instruction=final_instruction,
323
+ child_agents=agents,
324
+ servers=servers,
325
+ model=model,
326
+ use_history=use_history,
327
+ request_params=request_params,
328
+ human_input=human_input,
329
+ default=default,
330
+ elicitation_handler=elicitation_handler,
331
+ tools=tools,
332
+ resources=resources,
333
+ prompts=prompts,
334
+ skills=skills,
335
+ api_key=api_key,
336
+ agents_as_tools_options={
337
+ "history_mode": history_mode,
338
+ "max_parallel": max_parallel,
339
+ "child_timeout_sec": child_timeout_sec,
340
+ "max_display_instances": max_display_instances,
341
+ },
342
+ )
343
+
344
+
345
+ def custom(
346
+ self,
347
+ cls,
348
+ name: str = "default",
349
+ instruction_or_kwarg: str | Path | AnyUrl | None = None,
350
+ *,
351
+ instruction: str | Path | AnyUrl = "You are a helpful agent.",
352
+ servers: list[str] = [],
353
+ tools: dict[str, list[str]] | None = None,
354
+ resources: dict[str, list[str]] | None = None,
355
+ prompts: dict[str, list[str]] | None = None,
356
+ skills: SkillManifest | SkillRegistry | Path | str | None = None,
357
+ model: str | None = None,
358
+ use_history: bool = True,
359
+ request_params: RequestParams | None = None,
360
+ human_input: bool = False,
361
+ default: bool = False,
362
+ elicitation_handler: ElicitationFnT | None = None,
363
+ api_key: str | None = None,
364
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
365
+ """
366
+ Decorator to create and register a standard agent with type-safe signature.
367
+
368
+ Args:
369
+ name: Name of the agent
370
+ instruction_or_kwarg: Optional positional parameter for instruction
371
+ instruction: Base instruction for the agent (keyword arg)
372
+ servers: List of server names the agent should connect to
373
+ model: Model specification string
374
+ use_history: Whether to maintain conversation history
375
+ request_params: Additional request parameters for the LLM
376
+ human_input: Whether to enable human input capabilities
377
+ elicitation_handler: Custom elicitation handler function (ElicitationFnT)
378
+
379
+ Returns:
380
+ A decorator that registers the agent with proper type annotations
381
+ """
382
+ final_instruction_raw = (
383
+ instruction_or_kwarg if instruction_or_kwarg is not None else instruction
384
+ )
385
+ final_instruction = _resolve_instruction(final_instruction_raw)
386
+
387
+ return _decorator_impl(
388
+ self,
389
+ AgentType.CUSTOM,
390
+ name=name,
391
+ instruction=final_instruction,
392
+ servers=servers,
393
+ model=model,
394
+ use_history=use_history,
395
+ request_params=request_params,
396
+ human_input=human_input,
397
+ agent_class=cls,
398
+ default=default,
399
+ elicitation_handler=elicitation_handler,
400
+ api_key=api_key,
401
+ tools=tools,
402
+ resources=resources,
403
+ prompts=prompts,
404
+ skills=skills,
405
+ )
406
+
407
+
408
+ DEFAULT_INSTRUCTION_ORCHESTRATOR = """
409
+ You are an expert planner. Given an objective task and a list of Agents
410
+ (which are collections of capabilities), your job is to break down the objective
411
+ into a series of steps, which can be performed by these agents.
412
+ """
413
+
414
+
415
+ def orchestrator(
416
+ self,
417
+ name: str,
418
+ *,
419
+ agents: list[str],
420
+ instruction: str | Path | AnyUrl = DEFAULT_INSTRUCTION_ORCHESTRATOR,
421
+ model: str | None = None,
422
+ request_params: RequestParams | None = None,
423
+ use_history: bool = False,
424
+ human_input: bool = False,
425
+ plan_type: Literal["full", "iterative"] = "full",
426
+ plan_iterations: int = 5,
427
+ default: bool = False,
428
+ api_key: str | None = None,
429
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
430
+ """
431
+ Decorator to create and register an orchestrator agent with type-safe signature.
432
+
433
+ Args:
434
+ name: Name of the orchestrator
435
+ agents: List of agent names this orchestrator can use
436
+ instruction: Base instruction for the orchestrator
437
+ model: Model specification string
438
+ use_history: Whether to maintain conversation history
439
+ request_params: Additional request parameters for the LLM
440
+ human_input: Whether to enable human input capabilities
441
+ plan_type: Planning approach - "full" or "iterative"
442
+ plan_iterations: Maximum number of planning iterations
443
+ default: Whether to mark this as the default agent
444
+
445
+ Returns:
446
+ A decorator that registers the orchestrator with proper type annotations
447
+ """
448
+
449
+ # Create final request params with plan_iterations
450
+ resolved_instruction = _resolve_instruction(instruction)
451
+
452
+ return _decorator_impl(
453
+ self,
454
+ AgentType.ORCHESTRATOR,
455
+ name=name,
456
+ instruction=resolved_instruction,
457
+ servers=[], # Orchestrators don't connect to servers directly
458
+ model=model,
459
+ use_history=use_history,
460
+ request_params=request_params,
461
+ human_input=human_input,
462
+ child_agents=agents,
463
+ plan_type=plan_type,
464
+ plan_iterations=plan_iterations,
465
+ default=default,
466
+ api_key=api_key,
467
+ )
468
+
469
+
470
+ def iterative_planner(
471
+ self,
472
+ name: str,
473
+ *,
474
+ agents: list[str],
475
+ instruction: str | Path | AnyUrl = ITERATIVE_PLAN_SYSTEM_PROMPT_TEMPLATE,
476
+ model: str | None = None,
477
+ request_params: RequestParams | None = None,
478
+ plan_iterations: int = -1,
479
+ default: bool = False,
480
+ api_key: str | None = None,
481
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
482
+ """
483
+ Decorator to create and register an orchestrator agent with type-safe signature.
484
+
485
+ Args:
486
+ name: Name of the orchestrator
487
+ agents: List of agent names this orchestrator can use
488
+ instruction: Base instruction for the orchestrator
489
+ model: Model specification string
490
+ use_history: Whether to maintain conversation history
491
+ request_params: Additional request parameters for the LLM
492
+ human_input: Whether to enable human input capabilities
493
+ plan_type: Planning approach - "full" or "iterative"
494
+ plan_iterations: Maximum number of planning iterations (0 for unlimited)
495
+ default: Whether to mark this as the default agent
496
+
497
+ Returns:
498
+ A decorator that registers the orchestrator with proper type annotations
499
+ """
500
+
501
+ # Create final request params with plan_iterations
502
+ resolved_instruction = _resolve_instruction(instruction)
503
+
504
+ return _decorator_impl(
505
+ self,
506
+ AgentType.ITERATIVE_PLANNER,
507
+ name=name,
508
+ instruction=resolved_instruction,
509
+ servers=[], # Orchestrators don't connect to servers directly
510
+ model=model,
511
+ use_history=False,
512
+ request_params=request_params,
513
+ child_agents=agents,
514
+ plan_iterations=plan_iterations,
515
+ default=default,
516
+ api_key=api_key,
517
+ )
518
+
519
+
520
+ def router(
521
+ self,
522
+ name: str,
523
+ *,
524
+ agents: list[str],
525
+ instruction: str | Path | AnyUrl | None = None,
526
+ servers: list[str] = [],
527
+ tools: dict[str, list[str]] | None = None,
528
+ resources: dict[str, list[str]] | None = None,
529
+ prompts: dict[str, list[str]] | None = None,
530
+ model: str | None = None,
531
+ use_history: bool = False,
532
+ request_params: RequestParams | None = None,
533
+ human_input: bool = False,
534
+ default: bool = False,
535
+ elicitation_handler: ElicitationFnT
536
+ | None = None, ## exclude from docs, decide whether allowable
537
+ api_key: str | None = None,
538
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
539
+ """
540
+ Decorator to create and register a router agent with type-safe signature.
541
+
542
+ Args:
543
+ name: Name of the router
544
+ agents: List of agent names this router can route to
545
+ instruction: Base instruction for the router
546
+ model: Model specification string
547
+ use_history: Whether to maintain conversation history
548
+ request_params: Additional request parameters for the LLM
549
+ human_input: Whether to enable human input capabilities
550
+ default: Whether to mark this as the default agent
551
+ elicitation_handler: Custom elicitation handler function (ElicitationFnT)
552
+
553
+ Returns:
554
+ A decorator that registers the router with proper type annotations
555
+ """
556
+ resolved_instruction = _resolve_instruction(instruction or ROUTING_SYSTEM_INSTRUCTION)
557
+
558
+ return _decorator_impl(
559
+ self,
560
+ AgentType.ROUTER,
561
+ name=name,
562
+ instruction=resolved_instruction,
563
+ servers=servers,
564
+ model=model,
565
+ use_history=use_history,
566
+ request_params=request_params,
567
+ human_input=human_input,
568
+ default=default,
569
+ router_agents=agents,
570
+ elicitation_handler=elicitation_handler,
571
+ api_key=api_key,
572
+ tools=tools,
573
+ prompts=prompts,
574
+ resources=resources,
575
+ )
576
+
577
+
578
+ def chain(
579
+ self,
580
+ name: str,
581
+ *,
582
+ sequence: list[str],
583
+ instruction: str | Path | AnyUrl | None = None,
584
+ cumulative: bool = False,
585
+ default: bool = False,
586
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
587
+ """
588
+ Decorator to create and register a chain agent with type-safe signature.
589
+
590
+ Args:
591
+ name: Name of the chain
592
+ sequence: List of agent names in the chain, executed in sequence
593
+ instruction: Base instruction for the chain
594
+ cumulative: Whether to use cumulative mode (each agent sees all previous responses)
595
+ default: Whether to mark this as the default agent
596
+
597
+ Returns:
598
+ A decorator that registers the chain with proper type annotations
599
+ """
600
+ # Validate sequence is not empty
601
+ if not sequence:
602
+ from fast_agent.core.exceptions import AgentConfigError
603
+
604
+ raise AgentConfigError(f"Chain '{name}' requires at least one agent in the sequence")
605
+
606
+ default_instruction = """Chain processes requests through a series of agents in sequence, the output of each agent is passed to the next."""
607
+ resolved_instruction = _resolve_instruction(instruction or default_instruction)
608
+
609
+ return _decorator_impl(
610
+ self,
611
+ AgentType.CHAIN,
612
+ name=name,
613
+ instruction=resolved_instruction,
614
+ sequence=sequence,
615
+ cumulative=cumulative,
616
+ default=default,
617
+ )
618
+
619
+
620
+ def parallel(
621
+ self,
622
+ name: str,
623
+ *,
624
+ fan_out: list[str],
625
+ fan_in: str | None = None,
626
+ instruction: str | Path | AnyUrl | None = None,
627
+ include_request: bool = True,
628
+ default: bool = False,
629
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
630
+ """
631
+ Decorator to create and register a parallel agent with type-safe signature.
632
+
633
+ Args:
634
+ name: Name of the parallel agent
635
+ fan_out: List of agents to execute in parallel
636
+ fan_in: Agent to aggregate results
637
+ instruction: Base instruction for the parallel agent
638
+ include_request: Whether to include the original request when aggregating
639
+ default: Whether to mark this as the default agent
640
+
641
+ Returns:
642
+ A decorator that registers the parallel agent with proper type annotations
643
+ """
644
+ default_instruction = """
645
+ You are a parallel processor that executes multiple agents simultaneously
646
+ and aggregates their results.
647
+ """
648
+ resolved_instruction = _resolve_instruction(instruction or default_instruction)
649
+
650
+ return _decorator_impl(
651
+ self,
652
+ AgentType.PARALLEL,
653
+ name=name,
654
+ instruction=resolved_instruction,
655
+ servers=[], # Parallel agents don't connect to servers directly
656
+ fan_in=fan_in,
657
+ fan_out=fan_out,
658
+ include_request=include_request,
659
+ default=default,
660
+ )
661
+
662
+
663
+ def evaluator_optimizer(
664
+ self,
665
+ name: str,
666
+ *,
667
+ generator: str,
668
+ evaluator: str,
669
+ instruction: str | Path | AnyUrl | None = None,
670
+ min_rating: str = "GOOD",
671
+ max_refinements: int = 3,
672
+ refinement_instruction: str | None = None,
673
+ default: bool = False,
674
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
675
+ """
676
+ Decorator to create and register an evaluator-optimizer agent with type-safe signature.
677
+
678
+ Args:
679
+ name: Name of the evaluator-optimizer agent
680
+ generator: Name of the agent that generates responses
681
+ evaluator: Name of the agent that evaluates responses
682
+ instruction: Base instruction for the evaluator-optimizer
683
+ min_rating: Minimum acceptable quality rating (EXCELLENT, GOOD, FAIR, POOR)
684
+ max_refinements: Maximum number of refinement iterations
685
+ default: Whether to mark this as the default agent
686
+
687
+ Returns:
688
+ A decorator that registers the evaluator-optimizer with proper type annotations
689
+ """
690
+ default_instruction = """
691
+ You implement an iterative refinement process where content is generated,
692
+ evaluated for quality, and then refined based on specific feedback until
693
+ it reaches an acceptable quality standard.
694
+ """
695
+ resolved_instruction = _resolve_instruction(instruction or default_instruction)
696
+
697
+ return _decorator_impl(
698
+ self,
699
+ AgentType.EVALUATOR_OPTIMIZER,
700
+ name=name,
701
+ instruction=resolved_instruction,
702
+ servers=[], # Evaluator-optimizer doesn't connect to servers directly
703
+ generator=generator,
704
+ evaluator=evaluator,
705
+ min_rating=min_rating,
706
+ max_refinements=max_refinements,
707
+ refinement_instruction=refinement_instruction,
708
+ default=default,
709
+ )
710
+
711
+
712
+ def maker(
713
+ self,
714
+ name: str,
715
+ *,
716
+ worker: str,
717
+ k: int = 3,
718
+ max_samples: int = 50,
719
+ match_strategy: str = "exact",
720
+ red_flag_max_length: int | None = None,
721
+ instruction: str | Path | AnyUrl | None = None,
722
+ default: bool = False,
723
+ ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
724
+ """
725
+ Decorator to create a MAKER agent for statistical error correction via voting.
726
+
727
+ MAKER: Massively decomposed Agentic processes with K-voting Error Reduction.
728
+
729
+ Based on the paper "Solving a Million-Step LLM Task with Zero Errors"
730
+ (arXiv:2511.09030). Implements first-to-ahead-by-k voting where multiple
731
+ samples are drawn from a worker agent, and the first response to achieve
732
+ a k-vote margin over alternatives wins.
733
+
734
+ This enables high reliability with cost-effective models by trading
735
+ compute (multiple samples) for accuracy (statistical consensus).
736
+
737
+ Args:
738
+ name: Name of the MAKER agent
739
+ worker: Name of the agent to sample from for voting
740
+ k: Margin required to declare winner (first-to-ahead-by-k).
741
+ Higher k = more reliable but more samples needed.
742
+ Default of 3 provides strong guarantees for most use cases.
743
+ max_samples: Maximum samples before falling back to plurality vote
744
+ match_strategy: How to compare responses for voting:
745
+ - "exact": Character-for-character match
746
+ - "normalized": Ignore whitespace and case differences
747
+ - "structured": Parse as JSON and compare structurally
748
+ red_flag_max_length: Discard responses longer than this (characters).
749
+ Per the paper, overly long responses correlate
750
+ with errors. None = no length limit.
751
+ instruction: Base instruction for the MAKER agent
752
+ default: Whether to mark this as the default agent
753
+
754
+ Returns:
755
+ A decorator that registers the MAKER agent
756
+
757
+ Example:
758
+ @fast.agent(name="calculator", instruction="Return only the numeric result")
759
+ @fast.maker(name="reliable_calc", worker="calculator", k=3)
760
+ async def main():
761
+ async with fast.run() as agent:
762
+ result = await agent.reliable_calc.send("What is 17 * 23?")
763
+ """
764
+ default_instruction = """
765
+ MAKER: Massively decomposed Agentic processes with K-voting Error Reduction.
766
+ Implements statistical error correction through voting consensus.
767
+ Multiple samples are drawn and the first response to achieve a k-vote
768
+ margin wins, ensuring high reliability even with cost-effective models.
769
+ """
770
+ resolved_instruction = _resolve_instruction(instruction or default_instruction)
771
+
772
+ return _decorator_impl(
773
+ self,
774
+ AgentType.MAKER,
775
+ name=name,
776
+ instruction=resolved_instruction,
777
+ servers=[], # MAKER doesn't connect to servers directly
778
+ worker=worker,
779
+ k=k,
780
+ max_samples=max_samples,
781
+ match_strategy=match_strategy,
782
+ red_flag_max_length=red_flag_max_length,
783
+ default=default,
784
+ )