mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix: wait briefly for installation names before answering
Installation tile results can arrive before the name pack, and the tool answered with generic names such as "Military area" where a moment later it would say "Camp Mabry". It now waits up to five seconds for the named result and says when names are still loading.
This commit is contained in:
1 parent
9e4cc9095b
commit
13f8fa7c8e
2 files changed
+84
-2
No files matched your search
@@ -340,6 +340,33 @@ export const getTerrainHeight = defineTool({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const NAMES_WAIT_MS = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value `promise` resolves to within `ms`, or null when it takes longer
|
||||||
|
* or fails. Rejects only when `signal` aborts.
|
||||||
|
*/
|
||||||
|
function settleWithin(promise, ms, signal) {
|
||||||
|
signal?.throwIfAborted();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const done = (value) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
signal?.removeEventListener('abort', abort);
|
||||||
|
resolve(value);
|
||||||
|
};
|
||||||
|
const abort = () => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject(signal.reason);
|
||||||
|
};
|
||||||
|
const timer = setTimeout(() => done(null), ms);
|
||||||
|
signal?.addEventListener('abort', abort, { once: true });
|
||||||
|
Promise.resolve(promise).then(
|
||||||
|
(value) => done(value ?? null),
|
||||||
|
() => done(null),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const findMilitaryInstallations = defineTool({
|
export const findMilitaryInstallations = defineTool({
|
||||||
name: 'find_military_installations',
|
name: 'find_military_installations',
|
||||||
title: 'Military installations',
|
title: 'Military installations',
|
||||||
@@ -365,11 +392,23 @@ export const findMilitaryInstallations = defineTool({
|
|||||||
`The area must be at most ${MAX_SITE_BOX_DEGREES}° on each side and not cross the antimeridian`,
|
`The area must be at most ${MAX_SITE_BOX_DEGREES}° on each side and not cross the antimeridian`,
|
||||||
);
|
);
|
||||||
const center = areaCenter(area);
|
const center = areaCenter(area);
|
||||||
const result = await services.installations.getMappedSites(area, {
|
let result = await services.installations.getMappedSites(area, {
|
||||||
exact: true,
|
exact: true,
|
||||||
thinned: false,
|
thinned: false,
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
|
// Tile results can arrive before the name pack; wait briefly for the
|
||||||
|
// named version rather than answer with generic names.
|
||||||
|
let namesPending = false;
|
||||||
|
if (result.enrichment) {
|
||||||
|
const named = await settleWithin(
|
||||||
|
result.enrichment,
|
||||||
|
NAMES_WAIT_MS,
|
||||||
|
signal,
|
||||||
|
);
|
||||||
|
if (named) result = named;
|
||||||
|
else namesPending = true;
|
||||||
|
}
|
||||||
// A saturated source returned only part of the mapped sites.
|
// A saturated source returned only part of the mapped sites.
|
||||||
const complete = !result.saturated;
|
const complete = !result.saturated;
|
||||||
const rows = (result.records || [])
|
const rows = (result.records || [])
|
||||||
@@ -388,13 +427,18 @@ export const findMilitaryInstallations = defineTool({
|
|||||||
distance_km: round(distanceKm(center, point), 1),
|
distance_km: round(distanceKm(center, point), 1),
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => a.distance_km - b.distance_km);
|
.sort((a, b) => a.distance_km - b.distance_km);
|
||||||
|
const notes = [
|
||||||
|
...(complete ? [] : ['partial: the source returned only some sites']),
|
||||||
|
...(namesPending ? ['site names are still loading'] : []),
|
||||||
|
];
|
||||||
return {
|
return {
|
||||||
summary:
|
summary:
|
||||||
`${countNoun(rows.length, 'mapped military installation')} in ${area.label}` +
|
`${countNoun(rows.length, 'mapped military installation')} in ${area.label}` +
|
||||||
(complete ? '.' : ' (partial: the source returned only some sites).'),
|
(notes.length ? ` (${notes.join('; ')}).` : '.'),
|
||||||
data: {
|
data: {
|
||||||
...capRows(rows, args.limit),
|
...capRows(rows, args.limit),
|
||||||
complete,
|
complete,
|
||||||
|
names_pending: namesPending,
|
||||||
source: result.source ?? null,
|
source: result.source ?? null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -742,3 +742,41 @@ test('stale weather and partial fire data reach answers and the HUD caption', as
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('installation names wait for the name pack, briefly', async (t) => {
|
||||||
|
const site = (name) => ({
|
||||||
|
id: 'osm:9',
|
||||||
|
kind: 'installation',
|
||||||
|
name,
|
||||||
|
latitude: 30.31,
|
||||||
|
longitude: -97.76,
|
||||||
|
});
|
||||||
|
const source = (enrichment) => ({
|
||||||
|
getMappedSites: async () => ({
|
||||||
|
source: 'OpenStreetMap tiles',
|
||||||
|
records: [site('Military area')],
|
||||||
|
enrichment,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const area = { lat: 30.31, lon: -97.76, radius_km: 5 };
|
||||||
|
const named = await catalogWith({
|
||||||
|
installations: source(
|
||||||
|
Promise.resolve({
|
||||||
|
source: 'OpenStreetMap tiles',
|
||||||
|
records: [site('Camp Mabry')],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}).call('find_military_installations', { area });
|
||||||
|
assert.equal(named.data.rows[0].name, 'Camp Mabry');
|
||||||
|
assert.equal(named.data.names_pending, false);
|
||||||
|
t.mock.timers.enable({ apis: ['setTimeout'] });
|
||||||
|
const pending = catalogWith({
|
||||||
|
installations: source(new Promise(() => {})),
|
||||||
|
}).call('find_military_installations', { area });
|
||||||
|
await new Promise((resolve) => setImmediate(resolve));
|
||||||
|
t.mock.timers.tick(5000);
|
||||||
|
const slow = await pending;
|
||||||
|
assert.equal(slow.data.rows[0].name, 'Military area');
|
||||||
|
assert.equal(slow.data.names_pending, true);
|
||||||
|
assert.match(slow.summary, /site names are still loading\)\.$/);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user