fast-agent-mcp 0.3.13__py3-none-any.whl → 0.3.15__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/agents/llm_agent.py +59 -37
- fast_agent/agents/llm_decorator.py +13 -2
- fast_agent/agents/mcp_agent.py +21 -5
- fast_agent/agents/tool_agent.py +41 -29
- fast_agent/agents/workflow/router_agent.py +2 -1
- fast_agent/cli/commands/check_config.py +48 -1
- fast_agent/config.py +65 -2
- fast_agent/constants.py +3 -0
- fast_agent/context.py +42 -9
- fast_agent/core/fastagent.py +14 -1
- fast_agent/core/logging/listeners.py +1 -1
- fast_agent/core/validation.py +31 -33
- fast_agent/event_progress.py +2 -3
- fast_agent/human_input/form_fields.py +4 -1
- fast_agent/interfaces.py +12 -2
- fast_agent/llm/fastagent_llm.py +31 -0
- fast_agent/llm/model_database.py +2 -2
- fast_agent/llm/model_factory.py +8 -1
- fast_agent/llm/provider_key_manager.py +1 -0
- fast_agent/llm/provider_types.py +1 -0
- fast_agent/llm/request_params.py +3 -1
- fast_agent/mcp/mcp_aggregator.py +313 -40
- fast_agent/mcp/mcp_connection_manager.py +39 -9
- fast_agent/mcp/prompt_message_extended.py +2 -2
- fast_agent/mcp/skybridge.py +45 -0
- fast_agent/mcp/sse_tracking.py +287 -0
- fast_agent/mcp/transport_tracking.py +37 -3
- fast_agent/mcp/types.py +24 -0
- fast_agent/resources/examples/workflows/router.py +1 -0
- fast_agent/resources/setup/fastagent.config.yaml +7 -1
- fast_agent/ui/console_display.py +946 -84
- fast_agent/ui/elicitation_form.py +23 -1
- fast_agent/ui/enhanced_prompt.py +153 -58
- fast_agent/ui/interactive_prompt.py +57 -34
- fast_agent/ui/markdown_truncator.py +942 -0
- fast_agent/ui/mcp_display.py +110 -29
- fast_agent/ui/plain_text_truncator.py +68 -0
- fast_agent/ui/rich_progress.py +4 -1
- fast_agent/ui/streaming_buffer.py +449 -0
- {fast_agent_mcp-0.3.13.dist-info → fast_agent_mcp-0.3.15.dist-info}/METADATA +4 -3
- {fast_agent_mcp-0.3.13.dist-info → fast_agent_mcp-0.3.15.dist-info}/RECORD +44 -38
- {fast_agent_mcp-0.3.13.dist-info → fast_agent_mcp-0.3.15.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.3.13.dist-info → fast_agent_mcp-0.3.15.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.3.13.dist-info → fast_agent_mcp-0.3.15.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Simplified, robust elicitation form dialog."""
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
from datetime import date, datetime
|
|
4
5
|
from typing import Any, Dict, Optional
|
|
5
6
|
|
|
@@ -63,9 +64,15 @@ class SimpleNumberValidator(Validator):
|
|
|
63
64
|
class SimpleStringValidator(Validator):
|
|
64
65
|
"""Simple string validator with real-time feedback."""
|
|
65
66
|
|
|
66
|
-
def __init__(
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
min_length: Optional[int] = None,
|
|
70
|
+
max_length: Optional[int] = None,
|
|
71
|
+
pattern: Optional[str] = None
|
|
72
|
+
):
|
|
67
73
|
self.min_length = min_length
|
|
68
74
|
self.max_length = max_length
|
|
75
|
+
self.pattern = re.compile(pattern, re.DOTALL) if pattern else None
|
|
69
76
|
|
|
70
77
|
def validate(self, document):
|
|
71
78
|
text = document.text
|
|
@@ -83,6 +90,12 @@ class SimpleStringValidator(Validator):
|
|
|
83
90
|
cursor_position=self.max_length,
|
|
84
91
|
)
|
|
85
92
|
|
|
93
|
+
if self.pattern is not None and self.pattern.fullmatch(text) is None:
|
|
94
|
+
# TODO: Wrap or truncate line if too long
|
|
95
|
+
raise ValidationError(
|
|
96
|
+
message=f"Must match pattern '{self.pattern.pattern}'", cursor_position=len(text)
|
|
97
|
+
)
|
|
98
|
+
|
|
86
99
|
|
|
87
100
|
class FormatValidator(Validator):
|
|
88
101
|
"""Format-specific validator using Pydantic validators."""
|
|
@@ -429,6 +442,8 @@ class ElicitationForm:
|
|
|
429
442
|
constraints["minLength"] = field_def["minLength"]
|
|
430
443
|
if field_def.get("maxLength") is not None:
|
|
431
444
|
constraints["maxLength"] = field_def["maxLength"]
|
|
445
|
+
if field_def.get("pattern") is not None:
|
|
446
|
+
constraints["pattern"] = field_def["pattern"]
|
|
432
447
|
|
|
433
448
|
# Check anyOf constraints (for Optional fields)
|
|
434
449
|
if "anyOf" in field_def:
|
|
@@ -438,6 +453,8 @@ class ElicitationForm:
|
|
|
438
453
|
constraints["minLength"] = variant["minLength"]
|
|
439
454
|
if variant.get("maxLength") is not None:
|
|
440
455
|
constraints["maxLength"] = variant["maxLength"]
|
|
456
|
+
if variant.get("pattern") is not None:
|
|
457
|
+
constraints["pattern"] = variant["pattern"]
|
|
441
458
|
break
|
|
442
459
|
|
|
443
460
|
return constraints
|
|
@@ -468,6 +485,10 @@ class ElicitationForm:
|
|
|
468
485
|
if constraints.get("maxLength"):
|
|
469
486
|
hints.append(f"max {constraints['maxLength']} chars")
|
|
470
487
|
|
|
488
|
+
if constraints.get("pattern"):
|
|
489
|
+
# TODO: Wrap or truncate line if too long
|
|
490
|
+
format_hint = f"Pattern: {constraints['pattern']}"
|
|
491
|
+
|
|
471
492
|
# Handle format hints separately (these go on next line)
|
|
472
493
|
format_type = field_def.get("format")
|
|
473
494
|
if format_type:
|
|
@@ -545,6 +566,7 @@ class ElicitationForm:
|
|
|
545
566
|
validator = SimpleStringValidator(
|
|
546
567
|
min_length=constraints.get("minLength"),
|
|
547
568
|
max_length=constraints.get("maxLength"),
|
|
569
|
+
pattern=constraints.get("pattern"),
|
|
548
570
|
)
|
|
549
571
|
else:
|
|
550
572
|
constraints = {}
|
fast_agent/ui/enhanced_prompt.py
CHANGED
|
@@ -9,7 +9,7 @@ import shlex
|
|
|
9
9
|
import subprocess
|
|
10
10
|
import tempfile
|
|
11
11
|
from importlib.metadata import version
|
|
12
|
-
from typing import TYPE_CHECKING, List, Optional
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
13
13
|
|
|
14
14
|
from prompt_toolkit import PromptSession
|
|
15
15
|
from prompt_toolkit.completion import Completer, Completion, WordCompleter
|
|
@@ -24,6 +24,7 @@ from fast_agent.agents.agent_types import AgentType
|
|
|
24
24
|
from fast_agent.constants import FAST_AGENT_ERROR_CHANNEL, FAST_AGENT_REMOVED_METADATA_CHANNEL
|
|
25
25
|
from fast_agent.core.exceptions import PromptExitError
|
|
26
26
|
from fast_agent.llm.model_info import get_model_info
|
|
27
|
+
from fast_agent.mcp.types import McpAgentProtocol
|
|
27
28
|
from fast_agent.ui.mcp_display import render_mcp_status
|
|
28
29
|
|
|
29
30
|
if TYPE_CHECKING:
|
|
@@ -103,10 +104,9 @@ async def _display_agent_info_helper(agent_name: str, agent_provider: "AgentApp
|
|
|
103
104
|
|
|
104
105
|
# Get counts TODO -- add this to the type library or adjust the way aggregator/reporting works
|
|
105
106
|
server_count = 0
|
|
106
|
-
if
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
107
|
+
if isinstance(agent, McpAgentProtocol):
|
|
108
|
+
server_names = agent.aggregator.server_names
|
|
109
|
+
server_count = len(server_names) if server_names else 0
|
|
110
110
|
|
|
111
111
|
tools_result = await agent.list_tools()
|
|
112
112
|
tool_count = (
|
|
@@ -182,6 +182,17 @@ async def _display_agent_info_helper(agent_name: str, agent_provider: "AgentApp
|
|
|
182
182
|
rich_print(f"[dim]Agent [/dim][blue]{agent_name}[/blue][dim]:[/dim] {content}")
|
|
183
183
|
# await _render_mcp_status(agent)
|
|
184
184
|
|
|
185
|
+
# Display Skybridge status (if aggregator discovered any)
|
|
186
|
+
try:
|
|
187
|
+
aggregator = agent.aggregator if isinstance(agent, McpAgentProtocol) else None
|
|
188
|
+
display = getattr(agent, "display", None)
|
|
189
|
+
if aggregator and display and hasattr(display, "show_skybridge_summary"):
|
|
190
|
+
skybridge_configs = await aggregator.get_skybridge_configs()
|
|
191
|
+
display.show_skybridge_summary(agent_name, skybridge_configs)
|
|
192
|
+
except Exception:
|
|
193
|
+
# Ignore Skybridge rendering issues to avoid interfering with startup
|
|
194
|
+
pass
|
|
195
|
+
|
|
185
196
|
# Mark as shown
|
|
186
197
|
_agent_info_shown.add(agent_name)
|
|
187
198
|
|
|
@@ -648,60 +659,102 @@ async def get_enhanced_input(
|
|
|
648
659
|
model_display = None
|
|
649
660
|
tdv_segment = None
|
|
650
661
|
turn_count = 0
|
|
651
|
-
|
|
652
|
-
|
|
662
|
+
agent = None
|
|
663
|
+
if agent_provider:
|
|
664
|
+
try:
|
|
653
665
|
agent = agent_provider._agent(agent_name)
|
|
666
|
+
except Exception as exc:
|
|
667
|
+
print(f"[toolbar debug] unable to resolve agent '{agent_name}': {exc}")
|
|
654
668
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
669
|
+
if agent:
|
|
670
|
+
for message in agent.message_history:
|
|
671
|
+
if message.role == "user":
|
|
672
|
+
turn_count += 1
|
|
673
|
+
|
|
674
|
+
# Resolve LLM reference safely (avoid assertion when unattached)
|
|
675
|
+
llm = None
|
|
676
|
+
try:
|
|
677
|
+
llm = agent.llm
|
|
678
|
+
except AssertionError:
|
|
679
|
+
llm = getattr(agent, "_llm", None)
|
|
680
|
+
except Exception as exc:
|
|
681
|
+
print(f"[toolbar debug] agent.llm access failed for '{agent_name}': {exc}")
|
|
682
|
+
|
|
683
|
+
model_name = None
|
|
684
|
+
if llm:
|
|
685
|
+
model_name = getattr(llm, "model_name", None)
|
|
686
|
+
if not model_name:
|
|
687
|
+
model_name = getattr(
|
|
688
|
+
getattr(llm, "default_request_params", None), "model", None
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
if not model_name:
|
|
692
|
+
model_name = getattr(agent.config, "model", None)
|
|
693
|
+
if not model_name and getattr(agent.config, "default_request_params", None):
|
|
694
|
+
model_name = getattr(agent.config.default_request_params, "model", None)
|
|
695
|
+
if not model_name:
|
|
696
|
+
context = getattr(agent, "context", None) or getattr(
|
|
697
|
+
agent_provider, "context", None
|
|
698
|
+
)
|
|
699
|
+
config_obj = getattr(context, "config", None) if context else None
|
|
700
|
+
model_name = getattr(config_obj, "default_model", None)
|
|
701
|
+
|
|
702
|
+
if model_name:
|
|
703
|
+
max_len = 25
|
|
704
|
+
model_display = (
|
|
705
|
+
model_name[: max_len - 1] + "…" if len(model_name) > max_len else model_name
|
|
706
|
+
)
|
|
707
|
+
else:
|
|
708
|
+
print(f"[toolbar debug] no model resolved for agent '{agent_name}'")
|
|
709
|
+
model_display = "unknown"
|
|
710
|
+
|
|
711
|
+
# Build TDV capability segment based on model database
|
|
712
|
+
info = None
|
|
713
|
+
if llm:
|
|
714
|
+
try:
|
|
715
|
+
info = get_model_info(llm)
|
|
716
|
+
except TypeError:
|
|
717
|
+
info = None
|
|
718
|
+
if not info and model_name:
|
|
719
|
+
try:
|
|
720
|
+
info = get_model_info(model_name)
|
|
721
|
+
except TypeError:
|
|
722
|
+
info = None
|
|
723
|
+
except Exception as exc:
|
|
724
|
+
print(f"[toolbar debug] get_model_info failed for '{agent_name}': {exc}")
|
|
725
|
+
info = None
|
|
726
|
+
|
|
727
|
+
# Default to text-only if info resolution fails for any reason
|
|
728
|
+
t, d, v = (True, False, False)
|
|
729
|
+
if info:
|
|
730
|
+
t, d, v = info.tdv_flags
|
|
731
|
+
|
|
732
|
+
# Check for alert flags in user messages
|
|
733
|
+
alert_flags: set[str] = set()
|
|
734
|
+
error_seen = False
|
|
735
|
+
for message in agent.message_history:
|
|
736
|
+
if message.channels:
|
|
737
|
+
if message.channels.get(FAST_AGENT_ERROR_CHANNEL):
|
|
738
|
+
error_seen = True
|
|
739
|
+
if message.role == "user" and message.channels:
|
|
740
|
+
meta_blocks = message.channels.get(FAST_AGENT_REMOVED_METADATA_CHANNEL, [])
|
|
741
|
+
alert_flags.update(_extract_alert_flags_from_meta(meta_blocks))
|
|
742
|
+
|
|
743
|
+
if error_seen and not alert_flags:
|
|
744
|
+
alert_flags.add("T")
|
|
745
|
+
|
|
746
|
+
def _style_flag(letter: str, supported: bool) -> str:
|
|
747
|
+
# Enabled uses the same color as NORMAL mode (ansigreen), disabled is dim
|
|
748
|
+
if letter in alert_flags:
|
|
749
|
+
return f"<style fg='ansired' bg='ansiblack'>{letter}</style>"
|
|
750
|
+
|
|
751
|
+
enabled_color = "ansigreen"
|
|
752
|
+
if supported:
|
|
753
|
+
return f"<style fg='{enabled_color}' bg='ansiblack'>{letter}</style>"
|
|
754
|
+
return f"<style fg='ansiblack' bg='ansiwhite'>{letter}</style>"
|
|
755
|
+
|
|
756
|
+
tdv_segment = f"{_style_flag('T', t)}{_style_flag('D', d)}{_style_flag('V', v)}"
|
|
757
|
+
else:
|
|
705
758
|
model_display = None
|
|
706
759
|
tdv_segment = None
|
|
707
760
|
|
|
@@ -829,6 +882,46 @@ async def get_enhanced_input(
|
|
|
829
882
|
# Display info for all available agents with tree structure for workflows
|
|
830
883
|
await _display_all_agents_with_hierarchy(available_agents, agent_provider)
|
|
831
884
|
|
|
885
|
+
# Show streaming status message
|
|
886
|
+
if agent_provider:
|
|
887
|
+
# Get logger settings from the agent's context (not agent_provider)
|
|
888
|
+
logger_settings = None
|
|
889
|
+
try:
|
|
890
|
+
agent = agent_provider._agent(agent_name)
|
|
891
|
+
agent_context = agent._context or agent.context
|
|
892
|
+
logger_settings = agent_context.config.logger
|
|
893
|
+
except Exception:
|
|
894
|
+
# If we can't get the agent or its context, logger_settings stays None
|
|
895
|
+
pass
|
|
896
|
+
|
|
897
|
+
# Only show streaming messages if chat display is enabled AND we have logger_settings
|
|
898
|
+
if logger_settings:
|
|
899
|
+
show_chat = getattr(logger_settings, "show_chat", True)
|
|
900
|
+
|
|
901
|
+
if show_chat:
|
|
902
|
+
# Check for parallel agents
|
|
903
|
+
has_parallel = any(
|
|
904
|
+
agent.agent_type == AgentType.PARALLEL
|
|
905
|
+
for agent in agent_provider._agents.values()
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
# Note: streaming may have been disabled by fastagent.py if parallel agents exist
|
|
909
|
+
# So we check has_parallel first to show the appropriate message
|
|
910
|
+
if has_parallel:
|
|
911
|
+
# Streaming is disabled due to parallel agents
|
|
912
|
+
rich_print(
|
|
913
|
+
"[dim]Markdown Streaming disabled (Parallel Agents configured)[/dim]"
|
|
914
|
+
)
|
|
915
|
+
else:
|
|
916
|
+
# Check if streaming is enabled
|
|
917
|
+
streaming_enabled = getattr(logger_settings, "streaming_display", True)
|
|
918
|
+
streaming_mode = getattr(logger_settings, "streaming", "markdown")
|
|
919
|
+
if streaming_enabled and streaming_mode != "none":
|
|
920
|
+
# Streaming is enabled - notify users since it's experimental
|
|
921
|
+
rich_print(
|
|
922
|
+
f"[dim]Experimental: Streaming Enabled - {streaming_mode} mode[/dim]"
|
|
923
|
+
)
|
|
924
|
+
|
|
832
925
|
rich_print()
|
|
833
926
|
help_message_shown = True
|
|
834
927
|
|
|
@@ -1022,7 +1115,9 @@ async def get_argument_input(
|
|
|
1022
1115
|
prompt_session.app.exit()
|
|
1023
1116
|
|
|
1024
1117
|
|
|
1025
|
-
async def handle_special_commands(
|
|
1118
|
+
async def handle_special_commands(
|
|
1119
|
+
command: Any, agent_app: "AgentApp | None" = None
|
|
1120
|
+
) -> bool | Dict[str, Any]:
|
|
1026
1121
|
"""
|
|
1027
1122
|
Handle special input commands.
|
|
1028
1123
|
|
|
@@ -14,7 +14,7 @@ Usage:
|
|
|
14
14
|
)
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Union
|
|
17
|
+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Optional, Union, cast
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from fast_agent.core.agent_app import AgentApp
|
|
@@ -25,6 +25,7 @@ from rich import print as rich_print
|
|
|
25
25
|
from fast_agent.agents.agent_types import AgentType
|
|
26
26
|
from fast_agent.history.history_exporter import HistoryExporter
|
|
27
27
|
from fast_agent.mcp.mcp_aggregator import SEP
|
|
28
|
+
from fast_agent.mcp.types import McpAgentProtocol
|
|
28
29
|
from fast_agent.types import PromptMessageExtended
|
|
29
30
|
from fast_agent.ui.enhanced_prompt import (
|
|
30
31
|
_display_agent_info_helper,
|
|
@@ -114,8 +115,9 @@ class InteractivePrompt:
|
|
|
114
115
|
|
|
115
116
|
# Check if we should switch agents
|
|
116
117
|
if isinstance(command_result, dict):
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
command_dict: Dict[str, Any] = command_result
|
|
119
|
+
if "switch_agent" in command_dict:
|
|
120
|
+
new_agent = command_dict["switch_agent"]
|
|
119
121
|
if new_agent in available_agents_set:
|
|
120
122
|
agent = new_agent
|
|
121
123
|
# Display new agent info immediately when switching
|
|
@@ -126,14 +128,14 @@ class InteractivePrompt:
|
|
|
126
128
|
rich_print(f"[red]Agent '{new_agent}' not found[/red]")
|
|
127
129
|
continue
|
|
128
130
|
# Keep the existing list_prompts handler for backward compatibility
|
|
129
|
-
elif "list_prompts" in
|
|
131
|
+
elif "list_prompts" in command_dict:
|
|
130
132
|
# Use the prompt_provider directly
|
|
131
133
|
await self._list_prompts(prompt_provider, agent)
|
|
132
134
|
continue
|
|
133
|
-
elif "select_prompt" in
|
|
135
|
+
elif "select_prompt" in command_dict:
|
|
134
136
|
# Handle prompt selection, using both list_prompts and apply_prompt
|
|
135
|
-
prompt_name =
|
|
136
|
-
prompt_index =
|
|
137
|
+
prompt_name = command_dict.get("prompt_name")
|
|
138
|
+
prompt_index = command_dict.get("prompt_index")
|
|
137
139
|
|
|
138
140
|
# If a specific index was provided (from /prompt <number>)
|
|
139
141
|
if prompt_index is not None:
|
|
@@ -163,16 +165,20 @@ class InteractivePrompt:
|
|
|
163
165
|
# Use the name-based selection
|
|
164
166
|
await self._select_prompt(prompt_provider, agent, prompt_name)
|
|
165
167
|
continue
|
|
166
|
-
elif "list_tools" in
|
|
168
|
+
elif "list_tools" in command_dict:
|
|
167
169
|
# Handle tools list display
|
|
168
170
|
await self._list_tools(prompt_provider, agent)
|
|
169
171
|
continue
|
|
170
|
-
elif "show_usage" in
|
|
172
|
+
elif "show_usage" in command_dict:
|
|
171
173
|
# Handle usage display
|
|
172
174
|
await self._show_usage(prompt_provider, agent)
|
|
173
175
|
continue
|
|
174
|
-
elif "show_history" in
|
|
175
|
-
|
|
176
|
+
elif "show_history" in command_dict:
|
|
177
|
+
history_info = command_dict.get("show_history")
|
|
178
|
+
history_agent = (
|
|
179
|
+
history_info.get("agent") if isinstance(history_info, dict) else None
|
|
180
|
+
)
|
|
181
|
+
target_agent = history_agent or agent
|
|
176
182
|
try:
|
|
177
183
|
agent_obj = prompt_provider._agent(target_agent)
|
|
178
184
|
except Exception:
|
|
@@ -183,8 +189,12 @@ class InteractivePrompt:
|
|
|
183
189
|
usage = getattr(agent_obj, "usage_accumulator", None)
|
|
184
190
|
display_history_overview(target_agent, history, usage)
|
|
185
191
|
continue
|
|
186
|
-
elif "clear_history" in
|
|
187
|
-
|
|
192
|
+
elif "clear_history" in command_dict:
|
|
193
|
+
clear_info = command_dict.get("clear_history")
|
|
194
|
+
clear_agent = (
|
|
195
|
+
clear_info.get("agent") if isinstance(clear_info, dict) else None
|
|
196
|
+
)
|
|
197
|
+
target_agent = clear_agent or agent
|
|
188
198
|
try:
|
|
189
199
|
agent_obj = prompt_provider._agent(target_agent)
|
|
190
200
|
except Exception:
|
|
@@ -194,7 +204,9 @@ class InteractivePrompt:
|
|
|
194
204
|
if hasattr(agent_obj, "clear"):
|
|
195
205
|
try:
|
|
196
206
|
agent_obj.clear()
|
|
197
|
-
rich_print(
|
|
207
|
+
rich_print(
|
|
208
|
+
f"[green]History cleared for agent '{target_agent}'.[/green]"
|
|
209
|
+
)
|
|
198
210
|
except Exception as exc:
|
|
199
211
|
rich_print(
|
|
200
212
|
f"[red]Failed to clear history for '{target_agent}': {exc}[/red]"
|
|
@@ -204,21 +216,21 @@ class InteractivePrompt:
|
|
|
204
216
|
f"[yellow]Agent '{target_agent}' does not support clearing history.[/yellow]"
|
|
205
217
|
)
|
|
206
218
|
continue
|
|
207
|
-
elif "show_system" in
|
|
219
|
+
elif "show_system" in command_dict:
|
|
208
220
|
# Handle system prompt display
|
|
209
221
|
await self._show_system(prompt_provider, agent)
|
|
210
222
|
continue
|
|
211
|
-
elif "show_markdown" in
|
|
223
|
+
elif "show_markdown" in command_dict:
|
|
212
224
|
# Handle markdown display
|
|
213
225
|
await self._show_markdown(prompt_provider, agent)
|
|
214
226
|
continue
|
|
215
|
-
elif "show_mcp_status" in
|
|
227
|
+
elif "show_mcp_status" in command_dict:
|
|
216
228
|
rich_print()
|
|
217
229
|
await show_mcp_status(agent, prompt_provider)
|
|
218
230
|
continue
|
|
219
|
-
elif "save_history" in
|
|
231
|
+
elif "save_history" in command_dict:
|
|
220
232
|
# Save history for the current agent
|
|
221
|
-
filename =
|
|
233
|
+
filename = command_dict.get("filename")
|
|
222
234
|
try:
|
|
223
235
|
agent_obj = prompt_provider._agent(agent)
|
|
224
236
|
|
|
@@ -353,15 +365,16 @@ class InteractivePrompt:
|
|
|
353
365
|
)
|
|
354
366
|
else:
|
|
355
367
|
# Handle Prompt objects from mcp.types
|
|
368
|
+
prompt_obj = cast("Prompt", prompt)
|
|
356
369
|
all_prompts.append(
|
|
357
370
|
{
|
|
358
371
|
"server": server_name,
|
|
359
|
-
"name":
|
|
360
|
-
"namespaced_name": f"{server_name}{SEP}{
|
|
361
|
-
"title":
|
|
362
|
-
"description":
|
|
363
|
-
"arg_count": len(
|
|
364
|
-
"arguments":
|
|
372
|
+
"name": prompt_obj.name,
|
|
373
|
+
"namespaced_name": f"{server_name}{SEP}{prompt_obj.name}",
|
|
374
|
+
"title": prompt_obj.title or None,
|
|
375
|
+
"description": prompt_obj.description or "No description",
|
|
376
|
+
"arg_count": len(prompt_obj.arguments or []),
|
|
377
|
+
"arguments": prompt_obj.arguments or [],
|
|
365
378
|
}
|
|
366
379
|
)
|
|
367
380
|
|
|
@@ -856,6 +869,10 @@ class InteractivePrompt:
|
|
|
856
869
|
if tool.title and tool.title.strip():
|
|
857
870
|
tool_line.append(f" {tool.title}", style="default")
|
|
858
871
|
|
|
872
|
+
meta = getattr(tool, "meta", {}) or {}
|
|
873
|
+
if meta.get("openai/skybridgeEnabled"):
|
|
874
|
+
tool_line.append(" (skybridge)", style="cyan")
|
|
875
|
+
|
|
859
876
|
rich_print(tool_line)
|
|
860
877
|
|
|
861
878
|
# Description lines - show 2-3 rows if needed
|
|
@@ -909,6 +926,11 @@ class InteractivePrompt:
|
|
|
909
926
|
args_text = args_text[:77] + "..."
|
|
910
927
|
rich_print(f" [dim magenta]args: {args_text}[/dim magenta]")
|
|
911
928
|
|
|
929
|
+
if meta.get("openai/skybridgeEnabled"):
|
|
930
|
+
template = meta.get("openai/skybridgeTemplate")
|
|
931
|
+
if template:
|
|
932
|
+
rich_print(f" [dim magenta]template:[/dim magenta] {template}")
|
|
933
|
+
|
|
912
934
|
rich_print() # Space between tools
|
|
913
935
|
|
|
914
936
|
except Exception as e:
|
|
@@ -962,22 +984,23 @@ class InteractivePrompt:
|
|
|
962
984
|
|
|
963
985
|
# Get server count for display
|
|
964
986
|
server_count = 0
|
|
965
|
-
if
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
)
|
|
987
|
+
if isinstance(agent, McpAgentProtocol):
|
|
988
|
+
server_names = agent.aggregator.server_names
|
|
989
|
+
server_count = len(server_names) if server_names else 0
|
|
969
990
|
|
|
970
991
|
# Use the display utility to show the system prompt
|
|
971
|
-
|
|
972
|
-
|
|
992
|
+
agent_display = getattr(agent, "display", None)
|
|
993
|
+
if agent_display:
|
|
994
|
+
agent_display.show_system_message(
|
|
973
995
|
system_prompt=system_prompt, agent_name=agent_name, server_count=server_count
|
|
974
996
|
)
|
|
975
997
|
else:
|
|
976
998
|
# Fallback to basic display
|
|
977
999
|
from fast_agent.ui.console_display import ConsoleDisplay
|
|
978
1000
|
|
|
1001
|
+
agent_context = getattr(agent, "context", None)
|
|
979
1002
|
display = ConsoleDisplay(
|
|
980
|
-
config=
|
|
1003
|
+
config=agent_context.config if hasattr(agent_context, "config") else None
|
|
981
1004
|
)
|
|
982
1005
|
display.show_system_message(
|
|
983
1006
|
system_prompt=system_prompt, agent_name=agent_name, server_count=server_count
|
|
@@ -1005,11 +1028,11 @@ class InteractivePrompt:
|
|
|
1005
1028
|
agent = prompt_provider._agent(agent_name)
|
|
1006
1029
|
|
|
1007
1030
|
# Check if agent has message history
|
|
1008
|
-
if not
|
|
1031
|
+
if not agent.llm:
|
|
1009
1032
|
rich_print("[yellow]No message history available[/yellow]")
|
|
1010
1033
|
return
|
|
1011
1034
|
|
|
1012
|
-
message_history = agent.
|
|
1035
|
+
message_history = agent.llm.message_history
|
|
1013
1036
|
if not message_history:
|
|
1014
1037
|
rich_print("[yellow]No messages in history[/yellow]")
|
|
1015
1038
|
return
|