@tomtom-org/maps-sdk-plugin-agent-toolkit 0.2.3 → 0.2.4

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.
@@ -0,0 +1,2 @@
1
+ import{Output as e,ToolLoopAgent as t,generateText as o,stepCountIs as a,tool as r}from"ai";import{TomTomConfig as i,avoidableTypes as s,bboxFromGeoJSON as n,formatDistance as l,formatDuration as c,getCoordinateAtRouteProgress as u,getPosition as d,getRouteProgressForSection as p,getSectionBBox as m,poiCategories as h,sectionTypes as g,trafficIncidentCategories as f,withInsertedWaypoint as y}from"@tomtom-org/maps-sdk/core";import{BaseMapModule as b,GeometriesModule as w,HillshadeModule as v,POIsModule as S,PlacesModule as x,RoutingModule as P,TrafficAreaAnalyticsModule as M,TrafficFlowModule as T,TrafficIncidentsModule as I,baseMapLayerGroupNames as R,reachableRangeGeometryConfig as L,standardStyleIDs as A}from"@tomtom-org/maps-sdk/map";import{z as O}from"zod";import{alongRouteSearch as C,calculateReachableRanges as D,calculateRoute as j,geocode as E,geocodeOne as _,geometryData as k,getPOICategoryCodes as F,reverseGeocode as N,routeTypes as $,search as q,searchOne as B,trafficAreaAnalytics as z,trafficIncidentDetails as W}from"@tomtom-org/maps-sdk/services";var U=(e,t)=>{const o={...e};if(!t)return o;for(const[a,r]of Object.entries(t))r?o[a]=r:delete o[a];return o};i.instance.put({language:"en-GB"});var G=class{_placesModule;_entries=[];_shownEntryIds=/* @__PURE__ */new Set;constructor(e){this._ttMap=e}async getPlacesModule(){return this._placesModule??=await x.get(this._ttMap),this._placesModule}get placesModule(){return this._placesModule}get entries(){return this._entries}get latestPlace(){return this._entries.at(-1)?.data}addPlaceResult(e,t){const o=`places-${this._entries.length}`;return this._entries.push({id:o,timestamp:Date.now(),label:t,data:"features"in e?e.features:[e]}),o}get shownEntryIds(){return this._shownEntryIds}getShownFeatures(){const e=[];for(const t of this._entries)this._shownEntryIds.has(t.id)&&e.push(...t.data);return e}async setShownEntries(e){const t=new Set(this._entries.map(e=>e.id));return this._shownEntryIds=new Set(e.filter(e=>t.has(e))),this._renderShown()}async addShownEntries(e){const t=new Set(this._entries.map(e=>e.id));let o=!1;for(const a of e)t.has(a)&&!this._shownEntryIds.has(a)&&(this._shownEntryIds.add(a),o=!0);return o?this._renderShown():this.getShownFeatures()}async removeShownEntries(e){let t=!1;for(const o of e)this._shownEntryIds.delete(o)&&(t=!0);return t?this._renderShown():this.getShownFeatures()}async clearShownEntries(){0!==this._shownEntryIds.size&&(this._shownEntryIds.clear(),await(await this.getPlacesModule()).clear())}async _renderShown(){const e=this.getShownFeatures();return await(await this.getPlacesModule()).show({type:"FeatureCollection",features:e}),e}reset(){this._placesModule=void 0,this._entries=[],this._shownEntryIds.clear()}},V=class{_poisModule;constructor(e){this._ttMap=e}async getPOIsModule(){return this._poisModule??=await S.get(this._ttMap),this._poisModule}get poisModule(){return this._poisModule}reset(){this._poisModule=void 0}},Y=class{_routingModule;_entries=[];_planningSlots=[];_params={};constructor(e){this._ttMap=e}async getRoutingModule(){return this._routingModule??=await P.get(this._ttMap),this._routingModule}get routingModule(){return this._routingModule}get entries(){return this._entries}get currentRoutes(){return this._entries.at(-1)?.data}get currentWaypoints(){return this._entries.at(-1)?.waypoints}get planningSlots(){return this._planningSlots}get params(){return this._params}addRoutes(e,t,o){this._entries.push({id:`routes-${this._entries.length}`,timestamp:Date.now(),label:o,data:e,waypoints:t,params:{...this._params}}),this._planningSlots=[...t]}setWaypointAt(e,t){const o=Math.max(2,e+1);for(;this._planningSlots.length<o;)this._planningSlots.push(null);this._planningSlots[e]=t}setParams(e){this._params={...this._params,...e}}reset(){this._routingModule=void 0,this._entries=[],this._planningSlots=[],this._params={}}},H=class{_baseMapModule;_hillshadeModule;constructor(e){this.ttMap=e}get mapLibreMap(){return this.ttMap.mapLibreMap}async getBaseMapModule(){return this._baseMapModule??=await b.get(this.ttMap),this._baseMapModule}async getHillshadeModule(){return this._hillshadeModule??=await v.get(this.ttMap),this._hillshadeModule}reset(){this._baseMapModule=void 0,this._hillshadeModule=void 0}},J=class{_trafficFlowModule;_trafficIncidentsModule;_trafficAreaAnalyticsModule;_lastAreaAnalytics;_currentAnalyticsConfig;_configChangeUnsub;constructor(e){this._ttMap=e}async getTrafficFlowModule(){return this._trafficFlowModule??=await T.get(this._ttMap),this._trafficFlowModule}async getTrafficIncidentsModule(){return this._trafficIncidentsModule??=await I.get(this._ttMap),this._trafficIncidentsModule}async getTrafficAreaAnalyticsModule(){return this._trafficAreaAnalyticsModule||(this._trafficAreaAnalyticsModule=await M.get(this._ttMap),this._configChangeUnsub=this._trafficAreaAnalyticsModule.events.on("config-change",e=>{this._currentAnalyticsConfig=e})),this._trafficAreaAnalyticsModule}get trafficAreaAnalyticsModule(){return this._trafficAreaAnalyticsModule}get lastAreaAnalytics(){return this._lastAreaAnalytics}setLastAreaAnalytics(e){this._lastAreaAnalytics=e}get currentAnalyticsConfig(){return this._currentAnalyticsConfig}onAnalyticsShown;onAnalyticsCleared;reset(){this._configChangeUnsub?.(),this.onAnalyticsCleared?.(),this._trafficFlowModule=void 0,this._trafficIncidentsModule=void 0,this._trafficAreaAnalyticsModule=void 0,this._lastAreaAnalytics=void 0,this._currentAnalyticsConfig=void 0,this._configChangeUnsub=void 0}},K=class{_entries=[];_placesModule;_geometriesModule;_currentTheme;constructor(e){this._ttMap=e}async getPlacesModule(){return this._placesModule??=await x.get(this._ttMap),this._placesModule}async getGeometriesModule(e){return this._geometriesModule?this._currentTheme!==e&&(this._geometriesModule.applyConfig(L(void 0,e)),this._currentTheme=e):(this._geometriesModule=await w.get(this._ttMap,L(void 0,e)),this._currentTheme=e),this._geometriesModule}get geometriesModule(){return this._geometriesModule}get entries(){return this._entries}get latestEntry(){return this._entries.at(-1)}addEntry(e){const t=`ranges-${this._entries.length}`;return this._entries.push({id:t,timestamp:Date.now(),...e}),t}reset(){this._entries=[],this._geometriesModule=void 0,this._currentTheme=void 0}},Z=(e,t)=>{const o={places:new G(e),mapPOIs:new V(e),routing:new Y(e),baseMap:new H(e),traffic:new J(e),ranges:new K(e)};return t&&Object.assign(o,t),o},Q='You are a helpful map assistant with access to a TomTom interactive map and location services.\n\nCOORDINATE ORDER:\n- All coordinates are [longitude, latitude] (GeoJSON standard)\n- All bounding boxes are [minLng, minLat, maxLng, maxLat]\n\nTOOL EXECUTION:\n- Call context-independent tools in the same step (parallel execution).\n- Many service tools have a show or showOnMap parameter — use it to display results on the map in one step instead of calling a separate show tool afterward.\n- Use standalone showPlaces / showRoute / showWaypoints only when displaying results already in context from a previous step.\n\nLOCATION REFERENCE:\n- "near me" / "my location" / "where I am" → getCurrentLocation (user\'s physical GPS position, may prompt permission)\n- "in this area" / "here on the map" / "near the map center" → getViewport (map\'s current view)\n- If getCurrentLocation fails due to permission denial, fall back to getViewport as the reference point\n\nRESPONSE FORMATTING:\n- Use markdown in all responses\n- Show key information in bold\n- Use bullet lists when presenting multiple items or results\n- Keep responses concise — lead with the most relevant information\n\n',X=(e,t)=>e||(t?`${Q}\n\nADDITIONAL INSTRUCTIONS:\n${t}`:Q),ee=O.object({geoJson:O.union([O.record(O.string(),O.unknown()),O.array(O.record(O.string(),O.unknown()))]).describe("GeoJSON object or array of GeoJSON objects")}),te=O.object({meters:O.number().describe("Distance in meters to format"),unitType:O.enum(["metric","imperial_us","imperial_uk"]).optional().describe("default: metric")}),oe=O.object({seconds:O.number().describe("Duration in seconds to format")}),ae=O.object({error:O.string()}),re=O.object({name:O.string().optional().describe("POI name if available"),address:O.string().optional().describe("Human-readable address"),position:O.array(O.number()).length(2).describe("[longitude, latitude]")}).describe("Compact place summary"),ie=O.object({count:O.number(),features:O.array(re)}).describe("Compact places summary"),se=O.object({travelTimeInSeconds:O.number(),lengthInMeters:O.number(),trafficDelayInSeconds:O.number().optional(),trafficLengthInMeters:O.number().optional(),departureTime:O.string().optional(),arrivalTime:O.string().optional(),noTrafficTravelTimeInSeconds:O.number().optional(),historicTrafficTravelTimeInSeconds:O.number().optional(),liveTrafficIncidentsTravelTimeInSeconds:O.number().optional()}),ne=O.object({index:O.number().describe("0=best, 1+=alternative"),summary:se,legSummaries:O.array(se).optional().describe("Present when route has multiple legs")}),le=O.object({count:O.number(),routes:O.array(ne)}),ce=O.object({}),ue=O.union([O.object({position:O.array(O.number()).min(2).max(2).describe("[longitude, latitude]"),accuracy:O.number().describe("Accuracy of the location in meters"),timestamp:O.number().describe("Timestamp of the location data")}),ae]),de=O.number().int().min(0).optional().describe("default: 0"),pe=O.object({routeIndex:de,traveledTimeInSeconds:O.number().min(0).optional().describe("seconds from start"),traveledDistanceInMeters:O.number().min(0).optional().describe("meters from start"),clockTime:O.string().optional().describe("ISO 8601; elapsed time derived from departure time")}).refine(({traveledTimeInSeconds:e,traveledDistanceInMeters:t,clockTime:o})=>1===[e,t,o].filter(e=>void 0!==e).length,{message:"Provide exactly one of: traveledTimeInSeconds, traveledDistanceInMeters, or clockTime."}),me=O.union([O.object({bbox:O.array(O.number()).describe("GeoJSON bbox [minLng, minLat, maxLng, maxLat]")}),ae]),he=O.object({sectionType:O.enum(g).describe("e.g. country|traffic|motorway|toll"),id:O.string().describe("Section ID from getShownRouteSections or getSectionProgress")}),ge=O.object({sectionType:O.enum(g).describe("e.g. country|traffic|motorway|toll"),ids:O.array(O.string()).optional().describe("Section IDs to query. If omitted, all sections of the given sectionType are returned.")}),fe=["location","route","waypoint","place","locate","discover","traffic","map style","utilities","search","detour","along-route","reachable-range","isochrone","range","EV","coverage","recall","state","carpool","carTrain","country","ferry","importantRoadStretch","lanes","leg","lowEmissionZone","motorway","pedestrian","roadShields","speedLimit","toll","tollVignette","tunnel","unpaved","urban","vehicleRestricted"],ye=O.object({name:O.string(),description:O.string(),examplePrompts:O.array(O.string()),relatedTools:O.array(O.string()).optional()}),be=O.union([O.object({mode:O.literal("summary"),examplePrompts:O.array(O.string())}),O.object({mode:O.literal("detail"),query:O.string().optional(),tag:O.enum(fe).optional(),matchedTools:O.array(ye),totalMatched:O.number()}),ae]),we=O.object({mode:O.enum(["summary","detail"]).describe('"summary": overview of all capabilities with example prompts mixed from all tools. "detail": searchable full tool info — use when you need to find a specific tool.'),query:O.string().optional().describe("Detail mode only. Case-insensitive keyword search across tool names, descriptions, and tags."),tag:O.enum(fe).optional().describe("Detail mode only. Filter results to tools with a specific tag.")}),ve="Discover what this agent can do. Returns all capability example prompts mixed together (summary mode) or searchable per-tool details with descriptions and examples (detail mode). Call this when the user asks what you can do, or when you need to find the right tool for a task.",Se=(e,t,o)=>({description:e.description,inputSchema:e.inputSchema,outputSchema:o?e.outputSchema:void 0,execute:o=>e.execute(o,t)}),xe=(e,t)=>({name:e,description:t.description,classificationPrompt:t.classificationPrompt,tags:t.tags,examples:t.examples,examplePrompts:t.examplePrompts,relatedTools:t.relatedTools,dependsOn:t.dependsOn}),Pe=(e,t,o)=>{const a=!1!==o?.outputSchemas,i={},s={};for(const[r,l]of Object.entries(e))i[r]=Se(l,t,a),s[r]=xe(r,l);var n;if(i.help&&(i.help=(n=()=>s,r({description:ve,inputSchema:we,outputSchema:be,execute:async e=>{const{mode:t,query:o,tag:a}=e;try{const e=Object.values(n());if("summary"===t)return{mode:"summary",examplePrompts:e.flatMap(e=>e.examplePrompts??[])};let r=e;if(a&&(r=r.filter(e=>e.tags?.includes(a)??!1)),o){const e=o.toLowerCase();r=r.filter(t=>t.name.toLowerCase().includes(e)||t.description.toLowerCase().includes(e)||(t.tags??[]).some(t=>t.toLowerCase().includes(e))||(t.examplePrompts??[]).some(t=>t.toLowerCase().includes(e)))}return{mode:"detail",query:o,tag:a,matchedTools:r.map(e=>({name:e.name,description:e.description,examplePrompts:e.examplePrompts??[],relatedTools:e.relatedTools??[]})),totalMatched:r.length}}catch(r){return{error:`Failed to load help: ${r instanceof Error?r.message:String(r)}`}}}}))),0===Object.keys(i).length)throw new Error("MapAgent requires at least one tool.");return{tools:i,toolsMetadata:s}},Me=O.object({added:O.array(O.string()).describe("Source IDs added by the executed code."),removed:O.array(O.string()).describe("Source IDs removed by the executed code."),updated:O.array(O.string()).describe("Source IDs whose definition changed.")}),Te=O.object({added:O.array(O.string()).describe("Layer IDs added by the executed code."),removed:O.array(O.string()).describe("Layer IDs removed by the executed code."),updated:O.array(O.string()).describe("Layer IDs whose properties changed.")}),Ie=O.object({code:O.string().describe('Async JavaScript code executed in an environment where `map` is the live MapLibre Map instance. Full JS is supported: variables, loops, conditionals, helper functions, top-level `await`. Example: await a map event with `await new Promise(r => map.once("idle", r))`. Return a value with `return` to include it in the result.')}),Re=O.union([O.object({success:O.literal(!0),result:O.unknown().optional().describe("Return value of the executed code, if any."),sources:Me,layers:Te}),ae]),Le=e=>{const t=e.getStyle()?.sources??{},o=/* @__PURE__ */new Map;for(const[a,r]of Object.entries(t))o.set(a,JSON.stringify(r));return o},Ae=e=>{const t=e.getStyle()?.layers??[],o=/* @__PURE__ */new Map;for(const a of t)o.set(a.id,JSON.stringify(a));return o},Oe=(e,t)=>{const o=[],a=[],r=[];for(const[i,s]of t){const t=e.get(i);void 0===t?o.push(i):t!==s&&r.push(i)}for(const i of e.keys())t.has(i)||a.push(i);return{added:o,removed:a,updated:r}},Ce=O.union([O.object({query:O.string().describe("Location string to resolve."),locationType:O.enum(["poi","default"]).describe('"poi" for landmarks and venues; "default" for addresses.')}),O.object({position:O.object({lng:O.number(),lat:O.number()}).describe("Explicit coordinates — use when you already have a position.")})]),De=new Set(h),je=async e=>{if(!e)return;const t=e.filter(e=>De.has(e)),o=e.filter(e=>!De.has(e));let a=[];o.length&&(a=await F({filters:o}));const r=[...new Set([...t,...a])];return r.length?r:void 0},Ee=O.union([O.array(O.number()).refine(e=>4===e.length,{message:"BBox must have 4 elements"})]).describe("[minLng, minLat, maxLng, maxLat] or [W,S,E,N]"),_e=O.union([Ee,O.object({bbox:Ee})]),ke=O.object({markerType:O.enum(["pin","none"]).describe('Marker type to show on the map. Show a marker only for addresses and small POIs. Use "none" towns, cities, or any areas or regions.'),zoomMode:O.enum(["auto","none"]).describe('How to zoom the map into the places. Use "none" to keep the map still.'),mode:O.enum(["add","replace"]).optional().describe('Display mode. Default: "replace" (clears existing pins, shows only these). Use "add" when the user wants to STACK these results on top of what is already shown ("also show", "additionally", "and X").')}),Fe=O.object({markerType:O.boolean(),zoomMode:O.boolean()}),Ne=O.union([O.object({position:O.array(O.number()).length(2)}).describe("Bias toward a specific [lng, lat] point."),O.object({boundingBox:_e}).describe("Consider only within a BBox [W,S,E,N] or GeoJSON with bbox."),O.literal("within-map-bounds").describe("Consider within the current map viewport bounds."),O.literal("nearby-map-center").describe("Bias toward the current map center."),O.literal("global").describe("No geographic bias — global search."),O.string().describe('Place name or area (e.g. "Paris", "Manhattan") — geocoded first, then its bbox or position is used as bias.')]),$e=async(e,t,o,a)=>{const r={markerType:!1,zoomMode:!1};if("pin"===a.markerType&&("add"===a.mode?await e.places.addShownEntries([o]):await e.places.setShownEntries([o]),r.markerType=!0),"auto"===a.zoomMode){const o=n(t);o&&e.baseMap.mapLibreMap.fitBounds(o,{padding:50}),r.zoomMode=!0}return r},qe=(e,t=6)=>{if(e.mapLibreMap.getZoom()<t)return;const o=e.mapLibreMap.getCenter();return[o.lng,o.lat]},Be=e=>{const t=e.mapLibreMap.getBounds();return[t.getWest(),t.getSouth(),t.getEast(),t.getNorth()]},ze=O.union([O.object({success:O.literal(!0)}),ae]),We=O.object({where:O.union([O.object({boundingBox:_e.describe("BBox [W,S,E,N] or GeoJSON object with bbox."),padding:O.number().optional().describe("Padding in pixels. Default: 50.")}).describe("Fit the camera to a bounding box."),O.object({position:O.array(O.number()).length(2).describe("[lng, lat] to fly to."),zoom:O.number().optional().describe("Camera zoom level. Default: 14.")}).describe("Fly the camera to a specific position.")])}),Ue=O.union([O.object({layers:O.array(O.object({id:O.string(),layout:O.unknown().optional(),paint:O.unknown().optional()}))}),ae]),Ge=O.object({layerIdQuery:O.string().optional().describe("Case-insensitive partial match on layer IDs. If omitted, all layers are returned."),include:O.array(O.enum(["paint","layout"])).describe('Which properties to include in the response. Pass only what you need: "paint" for visual properties like colors and opacity, "layout" for structural properties like sizes, positions, and visibility.')}),Ve=O.union([O.object({center:O.array(O.number()).describe("[lng, lat]"),zoom:O.number().describe("0–22"),bbox:O.array(O.number()).describe("[W, S, E, N]"),pitch:O.number().describe("degrees, 0=top-down, 85=near-horizontal"),bearing:O.number().describe("degrees, 0=north, 90=east")}),ae]),Ye=O.object({}),He=O.union([O.object({layerId:O.string(),propertyName:O.string(),value:O.unknown(),success:O.literal(!0)}),O.object({layerId:O.string(),propertyName:O.string(),error:O.string()})]),Je=O.union([O.object({results:O.array(He)}),ae]),Ke=O.object({changes:O.array(O.object({layerId:O.string().describe("MapLibre layer ID from getMapStyleLayers"),propertyName:O.string().describe("e.g. visibility|text-field|icon-size"),value:O.any()}))}).describe("List of layout property changes to apply in one go."),Ze=O.union([O.object({layerId:O.string(),propertyName:O.string(),value:O.unknown(),success:O.literal(!0)}),O.object({layerId:O.string(),propertyName:O.string(),error:O.string()})]),Qe=O.union([O.object({results:O.array(Ze)}),ae]),Xe=O.object({changes:O.array(O.object({layerId:O.string().describe("MapLibre layer ID from getMapStyleLayers"),propertyName:O.string().describe("e.g. fill-color|line-width|text-color"),value:O.any()})).describe("List of paint property changes to apply in one go.")}),et=O.union([O.object({success:O.literal(!0)}),ae]),tt=O.object({pitch:O.number().min(0).max(85).optional().describe("0=top-down, 85=near-horizontal"),bearing:O.number().min(-180).max(180).optional().describe("0=north, 90=east")}),ot=O.union([O.object({zoom:O.number().describe("Resulting zoom level after the change")}),ae]),at=O.object({delta:O.number().describe("Amount to zoom. Positive values zoom in, negative values zoom out. Can have decimals. Typical step: 1 or 2.")}),rt=e=>["You are a tool selector for a map assistant.","You will receive a conversation. Select the minimal set of tools needed to fulfill the LAST user message.",'LOCATION REFERENCE:\n - "near me" / "my location" / "where I am" → getCurrentLocation (user\'s physical GPS position, may prompt permission)\n - "in this area" / "here on the map" / "near the map center" → getViewport (map\'s current view)\n - If getCurrentLocation fails due to permission denial, fall back to getViewport as the reference point',"","Available tools:",...Object.entries(e).map(([e,t])=>((e,t)=>`${e}${t.classificationPrompt?` ${t.classificationPrompt}.`:""}${t.dependsOn?.length?` Depends on: ${t.dependsOn.join(", ")}.`:""}`)(e,t))].join("\n"),it=O.object({tools:O.array(O.string()).min(1).describe("Tool names needed to fulfill the query.")}),st=async(t,a)=>{const{chatModel:r,toolsMetadata:i}=a,s=performance.now(),{tools:n,usage:l}=await(async(t,a,r)=>{const i=await o({model:a,output:e.object({schema:it}),system:rt(r),messages:t,maxOutputTokens:200});return{tools:i.output.tools,usage:{inputTokens:i.usage?.inputTokens??0,outputTokens:i.usage?.outputTokens??0,totalTokens:i.usage?.totalTokens??0}}})(t,r,i);return{activeToolNames:n,timeMs:performance.now()-s,usage:l}},nt=e=>"text"===e.type,lt=e=>{if("string"==typeof e)return e;const t=e.filter(nt);return t.length>0?t.map(e=>e.text).join(""):null},ct=e=>{for(let t=e.length-1;t>=0;t--)if("user"===e[t].role)return lt(e[t].content);return null},ut=e=>{const{model:t,maxHistoryMessages:o,maxHistoryMessageLength:a}=e;return async e=>{const{messages:r,toolsMetadata:i}=e;if(!r?.length)return null;const s=o??8,n=a??300;let l=-1,c=null;for(let t=r.length-1;t>=0;t--)if("user"===r[t].role){l=t,c=lt(r[t].content);break}if(!c)return null;const u=[];for(let t=Math.max(0,l-s);t<l;t++){const e=r[t];if("user"!==e.role&&"assistant"!==e.role)continue;const o=lt(e.content);if(!o)continue;const a=o.length>n?o.slice(0,n)+"…":o;u.push({role:e.role,content:a})}u.push({role:"user",content:c});try{return await st(u,{chatModel:t,toolsMetadata:i})}catch{return null}}},dt=e=>{if(!Array.isArray(e))return e.properties?.address?.freeformAddress},pt=(e,t)=>{if("features"in e)return((e,t)=>{const o=[];t?.query&&o.push(`"${t.query}"`),t?.poiCategories?.length&&o.push(t.poiCategories.join(", ")),t?.routeLabel?o.push(`along ${t.routeLabel}`):t?.where&&o.push(`in ${t.where}`);const a=`${e} ${1===e?"place":"places"}`;return o.length?`${o.join(" ")} (${a})`:a})(e.features.length,t);const o=(a=e,a.properties?.poi?.name);var a;const r=(e=>e.properties?.address?.freeformAddress)(e);return o&&r?`${o}, ${r}`:o||(r||(t?.query?t.query:"Place"))},mt=(e,t)=>{const o=e.features[0]?.properties?.summary,a=o?` (${i=o.travelTimeInSeconds,`${Math.round(i/60)} min`}, ${r=o.lengthInMeters,`${(r/1e3).toFixed(1)} km`})`:"";var r,i;const s=t.map(dt).filter(Boolean);if(s.length>=2){const e=s[0],t=s.at(-1),o=s.slice(1,-1);return`${o.length>0?`${e} via ${o.join(", ")} to ${t}`:`${e} to ${t}`}${a}`}return`Route${a}`},ht={timeMinutes:"min",distanceKM:"km",remainingChargeCPT:"% remaining",spentChargePCT:"% spent",spentFuelLiters:"L"},gt=(e,t)=>`${[...e].sort((e,t)=>e.value-t.value).map(e=>`${e.value} ${ht[e.type]??e.type}`).join("/")} from ${t}`,ft=e=>{const t=e.geometry?.coordinates;return{name:e.properties?.poi?.name,address:e.properties?.address?.freeformAddress,position:t??[0,0]}},yt=e=>{const t=Array.isArray(e)?e:e.features;return{count:t.length,features:t.map(e=>ft(e))}},bt=e=>{const{summary:t,sections:o,index:a}=e.properties,r=o.leg,i=e=>({...e,arrivalTime:e.arrivalTime.toISOString(),departureTime:e.departureTime.toISOString()});return{index:a,summary:i(t),...r.length>1&&{legSummaries:r.map(e=>i(e.summary))}}},wt=e=>({count:e.features.length,routes:e.features.map(bt)}),vt=O.object({slotIndex:O.number(),isFilled:O.boolean(),address:O.string().optional(),position:O.array(O.number()).length(2).optional().describe("[longitude, latitude]")}),St=e=>{if(null==e)return null;const t=d(e);let o;return Array.isArray(e)||(o=e.properties?.address?.freeformAddress),{slotIndex:-1,isFilled:!0,...o&&{address:o},...t&&{position:t}}},xt=async(e,t,o)=>{const[a,r]="poi"===t?[q,B]:[E,_];return o&&"position"in o?(await a({query:e,position:o.position,limit:1})).features[0]??null:o&&"boundingBox"in o?(await a({query:e,boundingBox:o.boundingBox,limit:1})).features[0]??null:await r(e)??null},Pt=O.object({query:O.string().describe("Location string to resolve for downstream workflows such as routes or further searches."),waypointIndex:O.number().int().min(0).optional().describe("Route location slot to stage. Ordered as [origin, ...stops, destination]. Use it if this is an origin, stop or destination for a route."),locationType:O.enum(["poi","default"]).describe('"poi" for venues, landmarks, and businesses; "default" for places to geocode: addresses, parks, post codes, and geographies.'),where:Ne.describe("Geographic scope for the search."),show:ke.optional().describe("Optional map display actions to perform after resolving the place. Skip if this is an intermediate calculation for another step.")}),Mt=O.union([re.extend({waypointIndex:O.number().optional(),shown:Fe.optional()}),ae]),Tt=async e=>{if("position"in e){const{lng:t,lat:o}=e.position;return{place:[t,o],position:[t,o],name:`[${t}, ${o}]`}}const t=await xt(e.query,e.locationType);if(!t)return null;const o=d(t);return o?{place:t,position:o,name:t.properties?.address?.freeformAddress??e.query,query:e.query}:null},It=O.union([le,ae]),Rt=O.object({locations:O.array(Ce).min(2).describe("Ordered list: [origin, ...stops, destination]. Minimum 2."),showOnMap:O.boolean().describe("Show the route and waypoints on the map after calculation.")}),Lt=e=>{const t=e.filter(e=>null!==e);return t.length>=2?t:null},At=e=>{const{maxAlternatives:t=0,costModel:o,when:a}=e;return{...t>0&&{maxAlternatives:t},...o&&{costModel:{...o,...o.avoidAreas&&{avoidAreas:o.avoidAreas}}},...a&&{when:{option:a.option,date:new Date(a.date)}}}},Ot=async(e,t,o)=>{const a=await e.routing.getRoutingModule();await a.showRoutes(t),await a.showWaypoints(o);const r=n(t);r&&e.baseMap.mapLibreMap.fitBounds(r,{padding:50})},Ct=O.union([le,ae]),Dt=O.object({location:Ce.optional().describe("The stop to add. Omit to use the last stored place in context."),showOnMap:O.boolean().describe("Show the updated route and waypoints on the map after recalculation.")}),jt=O.union([ie.extend({shown:Fe.optional(),placesEntryId:O.string().optional(),label:O.string().optional().describe('Human-readable label stored with the entry (e.g. "cafe", "CINEMA (50 places)").')}),ae]),Et=O.object({query:O.string().optional().describe("Search query to filter places by name or address. For POI categories do not use query but use poiCategories."),where:Ne.optional().describe('Geographic scope for the search. Defaults to "within-map-bounds".'),radiusMeters:O.number().optional().describe("search radius in meters"),limit:O.number().max(100).optional().describe("default: 10 if query is supplied, 50 otherwise"),poiCategories:O.array(O.string()).optional().describe('POI category codes for filtering in CONSTANT_CASE. Call getPoiCategoryCodes first to resolve natural language (e.g. "gym", "restaurant", "aparcamiento") into codes.'),show:ke.optional().describe("Options to render the results on the map."),withinRange:O.string().optional().describe('Range ID from findReachableArea to restrict search to that reachable area (e.g. "ranges-0"). Use recallRanges to find the ID. Mutually exclusive with where.')}).refine(e=>!(e.withinRange&&e.where),{message:"withinRange and where are mutually exclusive — provide one or the other, not both."}),_t=e=>"string"==typeof e&&"within-map-bounds"!==e&&"nearby-map-center"!==e&&"global"!==e?e:void 0,kt=async(e,t,o,a,r,i)=>{const s=await(async(e,t)=>{const o=e??"within-map-bounds";if("within-map-bounds"===o)return{boundingBox:Be(t.baseMap)};if("nearby-map-center"===o){const e=qe(t.baseMap);return e?{position:e}:{}}if("global"===o)return{};if("string"==typeof o){const e=await B(o);if(e?.bbox)return{boundingBox:e.bbox};if(e){const t=d(e);if(t)return{position:t}}return{}}return"position"in o?{position:o.position}:{boundingBox:n(o.boundingBox)}})(o,e),l=await je(r),c=await q({query:t,limit:a??(t?10:50),poiCategories:l,...s,radiusMeters:i});return{result:c,placesEntryId:e.places.addPlaceResult(c,pt(c,{query:t,poiCategories:r,where:_t(o)}))}},Ft=O.object({type:O.enum(["timeMinutes","distanceKM"]).describe("Budget type including its unit."),value:O.number().describe("Budget value. e.g. 30 for 30 minutes, 50 for 50 km.")}),Nt=O.object({origin:Ce.describe("Starting point for the range calculation."),budgets:O.array(Ft).min(1).describe("One or more budget constraints. Pass multiple for nested ranges (e.g. 10, 20, 30 min or km). Order does not matter — sorted internally."),theme:O.enum(["filled","inverted","outline"]).optional().describe("Visual theme for the polygons. Default: outline (transparent fill with thick colored border). Use inverted for a donut (reachable highlighted, outside dimmed) or filled for solid polygons."),showOnMap:O.boolean().describe("Whether to render the range polygon(s) on the map."),showOriginPin:O.boolean().optional().describe("Whether to drop a pin at the origin. Default: true.")}),$t=O.object({rangeId:O.string(),originName:O.string(),budgets:O.array(Ft)}),qt=O.union([$t,O.object({status:O.enum(["not_found","no_results"])}),ae]),Bt=(O.object({query:O.string().describe("Street or postal address to geocode. Do not use for landmarks, POIs, venues, stations, cities, neighborhoods, or general place-name queries."),waypointIndex:O.number().int().min(0).optional().describe("0=origin, last=destination, middle=stop")}),O.union([re.extend({waypointIndex:O.number().optional()}),ae]),O.union([O.object({count:O.number().describe("Number of codes returned"),codes:O.array(O.string()).describe('POICategory enum values for discoverPlaces poiCategories. Generic codes (e.g. "RESTAURANT") also accepted by togglePOIs categories.')}),ae])),zt=O.object({filters:O.array(O.string()).optional().describe("Case-insensitive filter strings matched against category names and synonyms. Omit to return all codes."),language:O.string().describe('Locale e.g. "en-GB", "fr-FR", "es-ES", "de-DE".')}),Wt=O.object({speed:O.number().optional(),freeFlowSpeed:O.number().optional(),congestionLevel:O.number().optional(),travelTime:O.number().optional(),networkLength:O.number().optional()}),Ut=O.union([O.object({name:O.string().optional(),timezone:O.string().optional(),dateRange:O.object({start:O.string(),end:O.string()}),baseData:Wt,metrics:O.array(O.string()),tileCount:O.number(),availableGranularities:O.array(O.string())}),ae]),Gt=O.object({location:Ce.optional().describe("Named location (city, region, country) to fetch the boundary for. Resolved via geocoding + geometryData. Mutually exclusive with bbox and geometry."),bbox:O.array(O.number()).length(4).optional().describe("[minLng, minLat, maxLng, maxLat] — use a wide area (at least 5-10km across, city-level) for meaningful results. Mutually exclusive with location."),showOnMap:O.boolean().optional().describe("Visualize the result immediately with default settings. Use showTrafficAreaAnalytics to customize."),startDate:O.string().optional().describe("Start date 'YYYY-MM-DD'. Use with endDate for a continuous range (max 31 days)."),endDate:O.string().optional().describe("End date 'YYYY-MM-DD' (inclusive). Defaults to today if omitted."),days:O.array(O.string()).optional().describe("Specific dates 'YYYY-MM-DD' for non-consecutive analysis. Mutually exclusive with startDate/endDate."),metrics:O.union([O.literal("all"),O.array(O.enum(["speed","congestionLevel","freeFlowSpeed","travelTime","networkLength"])).min(1)]).describe("Traffic metrics to analyze. Use 'all' (preferred) or an explicit array like ['speed', 'congestionLevel', 'freeFlowSpeed', 'travelTime', 'networkLength']."),functionalRoadClasses:O.union([O.literal("all"),O.array(O.enum(["MOTORWAY","MAJOR_ROAD","OTHER_MAJOR_ROAD","SECONDARY_ROAD","LOCAL_CONNECTING_ROAD","LOCAL_ROAD_HIGH_IMPORTANCE","LOCAL_ROAD","LOCAL_ROAD_MINOR_IMPORTANCE","OTHER_ROAD"]))]).optional().describe("Road classes to include. 'all' (default) or array of specific classes."),hours:O.union([O.literal("all"),O.array(O.number().int().min(0).max(23))]).optional().describe("Hours of the day (0-23) to include. 'all' (default) or array like [7,8,9,17,18] for rush hours.")}),Vt=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,Yt=e=>e instanceof Date?Number.isNaN(e.getTime())?void 0:Vt(e):"string"==typeof e?e.slice(0,10):void 0,Ht=O.union([O.object({count:O.number(),incidents:O.array(O.object({id:O.string(),category:O.string(),magnitudeOfDelay:O.string().describe("unknown|minor|moderate|major|indefinite"),timeValidity:O.string().describe("present|future"),events:O.array(O.object({description:O.string(),category:O.string()})),from:O.string().optional(),to:O.string().optional(),roadNumbers:O.array(O.string()).optional(),lengthInMeters:O.number().optional(),delayInSeconds:O.number().optional(),startTime:O.date().optional(),endTime:O.date().optional()}))}),ae]),Jt=O.object({bbox:O.optional(O.array(O.number())).describe("[minLng, minLat, maxLng, maxLat]"),ids:O.array(O.string()).optional().describe("Up to 100 incident IDs"),categoryFilter:O.array(O.enum([...f])).optional().describe("Filter by incident category. If omitted, all categories are returned."),timeValidityFilter:O.array(O.enum(["present","future"])).optional().describe("default: ['present']")}),Kt=Wt.extend({date:O.string().optional(),hour:O.number().optional(),year:O.number().optional(),month:O.number().optional(),week:O.number().optional(),day:O.number().optional()}),Zt=O.object({granularity:O.enum(["daily","hourly","weekly","monthly","yearly","average"]).optional().describe("Time granularity. Default: 'daily'. Use 'average' for day-of-week × hour patterns."),metric:O.enum(["speed","congestionLevel","freeFlowSpeed","travelTime","networkLength"]).optional().describe("Filter to a single metric. Default: all requested metrics."),startDate:O.string().optional().describe("Filter entries from this date (YYYY-MM-DD). Works with 'daily' and 'hourly'."),endDate:O.string().optional().describe("Filter entries up to this date (YYYY-MM-DD). Works with 'daily' and 'hourly'."),hourStart:O.number().int().min(0).max(23).optional().describe("Filter hourly/average entries from this hour (0-23)."),hourEnd:O.number().int().min(0).max(23).optional().describe("Filter hourly/average entries up to this hour (0-23)."),dayOfWeek:O.array(O.number().int().min(1).max(7)).optional().describe("Filter 'average' entries by day of week (1=Mon…7=Sun).")}),Qt=O.union([O.object({granularity:O.string(),count:O.number(),entries:O.array(Kt),currentVisualization:O.object({activeMetric:O.string().optional(),displayMode:O.string().optional()}).optional()}),ae]),Xt=O.union([le,ae]),eo=O.object({stopIndex:O.number().int().describe("0=origin, last=destination; min 2 waypoints must remain"),showOnMap:O.boolean().describe("Show the updated route and waypoints on the map after recalculation.")}),to=O.union([re,ae]),oo=O.object({position:O.array(O.number()).length(2).describe("[longitude, latitude] GeoJSON position to reverse geocode")}),ao=O.object({status:O.literal("no_route")}),ro=O.union([ie.extend({placesEntryId:O.string(),shown:Fe.optional()}),ao,ae]),io=O.object({query:O.string().optional().describe("Search query to filter POIs by name."),poiCategories:O.array(O.string()).optional().describe("POI category codes in CONSTANT_CASE. Call getPoiCategoryCodes to resolve natural-language names."),routeId:O.string().optional().describe('Stable route entry ID (e.g. "routes-1"). Use recallRoutes to find the right ID; defaults to the most recent route.'),maxDetourTimeSeconds:O.number().describe("Maximum detour time in seconds to reach a POI from the route."),sortBy:O.enum(["detourTime","detourOffset"]).optional().describe("Default: detourTime."),limit:O.number().max(100).optional().describe("Max results. Default: 10."),show:ke.optional().describe("Display options to render results on the map after search.")}),so=O.object({routeType:O.enum($).optional().describe("fast|short|efficient|thrilling"),traffic:O.enum(["live","historical"]).optional().describe("live|historical"),avoid:O.array(O.enum(s)).optional().describe("tollRoads|motorways|ferries|unpavedRoads|carpools|alreadyUsedRoads|borderCrossings|tunnels|carTrains|lowEmissionZones"),avoidAreas:O.array(O.array(O.number()).describe("GeoJSON bbox [minLng, minLat, maxLng, maxLat]")).max(10).optional().describe("Up to 10 bounding boxes to bypass.")}),no=O.object({option:O.enum(["departAt","arriveBy"]),date:O.string().describe("ISO 8601")}),lo=O.union([le,O.object({success:O.literal(!0)}),ae]),co=O.object({maxAlternatives:O.number().int().min(0).max(5).optional().describe("0–5, default 0"),costModel:so.optional(),when:no.optional().describe("Omit to depart now."),showOnMap:O.boolean().describe("Show the route and waypoints on the map after recalculation.")}),uo=O.object({slotIndex:O.number().int().min(0).optional().describe("Exact waypoint slot to retrieve. Use when you need one known origin/stop/destination slot."),includeEmptySlots:O.boolean().optional().describe("Include unfilled slots in the result set. Defaults to false to avoid null-heavy responses."),offset:O.number().int().min(0).optional().describe("Pagination offset within the filtered slot list. Ignored when slotIndex is provided."),limit:O.number().int().min(1).max(25).optional().describe("Maximum slots to return. Defaults to 5. Ignored when slotIndex is provided.")}),po=O.object({totalSlots:O.number().describe("Total waypoint slots currently staged"),filledSlots:O.number().describe("Number of staged slots that already contain coordinates"),matchedCount:O.number().describe("Total slots matching the request before pagination"),returnedCount:O.number().describe("Number of slots returned in this page"),offset:O.number().describe("Offset applied to the filtered slot list"),hasMore:O.boolean().describe("True when more slots can be fetched with a higher offset"),nextOffset:O.number().optional().describe("Offset to request the next page when hasMore=true"),waypoints:O.array(vt)}),mo=O.object({id:O.string().optional().describe('Entry ID to retrieve (e.g. "places-3"). Omit to list all entries.')}),ho=O.object({id:O.string(),label:O.string(),timestamp:O.number()}),go=O.object({id:O.string(),label:O.string(),timestamp:O.number(),places:ie}),fo=O.union([O.object({entries:O.array(ho)}),go,ae]),yo=O.object({id:O.string().optional().describe('Entry ID to retrieve (e.g. "ranges-0"). Omit to list all entries.')}),bo=O.object({id:O.string(),label:O.string(),timestamp:O.number()}),wo=O.object({id:O.string(),label:O.string(),timestamp:O.number(),origin:O.object({query:O.string().optional(),position:O.tuple([O.number(),O.number()])}),budgets:O.array(O.object({type:O.string(),value:O.number()}))}),vo=O.union([O.object({entries:O.array(bo)}),wo,ae]),So=O.object({id:O.string().optional().describe('Entry ID to retrieve (e.g. "routes-1"). Omit to list all entries.')}),xo=O.object({id:O.string(),label:O.string(),timestamp:O.number()}),Po=O.object({maxAlternatives:O.number().optional(),costModel:so.optional(),when:no.optional()}),Mo=O.object({id:O.string(),label:O.string(),timestamp:O.number(),routes:le,waypoints:O.array(O.object({position:O.array(O.number()).length(2).describe("[longitude, latitude]")})),params:Po}),To=O.union([O.object({entries:O.array(xo)}),Mo,ae]),Io=O.union([O.object({success:O.literal(!0),cleared:O.array(O.string())}),ae]),Ro=O.object({layers:O.array(O.enum(["places","routes","geometries","analytics"])).optional().describe("Layers to clear (default: all). Includes traffic area analytics visualization.")}),Lo=O.union([O.object({success:O.literal(!0)}),ae]),Ao=O.object({sectionType:O.enum(g).describe("e.g. country|traffic|motorway|toll"),id:O.string().describe("From a shown route section"),padding:O.number().optional().describe("pixels, default: 50")}),Oo=O.union([O.object({count:O.number(),trafficIncidents:O.array(O.object({id:O.string(),category:O.string(),magnitudeOfDelay:O.string().describe("unknown|minor|moderate|major|indefinite"),description:O.string().optional(),delayInSeconds:O.number().optional(),roadCategory:O.string().optional(),averageSpeedKmph:O.number().optional()}))}),ae]),Co=O.object({}),Do=O.union([O.object({count:O.number().describe("Total feature count across all shown entries."),entries:O.array(O.object({id:O.string(),label:O.string(),featureCount:O.number(),features:O.array(O.object({name:O.string().optional(),address:O.string().optional(),position:O.array(O.number()).describe("[lng, lat]")}))}))}),ae]),jo=O.object({}),Eo=O.union([O.object({sectionType:O.string(),routes:O.array(O.object({routeIndex:O.number().describe("0=primary, 1+=alternative"),sections:O.array(O.unknown()).describe("startPointIndex/endPointIndex omitted")}))}),ae]),_o=O.object({sectionType:O.enum(g).describe("carpool|carTrain|country|ferry|importantRoadStretch|lanes|leg|lowEmissionZone|motorway|pedestrian|roadShields|speedLimit|toll|tollVignette|traffic|tunnel|unpaved|urban|vehicleRestricted")}),ko=O.union([O.object({count:O.number(),trafficIncidents:O.array(O.object({id:O.string(),magnitudeOfDelay:O.string().describe("unknown|minor|moderate|major|indefinite"),title:O.string().optional(),delayInSeconds:O.number().optional(),effectiveSpeedInKmh:O.number().optional(),categories:O.array(O.string()).optional()}))}),ae]),Fo=O.object({}),No=O.union([le,ae]),$o=O.object({}),qo=O.union([O.object({count:O.number(),waypoints:O.array(O.object({name:O.unknown().optional(),position:O.array(O.number()).describe("[lng, lat]")}))}),ae]),Bo=O.object({}),zo=O.union([O.object({styles:O.array(O.string()).readonly()}),ae]),Wo=O.object({}),Uo=O.object({id:O.string(),label:O.string(),featureCount:O.number()}),Go=O.union([O.object({success:O.literal(!0),totalShown:O.number(),shown:O.array(Uo).describe("Entries currently on the map, with their labels."),actuallyAdded:O.array(O.string()).describe("Ids from `add` / `addMatching` that were not already shown. Empty if it was a no-op."),actuallyRemoved:O.array(O.string()).describe("Ids from `remove` / `removeMatching` that were actually on the map. Empty if no-op.")}),ae]),Vo=O.object({add:O.array(O.string()).optional().describe('Entry ids to show (e.g. ["places-1"]).'),remove:O.array(O.string()).optional().describe("Entry ids to hide."),addMatching:O.array(O.string()).optional().describe("Category labels to show."),removeMatching:O.array(O.string()).optional().describe("Category labels to hide."),clear:O.boolean().optional().describe("Hide every displayed entry."),fitBounds:O.boolean().optional().describe("Pan/zoom to fit the resulting display. Default: false.")}).refine(e=>void 0!==e.add||void 0!==e.remove||void 0!==e.addMatching||void 0!==e.removeMatching||!0===e.clear,{message:"managePlaces requires at least one of: add, remove, addMatching, removeMatching, clear."}),Yo=(e,t)=>{if(0===t.length)return[];const o=t.map(e=>e.toLowerCase()),a=/* @__PURE__ */new Set;for(const r of e.places.entries){const e=r.label.toLowerCase();o.some(t=>e.includes(t))&&a.add(r.id)}return[...a]},Ho=O.union([O.object({success:O.literal(!0),language:O.string()}),ae]),Jo=O.object({language:O.string().describe('e.g. "en-US", "fr-FR"')}),Ko=O.union([O.object({success:O.literal(!0),style:O.string()}),ae]),Zo=O.object({style:O.enum(A).describe("Map visual theme")}),Qo=O.union([O.object({success:O.literal(!0),theme:O.object({mainColor:O.string().optional()})}),ae]),Xo=O.object({mainColor:O.string().optional().describe('CSS color for the route line and waypoint icons. Prefer CSS named colors when they match (e.g. "peachpuff", "coral", "steelblue"), otherwise use hex (e.g. "#FF0000").')}),ea={},ta=O.union([O.object({success:O.literal(!0),count:O.number(),shownEntryIds:O.array(O.string())}),ae]),oa=O.object({id:O.string().optional().describe("ID of a historical places entry (from recallPlaces). Omit to show the most recent."),fitBounds:O.boolean().optional().describe("Pan/zoom to fit the shown features. Default: true.")}),aa=O.union([O.object({success:O.literal(!0),displayedRoute:O.number(),routeCount:O.number()}),ae]),ra=O.object({id:O.string().optional().describe("ID of a historical route entry (from recallRoutes). Omit to show the most recent route."),selectedIndex:O.number().optional().describe("default: 0"),fitBounds:O.boolean().optional().describe("default: true")}),ia=O.object({mode:O.enum(["hexgrid-3d","hexgrid-2d","square-3d","square-2d","heatmap"]).optional().describe("Visualization mode. 'hexgrid-3d' (default): 3D hexagons. 'hexgrid-2d': flat hexagons. 'square-3d': 3D squares. 'square-2d': flat squares. 'heatmap': density layer."),metric:O.enum(["congestionLevel","speed","travelTime"]).optional().describe("Metric to visualize. Defaults to first fetched metric."),colorTheme:O.enum(["trafficLight","heat","monochrome","viridis","plasma"]).optional().describe("Preset color theme. 'trafficLight' (green→amber→red, default), 'heat' (blue→orange→red), 'monochrome' (grey), 'viridis' (purple→green→yellow), 'plasma' (purple→magenta→yellow)."),heightScale:O.number().optional().describe("Extrusion height multiplier / visual maximum in meters. Default: metric-dependent."),scaleMode:O.enum(["raw","predefinedRange","currentRange"]).optional().describe("Height scaling mode. 'raw': metric value × scale (default). 'predefinedRange': normalize to SDK predefined range so max = scale. 'currentRange': normalize to live data range so max = scale."),filter:O.object({min:O.number().optional(),max:O.number().optional()}).refine(e=>void 0!==e.min||void 0!==e.max,{message:"Filter must have at least one of min or max"}).optional().describe("Filter visible tiles for the active metric by value range."),visible:O.boolean().optional().describe("Set to false to clear the visualization. Default: true."),fitBounds:O.boolean().optional().describe("Fit map viewport to the analytics area. Default: true.")}),sa=O.union([O.object({success:O.literal(!0),mode:O.string(),metric:O.string(),colorTheme:O.string(),visible:O.boolean(),filtered:O.boolean()}),ae]),na=O.union([O.object({success:O.literal(!0),count:O.number()}),ae]),la=O.object({}),ca=O.union([O.object({success:O.literal(!0),visible:O.boolean(),layerGroups:O.array(O.string())}),ae]),ua=O.object({visible:O.boolean(),layerGroups:O.array(O.enum(R)).describe("The base map layer groups to show or hide.")}),da=O.union([O.object({success:O.literal(!0),allMapPOIsVisible:O.boolean().optional(),filterCategories:O.object({show:O.enum(["only","all_except"]),values:O.array(O.string())}).optional(),reset:O.boolean().optional()}),ae]),pa=O.object({reset:O.boolean().optional().describe("Set to true to reset all POI configuration to defaults (visibility and category filters). When true, all other parameters are ignored."),allMapPOIsVisible:O.boolean().optional().describe("Set the overall visibility of all built-in map POI icons. True to show all POIs, false to hide all POIs."),filterCategories:O.object({show:O.enum(["only","all_except"]).describe('"only": show POIs only from the given categories. "all_except": show all POIs except those in the given categories.'),values:O.array(O.string()).describe('MapStylePOICategory or POICategoryGroup values (e.g. "RESTAURANT", "FOOD_DRINKS_GROUP"). Overly specific codes like "ITALIAN_RESTAURANT" are not supported.')}).optional().describe("Filter which built-in map POI categories are shown.")}),ma=O.object({visible:O.boolean()}),ha=O.union([O.object({success:O.literal(!0),trafficFlowVisible:O.boolean()}),ae]),ga=O.object({visible:O.boolean()}),fa=O.union([O.object({success:O.literal(!0),trafficIncidentsVisible:O.boolean()}),ae]),ya={locatePlace:{description:"Resolve one user-provided location string into a normalized place summary for downstream workflows without changing the map or camera. Search-first: accepts landmarks, stations, venues, cities, neighborhoods, and full addresses. Can optionally stage a waypoint slot.",classificationPrompt:"Resolve a single location string (landmark, city, address) to a place without showing it; optionally stages a waypoint slot.",inputSchema:Pt,outputSchema:Mt,execute:async(e,t)=>{const{query:o,locationType:a,waypointIndex:r,where:i,show:s}=e;try{const e=await xt(o,a,await(async(e,t)=>{if("nearby-map-center"===e){const e=qe(t.baseMap);return e?{position:e}:void 0}if("within-map-bounds"===e)return{boundingBox:Be(t.baseMap)};if("global"!==e){if("string"==typeof e){const t=await _(e);if(t?.bbox)return{boundingBox:t.bbox};if(t){const e=d(t);if(e)return{position:e}}return}return"position"in e?{position:e.position}:{boundingBox:e.boundingBox}}})(i,t));if(!e)return{error:`No result found for "${o}"`};const n=t.places.addPlaceResult(e,pt(e,{query:o}));void 0!==r&&t.routing.setWaypointAt(r,e);const l=s?await(async(e,t,o,a)=>{const r={markerType:!1,zoomMode:!1};if("pin"===a.markerType&&("add"===a.mode?await e.places.addShownEntries([o]):await e.places.setShownEntries([o]),r.markerType=!0),"auto"===a.zoomMode){if(t.bbox)e.baseMap.mapLibreMap.fitBounds(t.bbox);else{const o=d(t);o&&e.baseMap.mapLibreMap.flyTo({center:o,zoom:13})}r.zoomMode=!0}return r})(t,e,n,s):void 0;return{...ft(e),...void 0!==r&&{waypointIndex:r},...l&&{shown:l}}}catch(n){return{error:`Location resolution failed: ${n instanceof Error?n.message:String(n)}`}}},tags:["locate","place","location","waypoint"],examples:['locatePlace("Buckingham Palace", where: "within-map-bounds", waypointIndex: 0)','locatePlace("Tower Bridge", where: "nearby-map-center", waypointIndex: 1)','locatePlace("Westminster Abbey", where: "anywhere")','locatePlace("Central Station", where: { position: [4.9, 52.37] })'],examplePrompts:["Where is the Louvre?","Find the nearest train station","Locate Big Ben"],relatedTools:["setRouteLocations","addStopToRoute","getCurrentWaypoints","recallPlaces"]},reverseGeocode:{description:"Convert a [longitude, latitude] position to an address and normalized place summary. Use after a map click, getViewport, getCurrentLocation, or any tool that returns coordinates. Does NOT search by name — use locatePlace or discoverPlaces for text queries.",classificationPrompt:"Convert [lng, lat] coordinates to an address; use after map clicks or any tool that returns a position.",inputSchema:oo,outputSchema:to,execute:async(e,t)=>{const{position:o}=e,a=o;try{const e=await N({position:a});return e?(t.places.addPlaceResult(e,pt(e)),ft(e)):{error:"No result found for the given coordinates"}}catch(r){return{error:`Reverse geocoding failed: ${r instanceof Error?r.message:String(r)}`}}},tags:["location","place"],examples:["reverseGeocode({ position: [4.9, 52.4] })"],examplePrompts:["What's the address at this point?","What street is at these coordinates?"],relatedTools:["getViewport","getCurrentLocation","showPlaces","locatePlace"]},discoverPlaces:{description:'Search for multiple places by text query or POI category. Stores results as a new places entry and returns its `placesEntryId`. Pass `show` to render on the map — set `show.mode: "add"` when stacking on top of an existing display ("also show cinemas"), default `"replace"` for a fresh view. Defaults to searching within the current map viewport; pass `where` to override. Query is optional — omit it to search by categories only. For a single specific place, use locatePlace instead.',classificationPrompt:"Search for multiple places by text query or POI category within an area.",inputSchema:Et,outputSchema:jt,execute:async(e,t)=>{const{query:o,where:a,radiusMeters:r,limit:i,poiCategories:s,show:n,withinRange:l}=e;try{let e,c;if(l){const a=await(async(e,t,o,a,r)=>{const i=e.ranges.entries.find(e=>e.id===t);if(!i?.polygon)return{error:`Range "${t}" not found. Use recallRanges to list available ranges.`};const s=await je(r),n=await q({query:o,limit:a??(o?10:50),poiCategories:s,geometries:[i.polygon]});return{result:n,placesEntryId:e.places.addPlaceResult(n,pt(n,{query:o,poiCategories:r}))}})(t,l,o,i,s);if("error"in a)return a;e=a.result,c=a.placesEntryId}else{const n=await kt(t,o,a,i,s,r);e=n.result,c=n.placesEntryId}const u=n?await $e(t,e,c,n):void 0,d=t.places.entries.find(e=>e.id===c)?.label;return{...yt(e),placesEntryId:c,...d&&{label:d},...u&&{shown:u}}}catch(c){return{error:`Search failed: ${c instanceof Error?c.message:String(c)}`}}},tags:["discover","place","location"],examples:['discoverPlaces({ query: "coffee", where: { position: [4.9, 52.4] } })','discoverPlaces({ poiCategories: ["ITALIAN_RESTAURANT"] }) // category-only, no query needed','discoverPlaces({ query: "hotel", where: { boundingBox: [4.8, 52.3, 5.0, 52.5] } })','discoverPlaces({ query: "parking", where: "Amsterdam" }) // geocoded area','discoverPlaces({ query: "coffee", withinRange: "ranges-0" })','discoverPlaces({ poiCategories: ["CAFE"], show: { markerType: "pin", zoomMode: "auto" } })'],examplePrompts:["Find coffee shops near me","Search for Italian restaurants in Amsterdam","Show me parking nearby","Find coffee shops within the range I just calculated"],relatedTools:["getPOICategoryCodes","showPlaces","managePlaces","locatePlace","getViewport","findReachableArea"]},setRouteLocations:{description:"Set the route waypoints by resolving location queries. Always triggers a route recalculation once all locations are resolved (minimum: origin + destination). Replaces all current waypoints. Uses route parameters from setRouteParameters if already set. Can be called in parallel with setRouteParameters. Only car/driving routes are supported.",classificationPrompt:"Set route waypoints by resolving location queries and trigger a recalculation (minimum: origin + destination).",inputSchema:Rt,outputSchema:It,execute:async(e,t)=>{const{locations:o,showOnMap:a}=e;try{const e=await Promise.all(o.map(Tt)),r=o.filter((t,o)=>null===e[o]&&"query"in t);if(r.length>0)return{error:`Could not resolve: ${r.map(e=>`"${e.query}"`).join(", ")}`};const i=Lt(e.map(e=>e?.place??null));if(!i)return{error:"Not enough valid waypoints to calculate a route (minimum 2)."};const s=await j({locations:i,...At(t.routing.params)});return t.routing.addRoutes(s,i,mt(s,i)),a&&await Ot(t,s,i),wt(s)}catch(r){return{error:`Route calculation failed: ${r instanceof Error?r.message:String(r)}`}}},tags:["route","waypoint","location"],examples:['setRouteLocations({ locations: [{ query: "Amsterdam" }, { query: "Brussels" }] })','setRouteLocations({ locations: [{ query: "Eiffel Tower" }, { query: "Louvre Museum" }, { query: "Notre Dame" }] })','setRouteLocations({ locations: [{ query: "5th Ave, New York", locationType: "default" }, { query: "JFK Airport", locationType: "default" }] })'],examplePrompts:["Get directions from Paris to Lyon","Route me from Amsterdam to Brussels","Navigate from here to the airport"],relatedTools:["setRouteParameters","showRoute","addStopToRoute","removeStopFromRoute"]},setRouteParameters:{description:"Set route planning parameters: number of alternatives, cost model (route type, traffic, avoidances), and departure/arrival time. Triggers a route recalculation automatically if origin and destination are already set. Can be called in parallel with setRouteLocations. Only car/driving routes are supported.",classificationPrompt:"Configure route options (alternatives, type, avoidances, departure/arrival time) and trigger recalculation if locations are set.",inputSchema:co,outputSchema:lo,execute:async(e,t)=>{const{showOnMap:o,...a}=e;try{t.routing.setParams(a);const e=Lt(t.routing.planningSlots);if(e){const a=await j({locations:e,...At(t.routing.params)});return t.routing.addRoutes(a,e,mt(a,e)),o&&await Ot(t,a,e),wt(a)}return{success:!0}}catch(r){return{error:`Failed to set route parameters: ${r instanceof Error?r.message:String(r)}`}}},tags:["route"],examples:["setRouteParameters({ maxAlternatives: 2 })",'setRouteParameters({ costModel: { routeType: "fast", avoid: ["tollRoads"] } })','setRouteParameters({ when: { option: "departAt", date: "2025-06-01T09:00:00Z" } })'],examplePrompts:["Avoid toll roads","Find the fastest route","Show 2 alternative routes","Depart at 9am"],relatedTools:["setRouteLocations","showRoute"]},addStopToRoute:{description:"Add a stop to the current route. Inserts the new waypoint at the optimal position and always triggers a route recalculation. If location is provided, it is resolved search-first. Requires an existing route (call setRouteLocations first).",classificationPrompt:"Insert a stop at the optimal position in the current route and recalculate.",inputSchema:Dt,outputSchema:Ct,execute:async(e,t)=>{const{location:o,showOnMap:a}=e;try{const e=await(async e=>{const t=(await e.routing.getRoutingModule()).getShown(),o=t?.mainLines,a=t?.waypoints;return o&&o.features.length?!a||a.features.length<2?"No existing waypoints available. Use calculate-route first to create a route with waypoints.":{shownRouteLines:o,shownWaypoints:a}:"No existing route available. Use calculate-route first."})(t);if("string"==typeof e)return{error:e};const{shownRouteLines:r,shownWaypoints:i}=e,s=await(async(e,t)=>{if(e){const t=await Tt(e);return t?{place:t.place}:{error:`Could not resolve location: ${"query"in e?`"${e.query}"`:JSON.stringify(e.position)}`}}const o=t.places.latestPlace?.at(0);return o?{place:o}:{error:"No location provided and no last place available in context. Provide a location or resolve a place first."}})(o,t);if("error"in s)return s;const n=s.place,l=r.features[0],c=Lt(y(l,i.features,n));if(!c)return{error:"Not enough valid waypoints to calculate a route (minimum 2)."};const u=await j({locations:c,...At(t.routing.params)});return t.routing.addRoutes(u,c,mt(u,c)),a&&await Ot(t,u,c),wt(u)}catch(r){return{error:`Failed to add stop to route: ${r instanceof Error?r.message:String(r)}`}}},tags:["route","waypoint"],examples:['addStopToRoute(location: "Westminster Abbey")','addStopToRoute(location: "gas station near route")',"addStopToRoute() // use the most recently resolved or shown place"],examplePrompts:["Add a stop at Westminster Abbey","Add a coffee break to my route"],relatedTools:["locatePlace","setRouteLocations","showRoute","removeStopFromRoute"],dependsOn:["setRouteLocations"]},removeStopFromRoute:{description:"Remove a stop from the current route by index and always triggers a route recalculation. Index 0 is the origin, last index is the destination — both must remain. Requires an existing route (call setRouteLocations first).",classificationPrompt:"Remove a stop by index from the current route and recalculate.",inputSchema:eo,outputSchema:Xt,execute:async(e,t)=>{const{stopIndex:o,showOnMap:a}=e;try{const e=((e,t)=>!e||e.length<2?"No existing waypoints available. Use calculate-route first to create a route with waypoints.":t<0||t>=e.length?`Invalid stop index ${t}. Valid range is 0 to ${e.length-1}.`:e.length<=2?"Cannot remove a stop: at least 2 waypoints (origin and destination) must remain.":e)(t.routing.currentWaypoints,o);if("string"==typeof e)return{error:e};const r=Lt(e.filter((e,t)=>t!==o));if(!r)return{error:"Not enough valid waypoints to calculate a route (minimum 2)."};const i=await j({locations:r,...At(t.routing.params)});return t.routing.addRoutes(i,r,mt(i,r)),a&&await Ot(t,i,r),wt(i)}catch(r){return{error:`Failed to remove stop from route: ${r instanceof Error?r.message:String(r)}`}}},tags:["route","waypoint"],examples:["removeStopFromRoute(1)","removeStopFromRoute(2, 1)"],examplePrompts:["Remove the second stop from my route","Delete the Utrecht stop"],relatedTools:["addStopToRoute","setRouteLocations","showRoute"],dependsOn:["setRouteLocations"]},getPOICategoryCodes:{description:'Resolve natural language (e.g. "gym", "italian food", "parking") into POICategory codes for use in the discoverPlaces poiCategories parameter. Returns all codes when no filter is given.',classificationPrompt:'Resolve natural-language category names (e.g. "gym", "italian food") to POICategory codes for discoverPlaces.',inputSchema:zt,outputSchema:Bt,execute:async(e,t)=>{const{filters:o,language:a}=e;try{const e=await F({filters:o,language:a});return{count:e.length,codes:e}}catch(r){return{error:`Failed to fetch POI category codes: ${r instanceof Error?r.message:String(r)}`}}},tags:["discover","place"],examples:["getPOICategoryCodes()",'getPOICategoryCodes(filters: ["gym"])','getPOICategoryCodes(filters: ["italian restaurant"]) // multi-word phrase, spaces removed before matching','getPOICategoryCodes(filters: ["restaurant"], language: "fr-FR")'],examplePrompts:["What POI categories are available?","What's the code for gym?"],relatedTools:["discoverPlaces","togglePOIs"]},getTrafficIncidents:{description:"Fetch and analyze traffic incidents (present or future) by bbox or IDs without showing them on the map. Combine with toggleTrafficIncidents to highlight the most important ones in an area, or use getShownIncidents IDs to get full details of what is already rendered. Returns category, severity, delay, and road location.",classificationPrompt:"Fetch traffic incidents by bbox or IDs without showing them; returns category, severity, and delay details.",inputSchema:Jt,outputSchema:Ht,execute:async(e,t)=>{const{bbox:o,ids:a,categoryFilter:r,timeValidityFilter:i}=e;if(!o&&!a)return{error:"Provide either a bbox or a list of ids"};try{const e={...r&&{categoryFilter:r},...i&&{timeValidityFilter:i}},t=await W(o?{...e,bbox:o}:{...e,ids:a});return t.features.length?{count:t.features.length,incidents:t.features.map(e=>{const t=e.properties;return{id:t.id,category:t.category,magnitudeOfDelay:t.magnitudeOfDelay,timeValidity:t.timeValidity,events:t.events.map(e=>({description:e.description,category:e.category})),from:t.from,to:t.to,roadNumbers:t.roadNumbers,lengthInMeters:t.lengthInMeters,delayInSeconds:t.delayInSeconds,startTime:t.startTime,endTime:t.endTime}})}:{count:0,incidents:[]}}catch(s){return{error:`Failed to get traffic incidents: ${s instanceof Error?s.message:String(s)}`}}},tags:["traffic","location"],examples:["getTrafficIncidents({ bbox: [4.728, 52.278, 5.080, 52.479] })",'getTrafficIncidents({ ids: ["incident-id-1", "incident-id-2"] })','getTrafficIncidents({ bbox: [...], categoryFilter: ["accident", "jam"] })','getTrafficIncidents({ bbox: [...], categoryFilter: ["roadworks"], timeValidityFilter: ["future"] })'],examplePrompts:["Fetch traffic incidents in Amsterdam","Any accidents in this area?"],relatedTools:["getShownIncidents","toggleTrafficIncidents","calculateBBox","getViewport"]},getTrafficAreaAnalytics:{description:"Fetch historical traffic analytics for a geographic area (max 31 days). Provide area via location (named city/region, resolved to boundary polygon) or bbox. Fetch all metrics in a single call — visualization requires all metrics in one result. Use city-level areas (~10km+) for meaningful data. Returns period averages. Use showOnMap to visualize immediately, queryTrafficAnalytics for breakdowns.",classificationPrompt:"Fetch historical traffic analytics (speed, congestion, travel time) for an area; use queryTrafficAnalytics to drill down.",inputSchema:Gt,outputSchema:Ut,execute:async(e,t)=>{const{location:o,bbox:a,showOnMap:r,startDate:i,endDate:s,days:l,metrics:c,functionalRoadClasses:u,hours:d}=e;if(!o&&!a)return{error:"Provide a location or bbox to define the analytics area."};const p=process.env.MOVE_PORTAL_KEY;if(!p)return{error:"MOVE_PORTAL_KEY environment variable is not set."};try{const e=await(async(e,t)=>{if(e){const t=await Tt(e);if(!t)return{error:"Could not resolve the provided location."};if(Array.isArray(t.place))return{error:"A bare position cannot define an analytics area. Provide a named location query instead."};const o=(await k({geometries:[t.place]}))?.features?.[0]?.geometry;return o||{error:`No boundary polygon found for "${t.name}". Try a bbox instead.`}}return t?(e=>{const[t,o,a,r]=e;return{type:"Polygon",coordinates:[[[t,o],[a,o],[a,r],[t,r],[t,o]]]}})(t):{error:"No area provided."}})(o,a);if("error"in e)return e;const m=((e,t,o)=>e&&e.length>0?{days:e}:t?o?{startDate:t,endDate:o}:{startDate:t}:{})(l,i,s),h=await z({apiKey:p,...m,metrics:c,functionalRoadClasses:u??"all",hours:d??"all",geometry:e});return t.traffic.setLastAreaAnalytics(h),r&&await(async(e,t)=>{const o=await e.traffic.getTrafficAreaAnalyticsModule();await o.clear(),await o.show(t);const a=t.properties?.metrics?.[0]??"congestionLevel";o.setMetric(a);const r=n(t.features);r&&e.baseMap.mapLibreMap.fitBounds(r,{padding:50,pitch:45}),e.traffic.onAnalyticsShown?.(t,o)})(t,h),((e,t,o)=>{const a=e.features[0]?.properties;if(!a)return{dateRange:{start:"",end:""},baseData:{},metrics:[],tileCount:0,availableGranularities:[]};const r=t??Yt(e.properties?.startDate)??(()=>{const e=/* @__PURE__ */new Date;return e.setDate(e.getDate()-3),Vt(e)})(),i=o??Yt(e.properties?.endDate)??(()=>{const e=/* @__PURE__ */new Date;return e.setDate(e.getDate()-2),Vt(e)})(),s=[];return a.timedData?.yearly?.length&&s.push("yearly"),a.timedData?.monthly?.length&&s.push("monthly"),a.timedData?.weekly?.length&&s.push("weekly"),a.timedData?.daily?.length&&s.push("daily"),a.timedData?.hourly?.length&&s.push("hourly"),a.timedData?.average?.length&&s.push("average"),{...a.name&&{name:a.name},...a.timezone&&{timezone:a.timezone},dateRange:{start:r,end:i},baseData:a.baseData,metrics:e.properties?.metrics??[],tileCount:a.tiledData?.tiles?.length??0,availableGranularities:s}})(h,m.startDate,m.endDate)}catch(m){return{error:`Failed to get traffic area analytics: ${m instanceof Error?m.message:String(m)}`}}},tags:["traffic","location"],examples:["getTrafficAreaAnalytics({ bbox: [4.728, 52.278, 5.080, 52.479], metrics: ['speed', 'congestionLevel'], startDate: '2025-03-01', endDate: '2025-03-07' })","getTrafficAreaAnalytics({ bbox: [...], metrics: ['congestionLevel'], hours: [7,8,9,17,18] })"],examplePrompts:["What was the average congestion in Amsterdam last week?","Analyze traffic patterns during rush hour in this area","Show me historical speed data for the city center"],relatedTools:["queryTrafficAnalytics","showTrafficAreaAnalytics","calculateBBox","getViewport"],dependsOn:["locatePlace"]},queryTrafficAnalytics:{description:"Query cached traffic analytics (from getTrafficAreaAnalytics) without re-fetching. Filter by granularity, date range, hour range, day of week, or metric. Returns filtered entries plus the current visualization state (metric, mode displayed on map). Use for follow-up questions: breakdowns, patterns, or checking what is currently shown.",classificationPrompt:"Query cached traffic analytics data or check what metric/mode is currently displayed on the map.",inputSchema:Zt,outputSchema:Qt,execute:async(e,t)=>{const{granularity:o="daily",metric:a,startDate:r,endDate:i,hourStart:s,hourEnd:n,dayOfWeek:l}=e,c=t.traffic.lastAreaAnalytics;if(!c)return{error:"No analytics data cached. Call getTrafficAreaAnalytics first."};const u=c.features[0]?.properties;if(!u)return{error:"Analytics result has no region data."};const d=u.timedData,p=d?.[o];if(!p||!Array.isArray(p)||0===p.length)return{error:`No '${o}' data available. Available: ${Object.keys(d??{}).join(", ")}`};const m=Yt(c.properties?.startDate);let h=p.map((e,t)=>{const r={};if("daily"===o||"hourly"===o){const a=((e,t,o,a)=>{const r=Yt(e);if(r)return r;if(a&&t>=0){const e=new Date(a);if(!Number.isNaN(e.getTime())){const a="hourly"===o?Math.floor(t/24):t;return e.setDate(e.getDate()+a),Vt(e)}}})(e.date,t,o,m);a&&(r.date=a)}if(void 0!==e.hour&&(r.hour=e.hour),void 0!==e.year&&(r.year=e.year),void 0!==e.month&&(r.month=e.month),void 0!==e.week&&(r.week=e.week),void 0!==e.day&&(r.day=e.day),a){const t=e[a];void 0!==t&&(r[a]=t)}else Object.assign(r,(e=>({...void 0!==e.speed&&{speed:e.speed},...void 0!==e.freeFlowSpeed&&{freeFlowSpeed:e.freeFlowSpeed},...void 0!==e.congestionLevel&&{congestionLevel:e.congestionLevel},...void 0!==e.travelTime&&{travelTime:e.travelTime},...void 0!==e.networkLength&&{networkLength:e.networkLength}}))(e));return r});r&&(h=h.filter(e=>!e.date||e.date>=r)),i&&(h=h.filter(e=>!e.date||e.date<=i)),void 0!==s&&(h=h.filter(e=>void 0===e.hour||e.hour>=s)),void 0!==n&&(h=h.filter(e=>void 0===e.hour||e.hour<=n)),l&&l.length>0&&(h=h.filter(e=>void 0===e.day||l.includes(e.day)));const g=t.traffic.currentAnalyticsConfig,f=g?{activeMetric:g.activeMetric,displayMode:g.displayMode}:void 0;return{granularity:o,count:h.length,entries:h,...f&&{currentVisualization:f}}},tags:["traffic","location"],examples:["queryTrafficAnalytics({ granularity: 'daily' })","queryTrafficAnalytics({ granularity: 'hourly', hourStart: 7, hourEnd: 9, metric: 'congestionLevel' })","queryTrafficAnalytics({ granularity: 'average', dayOfWeek: [6, 7] })"],examplePrompts:["Show me the daily breakdown","What was rush hour congestion?","Which day had the worst traffic?","What metric am I looking at?","What is currently shown on the map?"],relatedTools:["getTrafficAreaAnalytics","showTrafficAreaAnalytics"],dependsOn:["getTrafficAreaAnalytics"]},showPlaces:{description:"Display a places entry on the map, replacing whatever was previously shown. Pass an id (from recallPlaces) to show a specific entry, or omit to show the most recent. To stack additional entries or hide specific ones, use `managePlaces` instead.",classificationPrompt:"Display a places entry on the map, replacing anything currently shown.",inputSchema:oa,outputSchema:ta,execute:async(e,t)=>{const{id:o,fitBounds:a=!0}=e;try{const e=o??t.places.entries.at(-1)?.id;if(!e)return{error:"No places available to display. Resolve a place or run a search first (e.g. discoverPlaces)."};if(!t.places.entries.some(t=>t.id===e))return{error:`No places entry found with id "${e}"`};await t.places.setShownEntries([e]);const r=t.places.getShownFeatures();if(a&&r.length>0){const e=n(r);e&&t.baseMap.mapLibreMap.fitBounds(e,{padding:50})}return{success:!0,count:r.length,shownEntryIds:[...t.places.shownEntryIds]}}catch(r){return{error:`Failed to show places: ${r instanceof Error?r.message:String(r)}`}}},tags:["place","location"],examples:["showPlaces()",'showPlaces({ id: "places-2" })',"showPlaces({ fitBounds: false })"],examplePrompts:["Show the results on the map","Pin the search results","Display these places"],relatedTools:["discoverPlaces","locatePlace","reverseGeocode","managePlaces","clearMap","flyTo"],dependsOn:["discoverPlaces","locatePlace"]},managePlaces:{description:"Change which places entries are displayed on the map. Target entries by id (`add` / `remove`) or by category label (`addMatching` / `removeMatching`). `clear` hides all. Does not delete from history.",classificationPrompt:"Add more places on top of whatever is currently shown, or hide specific place entries from the map.",inputSchema:Vo,outputSchema:Go,execute:async(e,t)=>{const{add:o,remove:a,addMatching:r,removeMatching:i,clear:s,fitBounds:l=!1}=e;try{const e=[...o??[],...Yo(t,r??[])],c=[...a??[],...Yo(t,i??[])],u=new Set(t.places.entries.map(e=>e.id)),d=e.filter(e=>!u.has(e));if(d.length>0)return{error:`Unknown places entry ids: ${d.join(", ")}. Use recallPlaces to list available entries.`};const p=new Set(t.places.shownEntryIds);s&&await t.places.clearShownEntries(),c.length>0&&await t.places.removeShownEntries(c),e.length>0&&await t.places.addShownEntries(e);const m=t.places.shownEntryIds,h=e.filter(e=>!p.has(e)&&m.has(e)),g=c.filter(e=>p.has(e)&&!m.has(e)),f=t.places.getShownFeatures();if(l&&f.length>0){const e=n(f);e&&t.baseMap.mapLibreMap.fitBounds(e,{padding:50})}const y=t.places.entries.filter(e=>m.has(e.id)).map(e=>({id:e.id,label:e.label,featureCount:e.data.length}));return{success:!0,totalShown:f.length,shown:y,actuallyAdded:h,actuallyRemoved:g}}catch(c){return{error:`managePlaces failed: ${c instanceof Error?c.message:String(c)}`}}},tags:["place","location","map style"],examples:['managePlaces({ add: ["places-2"] })','managePlaces({ remove: ["places-1"] })','managePlaces({ removeMatching: ["cinema"] }) // hide every entry labelled "cinema"','managePlaces({ addMatching: ["cafe"] })',"managePlaces({ clear: true })",'managePlaces({ add: ["places-2"], fitBounds: true })'],examplePrompts:["Also show the cafes on the map","Additionally pin the pubs","Remove the banks from the map","Hide the cafes"],relatedTools:["discoverPlaces","showPlaces","recallPlaces","clearMap"],dependsOn:["discoverPlaces","locatePlace"]},showRoute:{description:"Show routes and waypoints on the map and fit the camera to the route extent. Pass an id (from recallRoutes) to show a historical route, or omit to show the most recent. Mutates map display. Does not call any service.",classificationPrompt:"Render the most recently calculated route on the map and fit the camera to it.",inputSchema:ra,outputSchema:aa,execute:async(e,t)=>{const{id:o,selectedIndex:a=0,fitBounds:r=!0}=e;try{let e,i;if(o){const a=t.routing.entries.find(e=>e.id===o);if(!a)return{error:`No route entry found with id "${o}"`};e=a.data,i=a.waypoints}else e=t.routing.currentRoutes,i=t.routing.planningSlots.filter(e=>null!==e);if(!e)return{error:"No routes available to display"};const s=await t.routing.getRoutingModule();if(await s.showRoutes(e,{selectedIndex:a}),i&&await s.showWaypoints(i),r){const o=n(e);o&&t.baseMap.mapLibreMap.fitBounds(o,{padding:50})}return{success:!0,displayedRoute:a,routeCount:e.features.length}}catch(i){return{error:`Failed to show route: ${i instanceof Error?i.message:String(i)}`}}},tags:["route","waypoint"],examples:["showRoute()","showRoute({ selectedIndex: 1 })","showRoute({ fitBounds: false })"],examplePrompts:["Draw the route on the map","Show the directions","Display the calculated route"],relatedTools:["setRouteLocations","getShownRouteSections","clearMap"],dependsOn:["setRouteLocations"]},showTrafficAreaAnalytics:{description:"Show HISTORICAL traffic area analytics on the map (hexgrid/heatmap). Not real-time — use toggleTrafficFlow for live traffic. Configure metric, color theme, height, and tile filtering. Use after getTrafficAreaAnalytics. Defaults to first fetched metric.",classificationPrompt:"Render traffic analytics as hexgrid, heatmap, or tiles with custom colors, filtering, height, and tooltip.",inputSchema:ia,outputSchema:sa,execute:async(e,t)=>{try{const o=t.traffic.lastAreaAnalytics;if(!o)return{error:"No analytics data available. Call getTrafficAreaAnalytics first to fetch data."};const a=o.properties?.metrics?.[0]??"congestionLevel",{mode:r="hexgrid-3d",metric:i=a,colorTheme:s="trafficLight",heightScale:l,scaleMode:c,filter:u,visible:d=!0,fitBounds:p=!0}=e,m=await t.traffic.getTrafficAreaAnalyticsModule();if(!d)return await m.clear(),t.traffic.onAnalyticsCleared?.(),{success:!0,mode:r,metric:i,colorTheme:s,visible:!1,filtered:!1};await m.clear(),await m.show(o),m.setMode(r),m.setMetric(i),m.setColor(s),void 0===l&&void 0===c||m.setHeight({...void 0!==l&&{maxHeightMeters:l},...void 0!==c&&{scaleMode:c}});const h=!!u;if(u?m.filter({min:u.min,max:u.max}):m.clearFilter(),p){const e=n(o.features);e&&t.baseMap.mapLibreMap.fitBounds(e,{padding:50,pitch:45})}return t.traffic.onAnalyticsShown?.(o,m),{success:!0,mode:r,metric:i,colorTheme:s,visible:!0,filtered:h}}catch(o){return{error:`Failed to show traffic area analytics: ${o instanceof Error?o.message:String(o)}`}}},tags:["traffic","map style"],examples:["showTrafficAreaAnalytics()","showTrafficAreaAnalytics({ mode: 'hexgrid-2d', metric: 'speed', colorTheme: 'heat' })","showTrafficAreaAnalytics({ filter: { min: 50 } })","showTrafficAreaAnalytics({ scaleMode: 'currentRange', heightScale: 200 })","showTrafficAreaAnalytics({ visible: false })"],examplePrompts:["Show it on the map","Visualize the congestion","Only show areas with congestion above 50%","Normalize height to the current data range","Switch to heatmap view"],relatedTools:["getTrafficAreaAnalytics","queryTrafficAnalytics","toggleTrafficFlow","clearMap"],dependsOn:["getTrafficAreaAnalytics"]},showWaypoints:{description:"Display origin, stop, and destination waypoints as markers on the map. Context-dependent: requires setRouteLocations or locatePlace with waypointIndex to have been called first. Does not recalculate the route. Prefer showRoute when you also need the route line drawn.",classificationPrompt:"Display staged origin/stop/destination markers without drawing the route line.",inputSchema:la,outputSchema:na,execute:async(e,t)=>{try{const e=t.routing.planningSlots;return await(await t.routing.getRoutingModule()).showWaypoints(e),{success:!0,count:e.length}}catch(o){return{error:`Failed to show waypoints: ${o instanceof Error?o.message:String(o)}`}}},tags:["waypoint","route"],examples:["showWaypoints()"],examplePrompts:["Show the waypoints on the map","Mark my route stops"],relatedTools:["setRouteLocations","showRoute","getShownWaypoints","clearMap"],dependsOn:["setRouteLocations","locatePlace"]},getShownPlaces:{description:'List the place entries currently shown on the map, grouped by `placesEntryId` with labels and a feature preview. Use to check which categories are visible before calling `managePlaces`, or when the user asks "what is on the map". Positions are [longitude, latitude].',classificationPrompt:"Return places currently displayed on the map (available after showPlaces or locatePlace).",inputSchema:jo,outputSchema:Do,execute:async(e,t)=>{try{const e=t.places.shownEntryIds;if(0===e.size)return{count:0,entries:[]};const o=t.places.entries.filter(t=>e.has(t.id)).map(e=>({id:e.id,label:e.label,featureCount:e.data.length,features:e.data.slice(0,5).map(e=>({name:e.properties.poi?.name,address:e.properties.address?.freeformAddress,position:e.geometry.coordinates}))}));return{count:o.reduce((e,t)=>e+t.featureCount,0),entries:o}}catch(o){return{error:`Failed to get shown places: ${o instanceof Error?o.message:String(o)}`}}},tags:["place","location"],examples:["getShownPlaces()"],examplePrompts:["What places are on the map?","List the pinned locations"],relatedTools:["showPlaces","clearMap","locatePlace","reverseGeocode"],dependsOn:["showPlaces"]},getShownRoutes:{description:"Get routes currently shown on the map. Reads rendered map state (not plugin service history). Returns routes currently visible on map — use after showRoute.",classificationPrompt:"Return routes currently rendered on the map (available after showRoute).",inputSchema:$o,outputSchema:No,execute:async(e,t)=>{try{if(!t.routing.routingModule)return{count:0,routes:[]};const e=t.routing.routingModule.getShown();return e.mainLines&&0!==e.mainLines.features.length?wt(e.mainLines):{count:0,routes:[]}}catch(o){return{error:`Failed to get shown routes: ${o instanceof Error?o.message:String(o)}`}}},tags:["route"],examples:["getShownRoutes()"],examplePrompts:["What routes are displayed?","Is there a route on the map?"],relatedTools:["showRoute","clearMap"],dependsOn:["showRoute"]},getShownWaypoints:{description:"Get origin/stop/destination waypoints shown on the map. Context-dependent: requires waypoints shown on the map. Returns positions as [longitude, latitude].",classificationPrompt:"Return waypoint markers currently shown on the map (available after showRoute or showWaypoints).",inputSchema:Bo,outputSchema:qo,execute:async(e,t)=>{try{const e=(await t.routing.getRoutingModule()).getShown();return e.waypoints&&0!==e.waypoints.features.length?{count:e.waypoints.features.length,waypoints:e.waypoints.features.map(e=>({name:e.properties.name,position:e.geometry.coordinates}))}:{error:"No waypoints currently shown on the map"}}catch(o){return{error:`Failed to get shown waypoints: ${o instanceof Error?o.message:String(o)}`}}},tags:["waypoint","route"],examples:["getShownWaypoints()"],examplePrompts:["What waypoints are shown?","List the stops on the map"],relatedTools:["showRoute","clearMap"],dependsOn:["showRoute","showWaypoints"]},getShownRouteTrafficIncidents:{description:"Get the route traffic incidents currently displayed on the map (not from service, but what is actually shown). Each section has an id.",classificationPrompt:"Return traffic incidents overlaid on the shown route.",inputSchema:Fo,outputSchema:ko,execute:async(e,t)=>{try{if(!t.routing.routingModule)return{error:"No routing module initialized - no route traffic incidents shown on map"};const e=t.routing.routingModule.getShown();return e.incidents&&0!==e.incidents.features.length?{count:e.incidents.features.length,trafficIncidents:e.incidents.features.map(e=>({id:e.properties.id,magnitudeOfDelay:e.properties.magnitudeOfDelay,title:e.properties.title,delayInSeconds:e.properties.delayInSeconds,effectiveSpeedInKmh:e.properties.effectiveSpeedInKmh,categories:e.properties.categories}))}:{error:"No route traffic incidents currently shown on the map"}}catch(o){return{error:`Failed to get shown route traffic incidents: ${o instanceof Error?o.message:String(o)}`}}},tags:["traffic","route"],examples:["getShownRouteTrafficIncidents()"],examplePrompts:["What traffic incidents are on my route?","Any delays along the route?"],relatedTools:["showRoute","clearMap","setRouteLocations"],dependsOn:["showRoute"]},getShownRouteSections:{description:"Get sections of a specific type (e.g. toll, motorway, country, traffic) from the currently shown routes. Returns section data without coordinate point indices.",classificationPrompt:"Return sections of a given type (toll, country, motorway, traffic) from the shown route.",inputSchema:_o,outputSchema:Eo,execute:async(e,t)=>{const{sectionType:o}=e;try{if(!t.routing.routingModule)return{error:"No routing module initialized - no routes shown on map"};const e=t.routing.routingModule.getShown();if(!e.mainLines||0===e.mainLines.features.length)return{error:"No routes currently shown on the map"};const a=e.mainLines.features.map(e=>{const t=e.properties.sections[o];return t&&0!==t.length?{routeIndex:e.properties.index,sections:t.map(e=>{const{startPointIndex:t,endPointIndex:o,...a}=e;return a})}:null}).filter(e=>null!==e);return 0===a.length?{error:`No "${o}" sections found on any currently shown route`}:{sectionType:o,routes:a}}catch(a){return{error:`Failed to get shown route sections: ${a instanceof Error?a.message:String(a)}`}}},tags:["route","location",...g],examples:['getShownRouteSections("toll")','getShownRouteSections("country")','getShownRouteSections("traffic")','getShownRouteSections("motorway")'],examplePrompts:["What countries does the route pass through?","Show me the toll sections","List the motorway sections on my route"],relatedTools:["showRoute","getShownRoutes","getShownRouteTrafficIncidents","fitRouteSection"],dependsOn:["showRoute"]},getShownIncidents:{description:"Get the real-time traffic incidents currently visible in the map viewport (not from service, but what is actually rendered on the map).",classificationPrompt:"Return real-time incidents currently visible in the map viewport (rendered on map, not fetched from service).",inputSchema:Co,outputSchema:Oo,execute:async(e,t)=>{try{const e=(await t.traffic.getTrafficIncidentsModule()).getShown();return 0===e.trafficIncidents.length?{error:"No traffic incidents currently shown on the map"}:{count:e.trafficIncidents.length,trafficIncidents:e.trafficIncidents.map(e=>({id:e.properties.id,category:e.properties.category,magnitudeOfDelay:e.properties.magnitudeOfDelay,description:e.properties.description,delayInSeconds:e.properties.delayInSeconds,roadCategory:e.properties.roadCategory,averageSpeedKmph:e.properties.averageSpeedKmph}))}}catch(o){return{error:`Failed to get shown incidents: ${o instanceof Error?o.message:String(o)}`}}},tags:["traffic","location"],examples:["getShownIncidents()"],examplePrompts:["What traffic incidents are visible?","Any incidents in the current view?"],relatedTools:["toggleTrafficIncidents","flyTo","getViewport"],dependsOn:["toggleTrafficIncidents"]},clearMap:{description:"Remove displayed features from the map (places, routes, geometries, analytics). Use to clean up before showing new results or to reset the map.",classificationPrompt:"Remove displayed places, routes, or all features from the map.",inputSchema:Ro,outputSchema:Io,execute:async(e,t)=>{const{layers:o}=e;try{const e=!o||0===o.length;return(e||o.includes("places"))&&await t.places.clearShownEntries(),(e||o.includes("routes"))&&t.routing.routingModule&&(await t.routing.routingModule.clearRoutes(),await t.routing.routingModule.clearWaypoints()),(e||o.includes("geometries"))&&t.ranges.geometriesModule&&await t.ranges.geometriesModule.clear(),(e||o.includes("analytics"))&&t.traffic.trafficAreaAnalyticsModule&&await t.traffic.trafficAreaAnalyticsModule.clear(),{success:!0,cleared:o||["places","routes","geometries","analytics"]}}catch(a){return{error:`Failed to clear map: ${a instanceof Error?a.message:String(a)}`}}},tags:["place","route","map style"],examples:["clearMap()",'clearMap(["places"])','clearMap(["places", "routes"])'],examplePrompts:["Clear the map","Remove all markers","Start fresh"],relatedTools:["showPlaces","showRoute"]},flyTo:{description:"Move the map camera to a bounding box or a specific position. Use with boundingBox to frame a region or set of results. Use with position to center on a point.",classificationPrompt:"Move the camera to a bounding box or specific position; use after locating places or computing bounds.",inputSchema:We,outputSchema:ze,execute:async(e,t)=>{const{where:o}=e;try{if("boundingBox"in o){const e=n(o.boundingBox);if(!e)return{error:"Invalid boundingBox — could not extract a bounding box."};t.baseMap.mapLibreMap.fitBounds(e,{padding:o.padding??50})}else t.baseMap.mapLibreMap.flyTo({center:o.position,zoom:o.zoom??14});return{success:!0}}catch(a){return{error:`flyTo failed: ${a instanceof Error?a.message:String(a)}`}}},tags:["location","map style"],examples:["flyTo({ where: { boundingBox: [4.8, 52.3, 5.0, 52.5] } })","flyTo({ where: { boundingBox: [4.8, 52.3, 5.0, 52.5], padding: 100 } })","flyTo({ where: { position: [4.9, 52.4], zoom: 14 } })"],examplePrompts:["Go to Berlin","Center the map on Rome","Fly to these coordinates"],relatedTools:["getViewport","locatePlace","showPlaces","showRoute","calculateBBox"]},fitRouteSection:{description:"Fit the map camera to show a specific route section by type and ID. Use getShownRouteSections to obtain valid section IDs. Requires a route to be shown on the map.",classificationPrompt:"Fit the camera to a specific route section by type and ID; use getShownRouteSections for valid IDs.",inputSchema:Ao,outputSchema:Lo,execute:async(e,t)=>{const{sectionType:o,id:a,padding:r=50}=e;try{if(!t.routing.routingModule)return{error:"No routing module initialized - no routes shown on map"};const e=t.routing.routingModule.getShown();if(!e.mainLines||0===e.mainLines.features.length)return{error:"No routes are currently displayed on the map. Please show a route first before fitting to a section."};const i=e.mainLines.features;let s,n;for(const t of i){const e=t.properties.sections[o];if(e&&Array.isArray(e)){const o=e.find(e=>e.id===a);if(o&&"number"==typeof o.startPointIndex&&"number"==typeof o.endPointIndex){n=o,s=t;break}}}if(!s||!n)return{error:`Could not find a section with type "${o}" and id "${a}" in any displayed route. Check the section type and id are correct.`};const l=m(s,n);return l?(t.baseMap.mapLibreMap.fitBounds(l,{padding:r}),{success:!0}):{error:"Could not calculate bounding box for the section. The section may have invalid indices."}}catch(i){return{error:`Failed to fit route section: ${i instanceof Error?i.message:String(i)}`}}},tags:["route","map style",...g],examples:['fitRouteSection("country", "NLD-section-1")','fitRouteSection("traffic", "traffic-1", 100)'],examplePrompts:["Zoom to the toll section","Fit the Netherlands part of the route in view"],relatedTools:["flyTo","showRoute","getShownRoutes","getShownRouteTrafficIncidents"],dependsOn:["getShownRouteSections"]},getViewport:{description:'Get the current map viewport: center coordinates [longitude, latitude], zoom level, and bounding box [minLng, minLat, maxLng, maxLat]. Use for queries referencing the map view: "in this area", "what I can see", "near the map center". Does NOT return the user\'s physical location — use getCurrentLocation for "near me" queries. Reads map state. Does not call any service.',classificationPrompt:'Return the map center, zoom, and bounding box; use for area-relative queries like "in this area" or "near the map center".',inputSchema:Ye,outputSchema:Ve,execute:async(e,t)=>{try{const e=t.baseMap.mapLibreMap;return{center:e.getCenter().toArray(),zoom:e.getZoom(),bbox:t.baseMap.ttMap.getBBox(),pitch:e.getPitch(),bearing:e.getBearing()}}catch(o){return{error:`Failed to get viewport: ${o instanceof Error?o.message:String(o)}`}}},tags:["location","map style"],examples:["getViewport()"],examplePrompts:["Where is the map centered?","What's the current map area?","What are the current map bounds?"],relatedTools:["locatePlace","flyTo","discoverPlaces","reverseGeocode","getTrafficIncidents"]},recallPlaces:{description:"Retrieve places and search results from session history. ALWAYS use this when referencing places from earlier in the session — do not re-search by name. Returns entries with stable IDs accepted by showPlaces, and exact coordinates usable in setRouteLocations. Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. Step 2: call with id to retrieve a specific entry with coordinates. Does not call any service.",classificationPrompt:"Return the history of locatePlace/discoverPlaces calls made in this session.",inputSchema:mo,outputSchema:fo,execute:async(e,t)=>{const{id:o}=e;if(!o)return{entries:[...t.places.entries].reverse().map(({id:e,label:t,timestamp:o})=>({id:e,label:t,timestamp:o}))};const a=t.places.entries.find(e=>e.id===o);if(!a)return{error:`No entry found with id "${o}"`};const r=yt(a.data);return{id:a.id,label:a.label,timestamp:a.timestamp,places:r}},tags:["place","location"],examples:["recallPlaces()",'recallPlaces({ id: "places-0" })'],examplePrompts:["What places did I search for?","Show the coffee shops from earlier","What was the first place we looked up?"],relatedTools:["discoverPlaces","locatePlace","reverseGeocode","showPlaces"],dependsOn:["locatePlace","discoverPlaces"]},recallRoutes:{description:"Retrieve calculated routes from session history. ALWAYS use this when referencing routes from earlier in the session. Entries have stable IDs that showRoute accepts. Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. Step 2: call with id to retrieve a specific entry with route details and params. Does not call any service.",classificationPrompt:"Return previously calculated routes from this session.",inputSchema:So,outputSchema:To,execute:async(e,t)=>{const{id:o}=e;if(!o)return{entries:[...t.routing.entries].reverse().map(({id:e,label:t,timestamp:o})=>({id:e,label:t,timestamp:o}))};const a=t.routing.entries.find(e=>e.id===o);if(!a)return{error:`No entry found with id "${o}"`};const r=wt(a.data),i=a.waypoints.map(e=>St(e)).filter(e=>null!==e).map(e=>({position:e.position??[0,0]}));return{id:a.id,label:a.label,timestamp:a.timestamp,routes:r,waypoints:i,params:a.params}},tags:["route"],examples:["recallRoutes()",'recallRoutes({ id: "routes-0" })'],examplePrompts:["What routes have I calculated?","Show the first route we planned","What was the route to Schiphol?"],relatedTools:["setRouteLocations","showRoute","getCurrentWaypoints"],dependsOn:["setRouteLocations"]},getCurrentWaypoints:{description:'Read the waypoint slots currently staged for the next route calculation without recalculating anything. Use for follow-up questions like "what coordinates are staged now?", "which slots are filled?", or "what is destination slot 1?". Highly specific rules: slotIndex returns one known slot; otherwise results are paged, default to 5 slots, and empty slots are omitted unless includeEmptySlots=true to keep payloads compact. Does not call any service.',classificationPrompt:"Return the staged waypoint slots (origin, stops, destination) not yet committed to a route.",inputSchema:uo,outputSchema:po,execute:async(e,t)=>{const{slotIndex:o,includeEmptySlots:a=!1,offset:r=0,limit:i=5}=e,s=t.routing.planningSlots.map((e,t)=>{const o=St(e);return o?{...o,slotIndex:t}:{slotIndex:t,isFilled:!1}}),n=a?s:s.filter(e=>e.isFilled),l=void 0!==o,c=l?n.filter(e=>e.slotIndex===o):n.slice(r,r+i),u=r+c.length;return{totalSlots:s.length,filledSlots:s.filter(e=>e.isFilled).length,matchedCount:l?c.length:n.length,returnedCount:c.length,offset:l?0:r,hasMore:!l&&u<n.length,...!l&&u<n.length&&{nextOffset:u},waypoints:c}},tags:["waypoint","route"],examples:["getCurrentWaypoints()","getCurrentWaypoints({ slotIndex: 1 })","getCurrentWaypoints({ includeEmptySlots: true })","getCurrentWaypoints({ offset: 2, limit: 4 })"],examplePrompts:["What are my current route waypoints?","What's my destination?","Show my staged stops"],relatedTools:["locatePlace","setRouteLocations","showWaypoints","recallRoutes"]},getStandardMapStyles:{description:"Get the list of available standard map style IDs. If you need more fine styling control, refer to getMapStyleLayers.",classificationPrompt:"List available standard map style IDs for use with setMapStandardStyle.",inputSchema:Wo,outputSchema:zo,execute:async(e,t)=>{try{return{styles:A}}catch(o){return{error:`Failed to get standard map styles: ${o instanceof Error?o.message:String(o)}`}}},tags:["map style"],examples:["getStandardMapStyles()"],examplePrompts:["What map styles are available?","List the map themes"],relatedTools:["setMapStandardStyle"]},setMapStandardStyle:{description:"Set the map style to a standard preset (light, dark, mono, driving, satellite, etc). For detailed or incremental style tweaking use getMapStyleLayers, setLayoutProperties, and setPaintProperties.",classificationPrompt:"Switch the map to a standard style preset (light, dark, satellite, driving, etc.).",inputSchema:Zo,outputSchema:Ko,execute:async(e,t)=>{const{style:o}=e;try{return t.baseMap.ttMap.setStyle(o),{success:!0,style:o}}catch(a){return{error:`Failed to set map style: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style"],examples:['setMapStandardStyle("standardDark")','setMapStandardStyle("satellite")'],examplePrompts:["Switch to dark mode","Use the satellite view","Change to the light theme"],relatedTools:["getStandardMapStyles","setLanguage","toggleBaseMapLayerGroups","getMapStyleLayers"]},setRouteTheme:{description:"Style the route line and waypoint icons with a color. Prefer this over setPaintProperties for route styling — it applies the color consistently across all route and waypoint layers. Requires a route to be shown on the map.",classificationPrompt:"Color the route line and waypoint icons; prefer over setPaintProperties for route styling.",inputSchema:Xo,outputSchema:Qo,execute:async(e,t)=>{try{return void 0!==e.mainColor&&(ea.mainColor=e.mainColor),(await t.routing.getRoutingModule()).applyConfig({theme:{mainColor:ea.mainColor}}),{success:!0,theme:{...ea}}}catch(o){return{error:`Failed to set route theme: ${o instanceof Error?o.message:String(o)}`}}},tags:["route","map style"],examples:['setRouteTheme({ mainColor: "#FF0000" }) // red route','setRouteTheme({ mainColor: "coral" })','setRouteTheme({ mainColor: "steelblue" })'],examplePrompts:["Make the route line red","Change the route color to blue","Style the route in coral"],relatedTools:["showRoute","setRouteLocations","setPaintProperties"],dependsOn:["showRoute"]},setLanguage:{description:"Set the language used for map labels (place names, road names, POI labels) and for all subsequent service API calls (search results, geocoding, routing instructions, etc.). Both the rendered map text and future service responses will use the new language.",classificationPrompt:"Change the language for map labels and all subsequent service API responses.",inputSchema:Jo,outputSchema:Ho,execute:async(e,t)=>{const{language:o}=e;try{return i.instance.put({language:o}),t.baseMap.ttMap.setLanguage(o),{success:!0,language:o}}catch(a){return{error:`Failed to set language: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style"],examples:['setLanguage("fr-FR")','setLanguage("de-DE")'],examplePrompts:["Show map labels in French","Switch the map to German","Use Spanish for place names"],relatedTools:["setMapStandardStyle"]},toggleBaseMapLayerGroups:{description:"Show or hide specific base map layer groups (water, buildings3D, roadLines, placeLabels, capitalLabels, etc.)",classificationPrompt:"Show or hide named base map layer groups (buildings3D, roadLabels, water, placeLabels, etc.).",inputSchema:ua,outputSchema:ca,execute:async(e,t)=>{const{visible:o,layerGroups:a}=e;try{return(await t.baseMap.getBaseMapModule()).setVisible(o,{layerGroups:{mode:"include",names:a}}),{success:!0,visible:o,layerGroups:a}}catch(r){return{error:`Failed to toggle layer groups: ${r instanceof Error?r.message:String(r)}`}}},tags:["map style"],examples:['toggleBaseMapLayerGroups(false, ["buildings3D"])','toggleBaseMapLayerGroups(true, ["roadLabels"])'],examplePrompts:["Hide 3D buildings","Show road labels","Toggle the building layer"],relatedTools:["togglePOIs","getMapStyleLayers","setMapStandardStyle"]},togglePOIs:{description:"Show or hide all built-in map POI icons (restaurants, hotels, gas stations, etc.) and optionally filter by category. Use allMapPOIsVisible to control overall POI visibility, filterCategories to restrict which categories are shown or hidden, or reset: true to restore all POI defaults.",classificationPrompt:"Show or hide built-in map POI icons with optional category filtering.",inputSchema:pa,outputSchema:da,execute:async(e,t)=>{try{const o=await t.mapPOIs.getPOIsModule();if(e.reset)return o.resetConfig(),{success:!0,reset:!0};const{allMapPOIsVisible:a,filterCategories:r}=e;return void 0!==a&&o.setVisible(a),r&&o.filterCategories({show:r.show,values:r.values}),{success:!0,allMapPOIsVisible:a,filterCategories:r}}catch(o){return{error:`Failed to toggle POIs: ${o instanceof Error?o.message:String(o)}`}}},tags:["place","map style"],examples:["togglePOIs({ allMapPOIsVisible: false })",'togglePOIs({ allMapPOIsVisible: true, filterCategories: { show: "only", values: ["RESTAURANT", "CAFE"] } })','togglePOIs({ filterCategories: { show: "all_except", values: ["PARKING_GARAGE"] } })',"togglePOIs({ reset: true })"],examplePrompts:["Hide all POI icons","Show only restaurant POIs","Turn off parking icons"],relatedTools:["toggleBaseMapLayerGroups","discoverPlaces","setMapStandardStyle"]},toggleTrafficFlow:{description:"Toggle the REAL-TIME traffic flow layer — colored road segments showing live speed conditions. This is NOT historical analytics; use showTrafficAreaAnalytics for historical data.",classificationPrompt:"Toggle REAL-TIME traffic flow (colored road segments for live speeds). Not historical analytics.",inputSchema:ma,outputSchema:ha,execute:async(e,t)=>{const{visible:o}=e;try{return(await t.traffic.getTrafficFlowModule()).setVisible(o),{success:!0,trafficFlowVisible:o}}catch(a){return{error:`Failed to toggle traffic flow: ${a instanceof Error?a.message:String(a)}`}}},tags:["traffic","map style"],examples:["toggleTrafficFlow(true)","toggleTrafficFlow(false)"],examplePrompts:["Show traffic flow","Turn off traffic colors","Enable the congestion overlay"],relatedTools:["toggleTrafficIncidents","setRouteLocations","getTrafficIncidents"]},toggleTrafficIncidents:{description:"Toggle REAL-TIME traffic incident markers on the map (jams, accidents, closures, roadworks). This is NOT historical analytics. Use getTrafficIncidents for incident details.",classificationPrompt:"Toggle REAL-TIME traffic incident markers and lines (accidents, jams, closures). Not historical analytics.",inputSchema:ga,outputSchema:fa,execute:async(e,t)=>{const{visible:o}=e;try{return(await t.traffic.getTrafficIncidentsModule()).setVisible(o),{success:!0,trafficIncidentsVisible:o}}catch(a){return{error:`Failed to toggle traffic incidents: ${a instanceof Error?a.message:String(a)}`}}},tags:["traffic","map style"],examples:["toggleTrafficIncidents(true)","toggleTrafficIncidents(false)"],examplePrompts:["Show traffic incidents","Hide accident icons","Enable incident markers"],relatedTools:["toggleTrafficFlow","getTrafficIncidents","getShownIncidents","setRouteLocations"]},getMapStyleLayers:{description:"Get map layer IDs with their paint/layout properties from MapLibre style for advanced runtime manipulation. Use before setLayoutProperty/setPaintProperty for custom styling.",classificationPrompt:"List MapLibre layer IDs with their paint/layout properties for custom styling.",inputSchema:Ge,outputSchema:Ue,execute:async(e,t)=>{const{layerIdQuery:o,include:a}=e;try{let e=t.baseMap.mapLibreMap.getStyle().layers??[];return o&&(e=e.filter(e=>e.id.toLowerCase().includes(o.toLowerCase())),0===e.length)?{error:`No layers found matching query: "${o}"`}:{layers:e.map(e=>({id:e.id,...a.includes("paint")&&{paint:e.paint},...a.includes("layout")&&{layout:e.layout}}))}}catch(r){return{error:`Failed to get style: ${r instanceof Error?r.message:String(r)}`}}},tags:["map style"],examples:["getMapStyleLayers()",'getMapStyleLayers("road")','getMapStyleLayers("water")'],examplePrompts:["What are the paint properties of the water layer?","Show me the road layer layout"],relatedTools:["setLayoutProperties","setPaintProperties"]},setLayoutProperties:{description:"Set one or more layout properties on MapLibre layers (visibility, text-field, icon-size). Use getMapStyleLayers to discover valid layer IDs first. Layout properties control structure and visibility — use setPaintProperties for colors and widths.",classificationPrompt:"Set MapLibre layout properties (visibility, text-field, icon-size) on named layers.",inputSchema:Ke,outputSchema:Je,execute:async(e,t)=>{const{changes:o}=e;try{return{results:o.map(({layerId:e,propertyName:o,value:a})=>{try{return t.baseMap.mapLibreMap.setLayoutProperty(e,o,a),{layerId:e,propertyName:o,value:a,success:!0}}catch(r){return{layerId:e,propertyName:o,error:`Failed to set layout property: ${r instanceof Error?r.message:String(r)}`}}})}}catch(a){return{error:`Failed to set layout properties: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style"],examples:['setLayoutProperties([{ layerId: "road-label", propertyName: "visibility", value: "none" }])','setLayoutProperties([{ layerId: "poi-label", propertyName: "text-field", value: "{name}" }, { layerId: "poi-label", propertyName: "icon-size", value: 1.2 }])'],examplePrompts:["Hide the road-label layer","Change the text size on building labels","Make the city labels bigger"],relatedTools:["getMapStyleLayers","setPaintProperties"],dependsOn:["getMapStyleLayers"]},setPaintProperties:{description:"Set one or more paint properties on MapLibre layers (colors, widths, opacity). Use getMapStyleLayers to discover valid layer IDs first. Paint properties control visual appearance — use setLayoutProperties for visibility and structural properties. For route styling, prefer setRouteTheme.",classificationPrompt:"Set MapLibre paint properties (colors, widths, opacity) on named layers.",inputSchema:Xe,outputSchema:Qe,execute:async(e,t)=>{const{changes:o}=e;try{return{results:o.map(({layerId:e,propertyName:o,value:a})=>{try{return t.baseMap.mapLibreMap.setPaintProperty(e,o,a),{layerId:e,propertyName:o,value:a,success:!0}}catch(r){return{layerId:e,propertyName:o,error:`Failed to set paint property: ${r instanceof Error?r.message:String(r)}`}}})}}catch(a){return{error:`Failed to set paint properties: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style"],examples:['setPaintProperties([{ layerId: "water", propertyName: "fill-color", value: "#0000ff" }])','setPaintProperties([{ layerId: "road", propertyName: "line-color", value: "#ff0000" }, { layerId: "road", propertyName: "line-width", value: 3 }])'],examplePrompts:["Make the water bright blue","Change the road color to red","Make buildings semi-transparent","Make the country borders pink"],relatedTools:["getMapStyleLayers","setLayoutProperties","setRouteTheme"],dependsOn:["getMapStyleLayers"]},setPitchBearing:{description:"Tilt and/or rotate the map camera. Pitch 0 = top-down view, 85 = near-horizontal (3D effect). Bearing 0 = north up, 90 = east up. Provide at least one of pitch or bearing.",classificationPrompt:"Tilt (pitch) and/or rotate (bearing) the map camera for a 3D perspective.",inputSchema:tt,outputSchema:et,execute:async(e,t)=>{const{pitch:o,bearing:a}=e;if(void 0===o&&void 0===a)return{error:"Provide at least one of pitch or bearing"};try{return t.baseMap.mapLibreMap.easeTo({...void 0!==o&&{pitch:o},...void 0!==a&&{bearing:a}}),{success:!0}}catch(r){return{error:`Failed to set pitch/bearing: ${r instanceof Error?r.message:String(r)}`}}},tags:["map style"],examples:["setPitchBearing({ pitch: 45 })","setPitchBearing({ bearing: 90 })","setPitchBearing({ pitch: 60, bearing: -45 })"],examplePrompts:["Tilt the map to 45 degrees","Rotate the map to face north","Set a 3D perspective view"],relatedTools:["getViewport","locatePlace","flyTo"]},zoomInOrOut:{description:"Zoom the map in or out by a given amount relative to the current zoom level. Positive delta zooms in (closer), negative delta zooms out (further away). Returns the resulting zoom level.",classificationPrompt:"Adjust the map zoom level by a delta; positive zooms in, negative zooms out.",inputSchema:at,outputSchema:ot,execute:async(e,t)=>{const{delta:o}=e;try{const e=t.baseMap.mapLibreMap,a=e.getZoom()+o;return e.zoomTo(a),{zoom:a}}catch(a){return{error:`Zoom failed: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style"],examples:["zoomInOrOut({ delta: 2 })","zoomInOrOut({ delta: -1 })"],examplePrompts:["Zoom in","Zoom out 2 levels","Get a wider view"],relatedTools:["getViewport","flyTo"]},executeMaplibreCode:{description:"Execute any MapLibre JS code for maximum flexibility. `map` is the live MapLibre Map instance — the full API is available. Use for anything: custom sources and layers, camera control, style mutations, event-driven sequences, animations, or any operation not covered by other tools. Full JS is supported: loops, conditionals, helper functions, top-level `await`, event listeners. Returns which sources and layers were added, removed, or updated.",classificationPrompt:"Execute any MapLibre JS code against the live map for maximum flexibility — use when no other tool covers the required operation.",inputSchema:Ie,outputSchema:Re,execute:async(e,t)=>{const{code:o}=e;try{const e=t.baseMap.mapLibreMap,a=Le(e),r=Ae(e),i=Object.getPrototypeOf(async()=>{}).constructor,s=await new i("map",o)(e),n=Oe(a,Le(e));return{success:!0,result:s??void 0,sources:n,layers:Oe(r,Ae(e))}}catch(a){return{error:`Code execution failed: ${a instanceof Error?a.message:String(a)}`}}},tags:["map style","maplibre","layers","sources","animation"],examples:["executeMaplibreCode({ code: \"map.addSource('pts', { type: 'geojson', data: fc }); map.addLayer({ id: 'pts', type: 'circle', source: 'pts', paint: { 'circle-color': '#f00' } })\" })",'executeMaplibreCode({ code: "map.easeTo({ center: [4.9, 52.37], zoom: 14, duration: 2000 })" })',"executeMaplibreCode({ code: \"for (let i = 0; i <= 20; i++) { map.setPaintProperty('fill', 'fill-opacity', i / 20); await new Promise(r => setTimeout(r, 50)); }\" })","executeMaplibreCode({ code: \"map.setFog({ color: 'white', 'horizon-blend': 0.1 })\" })"],examplePrompts:["Add a GeoJSON layer to the map","Animate the map camera","Fade in a layer gradually","Set map fog or atmosphere","Add a raster tile overlay"],relatedTools:["getMapStyleLayers","setLayoutProperties","setPaintProperties","flyTo"],dependsOn:["getMapStyleLayers"]},calculateBBox:{description:"Calculate a [minLng, minLat, maxLng, maxLat] bbox from GeoJSON. Context-independent. Returns bounding box as [minLng, minLat, maxLng, maxLat] — longitude before latitude.",classificationPrompt:"Compute a [minLng, minLat, maxLng, maxLat] bounding box from GeoJSON features or tool results.",inputSchema:ee,execute:async(e,t)=>{const{geoJson:o}=e;try{const e=n(o);return e?{bbox:e,minLng:e[0],minLat:e[1],maxLng:e[2],maxLat:e[3]}:{error:"Could not calculate bounding box - input may be empty or invalid GeoJSON"}}catch(a){return{error:`Failed to calculate bbox: ${a instanceof Error?a.message:String(a)}`}}},tags:["utilities","location"],examples:["calculateBBox(place)","calculateBBox(routes)","calculateBBox([place1, place2])"],examplePrompts:["What's the bounding box of these places?","Calculate the extent of this route"],relatedTools:["flyTo","getViewport","showPlaces","showRoute"]},formatDistance:{description:'Format a distance in meters into a human-readable string (e.g. "2.5 km", "1.5 mi"). Use after getSectionProgress, recallRoutes, or any tool that returns distances in meters.',classificationPrompt:'Format meters into a human-readable string (e.g. "2.5 km"); use after tools that return distances.',inputSchema:te,execute:async(e,t)=>{const{meters:o,unitType:a}=e;try{return{formatted:l(o,a?{type:a}:void 0),input:{meters:o,unitType:a??"metric"}}}catch(r){return{error:`Failed to format distance: ${r instanceof Error?r.message:String(r)}`}}},tags:["utilities","route"],examples:["formatDistance(2500)",'formatDistance(5000, "imperial_us")'],examplePrompts:["Format 5000 meters as a distance","Convert meters to a readable string"],relatedTools:["formatDuration","setRouteLocations","getSectionProgress","getRouteProgress"]},formatDuration:{description:'Format a duration in seconds into a human-readable time string (e.g. "1 h 30 min"). Use after getSectionProgress, recallRoutes, or any tool that returns durations in seconds.',classificationPrompt:'Format seconds into a human-readable string (e.g. "1 h 30 min"); use after tools that return durations.',inputSchema:oe,execute:async(e,t)=>{const{seconds:o}=e;try{const e=c(o);return void 0===e?{formatted:void 0,message:"< 1 min",input:{seconds:o}}:{formatted:e,input:{seconds:o}}}catch(a){return{error:`Failed to format duration: ${a instanceof Error?a.message:String(a)}`}}},tags:["utilities","route"],examples:["formatDuration(3600)","formatDuration(9000)"],examplePrompts:["Format 3600 seconds as a duration","Convert seconds to hours and minutes"],relatedTools:["formatDistance","setRouteLocations","getSectionProgress","getRouteProgress"]},getSectionProgress:{description:"Calculate the distance and travel time for one or more sections of the shown route. If ids is omitted, all sections of the given type are returned.",classificationPrompt:"Return the distance and travel time for one or more sections of the shown route by type.",inputSchema:ge,execute:async(e,t)=>{const{sectionType:o,ids:a}=e;try{const e=t.routing.currentRoutes;if(!e||0===e.features.length)return{error:"No routes available. Use calculate-route first."};const r=[];for(const t of e.features){const e=t.properties.sections[o];if(e)for(const o of e){if(a&&a.length>0&&!a.includes(o.id))continue;const e=p(t,o);e?r.push({sectionId:o.id,startPointIndex:o.startPointIndex,endPointIndex:o.endPointIndex,start:e.start,end:e.end,delta:e.delta}):r.push({sectionId:o.id,error:"Could not calculate progress for this section. The route may be missing progress data."})}}if(a&&a.length>0){const e=new Set(r.map(e=>e.sectionId));for(const t of a)e.has(t)||r.push({sectionId:t,error:`Could not find a section with type "${o}" and id "${t}" in the last calculated routes.`})}return 0===r.length?{error:`No sections of type "${o}" found in the last calculated routes.`}:{sectionType:o,sections:r}}catch(r){return{error:`Failed to get section progress: ${r instanceof Error?r.message:String(r)}`}}},tags:["utilities","route",...g],examples:['getSectionProgress({ sectionType: "country" }) // all country sections','getSectionProgress({ sectionType: "traffic", ids: ["incident-id-1"] })','getSectionProgress({ sectionType: "toll", ids: ["toll-1", "toll-2"] })'],examplePrompts:["How far is the toll section?","Travel time through France on this route"],relatedTools:["setRouteLocations","fitRouteSection","formatDistance","formatDuration"],dependsOn:["showRoute"]},getSectionBBox:{description:"Calculate the bounding box [minLng, minLat, maxLng, maxLat] for a specific section of the shown route. Use with flyTo to frame the section, or to query traffic incidents within it.",classificationPrompt:"Return the bounding box of a specific route section; use with flyTo to frame it.",inputSchema:he,outputSchema:me,execute:async(e,t)=>{const{sectionType:o,id:a}=e;try{const e=t.routing.currentRoutes;if(!e||0===e.features.length)return{error:"No routes available. Use calculate-route first."};for(const t of e.features){const e=t.properties.sections[o];if(!e||!Array.isArray(e))continue;const r=e.find(e=>e.id===a);if(r&&"number"==typeof r.startPointIndex&&"number"==typeof r.endPointIndex){const e=m(t,r);return e?{bbox:e}:{error:"Could not calculate bounding box for the section. The section may have invalid indices."}}}return{error:`Could not find a section with type "${o}" and id "${a}" in the last calculated routes.`}}catch(r){return{error:`Failed to get section bbox: ${r instanceof Error?r.message:String(r)}`}}},tags:["utilities","route","location",...g],examples:['getSectionBBox({ sectionType: "country", id: "NLD-section-1" })','getSectionBBox({ sectionType: "traffic", id: "traffic-1" })','getSectionBBox({ sectionType: "toll", id: "toll-2" })'],examplePrompts:["Get the extent of the Netherlands section","Bounding box of the traffic incident"],relatedTools:["flyTo","fitRouteSection","getSectionProgress","getShownRouteSections"],dependsOn:["getShownRouteSections"]},getRouteProgress:{description:"Return the geographic coordinates of the point along the last shown route at a given traveled time (seconds), traveled distance (meters), or absolute clock time (ISO 8601). Use for route progress tracking (e.g. route-point-progress-playground example).",classificationPrompt:"Return the position along the shown route at a given traveled time, distance, or clock time.",inputSchema:pe,execute:async(e,t)=>{const o=e.routeIndex??0;try{const a=(await t.routing.getRoutingModule()).getShown().mainLines;if(!a||0===a.features.length)return{error:"No routes available. Use calculate-route first."};const r=a.features[o];if(!r)return{error:`Route index ${o} is out of range. There are ${a.features.length} route(s) available.`};if(!r.properties.progress||0===r.properties.progress.length)return{error:"The route does not contain progress data. Re-calculate the route to ensure progress data is included."};const i=(e=>{if(void 0!==e.traveledTimeInSeconds)return{traveledTimeInSeconds:e.traveledTimeInSeconds};if(void 0!==e.traveledDistanceInMeters)return{traveledDistanceInMeters:e.traveledDistanceInMeters};const t=new Date(e.clockTime).getTime();return Number.isNaN(t)?{error:`Invalid clockTime value: "${e.clockTime}". Use ISO 8601 format.`}:{clockTime:new Date(e.clockTime)}})(e);if("error"in i)return i;const s=u(r,i);return void 0===s?{error:"Could not interpolate a position. The progress data may be incomplete or the requested value is out of range."}:{longitude:s.position[0],latitude:s.position[1],travelTimeInSeconds:Math.round(s.travelTimeInSeconds),distanceInMeters:Math.round(s.distanceInMeters)}}catch(a){return{error:`Failed to get route progress: ${a instanceof Error?a.message:String(a)}`}}},tags:["utilities","route","location"],examples:["getRouteProgress(traveledTimeInSeconds: 600)","getRouteProgress(traveledDistanceInMeters: 5000)",'getRouteProgress(clockTime: "2025-06-01T09:30:00Z")',"getRouteProgress(traveledTimeInSeconds: 300, routeIndex: 1)"],examplePrompts:["Where am I after 10 minutes of travel?","Position at 5km into the route"],relatedTools:["setRouteLocations","getSectionProgress","formatDistance","formatDuration"],dependsOn:["showRoute"]},getCurrentLocation:{description:'Get the user\'s physical location from the browser geolocation API. Use for queries referencing the user\'s body: "near me", "where I am", "my location", "nearby". May prompt the user for location permission. Does NOT return the map viewport center — use getViewport for map-based reference. Returns: position [longitude, latitude].',classificationPrompt:'Get the user\'s physical GPS location from the browser; use for "near me" queries, not map center.',inputSchema:ce,outputSchema:ue,execute:async(e,t)=>{if(void 0===globalThis.window||void 0===globalThis.navigator)return{error:"Current location is only available in a browser environment"};if(!("geolocation"in globalThis.navigator))return{error:"Geolocation is not supported by this browser"};try{const e=await new Promise((e,t)=>{globalThis.navigator.geolocation.getCurrentPosition(e,t,{enableHighAccuracy:!0,timeout:15e3,maximumAge:0})});return{position:[e.coords.longitude,e.coords.latitude],accuracy:e.coords.accuracy,timestamp:e.timestamp}}catch(o){const e=(e=>{if("object"!=typeof e||null===e||!("code"in e))return;const t=e.code;return 1===t?"Location permission denied by the user":2===t?"Current location is unavailable":3===t?"Timed out while trying to get current location":void 0})(o);return e?{error:e}:{error:`Failed to get current location: ${o instanceof Error?o.message:String(o)}`}}},tags:["utilities","location"],examples:["getCurrentLocation()"],examplePrompts:["Where am I?","Get my GPS location","Use my current position"],relatedTools:["discoverPlaces","reverseGeocode","locatePlace"]},help:{description:ve,classificationPrompt:"Return available capabilities in summary or searchable detail mode; call when the user asks what you can do.",inputSchema:we,outputSchema:be,execute:async()=>{throw new Error("help tool requires setupTools() — it needs resolved metadata from all tools.")},tags:["utilities"],examples:['help({ mode: "summary" })','help({ mode: "detail", query: "traffic" })','help({ mode: "detail", tag: "route" })','help({ mode: "detail", query: "route", tag: "utilities" })'],examplePrompts:["What can you do?","Show me available tools","How do I search for places?"]},searchAlongRoute:{description:"Search for POIs along a calculated route, ranked by detour cost. Reads the route from state — call setRouteLocations first. Use recallRoutes to find the ID of a specific route; defaults to the most recent. Stores results in places history; pass the returned placesEntryId to showPlaces({ id }) to display them. status: no_route if no route exists in state.",classificationPrompt:"Search for POIs along a calculated route ranked by detour cost.",inputSchema:io,outputSchema:ro,execute:async(e,t)=>{const{query:o,poiCategories:a,routeId:r,maxDetourTimeSeconds:i,sortBy:s,limit:n,show:l}=e,c=((e,t)=>{const o=e.routing.entries;if(0===o.length)return null;const a=t?o.find(e=>e.id===t):o.at(-1);if(!a)return`No route found with id "${t}". Use recallRoutes to list available routes.`;const r=a.data.features[0];return r?{entry:a,routeFeature:r}:"Route entry has no geometry."})(t,r);if(null===c)return{status:"no_route"};if("string"==typeof c)return{error:c};const{entry:u,routeFeature:d}=c;try{const e=await(async(e,t)=>{const{query:o,poiCategories:a,maxDetourTimeSeconds:r,sortBy:i,limit:s}=e,n=await je(a);return C({route:t,maxDetourTimeSeconds:r,...o&&{query:o},...n&&{poiCategories:n},...i&&{sortBy:i},...void 0!==s&&{limit:s}})})({query:o,poiCategories:a,maxDetourTimeSeconds:i,sortBy:s,limit:n},d),r=pt(e,{query:o,poiCategories:a,routeLabel:u.label}),c=t.places.addPlaceResult(e,r),p=l?await $e(t,e,c,l):void 0;return{...yt(e),placesEntryId:c,...p&&{shown:p}}}catch(p){return{error:`Along-route search failed: ${p instanceof Error?p.message:String(p)}`}}},tags:["search","route","place","detour","along-route"],examples:['searchAlongRoute({ maxDetourTimeSeconds: 300, query: "coffee" })','searchAlongRoute({ maxDetourTimeSeconds: 600, poiCategories: ["ELECTRIC_VEHICLE_STATION"], sortBy: "detourOffset" })','searchAlongRoute({ maxDetourTimeSeconds: 300, routeIndex: 0, show: { markerType: "pin", zoomMode: "auto" } })'],examplePrompts:["Find gas stations along my route","Show me coffee shops within 5 minutes off the route","Any EV chargers I can reach from this route?","I need a coffee stop on the way to the airport","Find me a restaurant somewhere between here and Paris"],relatedTools:["setRouteLocations","recallRoutes","showPlaces","recallPlaces"],dependsOn:["setRouteLocations"]},findReachableArea:{description:"Find the reachable area (isochrone/isodistance polygon) from an origin within time or distance budgets. Pass multiple budgets for nested ranges (e.g. 10/20/30 min or 10/25/50 km). Results stored in state; use recallRanges to retrieve. showOnMap renders the polygons on the map. status: not_found if origin cannot be resolved; no_results if API returns empty geometry.",classificationPrompt:"Calculate isochrone/isodistance polygons showing how far you can travel from a point.",inputSchema:Nt,outputSchema:qt,execute:async(e,t)=>{const{origin:o,budgets:a,theme:r,showOnMap:i,showOriginPin:s=!0}=e;try{const e=await Tt(o);if(!e)return{status:"not_found"};const{position:n,name:l,query:c}=e,u=[...a].sort((e,t)=>t.value-e.value),d=await(async(e,t)=>{const o=await D(e.map(e=>({origin:t,budget:{type:e.type,value:e.value}})));return 0===o.features.length?null:o})(u,n);if(!d)return{status:"no_results"};const p=r??"outline",m=c?{query:c,position:n}:{position:n},h=t.ranges.addEntry({label:gt(u,l),origin:m,budgets:u,polygon:d});return await(async(e,t,o,a,r,i,s)=>{if(i&&(await(await e.ranges.getGeometriesModule(o)).show(t),t.bbox&&e.baseMap.mapLibreMap.fitBounds(t.bbox,{padding:50})),s){const t={type:"Feature",id:"range-origin",geometry:{type:"Point",coordinates:a},properties:{type:"Point Address",address:{freeformAddress:r}}};await(await e.ranges.getPlacesModule()).show(t)}})(t,d,p,n,l,i,s),{rangeId:h,originName:l,budgets:u}}catch(n){return{error:`Reachable area calculation failed: ${n instanceof Error?n.message:String(n)}`}}},tags:["reachable-range","isochrone","range","EV","coverage"],examples:['findReachableArea({ origin: { query: "Amsterdam", locationType: "default" }, budgets: [{ type: "timeMinutes", value: 30 }], showOnMap: true })','findReachableArea({ origin: { position: { lng: 4.9, lat: 52.3 } }, budgets: [{ type: "timeMinutes", value: 10 }, { type: "timeMinutes", value: 30 }], showOnMap: true, theme: "inverted" })','findReachableArea({ origin: { query: "my location", locationType: "default" }, budgets: [{ type: "distanceKM", value: 50 }], showOnMap: false })'],examplePrompts:["Show me where I can reach in 30 minutes from Amsterdam","What area is within 50 km of Berlin?","Show 10, 20, 30 minute drive zones from here"],relatedTools:["recallRanges","locatePlace"]},recallRanges:{description:"Retrieve a stored reachable range result from session history. Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. Step 2: call with id to retrieve origin and budgets. Does not call any service.",classificationPrompt:"Retrieve stored reachable range results from session history.",inputSchema:yo,outputSchema:vo,execute:async(e,t)=>{const{id:o}=e;if(!o)return{entries:[...t.ranges.entries].reverse().map(({id:e,label:t,timestamp:o})=>({id:e,label:t,timestamp:o}))};const a=t.ranges.entries.find(e=>e.id===o);return a?{id:a.id,label:a.label,timestamp:a.timestamp,origin:{...a.origin,position:a.origin.position},budgets:a.budgets}:{error:`No entry found with id "${o}"`}},tags:["recall","reachable-range","state"],examples:["recallRanges()",'recallRanges({ id: "ranges-0" })'],examplePrompts:["What range did I calculate earlier?","Recall the isochrone from Amsterdam"],relatedTools:["findReachableArea"]}},ba=ya,wa=Object.keys(ba),va=(e,t)=>{if(!e)return t;if(!t)return e;const o=new Set(t);return e.filter(e=>o.has(e))},Sa=e=>"object"==typeof e&&null!==e&&"reset"in e&&"function"==typeof e.reset,xa=(e,o)=>{if(!o.model)throw new Error("MapAgent requires a model option. Please provide an AI SDK LanguageModel instance.");const r=Z(e,o.state),{tools:i,toolsMetadata:s}=Pe(U(!1===o.includeDefaultTools?{}:ba,o.tools),r,{outputSchemas:o.outputSchemas}),n=!1===o.classifier?null:o.classifier??ut({model:o.model}),l=X(o.systemPrompt,o.systemPromptSuffix);let c=null;const u=new t({model:o.model,tools:i,instructions:l,stopWhen:a(o.maxSteps??10),prepareStep:async e=>{let t;if(0===e.stepNumber){if(c=null,n)try{c=await n({messages:e.messages,toolsMetadata:s})}catch{c=null}o.onClassify?.(c)}c&&(t=c.activeToolNames);const a=await(o.prepareStep?.(e));return a?{...a,activeTools:va(t,a.activeTools)}:t?{activeTools:t}:{}}});return Object.assign(u,{state:r,destroy:()=>(e=>{for(const t of Object.values(e))Sa(t)&&t.reset()})(r)})};export{Q as BASE_SYSTEM_PROMPT,ba as DEFAULT_TOOLS,wa as TOOL_NAMES,X as buildSystemPrompt,st as classifyUserIntent,ut as createDefaultClassifier,xa as createMapAgent,Z as createToolState,ct as extractLastUserText,U as resolveTools};
2
+ //# sourceMappingURL=index.es.js.map