MCPcopy
hub / github.com/dataelement/Clawith / build_agent_context

Function build_agent_context

backend/app/services/agent_context.py:243–721  ·  view source on GitHub ↗

Build a rich system prompt incorporating agent's full context. Reads from workspace files and DB: - soul.md → personality - memory.md → long-term memory - skills/ → skill names + summaries - Database → relationship network (human + agent)

(agent_id: uuid.UUID, agent_name: str, role_description: str = "", current_user_name: str = None)

Source from the content-addressed store, hash-verified

241
242
243async def build_agent_context(agent_id: uuid.UUID, agent_name: str, role_description: str = "", current_user_name: str = None) -> tuple[str, str]:
244 """Build a rich system prompt incorporating agent's full context.
245
246 Reads from workspace files and DB:
247 - soul.md → personality
248 - memory.md → long-term memory
249 - skills/ → skill names + summaries
250 - Database → relationship network (human + agent)
251 """
252 # --- Soul ---
253 # Soul is the agent's full author-curated identity; detailed souls (e.g.
254 # bundle agents) run 4-12k chars. A tight cap silently drops every tail
255 # section — rules, boundaries, facts — and the agent then confidently
256 # denies things its soul plainly states, with no log of the truncation.
257 # Memory and relationships below keep small caps because they grow
258 # unbounded at runtime; the soul does not (only seeded/explicitly edited).
259 soul = await _read_file_safe(normalize_storage_key(f"{agent_id}/soul.md"), 30000)
260 # Strip markdown heading if present
261 if soul.startswith("# "):
262 soul = "\n".join(soul.split("\n")[1:]).strip()
263
264 # --- Memory ---
265 memory = await _read_file_safe(normalize_storage_key(f"{agent_id}/memory/memory.md"), 2000)
266 if not memory:
267 memory = await _read_file_safe(normalize_storage_key(f"{agent_id}/memory.md"), 2000)
268 if memory.startswith("# "):
269 memory = "\n".join(memory.split("\n")[1:]).strip()
270
271 # --- Skills index (progressive disclosure) ---
272 skills_text = await _load_skills_index(agent_id)
273
274 # --- Relationships ---
275 from app.database import async_session
276 async with async_session() as db:
277 relationships = await _load_relationships_from_db(db, agent_id)
278
279 # --- Compose static and dynamic system prompt blocks ---
280 from datetime import datetime, timezone as _tz
281 from app.services.timezone_utils import get_agent_timezone, now_in_timezone
282 agent_tz_name = await get_agent_timezone(agent_id)
283 agent_local_now = now_in_timezone(agent_tz_name)
284 now_str = agent_local_now.strftime(f"%Y-%m-%d %H:%M:%S ({agent_tz_name})")
285
286 static_parts = [f"You are {agent_name}, an enterprise digital employee."]
287
288
289 if role_description:
290 static_parts.append(f"\n## Role\n{role_description}")
291
292 if agent_name == "OKR Agent":
293 static_parts.append("""
294## Daily Report Recording Rules
295
296🔴 **ABSOLUTE RULE — MUST CALL `upsert_member_daily_report` IMMEDIATELY:**
297When ANY tracked member or agent sends you content that looks like a daily work update, status report, or progress note — **IMMEDIATELY call `upsert_member_daily_report` in the SAME response turn. Do NOT:**
298- First explain what you plan to do, then call the tool in a second turn
299- Claim the tool is unavailable, broken, or unknown — **it is ALWAYS available**
300- Write the report to memory, Focus, or any file instead

Callers 7

_execute_scheduleFunction · 0.90
execute_taskFunction · 0.90
_execute_heartbeatFunction · 0.90
run_agent_oneshotFunction · 0.90
_get_agent_replyFunction · 0.90
call_llmFunction · 0.90

Calls 12

normalize_storage_keyFunction · 0.90
get_agent_timezoneFunction · 0.90
now_in_timezoneFunction · 0.90
_read_file_safeFunction · 0.85
_load_skills_indexFunction · 0.85
whereMethod · 0.80
executeMethod · 0.45
scalar_one_or_noneMethod · 0.45
getMethod · 0.45
allMethod · 0.45
scalarsMethod · 0.45