Derive a session ID from the first user message (SHA-256 prefix). Used for cache key grouping, composition checkpoints, and agent/tool session continuity. Skips boilerplate user messages whose content is identical across sessions for the same workspace — notably Codex CLI's ``<
(messages: list[dict[str, Any]])
| 13 | |
| 14 | |
| 15 | def derive_session_id(messages: list[dict[str, Any]]) -> str | None: |
| 16 | """Derive a session ID from the first user message (SHA-256 prefix). |
| 17 | |
| 18 | Used for cache key grouping, composition checkpoints, and agent/tool |
| 19 | session continuity. |
| 20 | |
| 21 | Skips boilerplate user messages whose content is identical across |
| 22 | sessions for the same workspace — notably Codex CLI's |
| 23 | ``<environment_context>`` block, which wraps cwd/shell/date and would |
| 24 | otherwise collapse every Codex conversation in the same directory into |
| 25 | a single session. |
| 26 | """ |
| 27 | for msg in messages: |
| 28 | if msg.get("role") != "user": |
| 29 | continue |
| 30 | content = msg.get("content", "") |
| 31 | text = (content if isinstance(content, str) else str(content)).strip() |
| 32 | if not text: |
| 33 | continue |
| 34 | if text.startswith("<environment_context>") and text.endswith( |
| 35 | "</environment_context>" |
| 36 | ): |
| 37 | continue |
| 38 | return hashlib.sha256(text.encode()).hexdigest()[:8] |
| 39 | return None |
| 40 | |
| 41 | |
| 42 | @dataclass |