refactor(precedents): keep all LLM calls on the local-MCP path
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s
Architectural correction: every claude_session caller in this project
runs through the local MCP server (~/.claude.json points at
/home/chaim/legal-ai/mcp-server/.venv/bin/python). The Coolify container
has no `claude` CLI and no claude.ai session, so any LLM call originating
from web/ FastAPI fails with "Claude CLI not found" — which is exactly
what we hit on 403-17.
The earlier Anthropic SDK fallback would have made it work, but at
direct API cost. The chair's preference is to stay on the claude.ai
session for everything. So:
- claude_session.py: removed the SDK fallback, restored CLI-only.
The error message now points the next person at the architectural
rule in the module docstring instead of papering over it.
- precedent_library.py:ingest_precedent (called from FastAPI on upload)
now does only the non-LLM half: extract → chunk → embed → store.
Sets halacha_extraction_status='pending' for the chair to act on.
- reextract_halachot / reextract_metadata kept, but lazy-import their
extractors so the FastAPI path can't accidentally pull them in. They
are reachable only via the MCP tools precedent_extract_halachot /
precedent_extract_metadata, which run locally with CLI.
- Removed POST /api/precedent-library/{id}/extract-halachot and
/extract-metadata — they were dead ends from the container.
- Dropped the `anthropic` Python dep that the SDK fallback required.
- UI: removed the "refresh halachot" and "sparkles metadata" buttons
that called those endpoints. Edit sheet now points the chair at the
MCP tool names instead.
Halacha and metadata extraction for an uploaded precedent now happen
when the chair (via Claude Code) runs:
mcp__legal-ai__precedent_extract_metadata <case_law_id>
mcp__legal-ai__precedent_extract_halachot <case_law_id>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
66
web/app.py
66
web/app.py
@@ -3748,66 +3748,12 @@ async def precedent_library_delete(case_law_id: str):
|
||||
return {"deleted": True, "case_law_id": case_law_id}
|
||||
|
||||
|
||||
@app.post("/api/precedent-library/{case_law_id}/extract-halachot")
|
||||
async def precedent_library_reextract(case_law_id: str):
|
||||
"""Re-run halacha extraction in background. Returns a task_id for SSE."""
|
||||
try:
|
||||
cid = UUID(case_law_id)
|
||||
except ValueError:
|
||||
raise HTTPException(400, "case_law_id לא תקין")
|
||||
record = await db.get_case_law(cid)
|
||||
if not record:
|
||||
raise HTTPException(404, "פסיקה לא נמצאה")
|
||||
|
||||
task_id = str(uuid4())
|
||||
label = record.get("case_number") or case_law_id
|
||||
await _progress.set(task_id, {
|
||||
"status": "queued", "filename": label, "stage": "queued", "percent": 0,
|
||||
})
|
||||
publish = _make_progress_publisher(task_id, label)
|
||||
|
||||
async def _run():
|
||||
try:
|
||||
await plib_service.reextract_halachot(cid, progress=publish)
|
||||
except Exception as e:
|
||||
logger.exception("re-extract halachot failed")
|
||||
await _progress.set(task_id, {
|
||||
"status": "failed", "error": str(e), "filename": label,
|
||||
})
|
||||
|
||||
asyncio.create_task(_run())
|
||||
return {"task_id": task_id}
|
||||
|
||||
|
||||
@app.post("/api/precedent-library/{case_law_id}/extract-metadata")
|
||||
async def precedent_library_extract_metadata(case_law_id: str):
|
||||
"""Re-run metadata extraction in background. Fills empty fields only."""
|
||||
try:
|
||||
cid = UUID(case_law_id)
|
||||
except ValueError:
|
||||
raise HTTPException(400, "case_law_id לא תקין")
|
||||
record = await db.get_case_law(cid)
|
||||
if not record:
|
||||
raise HTTPException(404, "פסיקה לא נמצאה")
|
||||
|
||||
task_id = str(uuid4())
|
||||
label = record.get("case_number") or case_law_id
|
||||
await _progress.set(task_id, {
|
||||
"status": "queued", "filename": label, "stage": "queued", "percent": 0,
|
||||
})
|
||||
publish = _make_progress_publisher(task_id, label)
|
||||
|
||||
async def _run():
|
||||
try:
|
||||
await plib_service.reextract_metadata(cid, progress=publish)
|
||||
except Exception as e:
|
||||
logger.exception("re-extract metadata failed")
|
||||
await _progress.set(task_id, {
|
||||
"status": "failed", "error": str(e), "filename": label,
|
||||
})
|
||||
|
||||
asyncio.create_task(_run())
|
||||
return {"task_id": task_id}
|
||||
# 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.
|
||||
|
||||
|
||||
@app.get("/api/halachot")
|
||||
|
||||
Reference in New Issue
Block a user