Files
gods-eye-view/src/tools/queries/media.test.mjs
T
Rudy Mizrahi Celekli 2fd1b4323c fix(tools): identify historical camera fallback imagery (#1118)
The CCTV frame proxy marks a Street View fallback with X-CCTV-Source, but the portable source dropped the header and get_cctv_snapshot always reported a current view credited to the camera's agency. The source now keeps the recognised provenance, and the tool labels Street View frames as historical Google imagery, refuses synthetic placeholders, and reports unknown provenance without claiming a current view.
2026-10-16 17:06:34 -07:00

512 lines
15 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { composeCatalog, coreTools } from '../index.js';
import { createMcpServer } from '../mcp/index.js';
const cameras = [
{
id: 'austin-1',
name: 'Congress at 6th',
city: 'Austin',
provider: 'City of Austin',
lat: 30.2685,
lon: -97.7425,
headingDeg: 180,
feedType: 'image',
credit: 'City of Austin',
},
{
id: 'austin-2',
name: 'Lamar at 5th',
city: 'Austin',
provider: 'City of Austin',
lat: 30.2695,
lon: -97.7535,
headingDeg: 90,
feedType: 'image',
credit: '',
},
{ id: 'far', name: 'Elsewhere', city: 'Oslo', lat: 59.9, lon: 10.7 },
{ id: 'no-position', name: 'Unplaced' },
];
const PNG = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
const cctv = (
frame = {
contentType: 'image/png',
bytes: PNG,
sourceKind: 'upstream-image',
},
) => ({
frames: [],
async getCatalog() {
return { sources: cameras };
},
async getFrame(camera) {
this.frames.push(camera.id);
return frame;
},
});
const downtown = { lat: 30.2672, lon: -97.7431, radius_km: 3 };
test('cameras in an area are listed nearest first', async () => {
const catalog = composeCatalog({
tools: coreTools,
services: { cctv: cctv() },
});
const result = await catalog.call('find_cctv_cameras', { area: downtown });
assert.equal(
result.summary,
'2 public cameras in 3 km around 30.267, -97.743.',
);
assert.deepEqual(
result.data.rows.map((row) => row.id),
['austin-1', 'austin-2'],
);
assert.deepEqual(result.data.rows[0], {
id: 'austin-1',
name: 'Congress at 6th',
city: 'Austin',
provider: 'City of Austin',
lat: 30.2685,
lon: -97.7425,
heading_deg: 180,
feed_type: 'image',
credit: 'City of Austin',
distance_km: 0.16,
});
assert.equal(result.data.rows[1].credit, null);
});
test('a snapshot returns the frame as an image with its credit', async () => {
const source = cctv();
const catalog = composeCatalog({
tools: coreTools,
services: { cctv: source },
});
const result = await catalog.call('get_cctv_snapshot', {
camera_id: 'austin-1',
});
assert.equal(
result.summary,
'Current view from Congress at 6th in Austin, courtesy of City of Austin.',
);
assert.deepEqual(result.images, [
{ mimeType: 'image/png', data: 'iVBORw0KGgo=' },
]);
assert.equal(result.data.bytes, 8);
assert.deepEqual(source.frames, ['austin-1']);
const server = createMcpServer({ catalog, name: 'test', version: '1' });
const response = await server.handle({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: { name: 'get_cctv_snapshot', arguments: { camera_id: 'austin-1' } },
});
assert.deepEqual(response.result.content[2], {
type: 'image',
data: 'iVBORw0KGgo=',
mimeType: 'image/png',
});
});
test('mounted camera fallback provenance survives the source and MCP image result', async (t) => {
const { cctvProxy } = await import('../../../server/providers/cctv.js');
const { createCctvSource } = await import('../../layers/cctv/source.js');
const camera = {
id: 'fixture-camera',
name: 'Fixture crossing',
city: 'Fixture City',
provider: 'Fixture transport agency',
credit: 'Fixture transport agency',
lat: 30.2685,
lon: -97.7425,
headingDeg: 180,
fovDeg: 60,
url: 'https://camera.example/current.png',
feedType: 'image',
};
const environment = {
CCTV_SOURCES_JSON: JSON.stringify([camera]),
CCTV_PREFER_AUSTIN: '0',
CCTV_FORCE_AUSTIN: '0',
CCTV_SOURCES_FILE: 'missing-cctv-provenance-fixture.json',
GOOGLE_MAPS_SERVER_API_KEY: 'fixture-key',
GOOGLE_MAPS_API_KEY: '',
};
for (const [name, value] of Object.entries(environment)) {
const previous = process.env[name];
t.after(() => {
if (previous === undefined) delete process.env[name];
else process.env[name] = previous;
});
process.env[name] = value;
}
t.mock.method(console, 'warn', () => {});
let upstreamAvailable = false;
const calls = [];
t.mock.method(globalThis, 'fetch', async (raw) => {
const url = new URL(raw);
calls.push(url.origin);
if (url.origin === 'https://camera.example')
return upstreamAvailable
? new Response(PNG, { headers: { 'Content-Type': 'image/png' } })
: new Response(null, { status: 503 });
assert.equal(
url.origin,
'https://maps.googleapis.com',
'no actual upstream is contacted',
);
assert.equal(url.searchParams.get('key'), 'fixture-key');
return new Response(PNG, { headers: { 'Content-Type': 'image/png' } });
});
let middleware;
cctvProxy().configureServer({
middlewares: {
use(route, handler) {
assert.equal(route, '/api/cctv');
middleware = handler;
},
},
});
const source = createCctvSource({
fetchImpl: async (path) => {
assert.ok(path.startsWith('/api/cctv/'));
const response = {
writeHead(status, headers) {
this.status = status;
this.headers = headers;
},
end(body) {
this.body = body;
},
};
await middleware(
{ url: path.slice('/api/cctv'.length), method: 'GET', headers: {} },
response,
);
return new Response(response.body, {
status: response.status,
headers: response.headers,
});
},
});
const catalog = composeCatalog({
tools: coreTools,
services: { cctv: source },
});
const fallback = await catalog.call('get_cctv_snapshot', {
camera_id: camera.id,
});
assert.equal(fallback.data.source_kind, 'streetview');
assert.equal(fallback.data.current_view, false);
assert.equal(fallback.data.credit, 'Google Street View');
assert.match(fallback.summary, /Street View fallback/);
assert.match(fallback.summary, /Historical imagery/);
assert.doesNotMatch(
fallback.summary,
/Current view|courtesy of Fixture transport agency/,
);
assert.equal(
fallback.images.length,
1,
'the historical image stays available with its caveat',
);
assert.deepEqual(calls, [
'https://camera.example',
'https://maps.googleapis.com',
]);
upstreamAvailable = true;
const current = await catalog.call('get_cctv_snapshot', {
camera_id: camera.id,
});
assert.equal(current.data.source_kind, 'upstream-image');
assert.equal(current.data.current_view, true);
assert.equal(current.data.credit, camera.credit);
assert.match(current.summary, /^Current view from/);
const server = createMcpServer({ catalog, name: 'test', version: '1' });
upstreamAvailable = false;
const result = await server.handle({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: { name: 'get_cctv_snapshot', arguments: { camera_id: camera.id } },
});
assert.ok(
result.result.content.some(
(entry) => entry.type === 'text' && /Historical imagery/.test(entry.text),
),
);
assert.ok(result.result.content.some((entry) => entry.type === 'image'));
process.env.GOOGLE_MAPS_SERVER_API_KEY = '';
const placeholder = await source.getFrame(camera);
assert.equal(placeholder.sourceKind, 'synthetic');
assert.equal(placeholder.contentType, 'image/svg+xml');
await assert.rejects(
catalog.call('get_cctv_snapshot', { camera_id: camera.id }),
(error) => error.code === 'unavailable',
);
const unavailable = await server.handle({
jsonrpc: '2.0',
id: 2,
method: 'tools/call',
params: { name: 'get_cctv_snapshot', arguments: { camera_id: camera.id } },
});
assert.equal(unavailable.result.isError, true);
assert.ok(
!unavailable.result.content.some((entry) => entry.type === 'image'),
);
});
test('snapshot placeholders are refused and unknown frame provenance is explicit', async () => {
const synthetic = composeCatalog({
tools: coreTools,
services: {
cctv: cctv({
contentType: 'image/png',
bytes: PNG,
sourceKind: 'synthetic',
}),
},
});
await assert.rejects(
synthetic.call('get_cctv_snapshot', { camera_id: 'austin-1' }),
(error) => error.code === 'unavailable',
);
const unknown = await composeCatalog({
tools: coreTools,
services: { cctv: cctv({ contentType: 'image/png', bytes: PNG }) },
}).call('get_cctv_snapshot', { camera_id: 'austin-1' });
assert.equal(unknown.data.current_view, null);
assert.equal(
unknown.data.credit,
cameras[0].credit,
'catalog attribution is preserved',
);
assert.match(unknown.summary, /provenance is unknown/);
assert.doesNotMatch(unknown.summary, /Current view/);
});
test('unknown cameras, video-only feeds and oversized frames are reported', async () => {
const catalog = (frame) =>
composeCatalog({ tools: coreTools, services: { cctv: cctv(frame) } });
await assert.rejects(
catalog().call('get_cctv_snapshot', { camera_id: 'nope' }),
/No camera has id nope; use find_cctv_cameras first/,
);
await assert.rejects(
catalog({ contentType: 'video/mp2t', bytes: PNG }).call(
'get_cctv_snapshot',
{ camera_id: 'austin-2' },
),
(error) =>
error.code === 'unavailable' && /no still image/.test(error.message),
);
await assert.rejects(
catalog({
contentType: 'image/jpeg',
bytes: new Uint8Array(3 * 1024 * 1024 + 1),
}).call('get_cctv_snapshot', { camera_id: 'austin-2' }),
/too large/,
);
});
test('radio stations match area and every search term', async () => {
const radio = {
async getDirectory() {
return {
stations: [
{
id: 'a',
name: 'KUTX',
lat: 30.28,
lon: -97.74,
country: 'United States',
state: 'Texas',
tags: ['music', 'indie'],
languages: ['english'],
codec: 'MP3',
bitrate: 128,
streamUrl: 'https://example.org/kutx.mp3',
homepage: 'https://kutx.org',
},
{
id: 'b',
name: 'KMFA Classical',
lat: 30.3,
lon: -97.7,
country: 'United States',
state: 'Texas',
tags: ['classical'],
languages: ['english'],
codec: 'AAC',
bitrate: null,
streamUrl: 'https://example.org/kmfa.aac',
},
{
id: 'c',
name: 'Jazz Oslo',
lat: 59.9,
lon: 10.7,
country: 'Norway',
tags: ['jazz'],
languages: ['norwegian'],
},
],
};
},
};
const catalog = composeCatalog({ tools: coreTools, services: { radio } });
const nearby = await catalog.call('find_radio_stations', {
area: { lat: 30.27, lon: -97.74, radius_km: 20 },
});
assert.deepEqual(
nearby.data.rows.map((row) => row.id),
['a', 'b'],
);
assert.equal(nearby.data.rows[0].stream_url, 'https://example.org/kutx.mp3');
const jazz = await catalog.call('find_radio_stations', {
query: 'jazz norwegian',
});
assert.equal(
jazz.summary,
'1 radio station matching "jazz norwegian" (from a directory of 3 popular stations).',
);
assert.equal(jazz.data.directory_size, 3);
assert.equal(jazz.data.stale, false);
assert.equal(jazz.data.rows[0].distance_km, undefined);
const classicalTexas = await catalog.call('find_radio_stations', {
query: 'classical texas',
area: { lat: 30.27, lon: -97.74, radius_km: 20 },
});
assert.deepEqual(
classicalTexas.data.rows.map((row) => row.id),
['b'],
);
assert.equal(classicalTexas.data.rows[0].bitrate_kbps, null);
await assert.rejects(
catalog.call('find_radio_stations', {}),
/area, a query or both/,
);
});
test('malformed image results are a programming error', async () => {
const { defineTool } = await import('../catalog.js');
const bad = defineTool({
name: 'bad_image',
title: 'Bad',
description: 'Returns a malformed image.',
inputSchema: { type: 'object' },
run: async () => ({
summary: 'x',
data: {},
images: [{ mimeType: 'image/png' }],
}),
});
await assert.rejects(
composeCatalog({ tools: [bad] }).call('bad_image'),
/malformed images/,
);
});
test('a stale or degraded radio directory is reported', async () => {
const catalog = composeCatalog({
tools: coreTools,
services: {
radio: {
getDirectory: async () => ({
stations: [],
stale: true,
degraded: true,
}),
},
},
});
const result = await catalog.call('find_radio_stations', { query: 'jazz' });
assert.match(
result.summary,
/the directory may be stale; the directory is incomplete right now\)\.$/,
);
assert.equal(result.data.degraded, true);
});
test('cameras from a trimmed catalog pack are reported as partial', async () => {
const catalog = composeCatalog({
tools: coreTools,
services: {
cctv: {
getCatalog: async () => ({
trimmedPacks: [
{ pack: 'tfl', available: 900, served: 250 },
{ pack: 'other', available: 10, served: 5 },
],
sources: [
{
id: 'jam-1',
name: 'Strand',
lat: 51.51,
lon: -0.12,
pack: 'tfl',
},
],
}),
},
},
});
const result = await catalog.call('find_cctv_cameras', {
area: { lat: 51.51, lon: -0.12, radius_km: 5 },
});
assert.equal(result.data.complete, false);
assert.deepEqual(result.data.catalog_trimmed, [
{ pack: 'tfl', available: 900, served: 250 },
]);
assert.match(
result.summary,
/\(the catalog serves only some cameras here: 250 of 900 from tfl\)\.$/,
);
});
test('an area the catalog trimmed away entirely is not reported complete', async () => {
const catalog = composeCatalog({
tools: coreTools,
services: {
cctv: {
getCatalog: async () => ({
trimmedPacks: [
{
pack: 'tfl',
available: 900,
served: 250,
region: { west: -0.6, south: 51.3, east: 0.3, north: 51.7 },
},
],
// Every served camera is in central London, none in the suburb.
sources: [
{
id: 'jam-1',
name: 'Strand',
lat: 51.51,
lon: -0.12,
pack: 'tfl',
},
],
}),
},
},
});
const suburb = await catalog.call('find_cctv_cameras', {
area: { lat: 51.4, lon: -0.5, radius_km: 3 },
});
assert.equal(suburb.data.rows.length, 0);
assert.equal(suburb.data.complete, false);
assert.match(suburb.summary, /250 of 900 from tfl/);
const elsewhere = await catalog.call('find_cctv_cameras', {
area: { lat: 40.7, lon: -74, radius_km: 3 },
});
assert.equal(elsewhere.data.complete, true);
assert.equal(
elsewhere.summary,
'The camera catalog has no cameras in 3 km around 40.700, -74.000.',
);
});