mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 10:52:17 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
/**
|
|
* Unit tests for RequestTimeline's allocateLanes conversation-aware lane
|
|
* reuse (agentic conversation tracking / X-ConversationId).
|
|
*/
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { allocateLanes, type TimelineLog } from "../../src/shared/components/RequestTimeline.tsx";
|
|
|
|
function log(
|
|
id: string,
|
|
timestampMs: number,
|
|
durationMs: number,
|
|
sessionTag: string | null = null
|
|
): TimelineLog {
|
|
return {
|
|
id,
|
|
timestamp: new Date(timestampMs).toISOString(),
|
|
status: 200,
|
|
model: "test-model",
|
|
provider: "test-provider",
|
|
account: null,
|
|
duration: durationMs,
|
|
tokens: { in: 0, out: 0 },
|
|
completed: true,
|
|
sessionTag,
|
|
};
|
|
}
|
|
|
|
const BASE = 1_800_000_000_000; // arbitrary fixed epoch ms
|
|
|
|
test("allocateLanes: unrelated non-overlapping bars share a lane as before (no regression)", () => {
|
|
const items = [log("a", BASE, 1000), log("b", BASE + 5000, 1000)];
|
|
const lanes = allocateLanes(items, BASE + 10_000);
|
|
assert.equal(lanes.get("a"), lanes.get("b"));
|
|
});
|
|
|
|
test("allocateLanes: same conversation id reuses the same lane within the reuse window", () => {
|
|
const items = [
|
|
log("a", BASE, 1000, "conv-1"),
|
|
// Overlapping in time with "a" would normally force a different lane —
|
|
// but sharing conv-1 within the reuse window should force it onto a's lane.
|
|
log("b", BASE + 500, 1000, "conv-1"),
|
|
];
|
|
const lanes = allocateLanes(items, BASE + 10_000, 2 * 60 * 1000);
|
|
assert.equal(lanes.get("a"), lanes.get("b"));
|
|
});
|
|
|
|
test("allocateLanes: same conversation id falls back to normal packing outside the reuse window", () => {
|
|
const reuseWindowMs = 2 * 60 * 1000;
|
|
const items = [
|
|
log("a", BASE, 1000, "conv-2"),
|
|
// Same conversation id, but arrives long after the reuse window lapsed —
|
|
// must NOT be forced onto a's lane if that lane is still busy with
|
|
// something else (falls back to the ordinary overlap-avoidance packer).
|
|
log("b", BASE + reuseWindowMs + 60_000, 1000, "conv-2"),
|
|
// Occupies a's lane again right after "a" finishes, before "b" arrives —
|
|
// forces "b" to pack elsewhere via the normal greedy logic.
|
|
log("c", BASE + 2000, 1000, null),
|
|
];
|
|
const lanes = allocateLanes(items, BASE + reuseWindowMs + 65_000, reuseWindowMs);
|
|
// "a" and "c" share a's lane (c starts after a ends); "b" arrives far later
|
|
// and long after the reuse window, so it is free to reuse that same lane
|
|
// once it's genuinely free again — the key assertion is that "b" was NOT
|
|
// force-placed via conversation reuse logic (which only applies within the
|
|
// window), i.e. this is ordinary greedy packing, not identity-based.
|
|
assert.equal(lanes.get("a"), lanes.get("c"));
|
|
assert.ok(lanes.get("b") !== undefined);
|
|
});
|
|
|
|
test("allocateLanes: different conversation ids never share a lane just for overlapping in time", () => {
|
|
const items = [log("a", BASE, 5000, "conv-x"), log("b", BASE + 1000, 5000, "conv-y")];
|
|
const lanes = allocateLanes(items, BASE + 10_000);
|
|
assert.notEqual(lanes.get("a"), lanes.get("b"));
|
|
});
|