feat(curator): trigger Knowledge Curator from api_mark_final, drop CEO F2
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
The previous F2 stage in legal-ceo.md fired after the first DOCX export — too early, since the user often iterates with עריכה-* uploads after the first export. The true "this is dafna's chosen final" signal is the "סמן כסופי" button in the UI, which calls api_mark_final. This commit moves the curator wakeup from CEO's instructions to a direct hook in api_mark_final: - web/paperclip_client.py: add CURATOR_AGENTS dict (CMP + CMPA UUIDs) and wake_curator_for_final() helper. Looks up main case issue, creates a child issue assigned to the curator, tags plugin_state for case visibility, and triggers wakeup via Paperclip API. - web/app.py: api_mark_final now calls workflow_tools.ingest_final_version (so case_law table finally gets populated for search_decisions) and pc_wake_curator_for_final. Both are best-effort — failure does not block marking final. - legal-ceo.md: remove F2 stage, leave only the agents-table reference noting the curator runs from api_mark_final. - hermes-curator.md: update activation description to reflect the new flow. Result: curator runs only when chaim deliberately clicks "סמן כסופי", on the actual final file, with no risk of analyzing a draft that will later change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
34
web/app.py
34
web/app.py
@@ -62,6 +62,7 @@ from web.paperclip_client import (
|
||||
respond_to_interaction as pc_respond_to_interaction,
|
||||
restore_project as pc_restore_project,
|
||||
wake_ceo_agent as pc_wake_ceo,
|
||||
wake_curator_for_final as pc_wake_curator_for_final,
|
||||
wake_for_precedent_extraction as pc_wake_for_precedent_extraction,
|
||||
)
|
||||
|
||||
@@ -2347,10 +2348,43 @@ async def api_mark_final(case_number: str, filename: str):
|
||||
if case_dir.exists():
|
||||
commit_and_push(case_dir, f"גרסה סופית: {final_name}")
|
||||
|
||||
# Best-effort: ingest final into internal corpus (case_law) — feeds
|
||||
# search_decisions and learning_loop. Non-fatal on failure.
|
||||
ingest_status: dict = {"status": "skipped"}
|
||||
try:
|
||||
ingest_result = await workflow_tools.ingest_final_version(
|
||||
case_number, file_path=str(final_path)
|
||||
)
|
||||
ingest_status = {"status": "ok", "result": (ingest_result or "")[:200]}
|
||||
except Exception as e:
|
||||
logger.warning("ingest_final_version failed for %s: %s", case_number, e)
|
||||
ingest_status = {"status": "error", "error": str(e)}
|
||||
|
||||
# Best-effort: wake the Knowledge Curator (Hermes) to analyze the
|
||||
# signed final and propose updates to skills/lessons. Non-fatal on
|
||||
# failure so marking final never breaks for the user.
|
||||
curator_status: dict = {"status": "skipped"}
|
||||
try:
|
||||
# Company by case-number prefix: 1xxx=CMP (licensing), 8/9xxx=CMPA (betterment)
|
||||
prefix = case_number[:1]
|
||||
company_id = (
|
||||
PAPERCLIP_COMPANIES["licensing"] if prefix == "1"
|
||||
else PAPERCLIP_COMPANIES["betterment"] if prefix in ("8", "9")
|
||||
else ""
|
||||
)
|
||||
curator_status = await pc_wake_curator_for_final(
|
||||
case_number, final_name, company_id=company_id
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("curator wakeup failed for %s: %s", case_number, e)
|
||||
curator_status = {"status": "error", "error": str(e)}
|
||||
|
||||
return {
|
||||
"final_filename": final_name,
|
||||
"training_copy": str(training_dest),
|
||||
"status": "final",
|
||||
"ingest_final": ingest_status,
|
||||
"curator": curator_status,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user