From 296cd8c1f5bb9945f7afa30ba38ac2f39bc4a530 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 4 Sep 2026 19:45:42 -0700 Subject: [PATCH] fix(cli): read CLAUDE_CODE_SESSION_ID and skip subagent transcripts when detecting the Claude Code session --- litellm/proxy/client/cli/commands/debug.py | 7 ++++-- .../proxy/client/cli/test_debug_commands.py | 22 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/litellm/proxy/client/cli/commands/debug.py b/litellm/proxy/client/cli/commands/debug.py index c5f147eb37a..4e3914143d8 100644 --- a/litellm/proxy/client/cli/commands/debug.py +++ b/litellm/proxy/client/cli/commands/debug.py @@ -25,7 +25,7 @@ from ._cli_context import cli_context_values CLAUDE_DIR: Final = Path.home() / ".claude" REPORT_DIR: Final = Path.home() / ".litellm" / "debug" -SESSION_ID_ENV: Final = "CLAUDE_SESSION_ID" +SESSION_ID_ENV: Final = "CLAUDE_CODE_SESSION_ID" SLASH_COMMAND_NAME: Final = "debug-lite" SLASH_COMMAND_BODY: Final = """--- description: Pull the LiteLLM debug report (spend, request, response, error) for this Claude Code session @@ -118,13 +118,16 @@ _JSON: Final[TypeAdapter[JsonValue]] = TypeAdapter(JsonValue) _SESSION_PAGE_SIZE: Final = 100 _TRANSPORT_BODY_CHARS: Final = 500 +_SESSION_TRANSCRIPT_STEM: Final = re.compile(r"[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}") def detect_claude_session_id(env: Mapping[str, str], claude_dir: Path) -> str | None: explicit: Final = env.get(SESSION_ID_ENV) if explicit: return explicit - transcripts: Final = tuple(claude_dir.glob("projects/*/*.jsonl")) + transcripts: Final = tuple( + path for path in claude_dir.glob("projects/*/*.jsonl") if _SESSION_TRANSCRIPT_STEM.fullmatch(path.stem) + ) if not transcripts: return None newest: Final = max(transcripts, key=lambda p: p.stat().st_mtime) diff --git a/tests/test_litellm/proxy/client/cli/test_debug_commands.py b/tests/test_litellm/proxy/client/cli/test_debug_commands.py index 1853d0c3468..419fd821cfb 100644 --- a/tests/test_litellm/proxy/client/cli/test_debug_commands.py +++ b/tests/test_litellm/proxy/client/cli/test_debug_commands.py @@ -136,25 +136,33 @@ def test_no_rows_is_a_clear_error(): def test_no_session_id_anywhere_is_a_clear_error(monkeypatch): - monkeypatch.delenv("CLAUDE_SESSION_ID", raising=False) + monkeypatch.delenv("CLAUDE_CODE_SESSION_ID", raising=False) result = CliRunner().invoke(cli, ["debug", "claude"]) assert result.exit_code != 0 assert "Could not find a Claude Code session" in result.output -def test_detect_session_id_prefers_env_then_newest_transcript(tmp_path): +OLD_SESSION = "0f3c2b1a-1111-4222-8333-444455556666" +NEW_SESSION = "2d79c54d-4644-4708-b03e-95395ef9ecbd" + + +def test_detect_session_id_prefers_env_then_newest_session_transcript(tmp_path): project = tmp_path / "projects" / "-Users-me-repo" project.mkdir(parents=True) - old = project / "old-session.jsonl" - new = project / "new-session.jsonl" + old = project / f"{OLD_SESSION}.jsonl" + new = project / f"{NEW_SESSION}.jsonl" + subagent = project / "agent-a1b2c3d4.jsonl" old.write_text("{}") new.write_text("{}") + subagent.write_text("{}") now = time.time() os.utime(old, (now - 100, now - 100)) - os.utime(new, (now, now)) + os.utime(new, (now - 50, now - 50)) + os.utime(subagent, (now, now)) - assert detect_claude_session_id({}, tmp_path) == "new-session" - assert detect_claude_session_id({"CLAUDE_SESSION_ID": "from-env"}, tmp_path) == "from-env" + assert detect_claude_session_id({}, tmp_path) == NEW_SESSION + assert detect_claude_session_id({"CLAUDE_CODE_SESSION_ID": "from-env"}, tmp_path) == "from-env" + assert detect_claude_session_id({"CLAUDE_SESSION_ID": "stale-name"}, tmp_path) == NEW_SESSION assert detect_claude_session_id({}, tmp_path / "missing") is None