Replace all Anthropic API calls with Claude Code session (claude -p)

New module claude_session.py provides query() and query_json() that
run prompts via `claude -p` CLI — uses the claude.ai session, zero API cost.

Converted 6 services:
- claims_extractor.py: extract_claims_with_ai
- brainstorm.py: brainstorm_directions
- block_writer.py: write_block (was streaming+thinking, now simple)
- qa_validator.py: claims_coverage check
- style_analyzer.py: 3 API calls (single pass, multi pass, synthesis)
- learning_loop.py: extract_lessons

Only extractor.py still uses Anthropic API (for PDF OCR with Vision).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 14:14:08 +00:00
parent e5dc037088
commit bacb330a2a
7 changed files with 115 additions and 192 deletions

View File

@@ -6,10 +6,8 @@ import json
import logging
import re
import anthropic
from legal_mcp import config
from legal_mcp.services import db
from legal_mcp.services import db, claude_session
logger = logging.getLogger(__name__)
@@ -150,24 +148,16 @@ async def _analyze_single_pass(rows) -> dict:
decisions_text += f"\n\n--- החלטה {row['decision_number'] or 'ללא מספר'} ---\n"
decisions_text += row["full_text"]
client = anthropic.Anthropic(api_key=config.ANTHROPIC_API_KEY)
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=16384,
messages=[
{
"role": "user",
"content": ANALYSIS_PROMPT.format(decisions=decisions_text),
}
],
raw = claude_session.query(
ANALYSIS_PROMPT.format(decisions=decisions_text),
timeout=claude_session.LONG_TIMEOUT,
)
return await _parse_and_store_patterns(message.content[0].text, len(rows))
return await _parse_and_store_patterns(raw, len(rows))
async def _analyze_multi_pass(rows) -> dict:
"""Analyze each decision individually, then synthesize patterns."""
client = anthropic.Anthropic(api_key=config.ANTHROPIC_API_KEY)
all_patterns = []
# Pass 1: Analyze each decision individually
@@ -175,18 +165,12 @@ async def _analyze_multi_pass(rows) -> dict:
decision_text = f"--- החלטה {row['decision_number'] or 'ללא מספר'} ---\n"
decision_text += row["full_text"]
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
messages=[
{
"role": "user",
"content": SINGLE_DECISION_PROMPT.format(decision=decision_text),
}
],
raw = claude_session.query(
SINGLE_DECISION_PROMPT.format(decision=decision_text),
timeout=claude_session.LONG_TIMEOUT,
)
patterns = _extract_json(message.content[0].text)
patterns = _extract_json(raw)
if patterns:
all_patterns.extend(patterns)
@@ -194,21 +178,15 @@ async def _analyze_multi_pass(rows) -> dict:
return {"error": "לא הצלחתי לחלץ דפוסים מההחלטות"}
# Pass 2: Synthesize across all decisions
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=16384,
messages=[
{
"role": "user",
"content": SYNTHESIS_PROMPT.format(
num_decisions=len(rows),
patterns=json.dumps(all_patterns, ensure_ascii=False, indent=2),
),
}
],
raw = claude_session.query(
SYNTHESIS_PROMPT.format(
num_decisions=len(rows),
patterns=json.dumps(all_patterns, ensure_ascii=False, indent=2),
),
timeout=claude_session.LONG_TIMEOUT,
)
return await _parse_and_store_patterns(message.content[0].text, len(rows))
return await _parse_and_store_patterns(raw, len(rows))
def _extract_json(response_text: str) -> list | None: