fix(strategies): guard foresight sender scan against tool-call items - #373
Open
dani1005 wants to merge 1 commit into
Open
fix(strategies): guard foresight sender scan against tool-call items#373dani1005 wants to merge 1 commit into
dani1005 wants to merge 1 commit into
Conversation
A memcell cut from an agent trajectory carries ToolCallRequest and ToolCallResult items alongside ChatMessage. Neither has a role, so the sender scan's bare m.role raised AttributeError and took extract_foresight down for every session containing a tool call: no foresight is written for any user in that conversation. Guarded with getattr, matching the sibling scans in extract/pipeline/user_memory.py and service/_boundary.py, which already walk the same union defensively. This was the only unguarded read left. The extractor itself needs no change: everalgo documents that user-memory extractors silently skip non-ChatMessage items, and ForesightExtractor filters internally, so the crash was purely in our pre-scan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UyKinsWs1MgoARPoB9R4NW
dani1005
requested review from
Kendrick-Song and
cyfyifanchen
and removed request for
cyfyifanchen
July 29, 2026 19:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
extract_foresightopens by listing the user senders in the memcell:memcell.itemsis a union. OnlyChatMessagecarries arole;ToolCallRequesthas a sender but no role, andToolCallResulthas neither. So a memcell cut from an agent trajectory raisesAttributeError: 'ToolCallRequest' object has no attribute 'role'on the first tool item, and the strategy dies before it extracts anything. Every session containing a tool call loses foresights for all of its users.Found while recording a Langfuse trace fixture against 1.2.1: a four-round agent trajectory produced three
everos.ome.extract_foresighterror spans, one per retry.Change
Guard the attribute read with
getattr, matching how the rest of the codebase already walks this union:extract/pipeline/user_memory.py:230getattr(item, "role", None) != "user"— same job, collecting user sendersextract_agent_case.py:131getattr(item, "sender_id"/"role"/"kind", None)service/_boundary.py:467getattr(item, "sender_id", None)extract_foresight.py:54was the only unguarded read left, so this completes the pattern rather than introducing a new one.Semantics are unchanged: a tool call is issued by an agent, so its
sender_idcould never be a user sender, andToolCallResulthas no sender at all. The set of user senders is exactly the set ofrole == "user"chat messages either way.Why the extractor needs no change
ForesightExtractoris already designed to accept an agent-shaped memcell — its docstring states that non-ChatMessage items in memcell.items are silently skipped (agent → user-memory contract), and it filters internally through everalgo's ownchat_messages()helper. The crash was purely in our pre-scan, so the fix does not just move the failure one line down.That helper is deliberately not imported here: it lives in
everalgo/user_memory/_render.py, whose module docstring marks it internal and outside the public API.Testing
New regression test builds a memcell with a
ChatMessageplusToolCallRequest/ToolCallResultand asserts the strategy still finds the one user sender. It fails withAttributeErroragainst the unpatched line and passes with the guard.tests/unit1862 passed; ruff check/format, import-linter and the repo gates clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01UyKinsWs1MgoARPoB9R4NW