nextbillion-mcp 0.1.10 → 0.2.0
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/index.js +456 -141
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2561,6 +2561,112 @@ function handleIntersectionResults(result, left, right) {
|
|
|
2561
2561
|
result.value = merged.data;
|
|
2562
2562
|
return result;
|
|
2563
2563
|
}
|
|
2564
|
+
var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
|
|
2565
|
+
$ZodType.init(inst, def);
|
|
2566
|
+
const items = def.items;
|
|
2567
|
+
inst._zod.parse = (payload, ctx) => {
|
|
2568
|
+
const input = payload.value;
|
|
2569
|
+
if (!Array.isArray(input)) {
|
|
2570
|
+
payload.issues.push({
|
|
2571
|
+
input,
|
|
2572
|
+
inst,
|
|
2573
|
+
expected: "tuple",
|
|
2574
|
+
code: "invalid_type"
|
|
2575
|
+
});
|
|
2576
|
+
return payload;
|
|
2577
|
+
}
|
|
2578
|
+
payload.value = [];
|
|
2579
|
+
const proms = [];
|
|
2580
|
+
const optinStart = getTupleOptStart(items, "optin");
|
|
2581
|
+
const optoutStart = getTupleOptStart(items, "optout");
|
|
2582
|
+
if (!def.rest) {
|
|
2583
|
+
if (input.length < optinStart) {
|
|
2584
|
+
payload.issues.push({
|
|
2585
|
+
code: "too_small",
|
|
2586
|
+
minimum: optinStart,
|
|
2587
|
+
inclusive: true,
|
|
2588
|
+
input,
|
|
2589
|
+
inst,
|
|
2590
|
+
origin: "array"
|
|
2591
|
+
});
|
|
2592
|
+
return payload;
|
|
2593
|
+
}
|
|
2594
|
+
if (input.length > items.length) {
|
|
2595
|
+
payload.issues.push({
|
|
2596
|
+
code: "too_big",
|
|
2597
|
+
maximum: items.length,
|
|
2598
|
+
inclusive: true,
|
|
2599
|
+
input,
|
|
2600
|
+
inst,
|
|
2601
|
+
origin: "array"
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
const itemResults = new Array(items.length);
|
|
2606
|
+
for (let i = 0; i < items.length; i++) {
|
|
2607
|
+
const r = items[i]._zod.run({ value: input[i], issues: [] }, ctx);
|
|
2608
|
+
if (r instanceof Promise) {
|
|
2609
|
+
proms.push(r.then((rr) => {
|
|
2610
|
+
itemResults[i] = rr;
|
|
2611
|
+
}));
|
|
2612
|
+
} else {
|
|
2613
|
+
itemResults[i] = r;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
if (def.rest) {
|
|
2617
|
+
let i = items.length - 1;
|
|
2618
|
+
const rest = input.slice(items.length);
|
|
2619
|
+
for (const el of rest) {
|
|
2620
|
+
i++;
|
|
2621
|
+
const result = def.rest._zod.run({ value: el, issues: [] }, ctx);
|
|
2622
|
+
if (result instanceof Promise) {
|
|
2623
|
+
proms.push(result.then((r) => handleTupleResult(r, payload, i)));
|
|
2624
|
+
} else {
|
|
2625
|
+
handleTupleResult(result, payload, i);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
if (proms.length) {
|
|
2630
|
+
return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items, input, optoutStart));
|
|
2631
|
+
}
|
|
2632
|
+
return handleTupleResults(itemResults, payload, items, input, optoutStart);
|
|
2633
|
+
};
|
|
2634
|
+
});
|
|
2635
|
+
function getTupleOptStart(items, key) {
|
|
2636
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
2637
|
+
if (items[i]._zod[key] !== "optional")
|
|
2638
|
+
return i + 1;
|
|
2639
|
+
}
|
|
2640
|
+
return 0;
|
|
2641
|
+
}
|
|
2642
|
+
function handleTupleResult(result, final, index) {
|
|
2643
|
+
if (result.issues.length) {
|
|
2644
|
+
final.issues.push(...prefixIssues(index, result.issues));
|
|
2645
|
+
}
|
|
2646
|
+
final.value[index] = result.value;
|
|
2647
|
+
}
|
|
2648
|
+
function handleTupleResults(itemResults, final, items, input, optoutStart) {
|
|
2649
|
+
for (let i = 0; i < items.length; i++) {
|
|
2650
|
+
const r = itemResults[i];
|
|
2651
|
+
const isPresent = i < input.length;
|
|
2652
|
+
if (r.issues.length) {
|
|
2653
|
+
if (!isPresent && i >= optoutStart) {
|
|
2654
|
+
final.value.length = i;
|
|
2655
|
+
break;
|
|
2656
|
+
}
|
|
2657
|
+
final.issues.push(...prefixIssues(i, r.issues));
|
|
2658
|
+
}
|
|
2659
|
+
final.value[i] = r.value;
|
|
2660
|
+
}
|
|
2661
|
+
for (let i = final.value.length - 1; i >= input.length; i--) {
|
|
2662
|
+
if (items[i]._zod.optout === "optional" && final.value[i] === void 0) {
|
|
2663
|
+
final.value.length = i;
|
|
2664
|
+
} else {
|
|
2665
|
+
break;
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
return final;
|
|
2669
|
+
}
|
|
2564
2670
|
var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
2565
2671
|
$ZodType.init(inst, def);
|
|
2566
2672
|
inst._zod.parse = (payload, ctx) => {
|
|
@@ -5358,6 +5464,26 @@ function intersection(left, right) {
|
|
|
5358
5464
|
right
|
|
5359
5465
|
});
|
|
5360
5466
|
}
|
|
5467
|
+
var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
|
|
5468
|
+
$ZodTuple.init(inst, def);
|
|
5469
|
+
ZodType.init(inst, def);
|
|
5470
|
+
inst._zod.processJSONSchema = (ctx, json, params) => tupleProcessor(inst, ctx, json, params);
|
|
5471
|
+
inst.rest = (rest) => inst.clone({
|
|
5472
|
+
...inst._zod.def,
|
|
5473
|
+
rest
|
|
5474
|
+
});
|
|
5475
|
+
});
|
|
5476
|
+
function tuple(items, _paramsOrRest, _params) {
|
|
5477
|
+
const hasRest = _paramsOrRest instanceof $ZodType;
|
|
5478
|
+
const params = hasRest ? _params : _paramsOrRest;
|
|
5479
|
+
const rest = hasRest ? _paramsOrRest : null;
|
|
5480
|
+
return new ZodTuple({
|
|
5481
|
+
type: "tuple",
|
|
5482
|
+
items,
|
|
5483
|
+
rest,
|
|
5484
|
+
...util_exports.normalizeParams(params)
|
|
5485
|
+
});
|
|
5486
|
+
}
|
|
5361
5487
|
var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
|
|
5362
5488
|
$ZodRecord.init(inst, def);
|
|
5363
5489
|
ZodType.init(inst, def);
|
|
@@ -20432,6 +20558,34 @@ function summarizePlaces(response, noun = "result") {
|
|
|
20432
20558
|
return `${items.length} ${noun}${items.length === 1 ? "" : "s"} found:
|
|
20433
20559
|
${lines.join("\n")}${more}`;
|
|
20434
20560
|
}
|
|
20561
|
+
var HazmatSchema = array(
|
|
20562
|
+
_enum([
|
|
20563
|
+
"explosives",
|
|
20564
|
+
"gas",
|
|
20565
|
+
"flammable_liquid",
|
|
20566
|
+
"flammable_gas",
|
|
20567
|
+
"organic",
|
|
20568
|
+
"toxic",
|
|
20569
|
+
"radioactive",
|
|
20570
|
+
"corrosive",
|
|
20571
|
+
"other"
|
|
20572
|
+
])
|
|
20573
|
+
).min(1).describe("Hazardous cargo classes carried (truck mode, flexible service only)");
|
|
20574
|
+
var EmissionClassSchema = _enum(["euro0", "euro1", "euro2", "euro3", "euro4", "euro5", "euro6", "euro7", "euro8", "euro9"]).describe("Engine emission class (EU regions, truck mode, flexible service only)");
|
|
20575
|
+
var ExcludeSchema = array(
|
|
20576
|
+
_enum([
|
|
20577
|
+
"toll",
|
|
20578
|
+
"ferry",
|
|
20579
|
+
"highway",
|
|
20580
|
+
"service_road",
|
|
20581
|
+
"uturn",
|
|
20582
|
+
"sharp_turn",
|
|
20583
|
+
"left_turn",
|
|
20584
|
+
"right_turn"
|
|
20585
|
+
])
|
|
20586
|
+
).min(1).describe(
|
|
20587
|
+
"Strict filter: only routes that completely avoid these features are returned (error if none exists). Use `avoid` for a soft preference instead. Flexible service only"
|
|
20588
|
+
);
|
|
20435
20589
|
|
|
20436
20590
|
// src/tools/places/text-search.ts
|
|
20437
20591
|
var TextSearchSchema = strictObject({
|
|
@@ -20462,7 +20616,7 @@ var ForwardGeocodeSchema = strictObject({
|
|
|
20462
20616
|
var geocodeForward = {
|
|
20463
20617
|
name: "geocode_forward",
|
|
20464
20618
|
title: "Forward Geocode",
|
|
20465
|
-
description:
|
|
20619
|
+
description: 'Convert a free-text address, place name, locality or administrative area into coordinates and a full postal address; tolerates incomplete or partly wrong input. Use geocode_batch for many addresses, place_search for POIs/businesses, geocode_structured when the address components are already separated. Parameters: query (required); optional near {latitude, longitude} or country_codes (strongly recommended - landmark names rank poorly without a location bias), radius_m (with near), bounding_box {west, south, east, north}, limit, language, view, types (houseNumber | addressBlock | street | intersection | place | area). Example: {"query": "1600 Pennsylvania Avenue NW, Washington DC", "country_codes": ["USA"], "limit": 1}',
|
|
20466
20620
|
inputSchema: ForwardGeocodeSchema,
|
|
20467
20621
|
annotations: READ_ONLY,
|
|
20468
20622
|
async run(args, nb) {
|
|
@@ -20477,21 +20631,21 @@ var geocodeForward = {
|
|
|
20477
20631
|
var placeSearch = textSearchTool({
|
|
20478
20632
|
name: "place_search",
|
|
20479
20633
|
title: "Search Places",
|
|
20480
|
-
description: 'Search for places, points of interest
|
|
20634
|
+
description: 'Search for places, points of interest and businesses with a free-text query (e.g. "gas station", "coffee"), ranked by relevance around a location. Use geocode_forward for plain address-to-coordinates conversion. Parameters: query (required); optional near {latitude, longitude} (recommended), radius_m (with near), country_codes, bounding_box {west, south, east, north}, limit, language, view. Example: {"query": "coffee", "near": {"latitude": 37.7749, "longitude": -122.4194}, "radius_m": 1000, "limit": 5}',
|
|
20481
20635
|
path: "/discover",
|
|
20482
20636
|
noun: "place"
|
|
20483
20637
|
});
|
|
20484
20638
|
var autosuggest = textSearchTool({
|
|
20485
20639
|
name: "autosuggest",
|
|
20486
20640
|
title: "Autosuggest",
|
|
20487
|
-
description: 'Suggest address and place candidates from an incomplete or misspelled query (typo-tolerant, e.g. "aqaurium" still matches aquariums).
|
|
20641
|
+
description: 'Suggest address and place candidates from an incomplete or misspelled query (typo-tolerant, e.g. "aqaurium" still matches aquariums). Use for search-as-you-type; use autocomplete for strict prefix completion of valid addresses. Parameters: query (required); optional near {latitude, longitude}, radius_m (with near), country_codes, bounding_box {west, south, east, north}, limit, language, view. Example: {"query": "aqauriums", "near": {"latitude": 42.3501, "longitude": -71.0689}, "limit": 5}',
|
|
20488
20642
|
path: "/autosuggest",
|
|
20489
20643
|
noun: "suggestion"
|
|
20490
20644
|
});
|
|
20491
20645
|
var autocomplete = textSearchTool({
|
|
20492
20646
|
name: "autocomplete",
|
|
20493
20647
|
title: "Autocomplete",
|
|
20494
|
-
description: 'Complete
|
|
20648
|
+
description: 'Complete a partial address or administrative-area prefix into full valid addresses (e.g. "stat" -> "State Capitol, ..."). Use for prefix completion as the user types; use autosuggest for typo-tolerant fuzzy suggestions and geocode_forward for a full address. Parameters: query (required); optional near {latitude, longitude}, radius_m (with near), country_codes, bounding_box {west, south, east, north}, limit, language, view. Example: {"query": "stat", "near": {"latitude": 35.4769, "longitude": -97.4872}, "limit": 5}',
|
|
20495
20649
|
path: "/autocomplete",
|
|
20496
20650
|
noun: "completion"
|
|
20497
20651
|
});
|
|
@@ -20511,7 +20665,7 @@ var Schema = strictObject({
|
|
|
20511
20665
|
var geocodeBatch = {
|
|
20512
20666
|
name: "geocode_batch",
|
|
20513
20667
|
title: "Batch Geocode",
|
|
20514
|
-
description: 'Forward-geocode up to 100 free-text queries in one request; returns one ranked result set per query, in input order.
|
|
20668
|
+
description: 'Forward-geocode up to 100 free-text queries in one request; returns one ranked result set per query, in input order. Prefer this over repeated geocode_forward calls - this endpoint has its own low rate limit (60 requests per minute), so batch as much as possible into each call. Parameters: queries (required array; each item: query (required), optional near {latitude, longitude}, radius_m, country_codes, bounding_box, limit, language, view, types); optional top-level types (houseNumber | addressBlock | street | intersection | place | area) as the default for all queries (a per-query types overrides it). Example: {"queries": [{"query": "600-699 Golden Gate Ave, San Francisco, CA", "types": ["addressBlock"]}, {"query": "Empire State Building", "country_codes": ["USA"]}]}',
|
|
20515
20669
|
inputSchema: Schema,
|
|
20516
20670
|
annotations: READ_ONLY,
|
|
20517
20671
|
async run(args, nb) {
|
|
@@ -20554,7 +20708,7 @@ var Schema2 = strictObject({
|
|
|
20554
20708
|
var geocodeReverse = {
|
|
20555
20709
|
name: "geocode_reverse",
|
|
20556
20710
|
title: "Reverse Geocode",
|
|
20557
|
-
description:
|
|
20711
|
+
description: 'Find the nearest address for a coordinate; returns the full postal address, the matched position and a bounding box. Parameters: coordinate {latitude, longitude} (required); optional country_codes, bounding_box {west, south, east, north}, language, view. Example: {"coordinate": {"latitude": 48.8566, "longitude": 2.3522}}',
|
|
20558
20712
|
inputSchema: Schema2,
|
|
20559
20713
|
annotations: READ_ONLY,
|
|
20560
20714
|
async run(args, nb) {
|
|
@@ -20588,7 +20742,7 @@ var Schema3 = strictObject({
|
|
|
20588
20742
|
var geocodeStructured = {
|
|
20589
20743
|
name: "geocode_structured",
|
|
20590
20744
|
title: "Structured Geocode",
|
|
20591
|
-
description:
|
|
20745
|
+
description: 'Geocode an address given as separate fields instead of one string; searches addresses and administrative areas only, never POIs. Use when the components are already known and precision matters; otherwise use geocode_forward. Parameters: country_code (required, ISO 3166-1 alpha-3) plus at least one of state, county, city, suburb, neighborhood, street, house_number, postal_code; optional near {latitude, longitude}, limit, types, view. Example: {"country_code": "GBR", "city": "London", "street": "Baker Street", "house_number": "221B"}',
|
|
20592
20746
|
inputSchema: Schema3,
|
|
20593
20747
|
annotations: READ_ONLY,
|
|
20594
20748
|
async run(args, nb) {
|
|
@@ -20617,16 +20771,38 @@ var geocodeStructured = {
|
|
|
20617
20771
|
}
|
|
20618
20772
|
};
|
|
20619
20773
|
|
|
20620
|
-
// src/tools/places/place-
|
|
20774
|
+
// src/tools/places/place-browse.ts
|
|
20621
20775
|
var Schema4 = strictObject({
|
|
20776
|
+
categories: array(string2().min(1)).min(1).describe(
|
|
20777
|
+
'Category names or ids to browse; a place matching any of them is returned (e.g. ["restaurant"], ["schools"], ["7376"])'
|
|
20778
|
+
),
|
|
20779
|
+
...PlacesFilterShape
|
|
20780
|
+
});
|
|
20781
|
+
var placeBrowse = {
|
|
20782
|
+
name: "place_browse",
|
|
20783
|
+
title: "Browse Places by Category",
|
|
20784
|
+
description: 'List places of given categories around a location, ranked by distance, without a text query - e.g. all restaurants or schools near a point. Use place_search when the user describes what they want in words; use place_lookup to expand a result by id. Parameters: categories (required array of category names or ids); near {latitude, longitude} (recommended), radius_m (with near), country_codes, bounding_box {west, south, east, north}, limit, language, view. Example: {"categories": ["restaurant"], "near": {"latitude": 1.2839, "longitude": 103.8607}, "radius_m": 800, "limit": 10}',
|
|
20785
|
+
inputSchema: Schema4,
|
|
20786
|
+
annotations: READ_ONLY,
|
|
20787
|
+
async run(args, nb) {
|
|
20788
|
+
const response = await nb.getJson("/browse", {
|
|
20789
|
+
categories: args.categories.join(","),
|
|
20790
|
+
...placesFilterQuery(args)
|
|
20791
|
+
});
|
|
20792
|
+
return textResult(summarizePlaces(response, "place"), response);
|
|
20793
|
+
}
|
|
20794
|
+
};
|
|
20795
|
+
|
|
20796
|
+
// src/tools/places/place-lookup.ts
|
|
20797
|
+
var Schema5 = strictObject({
|
|
20622
20798
|
id: string2().min(1).describe("Unique place id, as returned by the other place/geocoding tools"),
|
|
20623
20799
|
view: ViewSchema.optional()
|
|
20624
20800
|
});
|
|
20625
20801
|
var placeLookup = {
|
|
20626
20802
|
name: "place_lookup",
|
|
20627
20803
|
title: "Place Lookup",
|
|
20628
|
-
description:
|
|
20629
|
-
inputSchema:
|
|
20804
|
+
description: 'Fetch the full details of a place (address, position, access points, categories, contacts) by its unique id, as returned by place_search, geocode_forward, autosuggest, autocomplete or search_along_route. Parameters: id (required); optional view. Example: {"id": "2EmBgAmFpR9dg0D89EBzNA"}',
|
|
20805
|
+
inputSchema: Schema5,
|
|
20630
20806
|
annotations: READ_ONLY,
|
|
20631
20807
|
async run(args, nb) {
|
|
20632
20808
|
const response = await nb.getJson("/lookup", {
|
|
@@ -20638,7 +20814,7 @@ var placeLookup = {
|
|
|
20638
20814
|
};
|
|
20639
20815
|
|
|
20640
20816
|
// src/tools/places/postcode-lookup.ts
|
|
20641
|
-
var
|
|
20817
|
+
var Schema6 = strictObject({
|
|
20642
20818
|
postal_code: string2().optional().describe("Postal/ZIP code to look up (requires `country`; do not combine with `coordinate`)"),
|
|
20643
20819
|
country: string2().optional().describe(
|
|
20644
20820
|
"Country of the postal code \u2014 name, alpha-2, or alpha-3 ISO code. Required with `postal_code`"
|
|
@@ -20650,12 +20826,11 @@ var Schema5 = strictObject({
|
|
|
20650
20826
|
"Return the boundary polygon in GeoJSON format instead of the default point-list format"
|
|
20651
20827
|
)
|
|
20652
20828
|
});
|
|
20653
|
-
var SUPPORTED_COUNTRIES = "USA, India, UK, Netherlands, Austria, Germany, Indonesia, France, Singapore, Philippines, Canada, Australia, New Zealand, Italy, Brazil, Mexico, Spain";
|
|
20654
20829
|
var postcodeLookup = {
|
|
20655
20830
|
name: "postcode_lookup",
|
|
20656
20831
|
title: "Postcode Lookup",
|
|
20657
|
-
description:
|
|
20658
|
-
inputSchema:
|
|
20832
|
+
description: 'Get the centroid and boundary polygon of a postal/ZIP code, or find the postal code that contains a coordinate; one lookup per call. Supported countries: USA, India, UK, Netherlands, Austria, Germany, Indonesia, France, Singapore, Philippines, Canada, Australia, New Zealand, Italy, Brazil, Mexico, Spain. Parameters: either postal_code plus country (name, alpha-2 or alpha-3 code), or coordinate {latitude, longitude}; optional geojson_boundary (true for a GeoJSON boundary). Example: {"postal_code": "90011", "country": "USA"}',
|
|
20833
|
+
inputSchema: Schema6,
|
|
20659
20834
|
annotations: READ_ONLY,
|
|
20660
20835
|
async run(args, nb) {
|
|
20661
20836
|
if (args.postal_code && args.coordinate) {
|
|
@@ -20698,7 +20873,7 @@ var AVOID_VALUES = [
|
|
|
20698
20873
|
"tunnel",
|
|
20699
20874
|
"none"
|
|
20700
20875
|
];
|
|
20701
|
-
var
|
|
20876
|
+
var Schema7 = strictObject({
|
|
20702
20877
|
origin: CoordinateSchema.describe("Route start (must be a routable land location)"),
|
|
20703
20878
|
destination: CoordinateSchema.describe("Route end (must be a routable land location)"),
|
|
20704
20879
|
waypoints: array(CoordinateSchema).max(200).optional().describe("Intermediate stops visited in order (max 200)"),
|
|
@@ -20713,6 +20888,26 @@ var Schema6 = strictObject({
|
|
|
20713
20888
|
avoid: array(_enum(AVOID_VALUES)).optional().describe(
|
|
20714
20889
|
"Road features to avoid when alternatives exist. Fast service supports only toll/ferry/highway"
|
|
20715
20890
|
),
|
|
20891
|
+
exclude: ExcludeSchema.optional(),
|
|
20892
|
+
road_info: array(
|
|
20893
|
+
_enum([
|
|
20894
|
+
"max_speed",
|
|
20895
|
+
"toll_distance",
|
|
20896
|
+
"toll_cost",
|
|
20897
|
+
"toll_info",
|
|
20898
|
+
"truck_route",
|
|
20899
|
+
"stop_sign",
|
|
20900
|
+
"traffic_light"
|
|
20901
|
+
])
|
|
20902
|
+
).min(1).optional().describe(
|
|
20903
|
+
"Extra per-segment information to return: max_speed, toll_distance, toll_cost, toll_info, truck_route, stop_sign, traffic_light (flexible service only)"
|
|
20904
|
+
),
|
|
20905
|
+
hazmat_type: HazmatSchema.optional(),
|
|
20906
|
+
truck_axle_load: number2().positive().optional().describe("Load per axle in tonnes (truck mode, flexible service only)"),
|
|
20907
|
+
emission_class: EmissionClassSchema.optional(),
|
|
20908
|
+
cross_border: boolean2().optional().describe(
|
|
20909
|
+
"Allow the route to cross international borders (region-dependent, flexible service only)"
|
|
20910
|
+
),
|
|
20716
20911
|
honor_restrictions: boolean2().optional().describe(
|
|
20717
20912
|
"When true, enforce restricted-area rules: no route is generated if origin, destination, or a waypoint is inside a restricted area. Default false: route anyway with a warning (flexible service only)"
|
|
20718
20913
|
),
|
|
@@ -20727,8 +20922,8 @@ var Schema6 = strictObject({
|
|
|
20727
20922
|
var directions = {
|
|
20728
20923
|
name: "directions",
|
|
20729
20924
|
title: "Directions",
|
|
20730
|
-
description:
|
|
20731
|
-
inputSchema:
|
|
20925
|
+
description: 'Calculate a route between an origin and a destination with optional waypoints; returns distance (meters), duration (seconds) and an encoded polyline per route - pass the polyline to static_route_map to draw it. Use distance_matrix for many origin/destination pairs. Parameters: origin, destination {latitude, longitude} (required); optional waypoints (array, max 200), mode (car | truck | motorcycle | bike | walk), service ("flexible" default: all modes and options; "fast": car/truck only, lower latency), route_type, departure_time (UNIX seconds), avoid (soft filter), exclude (strict filter), road_info (max_speed, toll_distance, toll_cost, toll_info, truck_route, stop_sign, traffic_light), honor_restrictions, alternatives, steps (fast only), geometry (polyline | polyline6), truck options: truck_size_cm {height, width, length}, truck_weight_kg, truck_axle_load (tonnes), hazmat_type, emission_class (euro0-euro9), cross_border. Example: {"origin": {"latitude": 37.7749, "longitude": -122.4194}, "destination": {"latitude": 34.0522, "longitude": -118.2437}, "mode": "truck", "truck_weight_kg": 18000, "hazmat_type": ["flammable_liquid"]}',
|
|
20926
|
+
inputSchema: Schema7,
|
|
20732
20927
|
annotations: READ_ONLY,
|
|
20733
20928
|
async run(args, nb) {
|
|
20734
20929
|
const service = args.service ?? "flexible";
|
|
@@ -20746,6 +20941,12 @@ var directions = {
|
|
|
20746
20941
|
route_type: args.route_type,
|
|
20747
20942
|
departure_time: args.departure_time,
|
|
20748
20943
|
avoid: args.avoid?.length ? args.avoid.join("|") : void 0,
|
|
20944
|
+
exclude: args.exclude?.length ? args.exclude.join("|") : void 0,
|
|
20945
|
+
road_info: args.road_info?.length ? args.road_info.join("|") : void 0,
|
|
20946
|
+
hazmat_type: args.hazmat_type?.length ? args.hazmat_type.join("|") : void 0,
|
|
20947
|
+
truck_axle_load: args.truck_axle_load,
|
|
20948
|
+
emission_class: args.emission_class,
|
|
20949
|
+
cross_border: args.cross_border,
|
|
20749
20950
|
honor_restrictions: args.honor_restrictions,
|
|
20750
20951
|
alternatives: args.alternatives,
|
|
20751
20952
|
altcount: args.alternatives ? 3 : void 0,
|
|
@@ -20770,7 +20971,7 @@ Geometry (encoded polyline) is in structured content.` : "No route found.",
|
|
|
20770
20971
|
};
|
|
20771
20972
|
|
|
20772
20973
|
// src/tools/routing/distance-matrix.ts
|
|
20773
|
-
var
|
|
20974
|
+
var Schema8 = strictObject({
|
|
20774
20975
|
origins: array(CoordinateSchema).min(1).max(1e3).describe("Start points (matrix rows)"),
|
|
20775
20976
|
destinations: array(CoordinateSchema).min(1).max(1e3).describe("End points (matrix columns)"),
|
|
20776
20977
|
mode: _enum(["car", "truck", "motorcycle", "bike", "walk"]).optional().describe("Travel mode (default car). Modes other than car/truck require service=flexible"),
|
|
@@ -20782,6 +20983,16 @@ var Schema7 = strictObject({
|
|
|
20782
20983
|
"Departure as a UNIX timestamp in seconds, for typical-traffic results (flexible only)"
|
|
20783
20984
|
),
|
|
20784
20985
|
avoid: array(_enum(["toll", "highway", "ferry", "none"])).optional().describe("Road features to avoid"),
|
|
20986
|
+
exclude: ExcludeSchema.optional(),
|
|
20987
|
+
hazmat_type: HazmatSchema.optional(),
|
|
20988
|
+
truck_axle_load: number2().positive().optional().describe("Load per axle in tonnes (truck mode, flexible service only)"),
|
|
20989
|
+
emission_class: EmissionClassSchema.optional(),
|
|
20990
|
+
cross_border: boolean2().optional().describe(
|
|
20991
|
+
"Allow routes to cross international borders (region-dependent, flexible service only)"
|
|
20992
|
+
),
|
|
20993
|
+
route_failed_prompt: boolean2().optional().describe(
|
|
20994
|
+
"When true, unroutable origin/destination pairs return -1 instead of 0 so they can be told apart from zero-distance pairs"
|
|
20995
|
+
),
|
|
20785
20996
|
honor_restrictions: boolean2().optional().describe(
|
|
20786
20997
|
"When true, enforce restricted-area rules for origin/destination points instead of routing through with a warning (flexible service only)"
|
|
20787
20998
|
),
|
|
@@ -20791,8 +21002,8 @@ var Schema7 = strictObject({
|
|
|
20791
21002
|
var distanceMatrix = {
|
|
20792
21003
|
name: "distance_matrix",
|
|
20793
21004
|
title: "Distance Matrix",
|
|
20794
|
-
description:
|
|
20795
|
-
inputSchema:
|
|
21005
|
+
description: 'Compute travel distance (meters) and duration (seconds) for every origin-to-destination pair in one call; one row per origin with one element per destination, in input order. Always prefer this over repeated directions calls for multiple pairs. Parameters: origins, destinations (arrays of {latitude, longitude}, required); optional mode, service ("fast" default: up to 1000x1000 points; "flexible": the options below, max 50x50), route_type, departure_time, avoid (soft), exclude (strict), honor_restrictions, route_failed_prompt (unroutable pairs return -1 instead of 0), truck options: truck_size_cm {height, width, length}, truck_weight_kg, truck_axle_load, hazmat_type, emission_class, cross_border. Example: {"origins": [{"latitude": 1.29, "longitude": 103.85}], "destinations": [{"latitude": 1.35, "longitude": 103.99}, {"latitude": 1.3, "longitude": 103.77}], "route_failed_prompt": true}',
|
|
21006
|
+
inputSchema: Schema8,
|
|
20796
21007
|
annotations: READ_ONLY,
|
|
20797
21008
|
async run(args, nb) {
|
|
20798
21009
|
const service = args.service ?? "fast";
|
|
@@ -20814,6 +21025,12 @@ var distanceMatrix = {
|
|
|
20814
21025
|
route_type: args.route_type,
|
|
20815
21026
|
departure_time: args.departure_time,
|
|
20816
21027
|
avoid: args.avoid?.length ? args.avoid.join("|") : void 0,
|
|
21028
|
+
exclude: args.exclude?.length ? args.exclude.join("|") : void 0,
|
|
21029
|
+
hazmat_type: args.hazmat_type?.length ? args.hazmat_type.join("|") : void 0,
|
|
21030
|
+
truck_axle_load: args.truck_axle_load,
|
|
21031
|
+
emission_class: args.emission_class,
|
|
21032
|
+
cross_border: args.cross_border,
|
|
21033
|
+
route_failed_prompt: args.route_failed_prompt,
|
|
20817
21034
|
honor_restrictions: args.honor_restrictions,
|
|
20818
21035
|
truck_size: args.truck_size_cm ? `${args.truck_size_cm.height},${args.truck_size_cm.width},${args.truck_size_cm.length}` : void 0,
|
|
20819
21036
|
truck_weight: args.truck_weight_kg
|
|
@@ -20828,7 +21045,7 @@ var distanceMatrix = {
|
|
|
20828
21045
|
};
|
|
20829
21046
|
|
|
20830
21047
|
// src/tools/routing/isochrone.ts
|
|
20831
|
-
var
|
|
21048
|
+
var Schema9 = strictObject({
|
|
20832
21049
|
origin: CoordinateSchema.describe("Starting point of the reachability analysis"),
|
|
20833
21050
|
contours_minutes: array(number2().int().min(1).max(40)).max(4).optional().describe("Travel times in minutes, one contour each (max 4 values, increasing, max 40)"),
|
|
20834
21051
|
contours_meters: array(number2().int().min(1).max(6e4)).max(4).optional().describe("Travel distances in meters, one contour each (max 4 values, increasing, max 60000)"),
|
|
@@ -20837,13 +21054,15 @@ var Schema8 = strictObject({
|
|
|
20837
21054
|
denoise: number2().min(0).max(1).optional().describe(
|
|
20838
21055
|
"Remove contours smaller than this fraction of the largest (default 1: largest only)"
|
|
20839
21056
|
),
|
|
20840
|
-
departure_time: number2().int().optional().describe("Departure as a UNIX timestamp in seconds, for typical-traffic analysis")
|
|
21057
|
+
departure_time: number2().int().optional().describe("Departure as a UNIX timestamp in seconds, for typical-traffic analysis"),
|
|
21058
|
+
contours_colors: array(string2().regex(/^[0-9a-fA-F]{6}$/, "hex color without #, e.g. ff0000")).max(4).optional().describe('One hex color (without #) per contour, e.g. ["ff0000", "00ff00"]'),
|
|
21059
|
+
generalize: number2().positive().optional().describe("Simplification tolerance in meters (Douglas-Peucker); omit for automatic")
|
|
20841
21060
|
});
|
|
20842
21061
|
var isochrone = {
|
|
20843
21062
|
name: "isochrone",
|
|
20844
21063
|
title: "Isochrone",
|
|
20845
|
-
description:
|
|
20846
|
-
inputSchema:
|
|
21064
|
+
description: 'Calculate the area reachable from a point within given travel times or distances; returns a GeoJSON FeatureCollection of contours (geometry coordinates are [longitude, latitude]). To draw the result, pass each contour ring to static_route_map as paths[].geojson_coordinates with a fill_color. Parameters: origin {latitude, longitude} (required); exactly one of contours_minutes (array, up to 4 values, max 40) or contours_meters (array, up to 4 values, max 60000); optional mode, polygons (true for Polygon geometry), denoise, generalize (meters), contours_colors (hex without #, one per contour), departure_time. Example: {"origin": {"latitude": 37.7749, "longitude": -122.4194}, "contours_minutes": [5, 10], "polygons": true}',
|
|
21065
|
+
inputSchema: Schema9,
|
|
20847
21066
|
annotations: READ_ONLY,
|
|
20848
21067
|
async run(args, nb) {
|
|
20849
21068
|
if (!args.contours_minutes?.length && !args.contours_meters?.length) {
|
|
@@ -20859,7 +21078,9 @@ var isochrone = {
|
|
|
20859
21078
|
mode: args.mode,
|
|
20860
21079
|
polygons: args.polygons,
|
|
20861
21080
|
denoise: args.denoise,
|
|
20862
|
-
departure_time: args.departure_time
|
|
21081
|
+
departure_time: args.departure_time,
|
|
21082
|
+
contours_colors: args.contours_colors?.join(","),
|
|
21083
|
+
generalize: args.generalize
|
|
20863
21084
|
});
|
|
20864
21085
|
const features = response.features ?? [];
|
|
20865
21086
|
const metric = args.contours_minutes?.length ? "minutes" : "meters";
|
|
@@ -20872,18 +21093,19 @@ var isochrone = {
|
|
|
20872
21093
|
};
|
|
20873
21094
|
|
|
20874
21095
|
// src/tools/routing/search-along-route.ts
|
|
20875
|
-
var
|
|
21096
|
+
var Schema10 = strictObject({
|
|
20876
21097
|
route_points: array(CoordinateSchema).min(2).describe("Waypoints defining the route to search along, in travel order"),
|
|
20877
21098
|
query: string2().min(1).describe('What to find along the route, e.g. "gas station", "coffee"'),
|
|
20878
21099
|
max_detour_seconds: number2().int().min(1).max(3600).optional().describe("Max driving time to reach a result after leaving the route (default 900 = 15 min)"),
|
|
20879
21100
|
sort_by: _enum(["detour_time", "detour_offset"]).optional().describe("Order by detour driving time, or by distance of the detour point from route start"),
|
|
20880
|
-
limit: number2().int().min(1).max(20).optional().describe("Maximum results (default 10, max 20)")
|
|
21101
|
+
limit: number2().int().min(1).max(20).optional().describe("Maximum results (default 10, max 20)"),
|
|
21102
|
+
view: _enum(["Unified", "AR", "CN", "IN", "PK", "MA", "RU", "RS", "TW", "TR"]).optional().describe("Geopolitical view for disputed territories (default: requester region or Unified)")
|
|
20881
21103
|
});
|
|
20882
21104
|
var searchAlongRoute = {
|
|
20883
21105
|
name: "search_along_route",
|
|
20884
21106
|
title: "Search Along Route",
|
|
20885
|
-
description: 'Find places
|
|
20886
|
-
inputSchema:
|
|
21107
|
+
description: 'Find places matching a text query along a driving route, with the detour time and distance each stop adds - for "find X on the way" questions. Pass the route as an ordered list of waypoints, e.g. the origin, waypoints and destination used with directions. Parameters: route_points (array of {latitude, longitude}, at least 2, required), query (required); optional max_detour_seconds (default 900, max 3600), sort_by (detour_time | detour_offset), limit (max 20), view. Example: {"route_points": [{"latitude": 34.0493, "longitude": -118.2557}, {"latitude": 34.0415, "longitude": -118.231}], "query": "gas station", "max_detour_seconds": 600}',
|
|
21108
|
+
inputSchema: Schema10,
|
|
20887
21109
|
annotations: READ_ONLY,
|
|
20888
21110
|
async run(args, nb) {
|
|
20889
21111
|
const response = await nb.postJson(
|
|
@@ -20894,7 +21116,8 @@ var searchAlongRoute = {
|
|
|
20894
21116
|
q: args.query,
|
|
20895
21117
|
max_detour_time: args.max_detour_seconds,
|
|
20896
21118
|
sort_by: args.sort_by,
|
|
20897
|
-
limit: args.limit
|
|
21119
|
+
limit: args.limit,
|
|
21120
|
+
view: args.view
|
|
20898
21121
|
}
|
|
20899
21122
|
);
|
|
20900
21123
|
const items = response.items ?? [];
|
|
@@ -20927,84 +21150,6 @@ function logInfo(message) {
|
|
|
20927
21150
|
console.error(`[nextbillion-mcp] ${message}`);
|
|
20928
21151
|
}
|
|
20929
21152
|
|
|
20930
|
-
// src/tools/maps/static-shared.ts
|
|
20931
|
-
var StaticImageShape = {
|
|
20932
|
-
width: number2().int().min(16).max(2048).optional().describe("Image width in pixels (default 512)"),
|
|
20933
|
-
height: number2().int().min(16).max(2048).optional().describe("Image height in pixels (default 512)"),
|
|
20934
|
-
style: string2().optional().describe('Map style id: "streets", "light", "dark", or "hybrid" (default streets)'),
|
|
20935
|
-
format: _enum(["png", "jpg", "webp"]).optional().describe("Image format (default png)"),
|
|
20936
|
-
retina: boolean2().optional().describe("Render at @2x resolution for high-DPI displays")
|
|
20937
|
-
};
|
|
20938
|
-
var MIME_TYPES = {
|
|
20939
|
-
png: "image/png",
|
|
20940
|
-
jpg: "image/jpeg",
|
|
20941
|
-
webp: "image/webp"
|
|
20942
|
-
};
|
|
20943
|
-
function staticImagePath(positionSegment, args) {
|
|
20944
|
-
const style = args.style ?? "streets";
|
|
20945
|
-
const size = `${args.width ?? 512}x${args.height ?? 512}${args.retina ? "@2x" : ""}`;
|
|
20946
|
-
const format = args.format ?? "png";
|
|
20947
|
-
return `/maps/${encodeURIComponent(style)}/static/${positionSegment}/${size}.${format}`;
|
|
20948
|
-
}
|
|
20949
|
-
function markerParam(markers, order) {
|
|
20950
|
-
return markers.map((m) => {
|
|
20951
|
-
const pair = order === "lng-first" ? `${m.longitude},${m.latitude}` : `${m.latitude},${m.longitude}`;
|
|
20952
|
-
return `${pair}${m.color ? `,${m.color}` : ""}`;
|
|
20953
|
-
}).join("|");
|
|
20954
|
-
}
|
|
20955
|
-
async function fetchImageResult(nb, path, query, caption, args, filePrefix = "map") {
|
|
20956
|
-
const image = await nb.getBinary(path, query);
|
|
20957
|
-
const mimeType = image.contentType.startsWith("image/") ? image.contentType : MIME_TYPES[args.format ?? "png"];
|
|
20958
|
-
const savedPath = await saveImage(image.data, filePrefix, args.format ?? "png");
|
|
20959
|
-
const location = savedPath ? ` Saved to ${savedPath} (for clients that cannot display images inline).` : "";
|
|
20960
|
-
return {
|
|
20961
|
-
content: [
|
|
20962
|
-
{ type: "image", data: Buffer.from(image.data).toString("base64"), mimeType },
|
|
20963
|
-
{ type: "text", text: caption + location }
|
|
20964
|
-
]
|
|
20965
|
-
};
|
|
20966
|
-
}
|
|
20967
|
-
async function saveImage(data, prefix, ext) {
|
|
20968
|
-
try {
|
|
20969
|
-
const dir = imageOutputDir();
|
|
20970
|
-
await mkdir(dir, { recursive: true });
|
|
20971
|
-
const hash = createHash("sha1").update(data).digest("hex").slice(0, 8);
|
|
20972
|
-
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\..+/, "");
|
|
20973
|
-
const filePath = join2(dir, `${prefix}-${stamp}-${hash}.${ext === "jpg" ? "jpg" : ext}`);
|
|
20974
|
-
await writeFile(filePath, data);
|
|
20975
|
-
return filePath;
|
|
20976
|
-
} catch (error2) {
|
|
20977
|
-
logError("Could not save rendered image to disk", error2);
|
|
20978
|
-
return void 0;
|
|
20979
|
-
}
|
|
20980
|
-
}
|
|
20981
|
-
|
|
20982
|
-
// src/tools/maps/static-map-image.ts
|
|
20983
|
-
var Schema10 = strictObject({
|
|
20984
|
-
center: CoordinateSchema.describe("Center of the map view"),
|
|
20985
|
-
zoom: number2().min(0).max(22).describe("Zoom level (0 = world, ~10 = city, ~15 = streets; fractional values allowed)"),
|
|
20986
|
-
markers: array(CoordinateSchema.extend({ color: string2().optional() })).optional().describe('Markers to draw, each with optional color (e.g. "red", "#0000ff")'),
|
|
20987
|
-
...StaticImageShape
|
|
20988
|
-
});
|
|
20989
|
-
var staticMapImage = {
|
|
20990
|
-
name: "static_map_image",
|
|
20991
|
-
title: "Static Map Image",
|
|
20992
|
-
description: "Render a static map image centered on a location, with optional markers. Returns the image directly. To draw a route on a map use static_route_map instead.",
|
|
20993
|
-
inputSchema: Schema10,
|
|
20994
|
-
annotations: READ_ONLY,
|
|
20995
|
-
async run(args, nb) {
|
|
20996
|
-
const position = `${args.center.latitude},${args.center.longitude},${args.zoom}`;
|
|
20997
|
-
return fetchImageResult(
|
|
20998
|
-
nb,
|
|
20999
|
-
staticImagePath(position, args),
|
|
21000
|
-
{ markers: args.markers?.length ? markerParam(args.markers, "lng-first") : void 0 },
|
|
21001
|
-
`Map centered at (${args.center.latitude}, ${args.center.longitude}), zoom ${args.zoom}` + (args.markers?.length ? `, ${args.markers.length} marker(s).` : "."),
|
|
21002
|
-
args,
|
|
21003
|
-
"map"
|
|
21004
|
-
);
|
|
21005
|
-
}
|
|
21006
|
-
};
|
|
21007
|
-
|
|
21008
21153
|
// src/tools/maps/polyline.ts
|
|
21009
21154
|
var PRECISION = 1e5;
|
|
21010
21155
|
function decodePolyline(encoded) {
|
|
@@ -21109,64 +21254,233 @@ function fitPolylineToBudget(points, maxEncodedChars) {
|
|
|
21109
21254
|
};
|
|
21110
21255
|
}
|
|
21111
21256
|
|
|
21112
|
-
// src/tools/maps/static-
|
|
21257
|
+
// src/tools/maps/static-shared.ts
|
|
21258
|
+
var StaticImageShape = {
|
|
21259
|
+
width: number2().int().min(16).max(2048).optional().describe("Image width in pixels (default 512)"),
|
|
21260
|
+
height: number2().int().min(16).max(2048).optional().describe("Image height in pixels (default 512)"),
|
|
21261
|
+
style: string2().optional().describe('Map style id: "streets", "light", "dark", or "hybrid" (default streets)'),
|
|
21262
|
+
format: _enum(["png", "jpg", "webp"]).optional().describe("Image format (default png)"),
|
|
21263
|
+
retina: boolean2().optional().describe("Render at @2x resolution for high-DPI displays")
|
|
21264
|
+
};
|
|
21265
|
+
var MarkerSchema = strictObject({
|
|
21266
|
+
latitude: number2().min(-90).max(90),
|
|
21267
|
+
longitude: number2().min(-180).max(180),
|
|
21268
|
+
color: string2().optional().describe('Marker color, e.g. "red" or "#0000ff" (ignored when icon_url is set)'),
|
|
21269
|
+
icon_url: string2().url().optional().describe("URL of a custom marker image (max 64 kB / 4096 px, e.g. 64x64 PNG)"),
|
|
21270
|
+
anchor: _enum([
|
|
21271
|
+
"top",
|
|
21272
|
+
"left",
|
|
21273
|
+
"bottom",
|
|
21274
|
+
"right",
|
|
21275
|
+
"center",
|
|
21276
|
+
"topleft",
|
|
21277
|
+
"bottomleft",
|
|
21278
|
+
"topright",
|
|
21279
|
+
"bottomright"
|
|
21280
|
+
]).optional().describe("Anchor point of a custom icon (default bottom)"),
|
|
21281
|
+
scale: number2().positive().optional().describe("Custom icon scale factor (default 1)")
|
|
21282
|
+
});
|
|
21283
|
+
var PathSchema = strictObject({
|
|
21284
|
+
points: array(CoordinateSchema).min(2).optional().describe("Vertices as {latitude, longitude} objects"),
|
|
21285
|
+
geojson_coordinates: array(tuple([number2(), number2()])).min(2).optional().describe(
|
|
21286
|
+
"Vertices as GeoJSON [longitude, latitude] pairs - pass an isochrone or GeoJSON ring here unchanged"
|
|
21287
|
+
),
|
|
21288
|
+
stroke_color: string2().optional().describe("Line color (default blue)"),
|
|
21289
|
+
stroke_width: number2().int().min(1).max(20).optional().describe("Line width in px (default 3)"),
|
|
21290
|
+
fill_color: string2().optional().describe(
|
|
21291
|
+
'Fill color for a closed shape, e.g. "rgba(255,0,0,0.3)" or "#ff000055"; omit for a line'
|
|
21292
|
+
)
|
|
21293
|
+
}).describe("A line or filled polygon overlay");
|
|
21294
|
+
var PathsShape = {
|
|
21295
|
+
paths: array(PathSchema).max(10).optional().describe("Extra lines/polygons to draw (e.g. isochrone contours as filled polygons)")
|
|
21296
|
+
};
|
|
21297
|
+
var MIME_TYPES = {
|
|
21298
|
+
png: "image/png",
|
|
21299
|
+
jpg: "image/jpeg",
|
|
21300
|
+
webp: "image/webp"
|
|
21301
|
+
};
|
|
21302
|
+
function staticImagePath(positionSegment, args) {
|
|
21303
|
+
const style = args.style ?? "streets";
|
|
21304
|
+
const size = `${args.width ?? 512}x${args.height ?? 512}${args.retina ? "@2x" : ""}`;
|
|
21305
|
+
const format = args.format ?? "png";
|
|
21306
|
+
return `/maps/${encodeURIComponent(style)}/static/${positionSegment}/${size}.${format}`;
|
|
21307
|
+
}
|
|
21308
|
+
function markerParam(markers, order) {
|
|
21309
|
+
return markers.map((m) => {
|
|
21310
|
+
const pair = order === "lng-first" ? `${m.longitude},${m.latitude}` : `${m.latitude},${m.longitude}`;
|
|
21311
|
+
const commands = [];
|
|
21312
|
+
if (m.icon_url) commands.push(`icon:${m.icon_url}`);
|
|
21313
|
+
if (m.anchor) commands.push(`anchor:${m.anchor}`);
|
|
21314
|
+
if (m.scale !== void 0) commands.push(`scale:${m.scale}`);
|
|
21315
|
+
const color = m.color && !m.icon_url ? `,${m.color}` : "";
|
|
21316
|
+
return `${commands.length ? commands.join("|") + "|" : ""}${pair}${color}`;
|
|
21317
|
+
}).join("|");
|
|
21318
|
+
}
|
|
21319
|
+
async function fetchImageResult(nb, path, query, caption, args, filePrefix = "map") {
|
|
21320
|
+
const image = await nb.getBinary(path, query);
|
|
21321
|
+
const mimeType = image.contentType.startsWith("image/") ? image.contentType : MIME_TYPES[args.format ?? "png"];
|
|
21322
|
+
const savedPath = await saveImage(image.data, filePrefix, args.format ?? "png");
|
|
21323
|
+
const location = savedPath ? ` Saved to ${savedPath} (for clients that cannot display images inline).` : "";
|
|
21324
|
+
return {
|
|
21325
|
+
content: [
|
|
21326
|
+
{ type: "image", data: Buffer.from(image.data).toString("base64"), mimeType },
|
|
21327
|
+
{ type: "text", text: caption + location }
|
|
21328
|
+
]
|
|
21329
|
+
};
|
|
21330
|
+
}
|
|
21331
|
+
async function saveImage(data, prefix, ext) {
|
|
21332
|
+
try {
|
|
21333
|
+
const dir = imageOutputDir();
|
|
21334
|
+
await mkdir(dir, { recursive: true });
|
|
21335
|
+
const hash = createHash("sha1").update(data).digest("hex").slice(0, 8);
|
|
21336
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\..+/, "");
|
|
21337
|
+
const filePath = join2(dir, `${prefix}-${stamp}-${hash}.${ext === "jpg" ? "jpg" : ext}`);
|
|
21338
|
+
await writeFile(filePath, data);
|
|
21339
|
+
return filePath;
|
|
21340
|
+
} catch (error2) {
|
|
21341
|
+
logError("Could not save rendered image to disk", error2);
|
|
21342
|
+
return void 0;
|
|
21343
|
+
}
|
|
21344
|
+
}
|
|
21345
|
+
var URL_BYTE_BUDGET = 8e3;
|
|
21346
|
+
function pathVertices(path) {
|
|
21347
|
+
const vertices = path.points?.length ? path.points : (path.geojson_coordinates ?? []).map(([longitude, latitude]) => ({ latitude, longitude }));
|
|
21348
|
+
if (path.fill_color && vertices.length >= 3) {
|
|
21349
|
+
const first = vertices[0];
|
|
21350
|
+
const last = vertices[vertices.length - 1];
|
|
21351
|
+
if (first.latitude !== last.latitude || first.longitude !== last.longitude) {
|
|
21352
|
+
return [...vertices, first];
|
|
21353
|
+
}
|
|
21354
|
+
}
|
|
21355
|
+
return vertices;
|
|
21356
|
+
}
|
|
21357
|
+
function pathParams(paths, maxEncodedChars = Number.POSITIVE_INFINITY) {
|
|
21358
|
+
let simplified = false;
|
|
21359
|
+
const values = paths.map((path) => {
|
|
21360
|
+
const style = [
|
|
21361
|
+
`stroke:${path.stroke_color ?? "blue"}`,
|
|
21362
|
+
`width:${path.stroke_width ?? 3}`,
|
|
21363
|
+
`fill:${path.fill_color ?? "none"}`
|
|
21364
|
+
];
|
|
21365
|
+
const fitted = fitPolylineToBudget(pathVertices(path), maxEncodedChars);
|
|
21366
|
+
simplified ||= fitted.simplified;
|
|
21367
|
+
return `${style.join("|")}|enc:${fitted.encoded}`;
|
|
21368
|
+
});
|
|
21369
|
+
return { values, simplified };
|
|
21370
|
+
}
|
|
21371
|
+
|
|
21372
|
+
// src/tools/maps/static-map-image.ts
|
|
21113
21373
|
var Schema11 = strictObject({
|
|
21374
|
+
center: CoordinateSchema.describe("Center of the map view"),
|
|
21375
|
+
zoom: number2().min(0).max(22).describe("Zoom level (0 = world, ~10 = city, ~15 = streets; fractional values allowed)"),
|
|
21376
|
+
markers: array(MarkerSchema).optional().describe("Markers to draw, each with optional color or custom icon"),
|
|
21377
|
+
...PathsShape,
|
|
21378
|
+
...StaticImageShape
|
|
21379
|
+
});
|
|
21380
|
+
var staticMapImage = {
|
|
21381
|
+
name: "static_map_image",
|
|
21382
|
+
title: "Static Map Image",
|
|
21383
|
+
description: 'Render a static map image centered on a location, with optional markers and line/polygon overlays; returns the image inline and also saves it to a local file (path in the result text) for clients that cannot display images. For a map auto-fitted to a route or to overlays, use static_route_map. Parameters: center {latitude, longitude} and zoom (0-22) (required); optional markers (array of {latitude, longitude, color, icon_url, anchor, scale}), paths (array of {points [{latitude, longitude}] OR geojson_coordinates [[longitude, latitude], ...], stroke_color, stroke_width, fill_color for a filled polygon}), width, height (default 512), style (streets | light | dark | hybrid), format (png | jpg | webp), retina. Example: {"center": {"latitude": 48.8566, "longitude": 2.3522}, "zoom": 14, "markers": [{"latitude": 48.8584, "longitude": 2.2945, "color": "red"}], "paths": [{"points": [{"latitude": 48.85, "longitude": 2.29}, {"latitude": 48.86, "longitude": 2.30}], "stroke_color": "green"}]}',
|
|
21384
|
+
inputSchema: Schema11,
|
|
21385
|
+
annotations: READ_ONLY,
|
|
21386
|
+
async run(args, nb) {
|
|
21387
|
+
const position = `${args.center.latitude},${args.center.longitude},${args.zoom}`;
|
|
21388
|
+
const path = staticImagePath(position, args);
|
|
21389
|
+
const markers = args.markers?.length ? markerParam(args.markers, "lng-first") : void 0;
|
|
21390
|
+
let overlay = args.paths?.length ? pathParams(args.paths) : void 0;
|
|
21391
|
+
for (const budget of [4e3, 2e3, 1e3, 500, 200]) {
|
|
21392
|
+
if (!overlay || nb.buildUrl(path, { markers, path: overlay.values }).length <= URL_BYTE_BUDGET)
|
|
21393
|
+
break;
|
|
21394
|
+
overlay = pathParams(args.paths, budget);
|
|
21395
|
+
}
|
|
21396
|
+
const parts = [
|
|
21397
|
+
`Map centered at (${args.center.latitude}, ${args.center.longitude}), zoom ${args.zoom}`
|
|
21398
|
+
];
|
|
21399
|
+
if (args.markers?.length) parts.push(`${args.markers.length} marker(s)`);
|
|
21400
|
+
if (args.paths?.length)
|
|
21401
|
+
parts.push(
|
|
21402
|
+
`${args.paths.length} overlay path(s)${overlay?.simplified ? " (simplified to fit the URL limit)" : ""}`
|
|
21403
|
+
);
|
|
21404
|
+
return fetchImageResult(
|
|
21405
|
+
nb,
|
|
21406
|
+
path,
|
|
21407
|
+
{ markers, path: overlay?.values },
|
|
21408
|
+
`${parts.join(", ")}.`,
|
|
21409
|
+
args,
|
|
21410
|
+
"map"
|
|
21411
|
+
);
|
|
21412
|
+
}
|
|
21413
|
+
};
|
|
21414
|
+
|
|
21415
|
+
// src/tools/maps/static-route-map.ts
|
|
21416
|
+
var Schema12 = strictObject({
|
|
21114
21417
|
encoded_polyline: string2().optional().describe(
|
|
21115
21418
|
"Route geometry as a Google encoded polyline (precision 5) \u2014 exactly what the directions tool returns with its default geometry setting"
|
|
21116
21419
|
),
|
|
21117
21420
|
route_points: array(CoordinateSchema).min(2).optional().describe("Alternative to encoded_polyline: the route as an ordered list of coordinates"),
|
|
21118
|
-
markers: array(
|
|
21421
|
+
markers: array(MarkerSchema).optional().describe("Extra markers, e.g. origin and destination, with optional color or custom icon"),
|
|
21422
|
+
...PathsShape,
|
|
21119
21423
|
stroke_color: string2().optional().describe('Route line color (e.g. "blue", "#ff0000"; default blue)'),
|
|
21120
21424
|
stroke_width: number2().int().min(1).max(20).optional().describe("Route line width in pixels (default 4)"),
|
|
21121
21425
|
padding: number2().min(0).max(1).optional().describe("Margin around the route as a fraction of image size (default 0.1)"),
|
|
21122
21426
|
...StaticImageShape
|
|
21123
21427
|
});
|
|
21124
|
-
var URL_BYTE_BUDGET = 8e3;
|
|
21125
21428
|
var ENCODED_CHAR_BUDGETS = [4e3, 3e3, 2e3, 1200, 600, 200];
|
|
21126
21429
|
var staticRouteMap = {
|
|
21127
21430
|
name: "static_route_map",
|
|
21128
21431
|
title: "Static Route Map",
|
|
21129
|
-
description:
|
|
21130
|
-
inputSchema:
|
|
21432
|
+
description: 'Render a static map auto-fitted to a route and/or overlays: a route from directions, and/or lines and filled polygons such as isochrone contours; very long geometry is simplified automatically to fit the map API URL limit (distances unaffected). Returns the image inline and also saves it to a local file (path in the result text). Parameters: at least one of encoded_polyline (the geometry string from directions, preferred), route_points (array of {latitude, longitude}) or paths (array of {points OR geojson_coordinates [[longitude, latitude], ...], stroke_color, stroke_width, fill_color}); optional markers (array of {latitude, longitude, color, icon_url, anchor, scale}), stroke_color, stroke_width (route line), padding, width, height, style, format, retina. Example (isochrone contours) - Example: {"paths": [{"geojson_coordinates": [[-122.42, 37.77], [-122.40, 37.78], [-122.41, 37.79], [-122.42, 37.77]], "fill_color": "rgba(29,78,216,0.35)", "stroke_color": "#1d4ed8"}], "markers": [{"latitude": 37.7749, "longitude": -122.4194, "color": "red"}]}',
|
|
21433
|
+
inputSchema: Schema12,
|
|
21131
21434
|
annotations: READ_ONLY,
|
|
21132
21435
|
async run(args, nb) {
|
|
21133
|
-
if (!args.encoded_polyline && !args.route_points) {
|
|
21134
|
-
throw new ToolInputError("Provide `encoded_polyline` (preferred) or `route_points`.");
|
|
21135
|
-
}
|
|
21136
21436
|
if (args.encoded_polyline && args.route_points) {
|
|
21137
21437
|
throw new ToolInputError("Provide either `encoded_polyline` or `route_points`, not both.");
|
|
21138
21438
|
}
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
21142
|
-
|
|
21143
|
-
|
|
21439
|
+
if (!args.encoded_polyline && !args.route_points && !args.paths?.length) {
|
|
21440
|
+
throw new ToolInputError(
|
|
21441
|
+
"Provide a route (`encoded_polyline` or `route_points`) and/or overlay `paths`."
|
|
21442
|
+
);
|
|
21443
|
+
}
|
|
21144
21444
|
const markers = args.markers?.length ? markerParam(args.markers, "lat-first") : void 0;
|
|
21145
21445
|
const padding = args.padding !== void 0 ? String(args.padding) : void 0;
|
|
21146
21446
|
const path = staticImagePath("auto", args);
|
|
21147
|
-
const
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21154
|
-
|
|
21155
|
-
|
|
21156
|
-
|
|
21157
|
-
const fitted = fitPolylineToBudget(
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21447
|
+
const routeStyle = [
|
|
21448
|
+
`stroke:${args.stroke_color ?? "blue"}`,
|
|
21449
|
+
`width:${args.stroke_width ?? 4}`,
|
|
21450
|
+
"fill:none"
|
|
21451
|
+
].join("|");
|
|
21452
|
+
const routePoints = args.encoded_polyline ? decodePolyline(args.encoded_polyline) : args.route_points ?? [];
|
|
21453
|
+
const build2 = (budget) => {
|
|
21454
|
+
const values = [];
|
|
21455
|
+
let simplified = false;
|
|
21456
|
+
if (routePoints.length) {
|
|
21457
|
+
const fitted = fitPolylineToBudget(routePoints, budget);
|
|
21458
|
+
simplified ||= fitted.simplified;
|
|
21459
|
+
values.push(`${routeStyle}|enc:${fitted.encoded}`);
|
|
21460
|
+
}
|
|
21461
|
+
if (args.paths?.length) {
|
|
21462
|
+
const overlay = pathParams(args.paths, budget);
|
|
21463
|
+
simplified ||= overlay.simplified;
|
|
21464
|
+
values.push(...overlay.values);
|
|
21465
|
+
}
|
|
21466
|
+
return { values, simplified };
|
|
21467
|
+
};
|
|
21468
|
+
let built = build2(Number.POSITIVE_INFINITY);
|
|
21469
|
+
for (const budget of ENCODED_CHAR_BUDGETS) {
|
|
21470
|
+
if (nb.buildUrl(path, { path: built.values, markers, padding }).length <= URL_BYTE_BUDGET)
|
|
21471
|
+
break;
|
|
21472
|
+
built = build2(budget);
|
|
21164
21473
|
}
|
|
21474
|
+
const parts = ["Map rendered"];
|
|
21475
|
+
if (routePoints.length) parts.push("with the route");
|
|
21476
|
+
if (args.paths?.length) parts.push(`${args.paths.length} overlay path(s)`);
|
|
21477
|
+
if (args.markers?.length) parts.push(`${args.markers.length} marker(s)`);
|
|
21478
|
+
const note = built.simplified ? " Display geometry was simplified to fit the map URL limit; distances are unaffected." : "";
|
|
21165
21479
|
return fetchImageResult(
|
|
21166
21480
|
nb,
|
|
21167
21481
|
path,
|
|
21168
|
-
|
|
21169
|
-
|
|
21482
|
+
{ path: built.values, markers, padding },
|
|
21483
|
+
`${parts.join(", ")}.${note}`,
|
|
21170
21484
|
args,
|
|
21171
21485
|
"route-map"
|
|
21172
21486
|
);
|
|
@@ -21184,6 +21498,7 @@ var ALL_TOOLS = [
|
|
|
21184
21498
|
geocodeReverse,
|
|
21185
21499
|
geocodeStructured,
|
|
21186
21500
|
isochrone,
|
|
21501
|
+
placeBrowse,
|
|
21187
21502
|
placeLookup,
|
|
21188
21503
|
placeSearch,
|
|
21189
21504
|
postcodeLookup,
|
|
@@ -21354,7 +21669,7 @@ function extractApiMessage(bodyText) {
|
|
|
21354
21669
|
}
|
|
21355
21670
|
|
|
21356
21671
|
// src/index.ts
|
|
21357
|
-
var pkg = true ? { version: "0.
|
|
21672
|
+
var pkg = true ? { version: "0.2.0" } : createRequire(import.meta.url)("../package.json");
|
|
21358
21673
|
function main() {
|
|
21359
21674
|
const args = process.argv.slice(2);
|
|
21360
21675
|
if (args.includes("--version") || args.includes("-v")) {
|
package/package.json
CHANGED