@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.
- package/dist/index.d.ts +174 -3858
- package/dist/index.es.js +2 -0
- package/dist/index.es.js.map +1 -0
- package/package.json +2 -2
- package/dist/index.es.js.js +0 -2
- package/dist/index.es.js.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.es.js","names":[],"sources":["../src/resolve-tools.ts","../src/state.ts","../src/system-prompt.ts","../src/tools/utilities/calculate-bbox.ts","../src/tools/utilities/format-distance.ts","../src/tools/utilities/format-duration.ts","../src/tools/shared-output-schemas.ts","../src/tools/utilities/get-current-location.ts","../src/tools/utilities/get-route-progress.ts","../src/tools/utilities/get-section-bbox.ts","../src/tools/utilities/get-section-progress.ts","../src/tools/tool-tags.ts","../src/tools/utilities/help.ts","../src/tool-setup.ts","../src/tools/maplibre/execute-maplibre-code.ts","../src/tools/shared/location-input.ts","../src/tools/shared/resolve-poi-categories.ts","../src/tools/shared/schema.ts","../src/tools/shared/show-places-on-map.ts","../src/tools/shared/viewport-bias.ts","../src/tools/maplibre/fly-to.ts","../src/tools/maplibre/get-map-style-layers.ts","../src/tools/maplibre/get-viewport.ts","../src/tools/maplibre/set-layout-properties.ts","../src/tools/maplibre/set-paint-properties.ts","../src/tools/maplibre/set-pitch-bearing.ts","../src/tools/maplibre/zoom-in-or-out.ts","../src/utils/intent-classifier.ts","../src/utils/state-labels.ts","../src/utils/summarize.ts","../src/tools/services/locate-place.ts","../src/tools/services/resolve-location-input.ts","../src/tools/services/set-route-locations.ts","../src/tools/services/add-stop-to-route.ts","../src/tools/services/discover-places.ts","../src/tools/services/find-reachable-area.ts","../src/tools/services/geocode.ts","../src/tools/services/get-poi-category-codes.ts","../src/tools/services/get-traffic-area-analytics.ts","../src/tools/services/get-traffic-incidents.ts","../src/tools/services/query-traffic-analytics.ts","../src/tools/services/remove-stop-from-route.ts","../src/tools/services/reverse-geocode.ts","../src/tools/services/search-along-route.ts","../src/tools/services/set-route-parameters.ts","../src/tools/state/get-current-waypoints.ts","../src/tools/state/recall-places.ts","../src/tools/state/recall-ranges.ts","../src/tools/state/recall-routes.ts","../src/tools/tomtom-map/clear-map.ts","../src/tools/tomtom-map/fit-route-section.ts","../src/tools/tomtom-map/get-shown-incidents.ts","../src/tools/tomtom-map/get-shown-places.ts","../src/tools/tomtom-map/get-shown-route-sections.ts","../src/tools/tomtom-map/get-shown-route-traffic-incidents.ts","../src/tools/tomtom-map/get-shown-routes.ts","../src/tools/tomtom-map/get-shown-waypoints.ts","../src/tools/tomtom-map/get-standard-map-styles.ts","../src/tools/tomtom-map/manage-places.ts","../src/tools/tomtom-map/set-language.ts","../src/tools/tomtom-map/set-map-standard-style.ts","../src/tools/tomtom-map/set-route-theme.ts","../src/tools/tomtom-map/show-places.ts","../src/tools/tomtom-map/show-routes.ts","../src/tools/tomtom-map/show-traffic-area-analytics.ts","../src/tools/tomtom-map/show-waypoints.ts","../src/tools/tomtom-map/toggle-base-map-layer-groups.ts","../src/tools/tomtom-map/toggle-pois.ts","../src/tools/tomtom-map/toggle-traffic.ts","../src/tools/tool-registry.ts","../src/create-map-agent.ts"],"sourcesContent":["import type { ToolEntry, ToolNameHint, ToolState } from './types';\n\n/**\n * Merges default tools with user overrides.\n *\n * - `ToolEntry` values add or replace tools in `defaults`.\n * - `false` values remove tools from `defaults`.\n * - Returns a new object — `defaults` is never mutated.\n *\n * @param defaults - Base tool record (typically DEFAULT_TOOLS or empty).\n * @param overrides - User-provided additions, replacements, and exclusions.\n * @returns Resolved tool record ready for setupTools.\n *\n * @group Agent Toolkit\n */\nexport const resolveTools = <S extends ToolState>(\n defaults: Record<string, ToolEntry<S>>,\n overrides?: { [K in ToolNameHint]?: ToolEntry<S> | false | undefined },\n): Record<string, ToolEntry<S>> => {\n const result = { ...defaults };\n\n if (!overrides) return result;\n\n for (const [name, entry] of Object.entries(overrides)) {\n if (entry) {\n result[name] = entry;\n } else {\n delete result[name];\n }\n }\n\n return result;\n};\n","/**\n * @module agent-toolkit-state\n */\n\nimport type { Place, Places, Routes, TrafficAreaAnalytics, WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport { TomTomConfig } from '@tomtom-org/maps-sdk/core';\nimport {\n BaseMapModule,\n GeometriesModule,\n type GeometryTheme,\n HillshadeModule,\n PlacesModule,\n PlanningWaypoint,\n POIsModule,\n RoutingModule,\n reachableRangeGeometryConfig,\n type TomTomMap,\n type TrafficAreaAnalyticsConfig,\n TrafficAreaAnalyticsModule,\n TrafficFlowModule,\n TrafficIncidentsModule,\n} from '@tomtom-org/maps-sdk/map';\nimport { Map } from 'maplibre-gl';\nimport type { ToolState } from './types';\nimport type { PlacesEntry, RangeEntry, RouteParams, RoutesEntry, StateSlice } from './types/state';\n\nTomTomConfig.instance.put({ language: 'en-GB' });\n\n/**\n * State for place search, geocoding, and geometries.\n *\n * Holds lazy-initialized PlacesModule and GeometriesModule alongside an\n * append-only history of place and search results produced during the session.\n *\n * @group Agent Toolkit\n */\nexport class PlacesState implements StateSlice {\n private _placesModule?: PlacesModule;\n\n private _entries: PlacesEntry[] = [];\n\n /** IDs of entries currently rendered on the map. */\n private _shownEntryIds: Set<PlacesEntry['id']> = new Set();\n\n constructor(private readonly _ttMap: TomTomMap) {}\n\n // Module getters (lazy initialization)\n\n async getPlacesModule(): Promise<PlacesModule> {\n this._placesModule ??= await PlacesModule.get(this._ttMap);\n return this._placesModule;\n }\n\n // Cached module access (for reading without triggering initialization)\n\n get placesModule(): PlacesModule | undefined {\n return this._placesModule;\n }\n\n // History\n\n get entries(): readonly PlacesEntry[] {\n return this._entries;\n }\n\n /**\n * This is used purely to pass data between tools in a context-dependent way,\n * so we assume the most recent entry is the relevant one to show on the map.\n */\n get latestPlace(): Place[] | undefined {\n return this._entries.at(-1)?.data;\n }\n\n addPlaceResult(place: Place | Places, label: string): string {\n const id = `places-${this._entries.length}`;\n this._entries.push({\n id,\n timestamp: Date.now(),\n label,\n data: 'features' in place ? place.features : [place],\n });\n return id;\n }\n\n /** IDs of entries currently shown on the map. */\n get shownEntryIds(): ReadonlySet<PlacesEntry['id']> {\n return this._shownEntryIds;\n }\n\n /** Return the union of all features belonging to currently-shown entries. */\n getShownFeatures(): Place[] {\n const out: Place[] = [];\n for (const entry of this._entries) {\n if (this._shownEntryIds.has(entry.id)) {\n out.push(...entry.data);\n }\n }\n return out;\n }\n\n /** Replace the shown set with exactly these ids and re-render. */\n async setShownEntries(ids: readonly PlacesEntry['id'][]): Promise<Place[]> {\n const entryIds = new Set(this._entries.map((entry) => entry.id));\n this._shownEntryIds = new Set(ids.filter((id) => entryIds.has(id)));\n return this._renderShown();\n }\n\n /** Add ids to the shown set and re-render. */\n async addShownEntries(ids: readonly PlacesEntry['id'][]): Promise<Place[]> {\n const entryIds = new Set(this._entries.map((entry) => entry.id));\n let changed = false;\n for (const id of ids) {\n if (entryIds.has(id) && !this._shownEntryIds.has(id)) {\n this._shownEntryIds.add(id);\n changed = true;\n }\n }\n return changed ? this._renderShown() : this.getShownFeatures();\n }\n\n /** Remove ids from the shown set and re-render. */\n async removeShownEntries(ids: readonly PlacesEntry['id'][]): Promise<Place[]> {\n let changed = false;\n for (const id of ids) {\n if (this._shownEntryIds.delete(id)) changed = true;\n }\n return changed ? this._renderShown() : this.getShownFeatures();\n }\n\n /** Clear everything from the map (does not touch entries history). */\n async clearShownEntries(): Promise<void> {\n if (this._shownEntryIds.size === 0) return;\n this._shownEntryIds.clear();\n const placesModule = await this.getPlacesModule();\n await placesModule.clear();\n }\n\n private async _renderShown(): Promise<Place[]> {\n const features = this.getShownFeatures();\n const placesModule = await this.getPlacesModule();\n await placesModule.show({ type: 'FeatureCollection', features } as Places);\n return features;\n }\n\n reset(): void {\n this._placesModule = undefined;\n this._entries = [];\n this._shownEntryIds.clear();\n }\n}\n\n/**\n * State for the map POI layer (points of interest overlay).\n *\n * Holds the lazy-initialized POIsModule for showing, hiding, and filtering\n * the built-in POI categories rendered on the base map.\n *\n * @group Agent Toolkit\n */\nexport class MapPOIsState implements StateSlice {\n private _poisModule?: POIsModule;\n\n constructor(private readonly _ttMap: TomTomMap) {}\n\n // Module getter (lazy initialization)\n\n async getPOIsModule(): Promise<POIsModule> {\n this._poisModule ??= await POIsModule.get(this._ttMap);\n return this._poisModule;\n }\n\n // Cached module access (for reading without triggering initialization)\n\n get poisModule(): POIsModule | undefined {\n return this._poisModule;\n }\n\n reset(): void {\n this._poisModule = undefined;\n }\n}\n\n/**\n * State for route calculation, waypoint management, and route planning parameters.\n *\n * Holds the lazy-initialized RoutingModule alongside an append-only history of\n * calculated routes, sparse planning slots (being assembled before a calculation),\n * and current route parameters.\n *\n * @group Agent Toolkit\n */\nexport class RoutingState implements StateSlice {\n private _routingModule?: RoutingModule;\n private _entries: RoutesEntry[] = [];\n private _planningSlots: PlanningWaypoint[] = [];\n private _params: RouteParams = {};\n\n constructor(private readonly _ttMap: TomTomMap) {}\n\n async getRoutingModule(): Promise<RoutingModule> {\n this._routingModule ??= await RoutingModule.get(this._ttMap);\n return this._routingModule;\n }\n\n get routingModule(): RoutingModule | undefined {\n return this._routingModule;\n }\n\n // History\n\n get entries(): readonly RoutesEntry[] {\n return this._entries;\n }\n\n get currentRoutes(): Routes | undefined {\n return this._entries.at(-1)?.data;\n }\n\n get currentWaypoints(): WaypointLike[] | undefined {\n return this._entries.at(-1)?.waypoints;\n }\n\n /** Sparse nullable slots being assembled before triggering a route calculation. */\n get planningSlots(): PlanningWaypoint[] {\n return this._planningSlots;\n }\n\n get params(): RouteParams {\n return this._params;\n }\n\n addRoutes(routes: Routes, waypoints: WaypointLike[], label: string): void {\n this._entries.push({\n id: `routes-${this._entries.length}`,\n timestamp: Date.now(),\n label,\n data: routes,\n waypoints,\n params: { ...this._params },\n });\n this._planningSlots = [...waypoints];\n }\n\n setWaypointAt(index: number, waypoint: WaypointLike): void {\n const minSize = Math.max(2, index + 1);\n while (this._planningSlots.length < minSize) {\n this._planningSlots.push(null);\n }\n this._planningSlots[index] = waypoint;\n }\n\n setParams(params: Partial<RouteParams>): void {\n this._params = { ...this._params, ...params };\n }\n\n reset(): void {\n this._routingModule = undefined;\n this._entries = [];\n this._planningSlots = [];\n this._params = {};\n }\n}\n\n/**\n * State for base map display: style, language, viewport, layers, and hillshade.\n *\n * Provides direct access to the TomTomMap and MapLibre instances alongside\n * lazy-initialized BaseMapModule and HillshadeModule.\n *\n * @group Agent Toolkit\n */\nexport class BaseMapState implements StateSlice {\n private _baseMapModule?: BaseMapModule;\n private _hillshadeModule?: HillshadeModule;\n\n constructor(public readonly ttMap: TomTomMap) {}\n\n get mapLibreMap(): Map {\n return this.ttMap.mapLibreMap;\n }\n\n // Module getters (lazy initialization)\n\n async getBaseMapModule(): Promise<BaseMapModule> {\n this._baseMapModule ??= await BaseMapModule.get(this.ttMap);\n return this._baseMapModule;\n }\n\n async getHillshadeModule(): Promise<HillshadeModule> {\n this._hillshadeModule ??= await HillshadeModule.get(this.ttMap);\n return this._hillshadeModule;\n }\n\n reset(): void {\n this._baseMapModule = undefined;\n this._hillshadeModule = undefined;\n }\n}\n\n/**\n * State for traffic: flow layer, incident overlay, and area analytics modules.\n *\n * @group Agent Toolkit\n */\nexport class TrafficState implements StateSlice {\n private _trafficFlowModule?: TrafficFlowModule;\n private _trafficIncidentsModule?: TrafficIncidentsModule;\n private _trafficAreaAnalyticsModule?: TrafficAreaAnalyticsModule;\n private _lastAreaAnalytics?: TrafficAreaAnalytics;\n private _currentAnalyticsConfig?: TrafficAreaAnalyticsConfig;\n private _configChangeUnsub?: () => void;\n\n constructor(private readonly _ttMap: TomTomMap) {}\n\n // Module getters (lazy initialization)\n\n async getTrafficFlowModule(): Promise<TrafficFlowModule> {\n this._trafficFlowModule ??= await TrafficFlowModule.get(this._ttMap);\n return this._trafficFlowModule;\n }\n\n async getTrafficIncidentsModule(): Promise<TrafficIncidentsModule> {\n this._trafficIncidentsModule ??= await TrafficIncidentsModule.get(this._ttMap);\n return this._trafficIncidentsModule;\n }\n\n async getTrafficAreaAnalyticsModule(): Promise<TrafficAreaAnalyticsModule> {\n if (!this._trafficAreaAnalyticsModule) {\n this._trafficAreaAnalyticsModule = await TrafficAreaAnalyticsModule.get(this._ttMap);\n // Wire config change events so agent state stays in sync with module\n this._configChangeUnsub = this._trafficAreaAnalyticsModule.events.on('config-change', (config) => {\n this._currentAnalyticsConfig = config;\n });\n }\n return this._trafficAreaAnalyticsModule;\n }\n\n // Cached module access (for reading without triggering initialization)\n\n get trafficAreaAnalyticsModule(): TrafficAreaAnalyticsModule | undefined {\n return this._trafficAreaAnalyticsModule;\n }\n\n // Area analytics result caching\n\n get lastAreaAnalytics(): TrafficAreaAnalytics | undefined {\n return this._lastAreaAnalytics;\n }\n\n setLastAreaAnalytics(result: TrafficAreaAnalytics): void {\n this._lastAreaAnalytics = result;\n }\n\n /** Current visualization config, updated by module configChange events. */\n get currentAnalyticsConfig(): TrafficAreaAnalyticsConfig | undefined {\n return this._currentAnalyticsConfig;\n }\n\n // Optional hooks for the host application to show/hide its own analytics UI.\n // The plugin does not manage any UI panel — wire these up in the consuming app.\n onAnalyticsShown?: (analytics: TrafficAreaAnalytics, module: TrafficAreaAnalyticsModule) => void;\n onAnalyticsCleared?: () => void;\n\n reset(): void {\n this._configChangeUnsub?.();\n this.onAnalyticsCleared?.();\n this._trafficFlowModule = undefined;\n this._trafficIncidentsModule = undefined;\n this._trafficAreaAnalyticsModule = undefined;\n this._lastAreaAnalytics = undefined;\n this._currentAnalyticsConfig = undefined;\n this._configChangeUnsub = undefined;\n }\n}\n\n/**\n * State for reachable range results.\n *\n * Stores semantic summaries of calculated ranges (origin, budgets).\n * Also retains raw polygon geometry internally for use in geometry searches\n * (e.g. discoverPlaces withinRange). Displayed on the map via GeometriesModule.\n *\n * @group Agent Toolkit\n */\nexport class RangeState implements StateSlice {\n private _entries: RangeEntry[] = [];\n private _placesModule?: PlacesModule;\n private _geometriesModule?: GeometriesModule;\n private _currentTheme?: GeometryTheme;\n\n constructor(private readonly _ttMap: TomTomMap) {}\n\n async getPlacesModule(): Promise<PlacesModule> {\n this._placesModule ??= await PlacesModule.get(this._ttMap);\n return this._placesModule;\n }\n\n async getGeometriesModule(theme: GeometryTheme): Promise<GeometriesModule> {\n if (!this._geometriesModule) {\n this._geometriesModule = await GeometriesModule.get(\n this._ttMap,\n reachableRangeGeometryConfig(undefined, theme),\n );\n this._currentTheme = theme;\n } else if (this._currentTheme !== theme) {\n this._geometriesModule.applyConfig(reachableRangeGeometryConfig(undefined, theme));\n this._currentTheme = theme;\n }\n return this._geometriesModule;\n }\n\n get geometriesModule(): GeometriesModule | undefined {\n return this._geometriesModule;\n }\n\n get entries(): readonly RangeEntry[] {\n return this._entries;\n }\n\n get latestEntry(): RangeEntry | undefined {\n return this._entries.at(-1);\n }\n\n addEntry(entry: Omit<RangeEntry, 'id' | 'timestamp'>): string {\n const id = `ranges-${this._entries.length}`;\n this._entries.push({\n id,\n timestamp: Date.now(),\n ...entry,\n });\n return id;\n }\n\n reset(): void {\n this._entries = [];\n this._geometriesModule = undefined;\n this._currentTheme = undefined;\n }\n}\n\n/**\n * Factory that creates a fully initialized ToolState from a TomTomMap instance.\n * Optionally merges custom state slices alongside built-in state.\n *\n * @param map - TomTomMap instance for module initialization\n * @param customSlices - Additional state slices accessible by custom tools\n *\n * @group Agent Toolkit\n */\nexport const createToolState = <T extends Record<string, unknown> = Record<string, never>>(\n map: TomTomMap,\n customSlices?: T,\n): ToolState & T => {\n const base: ToolState = {\n places: new PlacesState(map),\n mapPOIs: new MapPOIsState(map),\n routing: new RoutingState(map),\n baseMap: new BaseMapState(map),\n traffic: new TrafficState(map),\n ranges: new RangeState(map),\n };\n if (customSlices) {\n Object.assign(base, customSlices);\n }\n return base as ToolState & T;\n};\n","/**\n * @module agent-toolkit-system-prompt\n */\n\n/**\n * The base system prompt that teaches the LLM how to use the agent toolkit tools.\n *\n * @remarks\n * Export this constant so consumers can reference or extend it when providing\n * a custom system prompt via `MapAgentOptions.systemPrompt`.\n *\n * @example\n * ```typescript\n * import { createMapAgent, BASE_SYSTEM_PROMPT } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';\n *\n * const agent = createMapAgent(map, {\n * model: openai('gpt-4o'),\n * systemPrompt: BASE_SYSTEM_PROMPT + '\\n\\nAlways respond in Spanish.'\n * });\n * ```\n *\n * @group Agent Toolkit\n */\nexport const BASE_SYSTEM_PROMPT = `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`;\n\n/**\n * Builds the complete system prompt for the agent toolkit.\n *\n * @param customPrompt - Optional complete prompt that replaces the base prompt\n * @param suffix - Optional additional prompt text to append to base prompt (ignored if customPrompt provided)\n * @returns Complete system prompt string\n *\n * @internal\n * @ignore\n */\nexport const buildSystemPrompt = (customPrompt?: string, suffix?: string): string => {\n if (customPrompt) {\n return customPrompt;\n }\n if (suffix) {\n return `${BASE_SYSTEM_PROMPT}\\n\\nADDITIONAL INSTRUCTIONS:\\n${suffix}`;\n }\n return BASE_SYSTEM_PROMPT;\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\n\n/**\n * Tool schema for calculating a bounding box from GeoJSON.\n */\nexport const calculateBBoxSchema = z.object({\n geoJson: z\n .union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))])\n .describe('GeoJSON object or array of GeoJSON objects'),\n});\n\nexport const calculateBBoxDescription =\n 'Calculate a [minLng, minLat, maxLng, maxLat] bbox from GeoJSON. Context-independent. ' +\n 'Returns bounding box as [minLng, minLat, maxLng, maxLat] — longitude before latitude.';\n\n/** Execute function for calculateBBox — usable with ToolEntry format. */\nexport const executeCalculateBBox = async (params: z.infer<typeof calculateBBoxSchema>, _state: ToolState) => {\n const { geoJson } = params;\n try {\n const bbox = bboxFromGeoJSON(geoJson as any);\n\n if (!bbox) {\n return { error: 'Could not calculate bounding box - input may be empty or invalid GeoJSON' };\n }\n\n return {\n bbox,\n minLng: bbox[0],\n minLat: bbox[1],\n maxLng: bbox[2],\n maxLat: bbox[3],\n };\n } catch (error) {\n return {\n error: `Failed to calculate bbox: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { formatDistance } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\n\n/**\n * Tool schema for formatting distance.\n */\nexport const formatDistanceSchema = z.object({\n meters: z.number().describe('Distance in meters to format'),\n unitType: z.enum(['metric', 'imperial_us', 'imperial_uk']).optional().describe('default: metric'),\n});\n\nexport const formatDistanceDescription =\n 'Format a distance in meters into a human-readable string (e.g. \"2.5 km\", \"1.5 mi\"). ' +\n 'Use after getSectionProgress, recallRoutes, or any tool that returns distances in meters.';\n\n/** Execute function for formatDistance — usable with ToolEntry format. */\nexport const executeFormatDistance = async (params: z.infer<typeof formatDistanceSchema>, _state: ToolState) => {\n const { meters, unitType } = params;\n try {\n const formatted = formatDistance(meters, unitType ? { type: unitType } : undefined);\n return {\n formatted,\n input: {\n meters,\n unitType: unitType ?? 'metric',\n },\n };\n } catch (error) {\n return {\n error: `Failed to format distance: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { formatDuration } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\n\n/**\n * Tool schema for formatting duration.\n */\nexport const formatDurationSchema = z.object({\n seconds: z.number().describe('Duration in seconds to format'),\n});\n\nexport const formatDurationDescription =\n 'Format a duration in seconds into a human-readable time string (e.g. \"1 h 30 min\"). ' +\n 'Use after getSectionProgress, recallRoutes, or any tool that returns durations in seconds.';\n\n/** Execute function for formatDuration — usable with ToolEntry format. */\nexport const executeFormatDuration = async (params: z.infer<typeof formatDurationSchema>, _state: ToolState) => {\n const { seconds } = params;\n try {\n const formatted = formatDuration(seconds);\n\n if (formatted === undefined) {\n return {\n formatted: undefined,\n message: '< 1 min',\n input: { seconds },\n };\n }\n\n return {\n formatted,\n input: { seconds },\n };\n } catch (error) {\n return {\n error: `Failed to format duration: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n *\n * Shared output schema building blocks reused across multiple tools.\n * Tool-specific output schemas live next to their respective tool definitions.\n */\n\nimport { z } from 'zod';\n\n// ---------------------------------------------------------------------------\n// Common\n// ---------------------------------------------------------------------------\n\n/** Returned by every tool when execution fails. */\nexport const toolErrorSchema = z.object({\n error: z.string(),\n});\n\n// ---------------------------------------------------------------------------\n// Place (compact summary) — used by geocode, reverse-geocode, search, etc.\n// ---------------------------------------------------------------------------\n\n/** Token-efficient summary of a single place. */\nexport const placeOutputSchema = z\n .object({\n name: z.string().optional().describe('POI name if available'),\n address: z.string().optional().describe('Human-readable address'),\n position: z.array(z.number()).length(2).describe('[longitude, latitude]'),\n })\n .describe('Compact place summary');\n\n/** Token-efficient summary of a places collection. */\nexport const placesOutputSchema = z\n .object({\n count: z.number(),\n features: z.array(placeOutputSchema),\n })\n .describe('Compact places summary');\n\n// ---------------------------------------------------------------------------\n// Route (summarized — geometry, progress, and guidance stripped)\n// ---------------------------------------------------------------------------\n\nconst summarySchema = z.object({\n travelTimeInSeconds: z.number(),\n lengthInMeters: z.number(),\n trafficDelayInSeconds: z.number().optional(),\n trafficLengthInMeters: z.number().optional(),\n departureTime: z.string().optional(),\n arrivalTime: z.string().optional(),\n noTrafficTravelTimeInSeconds: z.number().optional(),\n historicTrafficTravelTimeInSeconds: z.number().optional(),\n liveTrafficIncidentsTravelTimeInSeconds: z.number().optional(),\n});\n\n/**\n * A single summarized route — just the route summary and optional per-leg summaries.\n */\nexport const summarizedRouteSchema = z.object({\n index: z.number().describe('0=best, 1+=alternative'),\n summary: summarySchema,\n legSummaries: z.array(summarySchema).optional().describe('Present when route has multiple legs'),\n});\n\n/** Summary of one or more calculated routes (coordinates stripped). */\nexport const routesOutputSchema = z.object({\n count: z.number(),\n routes: z.array(summarizedRouteSchema),\n});\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/**\n * Tool schema for retrieving browser current location.\n */\nexport const getCurrentLocationSchema = z.object({});\n\n/**\n * Output schema for current location tool.\n */\nexport const getCurrentLocationOutputSchema = z.union([\n z.object({\n position: z.array(z.number()).min(2).max(2).describe('[longitude, latitude]'),\n accuracy: z.number().describe('Accuracy of the location in meters'),\n timestamp: z.number().describe('Timestamp of the location data'),\n }),\n toolErrorSchema,\n]);\n\nconst getLocationErrorMessage = (error: unknown): string | undefined => {\n if (typeof error !== 'object' || error === null || !('code' in error)) {\n return undefined;\n }\n\n const code = (error as { code: number }).code;\n\n if (code === 1) {\n return 'Location permission denied by the user';\n }\n\n if (code === 2) {\n return 'Current location is unavailable';\n }\n\n if (code === 3) {\n return 'Timed out while trying to get current location';\n }\n\n return undefined;\n};\n\nexport const getCurrentLocationDescription =\n \"Get the user's physical location from the browser geolocation API. \" +\n 'Use for queries referencing the user\\'s body: \"near me\", \"where I am\", \"my location\", \"nearby\". ' +\n 'May prompt the user for location permission. ' +\n 'Does NOT return the map viewport center — use getViewport for map-based reference. ' +\n 'Returns: position [longitude, latitude].';\n\n/** Execute function for getCurrentLocation — usable with ToolEntry format. */\nexport const executeGetCurrentLocation = async (\n _params: z.infer<typeof getCurrentLocationSchema>,\n _state: ToolState,\n): Promise<z.infer<typeof getCurrentLocationOutputSchema>> => {\n if (globalThis.window === undefined || globalThis.navigator === undefined) {\n return { error: 'Current location is only available in a browser environment' };\n }\n\n if (!('geolocation' in globalThis.navigator)) {\n return { error: 'Geolocation is not supported by this browser' };\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n globalThis.navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 15000,\n maximumAge: 0,\n });\n });\n\n return {\n position: [position.coords.longitude, position.coords.latitude],\n accuracy: position.coords.accuracy,\n timestamp: position.timestamp,\n };\n } catch (error) {\n const locationErrorMessage = getLocationErrorMessage(error);\n if (locationErrorMessage) {\n return { error: locationErrorMessage };\n }\n\n return {\n error: `Failed to get current location: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport {\n getCoordinateAtRouteProgress,\n type RouteCoordinateAtProgress,\n type RouteProgressQuery,\n} from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\n\nconst routeIndexField = z.number().int().min(0).optional().describe('default: 0');\n\n/**\n * Tool schema for getting a coordinate position along a route.\n * The three progress inputs are mutually exclusive — provide exactly one.\n */\nexport const getRouteProgressSchema = z\n .object({\n routeIndex: routeIndexField,\n traveledTimeInSeconds: z.number().min(0).optional().describe('seconds from start'),\n traveledDistanceInMeters: z.number().min(0).optional().describe('meters from start'),\n clockTime: z.string().optional().describe('ISO 8601; elapsed time derived from departure time'),\n })\n .refine(\n ({ traveledTimeInSeconds, traveledDistanceInMeters, clockTime }) =>\n [traveledTimeInSeconds, traveledDistanceInMeters, clockTime].filter((v) => v !== undefined).length === 1,\n { message: 'Provide exactly one of: traveledTimeInSeconds, traveledDistanceInMeters, or clockTime.' },\n );\n\n/**\n * Maps the tool params to a {@link RouteProgressQuery} for the core utility.\n * Returns an error string when the clockTime string is invalid.\n */\nconst toRouteProgressQuery = (\n params: z.infer<typeof getRouteProgressSchema>,\n): RouteProgressQuery | { error: string } => {\n if (params.traveledTimeInSeconds !== undefined) {\n return { traveledTimeInSeconds: params.traveledTimeInSeconds };\n }\n\n if (params.traveledDistanceInMeters !== undefined) {\n return { traveledDistanceInMeters: params.traveledDistanceInMeters };\n }\n\n const clockTimeMs = new Date(params.clockTime as string).getTime();\n if (Number.isNaN(clockTimeMs)) {\n return { error: `Invalid clockTime value: \"${params.clockTime}\". Use ISO 8601 format.` };\n }\n\n return { clockTime: new Date(params.clockTime as string) };\n};\n\nexport const getRouteProgressDescription =\n '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).';\n\n/** Execute function for getRouteProgress — usable with ToolEntry format. */\nexport const executeGetRouteProgress = async (params: z.infer<typeof getRouteProgressSchema>, state: ToolState) => {\n const routeIndex = params.routeIndex ?? 0;\n\n try {\n const lastRoutes = (await state.routing.getRoutingModule()).getShown().mainLines;\n if (!lastRoutes || lastRoutes.features.length === 0) {\n return { error: 'No routes available. Use calculate-route first.' };\n }\n\n const route = lastRoutes.features[routeIndex];\n if (!route) {\n return {\n error: `Route index ${routeIndex} is out of range. There are ${lastRoutes.features.length} route(s) available.`,\n };\n }\n\n if (!route.properties.progress || route.properties.progress.length === 0) {\n return {\n error: 'The route does not contain progress data. Re-calculate the route to ensure progress data is included.',\n };\n }\n\n const query = toRouteProgressQuery(params);\n if ('error' in query) return query;\n\n const result: RouteCoordinateAtProgress | undefined = getCoordinateAtRouteProgress(route, query);\n\n if (result === undefined) {\n return {\n error: 'Could not interpolate a position. The progress data may be incomplete or the requested value is out of range.',\n };\n }\n\n return {\n longitude: result.position[0],\n latitude: result.position[1],\n travelTimeInSeconds: Math.round(result.travelTimeInSeconds),\n distanceInMeters: Math.round(result.distanceInMeters),\n };\n } catch (error) {\n return {\n error: `Failed to get route progress: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { getSectionBBox, type SectionProps, type SectionType, sectionTypes } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-section-bbox tool. */\nexport const getSectionBBoxOutputSchema = z.union([\n z.object({\n bbox: z.array(z.number()).describe('GeoJSON bbox [minLng, minLat, maxLng, maxLat]'),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for the get-section-bbox tool. */\nexport const getSectionBBoxSchema = z.object({\n sectionType: z.enum(sectionTypes as [SectionType, ...SectionType[]]).describe('e.g. country|traffic|motorway|toll'),\n id: z.string().describe('Section ID from getShownRouteSections or getSectionProgress'),\n});\n\nexport const getSectionBBoxDescription =\n '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.';\n\n/** Execute function for getSectionBBox — usable with ToolEntry format. */\nexport const executeGetSectionBBox = async (\n params: z.infer<typeof getSectionBBoxSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getSectionBBoxOutputSchema>> => {\n const { sectionType, id } = params;\n try {\n const lastRoutes = state.routing.currentRoutes;\n\n if (!lastRoutes || lastRoutes.features.length === 0) {\n return { error: 'No routes available. Use calculate-route first.' };\n }\n\n for (const route of lastRoutes.features) {\n const sections = route.properties.sections[sectionType as SectionType];\n if (!sections || !Array.isArray(sections)) continue;\n\n const section = sections.find((s) => s.id === id);\n if (section && typeof section.startPointIndex === 'number' && typeof section.endPointIndex === 'number') {\n const bbox = getSectionBBox(route, section as SectionProps);\n\n if (!bbox) {\n return {\n error: 'Could not calculate bounding box for the section. The section may have invalid indices.',\n };\n }\n\n return { bbox };\n }\n }\n\n return {\n error: `Could not find a section with type \"${sectionType}\" and id \"${id}\" in the last calculated routes.`,\n };\n } catch (error) {\n return {\n error: `Failed to get section bbox: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport {\n getRouteProgressForSection,\n type SectionProps,\n type SectionType,\n sectionTypes,\n} from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\n\n/**\n * Tool schema for getting section progress.\n */\nexport const getSectionProgressSchema = z.object({\n sectionType: z.enum(sectionTypes as [SectionType, ...SectionType[]]).describe('e.g. country|traffic|motorway|toll'),\n ids: z\n .array(z.string())\n .optional()\n .describe('Section IDs to query. If omitted, all sections of the given sectionType are returned.'),\n});\n\nexport const getSectionProgressDescription =\n '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.';\n\n/** Execute function for getSectionProgress — usable with ToolEntry format. */\nexport const executeGetSectionProgress = async (params: z.infer<typeof getSectionProgressSchema>, state: ToolState) => {\n const { sectionType, ids } = params;\n\n try {\n const lastRoutes = state.routing.currentRoutes;\n\n if (!lastRoutes || lastRoutes.features.length === 0) {\n return { error: 'No routes available. Use calculate-route first.' };\n }\n\n const results: object[] = [];\n\n for (const route of lastRoutes.features) {\n const sections = route.properties.sections[sectionType as SectionType];\n if (!sections) continue;\n\n for (const section of sections) {\n if (ids && ids.length > 0 && !ids.includes(section.id)) continue;\n\n const progress = getRouteProgressForSection(route, section as SectionProps);\n\n if (!progress) {\n results.push({\n sectionId: section.id,\n error: 'Could not calculate progress for this section. The route may be missing progress data.',\n });\n continue;\n }\n\n results.push({\n sectionId: section.id,\n startPointIndex: section.startPointIndex,\n endPointIndex: section.endPointIndex,\n start: progress.start,\n end: progress.end,\n delta: progress.delta,\n });\n }\n }\n\n if (ids && ids.length > 0) {\n const foundIds = new Set(results.map((r) => (r as { sectionId: string }).sectionId));\n for (const id of ids) {\n if (!foundIds.has(id)) {\n results.push({\n sectionId: id,\n error: `Could not find a section with type \"${sectionType}\" and id \"${id}\" in the last calculated routes.`,\n });\n }\n }\n }\n\n if (results.length === 0) {\n return { error: `No sections of type \"${sectionType}\" found in the last calculated routes.` };\n }\n\n return { sectionType, sections: results };\n } catch (error) {\n return {\n error: `Failed to get section progress: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\n/**\n * All valid tool tags for categorizing tools.\n *\n * @ignore\n */\nexport const TOOL_TAGS = [\n 'location',\n 'route',\n 'waypoint',\n 'place',\n 'locate',\n 'discover',\n 'traffic',\n 'map style',\n 'utilities',\n 'search',\n 'detour',\n 'along-route',\n 'reachable-range',\n 'isochrone',\n 'range',\n 'EV',\n 'coverage',\n 'recall',\n 'state',\n // Route section types (from SDK sectionTypes)\n 'carpool',\n 'carTrain',\n 'country',\n 'ferry',\n 'importantRoadStretch',\n 'lanes',\n 'leg',\n 'lowEmissionZone',\n 'motorway',\n 'pedestrian',\n 'roadShields',\n 'speedLimit',\n 'toll',\n 'tollVignette',\n 'tunnel',\n 'unpaved',\n 'urban',\n 'vehicleRestricted',\n] as const;\n\n/**\n * Union of all valid tool tags, derived from {@link TOOL_TAGS}.\n *\n * @ignore\n */\nexport type ToolTag = (typeof TOOL_TAGS)[number];\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { type Tool, tool } from 'ai';\nimport { z } from 'zod';\nimport type { ToolMetadata } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\nimport { TOOL_TAGS, type ToolTag } from '../tool-tags';\n\nconst detailToolSchema = z.object({\n name: z.string(),\n description: z.string(),\n examplePrompts: z.array(z.string()),\n relatedTools: z.array(z.string()).optional(),\n});\n\nexport const helpOutputSchema = z.union([\n z.object({\n mode: z.literal('summary'),\n examplePrompts: z.array(z.string()),\n }),\n z.object({\n mode: z.literal('detail'),\n query: z.string().optional(),\n tag: z.enum(TOOL_TAGS).optional(),\n matchedTools: z.array(detailToolSchema),\n totalMatched: z.number(),\n }),\n toolErrorSchema,\n]);\n\nexport const helpSchema = z.object({\n mode: z\n .enum(['summary', 'detail'])\n .describe(\n '\"summary\": overview of all capabilities with example prompts mixed from all tools. ' +\n '\"detail\": searchable full tool info — use when you need to find a specific tool.',\n ),\n query: z\n .string()\n .optional()\n .describe('Detail mode only. Case-insensitive keyword search across tool names, descriptions, and tags.'),\n tag: z.enum(TOOL_TAGS).optional().describe('Detail mode only. Filter results to tools with a specific tag.'),\n});\n\nexport const helpDescription =\n 'Discover what this agent can do. Returns all capability example prompts mixed together (summary mode) ' +\n 'or searchable per-tool details with descriptions and examples (detail mode). ' +\n 'Call this when the user asks what you can do, or when you need to find the right tool for a task.';\n\n/**\n * Create the help tool.\n *\n * @param getToolsMetadata - Lazy getter for resolved tool metadata.\n * Called at execution time, not at creation time, so metadata can be\n * populated after all tools are set up.\n */\nexport const createHelpTool = (getToolsMetadata: () => Record<string, ToolMetadata>): Tool => {\n return tool({\n description: helpDescription,\n inputSchema: helpSchema,\n outputSchema: helpOutputSchema,\n execute: async (params): Promise<z.infer<typeof helpOutputSchema>> => {\n const { mode, query, tag } = params;\n\n try {\n const allTools = Object.values(getToolsMetadata());\n\n if (mode === 'summary') {\n const examplePrompts = allTools.flatMap((toolMetadata) => toolMetadata.examplePrompts ?? []);\n return { mode: 'summary', examplePrompts };\n }\n\n // detail mode\n let tools = allTools;\n\n if (tag) {\n tools = tools.filter(\n (toolMetadata) => (toolMetadata.tags as readonly ToolTag[] | undefined)?.includes(tag) ?? false,\n );\n }\n\n if (query) {\n const lowerQuery = query.toLowerCase();\n tools = tools.filter(\n (toolMetadata) =>\n toolMetadata.name.toLowerCase().includes(lowerQuery) ||\n toolMetadata.description.toLowerCase().includes(lowerQuery) ||\n (toolMetadata.tags ?? []).some((toolTag) => toolTag.toLowerCase().includes(lowerQuery)) ||\n (toolMetadata.examplePrompts ?? []).some((prompt) =>\n prompt.toLowerCase().includes(lowerQuery),\n ),\n );\n }\n\n return {\n mode: 'detail',\n query,\n tag,\n matchedTools: tools.map((toolMetadata) => ({\n name: toolMetadata.name,\n description: toolMetadata.description,\n examplePrompts: toolMetadata.examplePrompts ?? [],\n relatedTools: toolMetadata.relatedTools ?? [],\n })),\n totalMatched: tools.length,\n };\n } catch (error) {\n return {\n error: `Failed to load help: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n },\n });\n};\n","import type { Tool } from 'ai';\nimport { createHelpTool } from './tools/utilities';\nimport type { ToolEntry, ToolMetadata, ToolState } from './types';\n\n/** Converts a ToolEntry to an AI SDK Tool, binding state to execute. */\nconst toAiTool = <S extends ToolState>(entry: ToolEntry<S>, state: S, includeOutputSchema: boolean): Tool =>\n ({\n description: entry.description,\n inputSchema: entry.inputSchema,\n outputSchema: includeOutputSchema ? entry.outputSchema : undefined,\n execute: (input: any) => entry.execute(input, state),\n }) as Tool;\n\n/** Extracts ToolMetadata from a ToolEntry, adding the name. */\nconst toMetadata = <S extends ToolState>(name: string, entry: ToolEntry<S>): ToolMetadata => ({\n name,\n description: entry.description,\n classificationPrompt: entry.classificationPrompt,\n tags: entry.tags,\n examples: entry.examples,\n examplePrompts: entry.examplePrompts,\n relatedTools: entry.relatedTools,\n dependsOn: entry.dependsOn,\n});\n\n/**\n * Converts a composed tool record into AI SDK tools and metadata.\n * Rebinds the help tool with resolved metadata.\n *\n * @ignore\n */\nexport const setupTools = <S extends ToolState>(\n toolEntries: Record<string, ToolEntry<S>>,\n state: S,\n options?: { outputSchemas?: boolean },\n): { tools: Record<string, Tool>; toolsMetadata: Record<string, ToolMetadata> } => {\n const includeOutputSchema = options?.outputSchemas !== false;\n const tools: Record<string, Tool> = {};\n const toolsMetadata: Record<string, ToolMetadata> = {};\n\n for (const [name, entry] of Object.entries(toolEntries)) {\n tools[name] = toAiTool(entry, state, includeOutputSchema);\n toolsMetadata[name] = toMetadata(name, entry);\n }\n\n // Rebind help tool with resolved metadata\n if (tools.help) {\n tools.help = createHelpTool(() => toolsMetadata);\n }\n\n if (Object.keys(tools).length === 0) {\n throw new Error('MapAgent requires at least one tool.');\n }\n\n return { tools, toolsMetadata };\n};\n","/**\n * @module agent-toolkit-tools/maplibre\n */\n\nimport type { Map as MapLibreMap } from 'maplibre-gl';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n// ---------------------------------------------------------------------------\n// Schemas\n// ---------------------------------------------------------------------------\n\nconst sourceDiffSchema = z.object({\n added: z.array(z.string()).describe('Source IDs added by the executed code.'),\n removed: z.array(z.string()).describe('Source IDs removed by the executed code.'),\n updated: z.array(z.string()).describe('Source IDs whose definition changed.'),\n});\n\nconst layerDiffSchema = z.object({\n added: z.array(z.string()).describe('Layer IDs added by the executed code.'),\n removed: z.array(z.string()).describe('Layer IDs removed by the executed code.'),\n updated: z.array(z.string()).describe('Layer IDs whose properties changed.'),\n});\n\n/** Input schema for the executeMaplibreCode tool. */\nexport const executeMaplibreCodeSchema = z.object({\n code: z\n .string()\n .describe(\n 'Async JavaScript code executed in an environment where `map` is the live MapLibre Map instance. ' +\n 'Full JS is supported: variables, loops, conditionals, helper functions, top-level `await`. ' +\n 'Example: await a map event with `await new Promise(r => map.once(\"idle\", r))`. ' +\n 'Return a value with `return` to include it in the result.',\n ),\n});\n\n/** Output schema for the executeMaplibreCode tool. */\nexport const executeMaplibreCodeOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n result: z.unknown().optional().describe('Return value of the executed code, if any.'),\n sources: sourceDiffSchema,\n layers: layerDiffSchema,\n }),\n toolErrorSchema,\n]);\n\nexport const executeMaplibreCodeDescription =\n 'Execute any MapLibre JS code for maximum flexibility. ' +\n '`map` is the live MapLibre Map instance — the full API is available. ' +\n 'Use for anything: custom sources and layers, camera control, style mutations, event-driven sequences, animations, or any operation not covered by other tools. ' +\n 'Full JS is supported: loops, conditionals, helper functions, top-level `await`, event listeners. ' +\n 'Returns which sources and layers were added, removed, or updated.';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ntype Snapshot = Map<string, string>;\n\nconst snapshotSources = (mapLibreMap: MapLibreMap): Snapshot => {\n const sources = mapLibreMap.getStyle()?.sources ?? {};\n const snapshot: Snapshot = new Map();\n\n for (const [sourceId, source] of Object.entries(sources)) {\n snapshot.set(sourceId, JSON.stringify(source));\n }\n\n return snapshot;\n};\n\nconst snapshotLayers = (mapLibreMap: MapLibreMap): Snapshot => {\n const layers = mapLibreMap.getStyle()?.layers ?? [];\n const snapshot: Snapshot = new Map();\n\n for (const layer of layers) {\n snapshot.set(layer.id, JSON.stringify(layer));\n }\n\n return snapshot;\n};\n\nconst diffSnapshots = (\n before: Snapshot,\n after: Snapshot,\n): { added: string[]; removed: string[]; updated: string[] } => {\n const added: string[] = [];\n const removed: string[] = [];\n const updated: string[] = [];\n\n for (const [identifier, afterJson] of after) {\n const beforeJson = before.get(identifier);\n\n if (beforeJson === undefined) {\n added.push(identifier);\n } else if (beforeJson !== afterJson) {\n updated.push(identifier);\n }\n }\n\n for (const identifier of before.keys()) {\n if (!after.has(identifier)) {\n removed.push(identifier);\n }\n }\n\n return { added, removed, updated };\n};\n\n// ---------------------------------------------------------------------------\n// Tool factory\n// ---------------------------------------------------------------------------\n\n/** Execute function for executeMaplibreCode — usable with ToolEntry format. */\nexport const executeExecuteMaplibreCode = async (\n params: z.infer<typeof executeMaplibreCodeSchema>,\n state: ToolState,\n) => {\n const { code } = params;\n try {\n const mapLibreMap = state.baseMap.mapLibreMap;\n const beforeSources = snapshotSources(mapLibreMap);\n const beforeLayers = snapshotLayers(mapLibreMap);\n\n // eslint-disable-next-line no-new-func\n const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor as new (\n ...args: string[]\n ) => (map: MapLibreMap) => Promise<unknown>;\n const userFunction = new AsyncFunction('map', code);\n const result = await userFunction(mapLibreMap);\n\n const sources = diffSnapshots(beforeSources, snapshotSources(mapLibreMap));\n const layers = diffSnapshots(beforeLayers, snapshotLayers(mapLibreMap));\n\n return { success: true, result: result ?? undefined, sources, layers };\n } catch (error) {\n return {\n error: `Code execution failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport type { Position } from 'geojson';\nimport { z } from 'zod';\n\n/** @ignore */\nexport type ResolvedLocation = {\n /** Resolved place: a Place (with address metadata) or a bare [lng, lat] tuple. */\n place: WaypointLike;\n position: Position;\n name: string;\n /** Original query string, when the input was resolved from text. */\n query?: string;\n};\n\n/** @ignore */\nexport const locationInputSchema = z.union([\n z.object({\n query: z.string().describe('Location string to resolve.'),\n locationType: z.enum(['poi', 'default']).describe('\"poi\" for landmarks and venues; \"default\" for addresses.'),\n }),\n z.object({\n position: z\n .object({ lng: z.number(), lat: z.number() })\n .describe('Explicit coordinates — use when you already have a position.'),\n }),\n]);\n\n/** @ignore */\nexport type LocationInput = z.infer<typeof locationInputSchema>;\n","import { poiCategories as knownPoiCategories, POICategory } from '@tomtom-org/maps-sdk/core';\nimport { getPOICategoryCodes } from '@tomtom-org/maps-sdk/services';\n\nconst knownPoiCategoriesSet = new Set<string>(knownPoiCategories);\n\n/** @ignore */\nexport const resolvePoiCategories = async (poiCategories: string[] | undefined): Promise<POICategory[] | undefined> => {\n if (!poiCategories) {\n return undefined;\n }\n const known = poiCategories.filter((c) => knownPoiCategoriesSet.has(c)) as POICategory[];\n const unrecognized = poiCategories.filter((c) => !knownPoiCategoriesSet.has(c));\n\n let resolvedUnrecognized: POICategory[] = [];\n if (unrecognized.length) {\n resolvedUnrecognized = await getPOICategoryCodes({ filters: unrecognized });\n }\n\n const merged = [...new Set([...known, ...resolvedUnrecognized])];\n return merged.length ? merged : undefined;\n};\n","/**\n * @module agent-toolkit-tools\n *\n * Shared input schema building blocks reused across multiple tools.\n */\n\nimport { z } from 'zod';\n\n/** @ignore */\nexport const geoJsonBBoxSchema = z\n .union([z.array(z.number()).refine((arr) => arr.length === 4, { message: 'BBox must have 4 elements' })])\n .describe('[minLng, minLat, maxLng, maxLat] or [W,S,E,N]');\n\n/** @ignore */\nexport const hasBBoxSchema = z.union([geoJsonBBoxSchema, z.object({ bbox: geoJsonBBoxSchema })]);\n\n/** @ignore */\nexport const showPlacesSchema = z.object({\n markerType: z\n .enum(['pin', 'none'])\n .describe(\n '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.',\n ),\n zoomMode: z\n .enum(['auto', 'none'])\n .describe('How to zoom the map into the places. Use \"none\" to keep the map still.'),\n mode: z\n .enum(['add', 'replace'])\n .optional()\n .describe(\n 'Display mode. Default: \"replace\" (clears existing pins, shows only these). ' +\n 'Use \"add\" when the user wants to STACK these results on top of what is already shown (\"also show\", \"additionally\", \"and X\").',\n ),\n});\n\n/** @ignore */\nexport const shownSchema = z.object({\n markerType: z.boolean(),\n zoomMode: z.boolean(),\n});\n\n/** @ignore */\nexport const whereSchema = z.union([\n z.object({ position: z.array(z.number()).length(2) }).describe('Bias toward a specific [lng, lat] point.'),\n z.object({ boundingBox: hasBBoxSchema }).describe('Consider only within a BBox [W,S,E,N] or GeoJSON with bbox.'),\n z.literal('within-map-bounds').describe('Consider within the current map viewport bounds.'),\n z.literal('nearby-map-center').describe('Bias toward the current map center.'),\n z.literal('global').describe('No geographic bias — global search.'),\n z\n .string()\n .describe(\n 'Place name or area (e.g. \"Paris\", \"Manhattan\") — geocoded first, then its bbox or position is used as bias.',\n ),\n]);\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, type Place, type Places } from '@tomtom-org/maps-sdk/core';\nimport type { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { shownSchema, showPlacesSchema } from './schema';\n\n/** @ignore */\nexport const showResultsOnMap = async (\n state: ToolState,\n result: Place | Places,\n placesEntryId: string,\n show: z.infer<typeof showPlacesSchema>,\n): Promise<z.infer<typeof shownSchema>> => {\n const shown: z.infer<typeof shownSchema> = { markerType: false, zoomMode: false };\n if (show.markerType === 'pin') {\n if (show.mode === 'add') {\n await state.places.addShownEntries([placesEntryId]);\n } else {\n await state.places.setShownEntries([placesEntryId]);\n }\n shown.markerType = true;\n }\n if (show.zoomMode === 'auto') {\n const bbox = bboxFromGeoJSON(result);\n if (bbox) state.baseMap.mapLibreMap.fitBounds(bbox, { padding: 50 });\n shown.zoomMode = true;\n }\n return shown;\n};\n","/**\n * @module agent-toolkit-tools\n *\n * Utility for deriving a search bias from the current map viewport.\n */\n\nimport type { BBox } from '@tomtom-org/maps-sdk/core';\nimport type { Position } from 'geojson';\nimport type { BaseMapState } from '../../state';\n\n/** @ignore */\nexport const MIN_VIEWPORT_BIAS_ZOOM = 6;\n\n/** @ignore */\nexport const getViewportBias = (map: BaseMapState, minZoom = MIN_VIEWPORT_BIAS_ZOOM): Position | undefined => {\n const zoom = map.mapLibreMap.getZoom();\n if (zoom < minZoom) return undefined;\n const center = map.mapLibreMap.getCenter();\n return [center.lng, center.lat];\n};\n\n/** @ignore */\nexport const getViewportBoundingBox = (map: BaseMapState): BBox => {\n const bounds = map.mapLibreMap.getBounds();\n return [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, type HasBBox } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { hasBBoxSchema } from '../shared';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the fly-to tool. */\nexport const flyToOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for fly-to. */\nexport const flyToSchema = z.object({\n where: z.union([\n z\n .object({\n boundingBox: hasBBoxSchema.describe('BBox [W,S,E,N] or GeoJSON object with bbox.'),\n padding: z.number().optional().describe('Padding in pixels. Default: 50.'),\n })\n .describe('Fit the camera to a bounding box.'),\n z\n .object({\n position: z.array(z.number()).length(2).describe('[lng, lat] to fly to.'),\n zoom: z.number().optional().describe('Camera zoom level. Default: 14.'),\n })\n .describe('Fly the camera to a specific position.'),\n ]),\n});\n\nexport const flyToDescription =\n 'Move the map camera to a bounding box or a specific position. ' +\n 'Use with boundingBox to frame a region or set of results. Use with position to center on a point.';\n\n/** Execute function for flyTo — usable with ToolEntry format. */\nexport const executeFlyTo = async (params: z.infer<typeof flyToSchema>, state: ToolState) => {\n const { where } = params;\n try {\n if ('boundingBox' in where) {\n const bbox = bboxFromGeoJSON(where.boundingBox as HasBBox);\n if (!bbox) {\n return { error: 'Invalid boundingBox — could not extract a bounding box.' };\n }\n state.baseMap.mapLibreMap.fitBounds(bbox, { padding: where.padding ?? 50 });\n } else {\n state.baseMap.mapLibreMap.flyTo({\n center: where.position as [number, number],\n zoom: where.zoom ?? 14,\n });\n }\n return { success: true };\n } catch (error) {\n return {\n error: `flyTo failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-map-style-layers tool. */\nexport const getMapStyleLayersOutputSchema = z.union([\n z.object({\n layers: z.array(\n z.object({\n id: z.string(),\n layout: z.unknown().optional(),\n paint: z.unknown().optional(),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting map style layers.\n */\nexport const getMapStyleLayersSchema = z.object({\n layerIdQuery: z\n .string()\n .optional()\n .describe('Case-insensitive partial match on layer IDs. If omitted, all layers are returned.'),\n include: z\n .array(z.enum(['paint', 'layout']))\n .describe(\n '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.',\n ),\n});\n\nexport const getMapStyleLayersDescription =\n 'Get map layer IDs with their paint/layout properties from MapLibre style for advanced runtime manipulation. Use before setLayoutProperty/setPaintProperty for custom styling.';\n\n/** Execute function for getMapStyleLayers — usable with ToolEntry format. */\nexport const executeGetMapStyleLayers = async (params: z.infer<typeof getMapStyleLayersSchema>, state: ToolState) => {\n const { layerIdQuery, include } = params;\n try {\n const style = state.baseMap.mapLibreMap.getStyle();\n let layers = style.layers ?? [];\n\n // Filter by layerIdQuery if provided (case-insensitive partial match)\n if (layerIdQuery) {\n layers = layers.filter((layer) => layer.id.toLowerCase().includes(layerIdQuery.toLowerCase()));\n if (layers.length === 0) {\n return {\n error: `No layers found matching query: \"${layerIdQuery}\"`,\n };\n }\n }\n\n return {\n layers: layers.map((layer) => ({\n id: layer.id,\n ...(include.includes('paint') && { paint: layer.paint }),\n ...(include.includes('layout') && { layout: layer.layout }),\n })),\n };\n } catch (error) {\n return {\n error: `Failed to get style: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-viewport tool. */\nexport const getViewportOutputSchema = z.union([\n z.object({\n center: z.array(z.number()).describe('[lng, lat]'),\n zoom: z.number().describe('0–22'),\n bbox: z.array(z.number()).describe('[W, S, E, N]'),\n pitch: z.number().describe('degrees, 0=top-down, 85=near-horizontal'),\n bearing: z.number().describe('degrees, 0=north, 90=east'),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting viewport.\n */\nexport const getViewportSchema = z.object({});\n\nexport const getViewportDescription =\n 'Get the current map viewport: center coordinates [longitude, latitude], zoom level, and bounding box [minLng, minLat, maxLng, maxLat]. ' +\n 'Use for queries referencing the map view: \"in this area\", \"what I can see\", \"near the map center\". ' +\n 'Does NOT return the user\\'s physical location — use getCurrentLocation for \"near me\" queries. ' +\n 'Reads map state. Does not call any service.';\n\n/** Execute function for getViewport — usable with ToolEntry format. */\nexport const executeGetViewport = async (_params: z.infer<typeof getViewportSchema>, state: ToolState) => {\n try {\n const mapLibreMap = state.baseMap.mapLibreMap;\n return {\n center: mapLibreMap.getCenter().toArray(),\n zoom: mapLibreMap.getZoom(),\n bbox: state.baseMap.ttMap.getBBox(),\n pitch: mapLibreMap.getPitch(),\n bearing: mapLibreMap.getBearing(),\n };\n } catch (error) {\n return {\n error: `Failed to get viewport: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools/maplibre\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\nconst changeResultSchema = z.union([\n z.object({\n layerId: z.string(),\n propertyName: z.string(),\n value: z.unknown(),\n success: z.literal(true),\n }),\n z.object({\n layerId: z.string(),\n propertyName: z.string(),\n error: z.string(),\n }),\n]);\n\n/** Output schema for the setLayoutProperties tool. */\nexport const setLayoutPropertiesOutputSchema = z.union([\n z.object({\n results: z.array(changeResultSchema),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for the setLayoutProperties tool. */\nexport const setLayoutPropertiesSchema = z\n .object({\n changes: z.array(\n z.object({\n layerId: z.string().describe('MapLibre layer ID from getMapStyleLayers'),\n propertyName: z.string().describe('e.g. visibility|text-field|icon-size'),\n value: z.any(),\n }),\n ),\n })\n .describe('List of layout property changes to apply in one go.');\n\nexport const setLayoutPropertiesDescription =\n 'Set one or more layout properties on MapLibre layers (visibility, text-field, icon-size). ' +\n 'Use getMapStyleLayers to discover valid layer IDs first. ' +\n 'Layout properties control structure and visibility — use setPaintProperties for colors and widths.';\n\n/** Execute function for setLayoutProperties — usable with ToolEntry format. */\nexport const executeSetLayoutProperties = async (\n params: z.infer<typeof setLayoutPropertiesSchema>,\n state: ToolState,\n) => {\n const { changes } = params;\n try {\n const results = changes.map(({ layerId, propertyName, value }) => {\n try {\n state.baseMap.mapLibreMap.setLayoutProperty(layerId, propertyName, value);\n return { layerId, propertyName, value, success: true as const };\n } catch (error) {\n return {\n layerId,\n propertyName,\n error: `Failed to set layout property: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n });\n\n return { results };\n } catch (error) {\n return {\n error: `Failed to set layout properties: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools/maplibre\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\nconst changeResultSchema = z.union([\n z.object({\n layerId: z.string(),\n propertyName: z.string(),\n value: z.unknown(),\n success: z.literal(true),\n }),\n z.object({\n layerId: z.string(),\n propertyName: z.string(),\n error: z.string(),\n }),\n]);\n\n/** Output schema for the setPaintProperties tool. */\nexport const setPaintPropertiesOutputSchema = z.union([\n z.object({\n results: z.array(changeResultSchema),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for the setPaintProperties tool. */\nexport const setPaintPropertiesSchema = z.object({\n changes: z\n .array(\n z.object({\n layerId: z.string().describe('MapLibre layer ID from getMapStyleLayers'),\n propertyName: z.string().describe('e.g. fill-color|line-width|text-color'),\n value: z.any(),\n }),\n )\n .describe('List of paint property changes to apply in one go.'),\n});\n\nexport const setPaintPropertiesDescription =\n 'Set one or more paint properties on MapLibre layers (colors, widths, opacity). ' +\n 'Use getMapStyleLayers to discover valid layer IDs first. ' +\n 'Paint properties control visual appearance — use setLayoutProperties for visibility and structural properties. ' +\n 'For route styling, prefer setRouteTheme.';\n\n/** Execute function for setPaintProperties — usable with ToolEntry format. */\nexport const executeSetPaintProperties = async (params: z.infer<typeof setPaintPropertiesSchema>, state: ToolState) => {\n const { changes } = params;\n try {\n const results = changes.map(({ layerId, propertyName, value }) => {\n try {\n state.baseMap.mapLibreMap.setPaintProperty(layerId, propertyName, value);\n return { layerId, propertyName, value, success: true as const };\n } catch (error) {\n return {\n layerId,\n propertyName,\n error: `Failed to set paint property: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n });\n\n return { results };\n } catch (error) {\n return {\n error: `Failed to set paint properties: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the set-pitch-bearing tool. */\nexport const setPitchBearingOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for setting pitch and bearing.\n */\nexport const setPitchBearingSchema = z.object({\n pitch: z.number().min(0).max(85).optional().describe('0=top-down, 85=near-horizontal'),\n bearing: z.number().min(-180).max(180).optional().describe('0=north, 90=east'),\n});\n\nexport const setPitchBearingDescription =\n 'Tilt and/or rotate the map camera. Pitch 0 = top-down view, 85 = near-horizontal (3D effect). ' +\n 'Bearing 0 = north up, 90 = east up. Provide at least one of pitch or bearing.';\n\n/** Execute function for setPitchBearing — usable with ToolEntry format. */\nexport const executeSetPitchBearing = async (params: z.infer<typeof setPitchBearingSchema>, state: ToolState) => {\n const { pitch, bearing } = params;\n\n if (pitch === undefined && bearing === undefined) {\n return { error: 'Provide at least one of pitch or bearing' };\n }\n\n try {\n const map = state.baseMap.mapLibreMap;\n map.easeTo({\n ...(pitch !== undefined && { pitch }),\n ...(bearing !== undefined && { bearing }),\n });\n\n return { success: true };\n } catch (error) {\n return {\n error: `Failed to set pitch/bearing: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the zoom-in-or-out tool. */\nexport const zoomInOrOutOutputSchema = z.union([\n z.object({\n zoom: z.number().describe('Resulting zoom level after the change'),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for zoom-in-or-out. */\nexport const zoomInOrOutSchema = z.object({\n delta: z\n .number()\n .describe(\n 'Amount to zoom. Positive values zoom in, negative values zoom out. Can have decimals. Typical step: 1 or 2.',\n ),\n});\n\nexport const zoomInOrOutDescription =\n 'Zoom the map in or out by a given amount relative to the current zoom level. ' +\n 'Positive delta zooms in (closer), negative delta zooms out (further away). ' +\n 'Returns the resulting zoom level.';\n\n/** Execute function for zoomInOrOut — usable with ToolEntry format. */\nexport const executeZoomInOrOut = async (params: z.infer<typeof zoomInOrOutSchema>, state: ToolState) => {\n const { delta } = params;\n try {\n const map = state.baseMap.mapLibreMap;\n const targetZoom = map.getZoom() + delta;\n map.zoomTo(targetZoom);\n return { zoom: targetZoom };\n } catch (error) {\n return {\n error: `Zoom failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-classifier\n *\n * Query intent classification for automatic tool selection.\n *\n * Uses LLM-based structured generation to map a user query directly to the\n * minimal set of tool names needed to answer it.\n *\n * The classifier prompt is built dynamically from each tool's `relatedTools`\n * in the tool metadata, so it stays in sync automatically when tools are\n * added or renamed.\n */\n\nimport { generateText, type LanguageModel, type ModelMessage, Output, type TextPart } from 'ai';\nimport { z } from 'zod';\nimport type { Classifier, ClassifierContext, ToolMetadata } from '../types';\nimport type { ClassificationResult, ClassifierOptions } from './types';\n\n/**\n * A single turn in the conversation passed to {@link classifyUserIntent}.\n *\n * @ignore\n */\nexport type ConversationMessage = { role: 'user' | 'assistant'; content: string };\n\n/** Max character length for each history message when compacting for the classifier. */\nconst MAX_HISTORY_MESSAGE_LENGTH = 300;\n\n/** Number of most-recent history messages (excluding the last user message) passed to the classifier. */\nconst MAX_CLASSIFIER_HISTORY_MESSAGES = 8;\n\n/** Formats a single tool's metadata into a compact classifier prompt entry. */\nconst formatToolEntry = (name: string, entry: ToolMetadata): string => {\n const classificationPrompt = entry.classificationPrompt ? ` ${entry.classificationPrompt}.` : '';\n // const related = entry.relatedTools?.length ? ` Related: ${entry.relatedTools.join(', ')}.` : '';\n const depends = entry.dependsOn?.length ? ` Depends on: ${entry.dependsOn.join(', ')}.` : '';\n return `${name}${classificationPrompt}${depends}`;\n};\n\n/**\n * Builds the system prompt listing available tools for the classifier.\n *\n * @ignore\n */\nexport const buildClassifySystemPrompt = (toolsMetadata: Record<string, ToolMetadata>): string => {\n const toolEntries = Object.entries(toolsMetadata).map(([name, entry]) => formatToolEntry(name, entry));\n\n return [\n 'You are a tool selector for a map assistant.',\n 'You will receive a conversation. Select the minimal set of tools needed to fulfill the LAST user message.',\n `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`,\n '',\n 'Available tools:',\n ...toolEntries,\n ].join('\\n');\n};\n\nconst classifySchema = z.object({\n tools: z\n .array(z.string()) // using string to save tokens, since tool names already included in system prompt\n .min(1)\n .describe('Tool names needed to fulfill the query.'),\n});\n\n/** Calls the LLM with structured output to select tools for the conversation. */\nconst classifyQueryToTools = async (\n conversation: ConversationMessage[],\n model: LanguageModel,\n toolsMetadata: Record<string, ToolMetadata>,\n): Promise<{ tools: string[]; usage: ClassificationResult['usage'] }> => {\n const generated = await generateText({\n model,\n output: Output.object({ schema: classifySchema }),\n system: buildClassifySystemPrompt(toolsMetadata),\n messages: conversation,\n maxOutputTokens: 200,\n });\n\n return {\n tools: generated.output.tools,\n usage: {\n inputTokens: generated.usage?.inputTokens ?? 0,\n outputTokens: generated.usage?.outputTokens ?? 0,\n totalTokens: generated.usage?.totalTokens ?? 0,\n },\n };\n};\n\n/**\n * Classify a user conversation to determine which tools to activate.\n *\n * The `conversation` should contain the last user message plus a compaction\n * of the previous chat history (each truncated to save tokens).\n *\n * @example\n * ```typescript\n * const result = await classifyUserIntent(conversation, {\n * chatModel: openai('gpt-4o-mini'),\n * toolsMetadata,\n * });\n * // result.activeToolNames contains the selected tools\n * ```\n *\n * @group Agent Toolkit\n */\nexport const classifyUserIntent = async (\n conversation: ConversationMessage[],\n options: ClassifierOptions,\n): Promise<ClassificationResult> => {\n const { chatModel, toolsMetadata } = options;\n const startTime = performance.now();\n\n const { tools, usage } = await classifyQueryToTools(conversation, chatModel, toolsMetadata);\n\n const activeToolNames = tools;\n\n const timeMs = performance.now() - startTime;\n\n return {\n activeToolNames,\n timeMs,\n usage,\n };\n};\n\n/** Type predicate that narrows a message content part to a TextPart. */\nconst isTextPart = (part: { type: string }): part is TextPart => part.type === 'text';\n\n/**\n * Extracts plain text from a message's content (string or structured content array).\n *\n * @ignore\n */\nexport const extractMessageText = (content: string | Array<{ type: string }>): string | null => {\n if (typeof content === 'string') return content;\n\n const textParts = content.filter(isTextPart);\n if (textParts.length > 0) return textParts.map((part) => part.text).join('');\n\n return null;\n};\n\n/**\n * Extracts the text content of the last user message in a message array.\n * Returns null if no user message is found or if content has no text.\n *\n * @group Agent Toolkit\n */\nexport const extractLastUserText = (messages: ReadonlyArray<ModelMessage>): string | null => {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'user') {\n return extractMessageText(messages[i].content);\n }\n }\n return null;\n};\n\n/**\n * Creates the default LLM-based classifier. Uses structured generation to select\n * the minimal tool set for each user message.\n *\n * @param options.model - Language model for classification (ideally fast/cheap like gpt-4o-mini)\n * @param options.maxHistoryMessages - Max prior turns for context. Default: 8\n * @param options.maxHistoryMessageLength - Max chars per history message. Default: 300\n *\n * @group Agent Toolkit\n */\nexport const createDefaultClassifier = (options: {\n model: LanguageModel;\n maxHistoryMessages?: number;\n maxHistoryMessageLength?: number;\n}): Classifier => {\n const { model, maxHistoryMessages, maxHistoryMessageLength } = options;\n\n return async (context: ClassifierContext): Promise<ClassificationResult | null> => {\n const { messages, toolsMetadata } = context;\n if (!messages?.length) return null;\n\n const historyLimit = maxHistoryMessages ?? MAX_CLASSIFIER_HISTORY_MESSAGES;\n const messageCharLimit = maxHistoryMessageLength ?? MAX_HISTORY_MESSAGE_LENGTH;\n\n // Find last user message index and extract text in one pass\n let lastUserIndex = -1;\n let lastUserText: string | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'user') {\n lastUserIndex = i;\n lastUserText = extractMessageText(messages[i].content);\n break;\n }\n }\n if (!lastUserText) return null;\n\n // Compact history\n const conversation: ConversationMessage[] = [];\n const historyStartIndex = Math.max(0, lastUserIndex - historyLimit);\n\n for (let i = historyStartIndex; i < lastUserIndex; i++) {\n const message = messages[i];\n if (message.role !== 'user' && message.role !== 'assistant') continue;\n\n const text = extractMessageText(message.content);\n if (!text) continue;\n\n const compacted = text.length > messageCharLimit ? text.slice(0, messageCharLimit) + '…' : text;\n conversation.push({ role: message.role, content: compacted });\n }\n\n conversation.push({ role: 'user', content: lastUserText });\n\n try {\n return await classifyUserIntent(conversation, { chatModel: model, toolsMetadata });\n } catch {\n return null;\n }\n };\n};\n","import type { Place, Places, Routes, WaypointLike } from '@tomtom-org/maps-sdk/core';\n\n/**\n * Optional search context used to enrich a places history label.\n *\n * @ignore\n */\nexport type PlacesLabelContext = {\n query?: string;\n poiCategories?: string[];\n where?: string;\n /** Route label when results come from an along-route search (e.g. \"Amsterdam to Utrecht\"). */\n routeLabel?: string;\n};\n\nconst placeName = (place: Place): string | undefined => place.properties?.poi?.name;\n\nconst placeAddress = (place: Place): string | undefined => place.properties?.address?.freeformAddress;\n\nconst waypointAddress = (wp: WaypointLike): string | undefined => {\n if (Array.isArray(wp)) return undefined;\n return (wp as any).properties?.address?.freeformAddress;\n};\n\nconst formatDuration = (seconds: number): string => `${Math.round(seconds / 60)} min`;\n\nconst formatDistance = (meters: number): string => `${(meters / 1000).toFixed(1)} km`;\n\n/** Builds a label for a Places FeatureCollection from its count and search context. */\nconst makeCollectionLabel = (count: number, context?: PlacesLabelContext): string => {\n const parts: string[] = [];\n\n if (context?.query) parts.push(`\"${context.query}\"`);\n if (context?.poiCategories?.length) parts.push(context.poiCategories.join(', '));\n if (context?.routeLabel) parts.push(`along ${context.routeLabel}`);\n else if (context?.where) parts.push(`in ${context.where}`);\n\n const countStr = `${count} ${count === 1 ? 'place' : 'places'}`;\n return parts.length ? `${parts.join(' ')} (${countStr})` : countStr;\n};\n\n/**\n * Generate a human-readable label for a places history entry.\n *\n * For a single Place the label is derived from result properties (name / address),\n * falling back to the query when properties are sparse.\n *\n * For a Places collection (FeatureCollection) the label is built from search\n * context (query, categories, location) plus the result count.\n *\n * @ignore\n */\nexport const makePlacesLabel = (data: Place | Places, context?: PlacesLabelContext): string => {\n if ('features' in data) return makeCollectionLabel(data.features.length, context);\n\n const name = placeName(data);\n const address = placeAddress(data);\n\n if (name && address) return `${name}, ${address}`;\n if (name) return name;\n if (address) return address;\n if (context?.query) return context.query;\n return 'Place';\n};\n\n/**\n * Generate a human-readable label for a routes history entry.\n *\n * @ignore\n */\nexport const makeRoutesLabel = (routes: Routes, waypoints: WaypointLike[]): string => {\n const summary = routes.features[0]?.properties?.summary;\n const timeDist = summary\n ? ` (${formatDuration(summary.travelTimeInSeconds)}, ${formatDistance(summary.lengthInMeters)})`\n : '';\n\n const addresses = waypoints.map(waypointAddress).filter(Boolean) as string[];\n\n if (addresses.length >= 2) {\n const origin = addresses[0];\n const destination = addresses.at(-1);\n const vias = addresses.slice(1, -1);\n const path =\n vias.length > 0 ? `${origin} via ${vias.join(', ')} to ${destination}` : `${origin} to ${destination}`;\n return `${path}${timeDist}`;\n }\n\n return `Route${timeDist}`;\n};\n\n/** Budget type → display unit suffix. */\nconst RANGE_BUDGET_UNITS: Record<string, string> = {\n timeMinutes: 'min',\n distanceKM: 'km',\n remainingChargeCPT: '% remaining',\n spentChargePCT: '% spent',\n spentFuelLiters: 'L',\n};\n\n/**\n * Generate a human-readable label for a range history entry.\n * e.g. \"10/20/30 min from Amsterdam\" or \"50 km from [4.9, 52.3]\"\n *\n * @ignore\n */\nexport const makeRangeLabel = (budgets: Array<{ type: string; value: number }>, originName: string): string => {\n const sorted = [...budgets].sort((a, b) => a.value - b.value);\n const budgetStr = sorted.map((b) => `${b.value} ${RANGE_BUDGET_UNITS[b.type] ?? b.type}`).join('/');\n return `${budgetStr} from ${originName}`;\n};\n","/**\n * @module agent-toolkit-utils\n */\n\nimport {\n type CommonPlaceProps,\n getPosition,\n type Place,\n type Places,\n type Route,\n type Routes,\n type Waypoint,\n type WaypointLike,\n} from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\n\n/** @ignore */\nexport type PlaceSummary = { name?: string; address?: string; position: [number, number] };\n\n/** @ignore */\nexport type PlacesSummary = { count: number; features: PlaceSummary[] };\n\ntype RouteSummary = Route['properties']['summary'];\ntype LegSummary = Route['properties']['sections']['leg'][number]['summary'];\n\n// Maps Date fields to string for LLM-safe serialization (distributive so Date | undefined → string | undefined).\ntype StringDateValue<T> = T extends Date ? string : T;\n\n/** @ignore */\nexport type StringDates<T> = { [K in keyof T]: StringDateValue<T[K]> };\n\n/** @ignore */\nexport type SummarizedRoute = {\n index: number;\n summary: StringDates<RouteSummary>;\n /** Per-leg summaries; only present when the route has more than one leg. */\n legSummaries?: StringDates<LegSummary>[];\n};\n\n/** @ignore */\nexport type SummarizedRoutes = { count: number; routes: SummarizedRoute[] };\n\n/**\n * Converts a Place to a token-efficient summary for LLM consumption.\n *\n * @ignore\n */\nexport const summarizePlace = (place: Place): PlaceSummary => {\n const coordinates = place.geometry?.coordinates as [number, number] | undefined;\n return {\n name: place.properties?.poi?.name,\n address: place.properties?.address?.freeformAddress,\n position: coordinates ?? [0, 0],\n };\n};\n\n/**\n * Converts Places to a token-efficient summary for LLM consumption.\n *\n * @ignore\n */\nexport const summarizePlaces = (places: Places | Place[]): PlacesSummary => {\n const features = Array.isArray(places) ? places : places.features;\n return {\n count: features.length,\n features: features.map((feature) => summarizePlace(feature)),\n };\n};\n\n/**\n * Converts a Route to a token-efficient summary for LLM consumption.\n * Returns only the route summary and per-leg summaries (when more than one leg).\n *\n * @ignore\n */\nexport const summarizeRoute = (route: Route): SummarizedRoute => {\n const { summary, sections, index } = route.properties;\n const legs = sections.leg;\n\n const stringifyDates = <T extends { arrivalTime: Date; departureTime: Date }>(summary: T): StringDates<T> =>\n ({\n ...summary,\n arrivalTime: summary.arrivalTime.toISOString(),\n departureTime: summary.departureTime.toISOString(),\n }) as StringDates<T>;\n\n return {\n index,\n summary: stringifyDates(summary),\n ...(legs.length > 1 && { legSummaries: legs.map((leg) => stringifyDates(leg.summary)) }),\n };\n};\n\n/**\n * Converts Routes to a token-efficient summary for LLM consumption.\n *\n * @ignore\n */\nexport const summarizeRoutes = (routes: Routes): SummarizedRoutes => {\n const count = routes.features.length;\n\n return {\n count,\n routes: routes.features.map(summarizeRoute),\n };\n};\n\n/** @ignore */\nexport const waypointSummarySchema = z.object({\n slotIndex: z.number(),\n isFilled: z.boolean(),\n address: z.string().optional(),\n position: z.array(z.number()).length(2).optional().describe('[longitude, latitude]'),\n});\n\n/**\n * Token-efficient summary of a waypoint for LLM consumption.\n *\n * @ignore\n */\nexport const summarizeWaypoint = (\n waypoint: WaypointLike | null | undefined,\n): z.infer<typeof waypointSummarySchema> | null => {\n if (waypoint === null || waypoint === undefined) {\n return null;\n }\n\n const position = getPosition(waypoint);\n let address: string | undefined;\n if (!Array.isArray(waypoint)) {\n address = (waypoint as Waypoint<CommonPlaceProps>).properties?.address?.freeformAddress;\n }\n\n return {\n slotIndex: -1,\n isFilled: true,\n ...(address && { address }),\n ...(position && { position }),\n };\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { type BBox, getPosition, type Place, type WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport { geocode, geocodeOne, search, searchOne } from '@tomtom-org/maps-sdk/services';\nimport type { Position } from 'geojson';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makePlacesLabel } from '../../utils/state-labels';\nimport { summarizePlace } from '../../utils/summarize';\nimport { getViewportBias, getViewportBoundingBox, shownSchema, showPlacesSchema, whereSchema } from '../shared';\nimport { placeOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\ntype LocateBias = { position: Position } | { boundingBox: BBox };\n\nexport const locatePlace = async (\n query: string,\n locationType: 'poi' | 'default',\n bias?: LocateBias,\n): Promise<Place | null> => {\n const [searchFn, searchOneFn] = locationType === 'poi' ? [search, searchOne] : [geocode, geocodeOne];\n\n if (bias && 'position' in bias) {\n const results = await searchFn({ query, position: bias.position, limit: 1 });\n return results.features[0] ?? null;\n }\n if (bias && 'boundingBox' in bias) {\n const results = await searchFn({ query, boundingBox: bias.boundingBox, limit: 1 });\n return results.features[0] ?? null;\n }\n return (await searchOneFn(query)) ?? null;\n};\n\nexport const locatePlaceSchema = z.object({\n query: z\n .string()\n .describe('Location string to resolve for downstream workflows such as routes or further searches.'),\n waypointIndex: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe(\n 'Route location slot to stage. Ordered as [origin, ...stops, destination]. Use it if this is an origin, stop or destination for a route.',\n ),\n locationType: z\n .enum(['poi', 'default'])\n .describe(\n '\"poi\" for venues, landmarks, and businesses; \"default\" for places to geocode: addresses, parks, post codes, and geographies.',\n ),\n where: whereSchema.describe('Geographic scope for the search.'),\n show: showPlacesSchema\n .optional()\n .describe(\n 'Optional map display actions to perform after resolving the place. Skip if this is an intermediate calculation for another step.',\n ),\n});\n\nexport const locatePlaceOutputSchema = z.union([\n placeOutputSchema.extend({\n waypointIndex: z.number().optional(),\n shown: shownSchema.optional(),\n }),\n toolErrorSchema,\n]);\n\nexport const locatePlaceDescription =\n 'Resolve one user-provided location string into a normalized place summary for downstream workflows without changing the map or camera. ' +\n 'Search-first: accepts landmarks, stations, venues, cities, neighborhoods, and full addresses. ' +\n 'Can optionally stage a waypoint slot.';\n\nconst resolveLocateBias = async (\n where: z.infer<typeof whereSchema>,\n state: ToolState,\n): Promise<LocateBias | undefined> => {\n if (where === 'nearby-map-center') {\n const position = getViewportBias(state.baseMap);\n return position ? { position } : undefined;\n }\n if (where === 'within-map-bounds') {\n return { boundingBox: getViewportBoundingBox(state.baseMap) };\n }\n if (where === 'global') {\n return undefined;\n }\n if (typeof where === 'string') {\n const geoResult = await geocodeOne(where);\n if (geoResult?.bbox) return { boundingBox: geoResult.bbox };\n if (geoResult) {\n const position = getPosition(geoResult);\n if (position) return { position };\n }\n return undefined;\n }\n if ('position' in where) {\n return { position: where.position as Position };\n }\n return { boundingBox: where.boundingBox as BBox };\n};\n\nconst showLocateResult = async (\n state: ToolState,\n result: Place,\n placesEntryId: string,\n show: z.infer<typeof showPlacesSchema>,\n): Promise<z.infer<typeof shownSchema>> => {\n const shown: z.infer<typeof shownSchema> = { markerType: false, zoomMode: false };\n if (show.markerType === 'pin') {\n if (show.mode === 'add') {\n await state.places.addShownEntries([placesEntryId]);\n } else {\n await state.places.setShownEntries([placesEntryId]);\n }\n shown.markerType = true;\n }\n if (show.zoomMode === 'auto') {\n if (result.bbox) {\n state.baseMap.mapLibreMap.fitBounds(result.bbox);\n } else {\n const pos = getPosition(result);\n if (pos) state.baseMap.mapLibreMap.flyTo({ center: pos as [number, number], zoom: 13 });\n }\n shown.zoomMode = true;\n }\n return shown;\n};\n\n/** Standalone execute for ToolEntry format. */\nexport const executeLocatePlace = async (\n params: z.infer<typeof locatePlaceSchema>,\n state: ToolState,\n): Promise<z.infer<typeof locatePlaceOutputSchema>> => {\n const { query, locationType, waypointIndex, where, show } = params;\n\n try {\n const bias = await resolveLocateBias(where, state);\n const result = await locatePlace(query, locationType, bias);\n\n if (!result) {\n return { error: `No result found for \"${query}\"` };\n }\n\n const placesEntryId = state.places.addPlaceResult(result, makePlacesLabel(result, { query }));\n\n if (waypointIndex !== undefined) {\n state.routing.setWaypointAt(waypointIndex, result as unknown as WaypointLike);\n }\n\n const shown = show ? await showLocateResult(state, result, placesEntryId, show) : undefined;\n\n return {\n ...summarizePlace(result),\n ...(waypointIndex !== undefined && { waypointIndex }),\n ...(shown && { shown }),\n };\n } catch (error) {\n return {\n error: `Location resolution failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { getPosition } from '@tomtom-org/maps-sdk/core';\nimport type { LocationInput, ResolvedLocation } from '../shared';\nimport { locatePlace } from './locate-place';\n\n/** @ignore */\nexport const resolveLocationInput = async (input: LocationInput): Promise<ResolvedLocation | null> => {\n if ('position' in input) {\n const { lng, lat } = input.position;\n return {\n place: [lng, lat],\n position: [lng, lat],\n name: `[${lng}, ${lat}]`,\n };\n }\n\n const resolved = await locatePlace(input.query, input.locationType);\n if (!resolved) return null;\n\n const pos = getPosition(resolved);\n if (!pos) return null;\n\n return {\n place: resolved,\n position: pos,\n name: resolved.properties?.address?.freeformAddress ?? input.query,\n query: input.query,\n };\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, type HasBBox, type Routes, type WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport { type CostModel, calculateRoute, type MaxNumberOfAlternatives } from '@tomtom-org/maps-sdk/services';\nimport type { LngLatBoundsLike } from 'maplibre-gl';\nimport { z } from 'zod';\nimport type { RouteParams, ToolState } from '../../types';\nimport { makeRoutesLabel, summarizeRoutes } from '../../utils';\nimport { locationInputSchema } from '../shared';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\nimport { resolveLocationInput } from './resolve-location-input';\n\n/** Output schema for the set-route-locations tool. */\nexport const setRouteLocationsOutputSchema = z.union([routesOutputSchema, toolErrorSchema]);\n\n/** Input schema for set-route-locations. */\nexport const setRouteLocationsSchema = z.object({\n locations: z\n .array(locationInputSchema)\n .min(2)\n .describe('Ordered list: [origin, ...stops, destination]. Minimum 2.'),\n showOnMap: z.boolean().describe('Show the route and waypoints on the map after calculation.'),\n});\n\nexport const setRouteLocationsDescription =\n 'Set the route waypoints by resolving location queries. ' +\n 'Always triggers a route recalculation once all locations are resolved (minimum: origin + destination). ' +\n 'Replaces all current waypoints. Uses route parameters from setRouteParameters if already set. ' +\n 'Can be called in parallel with setRouteParameters. ' +\n 'Only car/driving routes are supported.';\n\n/**\n * Filters out null waypoints and returns the array only if there are at least 2 valid entries.\n * Returns null if the condition is not met, preventing a route calculation call.\n */\nexport const resolveRouteWaypoints = (waypoints: (WaypointLike | null)[]): WaypointLike[] | null => {\n const valid = waypoints.filter((w): w is WaypointLike => w !== null);\n return valid.length >= 2 ? valid : null;\n};\n\nexport const buildCalculateRouteParams = (routeParams: RouteParams) => {\n const { maxAlternatives = 0, costModel, when } = routeParams;\n return {\n ...(maxAlternatives > 0 && { maxAlternatives: maxAlternatives as MaxNumberOfAlternatives }),\n ...(costModel && {\n costModel: {\n ...costModel,\n ...(costModel.avoidAreas && {\n avoidAreas: costModel.avoidAreas as unknown as HasBBox[],\n }),\n } as CostModel,\n }),\n ...(when && { when: { option: when.option, date: new Date(when.date) } }),\n };\n};\n\nexport const showRouteOnMap = async (state: ToolState, routes: Routes, waypoints: WaypointLike[]): Promise<void> => {\n const routingModule = await state.routing.getRoutingModule();\n await routingModule.showRoutes(routes);\n await routingModule.showWaypoints(waypoints);\n const bbox = bboxFromGeoJSON(routes);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox as LngLatBoundsLike, { padding: 50 });\n }\n};\n\n/**\n * Create the set-route-locations tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeSetRouteLocations = async (\n params: z.infer<typeof setRouteLocationsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof setRouteLocationsOutputSchema>> => {\n const { locations, showOnMap } = params;\n try {\n const resolved = await Promise.all(locations.map(resolveLocationInput));\n\n const unresolved = locations.filter((loc, i) => resolved[i] === null && 'query' in loc) as Array<{\n query: string;\n }>;\n if (unresolved.length > 0) {\n return { error: `Could not resolve: ${unresolved.map((l) => `\"${l.query}\"`).join(', ')}` };\n }\n\n const waypoints = resolveRouteWaypoints(resolved.map((r) => r?.place ?? null));\n if (!waypoints) {\n return { error: 'Not enough valid waypoints to calculate a route (minimum 2).' };\n }\n\n const routes = await calculateRoute({\n locations: waypoints,\n ...buildCalculateRouteParams(state.routing.params),\n });\n\n state.routing.addRoutes(routes, waypoints, makeRoutesLabel(routes, waypoints));\n\n if (showOnMap) {\n await showRouteOnMap(state, routes, waypoints);\n }\n\n return summarizeRoutes(routes);\n } catch (error) {\n return {\n error: `Route calculation failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { Place } from '@tomtom-org/maps-sdk/core';\nimport { withInsertedWaypoint } from '@tomtom-org/maps-sdk/core';\nimport { calculateRoute } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makeRoutesLabel, summarizeRoutes } from '../../utils';\nimport { locationInputSchema } from '../shared';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\nimport { resolveLocationInput } from './resolve-location-input';\nimport { buildCalculateRouteParams, resolveRouteWaypoints, showRouteOnMap } from './set-route-locations';\n\n/** Output schema for the add-stop-to-route tool. */\nexport const addStopToRouteOutputSchema = z.union([routesOutputSchema, toolErrorSchema]);\n\n/**\n * Tool schema for adding a stop to existing route.\n */\nexport const addStopToRouteSchema = z.object({\n location: locationInputSchema.optional().describe('The stop to add. Omit to use the last stored place in context.'),\n showOnMap: z.boolean().describe('Show the updated route and waypoints on the map after recalculation.'),\n});\n\nexport const addStopToRouteDescription =\n 'Add a stop to the current route. Inserts the new waypoint at the optimal position and always triggers a route recalculation. ' +\n 'If location is provided, it is resolved search-first. ' +\n 'Requires an existing route (call setRouteLocations first).';\n\nconst validateExistingRoute = async (state: ToolState) => {\n const shownRoutes = (await state.routing.getRoutingModule()).getShown();\n const shownRouteLines = shownRoutes?.mainLines;\n const shownWaypoints = shownRoutes?.waypoints;\n if (!shownRouteLines || !shownRouteLines.features.length) {\n return 'No existing route available. Use calculate-route first.';\n }\n if (!shownWaypoints || shownWaypoints.features.length < 2) {\n return 'No existing waypoints available. Use calculate-route first to create a route with waypoints.';\n }\n return { shownRouteLines, shownWaypoints };\n};\n\nconst resolveNewWaypoint = async (\n location: z.infer<typeof locationInputSchema> | undefined,\n state: ToolState,\n): Promise<{ place: Place | [number, number] } | { error: string }> => {\n if (location) {\n const resolved = await resolveLocationInput(location);\n if (!resolved) {\n const label = 'query' in location ? `\"${location.query}\"` : JSON.stringify(location.position);\n return { error: `Could not resolve location: ${label}` };\n }\n return { place: resolved.place as Place | [number, number] };\n }\n const fallback = state.places.latestPlace?.at(0);\n if (!fallback) {\n return {\n error: 'No location provided and no last place available in context. Provide a location or resolve a place first.',\n };\n }\n return { place: fallback };\n};\n\n/**\n * Create the add stop to route tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeAddStopToRoute = async (\n params: z.infer<typeof addStopToRouteSchema>,\n state: ToolState,\n): Promise<z.infer<typeof addStopToRouteOutputSchema>> => {\n const { location, showOnMap } = params;\n try {\n const routeResult = await validateExistingRoute(state);\n if (typeof routeResult === 'string') return { error: routeResult };\n const { shownRouteLines, shownWaypoints } = routeResult;\n\n const waypointResult = await resolveNewWaypoint(location, state);\n if ('error' in waypointResult) return waypointResult;\n const newWaypoint = waypointResult.place;\n\n const routeToUse = shownRouteLines.features[0];\n\n // Use withInsertedWaypoint to find the best position and get updated waypoints\n const updatedWaypoints = withInsertedWaypoint(routeToUse, shownWaypoints.features, newWaypoint);\n\n const waypoints = resolveRouteWaypoints(updatedWaypoints);\n if (!waypoints) {\n return { error: 'Not enough valid waypoints to calculate a route (minimum 2).' };\n }\n\n // Calculate new route with the updated waypoints and current route params\n const routes = await calculateRoute({\n locations: waypoints,\n ...buildCalculateRouteParams(state.routing.params),\n });\n\n state.routing.addRoutes(routes, waypoints, makeRoutesLabel(routes, waypoints));\n\n if (showOnMap) {\n await showRouteOnMap(state, routes, waypoints);\n }\n\n return summarizeRoutes(routes);\n } catch (error) {\n return {\n error: `Failed to add stop to route: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, getPosition, type HasBBox } from '@tomtom-org/maps-sdk/core';\nimport { search, searchOne } from '@tomtom-org/maps-sdk/services';\nimport type { Position } from 'geojson';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makePlacesLabel, summarizePlaces } from '../../utils';\nimport {\n getViewportBias,\n getViewportBoundingBox,\n resolvePoiCategories,\n shownSchema,\n showPlacesSchema,\n showResultsOnMap,\n whereSchema,\n} from '../shared';\nimport { placesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the discover-places tool. */\nexport const discoverPlacesOutputSchema = z.union([\n placesOutputSchema.extend({\n shown: shownSchema.optional(),\n placesEntryId: z.string().optional(),\n label: z\n .string()\n .optional()\n .describe('Human-readable label stored with the entry (e.g. \"cafe\", \"CINEMA (50 places)\").'),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for discovering places.\n */\nexport const discoverPlacesSchema = z\n .object({\n query: z\n .string()\n .optional()\n .describe(\n 'Search query to filter places by name or address. For POI categories do not use query but use poiCategories.',\n ),\n where: whereSchema.optional().describe('Geographic scope for the search. Defaults to \"within-map-bounds\".'),\n radiusMeters: z.number().optional().describe('search radius in meters'),\n limit: z.number().max(100).optional().describe('default: 10 if query is supplied, 50 otherwise'),\n poiCategories: z\n .array(z.string())\n .optional()\n .describe(\n 'POI category codes for filtering in CONSTANT_CASE. Call getPoiCategoryCodes first to resolve natural language (e.g. \"gym\", \"restaurant\", \"aparcamiento\") into codes.',\n ),\n show: showPlacesSchema.optional().describe('Options to render the results on the map.'),\n withinRange: z\n .string()\n .optional()\n .describe(\n '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.',\n ),\n })\n // Runtime guard only — .refine() doesn't emit JSON Schema, so LLMs won't see this constraint.\n // The LLM-facing constraint is in the withinRange description (\"Mutually exclusive with where\").\n .refine((data) => !(data.withinRange && data.where), {\n message: 'withinRange and where are mutually exclusive — provide one or the other, not both.',\n });\n\nexport const discoverPlacesDescription =\n 'Search for multiple places by text query or POI category. ' +\n 'Stores results as a new places entry and returns its `placesEntryId`. ' +\n '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. ' +\n 'Defaults to searching within the current map viewport; pass `where` to override. ' +\n 'Query is optional — omit it to search by categories only. ' +\n 'For a single specific place, use locatePlace instead.';\n\ntype WhereBias = { boundingBox?: HasBBox; position?: Position };\n\nconst searchInRange = async (\n state: ToolState,\n withinRange: string,\n query: string | undefined,\n limit: number | undefined,\n poiCategories: string[] | undefined,\n): Promise<{ result: Awaited<ReturnType<typeof search>>; placesEntryId: string } | { error: string }> => {\n const rangeEntry = state.ranges.entries.find((e) => e.id === withinRange);\n if (!rangeEntry?.polygon) {\n return { error: `Range \"${withinRange}\" not found. Use recallRanges to list available ranges.` };\n }\n const resolvedPoiCategories = await resolvePoiCategories(poiCategories);\n const result = await search({\n query,\n limit: limit ?? (query ? 10 : 50),\n poiCategories: resolvedPoiCategories,\n geometries: [rangeEntry.polygon],\n });\n const placesEntryId = state.places.addPlaceResult(result, makePlacesLabel(result, { query, poiCategories }));\n return { result, placesEntryId };\n};\n\nconst resolveWhereBias = async (\n where: z.infer<typeof whereSchema> | undefined,\n state: ToolState,\n): Promise<WhereBias> => {\n const resolvedWhere = where ?? 'within-map-bounds';\n\n if (resolvedWhere === 'within-map-bounds') {\n return { boundingBox: getViewportBoundingBox(state.baseMap) };\n }\n if (resolvedWhere === 'nearby-map-center') {\n const position = getViewportBias(state.baseMap);\n return position ? { position } : {};\n }\n if (resolvedWhere === 'global') {\n return {};\n }\n if (typeof resolvedWhere === 'string') {\n const geoResult = await searchOne(resolvedWhere);\n if (geoResult?.bbox) return { boundingBox: geoResult.bbox };\n if (geoResult) {\n const pos = getPosition(geoResult);\n if (pos) return { position: pos };\n }\n return {};\n }\n if ('position' in resolvedWhere) {\n return { position: resolvedWhere.position as Position };\n }\n return { boundingBox: bboxFromGeoJSON(resolvedWhere.boundingBox as HasBBox) as HasBBox };\n};\n\nconst resolveWhereLabel = (where: z.infer<typeof whereSchema> | undefined): string | undefined =>\n typeof where === 'string' && where !== 'within-map-bounds' && where !== 'nearby-map-center' && where !== 'global'\n ? where\n : undefined;\n\nconst searchWithBias = async (\n state: ToolState,\n query: string | undefined,\n where: z.infer<typeof whereSchema> | undefined,\n limit: number | undefined,\n poiCategories: string[] | undefined,\n radiusMeters: number | undefined,\n): Promise<{ result: Awaited<ReturnType<typeof search>>; placesEntryId: string }> => {\n const biasParams = await resolveWhereBias(where, state);\n const resolvedPoiCategories = await resolvePoiCategories(poiCategories);\n const result = await search({\n query,\n limit: limit ?? (query ? 10 : 50),\n poiCategories: resolvedPoiCategories,\n ...biasParams,\n radiusMeters,\n });\n const placesEntryId = state.places.addPlaceResult(\n result,\n makePlacesLabel(result, { query, poiCategories, where: resolveWhereLabel(where) }),\n );\n return { result, placesEntryId };\n};\n\n/**\n * Create the discover places tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeDiscoverPlaces = async (\n params: z.infer<typeof discoverPlacesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof discoverPlacesOutputSchema>> => {\n const { query, where, radiusMeters, limit, poiCategories, show, withinRange } = params;\n\n try {\n let result: Awaited<ReturnType<typeof search>>;\n let placesEntryId: string;\n\n if (withinRange) {\n const rangeResult = await searchInRange(state, withinRange, query, limit, poiCategories);\n if ('error' in rangeResult) return rangeResult;\n result = rangeResult.result;\n placesEntryId = rangeResult.placesEntryId;\n } else {\n const biasResult = await searchWithBias(state, query, where, limit, poiCategories, radiusMeters);\n result = biasResult.result;\n placesEntryId = biasResult.placesEntryId;\n }\n\n const shown = show ? await showResultsOnMap(state, result, placesEntryId, show) : undefined;\n const label = state.places.entries.find((entry) => entry.id === placesEntryId)?.label;\n\n return {\n ...summarizePlaces(result),\n placesEntryId,\n ...(label && { label }),\n ...(shown && { shown }),\n };\n } catch (error) {\n return {\n error: `Search failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { Place, PolygonFeatures } from '@tomtom-org/maps-sdk/core';\nimport type { GeometryTheme } from '@tomtom-org/maps-sdk/map';\nimport type { BudgetType, ReachableRangeParams } from '@tomtom-org/maps-sdk/services';\nimport { calculateReachableRanges } from '@tomtom-org/maps-sdk/services';\nimport { Position } from 'geojson';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makeRangeLabel } from '../../utils';\nimport { locationInputSchema } from '../shared';\nimport { toolErrorSchema } from '../shared-output-schemas';\nimport { resolveLocationInput } from './resolve-location-input';\n\nexport const budgetSchema = z.object({\n type: z\n .enum(['timeMinutes', 'distanceKM']) // TODO: 'remainingChargeCPT', 'spentChargePCT', 'spentFuelLiters' these need vehicle data\n .describe('Budget type including its unit.'),\n value: z.number().describe('Budget value. e.g. 30 for 30 minutes, 50 for 50 km.'),\n});\n\nexport const findReachableAreaSchema = z.object({\n origin: locationInputSchema.describe('Starting point for the range calculation.'),\n budgets: z\n .array(budgetSchema)\n .min(1)\n .describe(\n 'One or more budget constraints. Pass multiple for nested ranges (e.g. 10, 20, 30 min or km). Order does not matter — sorted internally.',\n ),\n theme: z\n .enum(['filled', 'inverted', 'outline'])\n .optional()\n .describe(\n '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.',\n ),\n showOnMap: z.boolean().describe('Whether to render the range polygon(s) on the map.'),\n showOriginPin: z.boolean().optional().describe('Whether to drop a pin at the origin. Default: true.'),\n});\n\nconst rangeOutputSchema = z.object({\n rangeId: z.string(),\n originName: z.string(),\n budgets: z.array(budgetSchema),\n});\n\nexport const findReachableAreaOutputSchema = z.union([\n rangeOutputSchema,\n z.object({ status: z.enum(['not_found', 'no_results']) }),\n toolErrorSchema,\n]);\n\nexport const findReachableAreaDescription =\n 'Find the reachable area (isochrone/isodistance polygon) from an origin within time or distance budgets. ' +\n 'Pass multiple budgets for nested ranges (e.g. 10/20/30 min or 10/25/50 km). ' +\n 'Results stored in state; use recallRanges to retrieve. ' +\n 'showOnMap renders the polygons on the map. ' +\n 'status: not_found if origin cannot be resolved; no_results if API returns empty geometry.';\n\nconst computeReachableRanges = async (budgets: z.infer<typeof budgetSchema>[], origin: Position) => {\n const paramsArray: ReachableRangeParams[] = budgets.map((b) => ({\n origin,\n budget: { type: b.type as BudgetType, value: b.value },\n }));\n const result = await calculateReachableRanges(paramsArray);\n return result.features.length === 0 ? null : result;\n};\n\nconst displayRangeResults = async (\n state: ToolState,\n result: PolygonFeatures,\n theme: GeometryTheme,\n position: Position,\n originName: string,\n showOnMap: boolean,\n showOriginPin: boolean,\n) => {\n if (showOnMap) {\n const geomModule = await state.ranges.getGeometriesModule(theme);\n await geomModule.show(result);\n if (result.bbox) {\n state.baseMap.mapLibreMap.fitBounds(result.bbox, {\n padding: 50,\n });\n }\n }\n if (showOriginPin) {\n const originPlace: Place = {\n type: 'Feature',\n id: 'range-origin',\n geometry: { type: 'Point', coordinates: position },\n properties: {\n type: 'Point Address',\n address: { freeformAddress: originName },\n },\n };\n const placesModule = await state.ranges.getPlacesModule();\n await placesModule.show(originPlace);\n }\n};\n\n/** Standalone execute for ToolEntry format. */\nexport const executeFindReachableArea = async (\n params: z.infer<typeof findReachableAreaSchema>,\n state: ToolState,\n): Promise<z.infer<typeof findReachableAreaOutputSchema>> => {\n const { origin, budgets, theme, showOnMap, showOriginPin = true } = params;\n\n try {\n const resolved = await resolveLocationInput(origin);\n if (!resolved) return { status: 'not_found' };\n const { position, name: originName, query: originQuery } = resolved;\n\n const sortedBudgets = [...budgets].sort((a, b) => b.value - a.value);\n\n const result = await computeReachableRanges(sortedBudgets, position);\n if (!result) return { status: 'no_results' };\n\n const resolvedTheme = theme ?? 'outline';\n\n const originEntry = originQuery ? { query: originQuery, position } : { position };\n const rangeId = state.ranges.addEntry({\n label: makeRangeLabel(sortedBudgets, originName),\n origin: originEntry,\n budgets: sortedBudgets,\n polygon: result,\n });\n\n await displayRangeResults(state, result, resolvedTheme, position, originName, showOnMap, showOriginPin);\n\n return { rangeId, originName, budgets: sortedBudgets };\n } catch (error) {\n return {\n error: `Reachable area calculation failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport { geocodeOne } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makePlacesLabel } from '../../utils/state-labels';\nimport { summarizePlace } from '../../utils/summarize';\nimport { placeOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\n/**\n * Tool schema for geocoding (address to coordinates).\n */\nexport const geocodeSchema = z.object({\n query: z\n .string()\n .describe(\n 'Street or postal address to geocode. Do not use for landmarks, POIs, venues, stations, cities, neighborhoods, or general place-name queries.',\n ),\n waypointIndex: z.number().int().min(0).optional().describe('0=origin, last=destination, middle=stop'),\n});\n\n/** Output schema for the geocode tool. */\nexport const geocodeOutputSchema = z.union([\n placeOutputSchema.extend({\n waypointIndex: z.number().optional(),\n }),\n toolErrorSchema,\n]);\n\nexport const geocodeDescription =\n 'Convert an explicit street or postal address to geographic coordinates without showing anything on the map. ' +\n 'Use only for address-geocoding workflows. Do not use for landmarks, POIs, venues, stations, cities, neighborhoods, or general place-name queries. ' +\n 'For single-place display use locatePlace with show. For route or other non-display location resolution use locatePlace. ' +\n 'Optionally assigns the resolved address to a waypoint slot.';\n\n/**\n * Create the geocode tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeGeocode = async (\n params: z.infer<typeof geocodeSchema>,\n state: ToolState,\n): Promise<z.infer<typeof geocodeOutputSchema>> => {\n const { query, waypointIndex } = params;\n try {\n const result = await geocodeOne(query);\n\n if (!result) {\n return { error: `No result found for \"${query}\"` };\n }\n\n state.places.addPlaceResult(result, makePlacesLabel(result, { query }));\n\n if (waypointIndex !== undefined) {\n state.routing.setWaypointAt(waypointIndex, result as unknown as WaypointLike);\n }\n\n return {\n ...summarizePlace(result),\n ...(waypointIndex !== undefined && { waypointIndex }),\n };\n } catch (error) {\n return { error: `Geocoding failed: ${error instanceof Error ? error.message : String(error)}` };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { type Language } from '@tomtom-org/maps-sdk/core';\nimport { getPOICategoryCodes } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-poi-category-codes tool. */\nexport const getPoiCategoryCodesOutputSchema = z.union([\n z.object({\n count: z.number().describe('Number of codes returned'),\n codes: z\n .array(z.string())\n .describe(\n 'POICategory enum values for discoverPlaces poiCategories. Generic codes (e.g. \"RESTAURANT\") also accepted by togglePOIs categories.',\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool input schema for fetching POI category codes.\n */\nexport const getPoiCategoryCodesSchema = z.object({\n filters: z\n .array(z.string())\n .optional()\n .describe(\n 'Case-insensitive filter strings matched against category names and synonyms. Omit to return all codes.',\n ),\n language: z.string().describe('Locale e.g. \"en-GB\", \"fr-FR\", \"es-ES\", \"de-DE\".'),\n});\n\nexport const getPoiCategoryCodesDescription =\n '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.';\n\n/**\n * Create the get-poi-category-codes tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeGetPoiCategoryCodes = async (\n params: z.infer<typeof getPoiCategoryCodesSchema>,\n _state: ToolState,\n): Promise<z.infer<typeof getPoiCategoryCodesOutputSchema>> => {\n const { filters, language } = params;\n try {\n const codes = await getPOICategoryCodes({\n filters,\n language: language as Language,\n });\n return {\n count: codes.length,\n codes,\n };\n } catch (error) {\n return {\n error: `Failed to fetch POI category codes: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, type Place, type TrafficAreaAnalytics } from '@tomtom-org/maps-sdk/core';\nimport type { TrafficAreaAnalyticsParams } from '@tomtom-org/maps-sdk/services';\nimport { geometryData, trafficAreaAnalytics } from '@tomtom-org/maps-sdk/services';\nimport type { MultiPolygon, Polygon } from 'geojson';\nimport type { LngLatBoundsLike } from 'maplibre-gl';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { locationInputSchema } from '../shared';\nimport { toolErrorSchema } from '../shared-output-schemas';\nimport { resolveLocationInput } from './resolve-location-input';\n\n// ---------------------------------------------------------------------------\n// Constants (inline — the SDK only type-exports these)\n// ---------------------------------------------------------------------------\n\nconst METRICS = ['speed', 'congestionLevel', 'freeFlowSpeed', 'travelTime', 'networkLength'] as const;\n\nconst FUNCTIONAL_ROAD_CLASSES = [\n 'MOTORWAY',\n 'MAJOR_ROAD',\n 'OTHER_MAJOR_ROAD',\n 'SECONDARY_ROAD',\n 'LOCAL_CONNECTING_ROAD',\n 'LOCAL_ROAD_HIGH_IMPORTANCE',\n 'LOCAL_ROAD',\n 'LOCAL_ROAD_MINOR_IMPORTANCE',\n 'OTHER_ROAD',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Schemas\n// ---------------------------------------------------------------------------\n\nexport const metricsSchema = z.object({\n speed: z.number().optional(),\n freeFlowSpeed: z.number().optional(),\n congestionLevel: z.number().optional(),\n travelTime: z.number().optional(),\n networkLength: z.number().optional(),\n});\n\n/** Output schema for the get-traffic-area-analytics tool. */\nexport const getTrafficAreaAnalyticsOutputSchema = z.union([\n z.object({\n name: z.string().optional(),\n timezone: z.string().optional(),\n dateRange: z.object({ start: z.string(), end: z.string() }),\n baseData: metricsSchema,\n metrics: z.array(z.string()),\n tileCount: z.number(),\n availableGranularities: z.array(z.string()),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for fetching traffic area analytics.\n */\nexport const getTrafficAreaAnalyticsSchema = z.object({\n location: locationInputSchema\n .optional()\n .describe(\n 'Named location (city, region, country) to fetch the boundary for. Resolved via geocoding + geometryData. Mutually exclusive with bbox and geometry.',\n ),\n bbox: z\n .array(z.number())\n .length(4)\n .optional()\n .describe(\n '[minLng, minLat, maxLng, maxLat] — use a wide area (at least 5-10km across, city-level) for meaningful results. Mutually exclusive with location.',\n ),\n showOnMap: z\n .boolean()\n .optional()\n .describe('Visualize the result immediately with default settings. Use showTrafficAreaAnalytics to customize.'),\n startDate: z\n .string()\n .optional()\n .describe(\"Start date 'YYYY-MM-DD'. Use with endDate for a continuous range (max 31 days).\"),\n endDate: z.string().optional().describe(\"End date 'YYYY-MM-DD' (inclusive). Defaults to today if omitted.\"),\n days: z\n .array(z.string())\n .optional()\n .describe(\n \"Specific dates 'YYYY-MM-DD' for non-consecutive analysis. Mutually exclusive with startDate/endDate.\",\n ),\n metrics: z\n .union([z.literal('all'), z.array(z.enum([...METRICS])).min(1)])\n .describe(\n \"Traffic metrics to analyze. Use 'all' (preferred) or an explicit array like ['speed', 'congestionLevel', 'freeFlowSpeed', 'travelTime', 'networkLength'].\",\n ),\n functionalRoadClasses: z\n .union([z.literal('all'), z.array(z.enum([...FUNCTIONAL_ROAD_CLASSES]))])\n .optional()\n .describe(\"Road classes to include. 'all' (default) or array of specific classes.\"),\n hours: z\n .union([z.literal('all'), z.array(z.number().int().min(0).max(23))])\n .optional()\n .describe(\"Hours of the day (0-23) to include. 'all' (default) or array like [7,8,9,17,18] for rush hours.\"),\n});\n\nexport const getTrafficAreaAnalyticsDescription =\n 'Fetch historical traffic analytics for a geographic area (max 31 days). ' +\n 'Provide area via location (named city/region, resolved to boundary polygon) or bbox. ' +\n 'Fetch all metrics in a single call — visualization requires all metrics in one result. ' +\n 'Use city-level areas (~10km+) for meaningful data. ' +\n 'Returns period averages. Use showOnMap to visualize immediately, queryTrafficAnalytics for breakdowns.';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// Convert [minLng, minLat, maxLng, maxLat] to a GeoJSON Polygon.\nconst bboxToPolygon = (bbox: number[]): Polygon => {\n const [minLng, minLat, maxLng, maxLat] = bbox;\n return {\n type: 'Polygon',\n coordinates: [\n [\n [minLng, minLat],\n [maxLng, minLat],\n [maxLng, maxLat],\n [minLng, maxLat],\n [minLng, minLat],\n ],\n ],\n };\n};\n\n// Resolve the analytics area geometry from a location query or bbox.\nconst resolveGeometry = async (\n location: z.infer<typeof locationInputSchema> | undefined,\n bbox: number[] | undefined,\n): Promise<Polygon | MultiPolygon | { error: string }> => {\n if (location) {\n const resolved = await resolveLocationInput(location);\n if (!resolved) return { error: 'Could not resolve the provided location.' };\n if (Array.isArray(resolved.place)) {\n return {\n error: 'A bare position cannot define an analytics area. Provide a named location query instead.',\n };\n }\n // resolved.place is a Place at runtime (locatePlace always returns Place | null)\n const boundary = await geometryData({ geometries: [resolved.place as unknown as Place] });\n const boundaryGeometry = boundary?.features?.[0]?.geometry as Polygon | MultiPolygon | undefined;\n if (!boundaryGeometry) {\n return { error: `No boundary polygon found for \"${resolved.name}\". Try a bbox instead.` };\n }\n return boundaryGeometry;\n }\n if (!bbox) return { error: 'No area provided.' };\n return bboxToPolygon(bbox);\n};\n\n// Resolve which date parameters to forward to the SDK from the tool inputs.\nconst resolveDateParams = (\n days: string[] | undefined,\n startDate: string | undefined,\n endDate: string | undefined,\n): { startDate?: string; endDate?: string; days?: string[] } => {\n if (days && days.length > 0) return { days };\n if (startDate) return endDate ? { startDate, endDate } : { startDate };\n return {};\n};\n\n// Show analytics on the map with default settings, fitting the viewport.\nconst showAnalyticsOnMap = async (state: ToolState, result: TrafficAreaAnalytics): Promise<void> => {\n const analyticsModule = await state.traffic.getTrafficAreaAnalyticsModule();\n await analyticsModule.clear();\n await analyticsModule.show(result);\n const defaultMetric = result.properties?.metrics?.[0] ?? 'congestionLevel';\n analyticsModule.setMetric(defaultMetric);\n const bbox = bboxFromGeoJSON(result.features);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox as LngLatBoundsLike, { padding: 50, pitch: 45 });\n }\n state.traffic.onAnalyticsShown?.(result, analyticsModule);\n};\n\n/** Format a Date to 'YYYY-MM-DD'. */\nexport const toDateString = (d: Date): string =>\n `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n\n/** Safely format a date value (Date object or string) to 'YYYY-MM-DD', or undefined if invalid. */\nexport const formatDate = (value: unknown): string | undefined => {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? undefined : toDateString(value);\n }\n if (typeof value === 'string') return value.slice(0, 10);\n return undefined;\n};\n\n/** Extract metrics from a timed entry, omitting undefined values. */\nexport const extractMetrics = (entry: Record<string, unknown>) => ({\n ...(entry.speed !== undefined && { speed: entry.speed as number }),\n ...(entry.freeFlowSpeed !== undefined && { freeFlowSpeed: entry.freeFlowSpeed as number }),\n ...(entry.congestionLevel !== undefined && { congestionLevel: entry.congestionLevel as number }),\n ...(entry.travelTime !== undefined && { travelTime: entry.travelTime as number }),\n ...(entry.networkLength !== undefined && { networkLength: entry.networkLength as number }),\n});\n\n/** Compact summary of the analytics result — just headline numbers + what's available for drill-down. */\nconst summarize = (\n result: TrafficAreaAnalytics,\n inputStartDate?: string,\n inputEndDate?: string,\n): z.infer<typeof getTrafficAreaAnalyticsOutputSchema> => {\n const region = result.features[0]?.properties;\n if (!region) {\n return {\n dateRange: { start: '', end: '' },\n baseData: {},\n metrics: [],\n tileCount: 0,\n availableGranularities: [],\n };\n }\n\n // SDK defaults to startDate=3 days ago, endDate=2 days ago when omitted\n const defaultStart = () => {\n const d = new Date();\n d.setDate(d.getDate() - 3);\n return toDateString(d);\n };\n const defaultEnd = () => {\n const d = new Date();\n d.setDate(d.getDate() - 2);\n return toDateString(d);\n };\n\n const start = inputStartDate ?? formatDate(result.properties?.startDate) ?? defaultStart();\n const end = inputEndDate ?? formatDate(result.properties?.endDate) ?? defaultEnd();\n\n const availableGranularities: string[] = [];\n if (region.timedData?.yearly?.length) availableGranularities.push('yearly');\n if (region.timedData?.monthly?.length) availableGranularities.push('monthly');\n if (region.timedData?.weekly?.length) availableGranularities.push('weekly');\n if (region.timedData?.daily?.length) availableGranularities.push('daily');\n if (region.timedData?.hourly?.length) availableGranularities.push('hourly');\n if (region.timedData?.average?.length) availableGranularities.push('average');\n\n return {\n ...(region.name && { name: region.name }),\n ...(region.timezone && { timezone: region.timezone }),\n dateRange: { start, end },\n baseData: region.baseData,\n metrics: result.properties?.metrics ?? [],\n tileCount: region.tiledData?.tiles?.length ?? 0,\n availableGranularities,\n };\n};\n\n// ---------------------------------------------------------------------------\n// Tool factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create the get traffic area analytics tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeGetTrafficAreaAnalytics = async (\n params: z.infer<typeof getTrafficAreaAnalyticsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getTrafficAreaAnalyticsOutputSchema>> => {\n const { location, bbox, showOnMap, startDate, endDate, days, metrics, functionalRoadClasses, hours } = params;\n\n if (!location && !bbox) {\n return { error: 'Provide a location or bbox to define the analytics area.' };\n }\n\n // Move Portal API key (different from standard TomTom key)\n const apiKey = process.env.MOVE_PORTAL_KEY;\n if (!apiKey) {\n return { error: 'MOVE_PORTAL_KEY environment variable is not set.' };\n }\n\n try {\n const resolvedGeometry = await resolveGeometry(location, bbox);\n if ('error' in resolvedGeometry) return resolvedGeometry;\n\n // Resolve dates — SDK defaults to startDate=3 days ago, endDate=2 days ago when omitted\n const dateParams = resolveDateParams(days, startDate, endDate);\n\n const result = await trafficAreaAnalytics({\n apiKey,\n ...dateParams,\n metrics,\n functionalRoadClasses: functionalRoadClasses ?? 'all',\n hours: hours ?? 'all',\n geometry: resolvedGeometry,\n } as TrafficAreaAnalyticsParams);\n\n state.traffic.setLastAreaAnalytics(result);\n\n if (showOnMap) {\n await showAnalyticsOnMap(state, result);\n }\n\n return summarize(result, dateParams.startDate, dateParams.endDate);\n } catch (error) {\n return {\n error: `Failed to get traffic area analytics: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { BBox } from '@tomtom-org/maps-sdk/core';\nimport { trafficIncidentCategories } from '@tomtom-org/maps-sdk/core';\nimport { trafficIncidentDetails } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-traffic-incidents tool. */\nexport const getTrafficIncidentsOutputSchema = z.union([\n z.object({\n count: z.number(),\n incidents: z.array(\n z.object({\n id: z.string(),\n category: z.string(),\n magnitudeOfDelay: z.string().describe('unknown|minor|moderate|major|indefinite'),\n timeValidity: z.string().describe('present|future'),\n events: z.array(\n z.object({\n description: z.string(),\n category: z.string(),\n }),\n ),\n from: z.string().optional(),\n to: z.string().optional(),\n roadNumbers: z.array(z.string()).optional(),\n lengthInMeters: z.number().optional(),\n delayInSeconds: z.number().optional(),\n startTime: z.date().optional(),\n endTime: z.date().optional(),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for fetching traffic incident details.\n */\nexport const getTrafficIncidentsSchema = z.object({\n bbox: z.optional(z.array(z.number())).describe('[minLng, minLat, maxLng, maxLat]'),\n ids: z.array(z.string()).optional().describe('Up to 100 incident IDs'),\n categoryFilter: z\n .array(z.enum([...trafficIncidentCategories]))\n .optional()\n .describe('Filter by incident category. If omitted, all categories are returned.'),\n timeValidityFilter: z\n .array(z.enum(['present', 'future']))\n .optional()\n .describe(\"default: ['present']\"),\n});\n\nexport const getTrafficIncidentsDescription =\n '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.';\n\n/**\n * Create the get traffic incidents tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeGetTrafficIncidents = async (\n params: z.infer<typeof getTrafficIncidentsSchema>,\n _state: ToolState,\n): Promise<z.infer<typeof getTrafficIncidentsOutputSchema>> => {\n const { bbox, ids, categoryFilter, timeValidityFilter } = params;\n\n if (!bbox && !ids) {\n return { error: 'Provide either a bbox or a list of ids' };\n }\n\n try {\n const filters = {\n ...(categoryFilter && { categoryFilter }),\n ...(timeValidityFilter && { timeValidityFilter }),\n };\n const result = await trafficIncidentDetails(\n bbox ? { ...filters, bbox: bbox as BBox } : { ...filters, ids: ids as string[] },\n );\n\n if (!result.features.length) {\n return { count: 0, incidents: [] };\n }\n\n return {\n count: result.features.length,\n incidents: result.features.map((feature) => {\n const p = feature.properties;\n return {\n id: p.id,\n category: p.category,\n magnitudeOfDelay: p.magnitudeOfDelay,\n timeValidity: p.timeValidity,\n events: p.events.map((e) => ({ description: e.description, category: e.category })),\n from: p.from,\n to: p.to,\n roadNumbers: p.roadNumbers,\n lengthInMeters: p.lengthInMeters,\n delayInSeconds: p.delayInSeconds,\n startTime: p.startTime,\n endTime: p.endTime,\n };\n }),\n };\n } catch (error) {\n return {\n error: `Failed to get traffic incidents: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\nimport { extractMetrics, formatDate, metricsSchema, toDateString } from './get-traffic-area-analytics';\n\n// ---------------------------------------------------------------------------\n// Schemas\n// ---------------------------------------------------------------------------\n\nconst timedEntrySchema = metricsSchema.extend({\n date: z.string().optional(),\n hour: z.number().optional(),\n year: z.number().optional(),\n month: z.number().optional(),\n week: z.number().optional(),\n day: z.number().optional(),\n});\n\nexport const queryTrafficAnalyticsSchema = z.object({\n granularity: z\n .enum(['daily', 'hourly', 'weekly', 'monthly', 'yearly', 'average'])\n .optional()\n .describe(\"Time granularity. Default: 'daily'. Use 'average' for day-of-week × hour patterns.\"),\n metric: z\n .enum(['speed', 'congestionLevel', 'freeFlowSpeed', 'travelTime', 'networkLength'])\n .optional()\n .describe('Filter to a single metric. Default: all requested metrics.'),\n startDate: z\n .string()\n .optional()\n .describe(\"Filter entries from this date (YYYY-MM-DD). Works with 'daily' and 'hourly'.\"),\n endDate: z\n .string()\n .optional()\n .describe(\"Filter entries up to this date (YYYY-MM-DD). Works with 'daily' and 'hourly'.\"),\n hourStart: z\n .number()\n .int()\n .min(0)\n .max(23)\n .optional()\n .describe('Filter hourly/average entries from this hour (0-23).'),\n hourEnd: z\n .number()\n .int()\n .min(0)\n .max(23)\n .optional()\n .describe('Filter hourly/average entries up to this hour (0-23).'),\n dayOfWeek: z\n .array(z.number().int().min(1).max(7))\n .optional()\n .describe(\"Filter 'average' entries by day of week (1=Mon…7=Sun).\"),\n});\n\n/** Output schema for the query-traffic-analytics tool. */\nexport const queryTrafficAnalyticsOutputSchema = z.union([\n z.object({\n granularity: z.string(),\n count: z.number(),\n entries: z.array(timedEntrySchema),\n currentVisualization: z\n .object({\n activeMetric: z.string().optional(),\n displayMode: z.string().optional(),\n })\n .optional(),\n }),\n toolErrorSchema,\n]);\n\nexport const queryTrafficAnalyticsDescription =\n 'Query cached traffic analytics (from getTrafficAreaAnalytics) without re-fetching. ' +\n 'Filter by granularity, date range, hour range, day of week, or metric. ' +\n 'Returns filtered entries plus the current visualization state (metric, mode displayed on map). ' +\n 'Use for follow-up questions: breakdowns, patterns, or checking what is currently shown.';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Derive a date string for a daily/hourly entry using index fallback. */\nconst resolveDateStr = (\n entryDate: unknown,\n index: number,\n granularity: string,\n startDateStr?: string,\n): string | undefined => {\n const direct = formatDate(entryDate);\n if (direct) return direct;\n if (startDateStr && index >= 0) {\n const d = new Date(startDateStr);\n if (!Number.isNaN(d.getTime())) {\n const dayOffset = granularity === 'hourly' ? Math.floor(index / 24) : index;\n d.setDate(d.getDate() + dayOffset);\n return toDateString(d);\n }\n }\n return undefined;\n};\n\n// ---------------------------------------------------------------------------\n// Tool factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create the query traffic analytics tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeQueryTrafficAnalytics = async (\n params: z.infer<typeof queryTrafficAnalyticsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof queryTrafficAnalyticsOutputSchema>> => {\n const { granularity = 'daily', metric, startDate, endDate, hourStart, hourEnd, dayOfWeek } = params;\n\n const analytics = state.traffic.lastAreaAnalytics;\n if (!analytics) {\n return { error: 'No analytics data cached. Call getTrafficAreaAnalytics first.' };\n }\n\n const region = analytics.features[0]?.properties;\n if (!region) {\n return { error: 'Analytics result has no region data.' };\n }\n\n const timedData = region.timedData;\n const rawEntries = timedData?.[granularity as keyof typeof timedData];\n if (!rawEntries || !Array.isArray(rawEntries) || rawEntries.length === 0) {\n return {\n error: `No '${granularity}' data available. Available: ${Object.keys(timedData ?? {}).join(', ')}`,\n };\n }\n\n // Resolve start date for index-based date derivation\n const collectionStartDate = formatDate(analytics.properties?.startDate);\n\n // Map and filter entries\n let entries = rawEntries.map((entry, index) => {\n const mapped: Record<string, unknown> = {};\n\n // Temporal fields\n if (granularity === 'daily' || granularity === 'hourly') {\n const dateStr = resolveDateStr(entry.date, index, granularity, collectionStartDate);\n if (dateStr) mapped.date = dateStr;\n }\n if (entry.hour !== undefined) mapped.hour = entry.hour;\n if (entry.year !== undefined) mapped.year = entry.year;\n if (entry.month !== undefined) mapped.month = entry.month;\n if (entry.week !== undefined) mapped.week = entry.week;\n if (entry.day !== undefined) mapped.day = entry.day;\n\n // Metrics\n if (metric) {\n const val = (entry as Record<string, unknown>)[metric];\n if (val !== undefined) mapped[metric] = val;\n } else {\n Object.assign(mapped, extractMetrics(entry));\n }\n\n return mapped;\n });\n\n // Apply date range filter (daily/hourly)\n if (startDate) {\n entries = entries.filter((e) => !e.date || (e.date as string) >= startDate);\n }\n if (endDate) {\n entries = entries.filter((e) => !e.date || (e.date as string) <= endDate);\n }\n\n // Apply hour range filter (hourly/average)\n if (hourStart !== undefined) {\n entries = entries.filter((e) => e.hour === undefined || (e.hour as number) >= hourStart);\n }\n if (hourEnd !== undefined) {\n entries = entries.filter((e) => e.hour === undefined || (e.hour as number) <= hourEnd);\n }\n\n // Apply day-of-week filter (average)\n if (dayOfWeek && dayOfWeek.length > 0) {\n entries = entries.filter((e) => e.day === undefined || dayOfWeek.includes(e.day as number));\n }\n\n // Include current visualization state so LLM knows what's displayed\n const vizConfig = state.traffic.currentAnalyticsConfig;\n const currentVisualization = vizConfig\n ? {\n activeMetric: vizConfig.activeMetric,\n displayMode: vizConfig.displayMode,\n }\n : undefined;\n\n return {\n granularity,\n count: entries.length,\n entries: entries as z.infer<typeof timedEntrySchema>[],\n ...(currentVisualization && { currentVisualization }),\n };\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { calculateRoute } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makeRoutesLabel } from '../../utils/state-labels';\nimport { summarizeRoutes } from '../../utils/summarize';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\nimport { buildCalculateRouteParams, resolveRouteWaypoints, showRouteOnMap } from './set-route-locations';\n\n/** Output schema for the remove-stop-from-route tool. */\nexport const removeStopFromRouteOutputSchema = z.union([routesOutputSchema, toolErrorSchema]);\n\n/**\n * Tool schema for removing a stop from an existing route.\n */\nexport const removeStopFromRouteSchema = z.object({\n stopIndex: z.number().int().describe('0=origin, last=destination; min 2 waypoints must remain'),\n showOnMap: z.boolean().describe('Show the updated route and waypoints on the map after recalculation.'),\n});\n\nexport const removeStopFromRouteDescription =\n 'Remove a stop from the current route by index and always triggers a route recalculation. ' +\n 'Index 0 is the origin, last index is the destination — both must remain. ' +\n 'Requires an existing route (call setRouteLocations first).';\n\nconst validateRemoveStop = <T>(waypoints: T[] | null | undefined, stopIndex: number): string | T[] => {\n if (!waypoints || waypoints.length < 2) {\n return 'No existing waypoints available. Use calculate-route first to create a route with waypoints.';\n }\n if (stopIndex < 0 || stopIndex >= waypoints.length) {\n return `Invalid stop index ${stopIndex}. Valid range is 0 to ${waypoints.length - 1}.`;\n }\n if (waypoints.length <= 2) {\n return 'Cannot remove a stop: at least 2 waypoints (origin and destination) must remain.';\n }\n return waypoints;\n};\n\n/**\n * Create the remove stop from route tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeRemoveStopFromRoute = async (\n params: z.infer<typeof removeStopFromRouteSchema>,\n state: ToolState,\n): Promise<z.infer<typeof removeStopFromRouteOutputSchema>> => {\n const { stopIndex, showOnMap } = params;\n try {\n const validated = validateRemoveStop(state.routing.currentWaypoints, stopIndex);\n if (typeof validated === 'string') return { error: validated };\n\n const updatedWaypointsPlaces = validated.filter((_, i) => i !== stopIndex);\n\n const waypoints = resolveRouteWaypoints(updatedWaypointsPlaces);\n if (!waypoints) {\n return { error: 'Not enough valid waypoints to calculate a route (minimum 2).' };\n }\n\n const routes = await calculateRoute({\n locations: waypoints,\n ...buildCalculateRouteParams(state.routing.params),\n });\n\n state.routing.addRoutes(routes, waypoints, makeRoutesLabel(routes, waypoints));\n\n if (showOnMap) {\n await showRouteOnMap(state, routes, waypoints);\n }\n\n return summarizeRoutes(routes);\n } catch (error) {\n return {\n error: `Failed to remove stop from route: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { reverseGeocode } from '@tomtom-org/maps-sdk/services';\nimport type { Position } from 'geojson';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makePlacesLabel } from '../../utils/state-labels';\nimport { summarizePlace } from '../../utils/summarize';\nimport { placeOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the reverse-geocode tool. */\nexport const reverseGeocodeOutputSchema = z.union([placeOutputSchema, toolErrorSchema]);\n\n/**\n * Tool schema for reverse geocoding (coordinates to address).\n */\nexport const reverseGeocodeSchema = z.object({\n position: z.array(z.number()).length(2).describe('[longitude, latitude] GeoJSON position to reverse geocode'),\n});\n\nexport const reverseGeocodeDescription =\n 'Convert a [longitude, latitude] position to an address and normalized place summary. ' +\n 'Use after a map click, getViewport, getCurrentLocation, or any tool that returns coordinates. ' +\n 'Does NOT search by name — use locatePlace or discoverPlaces for text queries.';\n\n/**\n * Create the reverse geocode tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeReverseGeocode = async (\n params: z.infer<typeof reverseGeocodeSchema>,\n state: ToolState,\n): Promise<z.infer<typeof reverseGeocodeOutputSchema>> => {\n const { position } = params;\n const pos: Position = position as Position;\n try {\n const result = await reverseGeocode({ position: pos });\n\n if (result) {\n state.places.addPlaceResult(result, makePlacesLabel(result));\n return summarizePlace(result);\n }\n\n return { error: 'No result found for the given coordinates' };\n } catch (error) {\n return {\n error: `Reverse geocoding failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { alongRouteSearch } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makePlacesLabel } from '../../utils/state-labels';\nimport { summarizePlaces } from '../../utils/summarize';\nimport { resolvePoiCategories, shownSchema, showPlacesSchema, showResultsOnMap } from '../shared';\nimport { placesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\nconst noRouteSchema = z.object({ status: z.literal('no_route') });\n\nexport const searchAlongRouteOutputSchema = z.union([\n placesOutputSchema.extend({\n placesEntryId: z.string(),\n shown: shownSchema.optional(),\n }),\n noRouteSchema,\n toolErrorSchema,\n]);\n\nexport const searchAlongRouteSchema = z.object({\n query: z.string().optional().describe('Search query to filter POIs by name.'),\n poiCategories: z\n .array(z.string())\n .optional()\n .describe('POI category codes in CONSTANT_CASE. Call getPoiCategoryCodes to resolve natural-language names.'),\n routeId: z\n .string()\n .optional()\n .describe(\n 'Stable route entry ID (e.g. \"routes-1\"). Use recallRoutes to find the right ID; defaults to the most recent route.',\n ),\n maxDetourTimeSeconds: z.number().describe('Maximum detour time in seconds to reach a POI from the route.'),\n sortBy: z.enum(['detourTime', 'detourOffset']).optional().describe('Default: detourTime.'),\n limit: z.number().max(100).optional().describe('Max results. Default: 10.'),\n show: showPlacesSchema.optional().describe('Display options to render results on the map after search.'),\n});\n\nexport const searchAlongRouteDescription =\n 'Search for POIs along a calculated route, ranked by detour cost. ' +\n 'Reads the route from state — call setRouteLocations first. ' +\n 'Use recallRoutes to find the ID of a specific route; defaults to the most recent. ' +\n 'Stores results in places history; pass the returned placesEntryId to showPlaces({ id }) to display them. ' +\n 'status: no_route if no route exists in state.';\n\nconst resolveRouteEntry = (state: ToolState, routeId: string | undefined) => {\n const entries = state.routing.entries;\n if (entries.length === 0) return null;\n\n const entry = routeId ? entries.find((e) => e.id === routeId) : entries.at(-1);\n if (!entry) return `No route found with id \"${routeId}\". Use recallRoutes to list available routes.`;\n\n const routeFeature = entry.data.features[0];\n if (!routeFeature) return 'Route entry has no geometry.';\n\n return { entry, routeFeature };\n};\n\nconst executeAlongRouteSearch = async (\n params: {\n query?: string;\n poiCategories?: string[];\n maxDetourTimeSeconds: number;\n sortBy?: 'detourTime' | 'detourOffset';\n limit?: number;\n },\n routeFeature: Parameters<typeof alongRouteSearch>[0]['route'],\n) => {\n const { query, poiCategories, maxDetourTimeSeconds, sortBy, limit } = params;\n const resolvedPoiCategories = await resolvePoiCategories(poiCategories);\n return alongRouteSearch({\n route: routeFeature,\n maxDetourTimeSeconds,\n ...(query && { query }),\n ...(resolvedPoiCategories && { poiCategories: resolvedPoiCategories }),\n ...(sortBy && { sortBy }),\n ...(limit !== undefined && { limit }),\n });\n};\n\n/** Standalone execute for ToolEntry format. */\nexport const executeSearchAlongRoute = async (\n params: z.infer<typeof searchAlongRouteSchema>,\n state: ToolState,\n): Promise<z.infer<typeof searchAlongRouteOutputSchema>> => {\n const { query, poiCategories, routeId, maxDetourTimeSeconds, sortBy, limit, show } = params;\n\n const resolved = resolveRouteEntry(state, routeId);\n if (resolved === null) return { status: 'no_route' };\n if (typeof resolved === 'string') return { error: resolved };\n const { entry, routeFeature } = resolved;\n\n try {\n const result = await executeAlongRouteSearch(\n { query, poiCategories, maxDetourTimeSeconds, sortBy, limit },\n routeFeature,\n );\n\n const label = makePlacesLabel(result, { query, poiCategories, routeLabel: entry.label });\n const placesEntryId = state.places.addPlaceResult(result, label);\n\n const shown = show ? await showResultsOnMap(state, result, placesEntryId, show) : undefined;\n\n return {\n ...summarizePlaces(result),\n placesEntryId,\n ...(shown && { shown }),\n };\n } catch (error) {\n return {\n error: `Along-route search failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { type Avoidable, avoidableTypes } from '@tomtom-org/maps-sdk/core';\nimport { calculateRoute, routeTypes } from '@tomtom-org/maps-sdk/services';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { makeRoutesLabel } from '../../utils/state-labels';\nimport { summarizeRoutes } from '../../utils/summarize';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\nimport { buildCalculateRouteParams, resolveRouteWaypoints, showRouteOnMap } from './set-route-locations';\n\nexport const costModelSchema = z.object({\n routeType: z.enum(routeTypes).optional().describe('fast|short|efficient|thrilling'),\n traffic: z.enum(['live', 'historical']).optional().describe('live|historical'),\n avoid: z\n .array(z.enum(avoidableTypes as unknown as [Avoidable, ...Avoidable[]]))\n .optional()\n .describe(\n 'tollRoads|motorways|ferries|unpavedRoads|carpools|alreadyUsedRoads|borderCrossings|tunnels|carTrains|lowEmissionZones',\n ),\n avoidAreas: z\n .array(z.array(z.number()).describe('GeoJSON bbox [minLng, minLat, maxLng, maxLat]'))\n .max(10)\n .optional()\n .describe('Up to 10 bounding boxes to bypass.'),\n});\n\nexport const whenSchema = z.object({\n option: z.enum(['departAt', 'arriveBy']),\n date: z.string().describe('ISO 8601'),\n});\n\n/** Output schema for set-route-parameters. */\nexport const setRouteParametersOutputSchema = z.union([\n routesOutputSchema,\n z.object({ success: z.literal(true) }),\n toolErrorSchema,\n]);\n\n/** Input schema for set-route-parameters. */\nexport const setRouteParametersSchema = z.object({\n maxAlternatives: z.number().int().min(0).max(5).optional().describe('0–5, default 0'),\n costModel: costModelSchema.optional(),\n when: whenSchema.optional().describe('Omit to depart now.'),\n showOnMap: z.boolean().describe('Show the route and waypoints on the map after recalculation.'),\n});\n\nexport const setRouteParametersDescription =\n 'Set route planning parameters: number of alternatives, cost model (route type, traffic, avoidances), and departure/arrival time. ' +\n 'Triggers a route recalculation automatically if origin and destination are already set. ' +\n 'Can be called in parallel with setRouteLocations. ' +\n 'Only car/driving routes are supported.';\n\n/**\n * Create the set-route-parameters tool.\n */\n/** Standalone execute for ToolEntry format. */\nexport const executeSetRouteParameters = async (\n params: z.infer<typeof setRouteParametersSchema>,\n state: ToolState,\n): Promise<z.infer<typeof setRouteParametersOutputSchema>> => {\n const { showOnMap, ...routeParams } = params;\n try {\n state.routing.setParams(routeParams);\n\n const waypoints = resolveRouteWaypoints(state.routing.planningSlots);\n if (waypoints) {\n const routes = await calculateRoute({\n locations: waypoints,\n ...buildCalculateRouteParams(state.routing.params),\n });\n state.routing.addRoutes(routes, waypoints, makeRoutesLabel(routes, waypoints));\n if (showOnMap) {\n await showRouteOnMap(state, routes, waypoints);\n }\n return summarizeRoutes(routes);\n }\n\n return { success: true };\n } catch (error) {\n return {\n error: `Failed to set route parameters: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { summarizeWaypoint, waypointSummarySchema } from '../../utils/summarize';\n\nexport const getCurrentWaypointsSchema = z.object({\n slotIndex: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Exact waypoint slot to retrieve. Use when you need one known origin/stop/destination slot.'),\n includeEmptySlots: z\n .boolean()\n .optional()\n .describe('Include unfilled slots in the result set. Defaults to false to avoid null-heavy responses.'),\n offset: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Pagination offset within the filtered slot list. Ignored when slotIndex is provided.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(25)\n .optional()\n .describe('Maximum slots to return. Defaults to 5. Ignored when slotIndex is provided.'),\n});\n\nexport const getCurrentWaypointsOutputSchema = z.object({\n totalSlots: z.number().describe('Total waypoint slots currently staged'),\n filledSlots: z.number().describe('Number of staged slots that already contain coordinates'),\n matchedCount: z.number().describe('Total slots matching the request before pagination'),\n returnedCount: z.number().describe('Number of slots returned in this page'),\n offset: z.number().describe('Offset applied to the filtered slot list'),\n hasMore: z.boolean().describe('True when more slots can be fetched with a higher offset'),\n nextOffset: z.number().optional().describe('Offset to request the next page when hasMore=true'),\n waypoints: z.array(waypointSummarySchema),\n});\n\nexport const getCurrentWaypointsDescription =\n 'Read the waypoint slots currently staged for the next route calculation without recalculating anything. ' +\n 'Use for follow-up questions like \"what coordinates are staged now?\", \"which slots are filled?\", or \"what is destination slot 1?\". ' +\n '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. ' +\n 'Does not call any service.';\n\nexport const executeGetCurrentWaypoints = async (\n params: z.infer<typeof getCurrentWaypointsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getCurrentWaypointsOutputSchema>> => {\n const { slotIndex, includeEmptySlots = false, offset = 0, limit = 5 } = params;\n const slots = state.routing.planningSlots.map((waypoint, index) => {\n const normalized = summarizeWaypoint(waypoint);\n return normalized ? { ...normalized, slotIndex: index } : { slotIndex: index, isFilled: false };\n });\n const filteredSlots = includeEmptySlots ? slots : slots.filter((slot) => slot.isFilled);\n const hasExactSlot = slotIndex !== undefined;\n const selected = hasExactSlot\n ? filteredSlots.filter((slot) => slot.slotIndex === slotIndex)\n : filteredSlots.slice(offset, offset + limit);\n const nextOffset = offset + selected.length;\n\n return {\n totalSlots: slots.length,\n filledSlots: slots.filter((slot) => slot.isFilled).length,\n matchedCount: hasExactSlot ? selected.length : filteredSlots.length,\n returnedCount: selected.length,\n offset: hasExactSlot ? 0 : offset,\n hasMore: !hasExactSlot && nextOffset < filteredSlots.length,\n ...(!hasExactSlot && nextOffset < filteredSlots.length && { nextOffset }),\n waypoints: selected,\n };\n};\n","import { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { summarizePlaces } from '../../utils/summarize';\nimport { placesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\nexport const recallPlacesSchema = z.object({\n id: z.string().optional().describe('Entry ID to retrieve (e.g. \"places-3\"). Omit to list all entries.'),\n});\n\nconst indexEntrySchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n});\n\nconst detailSchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n places: placesOutputSchema,\n});\n\nexport const recallPlacesOutputSchema = z.union([\n z.object({ entries: z.array(indexEntrySchema) }),\n detailSchema,\n toolErrorSchema,\n]);\n\nexport const recallPlacesDescription =\n 'Retrieve places and search results from session history. ' +\n 'ALWAYS use this when referencing places from earlier in the session — do not re-search by name. ' +\n 'Returns entries with stable IDs accepted by showPlaces, and exact coordinates usable in setRouteLocations. ' +\n 'Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. ' +\n 'Step 2: call with id to retrieve a specific entry with coordinates. ' +\n 'Does not call any service.';\n\nexport const executeRecallPlaces = async (\n params: z.infer<typeof recallPlacesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof recallPlacesOutputSchema>> => {\n const { id } = params;\n\n if (!id) {\n const entries = [...state.places.entries]\n .reverse()\n .map(({ id, label, timestamp }) => ({ id, label, timestamp }));\n return { entries };\n }\n\n const entry = state.places.entries.find((e) => e.id === id);\n if (!entry) {\n return { error: `No entry found with id \"${id}\"` };\n }\n\n const places = summarizePlaces(entry.data);\n\n return {\n id: entry.id,\n label: entry.label,\n timestamp: entry.timestamp,\n places,\n };\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\nexport const recallRangesSchema = z.object({\n id: z.string().optional().describe('Entry ID to retrieve (e.g. \"ranges-0\"). Omit to list all entries.'),\n});\n\nconst indexEntrySchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n});\n\nconst detailSchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n origin: z.object({\n query: z.string().optional(),\n position: z.tuple([z.number(), z.number()]),\n }),\n budgets: z.array(z.object({ type: z.string(), value: z.number() })),\n});\n\nexport const recallRangesOutputSchema = z.union([\n z.object({ entries: z.array(indexEntrySchema) }),\n detailSchema,\n toolErrorSchema,\n]);\n\nexport const recallRangesDescription =\n 'Retrieve a stored reachable range result from session history. ' +\n 'Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. ' +\n 'Step 2: call with id to retrieve origin and budgets. ' +\n 'Does not call any service.';\n\nexport const executeRecallRanges = async (\n params: z.infer<typeof recallRangesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof recallRangesOutputSchema>> => {\n const { id } = params;\n\n if (!id) {\n const entries = [...state.ranges.entries]\n .reverse()\n .map(({ id, label, timestamp }) => ({ id, label, timestamp }));\n return { entries };\n }\n\n const entry = state.ranges.entries.find((e) => e.id === id);\n if (!entry) {\n return { error: `No entry found with id \"${id}\"` };\n }\n\n return {\n id: entry.id,\n label: entry.label,\n timestamp: entry.timestamp,\n origin: { ...entry.origin, position: entry.origin.position as [number, number] },\n budgets: entry.budgets,\n };\n};\n","import { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { summarizeRoutes, summarizeWaypoint, waypointSummarySchema } from '../../utils/summarize';\nimport { costModelSchema, whenSchema } from '../services/set-route-parameters';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\nexport const recallRoutesSchema = z.object({\n id: z.string().optional().describe('Entry ID to retrieve (e.g. \"routes-1\"). Omit to list all entries.'),\n});\n\nconst indexEntrySchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n});\n\nconst routeParamsSchema = z.object({\n maxAlternatives: z.number().optional(),\n costModel: costModelSchema.optional(),\n when: whenSchema.optional(),\n});\n\nconst detailSchema = z.object({\n id: z.string(),\n label: z.string(),\n timestamp: z.number(),\n routes: routesOutputSchema,\n waypoints: z.array(\n z.object({\n position: z.array(z.number()).length(2).describe('[longitude, latitude]'),\n }),\n ),\n params: routeParamsSchema,\n});\n\nexport const recallRoutesOutputSchema = z.union([\n z.object({ entries: z.array(indexEntrySchema) }),\n detailSchema,\n toolErrorSchema,\n]);\n\nexport const recallRoutesDescription =\n 'Retrieve calculated routes from session history. ' +\n 'ALWAYS use this when referencing routes from earlier in the session. ' +\n 'Entries have stable IDs that showRoute accepts. ' +\n 'Step 1: call with no parameters to list all entries and find the right ID. Do NOT guess IDs. ' +\n 'Step 2: call with id to retrieve a specific entry with route details and params. ' +\n 'Does not call any service.';\n\nexport const executeRecallRoutes = async (\n params: z.infer<typeof recallRoutesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof recallRoutesOutputSchema>> => {\n const { id } = params;\n\n if (!id) {\n const entries = [...state.routing.entries]\n .reverse()\n .map(({ id, label, timestamp }) => ({ id, label, timestamp }));\n return { entries };\n }\n\n const entry = state.routing.entries.find((e) => e.id === id);\n if (!entry) {\n return { error: `No entry found with id \"${id}\"` };\n }\n\n const summarized = summarizeRoutes(entry.data);\n const waypoints = entry.waypoints\n .map((wp) => summarizeWaypoint(wp))\n .filter((wp): wp is z.infer<typeof waypointSummarySchema> => wp !== null)\n .map((wp) => ({ position: wp.position ?? [0, 0] }));\n\n return {\n id: entry.id,\n label: entry.label,\n timestamp: entry.timestamp,\n routes: summarized,\n waypoints,\n params: entry.params as z.infer<typeof routeParamsSchema>,\n };\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the clear-map tool. */\nexport const clearMapOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n cleared: z.array(z.string()),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for clearing map features.\n */\nexport const clearMapSchema = z.object({\n layers: z\n .array(z.enum(['places', 'routes', 'geometries', 'analytics']))\n .optional()\n .describe('Layers to clear (default: all). Includes traffic area analytics visualization.'),\n});\n\nexport const clearMapDescription =\n 'Remove displayed features from the map (places, routes, geometries, analytics). Use to clean up before showing new results or to reset the map.';\n\n/**\n * Execute clear map.\n */\nexport const executeClearMap = async (params: z.infer<typeof clearMapSchema>, state: ToolState) => {\n const { layers } = params;\n try {\n const clearAll = !layers || layers.length === 0;\n\n if (clearAll || layers.includes('places')) {\n await state.places.clearShownEntries();\n }\n\n if (clearAll || layers.includes('routes')) {\n if (state.routing.routingModule) {\n await state.routing.routingModule.clearRoutes();\n await state.routing.routingModule.clearWaypoints();\n }\n }\n\n if (clearAll || layers.includes('geometries')) {\n if (state.ranges.geometriesModule) {\n await state.ranges.geometriesModule.clear();\n }\n }\n\n if (clearAll || layers.includes('analytics')) {\n if (state.traffic.trafficAreaAnalyticsModule) {\n await state.traffic.trafficAreaAnalyticsModule.clear();\n }\n }\n\n return {\n success: true,\n cleared: layers || ['places', 'routes', 'geometries', 'analytics'],\n };\n } catch (error) {\n return {\n error: `Failed to clear map: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport {\n getSectionBBox,\n type Route,\n type SectionProps,\n type SectionType,\n sectionTypes,\n} from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the fit-route-section tool. */\nexport const fitRouteSectionOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for fitting route section bounds.\n */\nexport const fitRouteSectionSchema = z.object({\n sectionType: z.enum(sectionTypes as [SectionType, ...SectionType[]]).describe('e.g. country|traffic|motorway|toll'),\n id: z.string().describe('From a shown route section'),\n padding: z.number().optional().describe('pixels, default: 50'),\n});\n\nexport const fitRouteSectionDescription =\n 'Fit the map camera to show a specific route section by type and ID. ' +\n 'Use getShownRouteSections to obtain valid section IDs. ' +\n 'Requires a route to be shown on the map.';\n\n/**\n * Execute fit route section.\n */\nexport const executeFitRouteSection = async (params: z.infer<typeof fitRouteSectionSchema>, state: ToolState) => {\n const { sectionType, id, padding = 50 } = params;\n\n try {\n // Get the currently shown routes from the map\n if (!state.routing.routingModule) {\n return {\n error: 'No routing module initialized - no routes shown on map',\n };\n }\n\n const shown = state.routing.routingModule.getShown();\n\n if (!shown.mainLines || shown.mainLines.features.length === 0) {\n return {\n error: 'No routes are currently displayed on the map. Please show a route first before fitting to a section.',\n };\n }\n\n const shownRoutes = shown.mainLines.features;\n\n // Find the section in the shown routes\n let targetRoute: Route | undefined;\n let targetSection: { id: string; startPointIndex: number; endPointIndex: number } | undefined;\n\n for (const route of shownRoutes) {\n const sections = route.properties.sections[sectionType as SectionType];\n if (sections && Array.isArray(sections)) {\n const foundSection = sections.find((s) => s.id === id);\n if (\n foundSection &&\n typeof foundSection.startPointIndex === 'number' &&\n typeof foundSection.endPointIndex === 'number'\n ) {\n targetSection = foundSection as {\n id: string;\n startPointIndex: number;\n endPointIndex: number;\n };\n targetRoute = route;\n break;\n }\n }\n }\n\n if (!targetRoute || !targetSection) {\n return {\n error: `Could not find a section with type \"${sectionType}\" and id \"${id}\" in any displayed route. Check the section type and id are correct.`,\n };\n }\n\n // Calculate the bbox for the section\n const bbox = getSectionBBox(targetRoute, targetSection as SectionProps);\n\n if (!bbox) {\n return {\n error: 'Could not calculate bounding box for the section. The section may have invalid indices.',\n };\n }\n\n // Fit the map to the section bbox\n state.baseMap.mapLibreMap.fitBounds(bbox, { padding });\n\n return { success: true };\n } catch (error) {\n return {\n error: `Failed to fit route section: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-incidents tool. */\nexport const getShownIncidentsOutputSchema = z.union([\n z.object({\n count: z.number(),\n trafficIncidents: z.array(\n z.object({\n id: z.string(),\n category: z.string(),\n magnitudeOfDelay: z.string().describe('unknown|minor|moderate|major|indefinite'),\n description: z.string().optional(),\n delayInSeconds: z.number().optional(),\n roadCategory: z.string().optional(),\n averageSpeedKmph: z.number().optional(),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting shown traffic incidents on map.\n */\nexport const getShownIncidentsSchema = z.object({});\n\nexport const getShownIncidentsDescription =\n 'Get the real-time traffic incidents currently visible in the map viewport (not from service, but what is actually rendered on the map).';\n\n/**\n * Execute get shown incidents.\n */\nexport const executeGetShownIncidents = async (\n _params: z.infer<typeof getShownIncidentsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getShownIncidentsOutputSchema>> => {\n try {\n const trafficIncidentsModule = await state.traffic.getTrafficIncidentsModule();\n const shown = trafficIncidentsModule.getShown();\n\n if (shown.trafficIncidents.length === 0) {\n return { error: 'No traffic incidents currently shown on the map' };\n }\n\n return {\n count: shown.trafficIncidents.length,\n trafficIncidents: shown.trafficIncidents.map((incident) => ({\n id: incident.properties.id,\n category: incident.properties.category,\n magnitudeOfDelay: incident.properties.magnitudeOfDelay,\n description: incident.properties.description,\n delayInSeconds: incident.properties.delayInSeconds,\n roadCategory: incident.properties.roadCategory,\n averageSpeedKmph: incident.properties.averageSpeedKmph,\n })),\n };\n } catch (error) {\n return {\n error: `Failed to get shown incidents: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-places tool. */\nexport const getShownPlacesOutputSchema = z.union([\n z.object({\n count: z.number().describe('Total feature count across all shown entries.'),\n entries: z.array(\n z.object({\n id: z.string(),\n label: z.string(),\n featureCount: z.number(),\n features: z.array(\n z.object({\n name: z.string().optional(),\n address: z.string().optional(),\n position: z.array(z.number()).describe('[lng, lat]'),\n }),\n ),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting shown places on map.\n */\nexport const getShownPlacesSchema = z.object({});\n\nexport const getShownPlacesDescription =\n 'List the place entries currently shown on the map, grouped by `placesEntryId` with labels and a feature preview. ' +\n 'Use to check which categories are visible before calling `managePlaces`, or when the user asks \"what is on the map\". ' +\n 'Positions are [longitude, latitude].';\n\nconst FEATURE_PREVIEW_SIZE = 5;\n\n/**\n * Execute get shown places.\n */\nexport const executeGetShownPlaces = async (_params: z.infer<typeof getShownPlacesSchema>, state: ToolState) => {\n try {\n const shownIds = state.places.shownEntryIds;\n if (shownIds.size === 0) {\n return { count: 0, entries: [] };\n }\n\n const entries = state.places.entries\n .filter((entry) => shownIds.has(entry.id))\n .map((entry) => ({\n id: entry.id,\n label: entry.label,\n featureCount: entry.data.length,\n features: entry.data.slice(0, FEATURE_PREVIEW_SIZE).map((feature) => ({\n name: feature.properties.poi?.name,\n address: feature.properties.address?.freeformAddress,\n position: feature.geometry.coordinates,\n })),\n }));\n\n return {\n count: entries.reduce((total, entry) => total + entry.featureCount, 0),\n entries,\n };\n } catch (error) {\n return {\n error: `Failed to get shown places: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport type { SectionsProps, SectionType } from '@tomtom-org/maps-sdk/core';\nimport { sectionTypes } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-route-sections tool. */\nexport const getShownRouteSectionsOutputSchema = z.union([\n z.object({\n sectionType: z.string(),\n routes: z.array(\n z.object({\n routeIndex: z.number().describe('0=primary, 1+=alternative'),\n sections: z.array(z.unknown()).describe('startPointIndex/endPointIndex omitted'),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/** Input schema for the get-shown-route-sections tool. */\nexport const getShownRouteSectionsSchema = z.object({\n sectionType: z\n .enum(sectionTypes as [SectionType, ...SectionType[]])\n .describe(\n 'carpool|carTrain|country|ferry|importantRoadStretch|lanes|leg|lowEmissionZone|motorway|pedestrian|roadShields|speedLimit|toll|tollVignette|traffic|tunnel|unpaved|urban|vehicleRestricted',\n ),\n});\n\nexport const getShownRouteSectionsDescription =\n 'Get sections of a specific type (e.g. toll, motorway, country, traffic) from the currently shown routes. Returns section data without coordinate point indices.';\n\n/**\n * Execute get shown route sections.\n */\nexport const executeGetShownRouteSections = async (\n params: z.infer<typeof getShownRouteSectionsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getShownRouteSectionsOutputSchema>> => {\n const { sectionType } = params;\n try {\n if (!state.routing.routingModule) {\n return { error: 'No routing module initialized - no routes shown on map' };\n }\n\n const shown = state.routing.routingModule.getShown();\n\n if (!shown.mainLines || shown.mainLines.features.length === 0) {\n return { error: 'No routes currently shown on the map' };\n }\n\n const routes = shown.mainLines.features\n .map((route) => {\n const sectionArray = (route.properties.sections as SectionsProps)[sectionType as keyof SectionsProps];\n\n if (!sectionArray || sectionArray.length === 0) return null;\n\n return {\n routeIndex: route.properties.index,\n sections: sectionArray.map((section) => {\n const {\n startPointIndex: _s,\n endPointIndex: _e,\n ...rest\n } = section as Record<string, unknown> & {\n startPointIndex?: unknown;\n endPointIndex?: unknown;\n };\n return rest;\n }),\n };\n })\n .filter((r) => r !== null);\n\n if (routes.length === 0) {\n return { error: `No \"${sectionType}\" sections found on any currently shown route` };\n }\n\n return { sectionType, routes };\n } catch (error) {\n return {\n error: `Failed to get shown route sections: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-route-traffic-incidents tool. */\nexport const getShownRouteTrafficIncidentsOutputSchema = z.union([\n z.object({\n count: z.number(),\n trafficIncidents: z.array(\n z.object({\n id: z.string(),\n magnitudeOfDelay: z.string().describe('unknown|minor|moderate|major|indefinite'),\n title: z.string().optional(),\n delayInSeconds: z.number().optional(),\n effectiveSpeedInKmh: z.number().optional(),\n categories: z.array(z.string()).optional(),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting shown route traffic incidents on map.\n */\nexport const getShownRouteTrafficIncidentsSchema = z.object({});\n\nexport const getShownRouteTrafficIncidentsDescription =\n 'Get the route traffic incidents currently displayed on the map (not from service, but what is actually shown). Each section has an id.';\n\n/**\n * Execute get shown route traffic incidents.\n */\nexport const executeGetShownRouteTrafficIncidents = async (\n _params: z.infer<typeof getShownRouteTrafficIncidentsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getShownRouteTrafficIncidentsOutputSchema>> => {\n try {\n if (!state.routing.routingModule) {\n return { error: 'No routing module initialized - no route traffic incidents shown on map' };\n }\n\n const shown = state.routing.routingModule.getShown();\n\n if (!shown.incidents || shown.incidents.features.length === 0) {\n return { error: 'No route traffic incidents currently shown on the map' };\n }\n\n return {\n count: shown.incidents.features.length,\n trafficIncidents: shown.incidents.features.map((incident) => ({\n id: incident.properties.id,\n magnitudeOfDelay: incident.properties.magnitudeOfDelay,\n title: incident.properties.title,\n delayInSeconds: incident.properties.delayInSeconds,\n effectiveSpeedInKmh: incident.properties.effectiveSpeedInKmh,\n categories: incident.properties.categories,\n })),\n };\n } catch (error) {\n return {\n error: `Failed to get shown route traffic incidents: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { summarizeRoutes } from '../../utils/summarize';\nimport { routesOutputSchema, toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-routes tool. */\nexport const getShownRoutesOutputSchema = z.union([routesOutputSchema, toolErrorSchema]);\n\n/**\n * Tool schema for getting shown routes on map.\n */\nexport const getShownRoutesSchema = z.object({});\n\nexport const getShownRoutesDescription =\n 'Get routes currently shown on the map. ' +\n 'Reads rendered map state (not plugin service history). Returns routes currently visible on map — use after showRoute.';\n\n/**\n * Execute get shown routes.\n */\nexport const executeGetShownRoutes = async (\n _params: z.infer<typeof getShownRoutesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getShownRoutesOutputSchema>> => {\n try {\n if (!state.routing.routingModule) {\n return { count: 0, routes: [] };\n }\n\n const shown = state.routing.routingModule.getShown();\n\n if (!shown.mainLines || shown.mainLines.features.length === 0) {\n return { count: 0, routes: [] };\n }\n\n return summarizeRoutes(shown.mainLines);\n } catch (error) {\n return {\n error: `Failed to get shown routes: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-shown-waypoints tool. */\nexport const getShownWaypointsOutputSchema = z.union([\n z.object({\n count: z.number(),\n waypoints: z.array(\n z.object({\n name: z.unknown().optional(),\n position: z.array(z.number()).describe('[lng, lat]'),\n }),\n ),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting shown waypoints on map.\n */\nexport const getShownWaypointsSchema = z.object({});\n\nexport const getShownWaypointsDescription =\n 'Get origin/stop/destination waypoints shown on the map. Context-dependent: requires waypoints shown on the map. ' +\n 'Returns positions as [longitude, latitude].';\n\n/**\n * Execute get shown waypoints.\n */\nexport const executeGetShownWaypoints = async (\n _params: z.infer<typeof getShownWaypointsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof getShownWaypointsOutputSchema>> => {\n try {\n const shown = (await state.routing.getRoutingModule()).getShown();\n\n if (!shown.waypoints || shown.waypoints.features.length === 0) {\n return { error: 'No waypoints currently shown on the map' };\n }\n\n return {\n count: shown.waypoints.features.length,\n waypoints: shown.waypoints.features.map((w) => ({\n name: w.properties.name,\n position: w.geometry.coordinates,\n })),\n };\n } catch (error) {\n return {\n error: `Failed to get shown waypoints: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { standardStyleIDs } from '@tomtom-org/maps-sdk/map';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the get-standard-map-styles tool. */\nexport const getStandardMapStylesOutputSchema = z.union([\n z.object({\n styles: z.array(z.string()).readonly(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for getting standard map styles.\n */\nexport const getStandardMapStylesSchema = z.object({});\n\nexport const getStandardMapStylesDescription =\n 'Get the list of available standard map style IDs. If you need more fine styling control, refer to getMapStyleLayers.';\n\n/**\n * Execute get standard map styles.\n */\nexport const executeGetStandardMapStyles = async (\n _params: z.infer<typeof getStandardMapStylesSchema>,\n _state: ToolState,\n): Promise<z.infer<typeof getStandardMapStylesOutputSchema>> => {\n try {\n return {\n styles: standardStyleIDs,\n };\n } catch (error) {\n return {\n error: `Failed to get standard map styles: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\nconst shownEntrySummarySchema = z.object({\n id: z.string(),\n label: z.string(),\n featureCount: z.number(),\n});\n\nexport const managePlacesOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n totalShown: z.number(),\n shown: z.array(shownEntrySummarySchema).describe('Entries currently on the map, with their labels.'),\n actuallyAdded: z\n .array(z.string())\n .describe('Ids from `add` / `addMatching` that were not already shown. Empty if it was a no-op.'),\n actuallyRemoved: z\n .array(z.string())\n .describe('Ids from `remove` / `removeMatching` that were actually on the map. Empty if no-op.'),\n }),\n toolErrorSchema,\n]);\n\nexport const managePlacesSchema = z\n .object({\n add: z.array(z.string()).optional().describe('Entry ids to show (e.g. [\"places-1\"]).'),\n remove: z.array(z.string()).optional().describe('Entry ids to hide.'),\n addMatching: z.array(z.string()).optional().describe('Category labels to show.'),\n removeMatching: z.array(z.string()).optional().describe('Category labels to hide.'),\n clear: z.boolean().optional().describe('Hide every displayed entry.'),\n fitBounds: z.boolean().optional().describe('Pan/zoom to fit the resulting display. Default: false.'),\n })\n .refine(\n (data) =>\n data.add !== undefined ||\n data.remove !== undefined ||\n data.addMatching !== undefined ||\n data.removeMatching !== undefined ||\n data.clear === true,\n { message: 'managePlaces requires at least one of: add, remove, addMatching, removeMatching, clear.' },\n );\n\nexport const managePlacesDescription =\n 'Change which places entries are displayed on the map. ' +\n 'Target entries by id (`add` / `remove`) or by category label (`addMatching` / `removeMatching`). ' +\n '`clear` hides all. Does not delete from history.';\n\n/** Resolve category terms to entry ids by case-insensitive substring match on the entry label. */\nconst resolveMatchingIds = (state: ToolState, terms: readonly string[]): string[] => {\n if (terms.length === 0) return [];\n const needles = terms.map((term) => term.toLowerCase());\n const matched = new Set<string>();\n for (const entry of state.places.entries) {\n const label = entry.label.toLowerCase();\n if (needles.some((needle) => label.includes(needle))) {\n matched.add(entry.id);\n }\n }\n return [...matched];\n};\n\nexport const executeManagePlaces = async (\n params: z.infer<typeof managePlacesSchema>,\n state: ToolState,\n): Promise<z.infer<typeof managePlacesOutputSchema>> => {\n const { add, remove, addMatching, removeMatching, clear, fitBounds = false } = params;\n try {\n // Resolve label-matching selectors to concrete ids, merge with id-based selectors.\n const resolvedAdd = [...(add ?? []), ...resolveMatchingIds(state, addMatching ?? [])];\n const resolvedRemove = [...(remove ?? []), ...resolveMatchingIds(state, removeMatching ?? [])];\n\n const knownIds = new Set(state.places.entries.map((entry) => entry.id));\n const unknownAdd = resolvedAdd.filter((id) => !knownIds.has(id));\n if (unknownAdd.length > 0) {\n return {\n error: `Unknown places entry ids: ${unknownAdd.join(', ')}. Use recallPlaces to list available entries.`,\n };\n }\n\n // Snapshot the shown set BEFORE mutation so we can report diffs accurately.\n const beforeShown = new Set(state.places.shownEntryIds);\n\n if (clear) {\n await state.places.clearShownEntries();\n }\n if (resolvedRemove.length > 0) {\n await state.places.removeShownEntries(resolvedRemove);\n }\n if (resolvedAdd.length > 0) {\n await state.places.addShownEntries(resolvedAdd);\n }\n\n const afterShown = state.places.shownEntryIds;\n const actuallyAdded = resolvedAdd.filter((id) => !beforeShown.has(id) && afterShown.has(id));\n const actuallyRemoved = resolvedRemove.filter((id) => beforeShown.has(id) && !afterShown.has(id));\n\n const shownFeatures = state.places.getShownFeatures();\n if (fitBounds && shownFeatures.length > 0) {\n const bbox = bboxFromGeoJSON(shownFeatures);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox, { padding: 50 });\n }\n }\n\n const shownWithLabels = state.places.entries\n .filter((entry) => afterShown.has(entry.id))\n .map((entry) => ({ id: entry.id, label: entry.label, featureCount: entry.data.length }));\n\n return {\n success: true as const,\n totalShown: shownFeatures.length,\n shown: shownWithLabels,\n actuallyAdded,\n actuallyRemoved,\n };\n } catch (error) {\n return {\n error: `managePlaces failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { Language, TomTomConfig } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the set-language tool. */\nexport const setLanguageOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n language: z.string(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for setting language.\n */\nexport const setLanguageSchema = z.object({\n language: z.string().describe('e.g. \"en-US\", \"fr-FR\"'),\n});\n\nexport const setLanguageDescription =\n '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.). ' +\n 'Both the rendered map text and future service responses will use the new language.';\n\n/**\n * Execute set language.\n */\nexport const executeSetLanguage = async (params: z.infer<typeof setLanguageSchema>, state: ToolState) => {\n const { language } = params;\n try {\n TomTomConfig.instance.put({ language: language as Language });\n state.baseMap.ttMap.setLanguage(language as Language);\n\n return {\n success: true,\n language,\n };\n } catch (error) {\n return {\n error: `Failed to set language: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { standardStyleIDs } from '@tomtom-org/maps-sdk/map';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the setMapStandardStyle tool. */\nexport const setMapStandardStyleOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n style: z.string(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for setting a standard map style.\n */\nexport const setMapStandardStyleSchema = z.object({\n style: z.enum(standardStyleIDs).describe('Map visual theme'),\n});\n\nexport const setMapStandardStyleDescription =\n '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.';\n\n/**\n * Execute set map standard style.\n */\nexport const executeSetMapStandardStyle = async (\n params: z.infer<typeof setMapStandardStyleSchema>,\n state: ToolState,\n) => {\n const { style } = params;\n try {\n state.baseMap.ttMap.setStyle(style);\n\n return {\n success: true,\n style,\n };\n } catch (error) {\n return {\n error: `Failed to set map style: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the setRouteTheme tool. */\nexport const setRouteThemeOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n theme: z.object({\n mainColor: z.string().optional(),\n }),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for setting route theme.\n */\nexport const setRouteThemeSchema = z.object({\n mainColor: z\n .string()\n .optional()\n .describe(\n '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\").',\n ),\n});\n\nexport const setRouteThemeDescription =\n 'Style the route line and waypoint icons with a color. ' +\n 'Prefer this over setPaintProperties for route styling — it applies the color consistently across all route and waypoint layers. ' +\n 'Requires a route to be shown on the map.';\n\nconst currentTheme: { mainColor?: string } = {};\n\n/**\n * Execute set route theme.\n */\nexport const executeSetRouteTheme = async (params: z.infer<typeof setRouteThemeSchema>, state: ToolState) => {\n try {\n if (params.mainColor !== undefined) currentTheme.mainColor = params.mainColor;\n\n const routingModule = await state.routing.getRoutingModule();\n routingModule.applyConfig({\n theme: {\n mainColor: currentTheme.mainColor,\n },\n });\n\n return {\n success: true as const,\n theme: { ...currentTheme },\n };\n } catch (error) {\n return {\n error: `Failed to set route theme: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON } from '@tomtom-org/maps-sdk/core';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the show-places tool. */\nexport const showPlacesOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n count: z.number(),\n shownEntryIds: z.array(z.string()),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for showing places on the map.\n */\nexport const showPlacesSchema = z.object({\n id: z\n .string()\n .optional()\n .describe('ID of a historical places entry (from recallPlaces). Omit to show the most recent.'),\n fitBounds: z.boolean().optional().describe('Pan/zoom to fit the shown features. Default: true.'),\n});\n\nexport const showPlacesDescription =\n 'Display a places entry on the map, replacing whatever was previously shown. ' +\n 'Pass an id (from recallPlaces) to show a specific entry, or omit to show the most recent. ' +\n 'To stack additional entries or hide specific ones, use `managePlaces` instead.';\n\n/**\n * Execute show places.\n */\nexport const executeShowPlaces = async (params: z.infer<typeof showPlacesSchema>, state: ToolState) => {\n const { id, fitBounds = true } = params;\n try {\n const targetId = id ?? state.places.entries.at(-1)?.id;\n\n if (!targetId) {\n return {\n error: 'No places available to display. Resolve a place or run a search first (e.g. discoverPlaces).',\n };\n }\n\n if (!state.places.entries.some((entry) => entry.id === targetId)) {\n return { error: `No places entry found with id \"${targetId}\"` };\n }\n\n await state.places.setShownEntries([targetId]);\n const shownFeatures = state.places.getShownFeatures();\n\n if (fitBounds && shownFeatures.length > 0) {\n const bbox = bboxFromGeoJSON(shownFeatures);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox, { padding: 50 });\n }\n }\n\n return {\n success: true as const,\n count: shownFeatures.length,\n shownEntryIds: [...state.places.shownEntryIds],\n };\n } catch (error) {\n return {\n error: `Failed to show places: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON, type Routes, type WaypointLike } from '@tomtom-org/maps-sdk/core';\nimport type { LngLatBoundsLike } from 'maplibre-gl';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the show-route tool. */\nexport const showRouteOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n displayedRoute: z.number(),\n routeCount: z.number(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for showing routes on the map.\n */\nexport const showRouteSchema = z.object({\n id: z\n .string()\n .optional()\n .describe('ID of a historical route entry (from recallRoutes). Omit to show the most recent route.'),\n selectedIndex: z.number().optional().describe('default: 0'),\n fitBounds: z.boolean().optional().describe('default: true'),\n});\n\nexport const showRouteDescription =\n 'Show routes and waypoints on the map and fit the camera to the route extent. ' +\n 'Pass an id (from recallRoutes) to show a historical route, or omit to show the most recent. ' +\n 'Mutates map display. Does not call any service.';\n\n/**\n * Execute show routes.\n */\nexport const executeShowRoutes = async (params: z.infer<typeof showRouteSchema>, state: ToolState) => {\n const { id, selectedIndex = 0, fitBounds = true } = params;\n try {\n let routes: Routes | undefined;\n let waypoints: WaypointLike[] | undefined;\n\n if (id) {\n const entry = state.routing.entries.find((e) => e.id === id);\n if (!entry) {\n return { error: `No route entry found with id \"${id}\"` };\n }\n routes = entry.data;\n waypoints = entry.waypoints;\n } else {\n routes = state.routing.currentRoutes;\n waypoints = state.routing.planningSlots.filter((w): w is WaypointLike => w !== null);\n }\n\n if (!routes) {\n return { error: 'No routes available to display' };\n }\n\n const routingModule = await state.routing.getRoutingModule();\n await routingModule.showRoutes(routes, { selectedIndex });\n\n if (waypoints) {\n await routingModule.showWaypoints(waypoints);\n }\n\n // Fit bounds to show all routes if requested\n if (fitBounds) {\n const bbox = bboxFromGeoJSON(routes);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox as LngLatBoundsLike, { padding: 50 });\n }\n }\n\n return {\n success: true,\n displayedRoute: selectedIndex,\n routeCount: routes.features.length,\n };\n } catch (error) {\n return {\n error: `Failed to show route: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { bboxFromGeoJSON } from '@tomtom-org/maps-sdk/core';\nimport type { LngLatBoundsLike } from 'maplibre-gl';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n// ---------------------------------------------------------------------------\n// Schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Tool schema for showing traffic area analytics on the map.\n */\nexport const showTrafficAreaAnalyticsSchema = z.object({\n mode: z\n .enum(['hexgrid-3d', 'hexgrid-2d', 'square-3d', 'square-2d', 'heatmap'])\n .optional()\n .describe(\n \"Visualization mode. 'hexgrid-3d' (default): 3D hexagons. 'hexgrid-2d': flat hexagons. 'square-3d': 3D squares. 'square-2d': flat squares. 'heatmap': density layer.\",\n ),\n metric: z\n .enum(['congestionLevel', 'speed', 'travelTime'])\n .optional()\n .describe('Metric to visualize. Defaults to first fetched metric.'),\n colorTheme: z\n .enum(['trafficLight', 'heat', 'monochrome', 'viridis', 'plasma'])\n .optional()\n .describe(\n \"Preset color theme. 'trafficLight' (green→amber→red, default), 'heat' (blue→orange→red), 'monochrome' (grey), 'viridis' (purple→green→yellow), 'plasma' (purple→magenta→yellow).\",\n ),\n heightScale: z\n .number()\n .optional()\n .describe('Extrusion height multiplier / visual maximum in meters. Default: metric-dependent.'),\n scaleMode: z\n .enum(['raw', 'predefinedRange', 'currentRange'])\n .optional()\n .describe(\n \"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.\",\n ),\n filter: z\n .object({\n min: z.number().optional(),\n max: z.number().optional(),\n })\n .refine((filter) => filter.min !== undefined || filter.max !== undefined, {\n message: 'Filter must have at least one of min or max',\n })\n .optional()\n .describe('Filter visible tiles for the active metric by value range.'),\n visible: z.boolean().optional().describe('Set to false to clear the visualization. Default: true.'),\n fitBounds: z.boolean().optional().describe('Fit map viewport to the analytics area. Default: true.'),\n});\n\n/** Output schema for the show-traffic-area-analytics tool. */\nexport const showTrafficAreaAnalyticsOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n mode: z.string(),\n metric: z.string(),\n colorTheme: z.string(),\n visible: z.boolean(),\n filtered: z.boolean(),\n }),\n toolErrorSchema,\n]);\n\nexport const showTrafficAreaAnalyticsDescription =\n 'Show HISTORICAL traffic area analytics on the map (hexgrid/heatmap). ' +\n 'Not real-time — use toggleTrafficFlow for live traffic. ' +\n 'Configure metric, color theme, height, and tile filtering. ' +\n 'Use after getTrafficAreaAnalytics. Defaults to first fetched metric.';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Tool factory\n// ---------------------------------------------------------------------------\n\n/**\n * Execute show traffic area analytics.\n */\nexport const executeShowTrafficAreaAnalytics = async (\n params: z.infer<typeof showTrafficAreaAnalyticsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof showTrafficAreaAnalyticsOutputSchema>> => {\n try {\n // Get stored analytics result\n const analyticsResult = state.traffic.lastAreaAnalytics;\n if (!analyticsResult) {\n return { error: 'No analytics data available. Call getTrafficAreaAnalytics first to fetch data.' };\n }\n\n // Default metric to first fetched metric\n const defaultMetric = analyticsResult.properties?.metrics?.[0] ?? 'congestionLevel';\n\n const {\n mode = 'hexgrid-3d',\n metric = defaultMetric,\n colorTheme = 'trafficLight',\n heightScale,\n scaleMode,\n filter,\n visible = true,\n fitBounds: shouldFitBounds = true,\n } = params;\n\n // Lazy-init TrafficAreaAnalyticsModule\n const analyticsModule = await state.traffic.getTrafficAreaAnalyticsModule();\n\n if (!visible) {\n await analyticsModule.clear();\n state.traffic.onAnalyticsCleared?.();\n return { success: true, mode, metric, colorTheme, visible: false, filtered: false };\n }\n\n // Clear previous visualization before showing new data\n await analyticsModule.clear();\n await analyticsModule.show(analyticsResult);\n\n // Apply mode and active metric\n analyticsModule.setMode(mode);\n analyticsModule.setMetric(metric);\n\n // Apply color theme\n analyticsModule.setColor(colorTheme);\n\n // Apply height config\n if (heightScale !== undefined || scaleMode !== undefined) {\n analyticsModule.setHeight({\n ...(heightScale !== undefined && { maxHeightMeters: heightScale }),\n ...(scaleMode !== undefined && { scaleMode }),\n });\n }\n\n // Apply tile filter for active metric\n const isFiltered = !!filter;\n if (filter) {\n analyticsModule.filter({ min: filter.min, max: filter.max });\n } else {\n analyticsModule.clearFilter();\n }\n\n // Fit map to analytics area\n if (shouldFitBounds) {\n const bbox = bboxFromGeoJSON(analyticsResult.features);\n if (bbox) {\n state.baseMap.mapLibreMap.fitBounds(bbox as LngLatBoundsLike, { padding: 50, pitch: 45 });\n }\n }\n\n state.traffic.onAnalyticsShown?.(analyticsResult, analyticsModule);\n\n return {\n success: true,\n mode,\n metric,\n colorTheme,\n visible: true,\n filtered: isFiltered,\n };\n } catch (error) {\n return {\n error: `Failed to show traffic area analytics: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the show-waypoints tool. */\nexport const showWaypointsOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n count: z.number(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for showing waypoints on the map.\n */\nexport const showWaypointsSchema = z.object({});\n\nexport const showWaypointsDescription =\n 'Display origin, stop, and destination waypoints as markers on the map. ' +\n 'Context-dependent: requires setRouteLocations or locatePlace with waypointIndex to have been called first. ' +\n 'Does not recalculate the route. Prefer showRoute when you also need the route line drawn.';\n\n/**\n * Execute show waypoints.\n */\nexport const executeShowWaypoints = async (\n _params: z.infer<typeof showWaypointsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof showWaypointsOutputSchema>> => {\n try {\n // Prefer the current (possibly sparse) waypoints being assembled;\n // fall back to the last finalized waypoints from route history.\n const current = state.routing.planningSlots;\n\n const routingModule = await state.routing.getRoutingModule();\n await routingModule.showWaypoints(current);\n\n return { success: true, count: current.length };\n } catch (error) {\n return {\n error: `Failed to show waypoints: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { baseMapLayerGroupNames } from '@tomtom-org/maps-sdk/map';\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the toggle-base-map-layer-groups tool. */\nexport const toggleBaseMapLayerGroupsOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n visible: z.boolean(),\n layerGroups: z.array(z.string()),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for toggling base map layer groups.\n */\nexport const toggleBaseMapLayerGroupsSchema = z.object({\n visible: z.boolean(),\n layerGroups: z.array(z.enum(baseMapLayerGroupNames)).describe('The base map layer groups to show or hide.'),\n});\n\nexport const toggleBaseMapLayerGroupsDescription =\n 'Show or hide specific base map layer groups (water, buildings3D, roadLines, placeLabels, capitalLabels, etc.)';\n\n/**\n * Execute toggle base map layer groups.\n */\nexport const executeToggleBaseMapLayerGroups = async (\n params: z.infer<typeof toggleBaseMapLayerGroupsSchema>,\n state: ToolState,\n) => {\n const { visible, layerGroups } = params;\n try {\n // Lazy-init BaseMapModule\n const baseMapModule = await state.baseMap.getBaseMapModule();\n\n baseMapModule.setVisible(visible, {\n layerGroups: {\n mode: 'include',\n names: layerGroups,\n },\n });\n\n return {\n success: true,\n visible,\n layerGroups,\n };\n } catch (error) {\n return {\n error: `Failed to toggle layer groups: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/** Output schema for the toggle-pois tool. */\nexport const togglePOIsOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n allMapPOIsVisible: z.boolean().optional(),\n filterCategories: z\n .object({\n show: z.enum(['only', 'all_except']),\n values: z.array(z.string()),\n })\n .optional(),\n reset: z.boolean().optional(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for toggling POIs.\n */\nexport const togglePOIsSchema = z.object({\n reset: z\n .boolean()\n .optional()\n .describe(\n 'Set to true to reset all POI configuration to defaults (visibility and category filters). When true, all other parameters are ignored.',\n ),\n allMapPOIsVisible: z\n .boolean()\n .optional()\n .describe(\n 'Set the overall visibility of all built-in map POI icons. True to show all POIs, false to hide all POIs.',\n ),\n filterCategories: z\n .object({\n show: z\n .enum(['only', 'all_except'])\n .describe(\n '\"only\": show POIs only from the given categories. \"all_except\": show all POIs except those in the given categories.',\n ),\n values: z\n .array(z.string())\n .describe(\n 'MapStylePOICategory or POICategoryGroup values (e.g. \"RESTAURANT\", \"FOOD_DRINKS_GROUP\"). Overly specific codes like \"ITALIAN_RESTAURANT\" are not supported.',\n ),\n })\n .optional()\n .describe('Filter which built-in map POI categories are shown.'),\n});\n\nexport const togglePOIsDescription =\n 'Show or hide all built-in map POI icons (restaurants, hotels, gas stations, etc.) and optionally filter by category. ' +\n 'Use allMapPOIsVisible to control overall POI visibility, filterCategories to restrict which categories are shown or hidden, ' +\n 'or reset: true to restore all POI defaults.';\n\n/**\n * Execute toggle POIs.\n */\nexport const executeTogglePOIs = async (\n params: z.infer<typeof togglePOIsSchema>,\n state: ToolState,\n): Promise<z.infer<typeof togglePOIsOutputSchema>> => {\n try {\n const poisModule = await state.mapPOIs.getPOIsModule();\n\n if (params.reset) {\n poisModule.resetConfig();\n return { success: true, reset: true };\n }\n\n const { allMapPOIsVisible, filterCategories } = params;\n\n if (allMapPOIsVisible !== undefined) poisModule.setVisible(allMapPOIsVisible);\n if (filterCategories) {\n poisModule.filterCategories({ show: filterCategories.show, values: filterCategories.values });\n }\n\n return { success: true, allMapPOIsVisible, filterCategories };\n } catch (error) {\n return {\n error: `Failed to toggle POIs: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { z } from 'zod';\nimport type { ToolState } from '../../types';\nimport { toolErrorSchema } from '../shared-output-schemas';\n\n/**\n * Tool schema for toggling traffic flow.\n */\nexport const toggleTrafficFlowSchema = z.object({\n visible: z.boolean(),\n});\n\n/** Output schema for the toggle-traffic-flow tool. */\nexport const toggleTrafficFlowOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n trafficFlowVisible: z.boolean(),\n }),\n toolErrorSchema,\n]);\n\n/**\n * Tool schema for toggling traffic incidents.\n */\nexport const toggleTrafficIncidentsSchema = z.object({\n visible: z.boolean(),\n});\n\n/** Output schema for the toggle-traffic-incidents tool. */\nexport const toggleTrafficIncidentsOutputSchema = z.union([\n z.object({\n success: z.literal(true),\n trafficIncidentsVisible: z.boolean(),\n }),\n toolErrorSchema,\n]);\n\nexport const toggleTrafficFlowDescription =\n 'Toggle the REAL-TIME traffic flow layer — colored road segments showing live speed conditions. ' +\n 'This is NOT historical analytics; use showTrafficAreaAnalytics for historical data.';\n\nexport const toggleTrafficIncidentsDescription =\n 'Toggle REAL-TIME traffic incident markers on the map (jams, accidents, closures, roadworks). ' +\n 'This is NOT historical analytics. Use getTrafficIncidents for incident details.';\n\n/**\n * Execute toggle traffic flow.\n */\nexport const executeToggleTrafficFlow = async (params: z.infer<typeof toggleTrafficFlowSchema>, state: ToolState) => {\n const { visible } = params;\n try {\n // Lazy-init TrafficFlowModule\n const trafficFlowModule = await state.traffic.getTrafficFlowModule();\n\n trafficFlowModule.setVisible(visible);\n\n return {\n success: true,\n trafficFlowVisible: visible,\n };\n } catch (error) {\n return {\n error: `Failed to toggle traffic flow: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n\n/**\n * Execute toggle traffic incidents.\n */\nexport const executeToggleTrafficIncidents = async (\n params: z.infer<typeof toggleTrafficIncidentsSchema>,\n state: ToolState,\n) => {\n const { visible } = params;\n try {\n // Lazy-init TrafficIncidentsModule\n const trafficIncidentsModule = await state.traffic.getTrafficIncidentsModule();\n\n trafficIncidentsModule.setVisible(visible);\n\n return {\n success: true,\n trafficIncidentsVisible: visible,\n };\n } catch (error) {\n return {\n error: `Failed to toggle traffic incidents: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n};\n","/**\n * @module agent-toolkit-tools\n */\n\nimport { sectionTypes } from '@tomtom-org/maps-sdk/core';\nimport type { ToolEntry } from '../types';\n\n// --- MapLibre tools ---\nimport {\n executeExecuteMaplibreCode,\n executeFlyTo,\n executeGetMapStyleLayers,\n executeGetViewport,\n executeMaplibreCodeDescription,\n executeMaplibreCodeOutputSchema,\n executeMaplibreCodeSchema,\n executeSetLayoutProperties,\n executeSetPaintProperties,\n executeSetPitchBearing,\n executeZoomInOrOut,\n flyToDescription,\n flyToOutputSchema,\n flyToSchema,\n getMapStyleLayersDescription,\n getMapStyleLayersOutputSchema,\n getMapStyleLayersSchema,\n getViewportDescription,\n getViewportOutputSchema,\n getViewportSchema,\n setLayoutPropertiesDescription,\n setLayoutPropertiesOutputSchema,\n setLayoutPropertiesSchema,\n setPaintPropertiesDescription,\n setPaintPropertiesOutputSchema,\n setPaintPropertiesSchema,\n setPitchBearingDescription,\n setPitchBearingOutputSchema,\n setPitchBearingSchema,\n zoomInOrOutDescription,\n zoomInOrOutOutputSchema,\n zoomInOrOutSchema,\n} from './maplibre';\n\n// --- Service tools ---\nimport {\n addStopToRouteDescription,\n addStopToRouteOutputSchema,\n addStopToRouteSchema,\n discoverPlacesDescription,\n discoverPlacesOutputSchema,\n discoverPlacesSchema,\n executeAddStopToRoute,\n executeDiscoverPlaces,\n executeFindReachableArea,\n executeGetPoiCategoryCodes,\n executeGetTrafficAreaAnalytics,\n executeGetTrafficIncidents,\n executeLocatePlace,\n executeQueryTrafficAnalytics,\n executeRemoveStopFromRoute,\n executeReverseGeocode,\n executeSearchAlongRoute,\n executeSetRouteLocations,\n executeSetRouteParameters,\n findReachableAreaDescription,\n findReachableAreaOutputSchema,\n findReachableAreaSchema,\n getPoiCategoryCodesDescription,\n getPoiCategoryCodesOutputSchema,\n getPoiCategoryCodesSchema,\n getTrafficAreaAnalyticsDescription,\n getTrafficAreaAnalyticsOutputSchema,\n getTrafficAreaAnalyticsSchema,\n getTrafficIncidentsDescription,\n getTrafficIncidentsOutputSchema,\n getTrafficIncidentsSchema,\n locatePlaceDescription,\n locatePlaceOutputSchema,\n locatePlaceSchema,\n queryTrafficAnalyticsDescription,\n queryTrafficAnalyticsOutputSchema,\n queryTrafficAnalyticsSchema,\n removeStopFromRouteDescription,\n removeStopFromRouteOutputSchema,\n removeStopFromRouteSchema,\n reverseGeocodeDescription,\n reverseGeocodeOutputSchema,\n reverseGeocodeSchema,\n searchAlongRouteDescription,\n searchAlongRouteOutputSchema,\n searchAlongRouteSchema,\n setRouteLocationsDescription,\n setRouteLocationsOutputSchema,\n setRouteLocationsSchema,\n setRouteParametersDescription,\n setRouteParametersOutputSchema,\n setRouteParametersSchema,\n} from './services';\n\n// --- State tools ---\nimport {\n executeGetCurrentWaypoints,\n executeRecallPlaces,\n executeRecallRanges,\n executeRecallRoutes,\n getCurrentWaypointsDescription,\n getCurrentWaypointsOutputSchema,\n getCurrentWaypointsSchema,\n recallPlacesDescription,\n recallPlacesOutputSchema,\n recallPlacesSchema,\n recallRangesDescription,\n recallRangesOutputSchema,\n recallRangesSchema,\n recallRoutesDescription,\n recallRoutesOutputSchema,\n recallRoutesSchema,\n} from './state';\n\n// --- TomTom Map tools ---\nimport {\n clearMapDescription,\n clearMapOutputSchema,\n clearMapSchema,\n executeClearMap,\n executeFitRouteSection,\n executeGetShownIncidents,\n executeGetShownPlaces,\n executeGetShownRouteSections,\n executeGetShownRoutes,\n executeGetShownRouteTrafficIncidents,\n executeGetShownWaypoints,\n executeGetStandardMapStyles,\n executeManagePlaces,\n executeSetLanguage,\n executeSetMapStandardStyle,\n executeSetRouteTheme,\n executeShowPlaces,\n executeShowRoutes,\n executeShowTrafficAreaAnalytics,\n executeShowWaypoints,\n executeToggleBaseMapLayerGroups,\n executeTogglePOIs,\n executeToggleTrafficFlow,\n executeToggleTrafficIncidents,\n fitRouteSectionDescription,\n fitRouteSectionOutputSchema,\n fitRouteSectionSchema,\n getShownIncidentsDescription,\n getShownIncidentsOutputSchema,\n getShownIncidentsSchema,\n getShownPlacesDescription,\n getShownPlacesOutputSchema,\n getShownPlacesSchema,\n getShownRouteSectionsDescription,\n getShownRouteSectionsOutputSchema,\n getShownRouteSectionsSchema,\n getShownRoutesDescription,\n getShownRoutesOutputSchema,\n getShownRoutesSchema,\n getShownRouteTrafficIncidentsDescription,\n getShownRouteTrafficIncidentsOutputSchema,\n getShownRouteTrafficIncidentsSchema,\n getShownWaypointsDescription,\n getShownWaypointsOutputSchema,\n getShownWaypointsSchema,\n getStandardMapStylesDescription,\n getStandardMapStylesOutputSchema,\n getStandardMapStylesSchema,\n managePlacesDescription,\n managePlacesOutputSchema,\n managePlacesSchema,\n setLanguageDescription,\n setLanguageOutputSchema,\n setLanguageSchema,\n setMapStandardStyleDescription,\n setMapStandardStyleOutputSchema,\n setMapStandardStyleSchema,\n setRouteThemeDescription,\n setRouteThemeOutputSchema,\n setRouteThemeSchema,\n showPlacesDescription,\n showPlacesOutputSchema,\n showPlacesSchema,\n showRouteDescription,\n showRouteOutputSchema,\n showRouteSchema,\n showTrafficAreaAnalyticsDescription,\n showTrafficAreaAnalyticsOutputSchema,\n showTrafficAreaAnalyticsSchema,\n showWaypointsDescription,\n showWaypointsOutputSchema,\n showWaypointsSchema,\n toggleBaseMapLayerGroupsDescription,\n toggleBaseMapLayerGroupsOutputSchema,\n toggleBaseMapLayerGroupsSchema,\n togglePOIsDescription,\n togglePOIsOutputSchema,\n togglePOIsSchema,\n toggleTrafficFlowDescription,\n toggleTrafficFlowOutputSchema,\n toggleTrafficFlowSchema,\n toggleTrafficIncidentsDescription,\n toggleTrafficIncidentsOutputSchema,\n toggleTrafficIncidentsSchema,\n} from './tomtom-map';\n\n// --- Utility tools ---\nimport {\n calculateBBoxDescription,\n calculateBBoxSchema,\n executeCalculateBBox,\n executeFormatDistance,\n executeFormatDuration,\n executeGetCurrentLocation,\n executeGetRouteProgress,\n executeGetSectionBBox,\n executeGetSectionProgress,\n formatDistanceDescription,\n formatDistanceSchema,\n formatDurationDescription,\n formatDurationSchema,\n getCurrentLocationDescription,\n getCurrentLocationOutputSchema,\n getCurrentLocationSchema,\n getRouteProgressDescription,\n getRouteProgressSchema,\n getSectionBBoxDescription,\n getSectionBBoxOutputSchema,\n getSectionBBoxSchema,\n getSectionProgressDescription,\n getSectionProgressSchema,\n helpDescription,\n helpOutputSchema,\n helpSchema,\n} from './utilities';\n\nconst defaultTools = {\n locatePlace: {\n description: locatePlaceDescription,\n classificationPrompt:\n 'Resolve a single location string (landmark, city, address) to a place without showing it; optionally stages a waypoint slot.',\n inputSchema: locatePlaceSchema,\n outputSchema: locatePlaceOutputSchema,\n execute: executeLocatePlace,\n tags: ['locate', 'place', 'location', 'waypoint'],\n examples: [\n 'locatePlace(\"Buckingham Palace\", where: \"within-map-bounds\", waypointIndex: 0)',\n 'locatePlace(\"Tower Bridge\", where: \"nearby-map-center\", waypointIndex: 1)',\n 'locatePlace(\"Westminster Abbey\", where: \"anywhere\")',\n 'locatePlace(\"Central Station\", where: { position: [4.9, 52.37] })',\n ],\n examplePrompts: ['Where is the Louvre?', 'Find the nearest train station', 'Locate Big Ben'],\n relatedTools: ['setRouteLocations', 'addStopToRoute', 'getCurrentWaypoints', 'recallPlaces'],\n },\n reverseGeocode: {\n description: reverseGeocodeDescription,\n classificationPrompt:\n 'Convert [lng, lat] coordinates to an address; use after map clicks or any tool that returns a position.',\n inputSchema: reverseGeocodeSchema,\n outputSchema: reverseGeocodeOutputSchema,\n execute: executeReverseGeocode,\n tags: ['location', 'place'],\n examples: ['reverseGeocode({ position: [4.9, 52.4] })'],\n examplePrompts: [\"What's the address at this point?\", 'What street is at these coordinates?'],\n relatedTools: ['getViewport', 'getCurrentLocation', 'showPlaces', 'locatePlace'],\n },\n discoverPlaces: {\n description: discoverPlacesDescription,\n classificationPrompt: 'Search for multiple places by text query or POI category within an area.',\n inputSchema: discoverPlacesSchema,\n outputSchema: discoverPlacesOutputSchema,\n execute: executeDiscoverPlaces,\n tags: ['discover', 'place', 'location'],\n examples: [\n 'discoverPlaces({ query: \"coffee\", where: { position: [4.9, 52.4] } })',\n 'discoverPlaces({ poiCategories: [\"ITALIAN_RESTAURANT\"] }) // category-only, no query needed',\n 'discoverPlaces({ query: \"hotel\", where: { boundingBox: [4.8, 52.3, 5.0, 52.5] } })',\n 'discoverPlaces({ query: \"parking\", where: \"Amsterdam\" }) // geocoded area',\n 'discoverPlaces({ query: \"coffee\", withinRange: \"ranges-0\" })',\n 'discoverPlaces({ poiCategories: [\"CAFE\"], show: { markerType: \"pin\", zoomMode: \"auto\" } })',\n ],\n examplePrompts: [\n 'Find coffee shops near me',\n 'Search for Italian restaurants in Amsterdam',\n 'Show me parking nearby',\n 'Find coffee shops within the range I just calculated',\n ],\n relatedTools: [\n 'getPOICategoryCodes',\n 'showPlaces',\n 'managePlaces',\n 'locatePlace',\n 'getViewport',\n 'findReachableArea',\n ],\n },\n setRouteLocations: {\n description: setRouteLocationsDescription,\n classificationPrompt:\n 'Set route waypoints by resolving location queries and trigger a recalculation (minimum: origin + destination).',\n inputSchema: setRouteLocationsSchema,\n outputSchema: setRouteLocationsOutputSchema,\n execute: executeSetRouteLocations,\n tags: ['route', 'waypoint', 'location'],\n examples: [\n 'setRouteLocations({ locations: [{ query: \"Amsterdam\" }, { query: \"Brussels\" }] })',\n 'setRouteLocations({ locations: [{ query: \"Eiffel Tower\" }, { query: \"Louvre Museum\" }, { query: \"Notre Dame\" }] })',\n 'setRouteLocations({ locations: [{ query: \"5th Ave, New York\", locationType: \"default\" }, { query: \"JFK Airport\", locationType: \"default\" }] })',\n ],\n examplePrompts: [\n 'Get directions from Paris to Lyon',\n 'Route me from Amsterdam to Brussels',\n 'Navigate from here to the airport',\n ],\n relatedTools: ['setRouteParameters', 'showRoute', 'addStopToRoute', 'removeStopFromRoute'],\n },\n setRouteParameters: {\n description: setRouteParametersDescription,\n classificationPrompt:\n 'Configure route options (alternatives, type, avoidances, departure/arrival time) and trigger recalculation if locations are set.',\n inputSchema: setRouteParametersSchema,\n outputSchema: setRouteParametersOutputSchema,\n execute: executeSetRouteParameters,\n tags: ['route'],\n examples: [\n 'setRouteParameters({ maxAlternatives: 2 })',\n 'setRouteParameters({ costModel: { routeType: \"fast\", avoid: [\"tollRoads\"] } })',\n 'setRouteParameters({ when: { option: \"departAt\", date: \"2025-06-01T09:00:00Z\" } })',\n ],\n examplePrompts: ['Avoid toll roads', 'Find the fastest route', 'Show 2 alternative routes', 'Depart at 9am'],\n relatedTools: ['setRouteLocations', 'showRoute'],\n },\n addStopToRoute: {\n description: addStopToRouteDescription,\n classificationPrompt: 'Insert a stop at the optimal position in the current route and recalculate.',\n inputSchema: addStopToRouteSchema,\n outputSchema: addStopToRouteOutputSchema,\n execute: executeAddStopToRoute,\n tags: ['route', 'waypoint'],\n examples: [\n 'addStopToRoute(location: \"Westminster Abbey\")',\n 'addStopToRoute(location: \"gas station near route\")',\n 'addStopToRoute() // use the most recently resolved or shown place',\n ],\n examplePrompts: ['Add a stop at Westminster Abbey', 'Add a coffee break to my route'],\n relatedTools: ['locatePlace', 'setRouteLocations', 'showRoute', 'removeStopFromRoute'],\n dependsOn: ['setRouteLocations'],\n },\n removeStopFromRoute: {\n description: removeStopFromRouteDescription,\n classificationPrompt: 'Remove a stop by index from the current route and recalculate.',\n inputSchema: removeStopFromRouteSchema,\n outputSchema: removeStopFromRouteOutputSchema,\n execute: executeRemoveStopFromRoute,\n tags: ['route', 'waypoint'],\n examples: ['removeStopFromRoute(1)', 'removeStopFromRoute(2, 1)'],\n examplePrompts: ['Remove the second stop from my route', 'Delete the Utrecht stop'],\n relatedTools: ['addStopToRoute', 'setRouteLocations', 'showRoute'],\n dependsOn: ['setRouteLocations'],\n },\n getPOICategoryCodes: {\n description: getPoiCategoryCodesDescription,\n classificationPrompt:\n 'Resolve natural-language category names (e.g. \"gym\", \"italian food\") to POICategory codes for discoverPlaces.',\n inputSchema: getPoiCategoryCodesSchema,\n outputSchema: getPoiCategoryCodesOutputSchema,\n execute: executeGetPoiCategoryCodes,\n tags: ['discover', 'place'],\n examples: [\n 'getPOICategoryCodes()',\n 'getPOICategoryCodes(filters: [\"gym\"])',\n 'getPOICategoryCodes(filters: [\"italian restaurant\"]) // multi-word phrase, spaces removed before matching',\n 'getPOICategoryCodes(filters: [\"restaurant\"], language: \"fr-FR\")',\n ],\n examplePrompts: ['What POI categories are available?', \"What's the code for gym?\"],\n relatedTools: ['discoverPlaces', 'togglePOIs'],\n },\n getTrafficIncidents: {\n description: getTrafficIncidentsDescription,\n classificationPrompt:\n 'Fetch traffic incidents by bbox or IDs without showing them; returns category, severity, and delay details.',\n inputSchema: getTrafficIncidentsSchema,\n outputSchema: getTrafficIncidentsOutputSchema,\n execute: executeGetTrafficIncidents,\n tags: ['traffic', 'location'],\n examples: [\n 'getTrafficIncidents({ bbox: [4.728, 52.278, 5.080, 52.479] })',\n 'getTrafficIncidents({ ids: [\"incident-id-1\", \"incident-id-2\"] })',\n 'getTrafficIncidents({ bbox: [...], categoryFilter: [\"accident\", \"jam\"] })',\n 'getTrafficIncidents({ bbox: [...], categoryFilter: [\"roadworks\"], timeValidityFilter: [\"future\"] })',\n ],\n examplePrompts: ['Fetch traffic incidents in Amsterdam', 'Any accidents in this area?'],\n relatedTools: ['getShownIncidents', 'toggleTrafficIncidents', 'calculateBBox', 'getViewport'],\n },\n getTrafficAreaAnalytics: {\n description: getTrafficAreaAnalyticsDescription,\n classificationPrompt:\n 'Fetch historical traffic analytics (speed, congestion, travel time) for an area; use queryTrafficAnalytics to drill down.',\n inputSchema: getTrafficAreaAnalyticsSchema,\n outputSchema: getTrafficAreaAnalyticsOutputSchema,\n execute: executeGetTrafficAreaAnalytics,\n tags: ['traffic', 'location'],\n examples: [\n \"getTrafficAreaAnalytics({ bbox: [4.728, 52.278, 5.080, 52.479], metrics: ['speed', 'congestionLevel'], startDate: '2025-03-01', endDate: '2025-03-07' })\",\n \"getTrafficAreaAnalytics({ bbox: [...], metrics: ['congestionLevel'], hours: [7,8,9,17,18] })\",\n ],\n examplePrompts: [\n 'What was the average congestion in Amsterdam last week?',\n 'Analyze traffic patterns during rush hour in this area',\n 'Show me historical speed data for the city center',\n ],\n relatedTools: ['queryTrafficAnalytics', 'showTrafficAreaAnalytics', 'calculateBBox', 'getViewport'],\n dependsOn: ['locatePlace'],\n },\n queryTrafficAnalytics: {\n description: queryTrafficAnalyticsDescription,\n classificationPrompt:\n 'Query cached traffic analytics data or check what metric/mode is currently displayed on the map.',\n inputSchema: queryTrafficAnalyticsSchema,\n outputSchema: queryTrafficAnalyticsOutputSchema,\n execute: executeQueryTrafficAnalytics,\n tags: ['traffic', 'location'],\n examples: [\n \"queryTrafficAnalytics({ granularity: 'daily' })\",\n \"queryTrafficAnalytics({ granularity: 'hourly', hourStart: 7, hourEnd: 9, metric: 'congestionLevel' })\",\n \"queryTrafficAnalytics({ granularity: 'average', dayOfWeek: [6, 7] })\",\n ],\n // NOTE: \"What am I looking at?\" awareness should be handled at a higher level\n // (e.g. system prompt or state summary injected into context), not per-tool examplePrompts.\n // Current approach works but doesn't scale — every stateful tool would need similar hints.\n examplePrompts: [\n 'Show me the daily breakdown',\n 'What was rush hour congestion?',\n 'Which day had the worst traffic?',\n 'What metric am I looking at?',\n 'What is currently shown on the map?',\n ],\n relatedTools: ['getTrafficAreaAnalytics', 'showTrafficAreaAnalytics'],\n dependsOn: ['getTrafficAreaAnalytics'],\n },\n showPlaces: {\n description: showPlacesDescription,\n classificationPrompt: 'Display a places entry on the map, replacing anything currently shown.',\n inputSchema: showPlacesSchema,\n outputSchema: showPlacesOutputSchema,\n execute: executeShowPlaces,\n tags: ['place', 'location'],\n examples: ['showPlaces()', 'showPlaces({ id: \"places-2\" })', 'showPlaces({ fitBounds: false })'],\n examplePrompts: ['Show the results on the map', 'Pin the search results', 'Display these places'],\n relatedTools: ['discoverPlaces', 'locatePlace', 'reverseGeocode', 'managePlaces', 'clearMap', 'flyTo'],\n dependsOn: ['discoverPlaces', 'locatePlace'],\n },\n managePlaces: {\n description: managePlacesDescription,\n classificationPrompt:\n 'Add more places on top of whatever is currently shown, or hide specific place entries from the map.',\n inputSchema: managePlacesSchema,\n outputSchema: managePlacesOutputSchema,\n execute: executeManagePlaces,\n tags: ['place', 'location', 'map style'],\n examples: [\n 'managePlaces({ add: [\"places-2\"] })',\n 'managePlaces({ remove: [\"places-1\"] })',\n 'managePlaces({ removeMatching: [\"cinema\"] }) // hide every entry labelled \"cinema\"',\n 'managePlaces({ addMatching: [\"cafe\"] })',\n 'managePlaces({ clear: true })',\n 'managePlaces({ add: [\"places-2\"], fitBounds: true })',\n ],\n examplePrompts: [\n 'Also show the cafes on the map',\n 'Additionally pin the pubs',\n 'Remove the banks from the map',\n 'Hide the cafes',\n ],\n relatedTools: ['discoverPlaces', 'showPlaces', 'recallPlaces', 'clearMap'],\n dependsOn: ['discoverPlaces', 'locatePlace'],\n },\n showRoute: {\n description: showRouteDescription,\n classificationPrompt: 'Render the most recently calculated route on the map and fit the camera to it.',\n inputSchema: showRouteSchema,\n outputSchema: showRouteOutputSchema,\n execute: executeShowRoutes,\n tags: ['route', 'waypoint'],\n examples: ['showRoute()', 'showRoute({ selectedIndex: 1 })', 'showRoute({ fitBounds: false })'],\n examplePrompts: ['Draw the route on the map', 'Show the directions', 'Display the calculated route'],\n relatedTools: ['setRouteLocations', 'getShownRouteSections', 'clearMap'],\n dependsOn: ['setRouteLocations'],\n },\n showTrafficAreaAnalytics: {\n description: showTrafficAreaAnalyticsDescription,\n classificationPrompt:\n 'Render traffic analytics as hexgrid, heatmap, or tiles with custom colors, filtering, height, and tooltip.',\n inputSchema: showTrafficAreaAnalyticsSchema,\n outputSchema: showTrafficAreaAnalyticsOutputSchema,\n execute: executeShowTrafficAreaAnalytics,\n tags: ['traffic', 'map style'],\n examples: [\n 'showTrafficAreaAnalytics()',\n \"showTrafficAreaAnalytics({ mode: 'hexgrid-2d', metric: 'speed', colorTheme: 'heat' })\",\n 'showTrafficAreaAnalytics({ filter: { min: 50 } })',\n \"showTrafficAreaAnalytics({ scaleMode: 'currentRange', heightScale: 200 })\",\n 'showTrafficAreaAnalytics({ visible: false })',\n ],\n examplePrompts: [\n 'Show it on the map',\n 'Visualize the congestion',\n 'Only show areas with congestion above 50%',\n 'Normalize height to the current data range',\n 'Switch to heatmap view',\n ],\n relatedTools: ['getTrafficAreaAnalytics', 'queryTrafficAnalytics', 'toggleTrafficFlow', 'clearMap'],\n dependsOn: ['getTrafficAreaAnalytics'],\n },\n showWaypoints: {\n description: showWaypointsDescription,\n classificationPrompt: 'Display staged origin/stop/destination markers without drawing the route line.',\n inputSchema: showWaypointsSchema,\n outputSchema: showWaypointsOutputSchema,\n execute: executeShowWaypoints,\n tags: ['waypoint', 'route'],\n examples: ['showWaypoints()'],\n examplePrompts: ['Show the waypoints on the map', 'Mark my route stops'],\n relatedTools: ['setRouteLocations', 'showRoute', 'getShownWaypoints', 'clearMap'],\n dependsOn: ['setRouteLocations', 'locatePlace'],\n },\n getShownPlaces: {\n description: getShownPlacesDescription,\n classificationPrompt:\n 'Return places currently displayed on the map (available after showPlaces or locatePlace).',\n inputSchema: getShownPlacesSchema,\n outputSchema: getShownPlacesOutputSchema,\n execute: executeGetShownPlaces,\n tags: ['place', 'location'],\n examples: ['getShownPlaces()'],\n examplePrompts: ['What places are on the map?', 'List the pinned locations'],\n relatedTools: ['showPlaces', 'clearMap', 'locatePlace', 'reverseGeocode'],\n dependsOn: ['showPlaces'],\n },\n getShownRoutes: {\n description: getShownRoutesDescription,\n classificationPrompt: 'Return routes currently rendered on the map (available after showRoute).',\n inputSchema: getShownRoutesSchema,\n outputSchema: getShownRoutesOutputSchema,\n execute: executeGetShownRoutes,\n tags: ['route'],\n examples: ['getShownRoutes()'],\n examplePrompts: ['What routes are displayed?', 'Is there a route on the map?'],\n relatedTools: ['showRoute', 'clearMap'],\n dependsOn: ['showRoute'],\n },\n getShownWaypoints: {\n description: getShownWaypointsDescription,\n classificationPrompt:\n 'Return waypoint markers currently shown on the map (available after showRoute or showWaypoints).',\n inputSchema: getShownWaypointsSchema,\n outputSchema: getShownWaypointsOutputSchema,\n execute: executeGetShownWaypoints,\n tags: ['waypoint', 'route'],\n examples: ['getShownWaypoints()'],\n examplePrompts: ['What waypoints are shown?', 'List the stops on the map'],\n relatedTools: ['showRoute', 'clearMap'],\n dependsOn: ['showRoute', 'showWaypoints'],\n },\n getShownRouteTrafficIncidents: {\n description: getShownRouteTrafficIncidentsDescription,\n classificationPrompt: 'Return traffic incidents overlaid on the shown route.',\n inputSchema: getShownRouteTrafficIncidentsSchema,\n outputSchema: getShownRouteTrafficIncidentsOutputSchema,\n execute: executeGetShownRouteTrafficIncidents,\n tags: ['traffic', 'route'],\n examples: ['getShownRouteTrafficIncidents()'],\n examplePrompts: ['What traffic incidents are on my route?', 'Any delays along the route?'],\n relatedTools: ['showRoute', 'clearMap', 'setRouteLocations'],\n dependsOn: ['showRoute'],\n },\n getShownRouteSections: {\n description: getShownRouteSectionsDescription,\n classificationPrompt:\n 'Return sections of a given type (toll, country, motorway, traffic) from the shown route.',\n inputSchema: getShownRouteSectionsSchema,\n outputSchema: getShownRouteSectionsOutputSchema,\n execute: executeGetShownRouteSections,\n tags: ['route', 'location', ...sectionTypes],\n examples: [\n 'getShownRouteSections(\"toll\")',\n 'getShownRouteSections(\"country\")',\n 'getShownRouteSections(\"traffic\")',\n 'getShownRouteSections(\"motorway\")',\n ],\n examplePrompts: [\n 'What countries does the route pass through?',\n 'Show me the toll sections',\n 'List the motorway sections on my route',\n ],\n relatedTools: ['showRoute', 'getShownRoutes', 'getShownRouteTrafficIncidents', 'fitRouteSection'],\n dependsOn: ['showRoute'],\n },\n getShownIncidents: {\n description: getShownIncidentsDescription,\n classificationPrompt:\n 'Return real-time incidents currently visible in the map viewport (rendered on map, not fetched from service).',\n inputSchema: getShownIncidentsSchema,\n outputSchema: getShownIncidentsOutputSchema,\n execute: executeGetShownIncidents,\n tags: ['traffic', 'location'],\n examples: ['getShownIncidents()'],\n examplePrompts: ['What traffic incidents are visible?', 'Any incidents in the current view?'],\n relatedTools: ['toggleTrafficIncidents', 'flyTo', 'getViewport'],\n dependsOn: ['toggleTrafficIncidents'],\n },\n clearMap: {\n description: clearMapDescription,\n classificationPrompt: 'Remove displayed places, routes, or all features from the map.',\n inputSchema: clearMapSchema,\n outputSchema: clearMapOutputSchema,\n execute: executeClearMap,\n tags: ['place', 'route', 'map style'],\n examples: ['clearMap()', 'clearMap([\"places\"])', 'clearMap([\"places\", \"routes\"])'],\n examplePrompts: ['Clear the map', 'Remove all markers', 'Start fresh'],\n relatedTools: ['showPlaces', 'showRoute'],\n },\n flyTo: {\n description: flyToDescription,\n classificationPrompt:\n 'Move the camera to a bounding box or specific position; use after locating places or computing bounds.',\n inputSchema: flyToSchema,\n outputSchema: flyToOutputSchema,\n execute: executeFlyTo,\n tags: ['location', 'map style'],\n examples: [\n 'flyTo({ where: { boundingBox: [4.8, 52.3, 5.0, 52.5] } })',\n 'flyTo({ where: { boundingBox: [4.8, 52.3, 5.0, 52.5], padding: 100 } })',\n 'flyTo({ where: { position: [4.9, 52.4], zoom: 14 } })',\n ],\n examplePrompts: ['Go to Berlin', 'Center the map on Rome', 'Fly to these coordinates'],\n relatedTools: ['getViewport', 'locatePlace', 'showPlaces', 'showRoute', 'calculateBBox'],\n },\n fitRouteSection: {\n description: fitRouteSectionDescription,\n classificationPrompt:\n 'Fit the camera to a specific route section by type and ID; use getShownRouteSections for valid IDs.',\n inputSchema: fitRouteSectionSchema,\n outputSchema: fitRouteSectionOutputSchema,\n execute: executeFitRouteSection,\n tags: ['route', 'map style', ...sectionTypes],\n examples: ['fitRouteSection(\"country\", \"NLD-section-1\")', 'fitRouteSection(\"traffic\", \"traffic-1\", 100)'],\n examplePrompts: ['Zoom to the toll section', 'Fit the Netherlands part of the route in view'],\n relatedTools: ['flyTo', 'showRoute', 'getShownRoutes', 'getShownRouteTrafficIncidents'],\n dependsOn: ['getShownRouteSections'],\n },\n getViewport: {\n description: getViewportDescription,\n classificationPrompt:\n 'Return the map center, zoom, and bounding box; use for area-relative queries like \"in this area\" or \"near the map center\".',\n inputSchema: getViewportSchema,\n outputSchema: getViewportOutputSchema,\n execute: executeGetViewport,\n tags: ['location', 'map style'],\n examples: ['getViewport()'],\n examplePrompts: [\n 'Where is the map centered?',\n \"What's the current map area?\",\n 'What are the current map bounds?',\n ],\n relatedTools: ['locatePlace', 'flyTo', 'discoverPlaces', 'reverseGeocode', 'getTrafficIncidents'],\n },\n recallPlaces: {\n description: recallPlacesDescription,\n classificationPrompt: 'Return the history of locatePlace/discoverPlaces calls made in this session.',\n inputSchema: recallPlacesSchema,\n outputSchema: recallPlacesOutputSchema,\n execute: executeRecallPlaces,\n tags: ['place', 'location'],\n examples: ['recallPlaces()', 'recallPlaces({ id: \"places-0\" })'],\n examplePrompts: [\n 'What places did I search for?',\n 'Show the coffee shops from earlier',\n 'What was the first place we looked up?',\n ],\n relatedTools: ['discoverPlaces', 'locatePlace', 'reverseGeocode', 'showPlaces'],\n dependsOn: ['locatePlace', 'discoverPlaces'],\n },\n recallRoutes: {\n description: recallRoutesDescription,\n classificationPrompt: 'Return previously calculated routes from this session.',\n inputSchema: recallRoutesSchema,\n outputSchema: recallRoutesOutputSchema,\n execute: executeRecallRoutes,\n tags: ['route'],\n examples: ['recallRoutes()', 'recallRoutes({ id: \"routes-0\" })'],\n examplePrompts: [\n 'What routes have I calculated?',\n 'Show the first route we planned',\n 'What was the route to Schiphol?',\n ],\n relatedTools: ['setRouteLocations', 'showRoute', 'getCurrentWaypoints'],\n dependsOn: ['setRouteLocations'],\n },\n getCurrentWaypoints: {\n description: getCurrentWaypointsDescription,\n classificationPrompt:\n 'Return the staged waypoint slots (origin, stops, destination) not yet committed to a route.',\n inputSchema: getCurrentWaypointsSchema,\n outputSchema: getCurrentWaypointsOutputSchema,\n execute: executeGetCurrentWaypoints,\n tags: ['waypoint', 'route'],\n examples: [\n 'getCurrentWaypoints()',\n 'getCurrentWaypoints({ slotIndex: 1 })',\n 'getCurrentWaypoints({ includeEmptySlots: true })',\n 'getCurrentWaypoints({ offset: 2, limit: 4 })',\n ],\n examplePrompts: ['What are my current route waypoints?', \"What's my destination?\", 'Show my staged stops'],\n relatedTools: ['locatePlace', 'setRouteLocations', 'showWaypoints', 'recallRoutes'],\n },\n getStandardMapStyles: {\n description: getStandardMapStylesDescription,\n classificationPrompt: 'List available standard map style IDs for use with setMapStandardStyle.',\n inputSchema: getStandardMapStylesSchema,\n outputSchema: getStandardMapStylesOutputSchema,\n execute: executeGetStandardMapStyles,\n tags: ['map style'],\n examples: ['getStandardMapStyles()'],\n examplePrompts: ['What map styles are available?', 'List the map themes'],\n relatedTools: ['setMapStandardStyle'],\n },\n setMapStandardStyle: {\n description: setMapStandardStyleDescription,\n classificationPrompt: 'Switch the map to a standard style preset (light, dark, satellite, driving, etc.).',\n inputSchema: setMapStandardStyleSchema,\n outputSchema: setMapStandardStyleOutputSchema,\n execute: executeSetMapStandardStyle,\n tags: ['map style'],\n examples: ['setMapStandardStyle(\"standardDark\")', 'setMapStandardStyle(\"satellite\")'],\n examplePrompts: ['Switch to dark mode', 'Use the satellite view', 'Change to the light theme'],\n relatedTools: ['getStandardMapStyles', 'setLanguage', 'toggleBaseMapLayerGroups', 'getMapStyleLayers'],\n },\n setRouteTheme: {\n description: setRouteThemeDescription,\n classificationPrompt:\n 'Color the route line and waypoint icons; prefer over setPaintProperties for route styling.',\n inputSchema: setRouteThemeSchema,\n outputSchema: setRouteThemeOutputSchema,\n execute: executeSetRouteTheme,\n tags: ['route', 'map style'],\n examples: [\n 'setRouteTheme({ mainColor: \"#FF0000\" }) // red route',\n 'setRouteTheme({ mainColor: \"coral\" })',\n 'setRouteTheme({ mainColor: \"steelblue\" })',\n ],\n examplePrompts: ['Make the route line red', 'Change the route color to blue', 'Style the route in coral'],\n relatedTools: ['showRoute', 'setRouteLocations', 'setPaintProperties'],\n dependsOn: ['showRoute'],\n },\n setLanguage: {\n description: setLanguageDescription,\n classificationPrompt: 'Change the language for map labels and all subsequent service API responses.',\n inputSchema: setLanguageSchema,\n outputSchema: setLanguageOutputSchema,\n execute: executeSetLanguage,\n tags: ['map style'],\n examples: ['setLanguage(\"fr-FR\")', 'setLanguage(\"de-DE\")'],\n examplePrompts: ['Show map labels in French', 'Switch the map to German', 'Use Spanish for place names'],\n relatedTools: ['setMapStandardStyle'],\n },\n toggleBaseMapLayerGroups: {\n description: toggleBaseMapLayerGroupsDescription,\n classificationPrompt:\n 'Show or hide named base map layer groups (buildings3D, roadLabels, water, placeLabels, etc.).',\n inputSchema: toggleBaseMapLayerGroupsSchema,\n outputSchema: toggleBaseMapLayerGroupsOutputSchema,\n execute: executeToggleBaseMapLayerGroups,\n tags: ['map style'],\n examples: [\n 'toggleBaseMapLayerGroups(false, [\"buildings3D\"])',\n 'toggleBaseMapLayerGroups(true, [\"roadLabels\"])',\n ],\n examplePrompts: ['Hide 3D buildings', 'Show road labels', 'Toggle the building layer'],\n relatedTools: ['togglePOIs', 'getMapStyleLayers', 'setMapStandardStyle'],\n },\n togglePOIs: {\n description: togglePOIsDescription,\n classificationPrompt: 'Show or hide built-in map POI icons with optional category filtering.',\n inputSchema: togglePOIsSchema,\n outputSchema: togglePOIsOutputSchema,\n execute: executeTogglePOIs,\n tags: ['place', 'map style'],\n examples: [\n 'togglePOIs({ allMapPOIsVisible: false })',\n 'togglePOIs({ allMapPOIsVisible: true, filterCategories: { show: \"only\", values: [\"RESTAURANT\", \"CAFE\"] } })',\n 'togglePOIs({ filterCategories: { show: \"all_except\", values: [\"PARKING_GARAGE\"] } })',\n 'togglePOIs({ reset: true })',\n ],\n examplePrompts: ['Hide all POI icons', 'Show only restaurant POIs', 'Turn off parking icons'],\n relatedTools: ['toggleBaseMapLayerGroups', 'discoverPlaces', 'setMapStandardStyle'],\n },\n toggleTrafficFlow: {\n description: toggleTrafficFlowDescription,\n classificationPrompt:\n 'Toggle REAL-TIME traffic flow (colored road segments for live speeds). Not historical analytics.',\n inputSchema: toggleTrafficFlowSchema,\n outputSchema: toggleTrafficFlowOutputSchema,\n execute: executeToggleTrafficFlow,\n tags: ['traffic', 'map style'],\n examples: ['toggleTrafficFlow(true)', 'toggleTrafficFlow(false)'],\n examplePrompts: ['Show traffic flow', 'Turn off traffic colors', 'Enable the congestion overlay'],\n relatedTools: ['toggleTrafficIncidents', 'setRouteLocations', 'getTrafficIncidents'],\n },\n toggleTrafficIncidents: {\n description: toggleTrafficIncidentsDescription,\n classificationPrompt:\n 'Toggle REAL-TIME traffic incident markers and lines (accidents, jams, closures). Not historical analytics.',\n inputSchema: toggleTrafficIncidentsSchema,\n outputSchema: toggleTrafficIncidentsOutputSchema,\n execute: executeToggleTrafficIncidents,\n tags: ['traffic', 'map style'],\n examples: ['toggleTrafficIncidents(true)', 'toggleTrafficIncidents(false)'],\n examplePrompts: ['Show traffic incidents', 'Hide accident icons', 'Enable incident markers'],\n relatedTools: ['toggleTrafficFlow', 'getTrafficIncidents', 'getShownIncidents', 'setRouteLocations'],\n },\n getMapStyleLayers: {\n description: getMapStyleLayersDescription,\n classificationPrompt: 'List MapLibre layer IDs with their paint/layout properties for custom styling.',\n inputSchema: getMapStyleLayersSchema,\n outputSchema: getMapStyleLayersOutputSchema,\n execute: executeGetMapStyleLayers,\n tags: ['map style'],\n examples: ['getMapStyleLayers()', 'getMapStyleLayers(\"road\")', 'getMapStyleLayers(\"water\")'],\n examplePrompts: ['What are the paint properties of the water layer?', 'Show me the road layer layout'],\n relatedTools: ['setLayoutProperties', 'setPaintProperties'],\n },\n setLayoutProperties: {\n description: setLayoutPropertiesDescription,\n classificationPrompt: 'Set MapLibre layout properties (visibility, text-field, icon-size) on named layers.',\n inputSchema: setLayoutPropertiesSchema,\n outputSchema: setLayoutPropertiesOutputSchema,\n execute: executeSetLayoutProperties,\n tags: ['map style'],\n examples: [\n 'setLayoutProperties([{ layerId: \"road-label\", propertyName: \"visibility\", value: \"none\" }])',\n 'setLayoutProperties([{ layerId: \"poi-label\", propertyName: \"text-field\", value: \"{name}\" }, { layerId: \"poi-label\", propertyName: \"icon-size\", value: 1.2 }])',\n ],\n examplePrompts: [\n 'Hide the road-label layer',\n 'Change the text size on building labels',\n 'Make the city labels bigger',\n ],\n relatedTools: ['getMapStyleLayers', 'setPaintProperties'],\n dependsOn: ['getMapStyleLayers'],\n },\n setPaintProperties: {\n description: setPaintPropertiesDescription,\n classificationPrompt: 'Set MapLibre paint properties (colors, widths, opacity) on named layers.',\n inputSchema: setPaintPropertiesSchema,\n outputSchema: setPaintPropertiesOutputSchema,\n execute: executeSetPaintProperties,\n tags: ['map style'],\n examples: [\n 'setPaintProperties([{ layerId: \"water\", propertyName: \"fill-color\", value: \"#0000ff\" }])',\n 'setPaintProperties([{ layerId: \"road\", propertyName: \"line-color\", value: \"#ff0000\" }, { layerId: \"road\", propertyName: \"line-width\", value: 3 }])',\n ],\n examplePrompts: [\n 'Make the water bright blue',\n 'Change the road color to red',\n 'Make buildings semi-transparent',\n 'Make the country borders pink',\n ],\n relatedTools: ['getMapStyleLayers', 'setLayoutProperties', 'setRouteTheme'],\n dependsOn: ['getMapStyleLayers'],\n },\n setPitchBearing: {\n description: setPitchBearingDescription,\n classificationPrompt: 'Tilt (pitch) and/or rotate (bearing) the map camera for a 3D perspective.',\n inputSchema: setPitchBearingSchema,\n outputSchema: setPitchBearingOutputSchema,\n execute: executeSetPitchBearing,\n tags: ['map style'],\n examples: [\n 'setPitchBearing({ pitch: 45 })',\n 'setPitchBearing({ bearing: 90 })',\n 'setPitchBearing({ pitch: 60, bearing: -45 })',\n ],\n examplePrompts: ['Tilt the map to 45 degrees', 'Rotate the map to face north', 'Set a 3D perspective view'],\n relatedTools: ['getViewport', 'locatePlace', 'flyTo'],\n },\n zoomInOrOut: {\n description: zoomInOrOutDescription,\n classificationPrompt: 'Adjust the map zoom level by a delta; positive zooms in, negative zooms out.',\n inputSchema: zoomInOrOutSchema,\n outputSchema: zoomInOrOutOutputSchema,\n execute: executeZoomInOrOut,\n tags: ['map style'],\n examples: ['zoomInOrOut({ delta: 2 })', 'zoomInOrOut({ delta: -1 })'],\n examplePrompts: ['Zoom in', 'Zoom out 2 levels', 'Get a wider view'],\n relatedTools: ['getViewport', 'flyTo'],\n },\n executeMaplibreCode: {\n description: executeMaplibreCodeDescription,\n classificationPrompt:\n 'Execute any MapLibre JS code against the live map for maximum flexibility — use when no other tool covers the required operation.',\n inputSchema: executeMaplibreCodeSchema,\n outputSchema: executeMaplibreCodeOutputSchema,\n execute: executeExecuteMaplibreCode,\n tags: ['map style', 'maplibre', 'layers', 'sources', 'animation'],\n examples: [\n \"executeMaplibreCode({ code: \\\"map.addSource('pts', { type: 'geojson', data: fc }); map.addLayer({ id: 'pts', type: 'circle', source: 'pts', paint: { 'circle-color': '#f00' } })\\\" })\",\n 'executeMaplibreCode({ code: \"map.easeTo({ center: [4.9, 52.37], zoom: 14, duration: 2000 })\" })',\n \"executeMaplibreCode({ code: \\\"for (let i = 0; i <= 20; i++) { map.setPaintProperty('fill', 'fill-opacity', i / 20); await new Promise(r => setTimeout(r, 50)); }\\\" })\",\n \"executeMaplibreCode({ code: \\\"map.setFog({ color: 'white', 'horizon-blend': 0.1 })\\\" })\",\n ],\n examplePrompts: [\n 'Add a GeoJSON layer to the map',\n 'Animate the map camera',\n 'Fade in a layer gradually',\n 'Set map fog or atmosphere',\n 'Add a raster tile overlay',\n ],\n relatedTools: ['getMapStyleLayers', 'setLayoutProperties', 'setPaintProperties', 'flyTo'],\n dependsOn: ['getMapStyleLayers'],\n },\n calculateBBox: {\n description: calculateBBoxDescription,\n classificationPrompt:\n 'Compute a [minLng, minLat, maxLng, maxLat] bounding box from GeoJSON features or tool results.',\n inputSchema: calculateBBoxSchema,\n execute: executeCalculateBBox,\n tags: ['utilities', 'location'],\n examples: ['calculateBBox(place)', 'calculateBBox(routes)', 'calculateBBox([place1, place2])'],\n examplePrompts: [\"What's the bounding box of these places?\", 'Calculate the extent of this route'],\n relatedTools: ['flyTo', 'getViewport', 'showPlaces', 'showRoute'],\n },\n formatDistance: {\n description: formatDistanceDescription,\n classificationPrompt:\n 'Format meters into a human-readable string (e.g. \"2.5 km\"); use after tools that return distances.',\n inputSchema: formatDistanceSchema,\n execute: executeFormatDistance,\n tags: ['utilities', 'route'],\n examples: ['formatDistance(2500)', 'formatDistance(5000, \"imperial_us\")'],\n examplePrompts: ['Format 5000 meters as a distance', 'Convert meters to a readable string'],\n relatedTools: ['formatDuration', 'setRouteLocations', 'getSectionProgress', 'getRouteProgress'],\n },\n formatDuration: {\n description: formatDurationDescription,\n classificationPrompt:\n 'Format seconds into a human-readable string (e.g. \"1 h 30 min\"); use after tools that return durations.',\n inputSchema: formatDurationSchema,\n execute: executeFormatDuration,\n tags: ['utilities', 'route'],\n examples: ['formatDuration(3600)', 'formatDuration(9000)'],\n examplePrompts: ['Format 3600 seconds as a duration', 'Convert seconds to hours and minutes'],\n relatedTools: ['formatDistance', 'setRouteLocations', 'getSectionProgress', 'getRouteProgress'],\n },\n getSectionProgress: {\n description: getSectionProgressDescription,\n classificationPrompt:\n 'Return the distance and travel time for one or more sections of the shown route by type.',\n inputSchema: getSectionProgressSchema,\n execute: executeGetSectionProgress,\n tags: ['utilities', 'route', ...sectionTypes],\n examples: [\n 'getSectionProgress({ sectionType: \"country\" }) // all country sections',\n 'getSectionProgress({ sectionType: \"traffic\", ids: [\"incident-id-1\"] })',\n 'getSectionProgress({ sectionType: \"toll\", ids: [\"toll-1\", \"toll-2\"] })',\n ],\n examplePrompts: ['How far is the toll section?', 'Travel time through France on this route'],\n relatedTools: ['setRouteLocations', 'fitRouteSection', 'formatDistance', 'formatDuration'],\n dependsOn: ['showRoute'],\n },\n getSectionBBox: {\n description: getSectionBBoxDescription,\n classificationPrompt: 'Return the bounding box of a specific route section; use with flyTo to frame it.',\n inputSchema: getSectionBBoxSchema,\n outputSchema: getSectionBBoxOutputSchema,\n execute: executeGetSectionBBox,\n tags: ['utilities', 'route', 'location', ...sectionTypes],\n examples: [\n 'getSectionBBox({ sectionType: \"country\", id: \"NLD-section-1\" })',\n 'getSectionBBox({ sectionType: \"traffic\", id: \"traffic-1\" })',\n 'getSectionBBox({ sectionType: \"toll\", id: \"toll-2\" })',\n ],\n examplePrompts: ['Get the extent of the Netherlands section', 'Bounding box of the traffic incident'],\n relatedTools: ['flyTo', 'fitRouteSection', 'getSectionProgress', 'getShownRouteSections'],\n dependsOn: ['getShownRouteSections'],\n },\n getRouteProgress: {\n description: getRouteProgressDescription,\n classificationPrompt:\n 'Return the position along the shown route at a given traveled time, distance, or clock time.',\n inputSchema: getRouteProgressSchema,\n execute: executeGetRouteProgress,\n tags: ['utilities', 'route', 'location'],\n examples: [\n 'getRouteProgress(traveledTimeInSeconds: 600)',\n 'getRouteProgress(traveledDistanceInMeters: 5000)',\n 'getRouteProgress(clockTime: \"2025-06-01T09:30:00Z\")',\n 'getRouteProgress(traveledTimeInSeconds: 300, routeIndex: 1)',\n ],\n examplePrompts: ['Where am I after 10 minutes of travel?', 'Position at 5km into the route'],\n relatedTools: ['setRouteLocations', 'getSectionProgress', 'formatDistance', 'formatDuration'],\n dependsOn: ['showRoute'],\n },\n getCurrentLocation: {\n description: getCurrentLocationDescription,\n classificationPrompt:\n 'Get the user\\'s physical GPS location from the browser; use for \"near me\" queries, not map center.',\n inputSchema: getCurrentLocationSchema,\n outputSchema: getCurrentLocationOutputSchema,\n execute: executeGetCurrentLocation,\n tags: ['utilities', 'location'],\n examples: ['getCurrentLocation()'],\n examplePrompts: ['Where am I?', 'Get my GPS location', 'Use my current position'],\n relatedTools: ['discoverPlaces', 'reverseGeocode', 'locatePlace'],\n },\n help: {\n description: helpDescription,\n classificationPrompt:\n 'Return available capabilities in summary or searchable detail mode; call when the user asks what you can do.',\n inputSchema: helpSchema,\n outputSchema: helpOutputSchema,\n execute: async () => {\n throw new Error('help tool requires setupTools() — it needs resolved metadata from all tools.');\n },\n tags: ['utilities'],\n examples: [\n 'help({ mode: \"summary\" })',\n 'help({ mode: \"detail\", query: \"traffic\" })',\n 'help({ mode: \"detail\", tag: \"route\" })',\n 'help({ mode: \"detail\", query: \"route\", tag: \"utilities\" })',\n ],\n examplePrompts: ['What can you do?', 'Show me available tools', 'How do I search for places?'],\n },\n searchAlongRoute: {\n description: searchAlongRouteDescription,\n classificationPrompt: 'Search for POIs along a calculated route ranked by detour cost.',\n inputSchema: searchAlongRouteSchema,\n outputSchema: searchAlongRouteOutputSchema,\n execute: executeSearchAlongRoute,\n tags: ['search', 'route', 'place', 'detour', 'along-route'],\n examples: [\n 'searchAlongRoute({ maxDetourTimeSeconds: 300, query: \"coffee\" })',\n 'searchAlongRoute({ maxDetourTimeSeconds: 600, poiCategories: [\"ELECTRIC_VEHICLE_STATION\"], sortBy: \"detourOffset\" })',\n 'searchAlongRoute({ maxDetourTimeSeconds: 300, routeIndex: 0, show: { markerType: \"pin\", zoomMode: \"auto\" } })',\n ],\n examplePrompts: [\n 'Find gas stations along my route',\n 'Show me coffee shops within 5 minutes off the route',\n 'Any EV chargers I can reach from this route?',\n 'I need a coffee stop on the way to the airport',\n 'Find me a restaurant somewhere between here and Paris',\n ],\n relatedTools: ['setRouteLocations', 'recallRoutes', 'showPlaces', 'recallPlaces'],\n dependsOn: ['setRouteLocations'],\n },\n findReachableArea: {\n description: findReachableAreaDescription,\n classificationPrompt: 'Calculate isochrone/isodistance polygons showing how far you can travel from a point.',\n inputSchema: findReachableAreaSchema,\n outputSchema: findReachableAreaOutputSchema,\n execute: executeFindReachableArea,\n tags: ['reachable-range', 'isochrone', 'range', 'EV', 'coverage'],\n examples: [\n 'findReachableArea({ origin: { query: \"Amsterdam\", locationType: \"default\" }, budgets: [{ type: \"timeMinutes\", value: 30 }], showOnMap: true })',\n 'findReachableArea({ origin: { position: { lng: 4.9, lat: 52.3 } }, budgets: [{ type: \"timeMinutes\", value: 10 }, { type: \"timeMinutes\", value: 30 }], showOnMap: true, theme: \"inverted\" })',\n 'findReachableArea({ origin: { query: \"my location\", locationType: \"default\" }, budgets: [{ type: \"distanceKM\", value: 50 }], showOnMap: false })',\n ],\n examplePrompts: [\n 'Show me where I can reach in 30 minutes from Amsterdam',\n 'What area is within 50 km of Berlin?',\n 'Show 10, 20, 30 minute drive zones from here',\n ],\n relatedTools: ['recallRanges', 'locatePlace'],\n },\n recallRanges: {\n description: recallRangesDescription,\n classificationPrompt: 'Retrieve stored reachable range results from session history.',\n inputSchema: recallRangesSchema,\n outputSchema: recallRangesOutputSchema,\n execute: executeRecallRanges,\n tags: ['recall', 'reachable-range', 'state'],\n examples: ['recallRanges()', 'recallRanges({ id: \"ranges-0\" })'],\n examplePrompts: ['What range did I calculate earlier?', 'Recall the isochrone from Amsterdam'],\n relatedTools: ['findReachableArea'],\n },\n} satisfies Record<string, ToolEntry>;\n\n// Narrow the value type so the emitted d.ts captures only the keys, not the\n// inlined `z.infer<...>` signatures from each `execute` (which the d.ts bundler\n// flattens to invalid `infer<typeof X>` syntax). Must go through an intermediate\n// const so TypeScript resolves the mapped type before re-exporting.\nconst DEFAULT_TOOLS_TYPED: { [K in keyof typeof defaultTools]: ToolEntry } = defaultTools;\n\n/**\n * Default tool set for the agent toolkit.\n * Included automatically by createMapAgent unless includeDefaultTools is false.\n * Use resolveTools() for manual composition outside createMapAgent.\n *\n * @group Agent Toolkit\n */\nexport const DEFAULT_TOOLS = DEFAULT_TOOLS_TYPED;\n\n/**\n * Union of all default tool names.\n *\n * @group Agent Toolkit\n */\nexport type ToolName = keyof typeof DEFAULT_TOOLS;\n\n/**\n * All valid default tool names, derived from {@link DEFAULT_TOOLS}.\n *\n * @group Agent Toolkit\n */\nexport const TOOL_NAMES = Object.keys(DEFAULT_TOOLS) as ToolName[];\n","/**\n * @module agent-toolkit\n */\n\nimport type { TomTomMap } from '@tomtom-org/maps-sdk/map';\nimport type { PrepareStepFunction, PrepareStepResult } from 'ai';\nimport { stepCountIs, ToolLoopAgent } from 'ai';\nimport { resolveTools } from './resolve-tools';\nimport { createToolState } from './state';\nimport { buildSystemPrompt } from './system-prompt';\nimport { setupTools } from './tool-setup';\nimport { DEFAULT_TOOLS } from './tools';\nimport type { Classifier, MapAgentInstance, MapAgentOptions, StateSlice, ToolEntry, ToolState } from './types';\nimport type { ClassificationResult } from './utils';\nimport { createDefaultClassifier } from './utils';\n\n/** Intersects two activeTools lists. Returns undefined if neither is set. */\nconst intersectActiveTools = (\n a: string[] | undefined,\n b: readonly (string | number | symbol)[] | undefined,\n): string[] | undefined => {\n if (!a) return b as string[] | undefined;\n if (!b) return a;\n const setB = new Set(b);\n return a.filter((name) => setB.has(name));\n};\n\n/** Type guard for StateSlice — checks for reset() method. */\nconst isStateSlice = (value: unknown): value is StateSlice =>\n typeof value === 'object' && value !== null && 'reset' in value && typeof (value as any).reset === 'function';\n\n/** Resets all state slices that implement StateSlice. */\nconst destroyState = (state: ToolState): void => {\n for (const slice of Object.values(state)) {\n if (isStateSlice(slice)) {\n slice.reset();\n }\n }\n};\n\n/**\n * Creates a conversational agent toolkit that gives an LLM control over a TomTom map.\n *\n * Returns a ToolLoopAgent instance (compatible with DirectChatTransport) with\n * `state` and `destroy` attached. Classification runs transparently inside\n * `prepareStep` — no wrapper type needed.\n *\n * @param map - The TomTomMap instance to control\n * @param options - Agent configuration options\n * @returns A ToolLoopAgent with state access and cleanup\n *\n * @example Basic usage\n * ```typescript\n * import { createMapAgent } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';\n * import { openai } from '@ai-sdk/openai';\n * import { DirectChatTransport } from 'ai/react';\n *\n * const agent = createMapAgent(map, { model: openai('gpt-4o') });\n *\n * // Works directly with DirectChatTransport — no .agent property needed\n * const { messages, sendMessage } = useChat({\n * transport: new DirectChatTransport({ agent }),\n * });\n * ```\n *\n * @example Custom tools + removal\n * ```typescript\n * const agent = createMapAgent(map, {\n * model: openai('gpt-4o'),\n * tools: {\n * getCustomLocation: myLocationTool, // add custom\n * setLanguage: false, // remove default\n * },\n * });\n * ```\n * @group Agent Toolkit\n */\nexport const createMapAgent = <CS extends ToolState = ToolState>(\n map: TomTomMap,\n options: MapAgentOptions<CS>,\n): MapAgentInstance<CS> => {\n if (!options.model) {\n throw new Error('MapAgent requires a model option. Please provide an AI SDK LanguageModel instance.');\n }\n\n const state = createToolState(map, options.state) as CS;\n\n // Safe: default tools only access base ToolState properties; CS extends ToolState.\n const defaults = options.includeDefaultTools === false ? {} : (DEFAULT_TOOLS as Record<string, ToolEntry<CS>>);\n const toolEntries = resolveTools(defaults, options.tools);\n\n const { tools, toolsMetadata } = setupTools(toolEntries, state, {\n outputSchemas: options.outputSchemas,\n });\n\n // Resolve classifier\n const classifier: Classifier | null =\n options.classifier === false ? null : (options.classifier ?? createDefaultClassifier({ model: options.model }));\n\n const systemPrompt = buildSystemPrompt(options.systemPrompt, options.systemPromptSuffix);\n\n // Classification state — cached per turn (reset on step 0)\n let lastClassification: ClassificationResult | null = null;\n\n const prepareStep: PrepareStepFunction = async (stepInfo) => {\n let activeTools: string[] | undefined;\n\n if (stepInfo.stepNumber === 0) {\n lastClassification = null;\n if (classifier) {\n try {\n lastClassification = await classifier({\n messages: stepInfo.messages,\n toolsMetadata,\n });\n } catch {\n lastClassification = null;\n }\n }\n options.onClassify?.(lastClassification);\n }\n\n if (lastClassification) {\n activeTools = lastClassification.activeToolNames;\n }\n\n // Compose with developer's prepareStep\n const userResult: PrepareStepResult | undefined = await options.prepareStep?.(stepInfo);\n\n if (userResult) {\n return {\n ...userResult,\n activeTools: intersectActiveTools(activeTools, userResult.activeTools),\n };\n }\n\n return activeTools ? { activeTools } : {};\n };\n\n const agent = new ToolLoopAgent({\n model: options.model,\n tools,\n instructions: systemPrompt,\n stopWhen: stepCountIs(options.maxSteps ?? 10),\n prepareStep,\n });\n\n return Object.assign(agent, {\n state,\n destroy: () => destroyState(state),\n });\n};\n"],"mappings":"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"}
|