Agent Toolkit state
The Agent Toolkit maintains structured state across the full conversation. As a rule, tools return
compact summaries instead of raw GeoJSON, and keep the underlying data in state — so the next tool
call (or the next user turn) can read it without the model having to re-derive or hallucinate it.
The opt-in recallState tool (scoped via kind) intentionally returns full feature
collections when the caller asks for an entry by id, but day-to-day discovery / analyse / process
tools stay summary-shaped.
State slices
State is organized by feature area:
Slices flagged entries own an append-only history of results; the rest are flat
configuration. Entry-bearing slices share a uniform shape — entries, entryMode,
setEntryMode(mode) — so the same code paths handle them all (see Entry mode).
| State slice | Entries | What it holds |
|---|---|---|
places | ✅ | Append-only history of place entries (search results, single-location lookups, processed sets). Each entry carries its own lazy PlacesModule and GeometriesModule for pins and footprints. |
routing | ✅ | Append-only history of route entries, staged waypoint slots, current route parameters, and a per-entry RoutingModule. |
ranges | ✅ | Reachable range (isochrone / isodistance) entries — origins, budgets, polygons, and per-entry display modules. |
customGeometries | ✅ | Derived polygon entries — output of processData (union, buffer, difference, h3 coverage, …) — kept separate from places so their provenance (source ids, operation label) stays explicit. |
byod | ✅ | Bring-your-own-data GeoJSON layer entries — customer-authored sources the agent can read and render alongside the built-in stack. Each entry carries an auto-detected BYODDataProfile (geometry types + per-property types/coverage/examples) derived on ingest. |
trafficAreaAnalytics | ✅ | Historical area-analytics entries: aggregation module, fetched results, and per-entry visualization config (hexgrid, heatmap, tiles). |
trafficIncidents | ✅ | Fetched incident entries, the optional polling monitor that keeps them fresh, registered analyses (_analysis[name]), and per-entry rendering. |
baseMap | — | Viewport, style, language, layer-group visibility, and the raw MapLibre Map instance. |
mapPOIs | — | Built-in map POI layer visibility and category filtering. |
trafficTiles | — | Real-time traffic flow + incident overlay tile visibility. |
Sharing across tools
State is shared across all tools. A place resolved by locatePlace is immediately available to
addWaypointsToRoute without the model having to pass it along — tools read directly from shared
stores. This prevents the hallucination-prone “read then pass” pattern.
The recallState tool exists because tool results
are not retained in conversation history. If a user asks “what were those places?” an hour into a
session, the model calls a recall tool — it does not guess or hallucinate prior results.
Entry mode
Every entry-bearing slice exposes an entry mode: multiple (default) lets several
entries render side-by-side; single keeps only the most recent one and auto-drops older
entries when flipped. The set of slices that support it is captured in the
EntryModeSliceName union — slice names there match the keys on agent.state exactly
(routing, not routes; customGeometries, not geometries), so the same name flows
through every layer:
| Slice | Field |
|---|---|
places | agent.state.places |
routing | agent.state.routing |
ranges | agent.state.ranges |
customGeometries | agent.state.customGeometries |
byod | agent.state.byod |
trafficAreaAnalytics | agent.state.trafficAreaAnalytics |
trafficIncidents | agent.state.trafficIncidents |
The model surfaces entry-mode changes through the setEntryMode tool when the user asks
to “only show one at a time” or “let me overlay multiple”. It accepts any of the slice
names above.
Defaults via createMapAgent
Set per-kind defaults at construction time with the dataEntries option. Each kind accepts
{ enabled?, entryMode? }. Keys are LLM-facing kind names (routes, incidents) — not
slice names (routing, trafficIncidents); the slice mapping is internal.
import { createMapAgent } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
const agent = createMapAgent(map, { model: openai('gpt-4o'), dataEntries: { routes: { entryMode: 'single' }, // only one route on the map incidents: { entryMode: 'single' }, // each refresh replaces the previous snapshot byod: { enabled: false }, // hide byod from analyse/process scope + drop addByodSource / setByodLayers / updateByodDisplay },});Omit a kind to leave it at its defaults (enabled: true, entryMode: 'multiple'). Setting
enabled: false is aggressive: the kind disappears from the agent’s tool surface entirely —
it is removed from analyseData / processData scope and input fields, and the slice’s
recall / display / fetch tools are dropped from the registry. See
TOOLS_BY_DATA_ENTRY_KIND for the
exact tool list per kind.
Modes can also be flipped at any time after construction:
await agent.state.customGeometries.setEntryMode('single');Working with the union from your own code
The reusable EntryModeSliceName type and the runtime list ENTRY_MODE_SLICE_NAMES are
exported so custom tools and dev UIs can iterate every entry-mode-aware slice without
hard-coding the names:
import { ENTRY_MODE_SLICE_NAMES, type EntryModeSliceName,} from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
for (const slice of ENTRY_MODE_SLICE_NAMES) { console.log(slice, agent.state[slice].entryMode);}Inspecting state from your application
You can read live state at any time:
agent.state.routing.currentRoutes; // most recent route resultsagent.state.places.latestPlace; // most recent place resultsagent.state.places.entries; // full history of place entriesagent.state.trafficIncidents.entries; // fetched incident entriesagent.state.trafficAreaAnalytics.entries; // historical analytics entriesagent.state.customGeometries.entries; // derived polygon entriesagent.state.byod.entries; // bring-your-own-data layer entriesagent.state.baseMap.mapLibreMap; // raw MapLibre Map instanceCustom state slices
If your custom tools need to share data across calls, extend ToolState with your own slice.
Implement reset() to participate in agent.destroy() cleanup:
import type { ToolState, StateSlice } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
class FleetState implements StateSlice { vehicles: Map<string, VehiclePosition> = new Map(); reset() { this.vehicles.clear(); }}
interface MyState extends ToolState { fleet: FleetState;}
const agent = createMapAgent<MyState>(map, { model: openai('gpt-4o'), state: { fleet: new FleetState() }, tools: { getFleetVehicle: myFleetTool },});
// Access live state from your applicationagent.state.fleet.vehicles;agent.state.routing.currentRoutes;For the tools that read and write these slices, see Tool registry.
State lives in the page, so everything in it is visible and editable by the person using your application. Securing your agent covers what follows from that.