feat(precedents): UI button queues extraction for local MCP worker
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m27s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m27s
The chair wanted a one-click "extract metadata" button on the edit sheet.
The constraint stays the same — claude_session needs the local CLI which
the container doesn't have, so the button can't run the extractor itself.
Compromise: button stamps a queue marker; the local MCP server drains the
queue on demand.
DB (V8): two nullable timestamps on case_law,
metadata_extraction_requested_at and halacha_extraction_requested_at,
with partial indexes for cheap "find pending" scans.
API:
POST /api/precedent-library/{id}/request-metadata → stamp the row
POST /api/precedent-library/{id}/request-halachot → same for halacha
GET /api/precedent-library/queue/pending?kind=... → read-only view
UI: Sparkles button in the edit sheet header. Click → toast tells the
chair what to run from Claude Code. The button never triggers the
extractor directly from the container.
MCP tool: precedent_process_pending(kind, limit) — runs from Claude Code
with the local CLI, picks up everything stamped, calls the extractor for
each, clears the timestamp on success. Failures keep the timestamp so the
next invocation retries them.
Architectural rule (claude_session local-only) is preserved end-to-end
and called out in the new endpoint comment + tool docstring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
46
web/app.py
46
web/app.py
@@ -3750,10 +3750,48 @@ async def precedent_library_delete(case_law_id: str):
|
||||
|
||||
# Halacha and metadata extraction are LLM-driven and rely on the local
|
||||
# `claude` CLI via mcp-server/services/claude_session.py — they CANNOT run
|
||||
# from this container (no CLI, no claude.ai session). They are exposed as
|
||||
# MCP tools (`precedent_extract_halachot`, `precedent_extract_metadata`)
|
||||
# and triggered from local Claude Code, not via HTTP. See
|
||||
# services/claude_session.py for the architectural rule.
|
||||
# from this container (no CLI, no claude.ai session). The endpoints below
|
||||
# DON'T run extraction; they only stamp a request in the queue. The
|
||||
# corresponding MCP tools (`precedent_process_pending_metadata`,
|
||||
# `precedent_process_pending_halachot`), invoked from local Claude Code,
|
||||
# drain the queue.
|
||||
|
||||
|
||||
@app.post("/api/precedent-library/{case_law_id}/request-metadata")
|
||||
async def precedent_request_metadata(case_law_id: str):
|
||||
"""Stamp the case_law row as needing metadata extraction. The local
|
||||
MCP worker (`precedent_process_pending_metadata`) will pick it up."""
|
||||
try:
|
||||
cid = UUID(case_law_id)
|
||||
except ValueError:
|
||||
raise HTTPException(400, "case_law_id לא תקין")
|
||||
ok = await db.request_metadata_extraction(cid)
|
||||
if not ok:
|
||||
raise HTTPException(404, "פסיקה לא נמצאה (או לא מסוג external_upload)")
|
||||
return {"queued": True, "case_law_id": case_law_id, "kind": "metadata"}
|
||||
|
||||
|
||||
@app.post("/api/precedent-library/{case_law_id}/request-halachot")
|
||||
async def precedent_request_halachot(case_law_id: str):
|
||||
"""Same, for halacha re-extraction."""
|
||||
try:
|
||||
cid = UUID(case_law_id)
|
||||
except ValueError:
|
||||
raise HTTPException(400, "case_law_id לא תקין")
|
||||
ok = await db.request_halacha_extraction(cid)
|
||||
if not ok:
|
||||
raise HTTPException(404, "פסיקה לא נמצאה (או לא מסוג external_upload)")
|
||||
return {"queued": True, "case_law_id": case_law_id, "kind": "halacha"}
|
||||
|
||||
|
||||
@app.get("/api/precedent-library/queue/pending")
|
||||
async def precedent_queue_pending(kind: str = "metadata", limit: int = 20):
|
||||
"""Read-only view of the queue. The MCP worker reads this too, but the
|
||||
UI calls it to show 'X ממתינות לעיבוד מקומי' badges."""
|
||||
if kind not in {"metadata", "halacha"}:
|
||||
raise HTTPException(400, "kind חייב להיות metadata או halacha")
|
||||
items = await db.list_pending_extraction_requests(kind=kind, limit=limit)
|
||||
return {"items": items, "count": len(items)}
|
||||
|
||||
|
||||
@app.get("/api/halachot")
|
||||
|
||||
Reference in New Issue
Block a user