Files
legal-ai/scripts/curator_apply_pipeline_branch.py
Chaim 98c5feff25 feat(cases): תצוגת "פסיקה שצוטטה בהחלטה" בעמוד-התיק + שחזור חיווט-הרמס
UI שביקש חיים: בכניסה להחלטה רואים את הפסיקה שצוטטה בתוכה — מקושרת לספרייה
(קליק → /precedents/[id]) מול חסרה (סומנה אוטומטית להעלאה).

- web/app.py: GET /api/cases/{case}/citations — מהשורה internal_committee של
  ההחלטה ב-case_law → precedent_internal_citations: linked (join case_law) +
  missing (unresolved + האם flagged ב-missing_precedents).
- web-ui: lib/api/citations.ts (hook) + CitationsSection ב-drafts-panel
  (מוצג כשההחלטה בספרייה). מקושרת=ירוק/קליק, חסרה=ענבר "סומנה להעלאה".
- scripts/curator_apply_pipeline_branch.py: מקור-אמת לחיווט-הכפתורים של הרמס
  (ה-prompt חי רק ב-Paperclip DB). מקדים branch שמריץ את pipeline-ה-final
  ל-wake reason final_learning_*/final_halacha_* (HOME/DOTENV/DATA_DIR מוחלטים
  → מפתחות DeepSeek+Gemini + DATA_DIR נפתרים נכון). idempotent, שני הסוכנים.
  כבר הוחל ב-DB; הסקריפט לשחזור אחרי reset.

אומת: py_compile ✓ · tsc ✓ · החיווט אומת חי על 8126 (deepseek+gemini, dedup,
✓ pipeline הושלם). G2 (יכולת חסרה) · INV-LRN1/G10 נשמרים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:59:21 +00:00

108 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Reproducible source-of-truth for the curator's PIPELINE-WAKE branch.
The Hermes curator's prompt lives ONLY in the Paperclip DB
(agents.adapter_config.promptTemplate), not in a repo file. This script (re-)prepends
a branch so that a wake whose reason starts with `final_learning_` / `final_halacha_`
runs the matching local pipeline script and stops — instead of the default §A/§B
style-curation routine. Without it, clicking the run-learning / run-halacha buttons
wakes the curator but it does style-curation, never the pipeline.
Idempotent: strips any prior branch (by the ORIG_START marker) and re-prepends the
current one. Applies to BOTH company curators (CMP + CMPA) so cross-company sync stays
consistent. Re-run this after any curator-prompt reset / agent re-creation.
python3 scripts/curator_apply_pipeline_branch.py # apply
python3 scripts/curator_apply_pipeline_branch.py --verify # show head, no write
Env knobs (defaults shown):
PAPERCLIP_DB_URL=postgresql://paperclip:paperclip@localhost:54329/paperclip
"""
from __future__ import annotations
import argparse
import asyncio
import os
import asyncpg
PAPERCLIP_DB = os.environ.get(
"PAPERCLIP_DB_URL", "postgresql://paperclip:paperclip@localhost:54329/paperclip"
)
CURATOR_AGENTS = [
"60dce831-5c5b-4bae-bda9-5282d506f0dc", # CMP (1xxx — licensing)
"d6f7c55d-570a-46b8-8d72-1286d07da0d8", # CMPA (8xxx/9xxx — betterment)
]
MARKER = "### PIPELINE-WAKE BRANCH (auto)"
ORIG_START = "אתה מנהל ידע" # first line of the canonical curator prompt
# HOME=/home/chaim is the root fix: the Hermes agent runs with $HOME pointing at its
# profile dir, so Path.home() / expanduser('~') would resolve DATA_DIR and the
# DeepSeek/Gemini key files wrong. Pinning HOME (+ DOTENV_PATH/DATA_DIR) makes the
# pipeline resolve the case files AND both judge keys correctly.
BRANCH = MARKER + r'''
לפני כל דבר אחר — בדוק אם זו יקיצת-pipeline אוטומטית. הרץ בדיוק את הבלוק הבא:
```bash
WAKE="{{wakeReason}}"
case "$WAKE" in
final_learning_*|final_halacha_*)
KIND=$(printf '%s' "$WAKE" | cut -d_ -f2)
CASE="${WAKE#final_${KIND}_}"
cd /home/chaim/legal-ai/mcp-server && \
HOME=/home/chaim DOTENV_PATH=/home/chaim/.env DATA_DIR=/home/chaim/legal-ai/data \
nohup .venv/bin/python ../scripts/final_${KIND}_pipeline.py --case "$CASE" \
> "/tmp/final_${KIND}_${CASE}.log" 2>&1 &
sleep 2
echo "PIPELINE_STARTED final_${KIND}_pipeline case=$CASE log=/tmp/final_${KIND}_${CASE}.log"
;;
*) echo "NO_PIPELINE_WAKE" ;;
esac
```
אם הפלט הוא `PIPELINE_STARTED ...` — **זו כל המשימה**: כתוב comment קצר בעברית ("הופעל צינור <KIND> לתיק <CASE>; התוצאות יופיעו ב-/training (סגנון) או /approvals + /precedents (הלכות) תוך מספר דקות."), סגור את ה-issue (status=done), ו**סיים מיד — אל תמשיך לסעיפים שלמטה**.
אם הפלט הוא `NO_PIPELINE_WAKE` — המשך כרגיל לתבנית שלמטה.
---
'''
async def main(verify: bool) -> int:
conn = await asyncpg.connect(PAPERCLIP_DB)
try:
for aid in CURATOR_AGENTS:
row = await conn.fetchrow(
"SELECT name, adapter_config->>'promptTemplate' AS t FROM agents WHERE id=$1",
aid,
)
if not row or not row["t"]:
print(f"{aid}: NO TEMPLATE — skip")
continue
t = row["t"]
if verify:
has = MARKER in t
print(f"{aid} ({row['name']}): branch={'present' if has else 'MISSING'} "
f"len={len(t)}")
continue
i = t.find(ORIG_START)
if i < 0:
print(f"{aid}: ORIG_START not found — skip (manual check)")
continue
new = BRANCH + t[i:] # strip any prior branch, re-prepend
await conn.execute(
"UPDATE agents SET adapter_config = "
"jsonb_set(adapter_config,'{promptTemplate}', to_jsonb($2::text)), "
"updated_at = now() WHERE id=$1",
aid, new,
)
print(f"{aid} ({row['name']}): branch applied; template now {len(new)} chars")
finally:
await conn.close()
return 0
if __name__ == "__main__":
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--verify", action="store_true", help="report only, no write")
raise SystemExit(asyncio.run(main(ap.parse_args().verify)))