Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions hindsight-integrations/codex/scripts/lib/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ def strip_memory_tags(content: str) -> str:
return content


def is_synthetic_codex_user_message(content: str) -> bool:
"""Return True for setup messages Codex persists as user chat.

Codex records AGENTS.md startup instructions as a normal user message in
rollout JSONL. Retaining those messages teaches Hindsight about hook and
agent rules instead of the user's work, and can create very large retain
payloads in long-running sessions.
"""
if not isinstance(content, str):
return False

stripped = content.lstrip()
return (
stripped.startswith("# AGENTS.md instructions for ")
and "<INSTRUCTIONS>" in stripped
and "</INSTRUCTIONS>" in stripped
)


# ---------------------------------------------------------------------------
# Transcript reading
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -118,6 +137,8 @@ def _read_transcript_text(transcript_path: str) -> list:
if t:
text_parts.append(t)
text = "\n".join(text_parts).strip()
if role == "user" and is_synthetic_codex_user_message(text):
continue
if text:
messages.append({"role": role, "content": text})
# Flat format (testing / future compatibility)
Expand Down Expand Up @@ -187,6 +208,8 @@ def _flush_assistant():
if role == "user":
_flush_assistant()
text = _extract_text_from_content_blocks(payload.get("content", []))
if is_synthetic_codex_user_message(text):
continue
if text:
messages.append({"role": "user", "content": [{"type": "text", "text": text}]})
elif role == "assistant":
Expand Down
69 changes: 69 additions & 0 deletions hindsight-integrations/codex/tests/test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from lib.content import (
compose_recall_query,
format_memories,
is_synthetic_codex_user_message,
prepare_retention_transcript,
read_transcript,
slice_last_turns_by_user_boundary,
Expand Down Expand Up @@ -51,6 +52,16 @@ def test_strips_multiline_block(self):
assert strip_memory_tags(raw).strip() == ""


class TestSyntheticCodexUserMessage:
def test_detects_agents_startup_instructions(self):
raw = "# AGENTS.md instructions for /home/coder/project\n\n<INSTRUCTIONS>\nremember things\n</INSTRUCTIONS>"
assert is_synthetic_codex_user_message(raw)

def test_does_not_match_normal_agents_discussion(self):
raw = "We should update AGENTS.md instructions for this repo."
assert not is_synthetic_codex_user_message(raw)


# ---------------------------------------------------------------------------
# read_transcript — flat format
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -160,6 +171,35 @@ def test_skips_invalid_roles(self, tmp_path):
msgs = read_transcript(path)
assert len(msgs) == 0

def test_skips_codex_agents_startup_instructions(self, tmp_path):
entries = [
{
"type": "response_item",
"payload": {
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "# AGENTS.md instructions for /home/coder/project\n\n<INSTRUCTIONS>\nsetup rules\n</INSTRUCTIONS>",
}
],
},
},
{
"type": "response_item",
"payload": {
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "actual user request"}],
},
},
]
path = _write_jsonl(tmp_path, entries)
msgs = read_transcript(path)
assert len(msgs) == 1
assert msgs[0]["content"] == "actual user request"

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')
Expand Down Expand Up @@ -398,6 +438,35 @@ def test_reads_messages_as_structured_blocks(self, tmp_path):
assert msgs[1]["role"] == "assistant"
assert msgs[1]["content"] == [{"type": "text", "text": "hi there"}]

def test_skips_codex_agents_startup_instructions(self, tmp_path):
entries = [
{
"type": "response_item",
"payload": {
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "# AGENTS.md instructions for /home/coder/project\n\n<INSTRUCTIONS>\nsetup rules\n</INSTRUCTIONS>",
}
],
},
},
{
"type": "response_item",
"payload": {
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "actual user request"}],
},
},
]
path = _write_jsonl(tmp_path, entries)
msgs = read_transcript(path, include_tool_calls=True)
assert len(msgs) == 1
assert msgs[0]["content"] == [{"type": "text", "text": "actual user request"}]

def test_reads_function_call(self, tmp_path):
entries = [
{
Expand Down