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,490 @@
1
+ """
2
+ Model database for LLM parameters.
3
+
4
+ This module provides a centralized lookup for model parameters including
5
+ context windows, max output tokens, and supported tokenization types.
6
+ """
7
+
8
+ from typing import Literal
9
+
10
+ from pydantic import BaseModel
11
+
12
+
13
+ class ModelParameters(BaseModel):
14
+ """Configuration parameters for a specific model"""
15
+
16
+ context_window: int
17
+ """Maximum context window size in tokens"""
18
+
19
+ max_output_tokens: int
20
+ """Maximum output tokens the model can generate"""
21
+
22
+ tokenizes: list[str]
23
+ """List of supported content types for tokenization"""
24
+
25
+ json_mode: None | str = "schema"
26
+ """Structured output style. 'schema', 'object' or None for unsupported """
27
+
28
+ reasoning: None | str = None
29
+ """Reasoning output style. 'tags' if enclosed in <thinking> tags, 'none' if not used"""
30
+
31
+ stream_mode: Literal["openai", "manual"] = "openai"
32
+ """Determines how streaming deltas should be processed."""
33
+
34
+
35
+ class ModelDatabase:
36
+ """Centralized model configuration database"""
37
+
38
+ # Common parameter sets
39
+ OPENAI_MULTIMODAL = ["text/plain", "image/jpeg", "image/png", "image/webp", "application/pdf"]
40
+ OPENAI_VISION = ["text/plain", "image/jpeg", "image/png", "image/webp"]
41
+ ANTHROPIC_MULTIMODAL = [
42
+ "text/plain",
43
+ "image/jpeg",
44
+ "image/png",
45
+ "image/webp",
46
+ "application/pdf",
47
+ ]
48
+ GOOGLE_MULTIMODAL = [
49
+ "text/plain",
50
+ "image/jpeg",
51
+ "image/png",
52
+ "image/webp",
53
+ "image/gif",
54
+ "application/pdf",
55
+ # Audio formats
56
+ "audio/wav",
57
+ "audio/mpeg", # Official MP3 MIME type
58
+ "audio/mp3", # Common alias
59
+ "audio/aac",
60
+ "audio/ogg",
61
+ "audio/flac",
62
+ "audio/webm",
63
+ # Video formats (MP4, AVI, FLV, MOV, MPEG, MPG, WebM)
64
+ "video/mp4",
65
+ "video/x-msvideo", # AVI
66
+ "video/x-flv", # FLV
67
+ "video/quicktime", # MOV
68
+ "video/mpeg", # MPEG, MPG
69
+ "video/webm",
70
+ ]
71
+ QWEN_MULTIMODAL = ["text/plain", "image/jpeg", "image/png", "image/webp"]
72
+ XAI_VISION = ["text/plain", "image/jpeg", "image/png", "image/webp"]
73
+ TEXT_ONLY = ["text/plain"]
74
+
75
+ # Common parameter configurations
76
+ OPENAI_STANDARD = ModelParameters(
77
+ context_window=128000, max_output_tokens=16384, tokenizes=OPENAI_MULTIMODAL
78
+ )
79
+
80
+ OPENAI_4_1_STANDARD = ModelParameters(
81
+ context_window=1047576, max_output_tokens=32768, tokenizes=OPENAI_MULTIMODAL
82
+ )
83
+
84
+ OPENAI_O_SERIES = ModelParameters(
85
+ context_window=200000,
86
+ max_output_tokens=100000,
87
+ tokenizes=OPENAI_VISION,
88
+ reasoning="openai",
89
+ )
90
+
91
+ ANTHROPIC_LEGACY = ModelParameters(
92
+ context_window=200000, max_output_tokens=4096, tokenizes=ANTHROPIC_MULTIMODAL
93
+ )
94
+
95
+ ANTHROPIC_35_SERIES = ModelParameters(
96
+ context_window=200000, max_output_tokens=8192, tokenizes=ANTHROPIC_MULTIMODAL
97
+ )
98
+
99
+ # TODO--- TO USE 64,000 NEED TO SUPPORT STREAMING
100
+ ANTHROPIC_37_SERIES = ModelParameters(
101
+ context_window=200000, max_output_tokens=16384, tokenizes=ANTHROPIC_MULTIMODAL
102
+ )
103
+
104
+ QWEN_STANDARD = ModelParameters(
105
+ context_window=32000,
106
+ max_output_tokens=8192,
107
+ tokenizes=QWEN_MULTIMODAL,
108
+ json_mode="object",
109
+ )
110
+ QWEN3_REASONER = ModelParameters(
111
+ context_window=131072,
112
+ max_output_tokens=16384,
113
+ tokenizes=TEXT_ONLY,
114
+ json_mode="object",
115
+ reasoning="tags",
116
+ )
117
+
118
+ FAST_AGENT_STANDARD = ModelParameters(
119
+ context_window=1000000, max_output_tokens=100000, tokenizes=TEXT_ONLY
120
+ )
121
+
122
+ OPENAI_4_1_SERIES = ModelParameters(
123
+ context_window=1047576, max_output_tokens=32768, tokenizes=OPENAI_MULTIMODAL
124
+ )
125
+
126
+ OPENAI_4O_SERIES = ModelParameters(
127
+ context_window=128000, max_output_tokens=16384, tokenizes=OPENAI_VISION
128
+ )
129
+
130
+ OPENAI_O3_SERIES = ModelParameters(
131
+ context_window=200000,
132
+ max_output_tokens=100000,
133
+ tokenizes=OPENAI_MULTIMODAL,
134
+ reasoning="openai",
135
+ )
136
+
137
+ OPENAI_O3_MINI_SERIES = ModelParameters(
138
+ context_window=200000,
139
+ max_output_tokens=100000,
140
+ tokenizes=TEXT_ONLY,
141
+ reasoning="openai",
142
+ )
143
+ OPENAI_GPT_OSS_SERIES = ModelParameters(
144
+ context_window=131072,
145
+ max_output_tokens=32766,
146
+ tokenizes=TEXT_ONLY,
147
+ json_mode="object",
148
+ reasoning="gpt_oss",
149
+ )
150
+ OPENAI_GPT_5 = ModelParameters(
151
+ context_window=400000,
152
+ max_output_tokens=128000,
153
+ tokenizes=OPENAI_MULTIMODAL,
154
+ reasoning="openai",
155
+ )
156
+
157
+ ANTHROPIC_OPUS_4_VERSIONED = ModelParameters(
158
+ context_window=200000, max_output_tokens=32000, tokenizes=ANTHROPIC_MULTIMODAL
159
+ )
160
+ ANTHROPIC_SONNET_4_VERSIONED = ModelParameters(
161
+ context_window=200000, max_output_tokens=64000, tokenizes=ANTHROPIC_MULTIMODAL
162
+ )
163
+
164
+ DEEPSEEK_CHAT_STANDARD = ModelParameters(
165
+ context_window=65536, max_output_tokens=8192, tokenizes=TEXT_ONLY
166
+ )
167
+
168
+ DEEPSEEK_REASONER = ModelParameters(
169
+ context_window=65536, max_output_tokens=32768, tokenizes=TEXT_ONLY
170
+ )
171
+
172
+ DEEPSEEK_DISTILL = ModelParameters(
173
+ context_window=131072,
174
+ max_output_tokens=131072,
175
+ tokenizes=TEXT_ONLY,
176
+ json_mode="object",
177
+ reasoning="tags",
178
+ )
179
+
180
+ GEMINI_STANDARD = ModelParameters(
181
+ context_window=1_048_576, max_output_tokens=65_536, tokenizes=GOOGLE_MULTIMODAL
182
+ )
183
+
184
+ GEMINI_2_FLASH = ModelParameters(
185
+ context_window=1_048_576, max_output_tokens=8192, tokenizes=GOOGLE_MULTIMODAL
186
+ )
187
+
188
+ # 31/08/25 switched to object mode (even though groq says schema supported and used to work..)
189
+ KIMI_MOONSHOT = ModelParameters(
190
+ context_window=262144,
191
+ max_output_tokens=16384,
192
+ tokenizes=TEXT_ONLY,
193
+ json_mode="object",
194
+ )
195
+ KIMI_MOONSHOT_THINKING = ModelParameters(
196
+ context_window=262144,
197
+ max_output_tokens=16384,
198
+ tokenizes=TEXT_ONLY,
199
+ json_mode="object",
200
+ reasoning="reasoning_content",
201
+ )
202
+
203
+ # FIXME: xAI has not documented the max output tokens for Grok 4. Using Grok 3 as a placeholder. Will need to update when available (if ever)
204
+ GROK_4 = ModelParameters(context_window=256000, max_output_tokens=16385, tokenizes=TEXT_ONLY)
205
+
206
+ GROK_4_VLM = ModelParameters(
207
+ context_window=2000000, max_output_tokens=16385, tokenizes=XAI_VISION
208
+ )
209
+
210
+ # Source for Grok 3 max output: https://www.reddit.com/r/grok/comments/1j7209p/exploring_grok_3_beta_output_capacity_a_simple/
211
+ # xAI does not document Grok 3 max output tokens, using the above source as a reference.
212
+ GROK_3 = ModelParameters(context_window=131072, max_output_tokens=16385, tokenizes=TEXT_ONLY)
213
+
214
+ # H U G G I N G F A C E - max output tokens are not documented, using 16k as a reasonable default
215
+ GLM_46 = ModelParameters(
216
+ context_window=202752,
217
+ max_output_tokens=8192,
218
+ tokenizes=TEXT_ONLY,
219
+ json_mode="object",
220
+ reasoning="reasoning_content",
221
+ stream_mode="manual",
222
+ )
223
+
224
+ HF_PROVIDER_DEEPSEEK31 = ModelParameters(
225
+ context_window=163_800, max_output_tokens=8192, tokenizes=TEXT_ONLY
226
+ )
227
+
228
+ HF_PROVIDER_DEEPSEEK32 = ModelParameters(
229
+ context_window=163_800,
230
+ max_output_tokens=8192,
231
+ tokenizes=TEXT_ONLY,
232
+ reasoning="gpt_oss",
233
+ )
234
+
235
+ HF_PROVIDER_QWEN3_NEXT = ModelParameters(
236
+ context_window=262_000, max_output_tokens=8192, tokenizes=TEXT_ONLY
237
+ )
238
+
239
+ # Model configuration database
240
+ # KEEP ALL LOWER CASE KEYS
241
+ MODELS: dict[str, ModelParameters] = {
242
+ # internal models
243
+ "passthrough": FAST_AGENT_STANDARD,
244
+ "silent": FAST_AGENT_STANDARD,
245
+ "playback": FAST_AGENT_STANDARD,
246
+ "slow": FAST_AGENT_STANDARD,
247
+ # aliyun models
248
+ "qwen-turbo": QWEN_STANDARD,
249
+ "qwen-plus": QWEN_STANDARD,
250
+ "qwen-max": QWEN_STANDARD,
251
+ "qwen-long": ModelParameters(
252
+ context_window=10000000, max_output_tokens=8192, tokenizes=TEXT_ONLY
253
+ ),
254
+ # OpenAI Models (vanilla aliases and versioned)
255
+ "gpt-4.1": OPENAI_4_1_SERIES,
256
+ "gpt-4.1-mini": OPENAI_4_1_SERIES,
257
+ "gpt-4.1-nano": OPENAI_4_1_SERIES,
258
+ "gpt-4.1-2025-04-14": OPENAI_4_1_SERIES,
259
+ "gpt-4.1-mini-2025-04-14": OPENAI_4_1_SERIES,
260
+ "gpt-4.1-nano-2025-04-14": OPENAI_4_1_SERIES,
261
+ "gpt-4o": OPENAI_4O_SERIES,
262
+ "gpt-4o-2024-11-20": OPENAI_4O_SERIES,
263
+ "gpt-4o-mini-2024-07-18": OPENAI_4O_SERIES,
264
+ "o1": OPENAI_O_SERIES,
265
+ "o1-2024-12-17": OPENAI_O_SERIES,
266
+ "o3": OPENAI_O3_SERIES,
267
+ "o3-pro": ModelParameters(
268
+ context_window=200_000, max_output_tokens=100_000, tokenizes=TEXT_ONLY
269
+ ),
270
+ "o3-mini": OPENAI_O3_MINI_SERIES,
271
+ "o4-mini": OPENAI_O3_SERIES,
272
+ "o3-2025-04-16": OPENAI_O3_SERIES,
273
+ "o3-mini-2025-01-31": OPENAI_O3_MINI_SERIES,
274
+ "o4-mini-2025-04-16": OPENAI_O3_SERIES,
275
+ "gpt-5": OPENAI_GPT_5,
276
+ "gpt-5-mini": OPENAI_GPT_5,
277
+ "gpt-5-nano": OPENAI_GPT_5,
278
+ "gpt-5.1": OPENAI_GPT_5,
279
+ "gpt-5.1-mini": OPENAI_GPT_5, # pre-emptive
280
+ "gpt-5.1-nano": OPENAI_GPT_5, # pre-emptive
281
+ # Anthropic Models
282
+ "claude-3-haiku": ANTHROPIC_35_SERIES,
283
+ "claude-3-haiku-20240307": ANTHROPIC_LEGACY,
284
+ "claude-3-sonnet": ANTHROPIC_LEGACY,
285
+ "claude-3-opus": ANTHROPIC_LEGACY,
286
+ "claude-3-opus-20240229": ANTHROPIC_LEGACY,
287
+ "claude-3-opus-latest": ANTHROPIC_LEGACY,
288
+ "claude-3-5-haiku": ANTHROPIC_35_SERIES,
289
+ "claude-3-5-haiku-20241022": ANTHROPIC_35_SERIES,
290
+ "claude-3-5-haiku-latest": ANTHROPIC_35_SERIES,
291
+ "claude-3-sonnet-20240229": ANTHROPIC_LEGACY,
292
+ "claude-3-5-sonnet": ANTHROPIC_35_SERIES,
293
+ "claude-3-5-sonnet-20240620": ANTHROPIC_35_SERIES,
294
+ "claude-3-5-sonnet-20241022": ANTHROPIC_35_SERIES,
295
+ "claude-3-5-sonnet-latest": ANTHROPIC_35_SERIES,
296
+ "claude-3-7-sonnet": ANTHROPIC_37_SERIES,
297
+ "claude-3-7-sonnet-20250219": ANTHROPIC_37_SERIES,
298
+ "claude-3-7-sonnet-latest": ANTHROPIC_37_SERIES,
299
+ "claude-sonnet-4-0": ANTHROPIC_SONNET_4_VERSIONED,
300
+ "claude-sonnet-4-20250514": ANTHROPIC_SONNET_4_VERSIONED,
301
+ "claude-sonnet-4-5": ANTHROPIC_SONNET_4_VERSIONED,
302
+ "claude-sonnet-4-5-20250929": ANTHROPIC_SONNET_4_VERSIONED,
303
+ "claude-opus-4-0": ANTHROPIC_OPUS_4_VERSIONED,
304
+ "claude-opus-4-1": ANTHROPIC_OPUS_4_VERSIONED,
305
+ "claude-opus-4-5": ANTHROPIC_OPUS_4_VERSIONED,
306
+ "claude-opus-4-20250514": ANTHROPIC_OPUS_4_VERSIONED,
307
+ "claude-haiku-4-5-20251001": ANTHROPIC_SONNET_4_VERSIONED,
308
+ "claude-haiku-4-5": ANTHROPIC_SONNET_4_VERSIONED,
309
+ # DeepSeek Models
310
+ "deepseek-chat": DEEPSEEK_CHAT_STANDARD,
311
+ # Google Gemini Models (vanilla aliases and versioned)
312
+ "gemini-2.0-flash": GEMINI_2_FLASH,
313
+ "gemini-2.5-flash-preview": GEMINI_STANDARD,
314
+ "gemini-2.5-pro-preview": GEMINI_STANDARD,
315
+ "gemini-2.5-flash-preview-05-20": GEMINI_STANDARD,
316
+ "gemini-2.5-pro-preview-05-06": GEMINI_STANDARD,
317
+ "gemini-2.5-pro": GEMINI_STANDARD,
318
+ "gemini-2.5-flash-preview-09-2025": GEMINI_STANDARD,
319
+ "gemini-2.5-flash": GEMINI_STANDARD,
320
+ "gemini-3-pro-preview": GEMINI_STANDARD,
321
+ # xAI Grok Models
322
+ "grok-4-fast-reasoning": GROK_4_VLM,
323
+ "grok-4-fast-non-reasoning": GROK_4_VLM,
324
+ "grok-4": GROK_4,
325
+ "grok-4-0709": GROK_4,
326
+ "grok-3": GROK_3,
327
+ "grok-3-mini": GROK_3,
328
+ "grok-3-fast": GROK_3,
329
+ "grok-3-mini-fast": GROK_3,
330
+ "moonshotai/kimi-k2": KIMI_MOONSHOT,
331
+ "moonshotai/kimi-k2-instruct-0905": KIMI_MOONSHOT,
332
+ "moonshotai/kimi-k2-thinking": KIMI_MOONSHOT_THINKING,
333
+ "moonshotai/kimi-k2-thinking-0905": KIMI_MOONSHOT_THINKING,
334
+ "qwen/qwen3-32b": QWEN3_REASONER,
335
+ "deepseek-r1-distill-llama-70b": DEEPSEEK_DISTILL,
336
+ "openai/gpt-oss-120b": OPENAI_GPT_OSS_SERIES, # https://cookbook.openai.com/articles/openai-harmony
337
+ "openai/gpt-oss-20b": OPENAI_GPT_OSS_SERIES, # tool/reasoning interleave guidance
338
+ "zai-org/glm-4.6": GLM_46,
339
+ "minimaxai/minimax-m2": GLM_46,
340
+ "qwen/qwen3-next-80b-a3b-instruct": HF_PROVIDER_QWEN3_NEXT,
341
+ "deepseek-ai/deepseek-v3.1": HF_PROVIDER_DEEPSEEK31,
342
+ "deepseek-ai/deepseek-v3.2-exp": HF_PROVIDER_DEEPSEEK32,
343
+ }
344
+
345
+ @classmethod
346
+ def get_model_params(cls, model: str) -> ModelParameters | None:
347
+ """Get model parameters for a given model name"""
348
+ if not model:
349
+ return None
350
+
351
+ normalized = cls.normalize_model_name(model)
352
+ return cls.MODELS.get(normalized)
353
+
354
+ @classmethod
355
+ def normalize_model_name(cls, model: str) -> str:
356
+ """Normalize model specs (provider/effort/aliases) to a ModelDatabase key.
357
+
358
+ This intentionally delegates to ModelFactory parsing where possible rather than
359
+ re-implementing model string semantics in the database layer.
360
+ """
361
+ from fast_agent.core.exceptions import ModelConfigError
362
+ from fast_agent.llm.model_factory import ModelFactory
363
+ from fast_agent.llm.provider_types import Provider
364
+
365
+ model_spec = (model or "").strip()
366
+ if not model_spec:
367
+ return ""
368
+
369
+ # If it's already a known key, keep it as-is (after casing/whitespace normalization).
370
+ direct_key = model_spec.lower()
371
+ if direct_key in cls.MODELS:
372
+ return direct_key
373
+
374
+ # Apply aliases first (case-insensitive).
375
+ aliased = ModelFactory.MODEL_ALIASES.get(model_spec)
376
+ if not aliased:
377
+ aliased = ModelFactory.MODEL_ALIASES.get(model_spec.lower())
378
+ if aliased:
379
+ model_spec = aliased
380
+ direct_key = model_spec.strip().lower()
381
+ if direct_key in cls.MODELS:
382
+ return direct_key
383
+
384
+ # Parse known spec formats to strip provider prefixes and reasoning effort.
385
+ try:
386
+ parsed = ModelFactory.parse_model_string(model_spec)
387
+ model_spec = parsed.model_name
388
+
389
+ # HF uses `model:provider` for routing; the suffix is not part of the model id.
390
+ if parsed.provider == Provider.HUGGINGFACE and ":" in model_spec:
391
+ model_spec = model_spec.rsplit(":", 1)[0]
392
+ except ModelConfigError:
393
+ # Best-effort fallback: keep original spec if it can't be parsed.
394
+ pass
395
+
396
+ # If parsing failed, still support common "model:route" forms by stripping the suffix
397
+ # only when the base resolves to a known database key.
398
+ if ":" in model_spec:
399
+ base = model_spec.rsplit(":", 1)[0].strip().lower()
400
+ if base in cls.MODELS:
401
+ return base
402
+
403
+ return model_spec.strip().lower()
404
+
405
+ @classmethod
406
+ def get_context_window(cls, model: str) -> int | None:
407
+ """Get context window size for a model"""
408
+ params = cls.get_model_params(model)
409
+ return params.context_window if params else None
410
+
411
+ @classmethod
412
+ def get_max_output_tokens(cls, model: str) -> int | None:
413
+ """Get maximum output tokens for a model"""
414
+ params = cls.get_model_params(model)
415
+ return params.max_output_tokens if params else None
416
+
417
+ @classmethod
418
+ def get_tokenizes(cls, model: str) -> list[str] | None:
419
+ """Get supported tokenization types for a model"""
420
+ params = cls.get_model_params(model)
421
+ return params.tokenizes if params else None
422
+
423
+ @classmethod
424
+ def supports_mime(cls, model: str, mime_type: str) -> bool:
425
+ """
426
+ Return True if the given model supports the provided MIME type.
427
+
428
+ Normalizes common aliases (e.g., image/jpg->image/jpeg, document/pdf->application/pdf)
429
+ and also accepts bare extensions like "pdf" or "png".
430
+ """
431
+ from fast_agent.mcp.mime_utils import normalize_mime_type
432
+
433
+ tokenizes = cls.get_tokenizes(model) or []
434
+
435
+ # Normalize the candidate and the database entries to lowercase
436
+ normalized_supported = [t.lower() for t in tokenizes]
437
+
438
+ # Handle wildcard inputs like "image/*" quickly
439
+ mt = (mime_type or "").strip().lower()
440
+ if mt.endswith("/*") and "/" in mt:
441
+ prefix = mt.split("/", 1)[0] + "/"
442
+ return any(s.startswith(prefix) for s in normalized_supported)
443
+
444
+ normalized = normalize_mime_type(mime_type)
445
+ if not normalized:
446
+ return False
447
+
448
+ return normalized.lower() in normalized_supported
449
+
450
+ @classmethod
451
+ def supports_any_mime(cls, model: str, mime_types: list[str]) -> bool:
452
+ """Return True if the model supports any of the provided MIME types."""
453
+ return any(cls.supports_mime(model, m) for m in mime_types)
454
+
455
+ @classmethod
456
+ def get_json_mode(cls, model: str) -> str | None:
457
+ """Get supported json mode (structured output) for a model"""
458
+ params = cls.get_model_params(model)
459
+ return params.json_mode if params else None
460
+
461
+ @classmethod
462
+ def get_reasoning(cls, model: str) -> str | None:
463
+ """Get supported reasoning output style for a model"""
464
+ params = cls.get_model_params(model)
465
+ return params.reasoning if params else None
466
+
467
+ @classmethod
468
+ def get_stream_mode(cls, model: str | None) -> Literal["openai", "manual"]:
469
+ """Return preferred streaming accumulation strategy for a model."""
470
+ if not model:
471
+ return "openai"
472
+
473
+ params = cls.get_model_params(model)
474
+ return params.stream_mode if params else "openai"
475
+
476
+ @classmethod
477
+ def get_default_max_tokens(cls, model: str) -> int:
478
+ """Get default max_tokens for RequestParams based on model"""
479
+ if not model:
480
+ return 2048 # Fallback when no model specified
481
+
482
+ params = cls.get_model_params(model)
483
+ if params:
484
+ return params.max_output_tokens
485
+ return 2048 # Fallback for unknown models
486
+
487
+ @classmethod
488
+ def list_models(cls) -> list[str]:
489
+ """List all available model names"""
490
+ return list(cls.MODELS.keys())