SIGN IN SIGN UP

fix(pi): resolve SessionEntry ids by AgentMessage reference identity

When Pi's `agent.state.messages` and `sessionManager.getBranch()`
desync — observed in production as off-by-one near the agent_end
boundary, and as 288-entry catastrophic gaps when another extension
mutates `event.messages` (e.g. condensed-milk-pi, GitHub issue #81) —
our position-based walk in `collectMessageEntryIds` returned a slice
with wrong alignment for every index past the divergence point. That
broke compartment boundary lookup in `<session-history>` injection
and forced degraded mode where the visible tail couldn't be trimmed.

The new `collectMessageEntryIdsByRef` walks `getBranch()` once
building a `Map<AgentMessage, entryId>` keyed by reference identity.
Pi's `appendMessage` stores `entry.message = sourceAgentMessage`
without cloning (session-manager.js:580), so `event.messages[i] ===
branchEntries[j].message` holds for every emit-eligible message.

Custom-message and branch-summary entries are skipped intentionally:
Pi's `buildSessionContext` wraps them in fresh objects per call, so
ref matching would always fail. They never carry compartment
boundaries (historian only writes boundaries on plain message
entries), so the caller's `buildPiMessageIdByIndex` fallback to a
synthesized `pi-msg-${index}-${ts}-${role}` id is harmless.

Returns `null` only when the SessionManager API is unavailable.
When traversal succeeds, always returns an array of `messages.length`
with `undefined` for unmapped positions — length mismatch is never
returned, which is the whole point of the switch.

Both production call sites in `registerPiContextHandler` (the
strict variant for `findLatestUserMessageIdPi`, and the non-strict
variant for `runPipeline`'s `entryIds` parameter) now use the new
function. The position-based `collectMessageEntryIds` and
`collectMessageEntryIdsStrict` remain as backward-compat exports
because external tooling might depend on them; production traffic
no longer touches them.

Updates `fakeContext` to accept optional message references so tests
can opt into ref-based resolution. Adds five new regression tests
covering: API unavailability, ref-based success, off-by-one survival
(your log scenario), catastrophic-gap survival (#81 scenario), and
correct skipping of non-message entry types.

Refs: GitHub issue #81; off-by-one logs observed in your session
019de471-4fdc-762d-9286-624dfad0b5fe.
U
ualtinok committed
e70d5d85eee7c6d15fbac9f43589aa1fa5355123
Parent: 4326e0b