fix(voice): keep the area in follow-ups on OSM places

osm_query handed its places to the analyst with no presentation, so "which of
those have emergency?" after "hospitals in Kathmandu" was answered as "anywhere
in the loaded data". The handoff now carries the scope the places were found
in ("inside Kathmandu" with its areaId, or "in view"), as an analyst count over
that area would.
This commit is contained in:
Manjunath committed 2026-11-03 17:27:32 +05:30
1 parent 451be8e3b7
commit 474cce51eb
5 files changed
+71 -9

No files matched your search

+7 -2
View File
@@ -1164,11 +1164,16 @@ export function createAnalystEngine(providers) {
* so a follow-up filters exactly what the user just heard about.
* @param {string} layerKey Queryable layer the rows belong to.
* @param {Array<object>} rows Records in that layer's analyst shape.
* @param {{scope?: string}} [options]
* @param {{scope?: string, presentation?: object|null}} [options]
* `presentation` is how the set was scoped ("inside Kathmandu"), so a
* follow-up names the same scope instead of "anywhere".
*/
remember(layerKey, rows, { scope = 'handoff' } = {}) {
remember(layerKey, rows, { scope = 'handoff', presentation = null } = {}) {
if (!ANALYST_LAYERS[layerKey] || !Array.isArray(rows)) return false;
lastResult = {
...(presentation
? { presentation: structuredClone(presentation) }
: {}),
matched: [{ key: layerKey, rows: rows.slice() }],
layerKeys: [layerKey],
coverage: {
+26
View File
@@ -1176,3 +1176,29 @@ test('analyst: without an area provider the area scopes refuse plainly', async (
assert.equal(r.ok, false);
assert.equal(r.code, 'AREA_UNAVAILABLE');
});
test('a follow-up on handed-off places keeps the area they were found in', async () => {
const rows = [
{ id: 'node/1', lat: 27.7, lon: 85.3, name: 'Bir Hospital', kind: 'hospital', emergency: 'yes' },
{ id: 'node/2', lat: 27.71, lon: 85.31, name: 'Teaching Hospital', kind: 'hospital', emergency: 'no' },
];
const engine = createAnalystEngine({
getRecords: (key) => (key === 'osm-places' ? rows : []),
resolveRegionRing: async () => null,
getViewContext: () => ({ lat: 27.7, lon: 85.3, viewRadiusKm: 20 }),
});
assert.equal(
engine.remember('osm-places', rows, {
presentation: { scopeLabel: 'inside Kathmandu', coverageScope: 'area:area-1', areaId: 'area-1' },
}),
true,
);
const result = await engine.query({
layers: ['osm-places'],
followUp: true,
filters: [{ field: 'emergency', op: 'eq', value: 'yes' }],
});
assert.equal(result.count, 1);
assert.equal(result.scopeLabel, 'inside Kathmandu');
assert.equal(result.coverage.scope, 'area:area-1');
});