@eleboucher/pi-memini 0.7.5 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.js +139 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -154,8 +154,8 @@ authority is restored.
|
|
|
154
154
|
| `MEMINI_RECALL` | on | Automatic prompt recall. |
|
|
155
155
|
| `MEMINI_CAPTURE` | on | Settled-turn capture. |
|
|
156
156
|
| `MEMINI_RECALL_LIMIT` | `3` | Maximum automatic recall hits. |
|
|
157
|
-
| `MEMINI_INJECT_RECALL_MAX_TOK` | `
|
|
158
|
-
| `MEMINI_INJECT_RECALL_MIN_SCORE` | `0`
|
|
157
|
+
| `MEMINI_INJECT_RECALL_MAX_TOK` | `250` | Recall injection token ceiling; `0` is unbounded. |
|
|
158
|
+
| `MEMINI_INJECT_RECALL_MIN_SCORE` | `0.5` | Minimum automatic recall score (composite post-rerank scale); `0` disables the floor. |
|
|
159
159
|
| `MEMINI_INJECT_DEDUPE` | on | Shared cross-surface suppression state. |
|
|
160
160
|
| `MEMINI_INJECT_COOLDOWN_MS` | `1800000` | Time cooldown for repeated injection; `0` disables this dimension. |
|
|
161
161
|
| `MEMINI_INJECT_COOLDOWN_PROMPTS` | `3` | Prompt cooldown; `0` disables this dimension. Both cooldowns at `0` suppress for the session. |
|
|
@@ -164,7 +164,7 @@ authority is restored.
|
|
|
164
164
|
| `MEMINI_INJECT_BRIEFING_FACTS` | `5` | Startup durable-fact cap. |
|
|
165
165
|
| `MEMINI_INJECT_BRIEFING_PROCEDURES` | `5` | Startup procedure cap. |
|
|
166
166
|
| `MEMINI_INJECT_BRIEFING_RECENT` | `3` | Startup recent-memory cap. |
|
|
167
|
-
| `MEMINI_INJECT_BRIEFING_MAX_TOK` | `
|
|
167
|
+
| `MEMINI_INJECT_BRIEFING_MAX_TOK` | `600` | Whole briefing token ceiling; `0` is unbounded. |
|
|
168
168
|
| `MEMINI_SESSION_DIGEST` | on | Pre-compaction and shutdown activity checkpoints. |
|
|
169
169
|
| `MEMINI_MIN_CAPTURE_CHARS` | `0` | Minimum settled user-text length required for capture. |
|
|
170
170
|
| `MEMINI_CAPTURE_USER_MAX_CHARS` | `1000` | Per-turn captured user-text cap; `0` is unbounded. |
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
|
-
import { createHash } from "node:crypto";
|
|
6
5
|
|
|
7
6
|
// ../../../packages/memini-client/src/redact.ts
|
|
8
7
|
function redactValue(value) {
|
|
@@ -108,26 +107,31 @@ var BEHAVIOR_KNOBS = [
|
|
|
108
107
|
{ envName: "MEMINI_INJECT_BRIEFING_FACTS", wireKey: "inject_briefing_facts", kind: "int", default: 5 },
|
|
109
108
|
{ envName: "MEMINI_INJECT_BRIEFING_PROCEDURES", wireKey: "inject_briefing_procedures", kind: "int", default: 5 },
|
|
110
109
|
{ envName: "MEMINI_INJECT_BRIEFING_RECENT", wireKey: "inject_briefing_recent", kind: "int", default: 3 },
|
|
111
|
-
{ envName: "MEMINI_INJECT_BRIEFING_MAX_TOK", wireKey: "inject_briefing_max_tok", kind: "int", default:
|
|
110
|
+
{ envName: "MEMINI_INJECT_BRIEFING_MAX_TOK", wireKey: "inject_briefing_max_tok", kind: "int", default: 600 },
|
|
112
111
|
{ envName: "MEMINI_INJECT_PRETOOL_ITEMS", wireKey: "inject_pretool_items", kind: "int", default: 3 },
|
|
113
|
-
{ envName: "MEMINI_INJECT_PRETOOL_MAX_TOK", wireKey: "inject_pretool_max_tok", kind: "int", default:
|
|
114
|
-
{ envName: "MEMINI_INJECT_PRETOOL_MIN_SCORE", wireKey: "inject_pretool_min_score", kind: "float", default: 0 },
|
|
112
|
+
{ envName: "MEMINI_INJECT_PRETOOL_MAX_TOK", wireKey: "inject_pretool_max_tok", kind: "int", default: 200 },
|
|
113
|
+
{ envName: "MEMINI_INJECT_PRETOOL_MIN_SCORE", wireKey: "inject_pretool_min_score", kind: "float", default: 0.5 },
|
|
114
|
+
// Glob and Grep are deliberately not in the default allowlist:
|
|
115
|
+
// pattern-derived queries ("Grep on <pattern>") are near-zero-signal and
|
|
116
|
+
// each ungated call costs a server embed+rerank — list them to restore the
|
|
117
|
+
// old behavior.
|
|
115
118
|
{
|
|
116
119
|
envName: "MEMINI_INJECT_PRETOOL_TOOLS",
|
|
117
120
|
wireKey: "inject_pretool_tools",
|
|
118
121
|
kind: "list",
|
|
119
|
-
default: ["Read", "Write", "Edit", "MultiEdit"
|
|
122
|
+
default: ["Read", "Write", "Edit", "MultiEdit"]
|
|
120
123
|
},
|
|
121
124
|
{ envName: "MEMINI_INJECT_PRETOOL_GATE_MS", wireKey: "inject_pretool_gate_ms", kind: "int", default: 9e4 },
|
|
122
125
|
{ envName: "MEMINI_INJECT_DEDUPE", wireKey: "inject_dedupe", kind: "bool", default: true },
|
|
126
|
+
{ envName: "MEMINI_INJECT_TELEMETRY", wireKey: "inject_telemetry", kind: "bool", default: true },
|
|
123
127
|
{ envName: "MEMINI_INJECT_COOLDOWN_MS", wireKey: "inject_cooldown_ms", kind: "int", default: 18e5 },
|
|
124
128
|
{ envName: "MEMINI_INJECT_COOLDOWN_PROMPTS", wireKey: "inject_cooldown_prompts", kind: "int", default: 3 },
|
|
125
129
|
{ envName: "MEMINI_INJECT_LABELS", wireKey: "inject_labels", kind: "list", default: [] },
|
|
126
130
|
{ envName: "MEMINI_RECALL", wireKey: "recall", kind: "bool", default: true },
|
|
127
131
|
{ envName: "MEMINI_CAPTURE", wireKey: "capture", kind: "bool", default: true },
|
|
128
132
|
{ envName: "MEMINI_RECALL_LIMIT", wireKey: "recall_limit", kind: "int", default: 3 },
|
|
129
|
-
{ envName: "MEMINI_INJECT_RECALL_MAX_TOK", wireKey: "inject_recall_max_tok", kind: "int", default:
|
|
130
|
-
{ envName: "MEMINI_INJECT_RECALL_MIN_SCORE", wireKey: "inject_recall_min_score", kind: "float", default: 0 },
|
|
133
|
+
{ envName: "MEMINI_INJECT_RECALL_MAX_TOK", wireKey: "inject_recall_max_tok", kind: "int", default: 250 },
|
|
134
|
+
{ envName: "MEMINI_INJECT_RECALL_MIN_SCORE", wireKey: "inject_recall_min_score", kind: "float", default: 0.5 },
|
|
131
135
|
{ envName: "MEMINI_MIN_CAPTURE_CHARS", wireKey: "min_capture_chars", kind: "int", default: 0 },
|
|
132
136
|
{ envName: "MEMINI_CAPTURE_USER_MAX_CHARS", wireKey: "capture_user_max_chars", kind: "int", default: 1e3 },
|
|
133
137
|
{
|
|
@@ -321,6 +325,88 @@ async function performHandshake(boot, facts, opts = {}) {
|
|
|
321
325
|
}
|
|
322
326
|
}
|
|
323
327
|
|
|
328
|
+
// ../../../packages/memini-client/src/enforce/identity.ts
|
|
329
|
+
import crypto from "node:crypto";
|
|
330
|
+
function isContentHash(s) {
|
|
331
|
+
return typeof s === "string" && /^[0-9a-f]{16}$/.test(s);
|
|
332
|
+
}
|
|
333
|
+
function injectedIdentity(m) {
|
|
334
|
+
const ch = m?.content_hash ?? m?.memory?.content_hash;
|
|
335
|
+
if (isContentHash(ch)) return ch;
|
|
336
|
+
const text = m?.content || m?.summary || "";
|
|
337
|
+
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ../../../packages/memini-client/src/enforce/seen.ts
|
|
341
|
+
function injectedSuppressed(entry, identity, { now, counter, cooldownMs, cooldownPrompts }) {
|
|
342
|
+
if (!entry || typeof entry !== "object") return false;
|
|
343
|
+
if (entry.h === "") return true;
|
|
344
|
+
if (identity && entry.h !== identity) return false;
|
|
345
|
+
if (cooldownMs === 0 && cooldownPrompts === 0) return true;
|
|
346
|
+
const promptDim = cooldownPrompts > 0 && counter > 0 && counter - entry.n < cooldownPrompts;
|
|
347
|
+
const timeDim = cooldownMs > 0 && now - entry.at < cooldownMs;
|
|
348
|
+
return promptDim || timeDim;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ../../../packages/memini-client/src/enforce/budget.ts
|
|
352
|
+
function approxTokens(text) {
|
|
353
|
+
if (!text) return 0;
|
|
354
|
+
const words = String(text).trim().split(/\s+/).filter(Boolean).length;
|
|
355
|
+
return Math.max(1, Math.ceil(words * 4 / 3));
|
|
356
|
+
}
|
|
357
|
+
function fitByTokens(items, maxTokens) {
|
|
358
|
+
if (!Array.isArray(items) || items.length === 0) return { items: [], tokens: 0, dropped: 0 };
|
|
359
|
+
if (!Number.isFinite(maxTokens) || maxTokens <= 0) {
|
|
360
|
+
const tokens = items.reduce((sum, s) => sum + approxTokens(s), 0);
|
|
361
|
+
return { items: items.slice(), tokens, dropped: 0 };
|
|
362
|
+
}
|
|
363
|
+
const out = [];
|
|
364
|
+
let used = 0;
|
|
365
|
+
let dropped = 0;
|
|
366
|
+
for (const s of items) {
|
|
367
|
+
const t = approxTokens(s);
|
|
368
|
+
if (used + t > maxTokens) {
|
|
369
|
+
const charBudget = (maxTokens - used) * 4;
|
|
370
|
+
if (charBudget > 20) {
|
|
371
|
+
let cut = s.slice(0, charBudget);
|
|
372
|
+
const lastNL = cut.lastIndexOf("\n");
|
|
373
|
+
if (lastNL > 20) cut = cut.slice(0, lastNL);
|
|
374
|
+
if (cut.length > 20) {
|
|
375
|
+
out.push(cut + "\n[...truncated]");
|
|
376
|
+
used += approxTokens(cut);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
dropped++;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
out.push(s);
|
|
384
|
+
used += t;
|
|
385
|
+
}
|
|
386
|
+
return { items: out, tokens: used, dropped };
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ../../../packages/memini-client/src/enforce/render.ts
|
|
390
|
+
function escapeMeminiTags(content) {
|
|
391
|
+
if (typeof content !== "string") return content;
|
|
392
|
+
return content.replace(/<(\/?)memini/gi, "<$1memini");
|
|
393
|
+
}
|
|
394
|
+
function truncate(value, max) {
|
|
395
|
+
if (typeof value === "string") {
|
|
396
|
+
return value.length > max ? value.slice(0, max) + "\n[...truncated]" : value;
|
|
397
|
+
}
|
|
398
|
+
if (value && typeof value === "object") {
|
|
399
|
+
let str;
|
|
400
|
+
try {
|
|
401
|
+
str = JSON.stringify(value);
|
|
402
|
+
} catch {
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
return str.length > max ? str.slice(0, max) + "...[truncated]" : str;
|
|
406
|
+
}
|
|
407
|
+
return value;
|
|
408
|
+
}
|
|
409
|
+
|
|
324
410
|
// src/index.ts
|
|
325
411
|
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
326
412
|
var DEFAULT_RECALL_LIMIT = 3;
|
|
@@ -459,45 +545,12 @@ async function sessionLive(ctx, env = process.env) {
|
|
|
459
545
|
const hs = await ctx.memo.get();
|
|
460
546
|
return resolveLiveConfig(ctx.boot, ctx.facts, hs, env);
|
|
461
547
|
}
|
|
462
|
-
function approxTokens(text) {
|
|
463
|
-
if (!text) return 0;
|
|
464
|
-
const words = String(text).trim().split(/\s+/).filter(Boolean).length;
|
|
465
|
-
return Math.max(1, Math.ceil(words * 4 / 3));
|
|
466
|
-
}
|
|
467
|
-
function fitByTokens(items, maxTokens) {
|
|
468
|
-
if (!Array.isArray(items) || items.length === 0) return { items: [], tokens: 0, dropped: 0 };
|
|
469
|
-
if (!Number.isFinite(maxTokens) || maxTokens <= 0) {
|
|
470
|
-
const tokens = items.reduce((sum, s) => sum + approxTokens(s), 0);
|
|
471
|
-
return { items: items.slice(), tokens, dropped: 0 };
|
|
472
|
-
}
|
|
473
|
-
const out = [];
|
|
474
|
-
let used = 0;
|
|
475
|
-
let dropped = 0;
|
|
476
|
-
for (const s of items) {
|
|
477
|
-
const t = approxTokens(s);
|
|
478
|
-
if (used + t > maxTokens) {
|
|
479
|
-
dropped++;
|
|
480
|
-
continue;
|
|
481
|
-
}
|
|
482
|
-
out.push(s);
|
|
483
|
-
used += t;
|
|
484
|
-
}
|
|
485
|
-
return { items: out, tokens: used, dropped };
|
|
486
|
-
}
|
|
487
|
-
function truncate(value, max) {
|
|
488
|
-
return value.length > max ? value.slice(0, max) + "\n[...truncated]" : value;
|
|
489
|
-
}
|
|
490
|
-
function escapeMeminiTags(value) {
|
|
491
|
-
return String(value ?? "").replace(/<(\/?)memini/gi, (_match, slash) => `<${slash}memini`);
|
|
492
|
-
}
|
|
493
548
|
function boundedInjectedText(value, max) {
|
|
494
|
-
const escaped = escapeMeminiTags(value).replace(/\s+/g, " ").trim();
|
|
549
|
+
const escaped = escapeMeminiTags(String(value ?? "")).replace(/\s+/g, " ").trim();
|
|
495
550
|
return unicodePrefix(escaped, max);
|
|
496
551
|
}
|
|
497
|
-
function
|
|
498
|
-
|
|
499
|
-
const content = String(memory?.content || memory?.summary || "");
|
|
500
|
-
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
552
|
+
function injectedIdentity2(raw) {
|
|
553
|
+
return injectedIdentity(raw?.memory ?? raw);
|
|
501
554
|
}
|
|
502
555
|
function formatResults(results, limit, labels) {
|
|
503
556
|
if (!Array.isArray(results) || results.length === 0) return [];
|
|
@@ -640,7 +693,12 @@ var MEMORY_FIELDS = [
|
|
|
640
693
|
"superseded_by",
|
|
641
694
|
"valid_from",
|
|
642
695
|
"valid_to",
|
|
643
|
-
"confidence"
|
|
696
|
+
"confidence",
|
|
697
|
+
// Progressive-disclosure fields: content_hash (16-hex identity over the
|
|
698
|
+
// full stored content, stable across response formats) and
|
|
699
|
+
// content_truncated (set on concise projections that actually cut).
|
|
700
|
+
"content_hash",
|
|
701
|
+
"content_truncated"
|
|
644
702
|
];
|
|
645
703
|
function normalizeMemory(raw) {
|
|
646
704
|
const memory = raw?.memory ?? raw ?? {};
|
|
@@ -1207,6 +1265,10 @@ function isExplicitExcludeIdsRejection(result) {
|
|
|
1207
1265
|
if (result.status !== 400 || !result.error || !/exclude_ids/i.test(result.error)) return false;
|
|
1208
1266
|
return /(unknown|unsupported|unrecognized|unexpected|not allowed|additional propert)/i.test(result.error);
|
|
1209
1267
|
}
|
|
1268
|
+
function isExplicitMinRankScoreRejection(result) {
|
|
1269
|
+
if (result.status !== 400 || !result.error || !/min_rank_score/i.test(result.error)) return false;
|
|
1270
|
+
return /(unknown|unsupported|unrecognized|unexpected|not allowed|additional propert)/i.test(result.error);
|
|
1271
|
+
}
|
|
1210
1272
|
function extractSettledTurn(entries) {
|
|
1211
1273
|
if (!Array.isArray(entries)) return null;
|
|
1212
1274
|
let userIndex = -1;
|
|
@@ -1406,7 +1468,7 @@ function meminiExtension(pi) {
|
|
|
1406
1468
|
if (!id) continue;
|
|
1407
1469
|
changed = true;
|
|
1408
1470
|
injected.delete(id);
|
|
1409
|
-
injected.set(id, { h: explicitRead ? "" :
|
|
1471
|
+
injected.set(id, { h: explicitRead ? "" : injectedIdentity2(raw), at: now, n: promptCount });
|
|
1410
1472
|
}
|
|
1411
1473
|
while (injected.size > MAX_INJECTED) injected.delete(injected.keys().next().value);
|
|
1412
1474
|
if (changed) persistState();
|
|
@@ -1439,14 +1501,7 @@ function meminiExtension(pi) {
|
|
|
1439
1501
|
});
|
|
1440
1502
|
rememberInjected(eligible, transition.explicit);
|
|
1441
1503
|
};
|
|
1442
|
-
const suppressed = (entry, now, cooldownMs, cooldownPrompts, identity) => {
|
|
1443
|
-
if (entry.h === "") return true;
|
|
1444
|
-
if (identity && entry.h !== identity) return false;
|
|
1445
|
-
if (cooldownMs === 0 && cooldownPrompts === 0) return true;
|
|
1446
|
-
const promptDim = cooldownPrompts > 0 && promptCount > 0 && promptCount - entry.n < cooldownPrompts;
|
|
1447
|
-
const timeDim = cooldownMs > 0 && now - entry.at < cooldownMs;
|
|
1448
|
-
return promptDim || timeDim;
|
|
1449
|
-
};
|
|
1504
|
+
const suppressed = (entry, now, cooldownMs, cooldownPrompts, identity) => injectedSuppressed(entry, identity ?? null, { now, counter: promptCount, cooldownMs, cooldownPrompts });
|
|
1450
1505
|
const injectedInWindow = (live) => {
|
|
1451
1506
|
const inWindow = /* @__PURE__ */ new Map();
|
|
1452
1507
|
if (!live.inject_dedupe) return inWindow;
|
|
@@ -1576,18 +1631,27 @@ function meminiExtension(pi) {
|
|
|
1576
1631
|
return null;
|
|
1577
1632
|
};
|
|
1578
1633
|
const searchExcluding = async (body, excludeIds, namespace) => {
|
|
1634
|
+
const rankFloorInBody = body.min_rank_score !== void 0;
|
|
1579
1635
|
const capped = excludeIds.slice(0, MAX_SERVER_EXCLUDE_IDS);
|
|
1580
|
-
|
|
1581
|
-
const first = await client.postJsonResult(
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1636
|
+
const withExcludeIds = serverExcludeIds && capped.length > 0;
|
|
1637
|
+
const first = await client.postJsonResult(
|
|
1638
|
+
"/v1/search",
|
|
1639
|
+
withExcludeIds ? { ...body, exclude_ids: capped } : body,
|
|
1640
|
+
namespace
|
|
1641
|
+
);
|
|
1642
|
+
if (first.ok) return { data: first.data, rankFloorStripped: false };
|
|
1643
|
+
const excludeIdsRejected = withExcludeIds && isExplicitExcludeIdsRejection(first);
|
|
1644
|
+
const rankFloorRejected = rankFloorInBody && isExplicitMinRankScoreRejection(first);
|
|
1645
|
+
if (!excludeIdsRejected && !rankFloorRejected) return { data: searchFailure(first), rankFloorStripped: false };
|
|
1646
|
+
if (excludeIdsRejected) {
|
|
1586
1647
|
serverExcludeIds = false;
|
|
1587
1648
|
warn("memini: server does not accept exclude_ids; using client-side dedupe only");
|
|
1588
|
-
return retry.data;
|
|
1589
1649
|
}
|
|
1590
|
-
|
|
1650
|
+
const stripped = { ...body };
|
|
1651
|
+
delete stripped.min_rank_score;
|
|
1652
|
+
const retry = await client.postJsonResult("/v1/search", stripped, namespace);
|
|
1653
|
+
if (retry.ok) return { data: retry.data, rankFloorStripped: rankFloorInBody };
|
|
1654
|
+
return { data: searchFailure(retry), rankFloorStripped: false };
|
|
1591
1655
|
};
|
|
1592
1656
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
1593
1657
|
const sid = sessionIdOf(ctx);
|
|
@@ -1606,12 +1670,16 @@ function meminiExtension(pi) {
|
|
|
1606
1670
|
limit: live.recall_limit
|
|
1607
1671
|
};
|
|
1608
1672
|
if (live.inject_dedupe && sid) body.exclude_metadata = { session_id: sid };
|
|
1609
|
-
|
|
1673
|
+
const rankFloor = live.recall_min_score;
|
|
1674
|
+
const rankFloorInRange = rankFloor > 0 && rankFloor < 1;
|
|
1675
|
+
if (rankFloorInRange) body.min_rank_score = rankFloor;
|
|
1610
1676
|
const inWindow = injectedInWindow(live);
|
|
1611
1677
|
const readVersion = mutationClock;
|
|
1612
1678
|
const readEpoch = stateEpoch;
|
|
1613
|
-
const
|
|
1614
|
-
const
|
|
1679
|
+
const searchResult = await searchExcluding(body, live.inject_dedupe ? [...inWindow.keys()] : [], live.namespace);
|
|
1680
|
+
const result = searchResult.data;
|
|
1681
|
+
const serverEnforcedFloor = rankFloorInRange && !searchResult.rankFloorStripped;
|
|
1682
|
+
const floor = rankFloor > 0 && !serverEnforcedFloor ? rankFloor : 0;
|
|
1615
1683
|
let rawHits = Array.isArray(result?.results) ? result.results : [];
|
|
1616
1684
|
if (live.inject_dedupe && inWindow.size) {
|
|
1617
1685
|
rawHits = rawHits.filter((raw) => {
|
|
@@ -1622,7 +1690,7 @@ function meminiExtension(pi) {
|
|
|
1622
1690
|
Date.now(),
|
|
1623
1691
|
live.inject_cooldown_ms,
|
|
1624
1692
|
live.inject_cooldown_prompts,
|
|
1625
|
-
|
|
1693
|
+
injectedIdentity2(raw)
|
|
1626
1694
|
);
|
|
1627
1695
|
});
|
|
1628
1696
|
}
|
|
@@ -1723,6 +1791,9 @@ function meminiExtension(pi) {
|
|
|
1723
1791
|
maxItems: MAX_SERVER_EXCLUDE_IDS,
|
|
1724
1792
|
description: "Drop these memory ids before ranking and limit."
|
|
1725
1793
|
})),
|
|
1794
|
+
min_rank_score: Type.Optional(Type.Number({
|
|
1795
|
+
description: "drop results whose final ranked score is below this ([0,1)); rarely needed \u2014 the server already gates relevance"
|
|
1796
|
+
})),
|
|
1726
1797
|
include_fresh_turns: Type.Optional(Type.Boolean({
|
|
1727
1798
|
description: "Include just-captured turns normally hidden by the temporal echo guard."
|
|
1728
1799
|
})),
|
|
@@ -1751,6 +1822,7 @@ function meminiExtension(pi) {
|
|
|
1751
1822
|
"metadata",
|
|
1752
1823
|
"exclude_metadata",
|
|
1753
1824
|
"exclude_ids",
|
|
1825
|
+
"min_rank_score",
|
|
1754
1826
|
"include_fresh_turns",
|
|
1755
1827
|
"query_rewrite",
|
|
1756
1828
|
"as_of"
|
|
@@ -2117,9 +2189,10 @@ export {
|
|
|
2117
2189
|
fitByTokens,
|
|
2118
2190
|
floatEnv,
|
|
2119
2191
|
formatResults,
|
|
2120
|
-
injectedIdentity,
|
|
2192
|
+
injectedIdentity2 as injectedIdentity,
|
|
2121
2193
|
intEnv,
|
|
2122
2194
|
isExplicitExcludeIdsRejection,
|
|
2195
|
+
isExplicitMinRankScoreRejection,
|
|
2123
2196
|
meminiListPath,
|
|
2124
2197
|
memoizeAsync,
|
|
2125
2198
|
memoryResultDetails,
|