Merge pull request #2212 from code-yeongyu/fix/h5-collector-ordering
fix(context-injector): use monotonic registration order instead of timestamp for deterministic sorting
This commit is contained in:
@@ -205,6 +205,45 @@ describe("ContextCollector", () => {
|
|||||||
const ids = pending.entries.map((e) => e.id)
|
const ids = pending.entries.map((e) => e.id)
|
||||||
expect(ids).toEqual(["first", "second", "third"])
|
expect(ids).toEqual(["first", "second", "third"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("keeps registration order even when Date.now values are not monotonic", () => {
|
||||||
|
// given
|
||||||
|
const sessionID = "ses_order_non_monotonic_time"
|
||||||
|
const originalDateNow = Date.now
|
||||||
|
const mockedTimestamps = [300, 100, 200]
|
||||||
|
let timestampIndex = 0
|
||||||
|
Date.now = () => mockedTimestamps[timestampIndex++] ?? 0
|
||||||
|
|
||||||
|
try {
|
||||||
|
collector.register(sessionID, {
|
||||||
|
id: "first",
|
||||||
|
source: "custom",
|
||||||
|
content: "First",
|
||||||
|
priority: "normal",
|
||||||
|
})
|
||||||
|
collector.register(sessionID, {
|
||||||
|
id: "second",
|
||||||
|
source: "custom",
|
||||||
|
content: "Second",
|
||||||
|
priority: "normal",
|
||||||
|
})
|
||||||
|
collector.register(sessionID, {
|
||||||
|
id: "third",
|
||||||
|
source: "custom",
|
||||||
|
content: "Third",
|
||||||
|
priority: "normal",
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
Date.now = originalDateNow
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const pending = collector.getPending(sessionID)
|
||||||
|
|
||||||
|
// then
|
||||||
|
const ids = pending.entries.map((entry) => entry.id)
|
||||||
|
expect(ids).toEqual(["first", "second", "third"])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("consume", () => {
|
describe("consume", () => {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ const PRIORITY_ORDER: Record<ContextPriority, number> = {
|
|||||||
|
|
||||||
const CONTEXT_SEPARATOR = "\n\n---\n\n"
|
const CONTEXT_SEPARATOR = "\n\n---\n\n"
|
||||||
|
|
||||||
|
let registrationCounter = 0
|
||||||
|
|
||||||
export class ContextCollector {
|
export class ContextCollector {
|
||||||
private sessions: Map<string, Map<string, ContextEntry>> = new Map()
|
private sessions: Map<string, Map<string, ContextEntry>> = new Map()
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ export class ContextCollector {
|
|||||||
source: options.source,
|
source: options.source,
|
||||||
content: options.content,
|
content: options.content,
|
||||||
priority: options.priority ?? "normal",
|
priority: options.priority ?? "normal",
|
||||||
timestamp: Date.now(),
|
registrationOrder: ++registrationCounter,
|
||||||
metadata: options.metadata,
|
metadata: options.metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +79,7 @@ export class ContextCollector {
|
|||||||
return entries.sort((a, b) => {
|
return entries.sort((a, b) => {
|
||||||
const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]
|
const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]
|
||||||
if (priorityDiff !== 0) return priorityDiff
|
if (priorityDiff !== 0) return priorityDiff
|
||||||
return a.timestamp - b.timestamp
|
return a.registrationOrder - b.registrationOrder
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export interface ContextEntry {
|
|||||||
content: string
|
content: string
|
||||||
/** Priority for ordering (default: normal) */
|
/** Priority for ordering (default: normal) */
|
||||||
priority: ContextPriority
|
priority: ContextPriority
|
||||||
/** Timestamp when registered */
|
/** Monotonic order when registered */
|
||||||
timestamp: number
|
registrationOrder: number
|
||||||
/** Optional metadata for debugging/logging */
|
/** Optional metadata for debugging/logging */
|
||||||
metadata?: Record<string, unknown>
|
metadata?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user