mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat: add a military awareness tool
This commit is contained in:
1 parent
28cfd39d1a
commit
a747b8a4e0
5 files changed
+197
-19
No files matched your search
+110
-16
@@ -1,13 +1,25 @@
|
||||
/** Composite queries that combine other tools' answers for one area. */
|
||||
|
||||
import { defineTool, ToolError } from '../catalog.js';
|
||||
import { AREA_SCHEMA, areaCenter, resolveArea } from '../area.js';
|
||||
import {
|
||||
AREA_SCHEMA,
|
||||
POINT_SCHEMA,
|
||||
areaCenter,
|
||||
resolveArea,
|
||||
resolvePoint,
|
||||
} from '../area.js';
|
||||
import { aircraftInArea } from './aviation.js';
|
||||
import { getCyclones, getWeather } from './environment.js';
|
||||
import {
|
||||
findMilitaryInstallations,
|
||||
getCyclones,
|
||||
getWeather,
|
||||
} from './environment.js';
|
||||
import { getActiveFires, getEarthquakes } from './hazards.js';
|
||||
import { vesselsInArea } from './maritime.js';
|
||||
|
||||
const SECTION_LIMIT = 5;
|
||||
const AWARENESS_LIMIT = 10;
|
||||
const AWARENESS_RADIUS_KM = 250;
|
||||
|
||||
/** Brief sections: the tool each one reuses and the services it needs. */
|
||||
const SECTIONS = [
|
||||
@@ -45,14 +57,37 @@ const SECTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Run every section whose services are supplied. A failing section is
|
||||
* reported as unavailable instead of failing the brief.
|
||||
*/
|
||||
async function buildBrief(args, { services, signal }) {
|
||||
const resolved = await resolveArea(args.area, { services, signal });
|
||||
// Sections receive the resolved box so a place name is looked up once.
|
||||
const area = {
|
||||
/** Military contacts around a point, as the app's military awareness panel. */
|
||||
const AWARENESS_SECTIONS = [
|
||||
{
|
||||
key: 'military_aircraft',
|
||||
tool: aircraftInArea,
|
||||
args: (area) => ({
|
||||
area: area.argument,
|
||||
military: true,
|
||||
limit: AWARENESS_LIMIT,
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'aircraft',
|
||||
tool: aircraftInArea,
|
||||
args: (area) => ({ area: area.argument, limit: AWARENESS_LIMIT }),
|
||||
},
|
||||
{
|
||||
key: 'vessels',
|
||||
tool: vesselsInArea,
|
||||
args: (area) => ({ area: area.argument, limit: AWARENESS_LIMIT }),
|
||||
},
|
||||
{
|
||||
key: 'installations',
|
||||
tool: findMilitaryInstallations,
|
||||
args: (area) => ({ area: area.argument, limit: AWARENESS_LIMIT }),
|
||||
},
|
||||
];
|
||||
|
||||
/** The resolved area, plus the argument sections receive in its place. */
|
||||
function sectionArea(resolved) {
|
||||
return {
|
||||
...resolved,
|
||||
argument: resolved.center
|
||||
? {
|
||||
@@ -64,8 +99,15 @@ async function buildBrief(args, { services, signal }) {
|
||||
bbox: [resolved.west, resolved.south, resolved.east, resolved.north],
|
||||
},
|
||||
};
|
||||
const center = areaCenter(resolved);
|
||||
const sections = SECTIONS.filter(({ tool }) =>
|
||||
}
|
||||
|
||||
/**
|
||||
* Run every section whose services are supplied. A failing section is
|
||||
* reported as unavailable instead of failing the whole answer.
|
||||
*/
|
||||
async function runSections(all, area, { services, signal }) {
|
||||
const center = areaCenter(area);
|
||||
const sections = all.filter(({ tool }) =>
|
||||
tool.requires.every((key) => services[key] != null),
|
||||
);
|
||||
const results = await Promise.allSettled(
|
||||
@@ -74,22 +116,32 @@ async function buildBrief(args, { services, signal }) {
|
||||
),
|
||||
);
|
||||
signal?.throwIfAborted();
|
||||
const brief = {};
|
||||
const answers = {};
|
||||
const lines = [];
|
||||
sections.forEach(({ key }, index) => {
|
||||
const result = results[index];
|
||||
if (result.status === 'fulfilled') {
|
||||
brief[key] = { summary: result.value.summary, data: result.value.data };
|
||||
answers[key] = { summary: result.value.summary, data: result.value.data };
|
||||
lines.push(result.value.summary);
|
||||
} else {
|
||||
const known = result.reason instanceof ToolError;
|
||||
brief[key] = {
|
||||
answers[key] = {
|
||||
unavailable: true,
|
||||
reason: known ? result.reason.message : 'unavailable right now',
|
||||
};
|
||||
}
|
||||
});
|
||||
return { area: resolved, center, brief, lines };
|
||||
return { center, answers, lines };
|
||||
}
|
||||
|
||||
async function buildBrief(args, { services, signal }) {
|
||||
// Sections receive the resolved box so a place name is looked up once.
|
||||
const area = sectionArea(await resolveArea(args.area, { services, signal }));
|
||||
const { center, answers, lines } = await runSections(SECTIONS, area, {
|
||||
services,
|
||||
signal,
|
||||
});
|
||||
return { area, center, brief: answers, lines };
|
||||
}
|
||||
|
||||
export const situationBrief = defineTool({
|
||||
@@ -143,3 +195,45 @@ export const getHudCaption = defineTool({
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const militaryAwareness = defineTool({
|
||||
name: 'military_awareness',
|
||||
title: 'Military awareness',
|
||||
description:
|
||||
'Military contacts around a location, as the military awareness panel ' +
|
||||
'shows them: military aircraft, other aircraft, ships and mapped ' +
|
||||
`military installations within ${AWARENESS_RADIUS_KM} km by default, ` +
|
||||
'each nearest first. Sections that are unavailable are marked as such.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: POINT_SCHEMA,
|
||||
radius_km: { type: 'number', minimum: 1, maximum: AWARENESS_RADIUS_KM },
|
||||
},
|
||||
required: ['location'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
requires: ['military'],
|
||||
async run(args, { services, signal }) {
|
||||
const point = await resolvePoint(args.location, { services, signal });
|
||||
const radiusKm = args.radius_km ?? AWARENESS_RADIUS_KM;
|
||||
const area = sectionArea(
|
||||
await resolveArea(
|
||||
{ lat: point.lat, lon: point.lon, radius_km: radiusKm },
|
||||
{ services, signal },
|
||||
),
|
||||
);
|
||||
const { answers, lines } = await runSections(AWARENESS_SECTIONS, area, {
|
||||
services,
|
||||
signal,
|
||||
});
|
||||
return {
|
||||
summary: `Military awareness within ${radiusKm} km of ${point.label}: ${lines.join(' ')}`,
|
||||
data: {
|
||||
location: point,
|
||||
radius_km: radiusKm,
|
||||
sections: answers,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user