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.
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/METADATA +1 -1
- fast_agent_mcp-0.1.13.dist-info/RECORD +164 -0
- mcp_agent/agents/agent.py +37 -79
- mcp_agent/app.py +16 -22
- mcp_agent/cli/commands/bootstrap.py +22 -52
- mcp_agent/cli/commands/config.py +4 -4
- mcp_agent/cli/commands/setup.py +11 -26
- mcp_agent/cli/main.py +6 -9
- mcp_agent/cli/terminal.py +2 -2
- mcp_agent/config.py +1 -5
- mcp_agent/context.py +13 -24
- mcp_agent/context_dependent.py +3 -7
- mcp_agent/core/agent_app.py +45 -121
- mcp_agent/core/agent_utils.py +3 -5
- mcp_agent/core/decorators.py +5 -12
- mcp_agent/core/enhanced_prompt.py +25 -52
- mcp_agent/core/exceptions.py +8 -8
- mcp_agent/core/factory.py +29 -70
- mcp_agent/core/fastagent.py +48 -88
- mcp_agent/core/mcp_content.py +8 -16
- mcp_agent/core/prompt.py +8 -15
- mcp_agent/core/proxies.py +34 -25
- mcp_agent/core/request_params.py +6 -3
- mcp_agent/core/types.py +4 -6
- mcp_agent/core/validation.py +4 -3
- mcp_agent/executor/decorator_registry.py +11 -23
- mcp_agent/executor/executor.py +8 -17
- mcp_agent/executor/task_registry.py +2 -4
- mcp_agent/executor/temporal.py +28 -74
- mcp_agent/executor/workflow.py +3 -5
- mcp_agent/executor/workflow_signal.py +17 -29
- mcp_agent/human_input/handler.py +4 -9
- mcp_agent/human_input/types.py +2 -3
- mcp_agent/logging/events.py +1 -5
- mcp_agent/logging/json_serializer.py +7 -6
- mcp_agent/logging/listeners.py +20 -23
- mcp_agent/logging/logger.py +15 -17
- mcp_agent/logging/rich_progress.py +10 -8
- mcp_agent/logging/tracing.py +4 -6
- mcp_agent/logging/transport.py +22 -22
- mcp_agent/mcp/gen_client.py +4 -12
- mcp_agent/mcp/interfaces.py +71 -86
- mcp_agent/mcp/mcp_agent_client_session.py +11 -19
- mcp_agent/mcp/mcp_agent_server.py +8 -10
- mcp_agent/mcp/mcp_aggregator.py +45 -117
- mcp_agent/mcp/mcp_connection_manager.py +16 -37
- mcp_agent/mcp/prompt_message_multipart.py +12 -18
- mcp_agent/mcp/prompt_serialization.py +13 -38
- mcp_agent/mcp/prompts/prompt_load.py +99 -0
- mcp_agent/mcp/prompts/prompt_server.py +21 -128
- mcp_agent/mcp/prompts/prompt_template.py +20 -42
- mcp_agent/mcp/resource_utils.py +8 -17
- mcp_agent/mcp/sampling.py +5 -14
- mcp_agent/mcp/stdio.py +11 -8
- mcp_agent/mcp_server/agent_server.py +10 -17
- mcp_agent/mcp_server_registry.py +13 -35
- mcp_agent/resources/examples/data-analysis/analysis-campaign.py +1 -1
- mcp_agent/resources/examples/data-analysis/analysis.py +1 -1
- mcp_agent/resources/examples/data-analysis/slides.py +110 -0
- mcp_agent/resources/examples/internal/agent.py +2 -1
- mcp_agent/resources/examples/internal/job.py +2 -1
- mcp_agent/resources/examples/internal/prompt_category.py +1 -1
- mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
- mcp_agent/resources/examples/internal/sizer.py +2 -1
- mcp_agent/resources/examples/internal/social.py +2 -1
- mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +1 -1
- mcp_agent/resources/examples/prompting/agent.py +2 -1
- mcp_agent/resources/examples/prompting/image_server.py +5 -11
- mcp_agent/resources/examples/researcher/researcher-eval.py +1 -1
- mcp_agent/resources/examples/researcher/researcher-imp.py +3 -4
- mcp_agent/resources/examples/researcher/researcher.py +2 -1
- mcp_agent/resources/examples/workflows/agent_build.py +2 -1
- mcp_agent/resources/examples/workflows/chaining.py +2 -1
- mcp_agent/resources/examples/workflows/evaluator.py +2 -1
- mcp_agent/resources/examples/workflows/human_input.py +2 -1
- mcp_agent/resources/examples/workflows/orchestrator.py +2 -1
- mcp_agent/resources/examples/workflows/parallel.py +2 -1
- mcp_agent/resources/examples/workflows/router.py +2 -1
- mcp_agent/resources/examples/workflows/sse.py +1 -1
- mcp_agent/telemetry/usage_tracking.py +2 -1
- mcp_agent/ui/console_display.py +15 -39
- mcp_agent/workflows/embedding/embedding_base.py +1 -4
- mcp_agent/workflows/embedding/embedding_cohere.py +2 -2
- mcp_agent/workflows/embedding/embedding_openai.py +4 -13
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +23 -57
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +5 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +7 -11
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +4 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +4 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +11 -22
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +3 -3
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +4 -6
- mcp_agent/workflows/llm/anthropic_utils.py +8 -29
- mcp_agent/workflows/llm/augmented_llm.py +69 -247
- mcp_agent/workflows/llm/augmented_llm_anthropic.py +39 -73
- mcp_agent/workflows/llm/augmented_llm_openai.py +42 -97
- mcp_agent/workflows/llm/augmented_llm_passthrough.py +13 -20
- mcp_agent/workflows/llm/augmented_llm_playback.py +8 -6
- mcp_agent/workflows/llm/memory.py +103 -0
- mcp_agent/workflows/llm/model_factory.py +8 -20
- mcp_agent/workflows/llm/openai_utils.py +1 -1
- mcp_agent/workflows/llm/prompt_utils.py +1 -3
- mcp_agent/workflows/llm/providers/multipart_converter_anthropic.py +47 -89
- mcp_agent/workflows/llm/providers/multipart_converter_openai.py +20 -55
- mcp_agent/workflows/llm/providers/openai_multipart.py +19 -61
- mcp_agent/workflows/llm/providers/sampling_converter_anthropic.py +10 -12
- mcp_agent/workflows/llm/providers/sampling_converter_openai.py +7 -11
- mcp_agent/workflows/llm/sampling_converter.py +4 -11
- mcp_agent/workflows/llm/sampling_format_converter.py +12 -12
- mcp_agent/workflows/orchestrator/orchestrator.py +24 -67
- mcp_agent/workflows/orchestrator/orchestrator_models.py +14 -40
- mcp_agent/workflows/parallel/fan_in.py +17 -47
- mcp_agent/workflows/parallel/fan_out.py +6 -12
- mcp_agent/workflows/parallel/parallel_llm.py +9 -26
- mcp_agent/workflows/router/router_base.py +19 -49
- mcp_agent/workflows/router/router_embedding.py +11 -25
- mcp_agent/workflows/router/router_embedding_cohere.py +2 -2
- mcp_agent/workflows/router/router_embedding_openai.py +2 -2
- mcp_agent/workflows/router/router_llm.py +12 -28
- mcp_agent/workflows/swarm/swarm.py +20 -48
- mcp_agent/workflows/swarm/swarm_anthropic.py +2 -2
- mcp_agent/workflows/swarm/swarm_openai.py +2 -2
- fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/licenses/LICENSE +0 -0
mcp_agent/core/agent_app.py
CHANGED
@@ -2,25 +2,25 @@
|
|
2
2
|
Main application wrapper for interacting with agents.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from typing import
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|
mcp_agent/core/agent_utils.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
Utility functions for agent operations.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from typing import
|
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
|
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
|
|
mcp_agent/core/decorators.py
CHANGED
@@ -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
|
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
|