Files
agentic-resources/tests/test_codex_adapter.py
tegwick bc11cb9aec session-memory Phase 1: Codex adapter (T01) + multi-file merge (T03)
- adapters/common.py: shared Normalized + helpers (resolve_repo, classify_tool,
  jsonl iter, etc.); claude.py refactored to use it (Normalized re-exported)
- adapters/codex.py: rollout {timestamp,type,payload} parser; session_meta/
  response_item/event_msg mapping; flat call_id join; token_count cost;
  registered in ingest dispatch
- core/store.py: ingest() now merges multi-file sessions by content
  fingerprint, appends new events with offset seq (design OQ6); idempotent
- tests/test_codex_adapter.py, tests/test_merge.py

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 21:55:32 +02:00

87 lines
4.0 KiB
Python

"""Codex adapter tests (T01): synthetic rollout fixture."""
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from session_memory.adapters.codex import parse_session # noqa: E402
REPO_MAP = {"agentic-resources": "helix_forge"}
def _rollout(path, lines):
with open(path, "w", encoding="utf-8") as f:
for ln in lines:
f.write(json.dumps(ln) + "\n")
def test_codex_rollout_parse(tmp_path):
p = tmp_path / "rollout-2026-06-06-abc.jsonl"
_rollout(p, [
{"timestamp": "2026-06-06T10:00:00Z", "type": "session_meta",
"payload": {"id": "cdx-1", "cwd": "/home/worsch/agentic-resources",
"model_provider": "openai", "cli_version": "0.44.0", "model": "gpt-5-codex"}},
{"timestamp": "2026-06-06T10:00:01Z", "type": "turn_context",
"payload": {"model": "gpt-5-codex", "approval_policy": "on-request"}},
{"timestamp": "2026-06-06T10:00:02Z", "type": "event_msg",
"payload": {"type": "task_started"}},
{"timestamp": "2026-06-06T10:00:03Z", "type": "response_item",
"payload": {"type": "message", "role": "user",
"content": [{"type": "input_text", "text": "fix the bug"}]}},
{"timestamp": "2026-06-06T10:00:04Z", "type": "response_item",
"payload": {"type": "reasoning", "summary": "think about it"}},
{"timestamp": "2026-06-06T10:00:05Z", "type": "response_item",
"payload": {"type": "function_call", "name": "apply_patch",
"arguments": "{\"path\":\"x.py\"}", "call_id": "call_1"}},
{"timestamp": "2026-06-06T10:00:06Z", "type": "response_item",
"payload": {"type": "function_call", "name": "shell",
"arguments": "{\"command\":\"pytest -q\"}", "call_id": "call_2"}},
{"timestamp": "2026-06-06T10:00:07Z", "type": "response_item",
"payload": {"type": "function_call_output", "call_id": "call_2", "output": "2 passed"}},
{"timestamp": "2026-06-06T10:00:08Z", "type": "response_item",
"payload": {"type": "message", "role": "assistant",
"content": [{"type": "output_text", "text": "done"}]}},
{"timestamp": "2026-06-06T10:00:09Z", "type": "event_msg",
"payload": {"type": "token_count",
"info": {"total_token_usage": {"input_tokens": 200, "output_tokens": 30,
"cached_input_tokens": 15}}}},
{"timestamp": "2026-06-06T10:00:10Z", "type": "event_msg",
"payload": {"type": "task_complete"}},
])
norm = parse_session(str(p), REPO_MAP)
assert norm is not None
s = norm.session
assert s.session_uid == "codex:cdx-1"
assert s.flavor == "codex"
assert s.repo == "agentic-resources" and s.domain == "helix_forge"
assert s.model == "gpt-5-codex"
assert s.cost.input_tokens == 200 and s.cost.output_tokens == 30 and s.cost.cache_tokens == 15
assert s.cost.turns == 1
assert s.cost.wall_clock_s == 10.0
kinds = [e.kind for e in norm.events]
assert kinds == ["lifecycle", "user_msg", "thinking", "edit", "test_run",
"tool_result", "assistant_msg", "completion"]
# flat linkage: function_call_output links to its function_call by call_id
out = next(e for e in norm.events if e.kind == "tool_result")
test_call = next(e for e in norm.events if e.kind == "test_run")
assert out.parent_seq == test_call.seq
# apply_patch classified as edit; pytest as test_run
edit = next(e for e in norm.events if e.kind == "edit")
assert edit.tool == "apply_patch"
def test_codex_empty_or_no_meta_returns_none(tmp_path):
p = tmp_path / "rollout-empty.jsonl"
p.write_text("")
assert parse_session(str(p), REPO_MAP) is None
p2 = tmp_path / "rollout-nometa.jsonl"
_rollout(p2, [{"timestamp": "t", "type": "event_msg", "payload": {"type": "task_started"}}])
assert parse_session(str(p2), REPO_MAP) is None # no session_meta -> no id