fast-agent-mcp 0.3.12__py3-none-any.whl → 0.3.14__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 +15 -34
- fast_agent/agents/llm_decorator.py +13 -2
- fast_agent/agents/mcp_agent.py +18 -2
- fast_agent/agents/tool_agent.py +8 -10
- fast_agent/cli/commands/check_config.py +45 -1
- fast_agent/config.py +63 -0
- fast_agent/constants.py +3 -0
- fast_agent/context.py +42 -9
- fast_agent/core/logging/listeners.py +1 -1
- fast_agent/event_progress.py +2 -3
- fast_agent/interfaces.py +9 -2
- fast_agent/llm/model_factory.py +4 -0
- fast_agent/llm/provider/google/google_converter.py +10 -3
- 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_agent_client_session.py +13 -0
- fast_agent/mcp/mcp_aggregator.py +313 -40
- fast_agent/mcp/mcp_connection_manager.py +95 -22
- 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 +5 -0
- fast_agent/ui/console_display.py +347 -20
- fast_agent/ui/enhanced_prompt.py +107 -58
- fast_agent/ui/interactive_prompt.py +57 -34
- fast_agent/ui/mcp_display.py +159 -41
- fast_agent/ui/rich_progress.py +4 -1
- {fast_agent_mcp-0.3.12.dist-info → fast_agent_mcp-0.3.14.dist-info}/METADATA +16 -7
- {fast_agent_mcp-0.3.12.dist-info → fast_agent_mcp-0.3.14.dist-info}/RECORD +35 -32
- {fast_agent_mcp-0.3.12.dist-info → fast_agent_mcp-0.3.14.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.3.12.dist-info → fast_agent_mcp-0.3.14.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.3.12.dist-info → fast_agent_mcp-0.3.14.dist-info}/licenses/LICENSE +0 -0
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,96 @@ 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(getattr(llm, "default_request_params", None), "model", None)
|
|
688
|
+
|
|
689
|
+
if not model_name:
|
|
690
|
+
model_name = getattr(agent.config, "model", None)
|
|
691
|
+
if not model_name and getattr(agent.config, "default_request_params", None):
|
|
692
|
+
model_name = getattr(agent.config.default_request_params, "model", None)
|
|
693
|
+
if not model_name:
|
|
694
|
+
context = getattr(agent, "context", None) or getattr(agent_provider, "context", None)
|
|
695
|
+
config_obj = getattr(context, "config", None) if context else None
|
|
696
|
+
model_name = getattr(config_obj, "default_model", None)
|
|
697
|
+
|
|
698
|
+
if model_name:
|
|
699
|
+
max_len = 25
|
|
700
|
+
model_display = model_name[: max_len - 1] + "…" if len(model_name) > max_len else model_name
|
|
701
|
+
else:
|
|
702
|
+
print(f"[toolbar debug] no model resolved for agent '{agent_name}'")
|
|
703
|
+
model_display = "unknown"
|
|
704
|
+
|
|
705
|
+
# Build TDV capability segment based on model database
|
|
706
|
+
info = None
|
|
707
|
+
if llm:
|
|
708
|
+
try:
|
|
709
|
+
info = get_model_info(llm)
|
|
710
|
+
except TypeError:
|
|
711
|
+
info = None
|
|
712
|
+
if not info and model_name:
|
|
713
|
+
try:
|
|
714
|
+
info = get_model_info(model_name)
|
|
715
|
+
except TypeError:
|
|
716
|
+
info = None
|
|
717
|
+
except Exception as exc:
|
|
718
|
+
print(f"[toolbar debug] get_model_info failed for '{agent_name}': {exc}")
|
|
719
|
+
info = None
|
|
720
|
+
|
|
721
|
+
# Default to text-only if info resolution fails for any reason
|
|
722
|
+
t, d, v = (True, False, False)
|
|
723
|
+
if info:
|
|
724
|
+
t, d, v = info.tdv_flags
|
|
725
|
+
|
|
726
|
+
# Check for alert flags in user messages
|
|
727
|
+
alert_flags: set[str] = set()
|
|
728
|
+
error_seen = False
|
|
729
|
+
for message in agent.message_history:
|
|
730
|
+
if message.channels:
|
|
731
|
+
if message.channels.get(FAST_AGENT_ERROR_CHANNEL):
|
|
732
|
+
error_seen = True
|
|
733
|
+
if message.role == "user" and message.channels:
|
|
734
|
+
meta_blocks = message.channels.get(FAST_AGENT_REMOVED_METADATA_CHANNEL, [])
|
|
735
|
+
alert_flags.update(_extract_alert_flags_from_meta(meta_blocks))
|
|
736
|
+
|
|
737
|
+
if error_seen and not alert_flags:
|
|
738
|
+
alert_flags.add("T")
|
|
739
|
+
|
|
740
|
+
def _style_flag(letter: str, supported: bool) -> str:
|
|
741
|
+
# Enabled uses the same color as NORMAL mode (ansigreen), disabled is dim
|
|
742
|
+
if letter in alert_flags:
|
|
743
|
+
return f"<style fg='ansired' bg='ansiblack'>{letter}</style>"
|
|
744
|
+
|
|
745
|
+
enabled_color = "ansigreen"
|
|
746
|
+
if supported:
|
|
747
|
+
return f"<style fg='{enabled_color}' bg='ansiblack'>{letter}</style>"
|
|
748
|
+
return f"<style fg='ansiblack' bg='ansiwhite'>{letter}</style>"
|
|
749
|
+
|
|
750
|
+
tdv_segment = f"{_style_flag('T', t)}{_style_flag('D', d)}{_style_flag('V', v)}"
|
|
751
|
+
else:
|
|
705
752
|
model_display = None
|
|
706
753
|
tdv_segment = None
|
|
707
754
|
|
|
@@ -1022,7 +1069,9 @@ async def get_argument_input(
|
|
|
1022
1069
|
prompt_session.app.exit()
|
|
1023
1070
|
|
|
1024
1071
|
|
|
1025
|
-
async def handle_special_commands(
|
|
1072
|
+
async def handle_special_commands(
|
|
1073
|
+
command: Any, agent_app: "AgentApp | None" = None
|
|
1074
|
+
) -> bool | Dict[str, Any]:
|
|
1026
1075
|
"""
|
|
1027
1076
|
Handle special input commands.
|
|
1028
1077
|
|
|
@@ -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
|