feat: add more logging
This commit is contained in:
@@ -19,6 +19,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import contextlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import uuid
|
||||
@@ -27,6 +28,8 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal, Self
|
||||
|
||||
_log = logging.getLogger("claude_code_api.backend")
|
||||
|
||||
from claude_code_api.errors import MessageParseError
|
||||
from claude_code_api.events import (
|
||||
AssistantMessage,
|
||||
@@ -171,31 +174,84 @@ class ClaudeCodeBackend:
|
||||
async with self._lock:
|
||||
prior = list(messages[:-1])
|
||||
fp_prior = hash_history(prior)
|
||||
_log.info(
|
||||
"complete: n_msgs=%d prior_fp=%s last_text_len=%d pool_size=%d",
|
||||
len(messages),
|
||||
fp_prior[:12],
|
||||
len(last_text),
|
||||
len(self._sessions),
|
||||
)
|
||||
|
||||
session: _LiveSession
|
||||
if prior and fp_prior in self._sessions:
|
||||
session = self._sessions.pop(fp_prior)
|
||||
send_text = last_text
|
||||
_log.info(
|
||||
"complete: POOL HIT fp=%s -> reusing session_id=%s",
|
||||
fp_prior[:12],
|
||||
session.session_id,
|
||||
)
|
||||
else:
|
||||
_log.info(
|
||||
"complete: POOL MISS fp=%s (prior=%d msgs) -> spawning new session",
|
||||
fp_prior[:12],
|
||||
len(prior),
|
||||
)
|
||||
session = await self._create_session(prior)
|
||||
if prior and self._opts.history_injection_mode == "concat_message":
|
||||
send_text = build_concat_prompt(prior, last_text)
|
||||
_log.info(
|
||||
"complete: concat_message mode, send_text_len=%d",
|
||||
len(send_text),
|
||||
)
|
||||
else:
|
||||
send_text = last_text
|
||||
|
||||
events: list[Event] = []
|
||||
n_assistant = 0
|
||||
n_user = 0
|
||||
n_system = 0
|
||||
try:
|
||||
_log.info(
|
||||
"complete: sending user msg to session_id=%s (text_len=%d)",
|
||||
session.session_id,
|
||||
len(send_text),
|
||||
)
|
||||
async for event in session.tm.send_user_message(send_text):
|
||||
events.append(event)
|
||||
if isinstance(event, AssistantMessage):
|
||||
n_assistant += 1
|
||||
elif isinstance(event, UserMessage):
|
||||
n_user += 1
|
||||
else:
|
||||
n_system += 1
|
||||
yield event
|
||||
except BaseException:
|
||||
except BaseException as exc:
|
||||
_log.exception(
|
||||
"complete: session_id=%s FAILED (events so far: a=%d u=%d sys=%d): %s",
|
||||
session.session_id,
|
||||
n_assistant,
|
||||
n_user,
|
||||
n_system,
|
||||
exc,
|
||||
)
|
||||
with contextlib.suppress(Exception):
|
||||
await session.aclose()
|
||||
raise
|
||||
|
||||
synthesized_cycle = synthesize_turn_messages(events)
|
||||
new_history = [*list(messages), *synthesized_cycle]
|
||||
self._sessions[hash_history(new_history)] = session
|
||||
new_fp = hash_history(new_history)
|
||||
self._sessions[new_fp] = session
|
||||
_log.info(
|
||||
"complete: session_id=%s DONE a=%d u=%d sys=%d synth=%d -> repooled under fp=%s",
|
||||
session.session_id,
|
||||
n_assistant,
|
||||
n_user,
|
||||
n_system,
|
||||
len(synthesized_cycle),
|
||||
new_fp[:12],
|
||||
)
|
||||
|
||||
async def aclose(self) -> None:
|
||||
"""Shut down all live sessions; remove the temp mcp-config file."""
|
||||
@@ -237,10 +293,24 @@ class ClaudeCodeBackend:
|
||||
jsonl_path.write_text(seed, encoding="utf-8")
|
||||
start_offset = jsonl_path.stat().st_size
|
||||
resume = True
|
||||
_log.info(
|
||||
"_create_session: session_id=%s SEED jsonl=%s bytes=%d history_msgs=%d resume=True",
|
||||
session_id,
|
||||
jsonl_path,
|
||||
start_offset,
|
||||
len(history),
|
||||
)
|
||||
else:
|
||||
jsonl_path = resolve_jsonl_path(cwd, session_id)
|
||||
start_offset = 0
|
||||
resume = False
|
||||
_log.info(
|
||||
"_create_session: session_id=%s FRESH jsonl=%s history_msgs=%d resume=False mode=%s",
|
||||
session_id,
|
||||
jsonl_path,
|
||||
len(history),
|
||||
self._opts.history_injection_mode,
|
||||
)
|
||||
|
||||
if self._session_factory is not None:
|
||||
result = self._session_factory(
|
||||
@@ -260,6 +330,12 @@ class ClaudeCodeBackend:
|
||||
async def _spawn_real_session(
|
||||
self, *, session_id: str, resume: bool, jsonl_path: Path, start_offset: int
|
||||
) -> _LiveSession:
|
||||
_log.info(
|
||||
"_spawn_real_session: session_id=%s resume=%s start_offset=%d",
|
||||
session_id,
|
||||
resume,
|
||||
start_offset,
|
||||
)
|
||||
pty_opts = self._build_pty_options(session_id=session_id, resume=resume)
|
||||
pty = PtyClaudeProcess(pty_opts)
|
||||
watcher = JsonlWatcher(jsonl_path, start_offset=start_offset)
|
||||
@@ -274,6 +350,11 @@ class ClaudeCodeBackend:
|
||||
on_parse_error=self._on_parse_error,
|
||||
)
|
||||
await tm.start()
|
||||
_log.info(
|
||||
"_spawn_real_session: session_id=%s STARTED pid=%s",
|
||||
session_id,
|
||||
getattr(pty, "pid", "?"),
|
||||
)
|
||||
return _LiveSession(pty=pty, watcher=watcher, tm=tm)
|
||||
|
||||
def _build_pty_options(self, *, session_id: str, resume: bool) -> PtyProcessOptions:
|
||||
|
||||
Reference in New Issue
Block a user