fast-agent-mcp 0.1.12__py3-none-any.whl → 0.1.13__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 (126) hide show
  1. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/METADATA +1 -1
  2. fast_agent_mcp-0.1.13.dist-info/RECORD +164 -0
  3. mcp_agent/agents/agent.py +37 -79
  4. mcp_agent/app.py +16 -22
  5. mcp_agent/cli/commands/bootstrap.py +22 -52
  6. mcp_agent/cli/commands/config.py +4 -4
  7. mcp_agent/cli/commands/setup.py +11 -26
  8. mcp_agent/cli/main.py +6 -9
  9. mcp_agent/cli/terminal.py +2 -2
  10. mcp_agent/config.py +1 -5
  11. mcp_agent/context.py +13 -24
  12. mcp_agent/context_dependent.py +3 -7
  13. mcp_agent/core/agent_app.py +45 -121
  14. mcp_agent/core/agent_utils.py +3 -5
  15. mcp_agent/core/decorators.py +5 -12
  16. mcp_agent/core/enhanced_prompt.py +25 -52
  17. mcp_agent/core/exceptions.py +8 -8
  18. mcp_agent/core/factory.py +29 -70
  19. mcp_agent/core/fastagent.py +48 -88
  20. mcp_agent/core/mcp_content.py +8 -16
  21. mcp_agent/core/prompt.py +8 -15
  22. mcp_agent/core/proxies.py +34 -25
  23. mcp_agent/core/request_params.py +6 -3
  24. mcp_agent/core/types.py +4 -6
  25. mcp_agent/core/validation.py +4 -3
  26. mcp_agent/executor/decorator_registry.py +11 -23
  27. mcp_agent/executor/executor.py +8 -17
  28. mcp_agent/executor/task_registry.py +2 -4
  29. mcp_agent/executor/temporal.py +28 -74
  30. mcp_agent/executor/workflow.py +3 -5
  31. mcp_agent/executor/workflow_signal.py +17 -29
  32. mcp_agent/human_input/handler.py +4 -9
  33. mcp_agent/human_input/types.py +2 -3
  34. mcp_agent/logging/events.py +1 -5
  35. mcp_agent/logging/json_serializer.py +7 -6
  36. mcp_agent/logging/listeners.py +20 -23
  37. mcp_agent/logging/logger.py +15 -17
  38. mcp_agent/logging/rich_progress.py +10 -8
  39. mcp_agent/logging/tracing.py +4 -6
  40. mcp_agent/logging/transport.py +22 -22
  41. mcp_agent/mcp/gen_client.py +4 -12
  42. mcp_agent/mcp/interfaces.py +71 -86
  43. mcp_agent/mcp/mcp_agent_client_session.py +11 -19
  44. mcp_agent/mcp/mcp_agent_server.py +8 -10
  45. mcp_agent/mcp/mcp_aggregator.py +45 -117
  46. mcp_agent/mcp/mcp_connection_manager.py +16 -37
  47. mcp_agent/mcp/prompt_message_multipart.py +12 -18
  48. mcp_agent/mcp/prompt_serialization.py +13 -38
  49. mcp_agent/mcp/prompts/prompt_load.py +99 -0
  50. mcp_agent/mcp/prompts/prompt_server.py +21 -128
  51. mcp_agent/mcp/prompts/prompt_template.py +20 -42
  52. mcp_agent/mcp/resource_utils.py +8 -17
  53. mcp_agent/mcp/sampling.py +5 -14
  54. mcp_agent/mcp/stdio.py +11 -8
  55. mcp_agent/mcp_server/agent_server.py +10 -17
  56. mcp_agent/mcp_server_registry.py +13 -35
  57. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +1 -1
  58. mcp_agent/resources/examples/data-analysis/analysis.py +1 -1
  59. mcp_agent/resources/examples/data-analysis/slides.py +110 -0
  60. mcp_agent/resources/examples/internal/agent.py +2 -1
  61. mcp_agent/resources/examples/internal/job.py +2 -1
  62. mcp_agent/resources/examples/internal/prompt_category.py +1 -1
  63. mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
  64. mcp_agent/resources/examples/internal/sizer.py +2 -1
  65. mcp_agent/resources/examples/internal/social.py +2 -1
  66. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +1 -1
  67. mcp_agent/resources/examples/prompting/agent.py +2 -1
  68. mcp_agent/resources/examples/prompting/image_server.py +5 -11
  69. mcp_agent/resources/examples/researcher/researcher-eval.py +1 -1
  70. mcp_agent/resources/examples/researcher/researcher-imp.py +3 -4
  71. mcp_agent/resources/examples/researcher/researcher.py +2 -1
  72. mcp_agent/resources/examples/workflows/agent_build.py +2 -1
  73. mcp_agent/resources/examples/workflows/chaining.py +2 -1
  74. mcp_agent/resources/examples/workflows/evaluator.py +2 -1
  75. mcp_agent/resources/examples/workflows/human_input.py +2 -1
  76. mcp_agent/resources/examples/workflows/orchestrator.py +2 -1
  77. mcp_agent/resources/examples/workflows/parallel.py +2 -1
  78. mcp_agent/resources/examples/workflows/router.py +2 -1
  79. mcp_agent/resources/examples/workflows/sse.py +1 -1
  80. mcp_agent/telemetry/usage_tracking.py +2 -1
  81. mcp_agent/ui/console_display.py +15 -39
  82. mcp_agent/workflows/embedding/embedding_base.py +1 -4
  83. mcp_agent/workflows/embedding/embedding_cohere.py +2 -2
  84. mcp_agent/workflows/embedding/embedding_openai.py +4 -13
  85. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +23 -57
  86. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +5 -8
  87. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +7 -11
  88. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +4 -8
  89. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +4 -8
  90. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +11 -22
  91. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +3 -3
  92. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +4 -6
  93. mcp_agent/workflows/llm/anthropic_utils.py +8 -29
  94. mcp_agent/workflows/llm/augmented_llm.py +69 -247
  95. mcp_agent/workflows/llm/augmented_llm_anthropic.py +39 -73
  96. mcp_agent/workflows/llm/augmented_llm_openai.py +42 -97
  97. mcp_agent/workflows/llm/augmented_llm_passthrough.py +13 -20
  98. mcp_agent/workflows/llm/augmented_llm_playback.py +8 -6
  99. mcp_agent/workflows/llm/memory.py +103 -0
  100. mcp_agent/workflows/llm/model_factory.py +8 -20
  101. mcp_agent/workflows/llm/openai_utils.py +1 -1
  102. mcp_agent/workflows/llm/prompt_utils.py +1 -3
  103. mcp_agent/workflows/llm/providers/multipart_converter_anthropic.py +47 -89
  104. mcp_agent/workflows/llm/providers/multipart_converter_openai.py +20 -55
  105. mcp_agent/workflows/llm/providers/openai_multipart.py +19 -61
  106. mcp_agent/workflows/llm/providers/sampling_converter_anthropic.py +10 -12
  107. mcp_agent/workflows/llm/providers/sampling_converter_openai.py +7 -11
  108. mcp_agent/workflows/llm/sampling_converter.py +4 -11
  109. mcp_agent/workflows/llm/sampling_format_converter.py +12 -12
  110. mcp_agent/workflows/orchestrator/orchestrator.py +24 -67
  111. mcp_agent/workflows/orchestrator/orchestrator_models.py +14 -40
  112. mcp_agent/workflows/parallel/fan_in.py +17 -47
  113. mcp_agent/workflows/parallel/fan_out.py +6 -12
  114. mcp_agent/workflows/parallel/parallel_llm.py +9 -26
  115. mcp_agent/workflows/router/router_base.py +19 -49
  116. mcp_agent/workflows/router/router_embedding.py +11 -25
  117. mcp_agent/workflows/router/router_embedding_cohere.py +2 -2
  118. mcp_agent/workflows/router/router_embedding_openai.py +2 -2
  119. mcp_agent/workflows/router/router_llm.py +12 -28
  120. mcp_agent/workflows/swarm/swarm.py +20 -48
  121. mcp_agent/workflows/swarm/swarm_anthropic.py +2 -2
  122. mcp_agent/workflows/swarm/swarm_openai.py +2 -2
  123. fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
  124. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/WHEEL +0 -0
  125. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/entry_points.txt +0 -0
  126. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/licenses/LICENSE +0 -0
@@ -2,25 +2,25 @@
2
2
  Main application wrapper for interacting with agents.
3
3
  """
4
4
 
5
- from typing import Optional, Dict, Union, TYPE_CHECKING
5
+ from typing import TYPE_CHECKING, Dict, Optional, Union
6
6
 
7
7
  from mcp_agent.app import MCPApp
8
- from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
9
- from mcp_agent.progress_display import progress_display
10
- from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator
11
- from mcp_agent.workflows.parallel.parallel_llm import ParallelLLM
12
- from mcp_agent.workflows.evaluator_optimizer.evaluator_optimizer import (
13
- EvaluatorOptimizerLLM,
14
- )
15
8
 
16
9
  # Import proxies directly - they handle their own circular imports
17
10
  from mcp_agent.core.proxies import (
18
11
  BaseAgentProxy,
12
+ ChainProxy,
19
13
  LLMAgentProxy,
20
14
  RouterProxy,
21
- ChainProxy,
22
15
  WorkflowProxy,
23
16
  )
17
+ from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
18
+ from mcp_agent.progress_display import progress_display
19
+ from mcp_agent.workflows.evaluator_optimizer.evaluator_optimizer import (
20
+ EvaluatorOptimizerLLM,
21
+ )
22
+ from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator
23
+ from mcp_agent.workflows.parallel.parallel_llm import ParallelLLM
24
24
 
25
25
  # Handle possible circular imports with types
26
26
  if TYPE_CHECKING:
@@ -32,15 +32,13 @@ else:
32
32
  class AgentApp:
33
33
  """Main application wrapper"""
34
34
 
35
- def __init__(self, app: MCPApp, agents: ProxyDict):
35
+ def __init__(self, app: MCPApp, agents: ProxyDict) -> None:
36
36
  self._app = app
37
37
  self._agents = agents
38
38
  # Optional: set default agent for direct calls
39
39
  self._default = next(iter(agents)) if agents else None
40
40
 
41
- async def send_prompt(
42
- self, prompt: PromptMessageMultipart, agent_name: Optional[str] = None
43
- ) -> str:
41
+ async def send_prompt(self, prompt: PromptMessageMultipart, agent_name: Optional[str] = None) -> str:
44
42
  """
45
43
  Send a PromptMessageMultipart to an agent
46
44
 
@@ -218,15 +216,9 @@ class AgentApp:
218
216
  found_prompts = False
219
217
  for agent_name, agent_proxy in self._agents.items():
220
218
  # Check if agent has an mcp_aggregator (agent instance)
221
- if hasattr(agent_proxy, "_agent") and hasattr(
222
- agent_proxy._agent, "list_prompts"
223
- ):
224
- rich_print(
225
- f"\n[bold]Fetching prompts for agent [cyan]{agent_name}[/cyan]...[/bold]"
226
- )
227
- prompt_servers = (
228
- await agent_proxy._agent.list_prompts()
229
- )
219
+ if hasattr(agent_proxy, "_agent") and hasattr(agent_proxy._agent, "list_prompts"):
220
+ rich_print(f"\n[bold]Fetching prompts for agent [cyan]{agent_name}[/cyan]...[/bold]")
221
+ prompt_servers = await agent_proxy._agent.list_prompts()
230
222
 
231
223
  if prompt_servers:
232
224
  found_prompts = True
@@ -234,31 +226,15 @@ class AgentApp:
234
226
  server_name,
235
227
  prompts_info,
236
228
  ) in prompt_servers.items():
237
- if (
238
- prompts_info
239
- and hasattr(prompts_info, "prompts")
240
- and prompts_info.prompts
241
- ):
242
- rich_print(
243
- f"\n[bold cyan]{server_name}:[/bold cyan]"
244
- )
229
+ if prompts_info and hasattr(prompts_info, "prompts") and prompts_info.prompts:
230
+ rich_print(f"\n[bold cyan]{server_name}:[/bold cyan]")
245
231
  for prompt in prompts_info.prompts:
246
232
  rich_print(f" {prompt.name}")
247
- elif (
248
- isinstance(prompts_info, list)
249
- and prompts_info
250
- ):
251
- rich_print(
252
- f"\n[bold cyan]{server_name}:[/bold cyan]"
253
- )
233
+ elif isinstance(prompts_info, list) and prompts_info:
234
+ rich_print(f"\n[bold cyan]{server_name}:[/bold cyan]")
254
235
  for prompt in prompts_info:
255
- if (
256
- isinstance(prompt, dict)
257
- and "name" in prompt
258
- ):
259
- rich_print(
260
- f" {prompt['name']}"
261
- )
236
+ if isinstance(prompt, dict) and "name" in prompt:
237
+ rich_print(f" {prompt['name']}")
262
238
  else:
263
239
  rich_print(f" {prompt}")
264
240
 
@@ -269,8 +245,8 @@ class AgentApp:
269
245
  continue
270
246
  elif "select_prompt" in command_result:
271
247
  from rich import print as rich_print
272
- from rich.table import Table
273
248
  from rich.console import Console
249
+ from rich.table import Table
274
250
 
275
251
  console = Console()
276
252
 
@@ -278,12 +254,8 @@ class AgentApp:
278
254
  current_proxy = self._agents[agent]
279
255
 
280
256
  # Check if the agent has prompt capabilities
281
- if not hasattr(current_proxy, "_agent") or not hasattr(
282
- current_proxy._agent, "list_prompts"
283
- ):
284
- rich_print(
285
- f"[red]Current agent '{agent}' does not support prompts[/red]"
286
- )
257
+ if not hasattr(current_proxy, "_agent") or not hasattr(current_proxy._agent, "list_prompts"):
258
+ rich_print(f"[red]Current agent '{agent}' does not support prompts[/red]")
287
259
  continue
288
260
 
289
261
  try:
@@ -291,15 +263,11 @@ class AgentApp:
291
263
  all_prompts = []
292
264
 
293
265
  # Get prompts from the current agent
294
- rich_print(
295
- f"\n[bold]Fetching prompts for agent [cyan]{agent}[/cyan]...[/bold]"
296
- )
266
+ rich_print(f"\n[bold]Fetching prompts for agent [cyan]{agent}[/cyan]...[/bold]")
297
267
  prompt_servers = await current_proxy._agent.list_prompts()
298
268
 
299
269
  if not prompt_servers:
300
- rich_print(
301
- "[yellow]No prompts available for this agent[/yellow]"
302
- )
270
+ rich_print("[yellow]No prompts available for this agent[/yellow]")
303
271
  continue
304
272
 
305
273
  # Process retrieved prompts
@@ -319,9 +287,7 @@ class AgentApp:
319
287
  for prompt in prompts:
320
288
  # Basic prompt information
321
289
  prompt_name = getattr(prompt, "name", "Unknown")
322
- description = getattr(
323
- prompt, "description", "No description"
324
- )
290
+ description = getattr(prompt, "description", "No description")
325
291
 
326
292
  # Extract argument information
327
293
  arg_names = []
@@ -339,9 +305,7 @@ class AgentApp:
339
305
  arg_names.append(name)
340
306
 
341
307
  # Store description if available
342
- description = getattr(
343
- arg, "description", None
344
- )
308
+ description = getattr(arg, "description", None)
345
309
  if description:
346
310
  arg_descriptions[name] = description
347
311
 
@@ -371,32 +335,20 @@ class AgentApp:
371
335
 
372
336
  # If no prompts were found
373
337
  if not all_prompts:
374
- rich_print(
375
- "[yellow]No prompts available for this agent[/yellow]"
376
- )
338
+ rich_print("[yellow]No prompts available for this agent[/yellow]")
377
339
  continue
378
340
 
379
341
  # Sort prompts by server then name
380
342
  all_prompts.sort(key=lambda p: (p["server"], p["name"]))
381
343
 
382
344
  # Check if a specific prompt was requested
383
- if (
384
- "prompt_name" in command_result
385
- and command_result["prompt_name"]
386
- ):
345
+ if "prompt_name" in command_result and command_result["prompt_name"]:
387
346
  requested_name = command_result["prompt_name"]
388
347
  # Find the prompt in our list (either by name or namespaced name)
389
- matching_prompts = [
390
- p
391
- for p in all_prompts
392
- if p["name"] == requested_name
393
- or p["namespaced_name"] == requested_name
394
- ]
348
+ matching_prompts = [p for p in all_prompts if p["name"] == requested_name or p["namespaced_name"] == requested_name]
395
349
 
396
350
  if not matching_prompts:
397
- rich_print(
398
- f"[red]Prompt '{requested_name}' not found[/red]"
399
- )
351
+ rich_print(f"[red]Prompt '{requested_name}' not found[/red]")
400
352
  rich_print("[yellow]Available prompts:[/yellow]")
401
353
  for p in all_prompts:
402
354
  rich_print(f" {p['namespaced_name']}")
@@ -407,22 +359,16 @@ class AgentApp:
407
359
  selected_prompt = matching_prompts[0]
408
360
  else:
409
361
  # If multiple matches, show them and ask user to be more specific
410
- rich_print(
411
- f"[yellow]Multiple prompts match '{requested_name}':[/yellow]"
412
- )
362
+ rich_print(f"[yellow]Multiple prompts match '{requested_name}':[/yellow]")
413
363
  for i, p in enumerate(matching_prompts):
414
- rich_print(
415
- f" {i + 1}. {p['namespaced_name']} - {p['description']}"
416
- )
364
+ rich_print(f" {i + 1}. {p['namespaced_name']} - {p['description']}")
417
365
 
418
366
  # Ask user to select one
419
367
  from mcp_agent.core.enhanced_prompt import (
420
368
  get_selection_input,
421
369
  )
422
370
 
423
- selection = await get_selection_input(
424
- "Enter prompt number to select: ", default="1"
425
- )
371
+ selection = await get_selection_input("Enter prompt number to select: ", default="1")
426
372
 
427
373
  try:
428
374
  idx = int(selection) - 1
@@ -432,9 +378,7 @@ class AgentApp:
432
378
  rich_print("[red]Invalid selection[/red]")
433
379
  continue
434
380
  except ValueError:
435
- rich_print(
436
- "[red]Invalid input, please enter a number[/red]"
437
- )
381
+ rich_print("[red]Invalid input, please enter a number[/red]")
438
382
  continue
439
383
  else:
440
384
  # Display prompt selection UI
@@ -455,9 +399,7 @@ class AgentApp:
455
399
  if required_args and optional_args:
456
400
  args_display = f"[bold]{len(required_args)}[/bold]+{len(optional_args)}"
457
401
  elif required_args:
458
- args_display = (
459
- f"[bold]{len(required_args)}[/bold]"
460
- )
402
+ args_display = f"[bold]{len(required_args)}[/bold]"
461
403
  elif optional_args:
462
404
  args_display = f"{len(optional_args)} opt"
463
405
  else:
@@ -472,9 +414,7 @@ class AgentApp:
472
414
  )
473
415
 
474
416
  console.print(table)
475
- prompt_names = [
476
- str(i + 1) for i in range(len(all_prompts))
477
- ]
417
+ prompt_names = [str(i + 1) for i in range(len(all_prompts))]
478
418
 
479
419
  # Ask user to select a prompt
480
420
  from mcp_agent.core.enhanced_prompt import (
@@ -489,9 +429,7 @@ class AgentApp:
489
429
 
490
430
  # Make cancellation easier
491
431
  if not selection or selection.strip() == "":
492
- rich_print(
493
- "[yellow]Prompt selection cancelled[/yellow]"
494
- )
432
+ rich_print("[yellow]Prompt selection cancelled[/yellow]")
495
433
  continue
496
434
 
497
435
  try:
@@ -502,17 +440,13 @@ class AgentApp:
502
440
  rich_print("[red]Invalid selection[/red]")
503
441
  continue
504
442
  except ValueError:
505
- rich_print(
506
- "[red]Invalid input, please enter a number[/red]"
507
- )
443
+ rich_print("[red]Invalid input, please enter a number[/red]")
508
444
  continue
509
445
 
510
446
  # Get our prompt arguments
511
447
  required_args = selected_prompt["required_args"]
512
448
  optional_args = selected_prompt["optional_args"]
513
- arg_descriptions = selected_prompt.get(
514
- "arg_descriptions", {}
515
- )
449
+ arg_descriptions = selected_prompt.get("arg_descriptions", {})
516
450
 
517
451
  # Always initialize arg_values
518
452
  arg_values = {}
@@ -525,13 +459,9 @@ class AgentApp:
525
459
  f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] requires {len(required_args)} arguments and has {len(optional_args)} optional arguments:[/bold]"
526
460
  )
527
461
  elif required_args:
528
- rich_print(
529
- f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] requires {len(required_args)} arguments:[/bold]"
530
- )
462
+ rich_print(f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] requires {len(required_args)} arguments:[/bold]")
531
463
  elif optional_args:
532
- rich_print(
533
- f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] has {len(optional_args)} optional arguments:[/bold]"
534
- )
464
+ rich_print(f"\n[bold]Prompt [cyan]{selected_prompt['name']}[/cyan] has {len(optional_args)} optional arguments:[/bold]")
535
465
 
536
466
  # Collect required arguments
537
467
  for arg_name in required_args:
@@ -573,21 +503,15 @@ class AgentApp:
573
503
  arg_values[arg_name] = arg_value
574
504
 
575
505
  # Apply the prompt with or without arguments
576
- rich_print(
577
- f"\n[bold]Applying prompt [cyan]{selected_prompt['namespaced_name']}[/cyan]...[/bold]"
578
- )
506
+ rich_print(f"\n[bold]Applying prompt [cyan]{selected_prompt['namespaced_name']}[/cyan]...[/bold]")
579
507
 
580
508
  # Call apply_prompt on the agent - always pass arg_values (empty dict if no args)
581
- await current_proxy._agent.apply_prompt(
582
- selected_prompt["namespaced_name"], arg_values
583
- )
509
+ await current_proxy._agent.apply_prompt(selected_prompt["namespaced_name"], arg_values)
584
510
 
585
511
  except Exception as e:
586
512
  import traceback
587
513
 
588
- rich_print(
589
- f"[red]Error selecting or applying prompt: {e}[/red]"
590
- )
514
+ rich_print(f"[red]Error selecting or applying prompt: {e}[/red]")
591
515
  rich_print(f"[dim]{traceback.format_exc()}[/dim]")
592
516
  continue
593
517
 
@@ -2,7 +2,7 @@
2
2
  Utility functions for agent operations.
3
3
  """
4
4
 
5
- from typing import List, TYPE_CHECKING
5
+ from typing import TYPE_CHECKING, List
6
6
 
7
7
  from mcp_agent.event_progress import ProgressAction
8
8
 
@@ -28,7 +28,7 @@ def unwrap_proxy(proxy: BaseAgentProxy) -> AgentOrWorkflow:
28
28
  Returns:
29
29
  The underlying Agent or workflow instance
30
30
  """
31
- from mcp_agent.core.proxies import LLMAgentProxy, ChainProxy
31
+ from mcp_agent.core.proxies import ChainProxy, LLMAgentProxy
32
32
 
33
33
  if isinstance(proxy, LLMAgentProxy):
34
34
  return proxy._agent
@@ -38,9 +38,7 @@ def unwrap_proxy(proxy: BaseAgentProxy) -> AgentOrWorkflow:
38
38
  return proxy._workflow
39
39
 
40
40
 
41
- def get_agent_instances(
42
- agent_names: List[str], active_agents: ProxyDict
43
- ) -> List[AgentOrWorkflow]:
41
+ def get_agent_instances(agent_names: List[str], active_agents: ProxyDict) -> List[AgentOrWorkflow]:
44
42
  """
45
43
  Get list of actual agent/workflow instances from a list of names.
46
44
 
@@ -3,7 +3,8 @@ Decorators for FastAgent applications.
3
3
  Contains decorator definitions extracted from fastagent.py.
4
4
  """
5
5
 
6
- from typing import Callable, Dict, List, Optional, TypeVar, Literal
6
+ from typing import Callable, Dict, List, Literal, Optional, TypeVar
7
+
7
8
  from mcp_agent.core.agent_types import AgentConfig, AgentType
8
9
  from mcp_agent.workflows.llm.augmented_llm import RequestParams
9
10
 
@@ -46,11 +47,7 @@ def _create_decorator(
46
47
  # Create base request params
47
48
  def decorator(func: Callable) -> Callable:
48
49
  # Create base request params
49
- if (
50
- request_params is not None
51
- or model is not None
52
- or use_history != default_use_history
53
- ):
50
+ if request_params is not None or model is not None or use_history != default_use_history:
54
51
  max_tokens = 4096 if agent_type == AgentType.BASIC else None
55
52
  params_dict = {"use_history": use_history, "model": model}
56
53
  if max_tokens:
@@ -142,9 +139,7 @@ def agent(
142
139
  @fast.agent("agent_name", instruction="Your instruction here") # Using keyword arg
143
140
  """
144
141
  # Use positional argument if provided, otherwise use keyword argument
145
- final_instruction = (
146
- instruction_or_kwarg if instruction_or_kwarg is not None else instruction
147
- )
142
+ final_instruction = instruction_or_kwarg if instruction_or_kwarg is not None else instruction
148
143
 
149
144
  decorator = self._create_decorator(
150
145
  AgentType.BASIC,
@@ -427,9 +422,7 @@ def chain(
427
422
  return decorator
428
423
 
429
424
 
430
- def passthrough(
431
- self, name: str = "Passthrough", use_history: bool = True, **kwargs
432
- ) -> Callable:
425
+ def passthrough(self, name: str = "Passthrough", use_history: bool = True, **kwargs) -> Callable:
433
426
  """
434
427
  Decorator to create and register a passthrough agent.
435
428
  A passthrough agent simply returns any input message without modification.
@@ -2,15 +2,16 @@
2
2
  Enhanced prompt functionality with advanced prompt_toolkit features.
3
3
  """
4
4
 
5
- from typing import List, Optional
6
5
  from importlib.metadata import version
6
+ from typing import List, Optional
7
+
7
8
  from prompt_toolkit import PromptSession
9
+ from prompt_toolkit.completion import Completer, Completion, WordCompleter
10
+ from prompt_toolkit.filters import Condition
8
11
  from prompt_toolkit.formatted_text import HTML
9
12
  from prompt_toolkit.history import InMemoryHistory
10
13
  from prompt_toolkit.key_binding import KeyBindings
11
- from prompt_toolkit.completion import Completer, Completion, WordCompleter
12
14
  from prompt_toolkit.lexers import PygmentsLexer
13
- from prompt_toolkit.filters import Condition
14
15
  from prompt_toolkit.styles import Style
15
16
  from pygments.lexers.python import PythonLexer
16
17
  from rich import print as rich_print
@@ -45,7 +46,7 @@ class AgentCompleter(Completer):
45
46
  commands: List[str] = None,
46
47
  agent_types: dict = None,
47
48
  is_human_input: bool = False,
48
- ):
49
+ ) -> None:
49
50
  self.agents = agents
50
51
  # Map commands to their descriptions for better completion hints
51
52
  self.commands = {
@@ -61,9 +62,7 @@ class AgentCompleter(Completer):
61
62
  if is_human_input:
62
63
  self.commands.pop("agents")
63
64
  self.commands.pop("prompts") # Remove prompts command in human input mode
64
- self.commands.pop(
65
- "prompt", None
66
- ) # Remove prompt command in human input mode
65
+ self.commands.pop("prompt", None) # Remove prompt command in human input mode
67
66
  self.agent_types = agent_types or {}
68
67
 
69
68
  def get_completions(self, document, complete_event):
@@ -103,23 +102,23 @@ def create_keybindings(on_toggle_multiline=None, app=None):
103
102
  kb = KeyBindings()
104
103
 
105
104
  @kb.add("c-m", filter=Condition(lambda: not in_multiline_mode))
106
- def _(event):
105
+ def _(event) -> None:
107
106
  """Enter: accept input when not in multiline mode."""
108
107
  event.current_buffer.validate_and_handle()
109
108
 
110
109
  @kb.add("c-m", filter=Condition(lambda: in_multiline_mode))
111
- def _(event):
110
+ def _(event) -> None:
112
111
  """Enter: insert newline when in multiline mode."""
113
112
  event.current_buffer.insert_text("\n")
114
113
 
115
114
  # Use c-j (Ctrl+J) as an alternative to represent Ctrl+Enter in multiline mode
116
115
  @kb.add("c-j", filter=Condition(lambda: in_multiline_mode))
117
- def _(event):
116
+ def _(event) -> None:
118
117
  """Ctrl+J (equivalent to Ctrl+Enter): Submit in multiline mode."""
119
118
  event.current_buffer.validate_and_handle()
120
119
 
121
120
  @kb.add("c-t")
122
- def _(event):
121
+ def _(event) -> None:
123
122
  """Ctrl+T: Toggle multiline mode."""
124
123
  global in_multiline_mode
125
124
  in_multiline_mode = not in_multiline_mode
@@ -138,7 +137,7 @@ def create_keybindings(on_toggle_multiline=None, app=None):
138
137
  # The toolbar will show the current mode
139
138
 
140
139
  @kb.add("c-l")
141
- def _(event):
140
+ def _(event) -> None:
142
141
  """Ctrl+L: Clear the input buffer."""
143
142
  event.current_buffer.text = ""
144
143
 
@@ -187,7 +186,7 @@ async def get_enhanced_input(
187
186
  agent_histories[agent_name] = InMemoryHistory()
188
187
 
189
188
  # Define callback for multiline toggle
190
- def on_multiline_toggle(enabled):
189
+ def on_multiline_toggle(enabled) -> None:
191
190
  nonlocal session
192
191
  if hasattr(session, "app") and session.app:
193
192
  session.app.invalidate()
@@ -209,9 +208,7 @@ async def get_enhanced_input(
209
208
  ("↑/↓", "History"),
210
209
  ]
211
210
 
212
- newline = (
213
- "Ctrl+<Enter>:Submit" if in_multiline_mode else "<Enter>:Submit"
214
- )
211
+ newline = "Ctrl+<Enter>:Submit" if in_multiline_mode else "<Enter>:Submit"
215
212
 
216
213
  # Only show relevant shortcuts based on mode
217
214
  shortcuts = [(k, v) for k, v in shortcuts if v]
@@ -250,9 +247,7 @@ async def get_enhanced_input(
250
247
  )
251
248
 
252
249
  # Create key bindings with a reference to the app
253
- bindings = create_keybindings(
254
- on_toggle_multiline=on_multiline_toggle, app=session.app
255
- )
250
+ bindings = create_keybindings(on_toggle_multiline=on_multiline_toggle, app=session.app)
256
251
  session.app.key_bindings = bindings
257
252
 
258
253
  # Create formatted prompt text
@@ -267,20 +262,14 @@ async def get_enhanced_input(
267
262
  if default == "STOP":
268
263
  rich_print("Enter a prompt, [red]STOP[/red] to finish")
269
264
  if default:
270
- rich_print(
271
- f"Press <ENTER> to use the default prompt:\n[cyan]{default}[/cyan]"
272
- )
265
+ rich_print(f"Press <ENTER> to use the default prompt:\n[cyan]{default}[/cyan]")
273
266
 
274
267
  # Mention available features but only on first usage globally
275
268
  if not help_message_shown:
276
269
  if is_human_input:
277
- rich_print(
278
- "[dim]Type /help for commands. Ctrl+T toggles multiline mode.[/dim]"
279
- )
270
+ rich_print("[dim]Type /help for commands. Ctrl+T toggles multiline mode.[/dim]")
280
271
  else:
281
- rich_print(
282
- "[dim]Type /help for commands, @agent to switch agent. Ctrl+T toggles multiline mode.[/dim]"
283
- )
272
+ rich_print("[dim]Type /help for commands, @agent to switch agent. Ctrl+T toggles multiline mode.[/dim]")
284
273
  rich_print()
285
274
  help_message_shown = True
286
275
 
@@ -366,9 +355,7 @@ async def get_selection_input(
366
355
 
367
356
  try:
368
357
  # Get user input
369
- selection = await prompt_session.prompt_async(
370
- prompt_text, default=default or ""
371
- )
358
+ selection = await prompt_session.prompt_async(prompt_text, default=default or "")
372
359
 
373
360
  # Handle cancellation
374
361
  if allow_cancel and not selection.strip():
@@ -409,9 +396,7 @@ async def get_argument_input(
409
396
  if description:
410
397
  rich_print(f" [dim]{arg_name}: {description}[/dim]")
411
398
 
412
- prompt_text = HTML(
413
- f"Enter value for <ansibrightcyan>{arg_name}</ansibrightcyan> {required_text}: "
414
- )
399
+ prompt_text = HTML(f"Enter value for <ansibrightcyan>{arg_name}</ansibrightcyan> {required_text}: ")
415
400
 
416
401
  # Create prompt session
417
402
  prompt_session = PromptSession()
@@ -452,13 +437,9 @@ async def handle_special_commands(command, agent_app=None):
452
437
  rich_print(" /prompt <name> - Apply a specific prompt by name")
453
438
  rich_print(" @agent_name - Switch to agent")
454
439
  rich_print(" STOP - Return control back to the workflow")
455
- rich_print(
456
- " EXIT - Exit fast-agent, terminating any running workflows"
457
- )
440
+ rich_print(" EXIT - Exit fast-agent, terminating any running workflows")
458
441
  rich_print("\n[bold]Keyboard Shortcuts:[/bold]")
459
- rich_print(
460
- " Enter - Submit (normal mode) / New line (multiline mode)"
461
- )
442
+ rich_print(" Enter - Submit (normal mode) / New line (multiline mode)")
462
443
  rich_print(" Ctrl+Enter - Always submit (in any mode)")
463
444
  rich_print(" Ctrl+T - Toggle multiline mode")
464
445
  rich_print(" Ctrl+L - Clear input")
@@ -489,14 +470,10 @@ async def handle_special_commands(command, agent_app=None):
489
470
  rich_print("\n[bold]Fetching available MCP prompts...[/bold]")
490
471
  return {"list_prompts": True}
491
472
  else:
492
- rich_print(
493
- "[yellow]Prompt listing is not available outside of an agent context[/yellow]"
494
- )
473
+ rich_print("[yellow]Prompt listing is not available outside of an agent context[/yellow]")
495
474
  return True
496
475
 
497
- elif command == "SELECT_PROMPT" or (
498
- isinstance(command, str) and command.startswith("SELECT_PROMPT:")
499
- ):
476
+ elif command == "SELECT_PROMPT" or (isinstance(command, str) and command.startswith("SELECT_PROMPT:")):
500
477
  # Handle prompt selection UI
501
478
  if agent_app:
502
479
  # If it's a specific prompt, extract the name
@@ -507,9 +484,7 @@ async def handle_special_commands(command, agent_app=None):
507
484
  # Return a dictionary with a select_prompt action to be handled by the caller
508
485
  return {"select_prompt": True, "prompt_name": prompt_name}
509
486
  else:
510
- rich_print(
511
- "[yellow]Prompt selection is not available outside of an agent context[/yellow]"
512
- )
487
+ rich_print("[yellow]Prompt selection is not available outside of an agent context[/yellow]")
513
488
  return True
514
489
 
515
490
  elif isinstance(command, str) and command.startswith("SWITCH:"):
@@ -519,9 +494,7 @@ async def handle_special_commands(command, agent_app=None):
519
494
  # rich_print(f"[green]Switching to agent: {agent_name}[/green]")
520
495
  return {"switch_agent": agent_name}
521
496
  else:
522
- rich_print(
523
- "[yellow]Agent switching not available in this context[/yellow]"
524
- )
497
+ rich_print("[yellow]Agent switching not available in this context[/yellow]")
525
498
  else:
526
499
  rich_print(f"[red]Unknown agent: {agent_name}[/red]")
527
500
  return True