From 2dd11c9db72271f21a7ac4092314c456f20bd7a7 Mon Sep 17 00:00:00 2001 From: claude-dev Date: Sun, 8 Mar 2026 13:25:21 +0100 Subject: [PATCH] =?UTF-8?q?DB-Migrationen=20(status=5Fhistory,=20category)?= =?UTF-8?q?=20+=20Claude=20CLI=20stdin-=C3=9Cbergabe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - status_history Spalte für fact_checks (Faktencheck-Verlauf als JSON) - category Spalte für article_locations (Marker-Klassifizierung) - Prompt-Übergabe an Claude CLI via stdin statt Argument (ARG_MAX) Co-Authored-By: Claude Opus 4.6 --- src/agents/claude_client.py | 13 +++++++++---- src/database.py | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/agents/claude_client.py b/src/agents/claude_client.py index 3282cba..661180d 100644 --- a/src/agents/claude_client.py +++ b/src/agents/claude_client.py @@ -41,12 +41,14 @@ class UsageAccumulator: async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", model: str | None = None) -> tuple[str, ClaudeUsage]: """Ruft Claude CLI auf. Gibt (result_text, usage) zurück. + Prompt wird via stdin uebergeben um OS ARG_MAX Limits zu vermeiden. + Args: - prompt: Der Prompt für Claude + prompt: Der Prompt fuer Claude tools: Kommagetrennte erlaubte Tools (None = keine Tools, --max-turns 1) - model: Optionales Modell (z.B. CLAUDE_MODEL_FAST für Haiku). None = CLI-Default (Opus). + model: Optionales Modell (z.B. CLAUDE_MODEL_FAST fuer Haiku). None = CLI-Default (Opus). """ - cmd = [CLAUDE_PATH, "-p", prompt, "--output-format", "json"] + cmd = [CLAUDE_PATH, "-p", "-", "--output-format", "json"] if model: cmd.extend(["--model", model]) if tools: @@ -56,6 +58,7 @@ async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", mod process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, + stdin=asyncio.subprocess.PIPE, env={ "PATH": "/usr/local/bin:/usr/bin:/bin", "HOME": "/home/claude-dev", @@ -64,7 +67,9 @@ async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", mod }, ) try: - stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=CLAUDE_TIMEOUT) + stdout, stderr = await asyncio.wait_for( + process.communicate(input=prompt.encode("utf-8")), timeout=CLAUDE_TIMEOUT + ) except asyncio.TimeoutError: process.kill() raise TimeoutError(f"Claude CLI Timeout nach {CLAUDE_TIMEOUT}s") diff --git a/src/database.py b/src/database.py index eb4ff00..2e95118 100644 --- a/src/database.py +++ b/src/database.py @@ -350,6 +350,26 @@ async def init_db(): await db.execute("ALTER TABLE fact_checks ADD COLUMN tenant_id INTEGER REFERENCES organizations(id)") await db.commit() + # Migration: status_history fuer fact_checks (Faktencheck-Verlauf) + if "status_history" not in fc_columns: + await db.execute("ALTER TABLE fact_checks ADD COLUMN status_history TEXT DEFAULT '[]'") + # Bestehende Eintraege initialisieren + cursor2 = await db.execute("SELECT id, status, checked_at FROM fact_checks") + for row2 in await cursor2.fetchall(): + import json as _json + initial_history = _json.dumps([{"status": row2[1], "at": str(row2[2])}]) + await db.execute("UPDATE fact_checks SET status_history = ? WHERE id = ?", (initial_history, row2[0])) + await db.commit() + logger.info("Migration: status_history zu fact_checks hinzugefuegt") + + # Migration: category fuer article_locations (Marker-Klassifizierung) + cursor = await db.execute("PRAGMA table_info(article_locations)") + al_columns = [row[1] for row in await cursor.fetchall()] + if "category" not in al_columns: + await db.execute("ALTER TABLE article_locations ADD COLUMN category TEXT DEFAULT 'mentioned'") + await db.commit() + logger.info("Migration: category zu article_locations hinzugefuegt") + # Migration: tenant_id fuer incident_snapshots cursor = await db.execute("PRAGMA table_info(incident_snapshots)") snap_columns2 = [row[1] for row in await cursor.fetchall()]