feat(api): multi-project folder manifest for daily brief
Add build_brief_multi_project_manifest() to deep_agent.py that fetches all project folder manifests via execute_on_client and keeps the top 5 most-recently-modified files per project. Wire into run_home_brief in brief_agent.py, injecting the <linked_folders> block into the system prompt alongside FOLDER_TOOLS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from app.core.deep_agent import (
|
||||
_relational_memory_injection,
|
||||
_run_single_agent_stream,
|
||||
_trace_id_from_context,
|
||||
build_brief_multi_project_manifest,
|
||||
)
|
||||
from app.core.langfuse_client import compile_prompt, get_prompt_or_fallback
|
||||
|
||||
@@ -159,6 +160,8 @@ async def run_home_brief(
|
||||
Yields (event_type, data) tuples identical to _run_single_agent_stream.
|
||||
Do NOT post-process output through _normalize_tagged_list_lines.
|
||||
"""
|
||||
from app.agents.folder_agent import FOLDER_TOOLS
|
||||
|
||||
trace_id = _trace_id_from_context(context)
|
||||
today = date.today().isoformat()
|
||||
language = _resolve_language(context)
|
||||
@@ -171,7 +174,10 @@ async def run_home_brief(
|
||||
if today not in system_prompt:
|
||||
system_prompt += f"\nToday is {today}."
|
||||
|
||||
tools = _build_read_tools(user_id, trace_id)
|
||||
brief_manifest = await build_brief_multi_project_manifest()
|
||||
system_prompt = system_prompt + ("\n\n" + brief_manifest if brief_manifest else "")
|
||||
|
||||
tools = [*_build_read_tools(user_id, trace_id), *FOLDER_TOOLS]
|
||||
async for event in _run_single_agent_stream(
|
||||
user_id=user_id,
|
||||
system_prompt=system_prompt,
|
||||
|
||||
@@ -110,6 +110,35 @@ async def _fetch_project_manifest(project_id: str) -> dict | None:
|
||||
return None
|
||||
|
||||
|
||||
async def build_brief_multi_project_manifest() -> str:
|
||||
"""Build a compact multi-project manifest for the daily brief agent.
|
||||
|
||||
Calls execute_on_client('list_projects_with_folder_manifests') and keeps
|
||||
the top 5 most-recently-modified files per project.
|
||||
"""
|
||||
try:
|
||||
result = await execute_on_client(
|
||||
action="list_projects_with_folder_manifests",
|
||||
data={},
|
||||
)
|
||||
except Exception:
|
||||
return ""
|
||||
projects = (result or {}).get("projects") or []
|
||||
if not projects:
|
||||
return ""
|
||||
blocks: list[str] = ["<linked_folders>"]
|
||||
for p in projects:
|
||||
files = sorted(p.get("files", []), key=lambda f: f.get("mtimeMs", 0), reverse=True)[:5]
|
||||
if not files:
|
||||
continue
|
||||
blocks.append(f"project: {p.get('projectName','?')} [{p.get('projectId','?')}]")
|
||||
blocks.append(f" path: {p.get('folderPath','?')} (scanned {p.get('lastScannedAt','?')})")
|
||||
for f in files:
|
||||
blocks.append(f" - /{f['relPath']} [{f.get('kind','text')}] {f.get('summary','')}")
|
||||
blocks.append("</linked_folders>")
|
||||
return "\n".join(blocks)
|
||||
|
||||
|
||||
def _datetime_context_injection(context: dict[str, Any]) -> str:
|
||||
"""Build a comprehensive DATE CONTEXT block with pre-computed ms-epoch boundaries for common ranges."""
|
||||
fp = context.get("format_prefs")
|
||||
|
||||
Reference in New Issue
Block a user