Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 14 additions & 15 deletions backend/app/services/agent_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@

settings = get_settings()

# Two workspace roots exist — tool workspace and persistent data
TOOL_WORKSPACE = Path("/tmp/clawith_workspaces")
PERSISTENT_DATA = Path(settings.AGENT_DATA_DIR)


def _agent_workspace(agent_id: uuid.UUID) -> Path:
"""Return the canonical persistent workspace path for an agent."""
return PERSISTENT_DATA / str(agent_id)


def _read_file_safe(path: Path, max_chars: int = 3000) -> str:
"""Read a file, return empty string if missing. Truncate if too long."""
if not path.exists():
Expand Down Expand Up @@ -84,11 +87,10 @@ def _load_skills_index(agent_id: uuid.UUID) -> str:
prompt. The model is instructed to call read_file to load full content
when a skill is relevant.
"""
ws_root = _agent_workspace(agent_id)
skills_dir = ws_root / "skills"
skills: list[tuple[str, str, str]] = [] # (name, description, path_relative_to_skills)
for ws_root in [TOOL_WORKSPACE / str(agent_id), PERSISTENT_DATA / str(agent_id)]:
skills_dir = ws_root / "skills"
if not skills_dir.exists():
continue
if skills_dir.exists():
for entry in sorted(skills_dir.iterdir()):
if entry.name.startswith("."):
continue
Expand Down Expand Up @@ -156,25 +158,24 @@ async def build_agent_context(agent_id: uuid.UUID, agent_name: str, role_descrip
- skills/ → skill names + summaries
- relationships.md → relationship descriptions
"""
tool_ws = TOOL_WORKSPACE / str(agent_id)
data_ws = PERSISTENT_DATA / str(agent_id)
ws_root = _agent_workspace(agent_id)

# --- Soul ---
soul = _read_file_safe(tool_ws / "soul.md", 2000) or _read_file_safe(data_ws / "soul.md", 2000)
soul = _read_file_safe(ws_root / "soul.md", 2000)
# Strip markdown heading if present
if soul.startswith("# "):
soul = "\n".join(soul.split("\n")[1:]).strip()

# --- Memory ---
memory = _read_file_safe(tool_ws / "memory" / "memory.md", 2000) or _read_file_safe(tool_ws / "memory.md", 2000)
memory = _read_file_safe(ws_root / "memory" / "memory.md", 2000) or _read_file_safe(ws_root / "memory.md", 2000)
if memory.startswith("# "):
memory = "\n".join(memory.split("\n")[1:]).strip()

# --- Skills index (progressive disclosure) ---
skills_text = _load_skills_index(agent_id)

# --- Relationships ---
relationships = _read_file_safe(data_ws / "relationships.md", 2000)
relationships = _read_file_safe(ws_root / "relationships.md", 2000)
if relationships.startswith("# "):
relationships = "\n".join(relationships.split("\n")[1:]).strip()

Expand Down Expand Up @@ -392,11 +393,9 @@ async def build_agent_context(agent_id: uuid.UUID, agent_name: str, role_descrip

# --- Focus (working memory) ---
focus = (
_read_file_safe(tool_ws / "focus.md", 3000)
or _read_file_safe(data_ws / "focus.md", 3000)
_read_file_safe(ws_root / "focus.md", 3000)
# Backward compat: also check old name
or _read_file_safe(tool_ws / "agenda.md", 3000)
or _read_file_safe(data_ws / "agenda.md", 3000)
or _read_file_safe(ws_root / "agenda.md", 3000)
)
if focus and focus.strip() not in ("# Focus", "# Agenda", "(暂无)"):
if focus.startswith("# "):
Expand Down
24 changes: 10 additions & 14 deletions backend/app/services/heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,14 @@ async def _execute_heartbeat(agent_id: uuid.UUID):
settings = get_settings()

heartbeat_instruction = DEFAULT_HEARTBEAT_INSTRUCTION
for ws_root in [
Path("/tmp/clawith_workspaces") / str(agent_id),
Path(settings.AGENT_DATA_DIR) / str(agent_id),
]:
hb_file = ws_root / "HEARTBEAT.md"
if hb_file.exists():
try:
custom = hb_file.read_text(encoding="utf-8", errors="replace").strip()
if custom:
# Prepend privacy rules to custom heartbeat
heartbeat_instruction = custom + """
ws_root = Path(settings.AGENT_DATA_DIR) / str(agent_id)
hb_file = ws_root / "HEARTBEAT.md"
if hb_file.exists():
try:
custom = hb_file.read_text(encoding="utf-8", errors="replace").strip()
if custom:
# Prepend privacy rules to custom heartbeat
heartbeat_instruction = custom + """

⚠️ PRIVACY RULES — STRICTLY FOLLOW:
- NEVER share information from private user conversations
Expand All @@ -168,9 +165,8 @@ async def _execute_heartbeat(agent_id: uuid.UUID):
- Maximum 2 comments on existing posts
- Do NOT post trivial or repetitive content
"""
except Exception:
pass
break
except Exception:
pass

# Build context
from app.services.agent_context import build_agent_context
Expand Down