Backend: Python-Logging statt print, Diagnose in allen Fallbacks

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
team3
2026-06-12 07:52:33 +02:00
parent d97ec48bf1
commit 32f6fab16b
4 changed files with 49 additions and 4 deletions

View File

@@ -5,15 +5,19 @@ jeweilige Provider fehl — der andere läuft unverändert weiter.
"""
import asyncio
import logging
import os
import re
import shutil
import tempfile
import time
import urllib.request
from pathlib import Path
from config import PROVIDERS, DEFAULT_PROVIDER
log = logging.getLogger("creator.agents")
_active_processes: dict[str, asyncio.subprocess.Process] = {}
# Capability → Claude --allowedTools
@@ -54,7 +58,11 @@ def provider_available(provider: str) -> bool:
def kill_process(agent_key_prefix: str) -> None:
"""Killt alle aktiven Prozesse, deren Key mit dem Prefix beginnt (deckt -plan/-w1… ab)."""
for key, process in list(_active_processes.items()):
if key.startswith(agent_key_prefix) and process.returncode is None:
if process.returncode is not None: # tote Einträge beim Iterieren aufräumen
_active_processes.pop(key, None)
continue
if key.startswith(agent_key_prefix):
log.debug("kill agent %s", key)
process.kill()
@@ -76,6 +84,7 @@ async def run_agent(
async def _communicate(agent_key: str, cmd: list[str], stdin_data: bytes | None, timeout: int) -> tuple[int, str, str]:
start = time.monotonic()
process = await asyncio.create_subprocess_exec(
*cmd,
stdin=asyncio.subprocess.PIPE if stdin_data is not None else asyncio.subprocess.DEVNULL,
@@ -95,10 +104,18 @@ async def _communicate(agent_key: str, cmd: list[str], stdin_data: bytes | None,
await asyncio.wait_for(process.wait(), timeout=5)
except asyncio.TimeoutError:
pass
log.info("agent %s: Timeout nach %ds", agent_key, timeout)
raise
log.info(
"agent %s: exit %s nach %.1fs (%d Bytes stdout)",
agent_key, process.returncode, time.monotonic() - start, len(stdout),
)
return process.returncode, stdout.decode("utf-8", errors="replace"), stderr.decode("utf-8", errors="replace")
finally:
_active_processes.pop(agent_key, None)
# Pop nur bei Identität: ein Slot-Restart unter demselben Key darf den
# NEUEN Prozess nicht aus dem Tracking werfen.
if _active_processes.get(agent_key) is process:
del _active_processes[agent_key]
async def _run_claude_cli(agent_key: str, prompt: str, timeout: int, role: str, capabilities: str) -> tuple[int, str, str]: