agenr 0.12.0 → 0.12.2
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/CHANGELOG.md +42 -0
- package/README.md +2 -2
- package/dist/agent-store-passthrough-defaults-M7BZ5U6A.js +36 -0
- package/dist/{bulk-store-defaults-DS5DDUSF.js → bulk-store-defaults-DDVYI3DG.js} +2 -2
- package/dist/{chunk-DSOV3M3M.js → chunk-BR65GBJG.js} +1 -1
- package/dist/chunk-CUCVRI3K.js +34 -0
- package/dist/{chunk-W6MVPK2E.js → chunk-D3DYUJKW.js} +108 -44
- package/dist/{chunk-UBX652ZM.js → chunk-HMBONTF3.js} +237 -34
- package/dist/{chunk-3MZJQ65U.js → chunk-L2CPAYHC.js} +9 -7
- package/dist/{chunk-SP22PEF5.js → chunk-R2X5CMR3.js} +22 -10
- package/dist/{chunk-Y4RTK5NN.js → chunk-UNB2GHB2.js} +1047 -1016
- package/dist/{chunk-7IU43M5Q.js → chunk-YFOFO2FC.js} +1 -1
- package/dist/{chunk-AGNLPIGB.js → chunk-YXHYBR54.js} +852 -122
- package/dist/{classify-entries-NPEN2KOL.js → classify-entries-XI6ACRFB.js} +2 -2
- package/dist/cli-main.d.ts +1 -1
- package/dist/cli-main.js +599 -89
- package/dist/{eval-defaults-E7P4JH56.js → eval-defaults-KQT4VBA7.js} +1 -1
- package/dist/{maintain-2OCNI6YE.js → maintain-5PS7LHYL.js} +106 -8
- package/dist/openclaw-plugin/index.d.ts +1 -1
- package/dist/openclaw-plugin/index.js +212 -58
- package/dist/{types-CHHaQeIC.d.ts → types-CxyMaRsR.d.ts} +50 -0
- package/dist/{workflow-JQOHY3MV.js → workflow-CNIGIVEH.js} +4 -4
- package/package.json +25 -31
- package/skills/SKILL.md +22 -1
- package/dist/chunk-IU7EJ23G.js +0 -81
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.12.2] - 2026-03-22
|
|
4
|
+
|
|
5
|
+
### Recall Scoping Fixes
|
|
6
|
+
|
|
7
|
+
- **Wildcard project passthrough.** `project: "*"` no longer gets silently dropped to `undefined` during recall request building. The wildcard marker now flows through the full stack to `hasWildcardProjectOverride` in `prepareRecallInputs`, enabling true cross-project recall.
|
|
8
|
+
- **Default project fallback for unscoped recall.** When an agent calls `agenr_recall` without an explicit `project`, the session's default project is now used as a `universal_first` hint — searching the default project first with null-project fallback. Previously, unscoped recall defaulted to null-project-only entries, silently returning near-empty results for project-heavy corpora.
|
|
9
|
+
- **Wildcard default when no project context.** When neither an explicit project nor a session default is available, unscoped recall now defaults to wildcard (`*`) cross-project search instead of null-project-only.
|
|
10
|
+
|
|
11
|
+
### Browse Recall
|
|
12
|
+
|
|
13
|
+
- **Temporal proximity rebalancing.** Browse mode recall now prioritizes temporal proximity over importance with a diversity pass, better surfacing recent entries during temporal exploration.
|
|
14
|
+
- **Removed default 1d since window.** Browse mode no longer applies a default 1-day `since` window, allowing full temporal exploration of the corpus.
|
|
15
|
+
|
|
16
|
+
### Update & Retire Improvements
|
|
17
|
+
|
|
18
|
+
- **Expiry changes via `agenr_update`.** The update tool now supports changing an entry's expiry tier (`core` → `permanent`, etc.) without retiring and re-creating it. Entry history (confirmations, recall count, created_at) is preserved.
|
|
19
|
+
- **Subject selectors for update and retire.** Both `agenr_update` and `agenr_retire` now accept `subject` as an alternative to `entry_id`. Subject matching is case-insensitive exact match; when multiple entries share a subject, the most recent is targeted.
|
|
20
|
+
- **Agent action replay.** Retire and update operations now support recall target hints for agent action replay workflows.
|
|
21
|
+
|
|
22
|
+
### Maintenance
|
|
23
|
+
|
|
24
|
+
- **Vector integrity detection.** New `vector-integrity` maintain task detects and repairs drift between the vector shadow table and the entries table.
|
|
25
|
+
|
|
26
|
+
## [0.12.1] - 2026-03-21
|
|
27
|
+
|
|
28
|
+
### Post-Ingest Quality Fixes
|
|
29
|
+
|
|
30
|
+
- **Active-only FTS index.** FTS triggers and rebuild helpers now scope to active entries only (`retired = 0, superseded_by IS NULL`). Retired entries no longer occupy FTS slots or get reindexed during maintenance.
|
|
31
|
+
- **Active-only vector index.** The `idx_entries_embedding_shadow` partial index now excludes retired entries. Vector `top_k` queries no longer waste slots on retired embeddings that get post-filtered. Rebuild and health-check paths updated to match.
|
|
32
|
+
- **Schema regression test.** Fresh `init`/`reset` must create active-only trigger and index definitions — validated by new schema test.
|
|
33
|
+
|
|
34
|
+
### Passthrough Dedup Fix
|
|
35
|
+
|
|
36
|
+
- **Normalized content hash dedup.** Passthrough now checks active `norm_content_hash` before insert, catching exact duplicates that survived because the previous `contentHash` included `source.file`. Identical content from different tool calls is now correctly deduplicated.
|
|
37
|
+
- **Within-batch norm-hash tracking.** Local batch dedup tracks both `contentHash` and `normContentHash`, preventing same-batch duplicates with different synthetic source files.
|
|
38
|
+
- **Granular skip tracking.** `stats.skipped` now counts by skipped candidates rather than matched set size.
|
|
39
|
+
|
|
40
|
+
### Store Guidance
|
|
41
|
+
|
|
42
|
+
- **Future-session test.** Updated `agenr_store` tool description, Memory Doctrine (`system-context.ts`), and SKILL.md with concrete store/don't-store guidance. Agents are now instructed to apply the "future-session test" before storing: will a fresh session need this to act differently, or is this just logging what happened?
|
|
43
|
+
- **Importance calibration.** Added "importance is not recency" guidance — shipping events are 5-6, recurring operational hazards are 7-8.
|
|
44
|
+
|
|
3
45
|
## [0.12.0] - 2026-03-20
|
|
4
46
|
|
|
5
47
|
### Ingestion Overhaul
|
package/README.md
CHANGED
|
@@ -162,7 +162,7 @@ agenr recall "package manager"
|
|
|
162
162
|
tags: tooling, package-manager
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
Recall supports date range queries (`--since 14d --until 7d`), temporal browse mode (`--browse --since 1d`), and around-date targeting (`--around 2026-02-15 --around-radius 14`) to rank entries by distance from a specific date.
|
|
165
|
+
Recall supports date range queries (`--since 14d --until 7d`), temporal browse mode (`--browse --since 1d`), and around-date targeting (`--around 2026-02-15 --around-radius 14`) to rank entries primarily by distance from a specific date with importance used as a secondary tiebreaker.
|
|
166
166
|
|
|
167
167
|
### Cross-session Handoff
|
|
168
168
|
|
|
@@ -257,7 +257,7 @@ This exposes four MCP tools: `agenr_recall`, `agenr_extract`, `agenr_retire`, an
|
|
|
257
257
|
| `agenr store [files...]` | Store entries with semantic dedup |
|
|
258
258
|
| `agenr recall [query]` | Semantic + memory-aware recall. Use `--since`/`--until` for date ranges, `--around` for target-date ranking, `--browse` for temporal mode. |
|
|
259
259
|
| `agenr retire [subject]` | Retire a stale entry (hidden, not deleted). Match by subject or `--id`. |
|
|
260
|
-
| `agenr update --id <id> --importance <n
|
|
260
|
+
| `agenr update --id <id> [--importance <n>] [--expiry <level>]` | Update mutable entry metadata in place. Supports importance and expiry; pass at least one. |
|
|
261
261
|
| `agenr watch [file]` | Live-watch files/directories, auto-extract knowledge |
|
|
262
262
|
| `agenr watcher install` | Install background watch daemon (macOS launchd) |
|
|
263
263
|
| `agenr watcher status` | Show daemon status (running/stopped, pid, watched file, recent logs) |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeMinhashSig,
|
|
3
|
+
computeNormContentHash,
|
|
4
|
+
findExistingContentHashes,
|
|
5
|
+
findExistingNormContentHashes,
|
|
6
|
+
hashEntrySourceContent,
|
|
7
|
+
insertEntry,
|
|
8
|
+
minhashSigToBuffer
|
|
9
|
+
} from "./chunk-UNB2GHB2.js";
|
|
10
|
+
import "./chunk-5645B45W.js";
|
|
11
|
+
import "./chunk-QDW77NBA.js";
|
|
12
|
+
import "./chunk-OZK32TEX.js";
|
|
13
|
+
import "./chunk-6HTA55NQ.js";
|
|
14
|
+
import {
|
|
15
|
+
composeEmbeddingText
|
|
16
|
+
} from "./chunk-RVPPKW4P.js";
|
|
17
|
+
import "./chunk-FIKYMSL6.js";
|
|
18
|
+
import "./chunk-7VFBBJVV.js";
|
|
19
|
+
import "./chunk-MLKGABMK.js";
|
|
20
|
+
|
|
21
|
+
// src/runtime/agent-store-passthrough-defaults.ts
|
|
22
|
+
function resolveAgentStorePassthroughDefaults() {
|
|
23
|
+
return {
|
|
24
|
+
computeMinhashSigFn: computeMinhashSig,
|
|
25
|
+
computeNormContentHashFn: computeNormContentHash,
|
|
26
|
+
minhashSigToBufferFn: minhashSigToBuffer,
|
|
27
|
+
hashEntrySourceContentFn: hashEntrySourceContent,
|
|
28
|
+
findExistingContentHashesFn: (db, hashes) => findExistingContentHashes(db, hashes),
|
|
29
|
+
findExistingNormContentHashesFn: (db, hashes) => findExistingNormContentHashes(db, hashes),
|
|
30
|
+
composeEmbeddingTextFn: composeEmbeddingText,
|
|
31
|
+
insertEntryFn: (db, entry, embedding, contentHash, normContentHash, minhashSig, config, options) => insertEntry(db, entry, embedding, contentHash, normContentHash, minhashSig, config, options)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
resolveAgentStorePassthroughDefaults
|
|
36
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/domain/watcher-demotion.ts
|
|
2
|
+
var WATCHER_DEMOTED_TAG = "watcher-demoted";
|
|
3
|
+
var DEFAULT_OPENCLAW_WATCHER_DEMOTION_IMPORTANCE_CAP = 4;
|
|
4
|
+
var DEFAULT_OPENCLAW_WATCHER_DEMOTION_TTL_DAYS = 30;
|
|
5
|
+
function clampInteger(value, floor, fallback) {
|
|
6
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
7
|
+
return fallback;
|
|
8
|
+
}
|
|
9
|
+
return Math.max(floor, Math.floor(value));
|
|
10
|
+
}
|
|
11
|
+
function resolveOpenClawWatcherDemotionConfig(config) {
|
|
12
|
+
const watcherConfig = config?.watcher?.openclawDemotion;
|
|
13
|
+
return {
|
|
14
|
+
enabled: watcherConfig?.enabled !== false,
|
|
15
|
+
importanceCap: Math.min(
|
|
16
|
+
10,
|
|
17
|
+
clampInteger(
|
|
18
|
+
watcherConfig?.importanceCap,
|
|
19
|
+
1,
|
|
20
|
+
DEFAULT_OPENCLAW_WATCHER_DEMOTION_IMPORTANCE_CAP
|
|
21
|
+
)
|
|
22
|
+
),
|
|
23
|
+
ttlDays: clampInteger(
|
|
24
|
+
watcherConfig?.ttlDays,
|
|
25
|
+
1,
|
|
26
|
+
DEFAULT_OPENCLAW_WATCHER_DEMOTION_TTL_DAYS
|
|
27
|
+
)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
WATCHER_DEMOTED_TAG,
|
|
33
|
+
resolveOpenClawWatcherDemotionConfig
|
|
34
|
+
};
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
recordEntrySupport,
|
|
30
30
|
resolveEmbeddingForText,
|
|
31
31
|
updateEntryForMerge
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-UNB2GHB2.js";
|
|
33
33
|
import {
|
|
34
34
|
applyEntryClassification,
|
|
35
35
|
inferProjectFromTags,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
createAppRuntime,
|
|
48
48
|
readAppDbSession,
|
|
49
49
|
resolveDefaultAppRuntimeDeps
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-YFOFO2FC.js";
|
|
51
51
|
import {
|
|
52
52
|
mapStoredEntry,
|
|
53
53
|
shapeRecallText
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
import {
|
|
66
66
|
createLogger,
|
|
67
67
|
walCheckpoint
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-HMBONTF3.js";
|
|
69
69
|
import {
|
|
70
70
|
DEFAULT_TASK_MODEL,
|
|
71
71
|
resolveClaimExtractionBatchSize,
|
|
@@ -219,11 +219,11 @@ async function runSimpleStream(params) {
|
|
|
219
219
|
continue;
|
|
220
220
|
}
|
|
221
221
|
if (event.type === "thinking_start") {
|
|
222
|
-
|
|
222
|
+
continue;
|
|
223
223
|
} else if (event.type === "thinking_delta") {
|
|
224
224
|
params.onStreamDelta?.(event.delta, "thinking");
|
|
225
225
|
} else if (event.type === "thinking_end") {
|
|
226
|
-
|
|
226
|
+
continue;
|
|
227
227
|
} else if (event.type === "text_delta") {
|
|
228
228
|
params.onStreamDelta?.(event.delta, "text");
|
|
229
229
|
} else if (event.type === "toolcall_delta") {
|
|
@@ -948,6 +948,37 @@ async function buildEntityRegistry(db) {
|
|
|
948
948
|
return buildEntityRegistryFromRows(rows);
|
|
949
949
|
}
|
|
950
950
|
|
|
951
|
+
// src/utils/expiry.ts
|
|
952
|
+
var EXPIRY_SET = new Set(EXPIRY_LEVELS);
|
|
953
|
+
var EXPIRY_PRIORITY = {
|
|
954
|
+
temporary: 0,
|
|
955
|
+
permanent: 1,
|
|
956
|
+
core: 2
|
|
957
|
+
};
|
|
958
|
+
function normalizeExpiry(value) {
|
|
959
|
+
if (typeof value !== "string") {
|
|
960
|
+
return void 0;
|
|
961
|
+
}
|
|
962
|
+
const normalized = value.trim().toLowerCase();
|
|
963
|
+
if (!normalized) {
|
|
964
|
+
return void 0;
|
|
965
|
+
}
|
|
966
|
+
return EXPIRY_SET.has(normalized) ? normalized : void 0;
|
|
967
|
+
}
|
|
968
|
+
function coerceExpiry(value, fallback = "temporary") {
|
|
969
|
+
return normalizeExpiry(value) ?? fallback;
|
|
970
|
+
}
|
|
971
|
+
function resolveHigherExpiry(a, b) {
|
|
972
|
+
return EXPIRY_PRIORITY[a] >= EXPIRY_PRIORITY[b] ? a : b;
|
|
973
|
+
}
|
|
974
|
+
function resolveHighestExpiry(expiries) {
|
|
975
|
+
let highest = "temporary";
|
|
976
|
+
for (const expiry of expiries) {
|
|
977
|
+
highest = resolveHigherExpiry(highest, expiry);
|
|
978
|
+
}
|
|
979
|
+
return highest;
|
|
980
|
+
}
|
|
981
|
+
|
|
951
982
|
// src/db/lockfile.ts
|
|
952
983
|
import fs from "fs";
|
|
953
984
|
import os from "os";
|
|
@@ -2301,37 +2332,6 @@ function evaluateConflictsForRejection(conflicts, newEntry, config) {
|
|
|
2301
2332
|
};
|
|
2302
2333
|
}
|
|
2303
2334
|
|
|
2304
|
-
// src/utils/expiry.ts
|
|
2305
|
-
var EXPIRY_SET = new Set(EXPIRY_LEVELS);
|
|
2306
|
-
var EXPIRY_PRIORITY = {
|
|
2307
|
-
temporary: 0,
|
|
2308
|
-
permanent: 1,
|
|
2309
|
-
core: 2
|
|
2310
|
-
};
|
|
2311
|
-
function normalizeExpiry(value) {
|
|
2312
|
-
if (typeof value !== "string") {
|
|
2313
|
-
return void 0;
|
|
2314
|
-
}
|
|
2315
|
-
const normalized = value.trim().toLowerCase();
|
|
2316
|
-
if (!normalized) {
|
|
2317
|
-
return void 0;
|
|
2318
|
-
}
|
|
2319
|
-
return EXPIRY_SET.has(normalized) ? normalized : void 0;
|
|
2320
|
-
}
|
|
2321
|
-
function coerceExpiry(value, fallback = "temporary") {
|
|
2322
|
-
return normalizeExpiry(value) ?? fallback;
|
|
2323
|
-
}
|
|
2324
|
-
function resolveHigherExpiry(a, b) {
|
|
2325
|
-
return EXPIRY_PRIORITY[a] >= EXPIRY_PRIORITY[b] ? a : b;
|
|
2326
|
-
}
|
|
2327
|
-
function resolveHighestExpiry(expiries) {
|
|
2328
|
-
let highest = "temporary";
|
|
2329
|
-
for (const expiry of expiries) {
|
|
2330
|
-
highest = resolveHigherExpiry(highest, expiry);
|
|
2331
|
-
}
|
|
2332
|
-
return highest;
|
|
2333
|
-
}
|
|
2334
|
-
|
|
2335
2335
|
// src/memory/store/mutations.ts
|
|
2336
2336
|
async function applyEntryMutation(repository, processed, embedFn, apiKey, cache, config, options) {
|
|
2337
2337
|
const mutation = processed.mutation;
|
|
@@ -5598,6 +5598,47 @@ async function finalizeRecallResults(params) {
|
|
|
5598
5598
|
return results;
|
|
5599
5599
|
}
|
|
5600
5600
|
|
|
5601
|
+
// src/domain/recall/browse-selection.ts
|
|
5602
|
+
var DEFAULT_BROWSE_DIVERSITY_TARGET = 4;
|
|
5603
|
+
function normalizeEntryType(result) {
|
|
5604
|
+
const rawType = result.entry.type;
|
|
5605
|
+
return typeof rawType === "string" ? rawType.trim().toLowerCase() : "";
|
|
5606
|
+
}
|
|
5607
|
+
function diversifyBrowseResults(results, limit, diversityTarget = DEFAULT_BROWSE_DIVERSITY_TARGET) {
|
|
5608
|
+
const normalizedLimit = Math.max(0, Math.floor(limit));
|
|
5609
|
+
if (normalizedLimit === 0 || results.length === 0) {
|
|
5610
|
+
return [];
|
|
5611
|
+
}
|
|
5612
|
+
const normalizedDiversityTarget = Math.max(0, Math.floor(diversityTarget));
|
|
5613
|
+
const seedTarget = Math.min(normalizedLimit, normalizedDiversityTarget);
|
|
5614
|
+
const selected = [];
|
|
5615
|
+
const selectedIds = /* @__PURE__ */ new Set();
|
|
5616
|
+
const admittedTypes = /* @__PURE__ */ new Set();
|
|
5617
|
+
for (const result of results) {
|
|
5618
|
+
if (selected.length >= seedTarget) {
|
|
5619
|
+
break;
|
|
5620
|
+
}
|
|
5621
|
+
const normalizedType = normalizeEntryType(result);
|
|
5622
|
+
if (!normalizedType || admittedTypes.has(normalizedType)) {
|
|
5623
|
+
continue;
|
|
5624
|
+
}
|
|
5625
|
+
selected.push(result);
|
|
5626
|
+
selectedIds.add(result.entry.id);
|
|
5627
|
+
admittedTypes.add(normalizedType);
|
|
5628
|
+
}
|
|
5629
|
+
for (const result of results) {
|
|
5630
|
+
if (selected.length >= normalizedLimit) {
|
|
5631
|
+
break;
|
|
5632
|
+
}
|
|
5633
|
+
if (selectedIds.has(result.entry.id)) {
|
|
5634
|
+
continue;
|
|
5635
|
+
}
|
|
5636
|
+
selected.push(result);
|
|
5637
|
+
selectedIds.add(result.entry.id);
|
|
5638
|
+
}
|
|
5639
|
+
return selected;
|
|
5640
|
+
}
|
|
5641
|
+
|
|
5601
5642
|
// src/domain/recall/lexical.ts
|
|
5602
5643
|
var STOP_TOKENS = /* @__PURE__ */ new Set([
|
|
5603
5644
|
"a",
|
|
@@ -5754,6 +5795,8 @@ var DEFAULT_RECALL_SATURATION = 10;
|
|
|
5754
5795
|
var DEFAULT_WARM_START_THRESHOLD = 3;
|
|
5755
5796
|
var DEFAULT_SYNTHETIC_FLOOR = 0.1;
|
|
5756
5797
|
var DEFAULT_AGENT_SOURCE_BONUS = 0.05;
|
|
5798
|
+
var BROWSE_RECENCY_WEIGHT = 0.8;
|
|
5799
|
+
var BROWSE_IMPORTANCE_WEIGHT = 0.2;
|
|
5757
5800
|
var MISSING_RECALL_DAYS = 99999;
|
|
5758
5801
|
var EMPTY_RECALL_METRICS = {
|
|
5759
5802
|
totalCount: 0,
|
|
@@ -5878,7 +5921,9 @@ function browseRecencyFactor(entry, now, aroundDate, aroundRadius = DEFAULT_AROU
|
|
|
5878
5921
|
return resolveRecallRecency(entry, now, aroundDate, aroundRadius);
|
|
5879
5922
|
}
|
|
5880
5923
|
function scoreBrowseEntry(entry, now, aroundDate, aroundRadius = DEFAULT_AROUND_RADIUS_DAYS) {
|
|
5881
|
-
|
|
5924
|
+
const recency2 = browseRecencyFactor(entry, now, aroundDate, aroundRadius);
|
|
5925
|
+
const importance = importanceScore(entry.importance);
|
|
5926
|
+
return clamp01(recency2 * BROWSE_RECENCY_WEIGHT + importance * BROWSE_IMPORTANCE_WEIGHT);
|
|
5882
5927
|
}
|
|
5883
5928
|
function scoreSessionEntry(entry, effectiveNow, freshnessNow, metricsMap, aroundDate, aroundRadius = DEFAULT_AROUND_RADIUS_DAYS, config) {
|
|
5884
5929
|
return scoreEntryWithBreakdown(
|
|
@@ -6261,8 +6306,21 @@ async function fetchBrowseCandidates(params) {
|
|
|
6261
6306
|
whereClauses.push("platform = ?");
|
|
6262
6307
|
args.push(params.query.platform);
|
|
6263
6308
|
}
|
|
6264
|
-
args.push(params.limit);
|
|
6265
6309
|
const whereClause = whereClauses.length > 0 ? "WHERE " + whereClauses.join(" AND ") : "";
|
|
6310
|
+
const orderBy = params.aroundDate ? `
|
|
6311
|
+
ORDER BY
|
|
6312
|
+
ABS(julianday(created_at) - julianday(?)) ASC,
|
|
6313
|
+
importance DESC,
|
|
6314
|
+
created_at DESC
|
|
6315
|
+
` : `
|
|
6316
|
+
ORDER BY
|
|
6317
|
+
created_at DESC,
|
|
6318
|
+
importance DESC
|
|
6319
|
+
`;
|
|
6320
|
+
if (params.aroundDate) {
|
|
6321
|
+
args.push(params.aroundDate.toISOString());
|
|
6322
|
+
}
|
|
6323
|
+
args.push(params.limit);
|
|
6266
6324
|
const result = await params.db.execute({
|
|
6267
6325
|
sql: `
|
|
6268
6326
|
SELECT
|
|
@@ -6270,10 +6328,10 @@ async function fetchBrowseCandidates(params) {
|
|
|
6270
6328
|
FROM entries
|
|
6271
6329
|
${whereClause}
|
|
6272
6330
|
-- SQL pre-sort is a best-effort approximation only.
|
|
6273
|
-
-- Final order is determined by
|
|
6274
|
-
--
|
|
6331
|
+
-- Final order is determined by recency-first browse scoring and a post-score
|
|
6332
|
+
-- diversity pass. The over-fetch buffer (limit*3, min 50)
|
|
6275
6333
|
-- ensures the final top-N are present in the candidate pool.
|
|
6276
|
-
|
|
6334
|
+
${orderBy}
|
|
6277
6335
|
LIMIT ?
|
|
6278
6336
|
`,
|
|
6279
6337
|
args
|
|
@@ -6499,6 +6557,7 @@ async function recallBrowseMode(params) {
|
|
|
6499
6557
|
query: browseQuery,
|
|
6500
6558
|
limit: browseLimit,
|
|
6501
6559
|
now: params.now,
|
|
6560
|
+
aroundDate: params.prepared.temporal.aroundDate,
|
|
6502
6561
|
projectFilter: params.prepared.scope.resolution.primaryFilter
|
|
6503
6562
|
});
|
|
6504
6563
|
const filtered = browseCandidates.filter(
|
|
@@ -6519,7 +6578,11 @@ async function recallBrowseMode(params) {
|
|
|
6519
6578
|
aroundRadiusDays: params.prepared.temporal.aroundRadiusDays
|
|
6520
6579
|
});
|
|
6521
6580
|
scored.sort((left, right) => right.score - left.score);
|
|
6522
|
-
|
|
6581
|
+
const results = diversifyBrowseResults(scored, requestedLimit, DEFAULT_BROWSE_DIVERSITY_TARGET);
|
|
6582
|
+
if (params.trace) {
|
|
6583
|
+
params.trace.finalResultIds = results.map((result) => result.entry.subject ?? result.entry.id);
|
|
6584
|
+
}
|
|
6585
|
+
return results;
|
|
6523
6586
|
}
|
|
6524
6587
|
async function retrieveCandidates(params) {
|
|
6525
6588
|
if (!params.prepared.retrievalSearchText) {
|
|
@@ -6924,11 +6987,12 @@ function resolvePreparedRecallScope(query, normalizedQuery) {
|
|
|
6924
6987
|
const explicitWildcardProject = hasWildcardProjectOverride(query.project);
|
|
6925
6988
|
const explicitProjects = explicitWildcardProject ? [] : parseProjectList(query.project);
|
|
6926
6989
|
const explicitExcludedProjects = parseProjectList(query.excludeProject);
|
|
6927
|
-
const inferredProjectHints = deriveRecallProjectScopeHints({
|
|
6990
|
+
const inferredProjectHints = explicitWildcardProject ? [] : deriveRecallProjectScopeHints({
|
|
6928
6991
|
queryText: normalizedQuery?.searchText ?? query.text ?? "",
|
|
6929
6992
|
explicitProjects
|
|
6930
6993
|
});
|
|
6931
|
-
const
|
|
6994
|
+
const callerProjectHints = explicitProjects.length > 0 || explicitWildcardProject ? [] : parseProjectList(query.projectHints).filter((projectHint) => projectHint !== "*");
|
|
6995
|
+
const projectHints = explicitProjects.length > 0 ? explicitProjects : Array.from(/* @__PURE__ */ new Set([...inferredProjectHints, ...callerProjectHints]));
|
|
6932
6996
|
const intent = projectHints.length > 0 ? "project" : normalizedQuery?.scopeIntent ?? "ambiguous";
|
|
6933
6997
|
if (query.universalOnly === true) {
|
|
6934
6998
|
return {
|