@remnic/core 9.66.11 → 9.67.0
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 +23 -23
- package/dist/access-authorization-probe.js +24 -24
- package/dist/access-boundary.js +23 -23
- package/dist/access-cli.js +81 -81
- package/dist/access-extraction-force-flush.js +23 -23
- package/dist/access-http-query.js +25 -25
- package/dist/access-http.js +41 -41
- package/dist/access-identity-continuity-surface.js +23 -23
- package/dist/access-lcm-surface.js +23 -23
- package/dist/access-mcp.js +32 -32
- package/dist/access-namespace-preflight.js +23 -23
- package/dist/access-observe-write-surface.js +23 -23
- package/dist/access-operations-batch.js +26 -26
- package/dist/access-operations.js +31 -31
- package/dist/access-recall-concurrency.js +23 -23
- package/dist/access-recall-response.js +23 -23
- package/dist/access-recall-surface.js +23 -23
- package/dist/access-schema.js +4 -4
- package/dist/access-service.js +23 -23
- package/dist/access-surface-catalog.js +25 -25
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +10 -10
- package/dist/buffer.js +4 -4
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
- package/dist/causal-consolidation.js +11 -11
- package/dist/{chunk-XN33JLRF.js → chunk-46XRYYOJ.js} +3 -3
- package/dist/{chunk-WD424KYT.js → chunk-4L7OKRGP.js} +2 -2
- package/dist/{chunk-XZ7QLOTJ.js → chunk-6KGBI54C.js} +2 -2
- package/dist/{chunk-245QROHZ.js → chunk-6SRUPUTY.js} +7 -7
- package/dist/{chunk-ZIGSNLYI.js → chunk-A6HVSRGM.js} +3 -3
- package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
- package/dist/{chunk-7BS5UVXA.js → chunk-AWMS3IFB.js} +3 -3
- package/dist/{chunk-HJQZQUPC.js → chunk-BE4Y6GK6.js} +6 -6
- package/dist/{chunk-D3AUQXTJ.js → chunk-BT7AQZQX.js} +2 -2
- package/dist/{chunk-IPLYGWQF.js → chunk-BUKK5SWA.js} +6 -6
- package/dist/{chunk-CEH2AFXG.js → chunk-C24UZSFW.js} +6 -6
- package/dist/{chunk-HCERYDRI.js → chunk-CJTZO5MW.js} +2 -2
- package/dist/{chunk-4QKWBVEE.js → chunk-CR73YTWC.js} +13 -13
- package/dist/{chunk-LTWFU6VJ.js → chunk-DDAHG5ZD.js} +2 -2
- package/dist/{chunk-S47XNAWD.js → chunk-EU5PDHU2.js} +2 -2
- package/dist/{chunk-KT3ERTF6.js → chunk-F3H7VNM4.js} +2 -2
- package/dist/{chunk-EG4FHU5C.js → chunk-FJP6MVRK.js} +2 -2
- package/dist/{chunk-7FLINMUE.js → chunk-GEHEBLVY.js} +2 -2
- package/dist/{chunk-G3B3LP6A.js → chunk-GRZYF6KK.js} +14 -14
- package/dist/{chunk-E2PORO7O.js → chunk-H6VYVOVP.js} +2 -2
- package/dist/{chunk-QKTGCL6M.js → chunk-HGRRJDUH.js} +2 -2
- package/dist/{chunk-J2R275FN.js → chunk-HQJM3BKH.js} +2 -2
- package/dist/{chunk-ZRQPX2DW.js → chunk-I3X5NWDU.js} +2 -2
- package/dist/{chunk-TGKLVAML.js → chunk-I7FVQMAA.js} +2 -2
- package/dist/{chunk-UWOA5L6N.js → chunk-IDPFBRPJ.js} +35 -35
- package/dist/{chunk-CNZVEU4X.js → chunk-IE7N2YK6.js} +2 -2
- package/dist/{chunk-PVV42HM4.js → chunk-IYFL3534.js} +2 -2
- package/dist/{chunk-X5SDZMO7.js → chunk-JGXMA6HL.js} +2 -2
- package/dist/{chunk-SQEIPTDV.js → chunk-JKXPFIPC.js} +2 -2
- package/dist/{chunk-Y2ECPAJI.js → chunk-K5JFIA44.js} +7 -7
- package/dist/{chunk-JNZSNJ43.js → chunk-K7VTD5AZ.js} +2 -2
- package/dist/{chunk-E62M4H4M.js → chunk-KDCPIXIY.js} +2 -2
- package/dist/{chunk-TS37MXC7.js → chunk-KZAN4JXY.js} +2 -2
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-5E7KXID5.js → chunk-M3BFW3VX.js} +1 -1
- package/dist/{chunk-PWVRMD37.js → chunk-MUYJQ273.js} +2 -2
- package/dist/{chunk-5KVMT25I.js → chunk-MWLBRFLY.js} +2 -2
- package/dist/{chunk-2OXBS2LV.js → chunk-NROLO2HY.js} +2 -2
- package/dist/{chunk-6H7JWYTC.js → chunk-O2HDDAUM.js} +3 -3
- package/dist/{chunk-RLEJULGN.js → chunk-OMA2B7GY.js} +2 -2
- package/dist/{chunk-K6PWPC7O.js → chunk-OQT34EVH.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
- package/dist/{chunk-4PWANX5V.js → chunk-PKRYQ222.js} +6 -6
- package/dist/{chunk-BCM6ZAJ3.js → chunk-QJLTAH5X.js} +208 -61
- package/dist/chunk-QJLTAH5X.js.map +1 -0
- package/dist/{chunk-DJLH3XWM.js → chunk-QMIKXIAM.js} +2 -2
- package/dist/{chunk-Y6KDJQLK.js → chunk-QRHKJT7F.js} +7 -7
- package/dist/{chunk-7MOYAT4Y.js → chunk-QXDICB4J.js} +3 -3
- package/dist/{chunk-KWLDB64F.js → chunk-QZPSIQRB.js} +2 -2
- package/dist/{chunk-54BRW3BL.js → chunk-REJCULWA.js} +2 -2
- package/dist/{chunk-ISX7JODR.js → chunk-SBUQ4KIE.js} +2 -2
- package/dist/{chunk-HPGXB56F.js → chunk-STUPJFG7.js} +2 -2
- package/dist/{chunk-LPSTQR26.js → chunk-SV3MDTJI.js} +2 -2
- package/dist/{chunk-MK7EJLB4.js → chunk-UJICQ77Y.js} +2 -2
- package/dist/{chunk-4PHT7KE2.js → chunk-UUGU26P2.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
- package/dist/{chunk-QB66LBXA.js → chunk-WGVAEVT7.js} +2 -2
- package/dist/{chunk-2L5FSNPC.js → chunk-X2NFFBTO.js} +7 -7
- package/dist/{chunk-EMAEDM2J.js → chunk-YWD5UIWY.js} +2 -2
- package/dist/{chunk-C6TMLF3A.js → chunk-ZFE7NXB7.js} +4 -4
- package/dist/cli.js +57 -57
- package/dist/coding/export-okf-codegraph.js +10 -10
- package/dist/compounding/engine.js +10 -10
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +10 -10
- package/dist/convergence-refresh.js +12 -12
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +12 -12
- package/dist/entity-retrieval.js +10 -10
- package/dist/external-wiki-access.js +24 -24
- package/dist/extraction-span-provenance.d.ts +28 -0
- package/dist/extraction-span-provenance.js +24 -0
- package/dist/extraction-span-provenance.js.map +1 -0
- package/dist/extraction.js +13 -13
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.d.ts +34 -6
- package/dist/index.js +115 -109
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +6 -6
- package/dist/location/index.js +12 -12
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/search.js +8 -8
- package/dist/namespaces/storage.js +10 -10
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-toolkit.js +18 -18
- package/dist/orchestration/maintenance.js +18 -18
- package/dist/orchestrator.js +82 -82
- package/dist/qmd.js +4 -4
- package/dist/recall-deep-rewrite.d.ts +23 -0
- package/dist/recall-deep-rewrite.js +29 -0
- package/dist/recall-deep-rewrite.js.map +1 -0
- package/dist/search/factory.js +7 -7
- package/dist/search/index.js +11 -11
- package/dist/semantic-consolidation.js +11 -11
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/source-agent-qualifier.js +12 -12
- package/dist/standup/build.js +10 -10
- package/dist/storage.js +9 -9
- package/dist/support-passport/index.js +26 -26
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.js +11 -11
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.js +11 -11
- package/dist/who-knows.js +10 -10
- package/package.json +2 -2
- package/src/activity/index.ts +1 -0
- package/src/activity/journal-section.ts +1 -1
- package/src/activity/journal-strip.test.ts +126 -0
- package/src/activity/journal-strip.ts +115 -0
- package/src/activity/timeline/analysis-failure.test.ts +104 -0
- package/src/activity/timeline/analysis-failure.ts +60 -0
- package/src/activity/timeline/index.ts +1 -0
- package/src/dedup/index.ts +7 -0
- package/src/dedup/merge-verdict.test.ts +74 -0
- package/src/dedup/merge-verdict.ts +31 -0
- package/src/extraction-span-provenance.test.ts +85 -0
- package/src/extraction-span-provenance.ts +41 -0
- package/src/recall-deep-rewrite.test.ts +199 -0
- package/src/recall-deep-rewrite.ts +50 -0
- package/dist/chunk-BCM6ZAJ3.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
- /package/dist/{chunk-XN33JLRF.js.map → chunk-46XRYYOJ.js.map} +0 -0
- /package/dist/{chunk-WD424KYT.js.map → chunk-4L7OKRGP.js.map} +0 -0
- /package/dist/{chunk-XZ7QLOTJ.js.map → chunk-6KGBI54C.js.map} +0 -0
- /package/dist/{chunk-245QROHZ.js.map → chunk-6SRUPUTY.js.map} +0 -0
- /package/dist/{chunk-ZIGSNLYI.js.map → chunk-A6HVSRGM.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-7BS5UVXA.js.map → chunk-AWMS3IFB.js.map} +0 -0
- /package/dist/{chunk-HJQZQUPC.js.map → chunk-BE4Y6GK6.js.map} +0 -0
- /package/dist/{chunk-D3AUQXTJ.js.map → chunk-BT7AQZQX.js.map} +0 -0
- /package/dist/{chunk-IPLYGWQF.js.map → chunk-BUKK5SWA.js.map} +0 -0
- /package/dist/{chunk-CEH2AFXG.js.map → chunk-C24UZSFW.js.map} +0 -0
- /package/dist/{chunk-HCERYDRI.js.map → chunk-CJTZO5MW.js.map} +0 -0
- /package/dist/{chunk-4QKWBVEE.js.map → chunk-CR73YTWC.js.map} +0 -0
- /package/dist/{chunk-LTWFU6VJ.js.map → chunk-DDAHG5ZD.js.map} +0 -0
- /package/dist/{chunk-S47XNAWD.js.map → chunk-EU5PDHU2.js.map} +0 -0
- /package/dist/{chunk-KT3ERTF6.js.map → chunk-F3H7VNM4.js.map} +0 -0
- /package/dist/{chunk-EG4FHU5C.js.map → chunk-FJP6MVRK.js.map} +0 -0
- /package/dist/{chunk-7FLINMUE.js.map → chunk-GEHEBLVY.js.map} +0 -0
- /package/dist/{chunk-G3B3LP6A.js.map → chunk-GRZYF6KK.js.map} +0 -0
- /package/dist/{chunk-E2PORO7O.js.map → chunk-H6VYVOVP.js.map} +0 -0
- /package/dist/{chunk-QKTGCL6M.js.map → chunk-HGRRJDUH.js.map} +0 -0
- /package/dist/{chunk-J2R275FN.js.map → chunk-HQJM3BKH.js.map} +0 -0
- /package/dist/{chunk-ZRQPX2DW.js.map → chunk-I3X5NWDU.js.map} +0 -0
- /package/dist/{chunk-TGKLVAML.js.map → chunk-I7FVQMAA.js.map} +0 -0
- /package/dist/{chunk-UWOA5L6N.js.map → chunk-IDPFBRPJ.js.map} +0 -0
- /package/dist/{chunk-CNZVEU4X.js.map → chunk-IE7N2YK6.js.map} +0 -0
- /package/dist/{chunk-PVV42HM4.js.map → chunk-IYFL3534.js.map} +0 -0
- /package/dist/{chunk-X5SDZMO7.js.map → chunk-JGXMA6HL.js.map} +0 -0
- /package/dist/{chunk-SQEIPTDV.js.map → chunk-JKXPFIPC.js.map} +0 -0
- /package/dist/{chunk-Y2ECPAJI.js.map → chunk-K5JFIA44.js.map} +0 -0
- /package/dist/{chunk-JNZSNJ43.js.map → chunk-K7VTD5AZ.js.map} +0 -0
- /package/dist/{chunk-E62M4H4M.js.map → chunk-KDCPIXIY.js.map} +0 -0
- /package/dist/{chunk-TS37MXC7.js.map → chunk-KZAN4JXY.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-5E7KXID5.js.map → chunk-M3BFW3VX.js.map} +0 -0
- /package/dist/{chunk-PWVRMD37.js.map → chunk-MUYJQ273.js.map} +0 -0
- /package/dist/{chunk-5KVMT25I.js.map → chunk-MWLBRFLY.js.map} +0 -0
- /package/dist/{chunk-2OXBS2LV.js.map → chunk-NROLO2HY.js.map} +0 -0
- /package/dist/{chunk-6H7JWYTC.js.map → chunk-O2HDDAUM.js.map} +0 -0
- /package/dist/{chunk-RLEJULGN.js.map → chunk-OMA2B7GY.js.map} +0 -0
- /package/dist/{chunk-K6PWPC7O.js.map → chunk-OQT34EVH.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
- /package/dist/{chunk-4PWANX5V.js.map → chunk-PKRYQ222.js.map} +0 -0
- /package/dist/{chunk-DJLH3XWM.js.map → chunk-QMIKXIAM.js.map} +0 -0
- /package/dist/{chunk-Y6KDJQLK.js.map → chunk-QRHKJT7F.js.map} +0 -0
- /package/dist/{chunk-7MOYAT4Y.js.map → chunk-QXDICB4J.js.map} +0 -0
- /package/dist/{chunk-KWLDB64F.js.map → chunk-QZPSIQRB.js.map} +0 -0
- /package/dist/{chunk-54BRW3BL.js.map → chunk-REJCULWA.js.map} +0 -0
- /package/dist/{chunk-ISX7JODR.js.map → chunk-SBUQ4KIE.js.map} +0 -0
- /package/dist/{chunk-HPGXB56F.js.map → chunk-STUPJFG7.js.map} +0 -0
- /package/dist/{chunk-LPSTQR26.js.map → chunk-SV3MDTJI.js.map} +0 -0
- /package/dist/{chunk-MK7EJLB4.js.map → chunk-UJICQ77Y.js.map} +0 -0
- /package/dist/{chunk-4PHT7KE2.js.map → chunk-UUGU26P2.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
- /package/dist/{chunk-QB66LBXA.js.map → chunk-WGVAEVT7.js.map} +0 -0
- /package/dist/{chunk-2L5FSNPC.js.map → chunk-X2NFFBTO.js.map} +0 -0
- /package/dist/{chunk-EMAEDM2J.js.map → chunk-YWD5UIWY.js.map} +0 -0
- /package/dist/{chunk-C6TMLF3A.js.map → chunk-ZFE7NXB7.js.map} +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
MAX_REFINES_PER_INVOCATION,
|
|
6
|
+
validateRefineRewrite,
|
|
7
|
+
} from "./recall-deep-rewrite.js";
|
|
8
|
+
|
|
9
|
+
const base = {
|
|
10
|
+
currentQuery: "who met at the cafe",
|
|
11
|
+
refinesUsed: 0,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
test("genuine rewrite succeeds and is trimmed", () => {
|
|
15
|
+
assert.deepEqual(
|
|
16
|
+
validateRefineRewrite({
|
|
17
|
+
...base,
|
|
18
|
+
refinedQuery: " which people met at the cafe on friday ",
|
|
19
|
+
}),
|
|
20
|
+
{ ok: true, refinedQuery: "which people met at the cafe on friday" },
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("success keeps internal whitespace as written", () => {
|
|
25
|
+
assert.deepEqual(
|
|
26
|
+
validateRefineRewrite({
|
|
27
|
+
...base,
|
|
28
|
+
refinedQuery: "which people met at the cafe",
|
|
29
|
+
}),
|
|
30
|
+
{ ok: true, refinedQuery: "which people met at the cafe" },
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("refinesUsed 0 is allowed", () => {
|
|
35
|
+
assert.equal(
|
|
36
|
+
validateRefineRewrite({
|
|
37
|
+
...base,
|
|
38
|
+
refinesUsed: 0,
|
|
39
|
+
refinedQuery: "which people met at the cafe",
|
|
40
|
+
}).ok,
|
|
41
|
+
true,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("refinesUsed 1 is allowed", () => {
|
|
46
|
+
assert.equal(
|
|
47
|
+
validateRefineRewrite({
|
|
48
|
+
...base,
|
|
49
|
+
refinesUsed: 1,
|
|
50
|
+
refinedQuery: "which people met at the cafe",
|
|
51
|
+
}).ok,
|
|
52
|
+
true,
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("refinesUsed 2 gives refine_budget_spent", () => {
|
|
57
|
+
assert.deepEqual(
|
|
58
|
+
validateRefineRewrite({
|
|
59
|
+
...base,
|
|
60
|
+
refinesUsed: 2,
|
|
61
|
+
refinedQuery: "which people met at the cafe",
|
|
62
|
+
}),
|
|
63
|
+
{ ok: false, stop: true, reason: "refine_budget_spent" },
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("refinesUsed 3 gives refine_budget_spent", () => {
|
|
68
|
+
assert.deepEqual(
|
|
69
|
+
validateRefineRewrite({
|
|
70
|
+
...base,
|
|
71
|
+
refinesUsed: 3,
|
|
72
|
+
refinedQuery: "which people met at the cafe",
|
|
73
|
+
}),
|
|
74
|
+
{ ok: false, stop: true, reason: "refine_budget_spent" },
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("budget check wins over a valid rewrite", () => {
|
|
79
|
+
assert.deepEqual(
|
|
80
|
+
validateRefineRewrite({
|
|
81
|
+
currentQuery: "who met at the cafe",
|
|
82
|
+
refinedQuery: "completely different and clearly better query",
|
|
83
|
+
refinesUsed: MAX_REFINES_PER_INVOCATION,
|
|
84
|
+
}),
|
|
85
|
+
{ ok: false, stop: true, reason: "refine_budget_spent" },
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("negative refinesUsed throws", () => {
|
|
90
|
+
assert.throws(
|
|
91
|
+
() => validateRefineRewrite({ ...base, refinedQuery: "new query", refinesUsed: -1 }),
|
|
92
|
+
RangeError,
|
|
93
|
+
);
|
|
94
|
+
assert.throws(
|
|
95
|
+
() => validateRefineRewrite({ ...base, refinedQuery: "new query", refinesUsed: -1 }),
|
|
96
|
+
/refinesUsed/,
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("float refinesUsed throws", () => {
|
|
101
|
+
assert.throws(
|
|
102
|
+
() => validateRefineRewrite({ ...base, refinedQuery: "new query", refinesUsed: 1.5 }),
|
|
103
|
+
/refinesUsed/,
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("NaN refinesUsed throws", () => {
|
|
108
|
+
assert.throws(
|
|
109
|
+
() => validateRefineRewrite({ ...base, refinedQuery: "new query", refinesUsed: Number.NaN }),
|
|
110
|
+
/refinesUsed/,
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("empty string rewrite gives empty_rewrite", () => {
|
|
115
|
+
assert.deepEqual(validateRefineRewrite({ ...base, refinedQuery: "" }), {
|
|
116
|
+
ok: false,
|
|
117
|
+
stop: true,
|
|
118
|
+
reason: "empty_rewrite",
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("whitespace-only rewrite gives empty_rewrite", () => {
|
|
123
|
+
assert.deepEqual(validateRefineRewrite({ ...base, refinedQuery: " " }), {
|
|
124
|
+
ok: false,
|
|
125
|
+
stop: true,
|
|
126
|
+
reason: "empty_rewrite",
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("null rewrite gives empty_rewrite", () => {
|
|
131
|
+
assert.deepEqual(validateRefineRewrite({ ...base, refinedQuery: null }), {
|
|
132
|
+
ok: false,
|
|
133
|
+
stop: true,
|
|
134
|
+
reason: "empty_rewrite",
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("undefined rewrite gives empty_rewrite", () => {
|
|
139
|
+
assert.deepEqual(validateRefineRewrite({ ...base, refinedQuery: undefined }), {
|
|
140
|
+
ok: false,
|
|
141
|
+
stop: true,
|
|
142
|
+
reason: "empty_rewrite",
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("number rewrite gives empty_rewrite", () => {
|
|
147
|
+
assert.deepEqual(validateRefineRewrite({ ...base, refinedQuery: 42 }), {
|
|
148
|
+
ok: false,
|
|
149
|
+
stop: true,
|
|
150
|
+
reason: "empty_rewrite",
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("exact duplicate gives identical_rewrite", () => {
|
|
155
|
+
assert.deepEqual(
|
|
156
|
+
validateRefineRewrite({
|
|
157
|
+
...base,
|
|
158
|
+
refinedQuery: "who met at the cafe",
|
|
159
|
+
}),
|
|
160
|
+
{ ok: false, stop: true, reason: "identical_rewrite" },
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("case-different duplicate gives identical_rewrite", () => {
|
|
165
|
+
assert.deepEqual(
|
|
166
|
+
validateRefineRewrite({
|
|
167
|
+
...base,
|
|
168
|
+
refinedQuery: " Who Met At The Cafe ",
|
|
169
|
+
}),
|
|
170
|
+
{ ok: false, stop: true, reason: "identical_rewrite" },
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("extra internal whitespace duplicate gives identical_rewrite", () => {
|
|
175
|
+
assert.deepEqual(
|
|
176
|
+
validateRefineRewrite({
|
|
177
|
+
currentQuery: "who met",
|
|
178
|
+
refinedQuery: "who met",
|
|
179
|
+
refinesUsed: 0,
|
|
180
|
+
}),
|
|
181
|
+
{ ok: false, stop: true, reason: "identical_rewrite" },
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("every failure carries stop true", () => {
|
|
186
|
+
const failures = [
|
|
187
|
+
validateRefineRewrite({
|
|
188
|
+
...base,
|
|
189
|
+
refinedQuery: "fine",
|
|
190
|
+
refinesUsed: 2,
|
|
191
|
+
}),
|
|
192
|
+
validateRefineRewrite({ ...base, refinedQuery: " " }),
|
|
193
|
+
validateRefineRewrite({ ...base, refinedQuery: "who met at the cafe" }),
|
|
194
|
+
];
|
|
195
|
+
for (const failure of failures) {
|
|
196
|
+
assert.equal(failure.ok, false);
|
|
197
|
+
assert.equal(failure.stop, true);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a deep-recall REFINE rewrite (issue #2332).
|
|
3
|
+
*
|
|
4
|
+
* Pure. The budget check runs before the rewrite is inspected, so an
|
|
5
|
+
* exhausted budget cannot be bypassed by a valid-looking query. An empty
|
|
6
|
+
* or no-progress rewrite is rejected and treated as STOP.
|
|
7
|
+
*/
|
|
8
|
+
export const MAX_REFINES_PER_INVOCATION = 2;
|
|
9
|
+
|
|
10
|
+
export type RefineRewriteResult =
|
|
11
|
+
| { ok: true; refinedQuery: string }
|
|
12
|
+
| {
|
|
13
|
+
ok: false;
|
|
14
|
+
stop: true;
|
|
15
|
+
reason: "empty_rewrite" | "identical_rewrite" | "refine_budget_spent";
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function validateRefineRewrite(input: {
|
|
19
|
+
currentQuery: string;
|
|
20
|
+
refinedQuery: unknown;
|
|
21
|
+
refinesUsed: number;
|
|
22
|
+
}): RefineRewriteResult {
|
|
23
|
+
if (!Number.isInteger(input.refinesUsed) || input.refinesUsed < 0) {
|
|
24
|
+
throw new RangeError(
|
|
25
|
+
`refinesUsed must be a non-negative integer; got ${JSON.stringify(input.refinesUsed)}`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
if (input.refinesUsed >= MAX_REFINES_PER_INVOCATION) {
|
|
29
|
+
return { ok: false, stop: true, reason: "refine_budget_spent" };
|
|
30
|
+
}
|
|
31
|
+
if (
|
|
32
|
+
typeof input.refinedQuery !== "string" ||
|
|
33
|
+
input.refinedQuery.trim() === ""
|
|
34
|
+
) {
|
|
35
|
+
return { ok: false, stop: true, reason: "empty_rewrite" };
|
|
36
|
+
}
|
|
37
|
+
const trimmed = input.refinedQuery.trim();
|
|
38
|
+
// Comparison key: case-folded with internal whitespace runs collapsed, so
|
|
39
|
+
// pure case/spacing drift is not progress. The returned rewrite keeps
|
|
40
|
+
// internal whitespace as the model wrote it.
|
|
41
|
+
const currentKey = input.currentQuery
|
|
42
|
+
.trim()
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.replace(/\s+/g, " ");
|
|
45
|
+
const refinedKey = trimmed.toLowerCase().replace(/\s+/g, " ");
|
|
46
|
+
if (refinedKey === currentKey) {
|
|
47
|
+
return { ok: false, stop: true, reason: "identical_rewrite" };
|
|
48
|
+
}
|
|
49
|
+
return { ok: true, refinedQuery: trimmed };
|
|
50
|
+
}
|