"""Tests for lib/content.py — pure content-processing functions.""" import json import os import sys import pytest from lib.content import ( compose_recall_query, format_memories, prepare_retention_transcript, read_transcript, slice_last_turns_by_user_boundary, strip_memory_tags, truncate_recall_query, ) def _write_jsonl(tmp_path, entries): f = tmp_path / "transcript.jsonl" f.write_text("\n".join(json.dumps(e) for e in entries)) return str(f) # --------------------------------------------------------------------------- # strip_memory_tags # --------------------------------------------------------------------------- class TestStripMemoryTags: def test_strips_hindsight_memories_block(self): raw = "before\nsecret\nafter" result = strip_memory_tags(raw) assert "hindsight_memories" not in result assert "before" in result assert "after" in result def test_strips_relevant_memories_block(self): raw = "text old stuff text" result = strip_memory_tags(raw) assert "relevant_memories" not in result assert "old stuff" not in result def test_passthrough_clean_text(self): raw = "no memory tags here" assert strip_memory_tags(raw) == raw def test_strips_multiline_block(self): raw = "\n- mem1\n- mem2\n" assert strip_memory_tags(raw).strip() == "" # --------------------------------------------------------------------------- # read_transcript — flat format # --------------------------------------------------------------------------- class TestReadTranscriptFlat: def test_reads_flat_format(self, tmp_path): path = _write_jsonl(tmp_path, [ {"role": "user", "content": "hello"}, {"role": "assistant", "content": "hi there"}, ]) msgs = read_transcript(path) assert len(msgs) == 2 assert msgs[0] == {"role": "user", "content": "hello"} def test_returns_empty_for_missing_file(self): assert read_transcript("/nonexistent/path.jsonl") == [] def test_returns_empty_for_empty_string(self): assert read_transcript("") == [] class TestReadTranscriptCodexFormat: def test_reads_codex_response_item_format(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "What is Python?"}], }, }, { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "A programming language."}], "phase": "final_answer", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path) assert len(msgs) == 2 assert msgs[0]["role"] == "user" assert msgs[0]["content"] == "What is Python?" assert msgs[1]["role"] == "assistant" assert msgs[1]["content"] == "A programming language." def test_skips_non_final_answer_assistant_messages(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "thinking..."}], "phase": "reasoning", }, }, { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "The answer is 42."}], "phase": "final_answer", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path) assert len(msgs) == 1 assert msgs[0]["content"] == "The answer is 42." def test_skips_non_message_response_items(self, tmp_path): entries = [ {"type": "response_item", "payload": {"type": "tool_call", "name": "Bash"}}, { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "hello"}], }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path) assert len(msgs) == 1 assert msgs[0]["role"] == "user" def test_skips_invalid_roles(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "system", "content": [{"type": "input_text", "text": "system message"}], }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path) assert len(msgs) == 0 def test_skips_blank_lines_gracefully(self, tmp_path): f = tmp_path / "transcript.jsonl" f.write_text('\n{"role": "user", "content": "hi"}\n\n{"role": "assistant", "content": "hey"}\n') msgs = read_transcript(str(f)) assert len(msgs) == 2 # --------------------------------------------------------------------------- # slice_last_turns_by_user_boundary # --------------------------------------------------------------------------- def _msgs(*pairs): return [{"role": r, "content": c} for r, c in pairs] class TestSliceLastTurnsByUserBoundary: def test_returns_all_when_fewer_turns_than_requested(self): msgs = _msgs(("user", "hi"), ("assistant", "hello")) assert slice_last_turns_by_user_boundary(msgs, 5) == msgs def test_slices_to_last_one_turn(self): msgs = _msgs( ("user", "first"), ("assistant", "a1"), ("user", "second"), ("assistant", "a2"), ) result = slice_last_turns_by_user_boundary(msgs, 1) assert result[0]["content"] == "second" assert len(result) == 2 def test_slices_to_last_two_turns(self): msgs = _msgs( ("user", "u1"), ("assistant", "a1"), ("user", "u2"), ("assistant", "a2"), ("user", "u3"), ("assistant", "a3"), ) result = slice_last_turns_by_user_boundary(msgs, 2) assert result[0]["content"] == "u2" assert len(result) == 4 def test_empty_list_returns_empty(self): assert slice_last_turns_by_user_boundary([], 3) == [] def test_zero_turns_returns_empty(self): assert slice_last_turns_by_user_boundary(_msgs(("user", "hi")), 0) == [] def test_non_list_returns_empty(self): assert slice_last_turns_by_user_boundary(None, 1) == [] # --------------------------------------------------------------------------- # compose_recall_query # --------------------------------------------------------------------------- class TestComposeRecallQuery: def test_single_turn_returns_latest_only(self): msgs = _msgs(("user", "previous"), ("assistant", "reply")) result = compose_recall_query("new query", msgs, recall_context_turns=1) assert result == "new query" def test_multi_turn_includes_prior_context(self): msgs = _msgs(("user", "prior question"), ("assistant", "prior answer")) result = compose_recall_query("current question", msgs, recall_context_turns=2) assert "Prior context:" in result assert "prior question" in result assert "current question" in result def test_skips_duplicate_of_latest_query(self): msgs = _msgs(("user", "same question"), ("assistant", "answer")) result = compose_recall_query("same question", msgs, recall_context_turns=2) assert result.count("same question") == 1 def test_empty_messages_returns_latest(self): result = compose_recall_query("query", [], recall_context_turns=3) assert result == "query" def test_strips_memory_tags_from_context(self): msgs = _msgs(("user", "secret actual question")) result = compose_recall_query("now", msgs, recall_context_turns=2) assert "hindsight_memories" not in result assert "secret" not in result def test_filters_by_recall_roles(self): msgs = _msgs(("user", "user msg"), ("assistant", "assistant msg")) result = compose_recall_query("query", msgs, recall_context_turns=2, recall_roles=["user"]) assert "user msg" in result assert "assistant msg" not in result # --------------------------------------------------------------------------- # truncate_recall_query # --------------------------------------------------------------------------- class TestTruncateRecallQuery: def test_short_query_unchanged(self): q = "short" assert truncate_recall_query(q, q, max_chars=100) == q def test_plain_query_truncated_to_max(self): q = "x" * 50 result = truncate_recall_query(q, q, max_chars=20) assert len(result) <= 20 def test_preserves_latest_when_context_dropped(self): latest = "final question" query = f"Prior context:\n\nuser: old stuff\nassistant: old reply\n\n{latest}" result = truncate_recall_query(query, latest, max_chars=30) assert latest in result def test_drops_oldest_context_lines_first(self): latest = "latest" query = f"Prior context:\n\nuser: oldest\nassistant: old\nuser: newer\n\n{latest}" max_chars = len(f"Prior context:\n\nnewer\n\n{latest}") + 5 result = truncate_recall_query(query, latest, max_chars=max_chars) if "Prior context:" in result: assert "oldest" not in result def test_zero_max_returns_query_unchanged(self): q = "anything" assert truncate_recall_query(q, q, max_chars=0) == q # --------------------------------------------------------------------------- # format_memories # --------------------------------------------------------------------------- class TestFormatMemories: def test_formats_single_memory(self): mems = [{"text": "Paris is the capital", "type": "world", "mentioned_at": "2024-01-01"}] result = format_memories(mems) assert "Paris is the capital" in result assert "[world]" in result assert "(2024-01-01)" in result def test_formats_multiple_memories(self): mems = [ {"text": "mem1", "type": "experience", "mentioned_at": "2024-01-01"}, {"text": "mem2", "type": "world", "mentioned_at": "2024-02-01"}, ] result = format_memories(mems) assert "mem1" in result assert "mem2" in result def test_empty_list_returns_empty_string(self): assert format_memories([]) == "" def test_missing_optional_fields_graceful(self): mems = [{"text": "bare memory"}] result = format_memories(mems) assert "bare memory" in result # --------------------------------------------------------------------------- # prepare_retention_transcript # --------------------------------------------------------------------------- class TestPrepareRetentionTranscript: def test_formats_last_turn_by_default(self): msgs = _msgs(("user", "old"), ("assistant", "old reply"), ("user", "new"), ("assistant", "new reply")) transcript, count = prepare_retention_transcript(msgs, retain_full_window=False) assert "new" in transcript assert "new reply" in transcript assert count == 2 def test_full_window_retains_all(self): msgs = _msgs(("user", "msg1"), ("assistant", "reply1"), ("user", "msg2"), ("assistant", "reply2")) transcript, count = prepare_retention_transcript(msgs, retain_full_window=True) assert "msg1" in transcript assert "msg2" in transcript assert count == 4 def test_strips_memory_tags(self): msgs = _msgs(("user", "leaked actual question")) transcript, _ = prepare_retention_transcript(msgs, retain_full_window=True) assert "leaked" not in transcript assert "actual question" in transcript def test_filters_by_retain_roles(self): msgs = _msgs(("user", "user msg"), ("assistant", "assistant msg")) transcript, _ = prepare_retention_transcript(msgs, retain_roles=["user"], retain_full_window=True) assert "user msg" in transcript assert "assistant msg" not in transcript def test_empty_messages_returns_none(self): result, count = prepare_retention_transcript([]) assert result is None assert count == 0 def test_role_markers_present(self): msgs = _msgs(("user", "hello")) transcript, _ = prepare_retention_transcript(msgs, retain_full_window=True) assert "[role: user]" in transcript assert "[user:end]" in transcript def test_no_user_message_returns_none(self): msgs = [{"role": "assistant", "content": "only assistant"}] result, _ = prepare_retention_transcript(msgs, retain_full_window=False) assert result is None # --------------------------------------------------------------------------- # read_transcript — rich format (include_tool_calls=True) # --------------------------------------------------------------------------- class TestReadTranscriptRich: def test_reads_messages_as_structured_blocks(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "hello"}], }, }, { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "hi there"}], "phase": "final_answer", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assert len(msgs) == 2 assert msgs[0]["role"] == "user" assert msgs[0]["content"] == [{"type": "text", "text": "hello"}] assert msgs[1]["role"] == "assistant" assert msgs[1]["content"] == [{"type": "text", "text": "hi there"}] def test_reads_function_call(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "list files"}], }, }, { "type": "response_item", "payload": { "type": "function_call", "name": "Read", "arguments": '{"file_path": "/tmp/foo.txt"}', "call_id": "call_1", }, }, { "type": "response_item", "payload": { "type": "function_call_output", "call_id": "call_1", "output": "file contents here", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assert len(msgs) == 2 # user + assistant assistant = msgs[1] assert assistant["role"] == "assistant" assert len(assistant["content"]) == 2 assert assistant["content"][0]["type"] == "tool_use" assert assistant["content"][0]["name"] == "Read" assert assistant["content"][0]["input"] == {"file_path": "/tmp/foo.txt"} assert assistant["content"][1]["type"] == "tool_result" assert "file contents here" in assistant["content"][1]["content"] def test_reads_local_shell_call(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "run ls"}], }, }, { "type": "response_item", "payload": { "type": "local_shell_call", "call_id": "call_1", "status": "completed", "action": {"type": "exec", "command": ["ls", "-la"]}, }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assistant = msgs[1] assert assistant["content"][0]["type"] == "tool_use" assert assistant["content"][0]["name"] == "shell" assert assistant["content"][0]["input"]["command"] == ["ls", "-la"] def test_reads_exec_command_end_event(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "check git status"}], }, }, { "type": "event_msg", "payload": { "type": "exec_command_end", "call_id": "call_1", "command": ["git", "status"], "aggregated_output": "On branch main\nnothing to commit", "exit_code": 0, "status": "completed", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assistant = msgs[1] assert assistant["content"][0]["type"] == "tool_use" assert assistant["content"][0]["name"] == "shell" assert assistant["content"][0]["input"]["command"] == ["git", "status"] assert assistant["content"][1]["type"] == "tool_result" assert "On branch main" in assistant["content"][1]["content"] def test_reads_exec_command_end_with_nonzero_exit(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "run bad cmd"}], }, }, { "type": "event_msg", "payload": { "type": "exec_command_end", "call_id": "call_1", "command": ["false"], "aggregated_output": "", "exit_code": 1, "status": "failed", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assistant = msgs[1] result = assistant["content"][1] assert "exit_code: 1" in result["content"] assert "status: failed" in result["content"] def test_reads_patch_apply_end_event(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "fix the bug"}], }, }, { "type": "event_msg", "payload": { "type": "patch_apply_end", "call_id": "call_1", "changes": [{"file": "main.py", "diff": "+fixed line"}], "status": "applied", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assistant = msgs[1] assert assistant["content"][0]["type"] == "tool_use" assert assistant["content"][0]["name"] == "patch" assert assistant["content"][1]["content"] == "status: applied" def test_reads_web_search_call(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "search for python docs"}], }, }, { "type": "response_item", "payload": { "type": "web_search_call", "status": "completed", "action": {"type": "search", "query": "python documentation"}, }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assistant = msgs[1] assert assistant["content"][0]["type"] == "tool_use" assert assistant["content"][0]["name"] == "web_search" assert assistant["content"][0]["input"]["query"] == "python documentation" def test_skips_non_final_answer_in_rich_mode(self, tmp_path): entries = [ { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "thinking..."}], "phase": "reasoning", }, }, { "type": "response_item", "payload": { "type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "The answer"}], "phase": "final_answer", }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) assert len(msgs) == 1 assert msgs[0]["content"][0]["text"] == "The answer" def test_flat_format_works_in_rich_mode(self, tmp_path): path = _write_jsonl(tmp_path, [ {"role": "user", "content": "hello"}, {"role": "assistant", "content": "hi"}, ]) msgs = read_transcript(path, include_tool_calls=True) assert len(msgs) == 2 assert msgs[0]["content"] == [{"type": "text", "text": "hello"}] assert msgs[1]["content"] == [{"type": "text", "text": "hi"}] def test_truncates_long_tool_output(self, tmp_path): long_output = "x" * 3000 entries = [ { "type": "response_item", "payload": { "type": "message", "role": "user", "content": [{"type": "input_text", "text": "do something"}], }, }, { "type": "response_item", "payload": { "type": "function_call", "name": "Read", "arguments": "{}", "call_id": "call_1", }, }, { "type": "response_item", "payload": { "type": "function_call_output", "call_id": "call_1", "output": long_output, }, }, ] path = _write_jsonl(tmp_path, entries) msgs = read_transcript(path, include_tool_calls=True) result = msgs[1]["content"][1] assert len(result["content"]) < 3000 assert "truncated" in result["content"] # --------------------------------------------------------------------------- # prepare_retention_transcript — JSON format (include_tool_calls=True) # --------------------------------------------------------------------------- class TestPrepareRetentionTranscriptJson: def test_json_format_basic(self): msgs = [ {"role": "user", "content": [{"type": "text", "text": "hello"}]}, {"role": "assistant", "content": [{"type": "text", "text": "hi"}]}, ] transcript, count = prepare_retention_transcript( msgs, retain_full_window=True, include_tool_calls=True ) assert count == 2 parsed = json.loads(transcript) assert len(parsed) == 2 assert parsed[0]["role"] == "user" assert parsed[1]["role"] == "assistant" def test_json_format_with_tool_calls(self): msgs = [ {"role": "user", "content": [{"type": "text", "text": "list files"}]}, { "role": "assistant", "content": [ {"type": "tool_use", "name": "shell", "input": {"command": ["ls"]}}, {"type": "tool_result", "content": "file1.txt"}, {"type": "text", "text": "Here are the files."}, ], }, ] transcript, count = prepare_retention_transcript( msgs, retain_full_window=True, include_tool_calls=True ) parsed = json.loads(transcript) assistant = parsed[1] assert any(b["type"] == "tool_use" for b in assistant["content"]) assert any(b["type"] == "tool_result" for b in assistant["content"]) def test_json_format_strips_memory_tags(self): msgs = [ { "role": "user", "content": [ {"type": "text", "text": "secret real question"}, ], }, ] transcript, _ = prepare_retention_transcript( msgs, retain_full_window=True, include_tool_calls=True ) assert "hindsight_memories" not in transcript assert "secret" not in transcript assert "real question" in transcript def test_json_format_filters_roles(self): msgs = [ {"role": "user", "content": [{"type": "text", "text": "user msg"}]}, {"role": "assistant", "content": [{"type": "text", "text": "assistant msg"}]}, ] transcript, count = prepare_retention_transcript( msgs, retain_roles=["user"], retain_full_window=True, include_tool_calls=True ) parsed = json.loads(transcript) assert count == 1 assert all(m["role"] == "user" for m in parsed)