Skip to content

Commit aad8d6e

Browse files
authored
Merge pull request #831 from inclusionAI/filesystem_traj
[cli]: /compact compact history and workspace /cost support by agent statistics pre [aworld_agent]: use CONTEXT_TOOL to fetch past sessions and thire path [core]: filesystem based memory
2 parents 6847508 + a03da22 commit aad8d6e

30 files changed

Lines changed: 2246 additions & 321 deletions

File tree

aworld-cli/src/aworld_cli/console.py

Lines changed: 145 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
from rich.style import Style
1616
from rich.table import Table
1717
from rich.text import Text
18+
import os
1819

1920
from aworld.logs.util import logger
2021
from ._globals import console
21-
from .core.skill_registry import get_skill_registry
22+
from .core.skill_registry import get_skill_registry, get_user_skills_paths
2223
from .models import AgentInfo
2324
from .user_input import UserInputHandler
2425

@@ -695,7 +696,87 @@ def __rich_console__(self, console, options):
695696

696697
# Print layout full width
697698
self.console.print(layout)
698-
699+
700+
def _display_system_info(self, help_text: str = ""):
701+
"""
702+
Display comprehensive system information including help commands,
703+
configuration, skills, agents, and memory loading locations.
704+
Consistent styling with _show_banner from main.py.
705+
"""
706+
707+
# Section 1: Help Commands
708+
self.console.print(Panel(help_text or "Available Commands", title="📋 Help", style="blue", border_style="bright_cyan"))
709+
710+
def _display_conf_info(self):
711+
from pathlib import Path
712+
from rich.table import Table
713+
714+
# Keep visual style aligned with main banner output.
715+
self.console.print("[bold bright_cyan]⚙ System Configuration[/bold bright_cyan]")
716+
717+
info_table = Table(show_header=False, box=None, padding=(0, 2))
718+
info_table.add_column("Icon", style="bright_yellow", justify="left")
719+
info_table.add_column("Component", style="bold bright_green")
720+
info_table.add_column("Details", style="bright_white")
721+
info_table.add_column("Status", justify="right")
722+
723+
# 1. Configuration
724+
try:
725+
from .core.config import get_config
726+
config = get_config()
727+
source_type, source_path = config.get_config_source(".env")
728+
# Keep source selection aligned with load_config_with_env:
729+
# local .env has higher priority; otherwise use global aworld.json.
730+
config_path = source_path if (source_type == "local" and source_path) else config.get_config_path()
731+
config_status = "[bold bright_green]ONLINE[/bold bright_green]"
732+
config_loc = f"[dim]{config_path}[/dim]"
733+
except Exception as e:
734+
config_status = "[bold red]ERROR[/bold red]"
735+
config_loc = f"[dim red]Error: {e}[/dim red]"
736+
info_table.add_row("⚡", "Config", config_loc, )
737+
738+
# 2. Memory
739+
try:
740+
from aworld.memory.main import _default_file_memory_store
741+
memory_store = _default_file_memory_store()
742+
memory_location = getattr(memory_store, 'memory_root', 'Unknown')
743+
memory_status = "[bold bright_green]ACTIVE[/bold bright_green]"
744+
memory_loc = f"[dim]{memory_location}[/dim]"
745+
except Exception as e:
746+
memory_status = "[bold red]ERROR[/bold red]"
747+
memory_loc = f"[dim red]Error: {e}[/dim red]"
748+
info_table.add_row("💾", "Memory", memory_loc, )
749+
750+
# 3. Skills
751+
try:
752+
from .core.skill_registry import get_skill_registry
753+
registry = get_skill_registry()
754+
skills_count = len(registry.get_all_skills())
755+
skills_loc = f"[dim]{[str(p) for p in get_user_skills_paths()]}[/dim]"
756+
skills_status = f"[bold bright_green]{skills_count} LOADED[/bold bright_green]"
757+
except Exception as e:
758+
skills_status = "[bold red]ERROR[/bold red]"
759+
skills_loc = f"[dim red]Error: {e}[/dim red]"
760+
info_table.add_row("🎯", "Skills", skills_loc, )
761+
762+
# 4. Agents
763+
try:
764+
import os
765+
agents_loc = os.path.expanduser(os.environ.get('AGENTS_PATH', '~/.aworld/agents'))
766+
agents_status = (
767+
"[bold bright_green]READY[/bold bright_green]"
768+
if Path(agents_loc).exists()
769+
else "[bold yellow]MISSING[/bold yellow]"
770+
)
771+
agents_loc_styled = f"[dim]{agents_loc}[/dim]"
772+
except Exception as e:
773+
agents_status = "[bold red]ERROR[/bold red]"
774+
agents_loc_styled = f"[dim red]Error: {e}[/dim red]"
775+
info_table.add_row("🤖", "Agents", agents_loc_styled, )
776+
777+
self.console.print(info_table)
778+
self.console.print()
779+
699780
async def _esc_key_listener(self):
700781
"""
701782
Background listener for Esc key to interrupt currently executing tasks.
@@ -765,7 +846,7 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
765846
session_id_info = ""
766847
if executor_instance and hasattr(executor_instance, 'session_id'):
767848
session_id_info = f"\nCurrent session: [dim]{executor_instance.session_id}[/dim]"
768-
849+
self.console.print(f"Starting chat with [bold]{agent_name}[/bold]. Type /help for available commands.")
769850
# Get agent configuration info (PTC, MCP servers, and Skills)
770851
config_info = ""
771852
if available_agents:
@@ -823,9 +904,9 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
823904
f"Type '/skills' to list all available skills.\n"
824905
f"Type '/agents' to list all available agents.\n"
825906
f"Type '/cost' for current session, '/cost -all' for global history.\n"
907+
f"Type '/compact' to run context compression.\n"
826908
f"Use @filename to include images or text files (e.g., @photo.jpg or @document.txt)."
827909
)
828-
self.console.print(Panel(help_text, style="blue"))
829910

830911
# Check if we're in a real terminal (not IDE debugger or redirected input)
831912
is_terminal = sys.stdin.isatty()
@@ -838,7 +919,7 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
838919
# 用整行前缀匹配:/ski → /skills、/age → /agents;meta_dict 在补全菜单中显示描述(命令左、描述右)
839920
slash_cmds = [
840921
"/agents", "/skills", "/new", "/restore", "/latest",
841-
"/exit", "/quit", "/switch", "/cost", "/cost -all",
922+
"/exit", "/quit", "/switch", "/cost", "/cost -all", "/compact",
842923
]
843924
switch_with_agents = [f"/switch {n}" for n in agent_names] if agent_names else []
844925
all_words = slash_cmds + switch_with_agents + ["exit", "quit"]
@@ -853,6 +934,7 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
853934
"/switch": "Switch to another agent",
854935
"/cost": "View query history (current session)",
855936
"/cost -all": "View global history (all sessions)",
937+
"/compact": "Run context compression",
856938
"exit": "Exit chat",
857939
"quit": "Exit chat",
858940
}
@@ -892,12 +974,17 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
892974
# Skip empty input (user just pressed Enter)
893975
if not user_input:
894976
continue
895-
977+
896978
# Handle explicit exit commands
897979
if user_input.lower() in ("exit", "quit", "/exit", "/quit"):
898980
self.console.print("[dim]Bye[/dim]")
899981
return False
900982

983+
# Handle help command - show system information
984+
if user_input.lower() in ("/help", "help"):
985+
self._display_system_info(help_text)
986+
continue
987+
901988
# Handle new session command
902989
if user_input.lower() in ("/new", "new"):
903990
if executor_instance and hasattr(executor_instance, 'new_session'):
@@ -1013,13 +1100,13 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
10131100
show_all = "-all" in cost_input
10141101

10151102
if show_all:
1016-
self.console.print(history.format_history_display(session_id=None))
1103+
self.console.print(history.format_cost_display(session_id=None))
10171104
else:
10181105
current_session_id = None
10191106
if executor_instance and hasattr(executor_instance, 'session_id'):
10201107
current_session_id = executor_instance.session_id
10211108
if current_session_id:
1022-
self.console.print(history.format_history_display(session_id=current_session_id))
1109+
self.console.print(history.format_cost_display(session_id=current_session_id))
10231110
else:
10241111
self.console.print("[yellow]No current session. Use /cost -all for global history.[/yellow]")
10251112

@@ -1029,6 +1116,56 @@ async def run_chat_session(self, agent_name: str, executor: Callable[[str], Any]
10291116
traceback.print_exc()
10301117
continue
10311118

1119+
# Handle compact command (context compression)
1120+
if user_input.lower() in ("/compact", "compact"):
1121+
try:
1122+
from .core.context import run_context_optimization
1123+
1124+
if not executor_instance:
1125+
self.console.print("[yellow]⚠️ No executor instance available for compression.[/yellow]")
1126+
continue
1127+
1128+
# Get session_id from executor
1129+
session_id = getattr(executor_instance, 'session_id', None)
1130+
if not session_id:
1131+
self.console.print("[yellow]⚠️ No session ID available for compression.[/yellow]")
1132+
continue
1133+
1134+
self.console.print("[dim]Running context compression...[/dim]")
1135+
1136+
# Get agent name from executor or swarm
1137+
agent_id = agent_name
1138+
if hasattr(executor_instance, 'swarm') and executor_instance.swarm:
1139+
swarm = executor_instance.swarm
1140+
if hasattr(swarm, 'agent_graph') and swarm.agent_graph:
1141+
agents = swarm.agent_graph.agents
1142+
if agents:
1143+
# Get first agent name
1144+
agent_id = list(agents.keys())[0] if agents.keys() else agent_name
1145+
1146+
# Run compression directly with session_id (no need to construct context)
1147+
ok, tokens_before, tokens_after, msg, compressed_content = await run_context_optimization(
1148+
agent_id=agent_id,
1149+
session_id=session_id
1150+
)
1151+
1152+
if ok:
1153+
ratio = ((tokens_before - tokens_after) / tokens_before) * 100 if tokens_before > 0 else 0
1154+
self.console.print(
1155+
f"[dim]Context compressed: {tokens_before:,}{tokens_after:,} tokens ({ratio:.1f}% reduction)[/dim]"
1156+
)
1157+
# Display compressed content in gray
1158+
if compressed_content:
1159+
self.console.print(f"[dim]{compressed_content}[/dim]")
1160+
else:
1161+
self.console.print(f"[yellow]⚠️ {msg}[/yellow]")
1162+
1163+
except Exception as e:
1164+
self.console.print(f"[red]Error running compression: {e}[/red]")
1165+
import traceback
1166+
traceback.print_exc()
1167+
continue
1168+
10321169
# Handle agents command
10331170
if user_input.lower() in ("/agents", "agents"):
10341171
try:
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions.
2+
This summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing development work without losing context.
3+
4+
Your summary should include the following sections:
5+
6+
1. Primary Request and Intent: Capture all of the user's explicit requests and intents in detail
7+
2. Key Technical Concepts: List all important technical concepts, technologies, and frameworks discussed.
8+
3. Files and Code Sections: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
9+
4. Errors and fixes: List all errors that you ran into, and how you fixed them. Pay special attention to specific user feedback that you received, especially if the user told you to do something differently.
10+
5. Problem Solving: Document problems solved and any ongoing troubleshooting efforts.
11+
6. All user messages: List ALL user messages that are not tool results. These are critical for understanding the users' feedback and changing intent.
12+
7. Pending Tasks: Outline any pending tasks that you have explicitly been asked to work on.
13+
8. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
14+
9. Optional Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests or really old requests that were already completed without confirming with the user first.
15+
If there is a next step, include direct quotes from the most recent conversation showing exactly what task you were working on and where you left off. This should be verbatim to ensure there's no drift in task interpretation.
16+
17+
Here's an example of how your output should be structured:
18+
19+
<example>
20+
<analysis>
21+
[Your thought process, ensuring all points are covered thoroughly and accurately]
22+
</analysis>
23+
24+
<summary>
25+
1. Primary Request and Intent:
26+
[Detailed description]
27+
28+
2. Key Technical Concepts:
29+
- [Concept 1]
30+
- [Concept 2]
31+
- [...]
32+
33+
3. Files and Code Sections:
34+
- [File Name 1]
35+
- [Summary of why this file is important]
36+
- [Summary of the changes made to this file, if any]
37+
- [Important Code Snippet]
38+
- [File Name 2]
39+
- [Important Code Snippet]
40+
- [...]
41+
42+
4. Errors and fixes:
43+
- [Detailed description of error 1]:
44+
- [How you fixed the error]
45+
- [User feedback on the error if any]
46+
- [...]
47+
48+
5. Problem Solving:
49+
[Description of solved problems and ongoing troubleshooting]
50+
51+
6. All user messages:
52+
- [Detailed non tool use user message]
53+
- [...]
54+
55+
7. Pending Tasks:
56+
- [Task 1]
57+
- [Task 2]
58+
- [...]
59+
60+
8. Current Work:
61+
[Precise description of current work]
62+
63+
9. Optional Next Step:
64+
[Optional Next step to take]
65+
66+
</summary>
67+
</example>
68+
69+
Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.
70+
71+
There may be additional summarization instructions provided in the included context. If so, remember to follow these instructions when creating the above summary. Examples of instructions include:
72+
<example>
73+
## Compact Instructions
74+
When summarizing the conversation focus on typescript code changes and also remember the mistakes you made and how you fixed them.
75+
</example>
76+
77+
<example>
78+
# Summary instructions
79+
When you are using compact - please focus on test output and code changes. Include file reads verbatim.
80+
</example>
81+
82+
83+
<user_task> {user_task} </user_task>
84+
<existed_summary> {existed_summary} </existed_summary>
85+
<conversation> {to_be_summary} </conversation>
86+
87+
## output new summary:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Your task is to create a detailed summary of the workspace so far, paying close attention to the user's explicit requests and your previous actions.
2+
This summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing development work without losing context.
3+
4+
Your summary should include the following sections:
5+
6+
1. Primary Request and Intent: Capture all of the user's explicit requests and intents in detail
7+
2. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
8+
3. Files and Code Sections: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
9+
10+
<user_task> {user_task} </user_task>
11+
<existed_summary> {existed_summary} </existed_summary>
12+
13+
## output new summary:

0 commit comments

Comments
 (0)