How the Agent Toolkit works

The Agent Toolkit sits between your application (chat UI and LLM provider) and the TomTom Maps SDK. Each user message goes through two phases — intent classification, then a tool loop — and shared plugin state carries context across turns.

Your ApplicationAgent Toolkit PluginMaps SDK for JavaScriptChat UI (BYO)LLM Provider (BYO)Intent ClassifierToolsState

1. Intent classification

Before the model sees the full tool list, a lightweight pre-pass selects only the tools relevant to this turn. Fewer tools in the prompt means fewer wrong choices and lower token usage.

The classifier is built from each tool’s classificationPrompt — a one-liner that describes when to activate that tool. When you add a custom tool, it participates in classification automatically as long as it has a classificationPrompt.

For scopable tools (analyseData, processData, and any custom tool that declares a scopeSchema + scopePrompt), the classifier also emits a toolScopes[<name>] value naming the narrower input kinds the turn touches — mandatory whenever a scopable tool is selected. prepareStep validates the scope against the tool’s scopeSchema and rebuilds that tool’s description + inputSchema for the upcoming step into a per-kind narrowed surface. The narrowing is invisible to the model — it just sees a smaller, more focused prompt. See Scope-aware data tools for the contract and how to add scopable custom tools.

The default classifier reuses your main model. For cost-sensitive deployments, swap it for a smaller model:

import { createMapAgent, createDefaultClassifier } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
import { openai } from '@ai-sdk/openai';
const agent = createMapAgent(map, {
model: openai('gpt-4o'),
classifier: createDefaultClassifier({ model: openai('gpt-4o-mini') }),
});

Or disable classification entirely (all tools always visible; scopable tools fall back to their terse unscoped surface, which is cheaper than their full per-kind doc but less detailed):

const agent = createMapAgent(map, {
model: openai('gpt-4o'),
classifier: false,
});

2. Tool loop

The model calls tools — geocode, search, route, show on map — in sequence or in parallel until it can form a complete answer. By default tools return compact summaries (counts, names, labels, status) instead of raw GeoJSON, and the full geospatial data is kept in plugin state for follow-up use. The opt-in recall tools (recallByod, recallGeometries, …) can return full feature collections when the model asks for a specific entry, but they are the exception, not the rule.

State persists across turns, so the user can say “add a stop after the first one” or “what were those restaurants again?” without repeating context. The agent retrieves prior results from its internal stores via dedicated recall tools.

See State for what is kept across turns, and Tool registry for the registry itself.

Per-turn sequence

The end-to-end picture of one user message:

User messageIntent classifierprepareStep rebuilds narrowed inputSchema for scopable toolsTool loopFinal assistant replyPicks active toolsEmits per-tool scopes { analyseData: { kinds: [...] } }Model picks a tool, calls itTool execute returns summaryHeavy data lands in state 1. classify2. activeToolNames + toolScopes3. rebuilt schemas4. call5. persist 6. next step reads state7. done — compose answer

Extending the system prompt

Append to the built-in prompt

const agent = createMapAgent(map, {
model: openai('gpt-4o'),
systemPromptSuffix: 'Always respond in Spanish. Never show more than 5 places at once.',
});

Full replacement

Import BASE_SYSTEM_PROMPT as a baseline to extend rather than starting from scratch. The base prompt contains coordinate order rules, tool-usage guidance, and response formatting instructions that are important for reliability:

import { createMapAgent, BASE_SYSTEM_PROMPT } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
const agent = createMapAgent(map, {
model: openai('gpt-4o'),
systemPrompt: BASE_SYSTEM_PROMPT + `
ADDITIONAL INSTRUCTIONS:
- This is a logistics application. Prioritize route efficiency over scenery.
- Always show estimated arrival times in responses.
- When a vehicle ID is mentioned, call getFleetVehicle before anything else.
`,
});

Per-tool classification prompts

If your custom tool is being activated too broadly or not activated when it should be, tune its classificationPrompt. This is the one-liner the classifier uses to decide whether a user message needs this tool:

// Too broad — activates for any location question
classificationPrompt: 'Get fleet vehicle data.'
// Precise — activates only for explicit vehicle ID references
classificationPrompt: 'Locate a fleet vehicle by its ID (e.g. "TT-001"); not for general location queries.'

Observing classification

Use onClassify to inspect which tools were selected and which per-tool scopes the classifier emitted — useful for debugging classification behaviour, watching scope narrowing in action, or building a dev panel:

const agent = createMapAgent(map, {
model: openai('gpt-4o'),
onClassify: (result) => {
if (result) {
console.log('Selected tools:', result.activeToolNames);
console.log('Per-tool scopes:', result.toolScopes); // e.g. { analyseData: { kinds: ['places', 'routes'] } }
console.log('Classification took:', result.timeMs, 'ms');
}
},
});