fix: keep aircraft search results when one feed is down

find_aircraft failed whenever either feed failed. It now answers from the
feeds that responded, names the ones that did not, and searches only the
military feed for registrations, the only feed that reports them.
This commit is contained in:
Sameh Khamis committed 2026-10-02 15:21:36 -07:00
1 parent 963c791a5c
commit 61974848fe
2 files changed
+70 -9

No files matched your search

+31 -9
View File
@@ -161,13 +161,31 @@ export const findAircraft = defineTool({
icao24: 'id',
registration: 'registration',
}[key];
const feeds = [services.aircraft, services.military].filter(Boolean);
const snapshots = await Promise.all(
feeds.map((feed) => feed.getSnapshot({}, { signal })),
// Only the military feed reports registrations.
const feeds = [
...(key === 'registration'
? []
: [{ name: 'civil', feed: services.aircraft }]),
{ name: 'military', feed: services.military },
].filter(({ feed }) => feed);
if (!feeds.length)
throw new ToolError(
'unavailable',
'The military aircraft feed is not available here',
);
const settled = await Promise.allSettled(
feeds.map(({ feed }) => feed.getSnapshot({}, { signal })),
);
signal?.throwIfAborted();
// A search succeeds when any feed answers; missing feeds are named.
const unavailable = feeds
.filter((_, index) => settled[index].status === 'rejected')
.map(({ name }) => name);
if (unavailable.length === feeds.length) throw settled[0].reason;
const seen = new Set();
const rows = snapshots
.flatMap((snapshot) => snapshot.records)
const rows = settled
.filter((result) => result.status === 'fulfilled')
.flatMap((result) => result.value.records)
.filter(
(record) =>
String(record[field] || '')
@@ -177,10 +195,14 @@ export const findAircraft = defineTool({
.filter((record) => !seen.has(record.id) && seen.add(record.id))
.map((record) => aircraftRow(record));
return {
summary: rows.length
? `Found ${countNoun(rows.length, 'aircraft', 'aircraft')} with ${key} ${wanted}.`
: `No aircraft with ${key} ${wanted} is currently reported.`,
data: capRows(rows, args.limit),
summary:
(rows.length
? `Found ${countNoun(rows.length, 'aircraft', 'aircraft')} with ${key} ${wanted}.`
: `No aircraft with ${key} ${wanted} is currently reported.`) +
(unavailable.length
? ` The ${unavailable.join(' and ')} feed did not answer.`
: ''),
data: { ...capRows(rows, args.limit), unavailable_feeds: unavailable },
};
},
});
+39
View File
@@ -298,3 +298,42 @@ test('live source failures become tool errors with retry guidance', async () =>
error.message === 'OpenSky rate limited',
);
});
test('aircraft searches keep the feeds that answered and name the others', async () => {
const down = {
getSnapshot: async () => {
throw new LiveSourceError('unavailable', 'OpenSky HTTP 503');
},
};
const military = feed([
record('ae1234', 38, -77, { callsign: 'RCH123', registration: '05-5140' }),
]);
const catalog = composeCatalog({
tools: coreTools,
services: { aircraft: down, military },
});
const byCallsign = await catalog.call('find_aircraft', {
callsign: 'rch123',
});
assert.equal(
byCallsign.summary,
'Found 1 aircraft with callsign RCH123. The civil feed did not answer.',
);
assert.deepEqual(byCallsign.data.unavailable_feeds, ['civil']);
const civil = feed([]);
const byRegistration = await composeCatalog({
tools: coreTools,
services: { aircraft: civil, military },
}).call('find_aircraft', { registration: '05-5140' });
assert.equal(byRegistration.data.rows[0].id, 'ae1234');
assert.deepEqual(byRegistration.data.unavailable_feeds, []);
assert.equal(civil.calls.length, 0);
await assert.rejects(
composeCatalog({
tools: coreTools,
services: { aircraft: down, military: down },
}).call('find_aircraft', { callsign: 'RCH123' }),
(error) =>
error.code === 'unavailable' && error.message === 'OpenSky HTTP 503',
);
});