Files
OmniRoute/tests/unit/no-memory-header.test.ts
Diego Rodrigues de Sa e Souza bf5b615969 feat(memory): x-omniroute-no-memory opt-out + memory off-by-default + token-cost alert (PRD-2026-06-19) (#4290)
* feat(memory): x-omniroute-no-memory opt-out + memory off-by-default + token-cost UI alert

PRD-2026-06-19-no-memory-header. The gateway injects up to memorySettings.maxTokens
(~2k) of memory (and skills) context into every chat call for memory-enabled keys,
inflating tokens+cost ~137x for clients that manage their own context (e.g. Omniflow).

Three changes:
- A) x-omniroute-no-memory request header (mirrors x-omniroute-no-cache): when truthy
  (true/1/yes), skip memory+skills injection for that request. New pure helper
  isNoMemoryRequested() in chatCore/headers.ts; chatCore passes memoryOwnerId=null on
  opt-out (a null owner disables both injection branches).
- B) Memory OFF by default: DEFAULT_MEMORY_SETTINGS.enabled true->false. Enabling injects
  billed context per request, so it's now an explicit opt-in. Installs that already
  enabled it keep it; unset installs default off (no migration seeds memoryEnabled).
- C) Settings -> Memory shows a token-cost warning callout when memory is enabled
  (new settings.memoryTokenCostWarning i18n key, interpolating the configured maxTokens).

Tests: no-memory-header.test.ts (5, helper truthiness/case/Headers); memory-settings-default
and chatcore-memory-skills-injection aligned to the new off-by-default. 65/65 memory+chatcore
tests green; typecheck/lint/file-size/i18n(@65) clean.

* test(memory): enable memory in memory-tools test (memory now off by default)

The full CI unit suite flagged memory-tools.test.ts 'memory search ...' failing
after DEFAULT_MEMORY_SETTINGS.enabled flipped to false: omniroute_memory_search
routes through retrieveMemories, which returns [] while memory is disabled
(enabled:false → maxTokens 0). The memory MCP tools operate within the memory
subsystem, so the test now enables memory explicitly (updateSettings + cache
invalidation) — the realistic precondition for a client using the tools.
Aligns the test to the intentional off-by-default change; assertions unchanged.
2026-06-19 16:14:18 -03:00

46 lines
1.7 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
// PRD-2026-06-19: per-request opt-out of memory/skills injection via the
// `x-omniroute-no-memory` header (mirrors `x-omniroute-no-cache`).
const { isNoMemoryRequested, getHeaderValueCaseInsensitive } = await import(
"../../open-sse/handlers/chatCore/headers.ts"
);
test("isNoMemoryRequested is true for truthy header values (plain object)", () => {
for (const v of ["true", "1", "yes", "TRUE", "Yes", " true "]) {
assert.equal(
isNoMemoryRequested({ "x-omniroute-no-memory": v }),
true,
`expected true for ${JSON.stringify(v)}`
);
}
});
test("isNoMemoryRequested is case-insensitive on the header NAME", () => {
assert.equal(isNoMemoryRequested({ "X-OmniRoute-No-Memory": "true" }), true);
});
test("isNoMemoryRequested works with a Headers instance", () => {
const h = new Headers();
h.set("x-omniroute-no-memory", "1");
assert.equal(isNoMemoryRequested(h), true);
});
test("isNoMemoryRequested is false when the header is absent / empty / falsy", () => {
assert.equal(isNoMemoryRequested(null), false);
assert.equal(isNoMemoryRequested(undefined), false);
assert.equal(isNoMemoryRequested({}), false);
assert.equal(isNoMemoryRequested({ "x-omniroute-no-memory": "" }), false);
assert.equal(isNoMemoryRequested({ "x-omniroute-no-memory": "false" }), false);
assert.equal(isNoMemoryRequested({ "x-omniroute-no-memory": "0" }), false);
assert.equal(isNoMemoryRequested({ "x-omniroute-no-memory": "no" }), false);
});
test("getHeaderValueCaseInsensitive still resolves the header (sanity)", () => {
assert.equal(
getHeaderValueCaseInsensitive({ "x-omniroute-no-memory": "true" }, "x-omniroute-no-memory"),
"true"
);
});