fast-agent-mcp 0.3.5__py3-none-any.whl → 0.3.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.

Potentially problematic release.


This version of fast-agent-mcp might be problematic. Click here for more details.

Files changed (41) hide show
  1. fast_agent/__init__.py +9 -1
  2. fast_agent/agents/agent_types.py +11 -11
  3. fast_agent/agents/llm_agent.py +76 -40
  4. fast_agent/agents/llm_decorator.py +355 -6
  5. fast_agent/agents/mcp_agent.py +154 -59
  6. fast_agent/agents/tool_agent.py +60 -4
  7. fast_agent/agents/workflow/router_agent.py +10 -2
  8. fast_agent/cli/commands/auth.py +52 -29
  9. fast_agent/cli/commands/check_config.py +26 -5
  10. fast_agent/cli/commands/go.py +11 -5
  11. fast_agent/cli/commands/setup.py +4 -7
  12. fast_agent/config.py +4 -1
  13. fast_agent/constants.py +2 -0
  14. fast_agent/core/agent_app.py +2 -0
  15. fast_agent/core/direct_factory.py +39 -120
  16. fast_agent/core/fastagent.py +2 -2
  17. fast_agent/history/history_exporter.py +3 -3
  18. fast_agent/llm/fastagent_llm.py +3 -3
  19. fast_agent/llm/provider/openai/llm_openai.py +57 -8
  20. fast_agent/mcp/__init__.py +1 -2
  21. fast_agent/mcp/mcp_aggregator.py +34 -1
  22. fast_agent/mcp/mcp_connection_manager.py +23 -4
  23. fast_agent/mcp/oauth_client.py +32 -4
  24. fast_agent/mcp/prompt_message_extended.py +2 -0
  25. fast_agent/mcp/prompt_serialization.py +124 -39
  26. fast_agent/mcp/prompts/prompt_load.py +34 -32
  27. fast_agent/mcp/prompts/prompt_server.py +26 -11
  28. fast_agent/resources/setup/.gitignore +6 -0
  29. fast_agent/resources/setup/agent.py +8 -1
  30. fast_agent/resources/setup/fastagent.config.yaml +2 -2
  31. fast_agent/resources/setup/pyproject.toml.tmpl +6 -0
  32. fast_agent/types/__init__.py +3 -1
  33. fast_agent/ui/console_display.py +48 -31
  34. fast_agent/ui/enhanced_prompt.py +119 -64
  35. fast_agent/ui/interactive_prompt.py +66 -40
  36. fast_agent/ui/rich_progress.py +12 -8
  37. {fast_agent_mcp-0.3.5.dist-info → fast_agent_mcp-0.3.7.dist-info}/METADATA +3 -3
  38. {fast_agent_mcp-0.3.5.dist-info → fast_agent_mcp-0.3.7.dist-info}/RECORD +41 -41
  39. {fast_agent_mcp-0.3.5.dist-info → fast_agent_mcp-0.3.7.dist-info}/WHEEL +0 -0
  40. {fast_agent_mcp-0.3.5.dist-info → fast_agent_mcp-0.3.7.dist-info}/entry_points.txt +0 -0
  41. {fast_agent_mcp-0.3.5.dist-info → fast_agent_mcp-0.3.7.dist-info}/licenses/LICENSE +0 -0
@@ -23,6 +23,7 @@ from mcp.types import (
23
23
  EmbeddedResource,
24
24
  GetPromptResult,
25
25
  ImageContent,
26
+ PromptMessage,
26
27
  TextContent,
27
28
  TextResourceContents,
28
29
  )
@@ -34,12 +35,30 @@ from fast_agent.mcp.prompts.prompt_constants import (
34
35
  )
35
36
  from fast_agent.types import PromptMessageExtended
36
37
 
38
+ # -------------------------------------------------------------------------
39
+ # Serialization Helpers
40
+ # -------------------------------------------------------------------------
41
+
42
+
43
+ def serialize_to_dict(obj, exclude_none: bool = True):
44
+ """Standardized Pydantic serialization to dictionary.
45
+
46
+ Args:
47
+ obj: Pydantic model object to serialize
48
+ exclude_none: Whether to exclude None values (default: True)
49
+
50
+ Returns:
51
+ Dictionary representation suitable for JSON serialization
52
+ """
53
+ return obj.model_dump(by_alias=True, mode="json", exclude_none=exclude_none)
54
+
55
+
37
56
  # -------------------------------------------------------------------------
38
57
  # JSON Serialization Functions
39
58
  # -------------------------------------------------------------------------
40
59
 
41
60
 
42
- def multipart_messages_to_get_prompt_result(
61
+ def to_get_prompt_result(
43
62
  messages: List[PromptMessageExtended],
44
63
  ) -> GetPromptResult:
45
64
  """
@@ -60,35 +79,58 @@ def multipart_messages_to_get_prompt_result(
60
79
  return GetPromptResult(messages=flat_messages)
61
80
 
62
81
 
63
- def multipart_messages_to_json(messages: List[PromptMessageExtended]) -> str:
82
+
83
+ def to_get_prompt_result_json(messages: List[PromptMessageExtended]) -> str:
84
+ """
85
+ Convert PromptMessageExtended objects to MCP-compatible GetPromptResult JSON.
86
+
87
+ This is a lossy conversion that flattens multipart messages and loses extended fields
88
+ like tool_calls, channels, and stop_reason. Use for MCP server compatibility.
89
+
90
+ Args:
91
+ messages: List of PromptMessageExtended objects
92
+
93
+ Returns:
94
+ JSON string in GetPromptResult format
95
+ """
96
+ result = to_get_prompt_result(messages)
97
+ result_dict = serialize_to_dict(result)
98
+ return json.dumps(result_dict, indent=2)
99
+
100
+
101
+ def to_json(messages: List[PromptMessageExtended]) -> str:
64
102
  """
65
- Convert PromptMessageExtended objects to a pure JSON string in GetPromptResult format.
103
+ Convert PromptMessageExtended objects directly to JSON, preserving all extended fields.
66
104
 
67
- This approach preserves all data and structure exactly as is, compatible with
68
- the MCP GetPromptResult type.
105
+ This preserves tool_calls, tool_results, channels, and stop_reason that would be lost
106
+ in the standard GetPromptResult conversion.
69
107
 
70
108
  Args:
71
109
  messages: List of PromptMessageExtended objects
72
110
 
73
111
  Returns:
74
- JSON string representation with GetPromptResult container
112
+ JSON string representation preserving all PromptMessageExtended data
75
113
  """
76
- # First convert to GetPromptResult
77
- result = multipart_messages_to_get_prompt_result(messages)
114
+ # Convert each message to dict using standardized serialization
115
+ messages_dicts = [serialize_to_dict(msg) for msg in messages]
78
116
 
79
- # Convert to dictionary using model_dump with proper JSON mode
80
- result_dict = result.model_dump(by_alias=True, mode="json", exclude_none=True)
117
+ # Wrap in a container similar to GetPromptResult for consistency
118
+ result_dict = {"messages": messages_dicts}
81
119
 
82
120
  # Convert to JSON string
83
121
  return json.dumps(result_dict, indent=2)
84
122
 
85
123
 
86
- def json_to_extended_messages(json_str: str) -> List[PromptMessageExtended]:
124
+ def from_json(json_str: str) -> List[PromptMessageExtended]:
87
125
  """
88
- Parse a JSON string in GetPromptResult format into PromptMessageExtended objects.
126
+ Parse a JSON string into PromptMessageExtended objects.
127
+
128
+ Handles both:
129
+ - Enhanced format with full PromptMessageExtended data
130
+ - Legacy GetPromptResult format (missing extended fields default to None)
89
131
 
90
132
  Args:
91
- json_str: JSON string representation of GetPromptResult
133
+ json_str: JSON string representation
92
134
 
93
135
  Returns:
94
136
  List of PromptMessageExtended objects
@@ -96,31 +138,66 @@ def json_to_extended_messages(json_str: str) -> List[PromptMessageExtended]:
96
138
  # Parse JSON to dictionary
97
139
  result_dict = json.loads(json_str)
98
140
 
99
- # Parse as GetPromptResult
100
- result = GetPromptResult.model_validate(result_dict)
141
+ # Extract messages array
142
+ messages_data = result_dict.get("messages", [])
143
+
144
+ extended_messages: List[PromptMessageExtended] = []
145
+ basic_buffer: List[PromptMessage] = []
146
+
147
+ def flush_basic_buffer() -> None:
148
+ nonlocal basic_buffer
149
+ if not basic_buffer:
150
+ return
151
+ extended_messages.extend(PromptMessageExtended.to_extended(basic_buffer))
152
+ basic_buffer = []
153
+
154
+ for msg_data in messages_data:
155
+ content = msg_data.get("content")
156
+ is_enhanced = isinstance(content, list)
157
+ if is_enhanced:
158
+ try:
159
+ msg = PromptMessageExtended.model_validate(msg_data)
160
+ except Exception:
161
+ is_enhanced = False
162
+ else:
163
+ flush_basic_buffer()
164
+ extended_messages.append(msg)
165
+ continue
166
+
167
+ try:
168
+ basic_msg = PromptMessage.model_validate(msg_data)
169
+ except Exception:
170
+ continue
171
+ basic_buffer.append(basic_msg)
101
172
 
102
- # Convert to multipart messages
103
- return PromptMessageExtended.to_extended(result.messages)
173
+ flush_basic_buffer()
104
174
 
175
+ return extended_messages
105
176
 
106
- def save_messages_to_json_file(messages: List[PromptMessageExtended], file_path: str) -> None:
177
+
178
+ def save_json(messages: List[PromptMessageExtended], file_path: str) -> None:
107
179
  """
108
- Save PromptMessageExtended objects to a JSON file.
180
+ Save PromptMessageExtended objects to a JSON file using enhanced format.
181
+
182
+ Uses the enhanced format that preserves tool_calls, tool_results, channels,
183
+ and stop_reason data.
109
184
 
110
185
  Args:
111
186
  messages: List of PromptMessageExtended objects
112
187
  file_path: Path to save the JSON file
113
188
  """
114
- json_str = multipart_messages_to_json(messages)
189
+ json_str = to_json(messages)
115
190
 
116
191
  with open(file_path, "w", encoding="utf-8") as f:
117
192
  f.write(json_str)
118
193
 
119
194
 
120
- def load_messages_from_json_file(file_path: str) -> List[PromptMessageExtended]:
195
+ def load_json(file_path: str) -> List[PromptMessageExtended]:
121
196
  """
122
197
  Load PromptMessageExtended objects from a JSON file.
123
198
 
199
+ Handles both enhanced format and legacy GetPromptResult format.
200
+
124
201
  Args:
125
202
  file_path: Path to the JSON file
126
203
 
@@ -130,14 +207,14 @@ def load_messages_from_json_file(file_path: str) -> List[PromptMessageExtended]:
130
207
  with open(file_path, "r", encoding="utf-8") as f:
131
208
  json_str = f.read()
132
209
 
133
- return json_to_extended_messages(json_str)
210
+ return from_json(json_str)
134
211
 
135
212
 
136
- def save_messages_to_file(messages: List[PromptMessageExtended], file_path: str) -> None:
213
+ def save_messages(messages: List[PromptMessageExtended], file_path: str) -> None:
137
214
  """
138
215
  Save PromptMessageExtended objects to a file, with format determined by file extension.
139
216
 
140
- Uses GetPromptResult JSON format for .json files (fully MCP compatible) and
217
+ Uses enhanced JSON format for .json files (preserves all fields) and
141
218
  delimited text format for other extensions.
142
219
 
143
220
  Args:
@@ -147,19 +224,16 @@ def save_messages_to_file(messages: List[PromptMessageExtended], file_path: str)
147
224
  path_str = str(file_path).lower()
148
225
 
149
226
  if path_str.endswith(".json"):
150
- # Use GetPromptResult JSON format for .json files (fully MCP compatible)
151
- save_messages_to_json_file(messages, file_path)
227
+ save_json(messages, file_path)
152
228
  else:
153
- # Use delimited text format for other extensions
154
- save_messages_to_delimited_file(messages, file_path)
229
+ save_delimited(messages, file_path)
155
230
 
156
231
 
157
- def load_messages_from_file(file_path: str) -> List[PromptMessageExtended]:
232
+ def load_messages(file_path: str) -> List[PromptMessageExtended]:
158
233
  """
159
234
  Load PromptMessageExtended objects from a file, with format determined by file extension.
160
235
 
161
- Uses GetPromptResult JSON format for .json files (fully MCP compatible) and
162
- delimited text format for other extensions.
236
+ Uses JSON format for .json files and delimited text format for other extensions.
163
237
 
164
238
  Args:
165
239
  file_path: Path to the file
@@ -170,11 +244,9 @@ def load_messages_from_file(file_path: str) -> List[PromptMessageExtended]:
170
244
  path_str = str(file_path).lower()
171
245
 
172
246
  if path_str.endswith(".json"):
173
- # Use GetPromptResult JSON format for .json files (fully MCP compatible)
174
- return load_messages_from_json_file(file_path)
247
+ return load_json(file_path)
175
248
  else:
176
- # Use delimited text format for other extensions
177
- return load_messages_from_delimited_file(file_path)
249
+ return load_delimited(file_path)
178
250
 
179
251
 
180
252
  # -------------------------------------------------------------------------
@@ -238,7 +310,7 @@ def multipart_messages_to_delimited_format(
238
310
  delimited_content.append(resource_delimiter)
239
311
 
240
312
  # Convert to dictionary using proper JSON mode
241
- content_dict = content.model_dump(by_alias=True, mode="json", exclude_none=True)
313
+ content_dict = serialize_to_dict(content)
242
314
 
243
315
  # Add to delimited content as JSON
244
316
  delimited_content.append(json.dumps(content_dict, indent=2))
@@ -253,7 +325,7 @@ def multipart_messages_to_delimited_format(
253
325
  delimited_content.append(resource_delimiter)
254
326
 
255
327
  # Convert to dictionary using proper JSON mode
256
- content_dict = content.model_dump(by_alias=True, mode="json", exclude_none=True)
328
+ content_dict = serialize_to_dict(content)
257
329
 
258
330
  # Add to delimited content as JSON
259
331
  delimited_content.append(json.dumps(content_dict, indent=2))
@@ -281,6 +353,17 @@ def delimited_format_to_extended_messages(
281
353
  Returns:
282
354
  List of PromptMessageExtended objects
283
355
  """
356
+ if user_delimiter not in content and assistant_delimiter not in content:
357
+ stripped = content.strip()
358
+ if not stripped:
359
+ return []
360
+ return [
361
+ PromptMessageExtended(
362
+ role="user",
363
+ content=[TextContent(type="text", text=stripped)],
364
+ )
365
+ ]
366
+
284
367
  lines = content.split("\n")
285
368
  messages = []
286
369
 
@@ -365,11 +448,13 @@ def delimited_format_to_extended_messages(
365
448
  resource_uri = f"resource://fast-agent/{resource_uri}"
366
449
 
367
450
  # Create a simple resource with just the URI
451
+ # For legacy format, we don't have the actual content, just the reference
368
452
  resource = EmbeddedResource(
369
453
  type="resource",
370
454
  resource=TextResourceContents(
371
455
  uri=resource_uri,
372
456
  mimeType="text/plain",
457
+ text="", # Legacy format doesn't include content
373
458
  ),
374
459
  )
375
460
  resource_contents.append(resource)
@@ -436,7 +521,7 @@ def delimited_format_to_extended_messages(
436
521
  return messages
437
522
 
438
523
 
439
- def save_messages_to_delimited_file(
524
+ def save_delimited(
440
525
  messages: List[PromptMessageExtended],
441
526
  file_path: str,
442
527
  user_delimiter: str = USER_DELIMITER,
@@ -467,7 +552,7 @@ def save_messages_to_delimited_file(
467
552
  f.write("\n".join(delimited_content))
468
553
 
469
554
 
470
- def load_messages_from_delimited_file(
555
+ def load_delimited(
471
556
  file_path: str,
472
557
  user_delimiter: str = USER_DELIMITER,
473
558
  assistant_delimiter: str = ASSISTANT_DELIMITER,
@@ -12,8 +12,6 @@ from fast_agent.core.logging.logger import get_logger
12
12
  from fast_agent.mcp import mime_utils, resource_utils
13
13
  from fast_agent.mcp.prompts.prompt_template import (
14
14
  PromptContent,
15
- PromptTemplate,
16
- PromptTemplateLoader,
17
15
  )
18
16
  from fast_agent.types import PromptMessageExtended
19
17
 
@@ -100,58 +98,62 @@ def create_resource_message(
100
98
  return message_class(content=embedded_resource)
101
99
 
102
100
 
103
- def load_prompt(file: Path) -> List[PromptMessage]:
101
+ def load_prompt(file: Path) -> List[PromptMessageExtended]:
104
102
  """
105
- Load a prompt from a file and return as PromptMessage objects.
103
+ Load a prompt from a file and return as PromptMessageExtended objects.
106
104
 
107
105
  The loader uses file extension to determine the format:
108
- - .json files are loaded as MCP SDK compatible GetPromptResult JSON format
109
- - All other files are loaded using the template-based delimited format
106
+ - .json files are loaded using enhanced format that preserves tool_calls, channels, etc.
107
+ - All other files are loaded using the template-based delimited format with resource loading
110
108
 
111
109
  Args:
112
110
  file: Path to the prompt file
113
111
 
114
112
  Returns:
115
- List of PromptMessage objects
113
+ List of PromptMessageExtended objects with full conversation state
116
114
  """
117
- file_str = str(file).lower()
115
+ path_str = str(file).lower()
118
116
 
119
- if file_str.endswith(".json"):
120
- # Handle JSON format as GetPromptResult
121
- import json
117
+ if path_str.endswith(".json"):
118
+ # JSON files use the serialization module directly
119
+ from fast_agent.mcp.prompt_serialization import load_messages
120
+ return load_messages(str(file))
121
+ else:
122
+ # Non-JSON files need template processing for resource loading
123
+ from fast_agent.mcp.prompts.prompt_template import PromptTemplateLoader
122
124
 
123
- from mcp.types import GetPromptResult
125
+ loader = PromptTemplateLoader()
126
+ template = loader.load_from_file(file)
124
127
 
125
- # Load JSON directly into GetPromptResult
126
- with open(file, "r", encoding="utf-8") as f:
127
- json_data = json.load(f)
128
+ # Render the template without arguments to get the messages
129
+ messages = create_messages_with_resources(
130
+ template.content_sections,
131
+ [file] # Pass the file path for resource resolution
132
+ )
133
+
134
+ # Convert to PromptMessageExtended
135
+ return PromptMessageExtended.to_extended(messages)
128
136
 
129
- # Parse as GetPromptResult object
130
- result = GetPromptResult.model_validate(json_data)
131
137
 
132
- # Return the messages directly
133
- return result.messages
134
- else:
135
- # Template-based format (delimited text)
136
- template: PromptTemplate = PromptTemplateLoader().load_from_file(file)
137
- return create_messages_with_resources(template.content_sections, [file])
138
138
 
139
139
 
140
- def load_prompt_multipart(file: Path) -> List[PromptMessageExtended]:
140
+ def load_prompt_as_get_prompt_result(file: Path):
141
141
  """
142
- Load a prompt from a file and return as PromptMessageExtended objects.
142
+ Load a prompt from a file and convert to GetPromptResult format for MCP compatibility.
143
143
 
144
- The loader uses file extension to determine the format:
145
- - .json files are loaded as MCP SDK compatible GetPromptResult JSON format
146
- - All other files are loaded using the template-based delimited format
144
+ This loses extended fields (tool_calls, channels, etc.) but provides
145
+ compatibility with MCP prompt servers.
147
146
 
148
147
  Args:
149
148
  file: Path to the prompt file
150
149
 
151
150
  Returns:
152
- List of PromptMessageExtended objects
151
+ GetPromptResult object for MCP compatibility
153
152
  """
154
- # First load as regular PromptMessage objects
153
+ from fast_agent.mcp.prompt_serialization import to_get_prompt_result
154
+
155
+ # Load with full data
155
156
  messages = load_prompt(file)
156
- # Then convert to multipart messages
157
- return PromptMessageExtended.to_extended(messages)
157
+
158
+ # Convert to GetPromptResult (loses extended fields)
159
+ return to_get_prompt_result(messages)
@@ -11,7 +11,7 @@ import base64
11
11
  import logging
12
12
  import sys
13
13
  from pathlib import Path
14
- from typing import Any, Awaitable, Callable, Dict, List, Optional
14
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Union
15
15
 
16
16
  from mcp.server.fastmcp import FastMCP
17
17
  from mcp.server.fastmcp.prompts.base import (
@@ -38,6 +38,7 @@ from fast_agent.mcp.prompts.prompt_template import (
38
38
  PromptMetadata,
39
39
  PromptTemplateLoader,
40
40
  )
41
+ from fast_agent.types import PromptMessageExtended
41
42
 
42
43
  # Configure logging
43
44
  logging.basicConfig(level=logging.ERROR)
@@ -47,13 +48,13 @@ logger = logging.getLogger("prompt_server")
47
48
  mcp = FastMCP("Prompt Server")
48
49
 
49
50
 
50
- def convert_to_fastmcp_messages(prompt_messages: List[PromptMessage]) -> List[Message]:
51
+ def convert_to_fastmcp_messages(prompt_messages: List[Union[PromptMessage, PromptMessageExtended]]) -> List[Message]:
51
52
  """
52
- Convert PromptMessage objects from prompt_load to FastMCP Message objects.
53
- This adapter prevents double-wrapping of messages.
53
+ Convert PromptMessage or PromptMessageExtended objects to FastMCP Message objects.
54
+ This adapter prevents double-wrapping of messages and handles both types.
54
55
 
55
56
  Args:
56
- prompt_messages: List of PromptMessage objects from prompt_load
57
+ prompt_messages: List of PromptMessage or PromptMessageExtended objects
57
58
 
58
59
  Returns:
59
60
  List of FastMCP Message objects
@@ -61,13 +62,27 @@ def convert_to_fastmcp_messages(prompt_messages: List[PromptMessage]) -> List[Me
61
62
  result = []
62
63
 
63
64
  for msg in prompt_messages:
64
- if msg.role == "user":
65
- result.append(UserMessage(content=msg.content))
66
- elif msg.role == "assistant":
67
- result.append(AssistantMessage(content=msg.content))
65
+ # Handle both PromptMessage and PromptMessageExtended
66
+ if hasattr(msg, 'from_multipart'):
67
+ # PromptMessageExtended - convert to regular PromptMessage format
68
+ flat_messages = msg.from_multipart()
69
+ for flat_msg in flat_messages:
70
+ if flat_msg.role == "user":
71
+ result.append(UserMessage(content=flat_msg.content))
72
+ elif flat_msg.role == "assistant":
73
+ result.append(AssistantMessage(content=flat_msg.content))
74
+ else:
75
+ logger.warning(f"Unknown message role: {flat_msg.role}, defaulting to user")
76
+ result.append(UserMessage(content=flat_msg.content))
68
77
  else:
69
- logger.warning(f"Unknown message role: {msg.role}, defaulting to user")
70
- result.append(UserMessage(content=msg.content))
78
+ # Regular PromptMessage - use directly
79
+ if msg.role == "user":
80
+ result.append(UserMessage(content=msg.content))
81
+ elif msg.role == "assistant":
82
+ result.append(AssistantMessage(content=msg.content))
83
+ else:
84
+ logger.warning(f"Unknown message role: {msg.role}, defaulting to user")
85
+ result.append(UserMessage(content=msg.content))
71
86
 
72
87
  return result
73
88
 
@@ -22,3 +22,9 @@ fastagent.jsonl
22
22
  # Editors (optional)
23
23
  .idea/
24
24
  .vscode/
25
+
26
+ # Packaging metadata
27
+ *.dist-info/
28
+ *.egg-info/
29
+ dist/
30
+ build/
@@ -6,8 +6,15 @@ from fast_agent import FastAgent
6
6
  fast = FastAgent("fast-agent example")
7
7
 
8
8
 
9
+ default_instruction = """You are a helpful AI Agent.
10
+
11
+ {{serverInstructions}}
12
+
13
+ The current date is {{currentDate}}."""
14
+
15
+
9
16
  # Define the agent
10
- @fast.agent(instruction="You are a helpful AI Agent")
17
+ @fast.agent(instruction=default_instruction)
11
18
  async def main():
12
19
  # use the --model command line switch or agent arguments to change model
13
20
  async with fast.run() as agent:
@@ -7,10 +7,10 @@
7
7
  # Accepts aliases for Anthropic Models: haiku, haiku3, sonnet, sonnet35, opus, opus3
8
8
  # and OpenAI Models: gpt-4.1, gpt-4.1-mini, o1, o1-mini, o3-mini
9
9
  #
10
- # If not specified, defaults to "haiku".
10
+ # If not specified, defaults to "gpt-5-mini.low".
11
11
  # Can be overriden with a command line switch --model=<model>, or within the Agent constructor.
12
12
 
13
- default_model: haiku
13
+ default_model: gpt-5-mini.low
14
14
  # mcp-ui support: disabled, enabled or auto. "auto" opens the web browser on the asset automatically
15
15
  # mcp_ui_output_dir: ".fast-agent/ui" # Where to write MCP-UI HTML files (relative to CWD if not absolute)
16
16
  # mcp_ui_mode: enabled
@@ -15,3 +15,9 @@ package = true
15
15
  [project.scripts]
16
16
  fast-agent-app = "agent:main"
17
17
 
18
+ [build-system]
19
+ requires = ["setuptools>=64", "wheel"]
20
+ build-backend = "setuptools.build_meta"
21
+
22
+ [tool.setuptools]
23
+ py-modules = ["agent"]
@@ -18,7 +18,9 @@ from fast_agent.mcp.helpers.content_helpers import (
18
18
 
19
19
  # Public message model used across providers and MCP integration
20
20
  from fast_agent.mcp.prompt_message_extended import PromptMessageExtended
21
- from fast_agent.types.llm_stop_reason import LlmStopReason
21
+
22
+ # Stop reason enum - imported directly to avoid circular dependency
23
+ from .llm_stop_reason import LlmStopReason
22
24
 
23
25
  __all__ = [
24
26
  # Enums / types