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.
- {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/METADATA +12 -12
- {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/RECORD +30 -27
- mcp_agent/agents/workflow/iterative_planner.py +572 -0
- mcp_agent/agents/workflow/orchestrator_agent.py +3 -3
- mcp_agent/agents/workflow/orchestrator_models.py +6 -6
- mcp_agent/cli/commands/go.py +17 -3
- mcp_agent/cli/main.py +2 -2
- mcp_agent/config.py +14 -0
- mcp_agent/core/agent_types.py +1 -0
- mcp_agent/core/direct_decorators.py +54 -0
- mcp_agent/core/direct_factory.py +42 -15
- mcp_agent/core/fastagent.py +4 -0
- mcp_agent/core/mermaid_utils.py +170 -0
- mcp_agent/llm/model_database.py +7 -7
- mcp_agent/llm/model_factory.py +5 -3
- mcp_agent/llm/provider_types.py +1 -0
- mcp_agent/llm/providers/augmented_llm_aliyun.py +1 -1
- mcp_agent/llm/providers/augmented_llm_anthropic.py +1 -1
- mcp_agent/llm/providers/augmented_llm_deepseek.py +4 -2
- mcp_agent/llm/providers/augmented_llm_google_oai.py +1 -1
- mcp_agent/llm/providers/augmented_llm_groq.py +30 -0
- mcp_agent/llm/providers/augmented_llm_openai.py +4 -1
- mcp_agent/llm/providers/augmented_llm_openrouter.py +1 -1
- mcp_agent/llm/providers/augmented_llm_tensorzero.py +1 -1
- mcp_agent/llm/providers/augmented_llm_xai.py +1 -1
- mcp_agent/resources/examples/workflows/orchestrator.py +5 -2
- mcp_agent/ui/console_display.py +104 -39
- {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.2.46.dist-info → fast_agent_mcp-0.2.48.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
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=
|
|
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=
|
|
95
|
+
max_iterations=20, # Max iterations for tool use loop
|
|
96
96
|
parallel_tool_calls=True,
|
|
97
97
|
)
|
|
98
98
|
|
|
@@ -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.
|
|
47
|
-
name="orchestrate",
|
|
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:
|
mcp_agent/ui/console_display.py
CHANGED
|
@@ -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
|
|
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 "
|
|
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
|
-
|
|
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
|
-
#
|
|
183
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
#
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|