nextbillion-mcp 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +6 -0
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/maps/polyline.d.ts +16 -0
- package/dist/tools/maps/polyline.js +117 -0
- package/dist/tools/maps/polyline.js.map +1 -0
- package/dist/tools/maps/static-map-image.js +1 -1
- package/dist/tools/maps/static-map-image.js.map +1 -1
- package/dist/tools/maps/static-route-map.js +38 -10
- package/dist/tools/maps/static-route-map.js.map +1 -1
- package/dist/tools/maps/static-shared.d.ts +1 -1
- package/dist/tools/maps/static-shared.js +30 -2
- package/dist/tools/maps/static-shared.js.map +1 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ export interface ServerConfig {
|
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
timeoutMs: number;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Directory where rendered map images are saved (in addition to being returned inline).
|
|
8
|
+
* Terminal-based MCP clients such as the Codex CLI cannot display image content, so a
|
|
9
|
+
* local file path in the result text is the only way for those users to see the map.
|
|
10
|
+
*/
|
|
11
|
+
export declare function imageOutputDir(env?: NodeJS.ProcessEnv): string;
|
|
6
12
|
export declare const DEFAULT_BASE_URL = "https://api.nextbillion.io";
|
|
7
13
|
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
8
14
|
export declare class ConfigError extends Error {
|
package/dist/config.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { tmpdir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Directory where rendered map images are saved (in addition to being returned inline).
|
|
5
|
+
* Terminal-based MCP clients such as the Codex CLI cannot display image content, so a
|
|
6
|
+
* local file path in the result text is the only way for those users to see the map.
|
|
7
|
+
*/
|
|
8
|
+
export function imageOutputDir(env = process.env) {
|
|
9
|
+
return env.NBAI_IMAGE_DIR?.trim() || join(tmpdir(), 'nextbillion-mcp');
|
|
10
|
+
}
|
|
1
11
|
export const DEFAULT_BASE_URL = 'https://api.nextbillion.io';
|
|
2
12
|
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
13
|
export class ConfigError extends Error {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IACjE,OAAO,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,MAAM,OAAO,WAAY,SAAQ,KAAK;CAAG;AAEzC,qGAAqG;AACrG,MAAM,UAAU,UAAU,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC7D,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,WAAW,CACnB,gFAAgF;YAC9E,2EAA2E,CAC9E,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACzF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,WAAW,CAAC,mDAAmD,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,OAAO;QACL,MAAM;QACN,OAAO,EAAE,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5E,SAAS;KACV,CAAC;AACJ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,8 @@ function main() {
|
|
|
18
18
|
'Environment variables:\n' +
|
|
19
19
|
' NBAI_API_KEY (required) NextBillion.ai API key\n' +
|
|
20
20
|
' NBAI_BASE_URL (optional) API base URL, default https://api.nextbillion.io\n' +
|
|
21
|
-
' NBAI_TIMEOUT_MS (optional) per-request timeout, default 30000\n'
|
|
21
|
+
' NBAI_TIMEOUT_MS (optional) per-request timeout, default 30000\n' +
|
|
22
|
+
' NBAI_IMAGE_DIR (optional) directory for saved map images, default <tmp>/nextbillion-mcp\n');
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
24
25
|
let config;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAC;AAErF,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CACT,GAAG,WAAW,IAAI,GAAG,CAAC,OAAO,oDAAoD;YAC/E,gFAAgF;YAChF,0BAA0B;YAC1B,yDAAyD;YACzD,mFAAmF;YACnF,qEAAqE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAC;AAErF,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CACT,GAAG,WAAW,IAAI,GAAG,CAAC,OAAO,oDAAoD;YAC/E,gFAAgF;YAChF,0BAA0B;YAC1B,yDAAyD;YACzD,mFAAmF;YACnF,qEAAqE;YACrE,gGAAgG,CACnG,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,WAAW,IAAI,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Coordinate } from '../shared/geo.js';
|
|
2
|
+
export declare function decodePolyline(encoded: string): Coordinate[];
|
|
3
|
+
export declare function encodePolyline(points: Coordinate[]): string;
|
|
4
|
+
/** Douglas-Peucker simplification with the tolerance in approximate meters. */
|
|
5
|
+
export declare function simplifyPoints(points: Coordinate[], toleranceMeters: number): Coordinate[];
|
|
6
|
+
export interface FittedGeometry {
|
|
7
|
+
encoded: string;
|
|
8
|
+
originalPointCount: number;
|
|
9
|
+
pointCount: number;
|
|
10
|
+
simplified: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Return an encoded polyline whose length is at most `maxEncodedChars`, simplifying
|
|
14
|
+
* with progressively coarser tolerances until it fits (or only endpoints remain).
|
|
15
|
+
*/
|
|
16
|
+
export declare function fitPolylineToBudget(points: Coordinate[], maxEncodedChars: number): FittedGeometry;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google encoded polyline codec (precision 5) plus Douglas-Peucker simplification.
|
|
3
|
+
* Used to shrink long route geometries so the static-image GET URL stays within
|
|
4
|
+
* the API's 8192-byte limit: a 600 km route encodes to ~30k characters (~50 kB
|
|
5
|
+
* URL-encoded), far beyond what the endpoint accepts.
|
|
6
|
+
*/
|
|
7
|
+
const PRECISION = 1e5;
|
|
8
|
+
export function decodePolyline(encoded) {
|
|
9
|
+
const points = [];
|
|
10
|
+
let index = 0;
|
|
11
|
+
let lat = 0;
|
|
12
|
+
let lng = 0;
|
|
13
|
+
while (index < encoded.length) {
|
|
14
|
+
lat += readVarint();
|
|
15
|
+
lng += readVarint();
|
|
16
|
+
points.push({ latitude: lat / PRECISION, longitude: lng / PRECISION });
|
|
17
|
+
}
|
|
18
|
+
return points;
|
|
19
|
+
function readVarint() {
|
|
20
|
+
let result = 0;
|
|
21
|
+
let shift = 0;
|
|
22
|
+
let byte;
|
|
23
|
+
do {
|
|
24
|
+
byte = encoded.charCodeAt(index++) - 63;
|
|
25
|
+
result |= (byte & 0x1f) << shift;
|
|
26
|
+
shift += 5;
|
|
27
|
+
} while (byte >= 0x20);
|
|
28
|
+
return result & 1 ? ~(result >> 1) : result >> 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function encodePolyline(points) {
|
|
32
|
+
let output = '';
|
|
33
|
+
let prevLat = 0;
|
|
34
|
+
let prevLng = 0;
|
|
35
|
+
for (const point of points) {
|
|
36
|
+
const lat = Math.round(point.latitude * PRECISION);
|
|
37
|
+
const lng = Math.round(point.longitude * PRECISION);
|
|
38
|
+
output += encodeValue(lat - prevLat) + encodeValue(lng - prevLng);
|
|
39
|
+
prevLat = lat;
|
|
40
|
+
prevLng = lng;
|
|
41
|
+
}
|
|
42
|
+
return output;
|
|
43
|
+
function encodeValue(value) {
|
|
44
|
+
let v = value < 0 ? ~(value << 1) : value << 1;
|
|
45
|
+
let chunk = '';
|
|
46
|
+
while (v >= 0x20) {
|
|
47
|
+
chunk += String.fromCharCode((0x20 | (v & 0x1f)) + 63);
|
|
48
|
+
v >>= 5;
|
|
49
|
+
}
|
|
50
|
+
return chunk + String.fromCharCode(v + 63);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Douglas-Peucker simplification with the tolerance in approximate meters. */
|
|
54
|
+
export function simplifyPoints(points, toleranceMeters) {
|
|
55
|
+
if (points.length <= 2 || toleranceMeters <= 0)
|
|
56
|
+
return points;
|
|
57
|
+
const keep = new Array(points.length).fill(false);
|
|
58
|
+
keep[0] = keep[points.length - 1] = true;
|
|
59
|
+
const stack = [[0, points.length - 1]];
|
|
60
|
+
while (stack.length > 0) {
|
|
61
|
+
const [start, end] = stack.pop();
|
|
62
|
+
let maxDistance = 0;
|
|
63
|
+
let maxIndex = -1;
|
|
64
|
+
for (let i = start + 1; i < end; i++) {
|
|
65
|
+
const distance = perpendicularDistanceMeters(points[i], points[start], points[end]);
|
|
66
|
+
if (distance > maxDistance) {
|
|
67
|
+
maxDistance = distance;
|
|
68
|
+
maxIndex = i;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (maxIndex !== -1 && maxDistance > toleranceMeters) {
|
|
72
|
+
keep[maxIndex] = true;
|
|
73
|
+
stack.push([start, maxIndex], [maxIndex, end]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return points.filter((_, i) => keep[i]);
|
|
77
|
+
}
|
|
78
|
+
/** Planar approximation (equirectangular) — accurate enough for display-level simplification. */
|
|
79
|
+
function perpendicularDistanceMeters(p, a, b) {
|
|
80
|
+
const metersPerDegLat = 111_320;
|
|
81
|
+
const cosLat = Math.cos((a.latitude * Math.PI) / 180);
|
|
82
|
+
const toXY = (c) => ({
|
|
83
|
+
x: c.longitude * metersPerDegLat * cosLat,
|
|
84
|
+
y: c.latitude * metersPerDegLat,
|
|
85
|
+
});
|
|
86
|
+
const P = toXY(p);
|
|
87
|
+
const A = toXY(a);
|
|
88
|
+
const B = toXY(b);
|
|
89
|
+
const dx = B.x - A.x;
|
|
90
|
+
const dy = B.y - A.y;
|
|
91
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
92
|
+
if (lengthSquared === 0)
|
|
93
|
+
return Math.hypot(P.x - A.x, P.y - A.y);
|
|
94
|
+
const t = Math.max(0, Math.min(1, ((P.x - A.x) * dx + (P.y - A.y) * dy) / lengthSquared));
|
|
95
|
+
return Math.hypot(P.x - (A.x + t * dx), P.y - (A.y + t * dy));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Return an encoded polyline whose length is at most `maxEncodedChars`, simplifying
|
|
99
|
+
* with progressively coarser tolerances until it fits (or only endpoints remain).
|
|
100
|
+
*/
|
|
101
|
+
export function fitPolylineToBudget(points, maxEncodedChars) {
|
|
102
|
+
let current = points;
|
|
103
|
+
let encoded = encodePolyline(current);
|
|
104
|
+
let tolerance = 5; // meters
|
|
105
|
+
while (encoded.length > maxEncodedChars && current.length > 2) {
|
|
106
|
+
current = simplifyPoints(points, tolerance);
|
|
107
|
+
encoded = encodePolyline(current);
|
|
108
|
+
tolerance *= 2;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
encoded,
|
|
112
|
+
originalPointCount: points.length,
|
|
113
|
+
pointCount: current.length,
|
|
114
|
+
simplified: current.length < points.length,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=polyline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyline.js","sourceRoot":"","sources":["../../../src/tools/maps/polyline.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,7 @@ export const staticMapImage = {
|
|
|
25
25
|
async run(args, nb) {
|
|
26
26
|
const position = `${args.center.latitude},${args.center.longitude},${args.zoom}`;
|
|
27
27
|
return fetchImageResult(nb, staticImagePath(position, args), { markers: args.markers?.length ? markerParam(args.markers, 'lng-first') : undefined }, `Map centered at (${args.center.latitude}, ${args.center.longitude}), zoom ${args.zoom}` +
|
|
28
|
-
(args.markers?.length ? `, ${args.markers.length} marker(s).` : '.'), args);
|
|
28
|
+
(args.markers?.length ? `, ${args.markers.length} marker(s).` : '.'), args, 'map');
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=static-map-image.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-map-image.js","sourceRoot":"","sources":["../../../src/tools/maps/static-map-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAe,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC3D,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SAChE,QAAQ,EAAE;SACV,QAAQ,CAAC,mEAAmE,CAAC;IAChF,GAAG,gBAAgB;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,6FAA6F;QAC7F,kEAAkE;IACpE,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,SAAS;IACtB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;QAChB,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACjF,OAAO,gBAAgB,CACrB,EAAE,EACF,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,EAC/B,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EACtF,oBAAoB,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE;YACtF,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EACtE,IAAI,
|
|
1
|
+
{"version":3,"file":"static-map-image.js","sourceRoot":"","sources":["../../../src/tools/maps/static-map-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAe,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC3D,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SAChE,QAAQ,EAAE;SACV,QAAQ,CAAC,mEAAmE,CAAC;IAChF,GAAG,gBAAgB;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,6FAA6F;QAC7F,kEAAkE;IACpE,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,SAAS;IACtB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;QAChB,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACjF,OAAO,gBAAgB,CACrB,EAAE,EACF,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,EAC/B,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EACtF,oBAAoB,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE;YACtF,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EACtE,IAAI,EACJ,KAAK,CACN,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -2,6 +2,7 @@ import * as z from 'zod/v4';
|
|
|
2
2
|
import { CoordinateSchema } from '../shared/geo.js';
|
|
3
3
|
import { READ_ONLY, ToolInputError } from '../types.js';
|
|
4
4
|
import { fetchImageResult, markerParam, StaticImageShape, staticImagePath, } from './static-shared.js';
|
|
5
|
+
import { decodePolyline, fitPolylineToBudget } from './polyline.js';
|
|
5
6
|
const Schema = z.object({
|
|
6
7
|
encoded_polyline: z
|
|
7
8
|
.string()
|
|
@@ -36,6 +37,10 @@ const Schema = z.object({
|
|
|
36
37
|
.describe('Margin around the route as a fraction of image size (default 0.1)'),
|
|
37
38
|
...StaticImageShape,
|
|
38
39
|
});
|
|
40
|
+
/** Stay comfortably under the API's documented 8192-byte URL limit. */
|
|
41
|
+
const URL_BYTE_BUDGET = 8000;
|
|
42
|
+
/** Progressively tighter encoded-polyline budgets tried when the URL is too long. */
|
|
43
|
+
const ENCODED_CHAR_BUDGETS = [4000, 3000, 2000, 1200, 600, 200];
|
|
39
44
|
export const staticRouteMap = {
|
|
40
45
|
name: 'static_route_map',
|
|
41
46
|
title: 'Static Route Map',
|
|
@@ -56,18 +61,41 @@ export const staticRouteMap = {
|
|
|
56
61
|
`width:${args.stroke_width ?? 4}`,
|
|
57
62
|
'fill:none',
|
|
58
63
|
];
|
|
59
|
-
|
|
60
|
-
const
|
|
64
|
+
const markers = args.markers?.length ? markerParam(args.markers, 'lat-first') : undefined;
|
|
65
|
+
const padding = args.padding !== undefined ? String(args.padding) : undefined;
|
|
66
|
+
const path = staticImagePath('auto', args);
|
|
67
|
+
const buildQuery = (geometry) => ({
|
|
68
|
+
path: `${styleSegments.join('|')}|${geometry}`,
|
|
69
|
+
markers,
|
|
70
|
+
padding,
|
|
71
|
+
});
|
|
72
|
+
// First try the geometry exactly as given. Path coordinates are `lat,lng`;
|
|
73
|
+
// `enc:` consumes the rest of the parameter value.
|
|
74
|
+
let geometry = args.encoded_polyline
|
|
61
75
|
? `enc:${args.encoded_polyline}`
|
|
62
76
|
: args.route_points.map((p) => `${p.latitude},${p.longitude}`).join('|');
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
let simplificationNote = '';
|
|
78
|
+
// The Static Images API is GET-only with an 8192-byte URL limit; a long route's
|
|
79
|
+
// full-resolution polyline blows past it (~50 kB for 600 km). When that happens,
|
|
80
|
+
// simplify the *display* geometry progressively until the URL fits — the route's
|
|
81
|
+
// distance/duration come from the directions tool and are unaffected.
|
|
82
|
+
if (nb.buildUrl(path, buildQuery(geometry)).length > URL_BYTE_BUDGET) {
|
|
83
|
+
const points = args.encoded_polyline
|
|
84
|
+
? decodePolyline(args.encoded_polyline)
|
|
85
|
+
: args.route_points;
|
|
86
|
+
for (const budget of ENCODED_CHAR_BUDGETS) {
|
|
87
|
+
const fitted = fitPolylineToBudget(points, budget);
|
|
88
|
+
geometry = `enc:${fitted.encoded}`;
|
|
89
|
+
if (nb.buildUrl(path, buildQuery(geometry)).length <= URL_BYTE_BUDGET) {
|
|
90
|
+
simplificationNote =
|
|
91
|
+
` Display geometry simplified from ${fitted.originalPointCount} to ` +
|
|
92
|
+
`${fitted.pointCount} points to fit the map URL limit; distances are unaffected.`;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return fetchImageResult(nb, path, buildQuery(geometry), `Route map rendered${args.markers?.length ? ` with ${args.markers.length} marker(s)` : ''}.` +
|
|
98
|
+
simplificationNote, args, 'route-map');
|
|
71
99
|
},
|
|
72
100
|
};
|
|
73
101
|
//# sourceMappingURL=static-route-map.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-route-map.js","sourceRoot":"","sources":["../../../src/tools/maps/static-route-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AACrE,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"static-route-map.js","sourceRoot":"","sources":["../../../src/tools/maps/static-route-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,4 +32,4 @@ export declare function staticImagePath(positionSegment: string, args: StaticIma
|
|
|
32
32
|
export declare function markerParam(markers: Array<Coordinate & {
|
|
33
33
|
color?: string;
|
|
34
34
|
}>, order: 'lng-first' | 'lat-first'): string;
|
|
35
|
-
export declare function fetchImageResult(nb: NbClient, path: string, query: Record<string, string | undefined>, caption: string, args: StaticImageArgs): Promise<ToolResult>;
|
|
35
|
+
export declare function fetchImageResult(nb: NbClient, path: string, query: Record<string, string | undefined>, caption: string, args: StaticImageArgs, filePrefix?: string): Promise<ToolResult>;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
1
4
|
import * as z from 'zod/v4';
|
|
5
|
+
import { imageOutputDir } from '../../config.js';
|
|
6
|
+
import { logError } from '../../log.js';
|
|
2
7
|
export const StaticImageShape = {
|
|
3
8
|
width: z
|
|
4
9
|
.number()
|
|
@@ -48,16 +53,39 @@ export function markerParam(markers, order) {
|
|
|
48
53
|
})
|
|
49
54
|
.join('|');
|
|
50
55
|
}
|
|
51
|
-
export async function fetchImageResult(nb, path, query, caption, args) {
|
|
56
|
+
export async function fetchImageResult(nb, path, query, caption, args, filePrefix = 'map') {
|
|
52
57
|
const image = await nb.getBinary(path, query);
|
|
53
58
|
const mimeType = image.contentType.startsWith('image/')
|
|
54
59
|
? image.contentType
|
|
55
60
|
: MIME_TYPES[args.format ?? 'png'];
|
|
61
|
+
const savedPath = await saveImage(image.data, filePrefix, args.format ?? 'png');
|
|
62
|
+
const location = savedPath
|
|
63
|
+
? ` Saved to ${savedPath} (for clients that cannot display images inline).`
|
|
64
|
+
: '';
|
|
56
65
|
return {
|
|
57
66
|
content: [
|
|
58
67
|
{ type: 'image', data: Buffer.from(image.data).toString('base64'), mimeType },
|
|
59
|
-
{ type: 'text', text: caption },
|
|
68
|
+
{ type: 'text', text: caption + location },
|
|
60
69
|
],
|
|
61
70
|
};
|
|
62
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Persist the rendered image locally so terminal clients (which drop inline image
|
|
74
|
+
* content) can open it. Failures are logged and never fail the tool call.
|
|
75
|
+
*/
|
|
76
|
+
async function saveImage(data, prefix, ext) {
|
|
77
|
+
try {
|
|
78
|
+
const dir = imageOutputDir();
|
|
79
|
+
await mkdir(dir, { recursive: true });
|
|
80
|
+
const hash = createHash('sha1').update(data).digest('hex').slice(0, 8);
|
|
81
|
+
const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\..+/, '');
|
|
82
|
+
const filePath = join(dir, `${prefix}-${stamp}-${hash}.${ext === 'jpg' ? 'jpg' : ext}`);
|
|
83
|
+
await writeFile(filePath, data);
|
|
84
|
+
return filePath;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logError('Could not save rendered image to disk', error);
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
63
91
|
//# sourceMappingURL=static-shared.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-shared.js","sourceRoot":"","sources":["../../../src/tools/maps/static-shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"static-shared.js","sourceRoot":"","sources":["../../../src/tools/maps/static-shared.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED