Key inbound correlation by messageId with monotonic pi-timestamps

`registerInboundInjection` used to index correlations by
`Date.parse(record.createdAt)` — a millisecond-precision wall-clock
value. Two inbox rows that landed in the same millisecond collapsed
onto one Map slot, and the thread-event writer lost one peer's
identity on `message_end`.

Identity now lives on `record.id`. `projectInboundMessage` allocates a
monotonic `piTimestamp` per run (base = `Date.parse(createdAt)`,
bumped to `max(base, lastAllocated + 1)` so it is always unique
within the run) and stamps that value onto the projected pi message.
The correlation registry keeps `byMessageId` as the primary index and
`byPiTimestamp` as a reverse lookup so the `message_end` callback —
which only surfaces the pi-message shape — still resolves back to the
author without depending on wall-clock precision.

The runtime message injector now defers projection to
`RuntimeBridge.projectInboundMessage` so the steered message, the
correlation entry, and the allocated timestamp stay in lockstep.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 15:50:39 -04:00
1 parent 320706fecf
commit a36884360a
3 files changed
+90 -58

No files matched your search

+16 -4
View File
@@ -66,12 +66,20 @@ function resolveSenderLabel(
/**
* Projects a stored `AgentMessageRecord` into a pi `AgentMessage`
* (role: "user") suitable for appending to the recipient's session
* transcript. `timestamp` carries the message's `createdAt` in
* ms-since-epoch so transcript ordering aligns with wall-clock time.
* transcript.
*
* `timestampOverride`, when supplied, replaces the wall-clock timestamp
* derived from `record.createdAt`. Callers use this to allocate a
* monotonically unique value per run — two inbound messages landing in
* the same millisecond would otherwise share the same key, and the
* `RuntimeBridge` correlation index would lose one author's identity
* on the `message_end` callback. The actual value still lives in pi's
* `timestamp` number so ordering semantics remain identical.
*/
export function projectInboxMessageToPi(
record: AgentMessageRecord,
directory: AgentDirectory,
options?: { timestampOverride?: number },
): AgentMessage {
const senderLabel = resolveSenderLabel(record, directory);
const channelLabel = formatChannelLabel(record);
@@ -87,10 +95,14 @@ export function projectInboxMessageToPi(
if (body.length > 0) parts.push(body);
const text = parts.join("\n\n");
const timestamp = Date.parse(record.createdAt);
let timestamp = options?.timestampOverride;
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
const parsed = Date.parse(record.createdAt);
timestamp = Number.isFinite(parsed) ? parsed : Date.now();
}
return {
role: "user",
content: [{ type: "text", text }],
timestamp: Number.isFinite(timestamp) ? timestamp : Date.now(),
timestamp,
} as AgentMessage;
}