@remnic/core 9.63.1 → 9.63.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/dist/access-admin-ops-surface.js +33 -32
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.js +34 -33
- package/dist/access-boundary.js +33 -32
- package/dist/access-cli.js +97 -95
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +33 -32
- package/dist/access-http-query.js +33 -32
- package/dist/access-http.js +46 -45
- package/dist/access-identity-continuity-surface.js +33 -32
- package/dist/access-lcm-surface.js +33 -32
- package/dist/access-mcp.js +39 -38
- package/dist/access-namespace-preflight.js +33 -32
- package/dist/access-observe-write-surface.js +33 -32
- package/dist/access-operations-batch.js +34 -33
- package/dist/access-operations.js +38 -37
- package/dist/access-recall-concurrency.js +33 -32
- package/dist/access-recall-response.js +33 -32
- package/dist/access-recall-surface.js +33 -32
- package/dist/access-schema.js +3 -3
- package/dist/access-service.js +33 -32
- package/dist/access-surface-catalog.js +35 -34
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-Z52VWMNC.js → auto-sync-BKRJDMKX.js} +3 -3
- package/dist/behavior-learner.js +2 -2
- package/dist/briefing.js +14 -14
- package/dist/buffer.js +4 -3
- package/dist/causal-behavior.js +3 -3
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.js +17 -17
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory.js +2 -2
- package/dist/{chunk-5F6HMNMZ.js → chunk-2LA3H54D.js} +2 -2
- package/dist/{chunk-IRLH4NM2.js → chunk-2PSX5BJU.js} +3 -3
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/{chunk-F2FZEVDE.js → chunk-3LJ2L3T3.js} +2 -2
- package/dist/{chunk-RBBYKXXK.js → chunk-44KHFMCM.js} +64 -62
- package/dist/{chunk-RBBYKXXK.js.map → chunk-44KHFMCM.js.map} +1 -1
- package/dist/{chunk-AUIAHNO7.js → chunk-4NMVX5U7.js} +2 -2
- package/dist/{chunk-ANMIOQPU.js → chunk-4XN35YQD.js} +478 -164
- package/dist/chunk-4XN35YQD.js.map +1 -0
- package/dist/{chunk-LJOIZPJH.js → chunk-5QZR2RA3.js} +2 -2
- package/dist/{chunk-RBJKE5LV.js → chunk-5UFQCU6M.js} +32 -32
- package/dist/{chunk-S52C2DEM.js → chunk-5W5N7XJZ.js} +2 -2
- package/dist/{chunk-GL4RHVHX.js → chunk-5W62VEFH.js} +4 -4
- package/dist/{chunk-DEOYTFA6.js → chunk-645WOU5I.js} +4 -52
- package/dist/chunk-645WOU5I.js.map +1 -0
- package/dist/{chunk-4WW5FMUD.js → chunk-6D7PZKCJ.js} +9 -9
- package/dist/{chunk-NVSTZ2PN.js → chunk-6F2UMP4H.js} +7 -7
- package/dist/{chunk-IIPJKCZB.js → chunk-6NAPOLRO.js} +3 -3
- package/dist/{chunk-U4CCRHN6.js → chunk-6UZR7KEK.js} +2 -2
- package/dist/{chunk-2TYIAKU5.js → chunk-6YMEU6OQ.js} +2 -2
- package/dist/{chunk-LAX6S5WS.js → chunk-A73QHOZP.js} +2 -2
- package/dist/{chunk-ZSH6GJ2V.js → chunk-AJSZ2EK6.js} +3 -3
- package/dist/{chunk-GUBT77YC.js → chunk-B2OOJCUX.js} +2 -2
- package/dist/chunk-BUYVPUEM.js +66 -0
- package/dist/chunk-BUYVPUEM.js.map +1 -0
- package/dist/{chunk-YTHQHH5U.js → chunk-C6WMSXCJ.js} +2 -2
- package/dist/{chunk-JKW663ZN.js → chunk-CIAI24TQ.js} +2 -2
- package/dist/{chunk-PD6O7AXF.js → chunk-CSAKJVXW.js} +14 -17
- package/dist/chunk-CSAKJVXW.js.map +1 -0
- package/dist/{chunk-ALKRPLWB.js → chunk-DNRTKO2U.js} +2 -2
- package/dist/{chunk-J5AFG5JN.js → chunk-EJLTNPRY.js} +3 -3
- package/dist/{chunk-ORB56L3Y.js → chunk-EJQXDKYK.js} +4 -4
- package/dist/{chunk-UM7A4CPT.js → chunk-FKJVEW6O.js} +2 -2
- package/dist/{chunk-ZXMNT75M.js → chunk-GFNS3BHV.js} +3 -3
- package/dist/{chunk-ALNZEWGN.js → chunk-GPFZFCRN.js} +2 -2
- package/dist/{chunk-MQFFR6QB.js → chunk-GTRGH4ZT.js} +2 -2
- package/dist/{chunk-USKANB65.js → chunk-I6OQCT3Y.js} +2 -2
- package/dist/{chunk-2AZBPQLK.js → chunk-IKXUG6KC.js} +7 -7
- package/dist/{chunk-5LVSFKQB.js → chunk-IM56VPKO.js} +3 -3
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-R7R4FSV2.js → chunk-ITYAXU4S.js} +3 -3
- package/dist/{chunk-7CJO52ET.js → chunk-JJ7JW62R.js} +23 -23
- package/dist/{chunk-5S7Y7AC6.js → chunk-JJX5XEIG.js} +2 -2
- package/dist/{chunk-OF6KQJ35.js → chunk-JWPG65LH.js} +14 -14
- package/dist/chunk-K2XUWZBM.js +417 -0
- package/dist/chunk-K2XUWZBM.js.map +1 -0
- package/dist/{chunk-G2FCSILA.js → chunk-KWIGDKM2.js} +2 -2
- package/dist/{chunk-UKBIB3FP.js → chunk-KWN6NOHQ.js} +2 -2
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-SHSJP4D6.js → chunk-LZCSOUJ7.js} +2 -2
- package/dist/{chunk-256FBCVX.js → chunk-M4AHBM72.js} +7 -7
- package/dist/{chunk-5PFGMO33.js → chunk-MEW53VQJ.js} +2 -2
- package/dist/{chunk-DCUMFQYM.js → chunk-ML3U4KPR.js} +2 -2
- package/dist/{chunk-UDL4DNBM.js → chunk-MR5HWQHS.js} +2 -2
- package/dist/{chunk-H7PRHUBD.js → chunk-NRLELHAY.js} +2 -2
- package/dist/{chunk-ZS4JADYY.js → chunk-OW7NVMGQ.js} +2 -2
- package/dist/{chunk-U5LYM2NS.js → chunk-PADG72LJ.js} +3 -3
- package/dist/{chunk-6GGTATZF.js → chunk-PYIR4SSB.js} +4 -4
- package/dist/chunk-PYIR4SSB.js.map +1 -0
- package/dist/{chunk-UW74LP76.js → chunk-Q35XGIEM.js} +2 -2
- package/dist/{chunk-XPRJSHNI.js → chunk-QJ622LTI.js} +6 -3
- package/dist/chunk-QJ622LTI.js.map +1 -0
- package/dist/{chunk-FNYIMSKI.js → chunk-QSIQVC32.js} +2 -2
- package/dist/{chunk-EJYAE2U7.js → chunk-R74NCKEY.js} +4 -4
- package/dist/{chunk-KP36WQBJ.js → chunk-RYGJGXL6.js} +2 -2
- package/dist/{chunk-4OW2T32G.js → chunk-SQ3EGGII.js} +2 -2
- package/dist/{chunk-FU7OICXE.js → chunk-TRPX6F2G.js} +10 -10
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-6VX2ZZH2.js → chunk-VAMQU4W7.js} +2 -2
- package/dist/{chunk-WLITCQAC.js → chunk-VN7IIQGS.js} +2 -2
- package/dist/{chunk-MMM7SDOJ.js → chunk-WDUG2CH3.js} +2 -2
- package/dist/{chunk-P2BT5ALE.js → chunk-X4MGNVOO.js} +2 -2
- package/dist/{chunk-BE5SVRFC.js → chunk-XFCQIQQU.js} +3 -3
- package/dist/{chunk-S4MF77NV.js → chunk-XZPSBGHA.js} +2 -2
- package/dist/{chunk-PMRUMGK6.js → chunk-Y7COCXY2.js} +2 -2
- package/dist/{chunk-DJ7HMNSL.js → chunk-YCVB7X56.js} +4 -2
- package/dist/chunk-YCVB7X56.js.map +1 -0
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-A5BYPCDI.js → chunk-Z334TJRB.js} +2 -2
- package/dist/cli.js +67 -66
- package/dist/coding/pre-action-gate.js +3 -3
- package/dist/compounding/engine.js +14 -14
- package/dist/connectors/codex-materialize-runner.js +14 -14
- package/dist/connectors/index.d.ts +45 -1
- package/dist/connectors/index.js +23 -15
- package/dist/convergence-refresh.js +16 -16
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +16 -16
- package/dist/dashboard-runtime.js +2 -2
- package/dist/direct-answer-wiring.js +3 -3
- package/dist/direct-answer.js +2 -2
- package/dist/entity-retrieval.js +14 -14
- package/dist/event-order-query.d.ts +3 -0
- package/dist/event-order-query.js +9 -0
- package/dist/event-order-query.js.map +1 -0
- package/dist/event-order-recall.d.ts +2 -2
- package/dist/event-order-recall.js +5 -2
- package/dist/external-wiki-access.js +34 -33
- package/dist/extraction-normalization.js +2 -2
- package/dist/extraction.js +23 -22
- package/dist/harmonic-construction.js +2 -2
- package/dist/harmonic-retrieval.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +106 -103
- package/dist/intent.js +2 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +6 -6
- package/dist/maintenance/memory-governance.js +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/namespaces/migrate.js +15 -15
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.js +14 -14
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-toolkit.js +21 -21
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/orchestrator.js +99 -97
- package/dist/policy-runtime.js +3 -3
- package/dist/recall-planner-i18n.d.ts +31 -0
- package/dist/recall-planner-i18n.js +30 -0
- package/dist/recall-planner-i18n.js.map +1 -0
- package/dist/recall-planner-llm.js +2 -1
- package/dist/recall-planner-llm.js.map +1 -1
- package/dist/recall-query-policy.js +2 -2
- package/dist/recall-tokenization.js +1 -1
- package/dist/resume-bundles.js +3 -3
- package/dist/retrieval-agents.js +2 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.js +14 -14
- package/dist/search/orama-backend.js +2 -2
- package/dist/semantic-consolidation.js +15 -15
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/source-agent-qualifier.js +20 -19
- package/dist/storage.js +13 -13
- package/dist/support-passport/index.js +36 -35
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/trust-zones.js +2 -2
- package/dist/verified-recall.js +14 -14
- package/dist/work-product-ledger.js +2 -2
- package/package.json +2 -2
- package/src/connectors/droid-mcp.ts +434 -0
- package/src/connectors/index.ts +70 -0
- package/src/direct-answer.ts +6 -3
- package/src/event-order-query.ts +78 -0
- package/src/event-order-recall.ts +4 -90
- package/src/intent.ts +19 -19
- package/src/recall-planner-i18n.ts +193 -0
- package/src/recall-tokenization.ts +3 -1
- package/src/retrieval-agents.ts +6 -10
- package/dist/chunk-6GGTATZF.js.map +0 -1
- package/dist/chunk-ANMIOQPU.js.map +0 -1
- package/dist/chunk-DEOYTFA6.js.map +0 -1
- package/dist/chunk-DJ7HMNSL.js.map +0 -1
- package/dist/chunk-PD6O7AXF.js.map +0 -1
- package/dist/chunk-XPRJSHNI.js.map +0 -1
- /package/dist/{auto-sync-Z52VWMNC.js.map → auto-sync-BKRJDMKX.js.map} +0 -0
- /package/dist/{chunk-5F6HMNMZ.js.map → chunk-2LA3H54D.js.map} +0 -0
- /package/dist/{chunk-IRLH4NM2.js.map → chunk-2PSX5BJU.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-F2FZEVDE.js.map → chunk-3LJ2L3T3.js.map} +0 -0
- /package/dist/{chunk-AUIAHNO7.js.map → chunk-4NMVX5U7.js.map} +0 -0
- /package/dist/{chunk-LJOIZPJH.js.map → chunk-5QZR2RA3.js.map} +0 -0
- /package/dist/{chunk-RBJKE5LV.js.map → chunk-5UFQCU6M.js.map} +0 -0
- /package/dist/{chunk-S52C2DEM.js.map → chunk-5W5N7XJZ.js.map} +0 -0
- /package/dist/{chunk-GL4RHVHX.js.map → chunk-5W62VEFH.js.map} +0 -0
- /package/dist/{chunk-4WW5FMUD.js.map → chunk-6D7PZKCJ.js.map} +0 -0
- /package/dist/{chunk-NVSTZ2PN.js.map → chunk-6F2UMP4H.js.map} +0 -0
- /package/dist/{chunk-IIPJKCZB.js.map → chunk-6NAPOLRO.js.map} +0 -0
- /package/dist/{chunk-U4CCRHN6.js.map → chunk-6UZR7KEK.js.map} +0 -0
- /package/dist/{chunk-2TYIAKU5.js.map → chunk-6YMEU6OQ.js.map} +0 -0
- /package/dist/{chunk-LAX6S5WS.js.map → chunk-A73QHOZP.js.map} +0 -0
- /package/dist/{chunk-ZSH6GJ2V.js.map → chunk-AJSZ2EK6.js.map} +0 -0
- /package/dist/{chunk-GUBT77YC.js.map → chunk-B2OOJCUX.js.map} +0 -0
- /package/dist/{chunk-YTHQHH5U.js.map → chunk-C6WMSXCJ.js.map} +0 -0
- /package/dist/{chunk-JKW663ZN.js.map → chunk-CIAI24TQ.js.map} +0 -0
- /package/dist/{chunk-ALKRPLWB.js.map → chunk-DNRTKO2U.js.map} +0 -0
- /package/dist/{chunk-J5AFG5JN.js.map → chunk-EJLTNPRY.js.map} +0 -0
- /package/dist/{chunk-ORB56L3Y.js.map → chunk-EJQXDKYK.js.map} +0 -0
- /package/dist/{chunk-UM7A4CPT.js.map → chunk-FKJVEW6O.js.map} +0 -0
- /package/dist/{chunk-ZXMNT75M.js.map → chunk-GFNS3BHV.js.map} +0 -0
- /package/dist/{chunk-ALNZEWGN.js.map → chunk-GPFZFCRN.js.map} +0 -0
- /package/dist/{chunk-MQFFR6QB.js.map → chunk-GTRGH4ZT.js.map} +0 -0
- /package/dist/{chunk-USKANB65.js.map → chunk-I6OQCT3Y.js.map} +0 -0
- /package/dist/{chunk-2AZBPQLK.js.map → chunk-IKXUG6KC.js.map} +0 -0
- /package/dist/{chunk-5LVSFKQB.js.map → chunk-IM56VPKO.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-R7R4FSV2.js.map → chunk-ITYAXU4S.js.map} +0 -0
- /package/dist/{chunk-7CJO52ET.js.map → chunk-JJ7JW62R.js.map} +0 -0
- /package/dist/{chunk-5S7Y7AC6.js.map → chunk-JJX5XEIG.js.map} +0 -0
- /package/dist/{chunk-OF6KQJ35.js.map → chunk-JWPG65LH.js.map} +0 -0
- /package/dist/{chunk-G2FCSILA.js.map → chunk-KWIGDKM2.js.map} +0 -0
- /package/dist/{chunk-UKBIB3FP.js.map → chunk-KWN6NOHQ.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-SHSJP4D6.js.map → chunk-LZCSOUJ7.js.map} +0 -0
- /package/dist/{chunk-256FBCVX.js.map → chunk-M4AHBM72.js.map} +0 -0
- /package/dist/{chunk-5PFGMO33.js.map → chunk-MEW53VQJ.js.map} +0 -0
- /package/dist/{chunk-DCUMFQYM.js.map → chunk-ML3U4KPR.js.map} +0 -0
- /package/dist/{chunk-UDL4DNBM.js.map → chunk-MR5HWQHS.js.map} +0 -0
- /package/dist/{chunk-H7PRHUBD.js.map → chunk-NRLELHAY.js.map} +0 -0
- /package/dist/{chunk-ZS4JADYY.js.map → chunk-OW7NVMGQ.js.map} +0 -0
- /package/dist/{chunk-U5LYM2NS.js.map → chunk-PADG72LJ.js.map} +0 -0
- /package/dist/{chunk-UW74LP76.js.map → chunk-Q35XGIEM.js.map} +0 -0
- /package/dist/{chunk-FNYIMSKI.js.map → chunk-QSIQVC32.js.map} +0 -0
- /package/dist/{chunk-EJYAE2U7.js.map → chunk-R74NCKEY.js.map} +0 -0
- /package/dist/{chunk-KP36WQBJ.js.map → chunk-RYGJGXL6.js.map} +0 -0
- /package/dist/{chunk-4OW2T32G.js.map → chunk-SQ3EGGII.js.map} +0 -0
- /package/dist/{chunk-FU7OICXE.js.map → chunk-TRPX6F2G.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-6VX2ZZH2.js.map → chunk-VAMQU4W7.js.map} +0 -0
- /package/dist/{chunk-WLITCQAC.js.map → chunk-VN7IIQGS.js.map} +0 -0
- /package/dist/{chunk-MMM7SDOJ.js.map → chunk-WDUG2CH3.js.map} +0 -0
- /package/dist/{chunk-P2BT5ALE.js.map → chunk-X4MGNVOO.js.map} +0 -0
- /package/dist/{chunk-BE5SVRFC.js.map → chunk-XFCQIQQU.js.map} +0 -0
- /package/dist/{chunk-S4MF77NV.js.map → chunk-XZPSBGHA.js.map} +0 -0
- /package/dist/{chunk-PMRUMGK6.js.map → chunk-Y7COCXY2.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-A5BYPCDI.js.map → chunk-Z334TJRB.js.map} +0 -0
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
type RankedEvidenceItem,
|
|
8
8
|
} from "./recall-pipeline-stages.js";
|
|
9
9
|
|
|
10
|
+
import { shouldRecallEventOrderEvidence } from "./event-order-query.js";
|
|
11
|
+
export { shouldRecallEventOrderEvidence };
|
|
12
|
+
|
|
13
|
+
|
|
10
14
|
export interface EventOrderRecallOptions {
|
|
11
15
|
engine: ExplicitCueRecallEngine | null | undefined;
|
|
12
16
|
// event-order reads a SINGLE LCM session key. Unlike the relevance-ranked
|
|
@@ -28,87 +32,6 @@ const DEFAULT_SCAN_WINDOW_TURNS = 12;
|
|
|
28
32
|
const DEFAULT_SCAN_WINDOW_TOKENS = 24_000;
|
|
29
33
|
const DEFAULT_MAX_ITEMS = 24;
|
|
30
34
|
|
|
31
|
-
export function shouldRecallEventOrderEvidence(query: string): boolean {
|
|
32
|
-
const normalized = query.toLowerCase();
|
|
33
|
-
|
|
34
|
-
// --- Existing event-order patterns (LongMemEval order-reconstruction phrasing) ---
|
|
35
|
-
if (
|
|
36
|
-
/\border in which\b/.test(normalized) ||
|
|
37
|
-
/\bsequence in which\b/.test(normalized) ||
|
|
38
|
-
/\breconstruct\b.*\btimeline\b/.test(normalized) ||
|
|
39
|
-
/\btimeline\b.*\bin order\b/.test(normalized) ||
|
|
40
|
-
/\bsequence\b.*\bin order\b/.test(normalized) ||
|
|
41
|
-
/\bintroduced\b.*\bin order\b/.test(normalized) ||
|
|
42
|
-
(/\bwalk me through\b/.test(normalized) && /\bin order\b/.test(normalized)) ||
|
|
43
|
-
(/\bin order\b/.test(normalized) &&
|
|
44
|
-
/\b(?:develop(?:ed|ment)?|evolv(?:e|ed|ing)?|progress|throughout|conversations?|sessions?)\b/.test(normalized)) ||
|
|
45
|
-
/\bprogress\b.*\bin order\b/.test(normalized) ||
|
|
46
|
-
/\bchronological(?:ly| order)?\b/.test(normalized) ||
|
|
47
|
-
isTimelineSummaryQuery(normalized)
|
|
48
|
-
) {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// --- Temporal-reasoning patterns (LongMemEval temporal-reasoning question type) ---
|
|
53
|
-
// These question shapes need chronological evidence to answer correctly:
|
|
54
|
-
// ordering ("which happened first"), relative time ("how many days
|
|
55
|
-
// between"), and recency ("which did I [verb] last"). The event-order tier
|
|
56
|
-
// surfaces a chronologically sorted evidence pack so the responder can
|
|
57
|
-
// reconstruct the answer from an ordered timeline rather than fragments.
|
|
58
|
-
// Verified against the LongMemEval-oracle dataset: 0% of the 133
|
|
59
|
-
// temporal-reasoning questions matched the original heuristic above.
|
|
60
|
-
|
|
61
|
-
// "Which X did I Y first, A or B?" / "What was the first X ...?"
|
|
62
|
-
if (/\bwhich\b.*\bfirst\b/.test(normalized) || /\bwhat was the first\b/.test(normalized)) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
// "Which event happened first, A or B?" / "Which happened first"
|
|
66
|
-
if (/\bhappened first\b/.test(normalized) || /\bwhich\b.*\bhappened\b/.test(normalized)) {
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
// "How many days before/between/after/did it take"
|
|
70
|
-
if (/\bhow many days\b/.test(normalized)) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
// "When did I ..." (date-shaped)
|
|
74
|
-
if (/\bwhen did\b/.test(normalized)) {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
// "Which X did I Y last?" / "the last X I ..."
|
|
78
|
-
if (/\bwhich\b.*\blast\b/.test(normalized) || /\bthe last\b.*\bi\b/.test(normalized)) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
// "Who did I meet/become first, X or Y?" (person ordering)
|
|
82
|
-
if (/\bwho\b.*\bfirst\b/.test(normalized)) {
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
// "most recently" / "most recent" (recency)
|
|
86
|
-
if (/\bmost recent(?:ly)?\b/.test(normalized)) {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
// "What is the order of..." / "...from earliest to latest"
|
|
90
|
-
if (/\border of\b/.test(normalized) || /\bfrom earliest to latest\b/.test(normalized)) {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// "How long have/did/had I been..." (duration)
|
|
95
|
-
if (/\bhow long\b/.test(normalized)) {
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
// "How many months/weeks/years ago/before" (relative time)
|
|
99
|
-
if (/\bhow many (months|weeks|years)\b/.test(normalized)) {
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
// "How many X did I [verb] before Y" (temporal comparison)
|
|
103
|
-
if (/\bhow many\b.*\bbefore\b/.test(normalized)) {
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
// "How old was I when..." (age-at-time)
|
|
107
|
-
if (/\bhow old\b.*\bwhen\b/.test(normalized)) {
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
35
|
|
|
113
36
|
export async function buildEventOrderRecallSection(
|
|
114
37
|
options: EventOrderRecallOptions,
|
|
@@ -1693,15 +1616,6 @@ function deriveChronologicalCueLabels(content: string, query: string): string[]
|
|
|
1693
1616
|
return [...labels].slice(0, 5);
|
|
1694
1617
|
}
|
|
1695
1618
|
|
|
1696
|
-
function isTimelineSummaryQuery(normalized: string): boolean {
|
|
1697
|
-
return /\b(?:summarize|summary|major progress|what happened|develop(?:ed|ment)?|approached)\b/.test(
|
|
1698
|
-
normalized,
|
|
1699
|
-
) &&
|
|
1700
|
-
(/\b(?:over time|throughout|between|project|progress|timeline|journey|sessions?|along the way)\b/.test(
|
|
1701
|
-
normalized,
|
|
1702
|
-
) ||
|
|
1703
|
-
/\bfrom\b.+\bthrough\b/.test(normalized));
|
|
1704
|
-
}
|
|
1705
1619
|
|
|
1706
1620
|
function addLabelIf(
|
|
1707
1621
|
labels: Set<string>,
|
package/src/intent.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CAUSAL_CHAIN_CUES,
|
|
3
|
+
GRAPH_MODE_CUES,
|
|
4
|
+
containsRecallCue,
|
|
5
|
+
endsWithQuestionMark,
|
|
6
|
+
isMultilingualAck,
|
|
7
|
+
stripTrailingRecallNoise,
|
|
8
|
+
} from "./recall-planner-i18n.js";
|
|
1
9
|
import type { MemoryIntent, RecallPlanMode } from "./types.js";
|
|
2
10
|
|
|
3
11
|
const GOAL_PATTERNS: Array<{ re: RegExp; goal: string }> = [
|
|
@@ -100,35 +108,26 @@ export function intentCompatibilityScore(queryIntent: MemoryIntent, memoryIntent
|
|
|
100
108
|
|
|
101
109
|
export function planRecallMode(prompt: string): RecallPlanMode {
|
|
102
110
|
const p = normalizeTextInput(prompt).trim();
|
|
103
|
-
let ackCandidate = p;
|
|
104
|
-
while (ackCandidate.length > 0) {
|
|
105
|
-
const ch = ackCandidate.charCodeAt(ackCandidate.length - 1);
|
|
106
|
-
const isDigit = ch >= 48 && ch <= 57;
|
|
107
|
-
const isUpper = ch >= 65 && ch <= 90;
|
|
108
|
-
const isLower = ch >= 97 && ch <= 122;
|
|
109
|
-
// Strip any trailing non-alphanumeric noise (punctuation/emojis/symbols).
|
|
110
|
-
if (isDigit || isUpper || isLower) break;
|
|
111
|
-
ackCandidate = ackCandidate.slice(0, -1);
|
|
112
|
-
}
|
|
113
|
-
ackCandidate = ackCandidate.trim();
|
|
114
111
|
if (p.length === 0) return "no_recall";
|
|
115
112
|
|
|
116
|
-
if (
|
|
113
|
+
if (
|
|
114
|
+
/\b(timeline|sequence|history|what happened|chain of events|root cause)\b/i.test(p) ||
|
|
115
|
+
containsRecallCue(p, GRAPH_MODE_CUES)
|
|
116
|
+
) {
|
|
117
117
|
return "graph_mode";
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// Reserve no_recall for low-information acknowledgements; avoid broad regressions.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
) {
|
|
121
|
+
// Multilingual table (issue #2191): Japanese/Chinese/Korean/Russian/etc acks
|
|
122
|
+
// route the same way; the exact-match set cannot match longer English prompts.
|
|
123
|
+
if (p.length <= 18 && isMultilingualAck(stripTrailingRecallNoise(p))) {
|
|
125
124
|
return "no_recall";
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
// Full recall for prompts that are explicitly memory-seeking or analytical questions.
|
|
129
128
|
if (
|
|
130
129
|
/\b(previous|earlier|remember|last time|did we|what did we decide|context|summarize|summary|recap|key points|decision)\b/i.test(p) ||
|
|
131
|
-
|
|
130
|
+
endsWithQuestionMark(p) ||
|
|
132
131
|
/^(what|why|how|when|where|who|which)\b/i.test(p.toLowerCase())
|
|
133
132
|
) {
|
|
134
133
|
return "full";
|
|
@@ -148,7 +147,8 @@ export function planRecallMode(prompt: string): RecallPlanMode {
|
|
|
148
147
|
export function hasBroadGraphIntent(prompt: string): boolean {
|
|
149
148
|
const p = normalizeTextInput(prompt).trim().toLowerCase();
|
|
150
149
|
if (!p) return false;
|
|
151
|
-
return
|
|
152
|
-
p
|
|
150
|
+
return (
|
|
151
|
+
/\b(what changed|how did we get here|why did this happen|what led to|cause chain|dependency chain|regression chain|failure chain)\b/i.test(p) ||
|
|
152
|
+
containsRecallCue(p, CAUSAL_CHAIN_CUES)
|
|
153
153
|
);
|
|
154
154
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-script closed-class cue tables and script-agnostic signal helpers
|
|
3
|
+
* shared by the recall planner heuristics (issue #2191).
|
|
4
|
+
*
|
|
5
|
+
* English keyword regexes stay in their consumers. These tables seed the
|
|
6
|
+
* top ~10 languages so non-English prompts route to the same recall modes
|
|
7
|
+
* as their English equivalents. Substring cues are curated so pure-ASCII
|
|
8
|
+
* entries are multi-word phrases (or non-English single words) that cannot
|
|
9
|
+
* occur in English text — the English corpus behavior is unchanged.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const ASCII_CHARS = /[\u0000-\u007f]/g;
|
|
13
|
+
const LETTER_RE = /\p{L}/u;
|
|
14
|
+
const WORDISH_RE = /[\p{L}\p{N}]/u;
|
|
15
|
+
const QUESTION_MARK_END_RE = /[??؟]$/u;
|
|
16
|
+
const COLON_TERMINATED_RE = /[::]\s*$/u;
|
|
17
|
+
|
|
18
|
+
/** True when the text contains a letter outside ASCII — the English keyword
|
|
19
|
+
* tables cannot be assumed to apply. */
|
|
20
|
+
export function hasNonAsciiLetter(text: string): boolean {
|
|
21
|
+
return LETTER_RE.test(text.replace(ASCII_CHARS, ""));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Strip trailing punctuation/symbols/emojis (Unicode-aware) so exact-match
|
|
25
|
+
* ack detection works for "はい。", "merci !", "شكرا" etc. */
|
|
26
|
+
export function stripTrailingRecallNoise(text: string): string {
|
|
27
|
+
let candidate = text;
|
|
28
|
+
while (candidate.length > 0) {
|
|
29
|
+
const last = candidate.at(-1) ?? "";
|
|
30
|
+
if (WORDISH_RE.test(last)) break;
|
|
31
|
+
candidate = candidate.slice(0, -1);
|
|
32
|
+
}
|
|
33
|
+
return candidate.trim();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** True when the text ends with an ASCII, fullwidth, or Arabic question mark. */
|
|
37
|
+
export function endsWithQuestionMark(text: string): boolean {
|
|
38
|
+
return QUESTION_MARK_END_RE.test(text.trimEnd());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function containsRecallCue(text: string, cues: readonly string[]): boolean {
|
|
42
|
+
const normalized = text.toLowerCase();
|
|
43
|
+
return cues.some((cue) => normalized.includes(cue));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Exact-match acknowledgements (lowercased, trailing noise stripped).
|
|
47
|
+
const ACK_CANDIDATES = new Set([
|
|
48
|
+
// English (membership identical to the previous regex alternation)
|
|
49
|
+
"ok", "okay", "kk", "thanks", "thx", "got it", "sounds good", "yep", "yes",
|
|
50
|
+
"nope", "no", "done", "cool", "works",
|
|
51
|
+
// Japanese
|
|
52
|
+
"はい", "うん", "わかった", "わかりました", "了解", "承知", "ありがとう",
|
|
53
|
+
"どうも", "おけー", "オッケー", "りょうかい",
|
|
54
|
+
// Chinese
|
|
55
|
+
"好", "好的", "嗯", "对", "行", "可以", "收到", "明白", "明白了", "知道了",
|
|
56
|
+
"谢谢", "没问题",
|
|
57
|
+
// Korean
|
|
58
|
+
"네", "응", "알겠어", "알겠습니다", "고마워", "감사합니다", "좋아",
|
|
59
|
+
// Spanish
|
|
60
|
+
"sí", "si", "gracias", "vale", "de acuerdo", "perfecto", "claro", "listo",
|
|
61
|
+
// French
|
|
62
|
+
"oui", "merci", "d'accord", "bien", "parfait", "compris", "ça marche",
|
|
63
|
+
// German
|
|
64
|
+
"ja", "danke", "gut", "verstanden", "alles klar", "passt", "einverstanden",
|
|
65
|
+
// Portuguese
|
|
66
|
+
"sim", "obrigado", "obrigada", "certo", "combinado", "beleza",
|
|
67
|
+
// Russian
|
|
68
|
+
"да", "спасибо", "ок", "хорошо", "понял", "поняла", "ясно", "угу", "принято",
|
|
69
|
+
// Arabic
|
|
70
|
+
"نعم", "شكرا", "حسنا", "تمام", "طيب", "موافق", "أوكي",
|
|
71
|
+
// Hindi
|
|
72
|
+
"हाँ", "ठीक", "अच्छा", "धन्यवाद", "समझ गया", "मंज़ूर",
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
export function isMultilingualAck(candidate: string): boolean {
|
|
76
|
+
return ACK_CANDIDATES.has(candidate.trim().toLowerCase());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Timeline / sequence / what-happened cues → graph_mode parity.
|
|
80
|
+
export const GRAPH_MODE_CUES: readonly string[] = [
|
|
81
|
+
// Japanese
|
|
82
|
+
"タイムライン", "時系列", "時の流れ", "順序", "経緯", "変遷", "何があった", "どうなった",
|
|
83
|
+
// Chinese
|
|
84
|
+
"时间线", "时间轴", "时间顺序", "先后顺序", "来龙去脉", "变迁", "发生了什么", "怎么演变",
|
|
85
|
+
// Korean
|
|
86
|
+
"타임라인", "시간순", "경위", "변천", "무슨 일이 있었", "어떻게 됐", "어떻게 변했",
|
|
87
|
+
// Spanish
|
|
88
|
+
"línea de tiempo", "cronología", "cronologia", "qué pasó", "qué ocurrió", "historial",
|
|
89
|
+
// French
|
|
90
|
+
"chronologie", "frise chronologique", "qu'est-il passé", "historique",
|
|
91
|
+
// German
|
|
92
|
+
"zeitleiste", "abfolge", "ereignisfolge", "was ist passiert", "verlauf",
|
|
93
|
+
// Portuguese
|
|
94
|
+
"linha do tempo", "sequência de eventos", "o que aconteceu",
|
|
95
|
+
// Russian
|
|
96
|
+
"хронология", "последовательность событий", "что произошло", "таймлайн",
|
|
97
|
+
// Arabic
|
|
98
|
+
"الجدول الزمني", "التسلسل الزمني", "تسلسل الأحداث", "ماذا حدث",
|
|
99
|
+
// Hindi
|
|
100
|
+
"टाइमलाइन", "कालक्रम", "घटनाक्रम", "क्या हुआ",
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
// Causal-chain cues (broad graph intent).
|
|
104
|
+
export const CAUSAL_CHAIN_CUES: readonly string[] = [
|
|
105
|
+
"原因", "因果", "根本原因", "怎么会",
|
|
106
|
+
"原因は", "なぜそうなった", "因果関係",
|
|
107
|
+
"원인이", "왜 이렇게", "인과",
|
|
108
|
+
"por qué pasó", "causa raíz", "cadena de causas",
|
|
109
|
+
"pourquoi c'est arrivé", "cause racine",
|
|
110
|
+
"wieso ist das passiert", "ursachenkette",
|
|
111
|
+
"por que aconteceu", "cadeia de causas",
|
|
112
|
+
"почему это произошло", "первопричина", "причинно",
|
|
113
|
+
"لماذا حدث هذا", "سلسلة الأسباب",
|
|
114
|
+
"ऐसा क्यों हुआ", "मूल कारण",
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
// Temporal-ordering markers → chronological evidence tier parity.
|
|
118
|
+
export const EVENT_ORDER_CUES: readonly string[] = [
|
|
119
|
+
// Japanese
|
|
120
|
+
"最初", "初めて", "いつ", "何日", "何ヶ月", "何か月", "前に", "後で", "以降",
|
|
121
|
+
"順番", "順に", "前回", "さかのぼ", "最近",
|
|
122
|
+
// Chinese
|
|
123
|
+
"第一", "最早", "最后一次", "上次", "什么时候", "几月", "几天", "几个月",
|
|
124
|
+
"之前", "之后", "顺序", "按时间", "最近",
|
|
125
|
+
// Korean
|
|
126
|
+
"처음", "언제", "며칠", "몇 달", "몇 개월", "전에", "후에", "순서대로", "지난번",
|
|
127
|
+
// Spanish
|
|
128
|
+
"cuándo", "cuando fue", "cuántos días", "cuántos meses", "primero", "última vez",
|
|
129
|
+
"por orden", "orden cronológico",
|
|
130
|
+
// French
|
|
131
|
+
"quand ", "combien de jours", "combien de mois", "la première fois",
|
|
132
|
+
"la dernière fois", "dans l'ordre",
|
|
133
|
+
// German
|
|
134
|
+
"wann ", "wie viele tage", "wie viele monate", "zum ersten", "das letzte mal",
|
|
135
|
+
// Portuguese
|
|
136
|
+
"quando foi", "quantos dias", "quantos meses", "primeira vez", "última vez",
|
|
137
|
+
// Russian
|
|
138
|
+
"когда", "сколько дней", "сколько месяцев", "впервые", "последний раз", "по порядку",
|
|
139
|
+
// Arabic
|
|
140
|
+
"متى", "كم يوم", "كم شهر", "أول مرة", "آخر مرة", "بالترتيب",
|
|
141
|
+
// Hindi
|
|
142
|
+
"कब", "कितने दिन", "कितने महीने", "पहली बार", "आख़िरी बार",
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
// Timing/detail question cues for the response-guidance dates intent.
|
|
146
|
+
export const TIMING_DETAIL_CUES: readonly string[] = [
|
|
147
|
+
"いつ", "日時", "期日", "締め切り", "締切",
|
|
148
|
+
"什么时候", "几点", "日期", "截止",
|
|
149
|
+
"언제", "날짜", "마감",
|
|
150
|
+
"qué día", "qué fecha", "fecha límite", "cuándo",
|
|
151
|
+
"quelle date", "date limite",
|
|
152
|
+
"welches datum", "frist",
|
|
153
|
+
"que dia", "que data", "prazo",
|
|
154
|
+
"какого числа", "дедлайн",
|
|
155
|
+
"تاريخ الموعد", "متى الموعد",
|
|
156
|
+
"तारीख",
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
// Contradiction-resolution cues for the response-guidance tier.
|
|
160
|
+
export const CONTRADICTION_CUES: readonly string[] = [
|
|
161
|
+
"矛盾", "食い違", "前と違う", "一貫して",
|
|
162
|
+
"不一致", "之前说的", "前后矛盾",
|
|
163
|
+
"모순", "일관되",
|
|
164
|
+
"contradice", "inconsistente", "antes dijiste",
|
|
165
|
+
"contredit", "incohérent", "tu avais dit",
|
|
166
|
+
"widerspricht", "widersprüchlich",
|
|
167
|
+
"contradiz",
|
|
168
|
+
"противореч", "непоследовательн",
|
|
169
|
+
"يناقض", "تعارض",
|
|
170
|
+
"विरोधाभास",
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
// Prompt-filler words (recall verbs in other languages) that must not count
|
|
174
|
+
// as content discriminators in the direct-answer gate.
|
|
175
|
+
export const MULTILINGUAL_PROMPT_RECALL_WORDS: readonly string[] = [
|
|
176
|
+
"教えて", "見せて", "探して", "一覧",
|
|
177
|
+
"告诉我", "显示", "查找",
|
|
178
|
+
"보여줘", "알려줘", "찾아줘",
|
|
179
|
+
"muestra", "busca", "encuentra",
|
|
180
|
+
"montre", "cherche",
|
|
181
|
+
"zeige", "suche",
|
|
182
|
+
"покажи",
|
|
183
|
+
"أظهر", "ابحث",
|
|
184
|
+
"दिखाओ", "खोजो",
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
/** Structural heading line for non-Latin scripts: colon-terminated, short,
|
|
188
|
+
* and containing a non-ASCII letter. English prompts are unaffected. */
|
|
189
|
+
export function isNonLatinHeadingLine(line: string): boolean {
|
|
190
|
+
if (line.length > 80) return false;
|
|
191
|
+
if (!COLON_TERMINATED_RE.test(line)) return false;
|
|
192
|
+
return hasNonAsciiLetter(line);
|
|
193
|
+
}
|
|
@@ -6,7 +6,9 @@ const DEFAULT_RECALL_STOP_WORDS = ["the", "and", "for", "with", "from", "into",
|
|
|
6
6
|
|
|
7
7
|
export function isUnsegmentableRecallChar(char: string): boolean {
|
|
8
8
|
if (char === "ー" || char === "ー") return true;
|
|
9
|
-
return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(
|
|
9
|
+
return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Thai}\p{Script=Khmer}\p{Script=Lao}\p{Script=Myanmar}]/u.test(
|
|
10
|
+
char,
|
|
11
|
+
);
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
function isRecallCombiningMark(char: string): boolean {
|
package/src/retrieval-agents.ts
CHANGED
|
@@ -24,6 +24,8 @@ import type { QmdSearchResult } from "./types.js";
|
|
|
24
24
|
import type { QmdClient } from "./qmd.js";
|
|
25
25
|
import { isTemporalQuery, recencyWindowBoundsFromPrompt } from "./temporal-index.js";
|
|
26
26
|
import { isAbortError } from "./abort-error.js";
|
|
27
|
+
import { normalizeRecallTokens } from "./recall-tokenization.js";
|
|
28
|
+
|
|
27
29
|
|
|
28
30
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
29
31
|
|
|
@@ -56,10 +58,9 @@ export function shouldRunAgent(
|
|
|
56
58
|
): boolean {
|
|
57
59
|
switch (agent) {
|
|
58
60
|
case "direct":
|
|
59
|
-
// Skip only if query has no
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
return knownEntityCount > 0 || /\b\w{2,}/.test(query);
|
|
61
|
+
// Skip only if the query has no letter/number tokens. `\w` and `\b` are
|
|
62
|
+
// ASCII-only, so CJK entity names would never start the direct agent.
|
|
63
|
+
return knownEntityCount > 0 || /[\p{L}\p{N}]{2,}/u.test(query);
|
|
63
64
|
case "temporal":
|
|
64
65
|
// Only run temporal agent when the query actually asks about a time window.
|
|
65
66
|
// Running it for every query injects recency bias into semantic searches.
|
|
@@ -74,12 +75,7 @@ export function shouldRunAgent(
|
|
|
74
75
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
75
76
|
|
|
76
77
|
function tokenize(value: string): string[] {
|
|
77
|
-
return value
|
|
78
|
-
.toLowerCase()
|
|
79
|
-
.replace(/[^a-z0-9]+/g, " ")
|
|
80
|
-
.trim()
|
|
81
|
-
.split(/\s+/)
|
|
82
|
-
.filter((t) => t.length >= 2);
|
|
78
|
+
return normalizeRecallTokens(value).filter((t) => t.length >= 2);
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
function overlapScore(queryTokens: string[], candidateTokens: string[]): number {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/direct-answer.ts"],"sourcesContent":["/**\n * Direct-answer retrieval tier eligibility (issue #518 slice 2).\n *\n * This module is a pure decision layer. It takes a query, a set of\n * caller-resolved candidates (each already decorated with trust-zone,\n * taxonomy-bucket, and importance information), and the direct-answer\n * config, then returns an eligibility verdict.\n *\n * Keeping the module pure means:\n *\n * - Tests do not need a trust-zones store, taxonomy resolver, or importance\n * scorer on disk.\n * - Slice 3 (retrieval.ts wiring) is responsible for resolving those signals\n * before calling in; the wiring layer decides where candidates come from\n * (entity index, token prefilter, etc.). This module only decides\n * whether the surfaced candidates add up to a confident direct answer.\n *\n * Not wired into retrieval yet — see slice 3.\n */\n\nimport { normalizeRecallTokenSet, normalizeRecallTokens } from \"./recall-tokenization.js\";\nimport type { TrustZoneName } from \"./trust-zones.js\";\nimport type { MemoryFile, MemoryStatus } from \"./types.js\";\n\n/**\n * Caller-supplied candidate.\n *\n * `trustZone`, `taxonomyBucket`, and `importanceScore` are resolved outside\n * this module because each comes from a different subsystem. Passing them\n * as inputs keeps the function deterministic and easy to unit-test.\n *\n * `matchScore` is optional; if omitted, candidates are ranked by\n * token-overlap ratio. Callers that already computed a better ranking\n * score (e.g. BM25, vector similarity) can supply it to drive the\n * ambiguity check.\n */\nexport interface DirectAnswerCandidate {\n memory: MemoryFile;\n trustZone: TrustZoneName | null;\n taxonomyBucket: string | null;\n importanceScore: number;\n matchScore?: number;\n}\n\nexport interface DirectAnswerConfig {\n enabled: boolean;\n tokenOverlapFloor: number;\n importanceFloor: number;\n ambiguityMargin: number;\n eligibleTaxonomyBuckets: string[];\n}\n\nexport interface DirectAnswerInput {\n query: string;\n candidates: DirectAnswerCandidate[];\n config: DirectAnswerConfig;\n /**\n * Optional entity-ref hints resolved from the query upstream. When\n * supplied, a candidate with a set `entityRef` must match one of these\n * (case-insensitive) to remain eligible. Candidates without an\n * `entityRef` are allowed through regardless.\n */\n queryEntityRefs?: string[];\n}\n\nexport type DirectAnswerReason =\n | \"disabled\"\n | \"empty-query\"\n | \"no-candidates\"\n | \"no-eligible-candidates\"\n | \"below-token-overlap-floor\"\n | \"ambiguous\"\n | \"eligible\";\n\nexport interface DirectAnswerResult {\n eligible: boolean;\n reason: DirectAnswerReason;\n /** Winning candidate when eligible. */\n winner?: DirectAnswerCandidate;\n /** Computed token-overlap ratio (0..1) of the winner. */\n tokenOverlap?: number;\n /**\n * Human-readable summary suitable for\n * `RecallTierExplain.tierReason`.\n */\n narrative: string;\n /**\n * Filter labels that eliminated at least one candidate along the way.\n * Populated regardless of eligibility so the caller can surface the\n * narrowing steps in `RecallTierExplain.filteredBy`.\n */\n filteredBy: string[];\n}\n\n/** Filter labels — exported so callers and tests can match them structurally. */\nexport const FILTER_LABELS = {\n nonActiveStatus: \"non-active-status\",\n notTrustedZone: \"not-trusted-zone\",\n ineligibleTaxonomyBucket: \"ineligible-taxonomy-bucket\",\n belowImportanceFloor: \"below-importance-floor\",\n entityRefMismatch: \"entity-ref-mismatch\",\n belowTokenOverlapFloor: \"below-token-overlap-floor\",\n} as const;\n\nconst PROMPT_RECALL_WORDS = new Set([\n \"what\",\n \"who\",\n \"where\",\n \"when\",\n \"why\",\n \"how\",\n \"is\",\n \"are\",\n \"was\",\n \"were\",\n \"do\",\n \"does\",\n \"did\",\n \"find\",\n \"get\",\n \"show\",\n \"search\",\n \"lookup\",\n \"recall\",\n \"remember\",\n \"list\",\n \"status\",\n \"include\",\n \"tell\",\n \"me\",\n \"give\",\n \"about\",\n \"please\",\n \"the\",\n \"and\",\n \"for\",\n \"with\",\n \"from\",\n \"into\",\n \"that\",\n \"this\",\n \"найди\",\n \"найти\",\n \"поиск\",\n \"покажи\",\n \"статус\",\n \"включи\",\n]);\n\ninterface ScoredCandidate {\n candidate: DirectAnswerCandidate;\n tokenOverlap: number;\n requiredTokenMismatch: boolean;\n}\n\nfunction hasUnsegmentableRecallChar(token: string): boolean {\n if (token.includes(\"ー\") || token.includes(\"ー\")) return true;\n return /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}]/u.test(token);\n}\n\nfunction requiredCjkPhraseTokens(query: string): string[] {\n const phrases = new Set<string>();\n let segment = \"\";\n\n const addPhrase = (phrase: string) => {\n if ([...phrase].length >= 4) {\n phrases.add(phrase);\n }\n };\n\n const flushSegment = () => {\n let buffered = \"\";\n for (const run of segment.split(/\\s+/)) {\n if (!run) continue;\n if ([...run].length >= 4) {\n addPhrase(buffered);\n buffered = \"\";\n addPhrase(run);\n continue;\n }\n buffered += run;\n }\n addPhrase(buffered);\n segment = \"\";\n };\n\n for (const ch of query.toLowerCase().normalize(\"NFC\")) {\n if (hasUnsegmentableRecallChar(ch)) {\n segment += ch;\n continue;\n }\n if (/\\p{M}/u.test(ch) && segment.length > 0 && !/\\s$/u.test(segment)) {\n segment += ch;\n continue;\n }\n if (/\\s/u.test(ch)) {\n segment += \" \";\n continue;\n }\n flushSegment();\n }\n flushSegment();\n\n return [...phrases];\n}\n\nfunction requiredMixedScriptTokens(query: string): string[] {\n const required = new Set<string>();\n const parts: string[] = [];\n let segment = \"\";\n\n const flushSegment = () => {\n if (segment) {\n parts.push(segment);\n }\n segment = \"\";\n };\n\n const segmentableRecallTokens = (value: string) => {\n const tokens = new Set<string>();\n let segment = \"\";\n const flushSegmentableSegment = () => {\n for (const token of normalizeRecallTokenSet(segment, [], { minTokenLength: 1 })) {\n tokens.add(token);\n }\n segment = \"\";\n };\n\n for (const ch of value) {\n if (/[\\p{L}\\p{N}]/u.test(ch) && !hasUnsegmentableRecallChar(ch)) {\n segment += ch;\n continue;\n }\n if (/\\p{M}/u.test(ch) && segment.length > 0) {\n segment += ch;\n continue;\n }\n flushSegmentableSegment();\n }\n flushSegmentableSegment();\n return tokens;\n };\n\n const hasRequiredSegmentableToken = (value: string) => {\n return segmentableRecallTokens(value).size > 0;\n };\n\n const hasBoundarySegmentableToken = (value: string) => {\n for (const token of segmentableRecallTokens(value)) {\n if (PROMPT_RECALL_WORDS.has(token)) {\n continue;\n }\n const hasNonAsciiCodepoint = [...token].some((ch) => (ch.codePointAt(0) ?? 0) > 0x7f);\n if (token.length >= 3 || /\\p{N}/u.test(token) || hasNonAsciiCodepoint) {\n return true;\n }\n }\n return false;\n };\n\n const addRequiredTokens = (value: string) => {\n for (const token of normalizeRecallTokenSet(value, [], { minTokenLength: 1 })) {\n required.add(token);\n }\n };\n\n for (const ch of query.toLowerCase().normalize(\"NFC\")) {\n if (/[\\p{L}\\p{N}\\p{M}]/u.test(ch) || hasUnsegmentableRecallChar(ch)) {\n segment += ch;\n continue;\n }\n flushSegment();\n }\n flushSegment();\n\n for (const part of parts) {\n if (hasUnsegmentableRecallChar(part) && hasRequiredSegmentableToken(part)) {\n addRequiredTokens(part);\n }\n }\n\n for (let i = 0; i < parts.length - 1; i += 1) {\n const current = parts[i];\n const next = parts[i + 1];\n const currentHasUnsegmentable = hasUnsegmentableRecallChar(current);\n const nextHasUnsegmentable = hasUnsegmentableRecallChar(next);\n if (currentHasUnsegmentable === nextHasUnsegmentable) {\n continue;\n }\n const segmentablePart = currentHasUnsegmentable ? next : current;\n if (!hasBoundarySegmentableToken(segmentablePart)) {\n continue;\n }\n addRequiredTokens(current);\n addRequiredTokens(next);\n }\n\n for (let i = 1; i < parts.length - 1; i += 1) {\n const prev = parts[i - 1];\n const current = parts[i];\n const next = parts[i + 1];\n if (!hasUnsegmentableRecallChar(prev) || hasUnsegmentableRecallChar(current) || !hasUnsegmentableRecallChar(next)) {\n continue;\n }\n if (!hasRequiredSegmentableToken(current)) {\n continue;\n }\n addRequiredTokens(prev);\n addRequiredTokens(current);\n addRequiredTokens(next);\n }\n\n return [...required];\n}\n\nfunction requiredSegmentableUnicodeTokens(queryTokens: Set<string>): string[] {\n const segmentableTokens = [...queryTokens].filter((token) => !hasUnsegmentableRecallChar(token));\n const hasSegmentableUnicodeToken = segmentableTokens.some((token) =>\n [...token].some((ch) => (ch.codePointAt(0) ?? 0) > 0x7f)\n );\n if (!hasSegmentableUnicodeToken) {\n return [];\n }\n return segmentableTokens.filter((token) => {\n if (PROMPT_RECALL_WORDS.has(token)) {\n return false;\n }\n const hasNonAsciiCodepoint = [...token].some((ch) => (ch.codePointAt(0) ?? 0) > 0x7f);\n if (hasNonAsciiCodepoint) {\n return true;\n }\n if (!/^[a-z0-9]+$/u.test(token)) {\n return false;\n }\n return token.length >= 3 || /\\p{N}/u.test(token);\n });\n}\n\nfunction countTokenOverlap(queryTokens: Set<string>, valueTokens: Set<string>): number {\n let matches = 0;\n for (const token of queryTokens) {\n if (valueTokens.has(token)) matches += 1;\n }\n return matches;\n}\n\n/**\n * Determine whether a query can be served by the direct-answer tier.\n *\n * Decision ladder, in order:\n *\n * 1. config.enabled === false → \"disabled\"\n * 2. empty query tokens → \"empty-query\"\n * 3. empty candidates → \"no-candidates\"\n * 4. hard filters drop all candidates → \"no-eligible-candidates\"\n * 5. token-overlap floor drops all → \"below-token-overlap-floor\"\n * 6. top two candidates within ambiguityMargin → \"ambiguous\"\n * 7. otherwise → \"eligible\"\n */\nexport function isDirectAnswerEligible(input: DirectAnswerInput): DirectAnswerResult {\n const { query, candidates, config, queryEntityRefs } = input;\n\n if (!config.enabled) {\n return {\n eligible: false,\n reason: \"disabled\",\n narrative: \"direct-answer tier is disabled\",\n filteredBy: [],\n };\n }\n\n const queryTokens = new Set(normalizeRecallTokens(query));\n if (queryTokens.size === 0) {\n return {\n eligible: false,\n reason: \"empty-query\",\n narrative: \"query has no searchable tokens after normalization\",\n filteredBy: [],\n };\n }\n\n if (candidates.length === 0) {\n return {\n eligible: false,\n reason: \"no-candidates\",\n narrative: \"no candidates supplied\",\n filteredBy: [],\n };\n }\n\n const filteredBy: string[] = [];\n let working: DirectAnswerCandidate[] = candidates;\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.nonActiveStatus, (c) => {\n const status: MemoryStatus = c.memory.frontmatter.status ?? \"active\";\n return status === \"active\";\n });\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.notTrustedZone, (c) => c.trustZone === \"trusted\");\n\n working = applyFilter(\n working,\n filteredBy,\n FILTER_LABELS.ineligibleTaxonomyBucket,\n (c) => c.taxonomyBucket !== null && config.eligibleTaxonomyBuckets.includes(c.taxonomyBucket)\n );\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.belowImportanceFloor, (c) => {\n if (c.memory.frontmatter.verificationState === \"user_confirmed\") return true;\n return c.importanceScore >= config.importanceFloor;\n });\n\n if (queryEntityRefs && queryEntityRefs.length > 0) {\n const normRefs = new Set(queryEntityRefs.map((r) => r.toLowerCase()));\n working = applyFilter(working, filteredBy, FILTER_LABELS.entityRefMismatch, (c) => {\n const ref = c.memory.frontmatter.entityRef;\n if (!ref) return true;\n return normRefs.has(ref.toLowerCase());\n });\n }\n\n if (working.length === 0) {\n return {\n eligible: false,\n reason: \"no-eligible-candidates\",\n narrative: \"no candidates survived eligibility filters\",\n filteredBy,\n };\n }\n\n const scored: ScoredCandidate[] = working.map((candidate) => {\n const searchable = `${candidate.memory.frontmatter.tags?.join(\" \") ?? \"\"} ${candidate.memory.content}`.trim();\n const searchableTokens = normalizeRecallTokenSet(searchable);\n const requiredSearchableTokens = normalizeRecallTokenSet(searchable, [], { minTokenLength: 1 });\n const requiredPhrases = requiredCjkPhraseTokens(query);\n const requiredMixedTokens = requiredMixedScriptTokens(query);\n const requiredUnicodeTokens = requiredSegmentableUnicodeTokens(queryTokens);\n const hasRequiredPhrase =\n requiredPhrases.length === 0 || requiredPhrases.every((token) => searchableTokens.has(token));\n const hasRequiredMixedTokens =\n requiredMixedTokens.length === 0 || requiredMixedTokens.every((token) => requiredSearchableTokens.has(token));\n const hasRequiredUnicodeTokens =\n requiredUnicodeTokens.length === 0 || requiredUnicodeTokens.every((token) => searchableTokens.has(token));\n const requiredTokenMismatch = !hasRequiredPhrase || !hasRequiredMixedTokens || !hasRequiredUnicodeTokens;\n const matches = requiredTokenMismatch ? 0 : countTokenOverlap(queryTokens, searchableTokens);\n return { candidate, tokenOverlap: matches / queryTokens.size, requiredTokenMismatch };\n });\n\n const overlapSurvivors = scored.filter((s) => !s.requiredTokenMismatch && s.tokenOverlap >= config.tokenOverlapFloor);\n if (overlapSurvivors.length < scored.length) {\n filteredBy.push(FILTER_LABELS.belowTokenOverlapFloor);\n }\n\n if (overlapSurvivors.length === 0) {\n return {\n eligible: false,\n reason: \"below-token-overlap-floor\",\n narrative: `no candidate met token-overlap floor ${config.tokenOverlapFloor}`,\n filteredBy,\n };\n }\n\n overlapSurvivors.sort(compareScored);\n\n if (overlapSurvivors.length >= 2) {\n const topScore = scoreFor(overlapSurvivors[0]);\n const secondScore = scoreFor(overlapSurvivors[1]);\n if (topScore - secondScore < config.ambiguityMargin) {\n return {\n eligible: false,\n reason: \"ambiguous\",\n narrative: `top two candidates within ambiguityMargin ${config.ambiguityMargin}`,\n filteredBy,\n };\n }\n }\n\n const winner = overlapSurvivors[0];\n const bucket = winner.candidate.taxonomyBucket ?? \"unknown\";\n return {\n eligible: true,\n reason: \"eligible\",\n winner: winner.candidate,\n tokenOverlap: winner.tokenOverlap,\n narrative: `trusted ${bucket}, unambiguous, token-overlap ${winner.tokenOverlap.toFixed(2)}`,\n filteredBy,\n };\n}\n\nfunction applyFilter(\n working: DirectAnswerCandidate[],\n filteredBy: string[],\n label: string,\n keep: (c: DirectAnswerCandidate) => boolean\n): DirectAnswerCandidate[] {\n const before = working.length;\n const next = working.filter(keep);\n if (next.length < before) filteredBy.push(label);\n return next;\n}\n\nfunction scoreFor(s: ScoredCandidate): number {\n return s.candidate.matchScore ?? s.tokenOverlap;\n}\n\nfunction compareScored(a: ScoredCandidate, b: ScoredCandidate): number {\n const diff = scoreFor(b) - scoreFor(a);\n if (diff !== 0) return diff;\n // Stable secondary key on path so the comparator returns 0 only for equal\n // entries (CLAUDE.md rule 19).\n return a.candidate.memory.path.localeCompare(b.candidate.memory.path);\n}\n"],"mappings":"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","names":["segment"]}
|