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
@@ -19,7 +19,7 @@ app = typer.Typer(
19
19
 
20
20
 
21
21
  async def _run_agent(
22
- name: str = "FastAgent CLI",
22
+ name: str = "fast-agent cli",
23
23
  instruction: str = "You are a helpful AI Agent.",
24
24
  config_path: Optional[str] = None,
25
25
  server_list: Optional[List[str]] = None,
@@ -28,6 +28,7 @@ async def _run_agent(
28
28
  prompt_file: Optional[str] = None,
29
29
  url_servers: Optional[Dict[str, Dict[str, str]]] = None,
30
30
  stdio_servers: Optional[Dict[str, Dict[str, str]]] = None,
31
+ agent_name: Optional[str] = "agent",
31
32
  ) -> None:
32
33
  """Async implementation to run an interactive agent."""
33
34
  from pathlib import Path
@@ -35,6 +36,7 @@ async def _run_agent(
35
36
  from mcp_agent.mcp.prompts.prompt_load import load_prompt_multipart
36
37
 
37
38
  # Create the FastAgent instance
39
+
38
40
  fast_kwargs = {
39
41
  "name": name,
40
42
  "config_path": config_path,
@@ -103,6 +105,8 @@ async def _run_agent(
103
105
  # Single model - use original behavior
104
106
  # Define the agent with specified parameters
105
107
  agent_kwargs = {"instruction": instruction}
108
+ if agent_name:
109
+ agent_kwargs["name"] = agent_name
106
110
  if server_list:
107
111
  agent_kwargs["servers"] = server_list
108
112
  if model:
@@ -117,7 +121,7 @@ async def _run_agent(
117
121
  print(response)
118
122
  elif prompt_file:
119
123
  prompt = load_prompt_multipart(Path(prompt_file))
120
- response = await agent.default.generate(prompt)
124
+ response = await agent.generate(prompt)
121
125
  # Print the response text and exit
122
126
  print(response.last_text())
123
127
  else:
@@ -138,6 +142,7 @@ def run_async_agent(
138
142
  message: Optional[str] = None,
139
143
  prompt_file: Optional[str] = None,
140
144
  stdio_commands: Optional[List[str]] = None,
145
+ agent_name: Optional[str] = None,
141
146
  ):
142
147
  """Run the async agent function with proper loop handling."""
143
148
  server_list = servers.split(",") if servers else None
@@ -237,6 +242,7 @@ def run_async_agent(
237
242
  prompt_file=prompt_file,
238
243
  url_servers=url_servers,
239
244
  stdio_servers=stdio_servers,
245
+ agent_name=agent_name,
240
246
  )
241
247
  )
242
248
  finally:
@@ -258,7 +264,7 @@ def run_async_agent(
258
264
  @app.callback(invoke_without_command=True, no_args_is_help=False)
259
265
  def go(
260
266
  ctx: typer.Context,
261
- name: str = typer.Option("FastAgent CLI", "--name", help="Name for the agent"),
267
+ name: str = typer.Option("fast-agent", "--name", help="Name for the agent"),
262
268
  instruction: Optional[str] = typer.Option(
263
269
  None, "--instruction", "-i", help="Path to file or URL containing instruction for the agent"
264
270
  ),
@@ -338,6 +344,8 @@ def go(
338
344
 
339
345
  # Resolve instruction from file/URL or use default
340
346
  resolved_instruction = "You are a helpful AI Agent." # Default
347
+ agent_name = "agent"
348
+
341
349
  if instruction:
342
350
  try:
343
351
  from pathlib import Path
@@ -352,6 +360,11 @@ def go(
352
360
  else:
353
361
  # Treat as file path
354
362
  resolved_instruction = _resolve_instruction(Path(instruction))
363
+ # Extract filename without extension to use as agent name
364
+ instruction_path = Path(instruction)
365
+ if instruction_path.exists() and instruction_path.is_file():
366
+ # Get filename without extension
367
+ agent_name = instruction_path.stem
355
368
  except Exception as e:
356
369
  typer.echo(f"Error loading instruction from {instruction}: {e}", err=True)
357
370
  raise typer.Exit(1)
@@ -367,4 +380,5 @@ def go(
367
380
  message=message,
368
381
  prompt_file=prompt_file,
369
382
  stdio_commands=stdio_commands,
383
+ agent_name=agent_name,
370
384
  )
mcp_agent/cli/main.py CHANGED
@@ -8,7 +8,7 @@ from mcp_agent.cli.commands import check_config, go, quickstart, setup
8
8
  from mcp_agent.cli.terminal import Application
9
9
 
10
10
  app = typer.Typer(
11
- help="FastAgent CLI - Build effective agents using Model Context Protocol",
11
+ help="fast-agent - Build effective agents using Model Context Protocol",
12
12
  add_completion=False, # We'll add this later when we have more commands
13
13
  )
14
14
 
@@ -60,7 +60,7 @@ def main(
60
60
  color: bool = typer.Option(True, "--color/--no-color", help="Enable/disable color output"),
61
61
  version: bool = typer.Option(False, "--version", help="Show version and exit"),
62
62
  ) -> None:
63
- """FastAgent CLI - Build effective agents using Model Context Protocol (MCP).
63
+ """fast-agent - Build effective agents using Model Context Protocol (MCP).
64
64
 
65
65
  Use --help with any command for detailed usage information.
66
66
  """
mcp_agent/config.py CHANGED
@@ -224,6 +224,17 @@ class AzureSettings(BaseModel):
224
224
  model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
225
225
 
226
226
 
227
+ class GroqSettings(BaseModel):
228
+ """
229
+ Settings for using xAI Grok models in the fast-agent application.
230
+ """
231
+
232
+ api_key: str | None = None
233
+ base_url: str | None = "https://api.groq.com/openai/v1"
234
+
235
+ model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
236
+
237
+
227
238
  class OpenTelemetrySettings(BaseModel):
228
239
  """
229
240
  OTEL settings for the fast-agent application.
@@ -441,6 +452,9 @@ class Settings(BaseSettings):
441
452
  huggingface: HuggingFaceSettings | None = None
442
453
  """Settings for HuggingFace authentication (used for MCP connections)"""
443
454
 
455
+ groq: GroqSettings | None = None
456
+ """Settings for using the Groq provider in the fast-agent application"""
457
+
444
458
  logger: LoggerSettings | None = LoggerSettings()
445
459
  """Logger settings for the fast-agent application"""
446
460
 
@@ -22,6 +22,7 @@ class AgentType(Enum):
22
22
  EVALUATOR_OPTIMIZER = "evaluator_optimizer"
23
23
  ROUTER = "router"
24
24
  CHAIN = "chain"
25
+ ITERATIVE_PLANNER = "iterative_planner"
25
26
 
26
27
 
27
28
  @dataclass
@@ -25,6 +25,7 @@ from mcp.client.session import ElicitationFnT
25
25
  from pydantic import AnyUrl
26
26
 
27
27
  from mcp_agent.agents.agent import AgentConfig
28
+ from mcp_agent.agents.workflow.iterative_planner import ITERATIVE_PLAN_SYSTEM_PROMPT_TEMPLATE
28
29
  from mcp_agent.agents.workflow.router_agent import (
29
30
  ROUTING_SYSTEM_INSTRUCTION,
30
31
  )
@@ -457,6 +458,59 @@ def orchestrator(
457
458
  )
458
459
 
459
460
 
461
+ def iterative_planner(
462
+ self,
463
+ name: str,
464
+ *,
465
+ agents: List[str],
466
+ instruction: str | Path | AnyUrl = ITERATIVE_PLAN_SYSTEM_PROMPT_TEMPLATE,
467
+ model: Optional[str] = None,
468
+ request_params: RequestParams | None = None,
469
+ plan_iterations: int = -1,
470
+ default: bool = False,
471
+ api_key: str | None = None,
472
+ ) -> Callable[[AgentCallable[P, R]], DecoratedOrchestratorProtocol[P, R]]:
473
+ """
474
+ Decorator to create and register an orchestrator agent with type-safe signature.
475
+
476
+ Args:
477
+ name: Name of the orchestrator
478
+ agents: List of agent names this orchestrator can use
479
+ instruction: Base instruction for the orchestrator
480
+ model: Model specification string
481
+ use_history: Whether to maintain conversation history
482
+ request_params: Additional request parameters for the LLM
483
+ human_input: Whether to enable human input capabilities
484
+ plan_type: Planning approach - "full" or "iterative"
485
+ plan_iterations: Maximum number of planning iterations (0 for unlimited)
486
+ default: Whether to mark this as the default agent
487
+
488
+ Returns:
489
+ A decorator that registers the orchestrator with proper type annotations
490
+ """
491
+
492
+ # Create final request params with plan_iterations
493
+ resolved_instruction = _resolve_instruction(instruction)
494
+
495
+ return cast(
496
+ "Callable[[AgentCallable[P, R]], DecoratedOrchestratorProtocol[P, R]]",
497
+ _decorator_impl(
498
+ self,
499
+ AgentType.ITERATIVE_PLANNER,
500
+ name=name,
501
+ instruction=resolved_instruction,
502
+ servers=[], # Orchestrators don't connect to servers directly
503
+ model=model,
504
+ use_history=False,
505
+ request_params=request_params,
506
+ child_agents=agents,
507
+ plan_iterations=plan_iterations,
508
+ default=default,
509
+ api_key=api_key,
510
+ ),
511
+ )
512
+
513
+
460
514
  def router(
461
515
  self,
462
516
  name: str,
@@ -10,6 +10,7 @@ from mcp_agent.agents.workflow.evaluator_optimizer import (
10
10
  EvaluatorOptimizerAgent,
11
11
  QualityRating,
12
12
  )
13
+ from mcp_agent.agents.workflow.iterative_planner import IterativePlanner
13
14
  from mcp_agent.agents.workflow.orchestrator_agent import OrchestratorAgent
14
15
  from mcp_agent.agents.workflow.parallel_agent import ParallelAgent
15
16
  from mcp_agent.agents.workflow.router_agent import RouterAgent
@@ -21,9 +22,10 @@ from mcp_agent.event_progress import ProgressAction
21
22
  from mcp_agent.llm.augmented_llm import RequestParams
22
23
  from mcp_agent.llm.model_factory import ModelFactory
23
24
  from mcp_agent.logging.logger import get_logger
25
+ from mcp_agent.mcp.interfaces import AgentProtocol
24
26
 
25
27
  # Type aliases for improved readability and IDE support
26
- AgentDict = Dict[str, Agent]
28
+ AgentDict = Dict[str, AgentProtocol]
27
29
  AgentConfigDict = Dict[str, Dict[str, Any]]
28
30
  T = TypeVar("T") # For generic types
29
31
 
@@ -153,7 +155,7 @@ async def create_agents_by_type(
153
155
  await agent.attach_llm(
154
156
  llm_factory,
155
157
  request_params=config.default_request_params,
156
- api_key=config.api_key
158
+ api_key=config.api_key,
157
159
  )
158
160
  result_agents[name] = agent
159
161
 
@@ -172,11 +174,11 @@ async def create_agents_by_type(
172
174
  await agent.attach_llm(
173
175
  llm_factory,
174
176
  request_params=config.default_request_params,
175
- api_key=config.api_key
177
+ api_key=config.api_key,
176
178
  )
177
179
  result_agents[name] = agent
178
180
 
179
- elif agent_type == AgentType.ORCHESTRATOR:
181
+ elif agent_type == AgentType.ORCHESTRATOR or agent_type == AgentType.ITERATIVE_PLANNER:
180
182
  # Get base params configured with model settings
181
183
  base_params = (
182
184
  config.default_request_params.model_copy()
@@ -193,24 +195,35 @@ async def create_agents_by_type(
193
195
  agent = active_agents[agent_name]
194
196
  child_agents.append(agent)
195
197
 
196
- # Create the orchestrator
197
- orchestrator = OrchestratorAgent(
198
- config=config,
199
- context=app_instance.context,
200
- agents=child_agents,
201
- plan_iterations=agent_data.get("plan_iterations", 5),
202
- plan_type=agent_data.get("plan_type", "full"),
203
- )
198
+ if AgentType.ORCHESTRATOR == agent_type:
199
+ # Create the orchestrator
200
+ orchestrator = OrchestratorAgent(
201
+ config=config,
202
+ context=app_instance.context,
203
+ agents=child_agents,
204
+ plan_iterations=agent_data.get("plan_iterations", 5),
205
+ plan_type=agent_data.get("plan_type", "full"),
206
+ )
207
+ else:
208
+ orchestrator = IterativePlanner(
209
+ config=config,
210
+ context=app_instance.context,
211
+ agents=child_agents,
212
+ plan_iterations=agent_data.get("plan_iterations", 5),
213
+ plan_type=agent_data.get("plan_type", "full"),
214
+ )
204
215
 
205
216
  # Initialize the orchestrator
206
217
  await orchestrator.initialize()
207
218
 
208
219
  # Attach LLM to the orchestrator
209
220
  llm_factory = model_factory_func(model=config.model)
221
+
222
+ # print("************", config.default_request_params.instruction)
210
223
  await orchestrator.attach_llm(
211
224
  llm_factory,
212
225
  request_params=config.default_request_params,
213
- api_key=config.api_key
226
+ api_key=config.api_key,
214
227
  )
215
228
 
216
229
  result_agents[name] = orchestrator
@@ -274,7 +287,7 @@ async def create_agents_by_type(
274
287
  await router.attach_llm(
275
288
  llm_factory,
276
289
  request_params=config.default_request_params,
277
- api_key=config.api_key
290
+ api_key=config.api_key,
278
291
  )
279
292
  result_agents[name] = router
280
293
 
@@ -461,7 +474,6 @@ async def create_agents_in_dependency_order(
461
474
  )
462
475
  active_agents.update(evaluator_agents)
463
476
 
464
- # Create orchestrator agents last since they might depend on other agents
465
477
  if AgentType.ORCHESTRATOR.value in [agents_dict[name]["type"] for name in group]:
466
478
  orchestrator_agents = await create_agents_by_type(
467
479
  app_instance,
@@ -476,6 +488,21 @@ async def create_agents_in_dependency_order(
476
488
  )
477
489
  active_agents.update(orchestrator_agents)
478
490
 
491
+ # Create orchestrator2 agents last since they might depend on other agents
492
+ if AgentType.ITERATIVE_PLANNER.value in [agents_dict[name]["type"] for name in group]:
493
+ orchestrator2_agents = await create_agents_by_type(
494
+ app_instance,
495
+ {
496
+ name: agents_dict[name]
497
+ for name in group
498
+ if agents_dict[name]["type"] == AgentType.ITERATIVE_PLANNER.value
499
+ },
500
+ AgentType.ITERATIVE_PLANNER,
501
+ active_agents,
502
+ model_factory_func,
503
+ )
504
+ active_agents.update(orchestrator2_agents)
505
+
479
506
  return active_agents
480
507
 
481
508
 
@@ -31,6 +31,9 @@ from mcp_agent.core.direct_decorators import (
31
31
  from mcp_agent.core.direct_decorators import (
32
32
  evaluator_optimizer as evaluator_optimizer_decorator,
33
33
  )
34
+ from mcp_agent.core.direct_decorators import (
35
+ iterative_planner as orchestrator2_decorator,
36
+ )
34
37
  from mcp_agent.core.direct_decorators import (
35
38
  orchestrator as orchestrator_decorator,
36
39
  )
@@ -249,6 +252,7 @@ class FastAgent:
249
252
  agent = agent_decorator
250
253
  custom = custom_decorator
251
254
  orchestrator = orchestrator_decorator
255
+ iterative_planner = orchestrator2_decorator
252
256
  router = router_decorator
253
257
  chain = chain_decorator
254
258
  parallel = parallel_decorator
@@ -0,0 +1,170 @@
1
+ """Utilities for detecting and processing Mermaid diagrams in text content."""
2
+
3
+ import base64
4
+ import re
5
+ import zlib
6
+ from dataclasses import dataclass
7
+ from typing import List, Optional
8
+
9
+ # Mermaid chart viewer URL prefix
10
+ MERMAID_VIEWER_URL = "https://www.mermaidchart.com/play#"
11
+ # mermaid.live#pako= also works but the playground has better ux
12
+
13
+
14
+ @dataclass
15
+ class MermaidDiagram:
16
+ """Represents a detected Mermaid diagram."""
17
+
18
+ content: str
19
+ title: Optional[str] = None
20
+ start_pos: int = 0
21
+ end_pos: int = 0
22
+
23
+
24
+ def extract_mermaid_diagrams(text: str) -> List[MermaidDiagram]:
25
+ """
26
+ Extract all Mermaid diagram blocks from text content.
27
+
28
+ Handles both simple mermaid blocks and blocks with titles:
29
+ - ```mermaid
30
+ - ```mermaid title={Some Title}
31
+
32
+ Also extracts titles from within the diagram content.
33
+
34
+ Args:
35
+ text: The text content to search for Mermaid diagrams
36
+
37
+ Returns:
38
+ List of MermaidDiagram objects found in the text
39
+ """
40
+ diagrams = []
41
+
42
+ # Pattern to match mermaid code blocks with optional title
43
+ # Matches: ```mermaid or ```mermaid title={...}
44
+ pattern = r"```mermaid(?:\s+title=\{([^}]+)\})?\s*\n(.*?)```"
45
+
46
+ for match in re.finditer(pattern, text, re.DOTALL):
47
+ title = match.group(1) # May be None if no title
48
+ content = match.group(2).strip()
49
+
50
+ if content: # Only add if there's actual diagram content
51
+ # If no title from code fence, look for title in the content
52
+ if not title:
53
+ # Look for various title patterns in mermaid diagrams
54
+ # pie title, graph title, etc.
55
+ title_patterns = [
56
+ r"^\s*title\s+(.+?)(?:\n|$)", # Generic title
57
+ r"^\s*pie\s+title\s+(.+?)(?:\n|$)", # Pie chart title
58
+ r"^\s*gantt\s+title\s+(.+?)(?:\n|$)", # Gantt chart title
59
+ ]
60
+
61
+ for title_pattern in title_patterns:
62
+ title_match = re.search(title_pattern, content, re.MULTILINE)
63
+ if title_match:
64
+ title = title_match.group(1).strip()
65
+ break
66
+
67
+ diagrams.append(
68
+ MermaidDiagram(
69
+ content=content, title=title, start_pos=match.start(), end_pos=match.end()
70
+ )
71
+ )
72
+
73
+ return diagrams
74
+
75
+
76
+ def create_mermaid_live_link(diagram_content: str) -> str:
77
+ """
78
+ Create a Mermaid Live Editor link from diagram content.
79
+
80
+ The link uses pako compression (zlib) and base64 encoding.
81
+
82
+ Args:
83
+ diagram_content: The Mermaid diagram source code
84
+
85
+ Returns:
86
+ Complete URL to Mermaid Live Editor
87
+ """
88
+ # Create the JSON structure expected by Mermaid Live
89
+ # Escape newlines and quotes in the diagram content
90
+ escaped_content = diagram_content.replace('"', '\\"').replace("\n", "\\n")
91
+ json_str = f'{{"code":"{escaped_content}","mermaid":{{"theme":"default"}},"updateEditor":false,"autoSync":true,"updateDiagram":false}}'
92
+
93
+ # Compress using zlib (pako compatible)
94
+ compressed = zlib.compress(json_str.encode("utf-8"))
95
+
96
+ # Base64 encode
97
+ encoded = base64.urlsafe_b64encode(compressed).decode("utf-8")
98
+
99
+ # Remove padding characters as Mermaid Live doesn't use them
100
+ encoded = encoded.rstrip("=")
101
+
102
+ return f"{MERMAID_VIEWER_URL}pako:{encoded}"
103
+
104
+
105
+ def format_mermaid_links(diagrams: List[MermaidDiagram]) -> List[str]:
106
+ """
107
+ Format Mermaid diagrams as markdown links.
108
+
109
+ Args:
110
+ diagrams: List of MermaidDiagram objects
111
+
112
+ Returns:
113
+ List of formatted markdown strings
114
+ """
115
+ links = []
116
+
117
+ for i, diagram in enumerate(diagrams, 1):
118
+ link = create_mermaid_live_link(diagram.content)
119
+
120
+ if diagram.title:
121
+ # Use the title from the diagram with number
122
+ markdown = f"Diagram {i} - {diagram.title}: [Open Diagram]({link})"
123
+ else:
124
+ # Use generic numbering
125
+ markdown = f"Diagram {i}: [Open Diagram]({link})"
126
+
127
+ links.append(markdown)
128
+
129
+ return links
130
+
131
+
132
+ def detect_diagram_type(content: str) -> str:
133
+ """
134
+ Detect the type of mermaid diagram from content.
135
+
136
+ Args:
137
+ content: The mermaid diagram source code
138
+
139
+ Returns:
140
+ Human-readable diagram type name
141
+ """
142
+ content_lower = content.strip().lower()
143
+
144
+ # Check for common diagram types
145
+ if content_lower.startswith(("graph ", "flowchart ")):
146
+ return "Flowchart"
147
+ elif content_lower.startswith("sequencediagram"):
148
+ return "Sequence"
149
+ elif content_lower.startswith("pie"):
150
+ return "Pie Chart"
151
+ elif content_lower.startswith("gantt"):
152
+ return "Gantt Chart"
153
+ elif content_lower.startswith("classdiagram"):
154
+ return "Class Diagram"
155
+ elif content_lower.startswith("statediagram"):
156
+ return "State Diagram"
157
+ elif content_lower.startswith("erdiagram"):
158
+ return "ER Diagram"
159
+ elif content_lower.startswith("journey"):
160
+ return "User Journey"
161
+ elif content_lower.startswith("gitgraph"):
162
+ return "Git Graph"
163
+ elif content_lower.startswith("c4context"):
164
+ return "C4 Context"
165
+ elif content_lower.startswith("mindmap"):
166
+ return "Mind Map"
167
+ elif content_lower.startswith("timeline"):
168
+ return "Timeline"
169
+ else:
170
+ return "Diagram"
@@ -129,16 +129,16 @@ class ModelDatabase:
129
129
  context_window=2097152, max_output_tokens=8192, tokenizes=GOOGLE_MULTIMODAL
130
130
  )
131
131
 
132
- # 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)
133
- GROK_4 = ModelParameters(
134
- context_window=256000, max_output_tokens=16385, tokenizes=XAI_VISION
132
+ KIMI_MOONSHOT = ModelParameters(
133
+ context_window=131072, max_output_tokens=16384, tokenizes=TEXT_ONLY
135
134
  )
136
135
 
136
+ # 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)
137
+ GROK_4 = ModelParameters(context_window=256000, max_output_tokens=16385, tokenizes=XAI_VISION)
138
+
137
139
  # Source for Grok 3 max output: https://www.reddit.com/r/grok/comments/1j7209p/exploring_grok_3_beta_output_capacity_a_simple/
138
140
  # xAI does not document Grok 3 max output tokens, using the above source as a reference.
139
- GROK_3 = ModelParameters(
140
- context_window=131072, max_output_tokens=16385, tokenizes=TEXT_ONLY
141
- )
141
+ GROK_3 = ModelParameters(context_window=131072, max_output_tokens=16385, tokenizes=TEXT_ONLY)
142
142
 
143
143
  # Model configuration database
144
144
  MODELS: Dict[str, ModelParameters] = {
@@ -193,7 +193,6 @@ class ModelDatabase:
193
193
  "claude-3-7-sonnet": ANTHROPIC_37_SERIES,
194
194
  "claude-3-7-sonnet-20250219": ANTHROPIC_37_SERIES,
195
195
  "claude-3-7-sonnet-latest": ANTHROPIC_37_SERIES,
196
- "claude-sonnet-4": ANTHROPIC_SONNET_4_VERSIONED,
197
196
  "claude-sonnet-4-0": ANTHROPIC_SONNET_4_VERSIONED,
198
197
  "claude-sonnet-4-20250514": ANTHROPIC_SONNET_4_VERSIONED,
199
198
  "claude-opus-4": ANTHROPIC_OPUS_4_VERSIONED,
@@ -214,6 +213,7 @@ class ModelDatabase:
214
213
  "grok-3-mini": GROK_3,
215
214
  "grok-3-fast": GROK_3,
216
215
  "grok-3-mini-fast": GROK_3,
216
+ "moonshotai/kimi-k2-instruct": KIMI_MOONSHOT,
217
217
  }
218
218
 
219
219
  @classmethod
@@ -19,6 +19,7 @@ from mcp_agent.llm.providers.augmented_llm_deepseek import DeepSeekAugmentedLLM
19
19
  from mcp_agent.llm.providers.augmented_llm_generic import GenericAugmentedLLM
20
20
  from mcp_agent.llm.providers.augmented_llm_google_native import GoogleNativeAugmentedLLM
21
21
  from mcp_agent.llm.providers.augmented_llm_google_oai import GoogleOaiAugmentedLLM
22
+ from mcp_agent.llm.providers.augmented_llm_groq import GroqAugmentedLLM
22
23
  from mcp_agent.llm.providers.augmented_llm_openai import OpenAIAugmentedLLM
23
24
  from mcp_agent.llm.providers.augmented_llm_openrouter import OpenRouterAugmentedLLM
24
25
  from mcp_agent.llm.providers.augmented_llm_tensorzero import TensorZeroAugmentedLLM
@@ -43,6 +44,7 @@ LLMClass = Union[
43
44
  Type[GenericAugmentedLLM],
44
45
  Type[AzureOpenAIAugmentedLLM],
45
46
  Type[BedrockAugmentedLLM],
47
+ Type[GroqAugmentedLLM],
46
48
  ]
47
49
 
48
50
 
@@ -122,7 +124,6 @@ class ModelFactory:
122
124
  "qwen-plus": Provider.ALIYUN,
123
125
  "qwen-max": Provider.ALIYUN,
124
126
  "qwen-long": Provider.ALIYUN,
125
-
126
127
  }
127
128
 
128
129
  MODEL_ALIASES = {
@@ -159,6 +160,7 @@ class ModelFactory:
159
160
  Provider.AZURE: AzureOpenAIAugmentedLLM,
160
161
  Provider.ALIYUN: AliyunAugmentedLLM,
161
162
  Provider.BEDROCK: BedrockAugmentedLLM,
163
+ Provider.GROQ: GroqAugmentedLLM,
162
164
  }
163
165
 
164
166
  # Mapping of special model names to their specific LLM classes
@@ -213,11 +215,11 @@ class ModelFactory:
213
215
  # If provider still None, try to get from DEFAULT_PROVIDERS using the model_name_str
214
216
  if provider is None:
215
217
  provider = cls.DEFAULT_PROVIDERS.get(model_name_str)
216
-
218
+
217
219
  # If still None, try pattern matching for Bedrock models
218
220
  if provider is None and BedrockAugmentedLLM.matches_model_pattern(model_name_str):
219
221
  provider = Provider.BEDROCK
220
-
222
+
221
223
  if provider is None:
222
224
  raise ModelConfigError(
223
225
  f"Unknown model or provider for: {model_string}. Model name parsed as '{model_name_str}'"
@@ -28,3 +28,4 @@ class Provider(Enum):
28
28
  HUGGINGFACE = ("huggingface", "HuggingFace") # For HuggingFace MCP connections
29
29
  XAI = ("xai", "XAI") # For xAI Grok models
30
30
  BEDROCK = ("bedrock", "Bedrock")
31
+ GROQ = ("groq", "Groq")
@@ -18,7 +18,7 @@ class AliyunAugmentedLLM(OpenAIAugmentedLLM):
18
18
  model=chosen_model,
19
19
  systemPrompt=self.instruction,
20
20
  parallel_tool_calls=True,
21
- max_iterations=10,
21
+ max_iterations=20,
22
22
  use_history=True,
23
23
  )
24
24
 
@@ -46,7 +46,7 @@ from mcp_agent.llm.augmented_llm import (
46
46
  )
47
47
  from mcp_agent.logging.logger import get_logger
48
48
 
49
- DEFAULT_ANTHROPIC_MODEL = "claude-3-7-sonnet-latest"
49
+ DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-0"
50
50
 
51
51
 
52
52
  class AnthropicAugmentedLLM(AugmentedLLM[MessageParam, Message]):
@@ -28,7 +28,7 @@ class DeepSeekAugmentedLLM(OpenAIAugmentedLLM):
28
28
  model=chosen_model,
29
29
  systemPrompt=self.instruction,
30
30
  parallel_tool_calls=True,
31
- max_iterations=10,
31
+ max_iterations=20,
32
32
  use_history=True,
33
33
  )
34
34
 
@@ -85,7 +85,9 @@ class DeepSeekAugmentedLLM(OpenAIAugmentedLLM):
85
85
  return self._structured_from_multipart(result, model)
86
86
 
87
87
  @classmethod
88
- def convert_message_to_message_param(cls, message: ChatCompletionMessage, **kwargs) -> ChatCompletionAssistantMessageParam:
88
+ def convert_message_to_message_param(
89
+ cls, message: ChatCompletionMessage, **kwargs
90
+ ) -> ChatCompletionAssistantMessageParam:
89
91
  """Convert a response object to an input parameter object to allow LLM calls to be chained."""
90
92
  if hasattr(message, "reasoning_content"):
91
93
  message = copy(message)
@@ -18,7 +18,7 @@ class GoogleOaiAugmentedLLM(OpenAIAugmentedLLM):
18
18
  model=chosen_model,
19
19
  systemPrompt=self.instruction,
20
20
  parallel_tool_calls=False,
21
- max_iterations=10,
21
+ max_iterations=20,
22
22
  use_history=True,
23
23
  )
24
24