fast-agent-mcp 0.2.46__py3-none-any.whl → 0.2.48__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 (30) hide show
  1. {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/METADATA +12 -12
  2. {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/RECORD +30 -27
  3. mcp_agent/agents/workflow/iterative_planner.py +572 -0
  4. mcp_agent/agents/workflow/orchestrator_agent.py +3 -3
  5. mcp_agent/agents/workflow/orchestrator_models.py +6 -6
  6. mcp_agent/cli/commands/go.py +17 -3
  7. mcp_agent/cli/main.py +2 -2
  8. mcp_agent/config.py +14 -0
  9. mcp_agent/core/agent_types.py +1 -0
  10. mcp_agent/core/direct_decorators.py +54 -0
  11. mcp_agent/core/direct_factory.py +42 -15
  12. mcp_agent/core/fastagent.py +4 -0
  13. mcp_agent/core/mermaid_utils.py +170 -0
  14. mcp_agent/llm/model_database.py +7 -7
  15. mcp_agent/llm/model_factory.py +5 -3
  16. mcp_agent/llm/provider_types.py +1 -0
  17. mcp_agent/llm/providers/augmented_llm_aliyun.py +1 -1
  18. mcp_agent/llm/providers/augmented_llm_anthropic.py +1 -1
  19. mcp_agent/llm/providers/augmented_llm_deepseek.py +4 -2
  20. mcp_agent/llm/providers/augmented_llm_google_oai.py +1 -1
  21. mcp_agent/llm/providers/augmented_llm_groq.py +30 -0
  22. mcp_agent/llm/providers/augmented_llm_openai.py +4 -1
  23. mcp_agent/llm/providers/augmented_llm_openrouter.py +1 -1
  24. mcp_agent/llm/providers/augmented_llm_tensorzero.py +1 -1
  25. mcp_agent/llm/providers/augmented_llm_xai.py +1 -1
  26. mcp_agent/resources/examples/workflows/orchestrator.py +5 -2
  27. mcp_agent/ui/console_display.py +104 -39
  28. {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/WHEEL +0 -0
  29. {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/entry_points.txt +0 -0
  30. {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,30 @@
1
+ from mcp_agent.core.request_params import RequestParams
2
+ from mcp_agent.llm.provider_types import Provider
3
+ from mcp_agent.llm.providers.augmented_llm_openai import OpenAIAugmentedLLM
4
+
5
+ GROQ_BASE_URL = "https://api.groq.com/openai/v1"
6
+ DEFAULT_GROQ_MODEL = ""
7
+
8
+
9
+ class GroqAugmentedLLM(OpenAIAugmentedLLM):
10
+ def __init__(self, *args, **kwargs) -> None:
11
+ super().__init__(*args, provider=Provider.GROQ, **kwargs)
12
+
13
+ def _initialize_default_params(self, kwargs: dict) -> RequestParams:
14
+ """Initialize Groq default parameters"""
15
+ chosen_model = kwargs.get("model", DEFAULT_GROQ_MODEL)
16
+
17
+ return RequestParams(
18
+ model=chosen_model,
19
+ systemPrompt=self.instruction,
20
+ parallel_tool_calls=False,
21
+ max_iterations=20,
22
+ use_history=True,
23
+ )
24
+
25
+ def _base_url(self) -> str:
26
+ base_url = None
27
+ if self.context.config and self.context.config.groq:
28
+ base_url = self.context.config.groq.base_url
29
+
30
+ return base_url if base_url else GROQ_BASE_URL
@@ -388,7 +388,10 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
388
388
 
389
389
  # ParsedChatCompletionMessage is compatible with ChatCompletionMessage
390
390
  # since it inherits from it, so we can use it directly
391
- messages.append(message)
391
+ # Convert to dict and remove None values
392
+ message_dict = message.model_dump()
393
+ message_dict = {k: v for k, v in message_dict.items() if v is not None}
394
+ messages.append(message_dict)
392
395
 
393
396
  message_text = message.content
394
397
  if await self._is_tool_stop_reason(choice.finish_reason) and message.tool_calls:
@@ -32,7 +32,7 @@ class OpenRouterAugmentedLLM(OpenAIAugmentedLLM):
32
32
  model=chosen_model, # Will be validated by base class
33
33
  systemPrompt=self.instruction,
34
34
  parallel_tool_calls=True, # Default based on OpenAI provider
35
- max_iterations=10, # Default based on OpenAI provider
35
+ max_iterations=20, # Default based on OpenAI provider
36
36
  use_history=True, # Default based on OpenAI provider
37
37
  )
38
38
 
@@ -92,7 +92,7 @@ class TensorZeroAugmentedLLM(AugmentedLLM[Dict[str, Any], Any]):
92
92
  systemPrompt=self.instruction,
93
93
  maxTokens=4096,
94
94
  use_history=True,
95
- max_iterations=10, # Max iterations for tool use loop
95
+ max_iterations=20, # Max iterations for tool use loop
96
96
  parallel_tool_calls=True,
97
97
  )
98
98
 
@@ -22,7 +22,7 @@ class XAIAugmentedLLM(OpenAIAugmentedLLM):
22
22
  model=chosen_model,
23
23
  systemPrompt=self.instruction,
24
24
  parallel_tool_calls=False,
25
- max_iterations=10,
25
+ max_iterations=20,
26
26
  use_history=True,
27
27
  )
28
28
 
@@ -43,8 +43,11 @@ fast = FastAgent("Orchestrator-Workers")
43
43
  model="gpt-4.1",
44
44
  )
45
45
  # Define the orchestrator to coordinate the other agents
46
- @fast.orchestrator(
47
- name="orchestrate", agents=["finder", "writer", "proofreader"], plan_type="full", model="sonnet"
46
+ @fast.iterative_planner(
47
+ name="orchestrate",
48
+ agents=["finder", "writer", "proofreader"],
49
+ model="sonnet",
50
+ plan_iterations=5,
48
51
  )
49
52
  async def main() -> None:
50
53
  async with fast.run() as agent:
@@ -7,6 +7,11 @@ from rich.panel import Panel
7
7
  from rich.text import Text
8
8
 
9
9
  from mcp_agent import console
10
+ from mcp_agent.core.mermaid_utils import (
11
+ create_mermaid_live_link,
12
+ detect_diagram_type,
13
+ extract_mermaid_diagrams,
14
+ )
10
15
  from mcp_agent.mcp.common import SEP
11
16
  from mcp_agent.mcp.mcp_aggregator import MCPAggregator
12
17
 
@@ -158,29 +163,29 @@ class ConsoleDisplay:
158
163
  content = content[:360] + "..."
159
164
  console.console.print(content, style="dim", markup=self._markup)
160
165
 
161
- # Bottom separator with tool list: [tool1] [tool2] ────────
166
+ # Bottom separator with tool list using pipe separators (matching server style)
162
167
  console.console.print()
168
+
169
+ # Use existing tool list formatting with pipe separators
163
170
  if display_tool_list and len(display_tool_list) > 0:
164
- # Truncate tool list if needed (leave space for " " prefix and some separator)
171
+ # Truncate tool list if needed (leave space for "─| " prefix and " |" suffix)
165
172
  max_tool_width = console.console.size.width - 10 # Reserve space for separators
166
173
  truncated_tool_list = self._truncate_list_if_needed(display_tool_list, max_tool_width)
167
- tool_width = truncated_tool_list.cell_len
168
-
169
- # Calculate how much space is left for separator line on the right
170
- total_width = console.console.size.width
171
- remaining_width = max(0, total_width - tool_width - 2) # -2 for "─ " prefix
172
- right_sep = "─" * remaining_width if remaining_width > 0 else ""
173
-
174
- # Create the separator line: ─ [tools] ────────
175
- combined = Text()
176
- combined.append("─ ", style="dim")
177
- combined.append_text(truncated_tool_list)
178
- combined.append(right_sep, style="dim")
179
174
 
180
- console.console.print(combined, markup=self._markup)
175
+ # Create the separator line: ─| [tools] |──────
176
+ line1 = Text()
177
+ line1.append("─| ", style="dim")
178
+ line1.append_text(truncated_tool_list)
179
+ line1.append(" |", style="dim")
180
+ remaining = console.console.size.width - line1.cell_len
181
+ if remaining > 0:
182
+ line1.append("─" * remaining, style="dim")
181
183
  else:
182
- # Full separator if no tools
183
- console.console.print("─" * console.console.size.width, style="dim")
184
+ # No tools - continuous bar
185
+ line1 = Text()
186
+ line1.append("─" * console.console.size.width, style="dim")
187
+
188
+ console.console.print(line1, markup=self._markup)
184
189
  console.console.print()
185
190
 
186
191
  async def show_tool_update(self, aggregator: MCPAggregator | None, updated_server: str) -> None:
@@ -224,6 +229,8 @@ class ConsoleDisplay:
224
229
  def _format_tool_list(self, available_tools, selected_tool_name):
225
230
  """Format the list of available tools, highlighting the selected one."""
226
231
  display_tool_list = Text()
232
+ matching_tools = []
233
+
227
234
  for display_tool in available_tools:
228
235
  # Handle both OpenAI and Anthropic tool formats
229
236
  if isinstance(display_tool, dict):
@@ -248,9 +255,15 @@ class ConsoleDisplay:
248
255
  )
249
256
 
250
257
  if selected_tool_name.split(SEP)[0] == parts[0]:
251
- style = "magenta" if tool_call_name == selected_tool_name else "dim white"
252
258
  shortened_name = parts[1] if len(parts[1]) <= 12 else parts[1][:11] + "…"
253
- display_tool_list.append(f"[{shortened_name}] ", style)
259
+ matching_tools.append((shortened_name, tool_call_name))
260
+
261
+ # Format with pipe separators instead of brackets
262
+ for i, (shortened_name, tool_call_name) in enumerate(matching_tools):
263
+ if i > 0:
264
+ display_tool_list.append(" | ", style="dim")
265
+ style = "magenta" if tool_call_name == selected_tool_name else "dim"
266
+ display_tool_list.append(shortened_name, style)
254
267
 
255
268
  return display_tool_list
256
269
 
@@ -379,31 +392,83 @@ class ConsoleDisplay:
379
392
  # Handle Rich Text objects directly
380
393
  console.console.print(message_text, markup=self._markup)
381
394
 
382
- # Bottom separator with server list: [server1] [server2] ────────
395
+ # Bottom separator with server list and diagrams
383
396
  console.console.print()
397
+
398
+ # Check for mermaid diagrams in the message content
399
+ diagrams = []
400
+ if isinstance(message_text, str):
401
+ diagrams = extract_mermaid_diagrams(message_text)
402
+
403
+ # Create server list with pipe separators (no "mcp:" prefix)
404
+ server_content = Text()
384
405
  if display_server_list and len(display_server_list) > 0:
385
- # Truncate server list if needed (leave space for "─ " prefix and some separator)
386
- max_server_width = console.console.size.width - 10 # Reserve space for separators
387
- truncated_server_list = self._truncate_list_if_needed(
388
- display_server_list, max_server_width
389
- )
390
- server_width = truncated_server_list.cell_len
406
+ # Convert the existing server list to pipe-separated format
407
+ servers = []
408
+ if aggregator:
409
+ for server_name in await aggregator.list_servers():
410
+ servers.append(server_name)
411
+
412
+ # Create pipe-separated server list
413
+ for i, server_name in enumerate(servers):
414
+ if i > 0:
415
+ server_content.append(" | ", style="dim")
416
+ # Highlight active server, dim inactive ones
417
+ mcp_server_name = (
418
+ highlight_namespaced_tool.split(SEP)[0]
419
+ if SEP in highlight_namespaced_tool
420
+ else highlight_namespaced_tool
421
+ )
422
+ style = "bright_green" if server_name == mcp_server_name else "dim"
423
+ server_content.append(server_name, style)
424
+
425
+ # Create main separator line
426
+ line1 = Text()
427
+ if server_content.cell_len > 0:
428
+ line1.append("─| ", style="dim")
429
+ line1.append_text(server_content)
430
+ line1.append(" |", style="dim")
431
+ remaining = console.console.size.width - line1.cell_len
432
+ if remaining > 0:
433
+ line1.append("─" * remaining, style="dim")
434
+ else:
435
+ # No servers - continuous bar (no break)
436
+ line1.append("─" * console.console.size.width, style="dim")
391
437
 
392
- # Calculate how much space is left for separator line on the right
393
- total_width = console.console.size.width
394
- remaining_width = max(0, total_width - server_width - 2) # -2 for "─ " prefix
395
- right_sep = "─" * remaining_width if remaining_width > 0 else ""
438
+ console.console.print(line1, markup=self._markup)
396
439
 
397
- # Create the separator line: [servers] ────────
398
- combined = Text()
399
- combined.append("─ ", style="dim")
400
- combined.append_text(truncated_server_list)
401
- combined.append(right_sep, style="dim")
440
+ # Add diagram links in panel if any diagrams found
441
+ if diagrams:
442
+ diagram_content = Text()
443
+ # Add bullet at the beginning
444
+ diagram_content.append("● ", style="dim")
445
+
446
+ for i, diagram in enumerate(diagrams, 1):
447
+ if i > 1:
448
+ diagram_content.append(" • ", style="dim")
449
+
450
+ # Generate URL
451
+ url = create_mermaid_live_link(diagram.content)
452
+
453
+ # Format: "1 - Title" or "1 - Flowchart" or "Diagram 1"
454
+ if diagram.title:
455
+ diagram_content.append(
456
+ f"{i} - {diagram.title}", style=f"bright_blue link {url}"
457
+ )
458
+ else:
459
+ # Try to detect diagram type, fallback to "Diagram N"
460
+ diagram_type = detect_diagram_type(diagram.content)
461
+ if diagram_type != "Diagram":
462
+ diagram_content.append(
463
+ f"{i} - {diagram_type}", style=f"bright_blue link {url}"
464
+ )
465
+ else:
466
+ diagram_content.append(f"Diagram {i}", style=f"bright_blue link {url}")
467
+
468
+ # Display diagrams on a simple new line (more space efficient)
469
+ console.console.print()
470
+ console.console.print(diagram_content, markup=self._markup)
402
471
 
403
- console.console.print(combined, markup=self._markup)
404
- else:
405
- # Full separator if no servers
406
- console.console.print("─" * console.console.size.width, style="dim")
407
472
  console.console.print()
408
473
 
409
474
  def show_user_message(