Customizing the system prompt
The base system prompt teaches the model to behave as a map assistant. It covers who it is, what it can do, how to decline out-of-scope requests, how to format answers and treat incomplete data, how to call tools, and how session state works. Instead of replacing it, prepend a preamble, append instructions or override individual sections while the others keep their defaults.
How a prompt is assembled
The base prompt has seven named sections, exported as SYSTEM_PROMPT_SECTIONS. In order, createMapAgent
assembles your optional systemPromptPrefix, the base sections with any overrides, and your optional
systemPromptSuffix under an ADDITIONAL INSTRUCTIONS: heading.
Prefix, suffix and section overrides work together. A full-string systemPrompt replaces the whole grey box and ignores the
prefix and suffix.
The sections
| Section | Heading in prompt | Default governs |
|---|---|---|
identity | (none — opening line) | Who the assistant is and its tone of voice. Override it to rebrand or set a persona. |
capabilities | (none) | A compact summary of what the toolkit can do (search, routing, ranges, traffic, analysis, BYOD, map control). Anchors what rejectionRules steers users back toward. |
rejectionRules | SCOPE & REJECTIONS: | How to handle in-scope / mixed / out-of-scope / illegal requests, and that every rejection explains why and offers an in-scope next step. |
responseFormatting | RESPONSE FORMATTING: | Markdown usage, bolding key info, bullet lists, conciseness. |
dataConfidence | DATA CONFIDENCE: | Surfacing incomplete, partial, stale or conflicting data honestly instead of presenting it as complete. |
toolExecution | TOOL EXECUTION: | Calling independent tools in parallel and rendering with a tool’s own show / showOnMap in the same step. Grounding every fact and map change in a tool call, and answering without one only from what the conversation and state already hold. Asking for missing input only by calling clarifyIntent. |
sessionState | SESSION STATE: | The append-only entry model (places-3, routes-1), checking recallState before referencing an id, and never inventing ids. |
Per-tool mechanics (coordinate order, "near me" vs "in this area") live in the tool descriptions and the
classifier prompt, so they stay correct as tools change.
What the prompt doesn’t reach
The system prompt goes only to the main model, never to the intent classifier,
which picks each turn’s tools from their classificationPrompt. So “always also call getTrafficIncidents” has no
effect on a turn where the classifier didn’t pick that tool:
- To change when a tool is offered, extend its
classificationPrompt. See Per-tool classification prompts. - To offer it on every turn, set
alwaysActive: trueon its entry. - Then use the prompt to tell the model when to call it.
Four ways to shape it
Choose the least invasive option. Nudge with the prefix or suffix, retune with section overrides, and replace the prompt only when you must remove base behaviour.
Prepend or append
systemPromptPrefix and systemPromptSuffix keep the whole base prompt, so your agent gets base refinements when
you upgrade.
const agent = createMapAgent(map, { model: openai('gpt-4o'), systemPromptPrefix: 'You work for Acme Logistics.', systemPromptSuffix: 'Always respond in Spanish. Never show more than 5 places at once.',});Override individual sections
Pass a SystemPromptSectionOverrides object as systemPrompt. Each key replaces that section’s body, and the SDK
adds the heading. Sections you leave out keep their defaults. An empty string drops the section, including its heading:
const agent = createMapAgent(map, { model: openai('gpt-4o'), systemPrompt: { identity: 'You are a delivery fleet dispatcher built on the TomTom map.', responseFormatting: 'Reply in Dutch, metric units, one short paragraph.', dataConfidence: '', // dropped // capabilities, rejectionRules, toolExecution, sessionState stay default },});Extend a default section
To add to a section instead of replacing it, read its default from SYSTEM_PROMPT_SECTIONS and
derive a new value. Use this to append one rule, or to hand the default to a coding agent to rewrite
under some criteria:
import { createMapAgent, SYSTEM_PROMPT_SECTIONS } from '@tomtom-org/maps-sdk-plugin-agent-toolkit';
const agent = createMapAgent(map, { model: openai('gpt-4o'), systemPrompt: { rejectionRules: `${SYSTEM_PROMPT_SECTIONS.rejectionRules}\n- Decline weather questions.`, },});composeSystemPrompt(overrides) returns the assembled string for logging, diffing or a token-budget check. If you pass it
back as systemPrompt, it is a full string, so the agent ignores the prefix and suffix.
The site selection agent example replaces identity and
capabilities and extends rejectionRules for a narrowly scoped agent.
Full replacement
With a full replacement, you own the entire prompt and re-check the base on each upgrade. Extend BASE_SYSTEM_PROMPT instead of starting from
scratch. Its sections carry the guidance that keeps the agent reliable.
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.`,});Keeping a persona prompt lean
Section overrides keep the base scaffolding around your persona text, so the result can be longer than a hand-written
prompt. If size matters, don’t restate what the base sections cover. Override only where the persona differs, for
example a one-line rejectionRules instead of the multi-bullet default, or '' to drop a section.
composeSystemPrompt(overrides).length gives the assembled length.
Related
- Securing your agent — why the prompt is public, and why it is not the place for credentials, internal detail or a spending rule.
- How it works — where the assembled prompt is used in a turn.
- Customizing tools — shaping the registry the prompt describes.