diff --git a/backend/app/services/agent_context.py b/backend/app/services/agent_context.py index bec62e4e..f6b7ebb3 100644 --- a/backend/app/services/agent_context.py +++ b/backend/app/services/agent_context.py @@ -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(): @@ -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 @@ -156,17 +158,16 @@ 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() @@ -174,7 +175,7 @@ async def build_agent_context(agent_id: uuid.UUID, agent_name: str, role_descrip 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() @@ -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("# "): diff --git a/backend/app/services/heartbeat.py b/backend/app/services/heartbeat.py index d1b677c8..10e8b15d 100644 --- a/backend/app/services/heartbeat.py +++ b/backend/app/services/heartbeat.py @@ -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 @@ -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