@remnic/core 9.6.29 → 9.6.31
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.d.ts +1 -0
- package/dist/access-admin-ops-surface.js +2 -1
- package/dist/access-boundary.d.ts +1 -0
- package/dist/access-boundary.js +3 -2
- package/dist/access-cli.js +18 -17
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +1 -0
- package/dist/access-http.js +7 -6
- package/dist/access-identity-continuity-surface.d.ts +1 -0
- package/dist/access-identity-continuity-surface.js +2 -1
- package/dist/access-lcm-surface.d.ts +1 -0
- package/dist/access-lcm-surface.js +2 -1
- package/dist/access-mcp.d.ts +1 -0
- package/dist/access-mcp.js +6 -5
- package/dist/access-observe-write-surface.d.ts +1 -0
- package/dist/access-observe-write-surface.js +2 -1
- package/dist/access-operations-batch.js +4 -3
- package/dist/access-operations.d.ts +1 -0
- package/dist/access-operations.js +5 -4
- package/dist/access-recall-surface.d.ts +1 -0
- package/dist/access-recall-surface.js +2 -1
- package/dist/access-service.d.ts +1 -0
- package/dist/access-service.js +2 -1
- package/dist/access-surface-catalog.d.ts +1 -0
- package/dist/bootstrap.d.ts +1 -0
- package/dist/causal-behavior.d.ts +1 -0
- package/dist/{chunk-L6W77GWW.js → chunk-6TCXIRP5.js} +25 -13
- package/dist/chunk-6TCXIRP5.js.map +1 -0
- package/dist/chunk-C37ZRXX7.js +36 -0
- package/dist/chunk-C37ZRXX7.js.map +1 -0
- package/dist/{chunk-SGYTQKC2.js → chunk-C6TKSI35.js} +3 -3
- package/dist/{chunk-C2SEH754.js → chunk-DAAJUA6Q.js} +4 -4
- package/dist/{chunk-FV5FVO2J.js → chunk-DEOYTFA6.js} +9 -5
- package/dist/chunk-DEOYTFA6.js.map +1 -0
- package/dist/{chunk-PYPOFEMK.js → chunk-DGFU5MSX.js} +16 -1
- package/dist/chunk-DGFU5MSX.js.map +1 -0
- package/dist/{chunk-EAREADWV.js → chunk-GQURC4B7.js} +2 -2
- package/dist/{chunk-XA4PWKBW.js → chunk-MXAGJHTA.js} +3 -3
- package/dist/{chunk-LZTFCAKE.js → chunk-OH7QLI6W.js} +28 -15
- package/dist/chunk-OH7QLI6W.js.map +1 -0
- package/dist/{chunk-5BHIGBHQ.js → chunk-OXVKR5OU.js} +6 -3
- package/dist/{chunk-5BHIGBHQ.js.map → chunk-OXVKR5OU.js.map} +1 -1
- package/dist/{chunk-IF7THCGJ.js → chunk-PUQZIS6A.js} +3 -3
- package/dist/{chunk-4SBW47WK.js → chunk-T67LUYCR.js} +28 -15
- package/dist/chunk-T67LUYCR.js.map +1 -0
- package/dist/{chunk-4463LUIE.js → chunk-TVIVY7KU.js} +180 -70
- package/dist/chunk-TVIVY7KU.js.map +1 -0
- package/dist/{chunk-KCYE2MZM.js → chunk-UXPUUL3G.js} +29 -8
- package/dist/chunk-UXPUUL3G.js.map +1 -0
- package/dist/chunk-VDC6RZI4.js +1 -0
- package/dist/{chunk-3RROR5KV.js → chunk-VJRJTRYF.js} +4 -4
- package/dist/{chunk-5WJ4LBFR.js → chunk-WSOEYOHN.js} +8 -8
- package/dist/{chunk-5AJIDEFT.js → chunk-XFTPUXCE.js} +11 -7
- package/dist/chunk-XFTPUXCE.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +8 -7
- package/dist/compounding/preference-consolidator.d.ts +1 -0
- package/dist/event-order-recall.d.ts +1 -0
- package/dist/event-order-recall.js +3 -2
- package/dist/evidence-pack.d.ts +18 -1
- package/dist/evidence-pack.js +1 -1
- package/dist/explicit-capture.d.ts +1 -0
- package/dist/explicit-cue-recall.d.ts +19 -1
- package/dist/explicit-cue-recall.js +3 -2
- package/dist/focused-list-recall.d.ts +1 -0
- package/dist/focused-list-recall.js +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -17
- package/dist/lcm/engine.d.ts +3 -0
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +23 -1
- package/dist/lcm/index.js +14 -4
- package/dist/lcm/recall.d.ts +15 -1
- package/dist/lcm/recall.js +5 -3
- package/dist/lcm/tools.d.ts +1 -0
- package/dist/mcp-memory-inspector-app.d.ts +1 -0
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.js +18 -17
- package/dist/response-guidance-recall.d.ts +1 -0
- package/dist/response-guidance-recall.js +3 -2
- package/dist/targeted-fact-recall.d.ts +1 -0
- package/dist/targeted-fact-recall.js +3 -2
- package/package.json +2 -2
- package/src/access-lcm-surface.ts +20 -5
- package/src/access-recall-surface.ts +2 -1
- package/src/event-order-recall.ts +5 -3
- package/src/evidence-pack.test.ts +66 -1
- package/src/evidence-pack.ts +41 -0
- package/src/explicit-cue-recall.ts +291 -133
- package/src/focused-list-recall.ts +25 -16
- package/src/index.ts +3 -0
- package/src/lcm/engine.ts +17 -5
- package/src/lcm/evidence-identity.ts +59 -0
- package/src/lcm/index.ts +13 -1
- package/src/lcm/recall.ts +48 -5
- package/src/lcm-engine.test.ts +46 -0
- package/src/lcm-recall.test.ts +48 -1
- package/src/lcm-retrieval-lineage.test.ts +236 -0
- package/src/recall-trace-receipts.test.ts +380 -0
- package/src/response-guidance-recall.ts +22 -14
- package/src/targeted-fact-recall.ts +25 -16
- package/dist/chunk-4463LUIE.js.map +0 -1
- package/dist/chunk-4SBW47WK.js.map +0 -1
- package/dist/chunk-5AJIDEFT.js.map +0 -1
- package/dist/chunk-FV5FVO2J.js.map +0 -1
- package/dist/chunk-HHLLAQGZ.js +0 -1
- package/dist/chunk-KCYE2MZM.js.map +0 -1
- package/dist/chunk-L6W77GWW.js.map +0 -1
- package/dist/chunk-LZTFCAKE.js.map +0 -1
- package/dist/chunk-PYPOFEMK.js.map +0 -1
- /package/dist/{chunk-SGYTQKC2.js.map → chunk-C6TKSI35.js.map} +0 -0
- /package/dist/{chunk-C2SEH754.js.map → chunk-DAAJUA6Q.js.map} +0 -0
- /package/dist/{chunk-EAREADWV.js.map → chunk-GQURC4B7.js.map} +0 -0
- /package/dist/{chunk-XA4PWKBW.js.map → chunk-MXAGJHTA.js.map} +0 -0
- /package/dist/{chunk-IF7THCGJ.js.map → chunk-PUQZIS6A.js.map} +0 -0
- /package/dist/{chunk-HHLLAQGZ.js.map → chunk-VDC6RZI4.js.map} +0 -0
- /package/dist/{chunk-3RROR5KV.js.map → chunk-VJRJTRYF.js.map} +0 -0
- /package/dist/{chunk-5WJ4LBFR.js.map → chunk-WSOEYOHN.js.map} +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
buildExplicitCueRecallSection,
|
|
6
|
+
buildTrajectoryAnalysisRecallSection,
|
|
7
|
+
type ExplicitCueRecallEngine,
|
|
8
|
+
type TrajectoryAnalysisLineReceipt,
|
|
9
|
+
} from "./explicit-cue-recall.js";
|
|
10
|
+
import type { EvidencePackSelectionReceipt } from "./evidence-pack.js";
|
|
11
|
+
|
|
12
|
+
interface ReceiptRow {
|
|
13
|
+
id?: number;
|
|
14
|
+
session_id: string;
|
|
15
|
+
turn_index: number;
|
|
16
|
+
role: string;
|
|
17
|
+
content: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class ReceiptEngine implements ExplicitCueRecallEngine {
|
|
21
|
+
constructor(private readonly rows: ReceiptRow[]) {}
|
|
22
|
+
|
|
23
|
+
async expandContext(
|
|
24
|
+
sessionId: string,
|
|
25
|
+
fromTurn: number,
|
|
26
|
+
toTurn: number,
|
|
27
|
+
): Promise<ReceiptRow[]> {
|
|
28
|
+
return this.rows.filter((row) =>
|
|
29
|
+
row.session_id === sessionId &&
|
|
30
|
+
row.turn_index >= fromTurn &&
|
|
31
|
+
row.turn_index <= toTurn
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async searchContextFull(): Promise<Array<ReceiptRow & { score: number }>> {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async getStats(): Promise<{ totalMessages: number; maxTurnIndex?: number }> {
|
|
40
|
+
return {
|
|
41
|
+
totalMessages: this.rows.length,
|
|
42
|
+
maxTurnIndex: this.rows.length > 0
|
|
43
|
+
? Math.max(...this.rows.map((row) => row.turn_index))
|
|
44
|
+
: undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
test("explicit-cue receipts identify only blocks that survive selection", async () => {
|
|
50
|
+
const engine = new ReceiptEngine([
|
|
51
|
+
{
|
|
52
|
+
id: 101,
|
|
53
|
+
session_id: "s",
|
|
54
|
+
turn_index: 7,
|
|
55
|
+
role: "user",
|
|
56
|
+
content: "first selected row",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 102,
|
|
60
|
+
session_id: "s",
|
|
61
|
+
turn_index: 7,
|
|
62
|
+
role: "assistant",
|
|
63
|
+
content: "second row that the deliberately narrow section budget rejects",
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
const receipts: EvidencePackSelectionReceipt[] = [];
|
|
67
|
+
const options = {
|
|
68
|
+
engine,
|
|
69
|
+
sessionId: "s",
|
|
70
|
+
query: "Review turn 7",
|
|
71
|
+
maxChars:
|
|
72
|
+
"## Explicit Cue Evidence".length +
|
|
73
|
+
2 +
|
|
74
|
+
"[s, turn 7, user]: first selected row".length,
|
|
75
|
+
maxItemChars: 200,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const baseline = await buildExplicitCueRecallSection(options);
|
|
79
|
+
const traced = await buildExplicitCueRecallSection({
|
|
80
|
+
...options,
|
|
81
|
+
onEvidenceSelected: (receipt) => receipts.push(receipt),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
assert.equal(traced, baseline);
|
|
85
|
+
assert.deepEqual(receipts.map((receipt) => receipt.item.archiveRowId), [101]);
|
|
86
|
+
assert.equal(
|
|
87
|
+
traced.slice(receipts[0]!.blockStart, receipts[0]!.blockEnd).includes(
|
|
88
|
+
"first selected row",
|
|
89
|
+
),
|
|
90
|
+
true,
|
|
91
|
+
);
|
|
92
|
+
assert.equal(JSON.stringify(receipts).includes("first selected row"), false);
|
|
93
|
+
assert.equal(JSON.stringify(receipts).includes("second row"), false);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("trajectory receipts retain row lineage only for emitted clipped lines", async () => {
|
|
97
|
+
const engine = new ReceiptEngine([
|
|
98
|
+
{
|
|
99
|
+
id: 201,
|
|
100
|
+
session_id: "ama",
|
|
101
|
+
turn_index: 1,
|
|
102
|
+
role: "user",
|
|
103
|
+
content: "[Action 1]: move right",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 202,
|
|
107
|
+
session_id: "ama",
|
|
108
|
+
turn_index: 1,
|
|
109
|
+
role: "assistant",
|
|
110
|
+
content: "[Observation 1]: reached the wall",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 203,
|
|
114
|
+
session_id: "ama",
|
|
115
|
+
turn_index: 2,
|
|
116
|
+
role: "user",
|
|
117
|
+
content: "[Action 2]: move left",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 204,
|
|
121
|
+
session_id: "ama",
|
|
122
|
+
turn_index: 2,
|
|
123
|
+
role: "assistant",
|
|
124
|
+
content: "[Observation 2]: reached the door",
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
const receipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
128
|
+
const options = {
|
|
129
|
+
engine,
|
|
130
|
+
sessionId: "ama",
|
|
131
|
+
query:
|
|
132
|
+
"What will be the resulting state at action 1? Provide the full observation.",
|
|
133
|
+
maxChars: 4_000,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const baseline = await buildTrajectoryAnalysisRecallSection(options);
|
|
137
|
+
const traced = await buildTrajectoryAnalysisRecallSection({
|
|
138
|
+
...options,
|
|
139
|
+
onLineSelected: (receipt) => receipts.push(receipt),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
assert.equal(traced, baseline);
|
|
143
|
+
const actionOne = receipts.find((receipt) =>
|
|
144
|
+
traced.slice(receipt.lineStart, receipt.lineEnd).startsWith("[Action 1]")
|
|
145
|
+
);
|
|
146
|
+
const observationOne = receipts.find((receipt) =>
|
|
147
|
+
traced.slice(receipt.lineStart, receipt.lineEnd).startsWith("[Observation 1]")
|
|
148
|
+
);
|
|
149
|
+
assert.ok(actionOne);
|
|
150
|
+
assert.ok(observationOne);
|
|
151
|
+
assert.equal(actionOne.lineageStatus, "exact");
|
|
152
|
+
assert.equal(observationOne.lineageStatus, "exact");
|
|
153
|
+
assert.deepEqual(actionOne.actionArchiveRowIds, [201]);
|
|
154
|
+
assert.deepEqual(actionOne.observationArchiveRowIds, []);
|
|
155
|
+
assert.deepEqual(observationOne.actionArchiveRowIds, []);
|
|
156
|
+
assert.deepEqual(observationOne.observationArchiveRowIds, [202]);
|
|
157
|
+
assert.equal(actionOne.actionArchiveRowIds.includes(203), false);
|
|
158
|
+
assert.equal(observationOne.observationArchiveRowIds.includes(204), false);
|
|
159
|
+
|
|
160
|
+
const clippedReceipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
161
|
+
const clipped = await buildTrajectoryAnalysisRecallSection({
|
|
162
|
+
...options,
|
|
163
|
+
maxChars: actionOne.lineStart + 8,
|
|
164
|
+
onLineSelected: (receipt) => clippedReceipts.push(receipt),
|
|
165
|
+
});
|
|
166
|
+
const partialAction = clippedReceipts.at(-1)!;
|
|
167
|
+
assert.equal(partialAction.lineStart, actionOne.lineStart);
|
|
168
|
+
assert.equal(partialAction.lineEnd, clipped.length);
|
|
169
|
+
assert.equal(partialAction.lineageStatus, "exact");
|
|
170
|
+
assert.deepEqual(partialAction.actionArchiveRowIds, [201]);
|
|
171
|
+
assert.equal(partialAction.actionArchiveRowIds.includes(203), false);
|
|
172
|
+
assert.equal(JSON.stringify(receipts).includes("move right"), false);
|
|
173
|
+
assert.equal(JSON.stringify(receipts).includes("reached the wall"), false);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("spatial derived-line receipts mark lineage unavailable without guessing siblings", async () => {
|
|
177
|
+
const engine = new ReceiptEngine([
|
|
178
|
+
{
|
|
179
|
+
id: 301,
|
|
180
|
+
session_id: "ama",
|
|
181
|
+
turn_index: 20,
|
|
182
|
+
role: "user",
|
|
183
|
+
content: "[Action 20]: right",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 302,
|
|
187
|
+
session_id: "ama",
|
|
188
|
+
turn_index: 20,
|
|
189
|
+
role: "assistant",
|
|
190
|
+
content: [
|
|
191
|
+
"[Observation 20]: Active rules:",
|
|
192
|
+
"baba is you",
|
|
193
|
+
"",
|
|
194
|
+
"Objects on the map:",
|
|
195
|
+
"rule `win` 3 step to the left",
|
|
196
|
+
].join("\n"),
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: 303,
|
|
200
|
+
session_id: "ama",
|
|
201
|
+
turn_index: 21,
|
|
202
|
+
role: "user",
|
|
203
|
+
content: "[Action 21]: left",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 304,
|
|
207
|
+
session_id: "ama",
|
|
208
|
+
turn_index: 21,
|
|
209
|
+
role: "assistant",
|
|
210
|
+
content: [
|
|
211
|
+
"[Observation 21]: Active rules:",
|
|
212
|
+
"baba is you",
|
|
213
|
+
"",
|
|
214
|
+
"Objects on the map:",
|
|
215
|
+
"rule `win` 2 step to the left",
|
|
216
|
+
].join("\n"),
|
|
217
|
+
},
|
|
218
|
+
]);
|
|
219
|
+
const receipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
220
|
+
const options = {
|
|
221
|
+
engine,
|
|
222
|
+
sessionId: "ama",
|
|
223
|
+
query:
|
|
224
|
+
"Between steps 20 and 21, the rule 'win' block's relative position changed from 3 step to the left to 2 step to the left. What was the actual movement?",
|
|
225
|
+
maxChars: 4_000,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const baseline = await buildTrajectoryAnalysisRecallSection(options);
|
|
229
|
+
const traced = await buildTrajectoryAnalysisRecallSection({
|
|
230
|
+
...options,
|
|
231
|
+
onLineSelected: (receipt) => receipts.push(receipt),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
assert.equal(traced, baseline);
|
|
235
|
+
const heading = receipts.find((receipt) =>
|
|
236
|
+
traced.slice(receipt.lineStart, receipt.lineEnd) === "Relative-position movement cues:"
|
|
237
|
+
);
|
|
238
|
+
const movement = receipts.find((receipt) =>
|
|
239
|
+
traced.slice(receipt.lineStart, receipt.lineEnd).startsWith("Observation 20->21:")
|
|
240
|
+
);
|
|
241
|
+
assert.ok(heading);
|
|
242
|
+
assert.ok(movement);
|
|
243
|
+
assert.equal(heading.lineageStatus, "exact");
|
|
244
|
+
assert.deepEqual(heading.actionArchiveRowIds, []);
|
|
245
|
+
assert.deepEqual(heading.observationArchiveRowIds, []);
|
|
246
|
+
assert.equal(movement.lineageStatus, "unavailable");
|
|
247
|
+
assert.deepEqual(movement.actionArchiveRowIds, []);
|
|
248
|
+
assert.deepEqual(movement.observationArchiveRowIds, []);
|
|
249
|
+
assert.equal(JSON.stringify(movement).includes("rule win"), false);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("trajectory receipts mark id-less and partially id-less direct sources unavailable", async () => {
|
|
253
|
+
const engine = new ReceiptEngine([
|
|
254
|
+
{
|
|
255
|
+
session_id: "ama",
|
|
256
|
+
turn_index: 1,
|
|
257
|
+
role: "user",
|
|
258
|
+
content: "[Action 1]: move right",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: 402,
|
|
262
|
+
session_id: "ama",
|
|
263
|
+
turn_index: 1,
|
|
264
|
+
role: "assistant",
|
|
265
|
+
content: "[Observation 1]: reached the wall",
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
session_id: "ama",
|
|
269
|
+
turn_index: 2,
|
|
270
|
+
role: "user",
|
|
271
|
+
content: "[Action 2]: move left",
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
session_id: "ama",
|
|
275
|
+
turn_index: 2,
|
|
276
|
+
role: "assistant",
|
|
277
|
+
content: "[Observation 2]: reached the door",
|
|
278
|
+
},
|
|
279
|
+
]);
|
|
280
|
+
const receipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
281
|
+
const text = await buildTrajectoryAnalysisRecallSection({
|
|
282
|
+
engine,
|
|
283
|
+
sessionId: "ama",
|
|
284
|
+
query: "Compare steps 1 and 2 and provide the full observations.",
|
|
285
|
+
maxChars: 4_000,
|
|
286
|
+
onLineSelected: (receipt) => receipts.push(receipt),
|
|
287
|
+
});
|
|
288
|
+
const findLine = (prefix: string) => receipts.find((receipt) =>
|
|
289
|
+
text.slice(receipt.lineStart, receipt.lineEnd).startsWith(prefix)
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const idLessAction = findLine("[Action 1]");
|
|
293
|
+
const identifiedObservation = findLine("[Observation 1]");
|
|
294
|
+
const idLessObservation = findLine("[Observation 2]");
|
|
295
|
+
assert.ok(idLessAction);
|
|
296
|
+
assert.ok(identifiedObservation);
|
|
297
|
+
assert.ok(idLessObservation);
|
|
298
|
+
assert.equal(idLessAction.lineageStatus, "unavailable");
|
|
299
|
+
assert.deepEqual(idLessAction.actionArchiveRowIds, []);
|
|
300
|
+
assert.equal(identifiedObservation.lineageStatus, "exact");
|
|
301
|
+
assert.deepEqual(identifiedObservation.observationArchiveRowIds, [402]);
|
|
302
|
+
assert.equal(idLessObservation.lineageStatus, "unavailable");
|
|
303
|
+
assert.deepEqual(idLessObservation.observationArchiveRowIds, []);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
test("inferred-location receipts identify only the action that establishes the final location", async () => {
|
|
307
|
+
const engine = new ReceiptEngine([
|
|
308
|
+
{
|
|
309
|
+
id: 501,
|
|
310
|
+
session_id: "ama",
|
|
311
|
+
turn_index: 1,
|
|
312
|
+
role: "user",
|
|
313
|
+
content: "[Action 1]: open cabinet 1",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
id: 502,
|
|
317
|
+
session_id: "ama",
|
|
318
|
+
turn_index: 2,
|
|
319
|
+
role: "user",
|
|
320
|
+
content: "[Action 2]: move cabinet 1 to kitchen",
|
|
321
|
+
},
|
|
322
|
+
]);
|
|
323
|
+
const receipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
324
|
+
const text = await buildTrajectoryAnalysisRecallSection({
|
|
325
|
+
engine,
|
|
326
|
+
sessionId: "ama",
|
|
327
|
+
query:
|
|
328
|
+
"What is the state of cabinet 1 at step 2 and what was its prior whole changes history?",
|
|
329
|
+
maxChars: 4_000,
|
|
330
|
+
onLineSelected: (receipt) => receipts.push(receipt),
|
|
331
|
+
});
|
|
332
|
+
const location = receipts.find((receipt) =>
|
|
333
|
+
text.slice(receipt.lineStart, receipt.lineEnd).startsWith(
|
|
334
|
+
"Inferred cabinet 1 location at step 2: kitchen",
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
assert.ok(location);
|
|
339
|
+
assert.equal(location.lineageStatus, "exact");
|
|
340
|
+
assert.deepEqual(location.actionArchiveRowIds, [502]);
|
|
341
|
+
assert.equal(location.actionArchiveRowIds.includes(501), false);
|
|
342
|
+
assert.deepEqual(location.observationArchiveRowIds, []);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test("stateful inventory-change lines do not publish partial current-row lineage", async () => {
|
|
346
|
+
const engine = new ReceiptEngine([
|
|
347
|
+
{
|
|
348
|
+
id: 601,
|
|
349
|
+
session_id: "ama",
|
|
350
|
+
turn_index: 1,
|
|
351
|
+
role: "user",
|
|
352
|
+
content: "[Action 1]: take apple 1 from shelf 1",
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
id: 602,
|
|
356
|
+
session_id: "ama",
|
|
357
|
+
turn_index: 2,
|
|
358
|
+
role: "user",
|
|
359
|
+
content: "[Action 2]: place apple 1 into bowl 1",
|
|
360
|
+
},
|
|
361
|
+
]);
|
|
362
|
+
const receipts: TrajectoryAnalysisLineReceipt[] = [];
|
|
363
|
+
const text = await buildTrajectoryAnalysisRecallSection({
|
|
364
|
+
engine,
|
|
365
|
+
sessionId: "ama",
|
|
366
|
+
query: "What changes occurred to the inventory throughout the trajectory?",
|
|
367
|
+
maxChars: 4_000,
|
|
368
|
+
onLineSelected: (receipt) => receipts.push(receipt),
|
|
369
|
+
});
|
|
370
|
+
const placed = receipts.find((receipt) =>
|
|
371
|
+
text.slice(receipt.lineStart, receipt.lineEnd).startsWith(
|
|
372
|
+
"[Action 2]: place apple 1 into bowl 1 => inventory removed apple 1",
|
|
373
|
+
)
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
assert.ok(placed);
|
|
377
|
+
assert.equal(placed.lineageStatus, "unavailable");
|
|
378
|
+
assert.deepEqual(placed.actionArchiveRowIds, []);
|
|
379
|
+
assert.deepEqual(placed.observationArchiveRowIds, []);
|
|
380
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildEvidencePack, type EvidencePackItem } from "./evidence-pack.js";
|
|
2
2
|
import type { ExplicitCueRecallEngine } from "./explicit-cue-recall.js";
|
|
3
|
+
import { isSameLcmRow, lcmEvidenceIdentity } from "./lcm/evidence-identity.js";
|
|
3
4
|
import {
|
|
4
5
|
gatherAcrossReadSessions,
|
|
5
6
|
resolveLcmReadSessionIds,
|
|
@@ -252,19 +253,26 @@ async function collectGuidanceItems(
|
|
|
252
253
|
searchWindowTokens,
|
|
253
254
|
);
|
|
254
255
|
const candidates = expanded.length > 0
|
|
255
|
-
? expanded.map((message) =>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
:
|
|
265
|
-
|
|
256
|
+
? expanded.map((message) => {
|
|
257
|
+
const matchesSearchHit = isSameLcmRow(
|
|
258
|
+
message,
|
|
259
|
+
result.session_id,
|
|
260
|
+
result,
|
|
261
|
+
result.session_id,
|
|
262
|
+
);
|
|
263
|
+
return {
|
|
264
|
+
...lcmEvidenceIdentity(message, result.session_id),
|
|
265
|
+
sessionId: message.session_id ?? result.session_id,
|
|
266
|
+
turnIndex: message.turn_index,
|
|
267
|
+
role: message.role,
|
|
268
|
+
content: message.content,
|
|
269
|
+
...(matchesSearchHit && typeof result.score === "number"
|
|
270
|
+
? { score: result.score }
|
|
271
|
+
: {}),
|
|
272
|
+
};
|
|
273
|
+
})
|
|
266
274
|
: [{
|
|
267
|
-
|
|
275
|
+
...lcmEvidenceIdentity(result, result.session_id),
|
|
268
276
|
sessionId: result.session_id,
|
|
269
277
|
turnIndex: result.turn_index,
|
|
270
278
|
role: result.role,
|
|
@@ -331,8 +339,8 @@ async function collectGuidanceScanItems(
|
|
|
331
339
|
for (const message of messages) {
|
|
332
340
|
if (!isGuidanceEvidence(message.content, options.query, intents, options.forceGeneric === true)) continue;
|
|
333
341
|
items.push({
|
|
334
|
-
|
|
335
|
-
sessionId: options.sessionId,
|
|
342
|
+
...lcmEvidenceIdentity(message, options.sessionId),
|
|
343
|
+
sessionId: message.session_id ?? options.sessionId,
|
|
336
344
|
turnIndex: message.turn_index,
|
|
337
345
|
role: message.role,
|
|
338
346
|
content: message.content,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
gatherAcrossReadSessions,
|
|
9
9
|
resolveLcmReadSessionIds,
|
|
10
10
|
} from "./lcm-fallback-read.js";
|
|
11
|
+
import { isSameLcmRow, lcmEvidenceIdentity } from "./lcm/evidence-identity.js";
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
14
|
unifiedDedupeAndRank,
|
|
@@ -124,27 +125,35 @@ async function collectTargetedFactSearchItems(
|
|
|
124
125
|
result.turn_index + searchWindowAfter,
|
|
125
126
|
searchWindowTokens,
|
|
126
127
|
);
|
|
128
|
+
const searchIdentity = lcmEvidenceIdentity(result, result.session_id);
|
|
127
129
|
const searchHit: EvidencePackItem = {
|
|
128
|
-
|
|
130
|
+
...searchIdentity,
|
|
129
131
|
sessionId: result.session_id,
|
|
130
132
|
turnIndex: result.turn_index,
|
|
131
133
|
role: result.role,
|
|
132
134
|
content: result.content,
|
|
133
135
|
...(typeof result.score === "number" ? { score: result.score } : {}),
|
|
134
136
|
};
|
|
135
|
-
const candidates: EvidencePackItem[] = expanded.map((message) =>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
137
|
+
const candidates: EvidencePackItem[] = expanded.map((message) => {
|
|
138
|
+
const matchesSearchHit = isSameLcmRow(
|
|
139
|
+
message,
|
|
140
|
+
result.session_id,
|
|
141
|
+
result,
|
|
142
|
+
result.session_id,
|
|
143
|
+
);
|
|
144
|
+
return {
|
|
145
|
+
...lcmEvidenceIdentity(message, result.session_id),
|
|
146
|
+
sessionId: message.session_id ?? result.session_id,
|
|
147
|
+
turnIndex: message.turn_index,
|
|
148
|
+
role: message.role,
|
|
149
|
+
content: message.content,
|
|
150
|
+
...(matchesSearchHit && typeof result.score === "number"
|
|
151
|
+
? { score: result.score }
|
|
152
|
+
: {}),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
const hitIndex = expanded.findIndex((message) =>
|
|
156
|
+
isSameLcmRow(message, result.session_id, result, result.session_id)
|
|
148
157
|
);
|
|
149
158
|
if (hitIndex >= 0) {
|
|
150
159
|
candidates[hitIndex] = searchHit;
|
|
@@ -200,8 +209,8 @@ async function collectTargetedFactScanItems(
|
|
|
200
209
|
for (const message of messages) {
|
|
201
210
|
if (!isTargetedFactEvidence(message.content, options.query)) continue;
|
|
202
211
|
items.push({
|
|
203
|
-
|
|
204
|
-
sessionId: options.sessionId,
|
|
212
|
+
...lcmEvidenceIdentity(message, options.sessionId),
|
|
213
|
+
sessionId: message.session_id ?? options.sessionId,
|
|
205
214
|
turnIndex: message.turn_index,
|
|
206
215
|
role: message.role,
|
|
207
216
|
content: message.content,
|