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>
This commit is contained in:
107
scripts/curator_apply_pipeline_branch.py
Normal file
107
scripts/curator_apply_pipeline_branch.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/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)))
|
||||
Reference in New Issue
Block a user