This is the documentation of version 0.64.0. Go to the latest version, 1.0.0-rc.5.

Customizing the system prompt

The base system prompt teaches the model to behave as a map assistant: who it is, what it can do, how to decline out-of-scope asks, how to format answers and treat incomplete data, how to call tools, and how session state works. Rather than replace 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. createMapAgent assembles, top to bottom: your optional systemPromptPrefix, the base sections with any overrides, then your optional systemPromptSuffix under an ADDITIONAL INSTRUCTIONS: heading.

MapAgentOptions (you supply)Assembled system promptsystemPromptPrefixsystemPrompt:SystemPromptSectionOverridessystemPromptSuffixsystemPromptPrefix — optional preamble, no headingBASE_SYSTEM_PROMPT — composeSystemPrompt(): each section overridableADDITIONAL INSTRUCTIONS: ← systemPromptSuffix (optional)identity (no heading)capabilities (no heading)rejectionRules → SCOPE & REJECTIONS:responseFormatting → RESPONSE FORMATTING:dataConfidence → DATA CONFIDENCE:toolExecution → TOOL EXECUTION:sessionState → SESSION STATE: prependsreplaces any section body(heading kept)appends

Prefix, suffix and section overrides compose. 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. The natural hook 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, 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 to the main model only, never to the intent classifier, which picks each turn's tools from their classificationPrompt. So "always also call toggleTilesTrafficFlow" has no effect on a turn where the classifier didn't pick that tool:

Four ways to shape it

Prefer 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 live, so your agent picks up base refinements on 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 — the heading is added for you — and omitted sections keep their defaults. An empty string drops the section, heading included:

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 rather than replace it, read its default from SYSTEM_PROMPT_SECTIONS and derive a new value — handy for appending one rule, or for handing 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. Passed back as systemPrompt it is a full string, so the prefix and suffix are then ignored.

The site selection agent example replaces identity and capabilities and extends rejectionRules for a narrowly scoped agent.

Full replacement

You own the entire prompt and re-check the base on each upgrade. Extend BASE_SYSTEM_PROMPT rather than start 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 they can assemble into a longer prompt than a hand-written one. If size matters, don't restate what the base sections cover, and override only where the persona differs — a one-line rejectionRules instead of the multi-bullet default, or '' to drop a section. composeSystemPrompt(overrides).length gives the assembled length.

Related