|
2 | 2 | actually work with -- messages, tool calls, token counts, file activity, etc.""" |
3 | 3 |
|
4 | 4 | import json |
| 5 | +import logging |
5 | 6 | import math |
6 | 7 | import os |
7 | 8 | from datetime import datetime |
8 | | -from typing import Any |
| 9 | +from typing import Any, cast, get_args |
9 | 10 |
|
10 | 11 | from models.record_data import RecordDataUnion |
11 | | -from models.session import MessageDict, SessionDict, ToolUseDict |
| 12 | +from models.session import MessageDict, RoleLiteral, SessionDict, ToolUseDict |
12 | 13 | from models.tool_results import ToolResultUnion, is_tool_result_dict |
13 | 14 | from utils.jsonl_helpers import ( |
14 | 15 | entry_message as _entry_message, |
|
40 | 41 | "_track_file_activity", |
41 | 42 | ] |
42 | 43 |
|
| 44 | +_HANDLED_ENTRY_TYPES = frozenset({"user", "assistant", "system", "progress"}) |
| 45 | +_VALID_ROLES = frozenset(get_args(RoleLiteral)) |
| 46 | + |
| 47 | + |
| 48 | +def _coerce_role(raw: str) -> RoleLiteral: |
| 49 | + if raw in _VALID_ROLES: |
| 50 | + return cast(RoleLiteral, raw) |
| 51 | + logging.warning("Unknown message role %r; mapping to 'system'", raw) |
| 52 | + return "system" |
| 53 | + |
| 54 | + |
| 55 | +def _fallback_message(entry: dict[str, Any], role: RoleLiteral) -> MessageDict: |
| 56 | + """Minimal message for JSONL entry types without a dedicated processor.""" |
| 57 | + content = entry.get("content", "") |
| 58 | + text = content if isinstance(content, str) else (str(content) if content is not None else "") |
| 59 | + return { |
| 60 | + "role": role, |
| 61 | + "uuid": entry.get("uuid"), |
| 62 | + "parent_uuid": entry.get("parentUuid"), |
| 63 | + "timestamp": entry.get("timestamp"), |
| 64 | + "content": text, |
| 65 | + "is_sidechain": entry.get("isSidechain", False), |
| 66 | + } |
| 67 | + |
43 | 68 |
|
44 | 69 | def _safe_int(val: Any) -> int: |
45 | 70 | """Coerce a value to a non-negative int for token accounting; non-numeric, |
@@ -144,6 +169,10 @@ def parse_session(filepath: str) -> SessionDict: |
144 | 169 | _process_system(entry, messages, metadata) |
145 | 170 | elif entry_type == "progress": |
146 | 171 | _process_progress(entry, messages) |
| 172 | + elif entry_type: |
| 173 | + type_str = entry_type if isinstance(entry_type, str) else str(entry_type) |
| 174 | + if type_str not in _HANDLED_ENTRY_TYPES: |
| 175 | + messages.append(_fallback_message(entry, _coerce_role(type_str))) |
147 | 176 |
|
148 | 177 | metadata["models_used"] = sorted(metadata["models_used"]) |
149 | 178 | metadata["service_tiers"] = sorted(metadata["service_tiers"]) |
|
0 commit comments