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:
1 parent
320706fecf
commit
a36884360a
3 files changed
+90
-58
No files matched your search
@@ -27,7 +27,6 @@ import { randomUUID } from "node:crypto";
|
||||
import type { AppDatabase } from "@main/database";
|
||||
import type { AgentMessageRecord } from "@shared/types";
|
||||
import type { ParentMessage } from "@main/worker/worker-helpers";
|
||||
import { projectInboxMessageToPi } from "./inbox-projection";
|
||||
import type { RuntimeBridge } from "./runtime-bridge";
|
||||
|
||||
export interface RuntimeMessageInjectorDeps {
|
||||
@@ -90,9 +89,13 @@ export class RuntimeMessageInjector {
|
||||
return false;
|
||||
}
|
||||
|
||||
const projected = projectInboxMessageToPi(message, {
|
||||
getAgentName: (id) => this.resolveAgentName(id),
|
||||
});
|
||||
// Delegate projection + correlation registration to the bridge so
|
||||
// the worker steers the exact same pi-message object that the
|
||||
// bridge has indexed under `record.id`. `projectInboundMessage`
|
||||
// allocates a monotonic `piTimestamp` which is what `message_end`
|
||||
// surfaces back on the wire — two inbound rows that share the
|
||||
// same wall-clock millisecond are no longer indistinguishable.
|
||||
const projected = this.deps.runtimeBridge.projectInboundMessage(ctx.runId, message);
|
||||
const correlationId = randomUUID();
|
||||
|
||||
try {
|
||||
@@ -146,13 +149,6 @@ export class RuntimeMessageInjector {
|
||||
this.pending.delete(correlationId);
|
||||
|
||||
if (accepted) {
|
||||
try {
|
||||
this.deps.runtimeBridge.registerInboundInjection(entry.runId, entry.message);
|
||||
} catch (error) {
|
||||
this.deps.logger.warn(
|
||||
`[injector] registerInboundInjection failed for ${entry.message.id}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
this.deps.db.markAgentInboxDelivered(entry.recipientAgentId, [entry.message.id]);
|
||||
} catch (error) {
|
||||
@@ -178,13 +174,4 @@ export class RuntimeMessageInjector {
|
||||
}
|
||||
}
|
||||
|
||||
private resolveAgentName(agentId: string): string {
|
||||
try {
|
||||
const name = this.deps.db.findAgentName(agentId);
|
||||
if (name && name.length > 0) return name;
|
||||
} catch {
|
||||
// fall through
|
||||
}
|
||||
return agentId;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user