# @carto/agentic-deckgl

`@carto/agentic-deckgl` is a framework-agnostic TypeScript library that provides tool definitions, system prompt generation, and SDK converters for building AI-powered [CARTO + deck.gl](https://github.com/CartoDB/gitbook-documentation/blob/master/carto-for-developers/key-concepts/carto-for-deck.gl) map applications. For an introduction to the concepts, see [AI-powered map interaction](/carto-for-developers/key-concepts/ai-powered-map-interaction.md).

## Installation

```bash
npm install @carto/agentic-deckgl
```

Peer dependencies: `@deck.gl/json` (^9.2.0) and `zod` (^4.3.6).

## buildSystemPrompt

Generates a system prompt for the AI agent, including tool-specific instructions, current map state, and optional user context.

### Usage

```typescript
import { buildSystemPrompt, TOOL_NAMES } from '@carto/agentic-deckgl';

const systemPrompt = buildSystemPrompt({
  toolNames: [TOOL_NAMES.SET_DECK_STATE, TOOL_NAMES.SET_MARKER, TOOL_NAMES.SET_MASK_LAYER],
  initialState: {
    viewState: { latitude: 40.7128, longitude: -74.006, zoom: 12 },
    layers: [{ id: 'my-layer', type: 'VectorTileLayer', visible: true }],
    activeLayerId: 'my-layer',
  },
});
```

### Options

```typescript
interface BuildSystemPromptOptions {
  toolNames: string[];          // List of tool names available to the agent
  initialState?: MapState;      // Current map state for context
  userContext?: UserContext;     // User context for business analysis
  semanticContext?: string;     // Pre-rendered data catalog markdown
  mcpToolNames?: string[];      // MCP tool names (enables MCP instructions)
  additionalPrompt?: string;    // Additional prompt text to append
}
```

* **toolNames:** The tools the agent is allowed to use. Use the `TOOL_NAMES` constant for type safety: `TOOL_NAMES.SET_DECK_STATE`, `TOOL_NAMES.SET_MARKER`, `TOOL_NAMES.SET_MASK_LAYER`.
* **initialState** (optional): The current map state, so the AI has context about what the user is viewing. Includes `viewState` (lat/lng/zoom/pitch/bearing), `layers` (array of layer state), and `activeLayerId`.
* **userContext** (optional): Business context such as country, business type, demographics, and proximity priorities. This shapes the AI's analytical responses.
* **semanticContext** (optional): A pre-rendered markdown string describing the available data tables and their columns. This is typically generated from a YAML-based data catalog.
* **mcpToolNames** (optional): When provided, the prompt includes MCP-specific instructions for the listed tool names.
* **additionalPrompt** (optional): Custom text appended to the end of the system prompt.

### Supporting types

```typescript
interface MapState {
  viewState?: MapViewState;
  layers?: LayerState[];
  activeLayerId?: string;
}

interface MapViewState {
  longitude: number;
  latitude: number;
  zoom: number;
  pitch?: number;
  bearing?: number;
}

interface LayerState {
  id: string;
  type?: string;
  visible?: boolean;
  [key: string]: unknown;
}
```

### Helper functions

```typescript
import { buildMapStateSection, buildUserContextSection } from '@carto/agentic-deckgl';

// Build just the map state portion of the prompt
const mapSection = buildMapStateSection({
  viewState: { latitude: 40.7128, longitude: -74.006, zoom: 12 },
  layers: [{ id: 'layer-1', type: 'VectorTileLayer' }],
  activeLayerId: 'layer-1',
});

// Build just the user context portion of the prompt
const userSection = buildUserContextSection({
  country: 'Spain',
  businessType: 'Retail',
});
```

## Tool definitions

The library defines 3 tools, each with a Zod validation schema. These tools are what the AI calls to manipulate the map.

### set-deck-state

Full deck.gl state control: navigation, basemap, layers, widgets, and effects.

```typescript
// Parameters (all optional — include only what you want to change)
{
  initialViewState?: {
    latitude: number;       // -90 to 90
    longitude: number;      // -180 to 180
    zoom: number;           // 0 to 22
    pitch?: number;         // 0 to 85
    bearing?: number;       // -180 to 180
    transitionDuration?: number;
  };
  mapStyle?: 'dark-matter' | 'positron' | 'voyager';
  layers?: Record<string, unknown>[];      // deck.gl JSON layer configs
  widgets?: Record<string, unknown>[];     // deck.gl JSON widget configs
  effects?: Record<string, unknown>[];     // deck.gl JSON effect configs
  layerOrder?: string[];                   // layer IDs in render order
  removeLayerIds?: string[];               // layer IDs to remove
  removeWidgetIds?: string[];              // widget IDs to remove
}
```

### set-marker

Places, removes, or clears location marker pins on the map.

```typescript
{
  action: 'add' | 'remove' | 'clear-all';  // default: 'add'
  latitude?: number;    // required for add/remove
  longitude?: number;   // required for add/remove
}
```

### set-mask-layer

Manages an editable mask layer for spatial filtering.

```typescript
{
  action: 'set' | 'enable-draw' | 'clear';
  geometry?: GeoJSON;    // GeoJSON geometry (mutually exclusive with tableName)
  tableName?: string;    // CARTO table containing mask geometry
}
```

### Accessing tool definitions

```typescript
import {
  tools,
  getToolNames,
  getTool,
  getConsolidatedToolDefinitions,
  validateToolParams,
  TOOL_NAMES,
} from '@carto/agentic-deckgl';

// Get all tool names
const names = getToolNames();
// ['set-deck-state', 'set-marker', 'set-mask-layer']

// Get a specific tool definition
const deckTool = getTool(TOOL_NAMES.SET_DECK_STATE);

// Get all tools in OpenAI function calling format
const openAITools = getConsolidatedToolDefinitions();

// Validate parameters against a tool's schema
const result = validateToolParams(TOOL_NAMES.SET_MARKER, {
  action: 'add',
  latitude: 40.7128,
  longitude: -74.006,
});
```

## SDK converters

Convert tool definitions into the format expected by each AI SDK. All converters return tool definitions with built-in Zod validation and a frontend tool marker, so the backend knows the tool should be executed on the client.

### getToolsForOpenAIAgents

```typescript
import { getToolsForOpenAIAgents } from '@carto/agentic-deckgl';

const toolDefs = getToolsForOpenAIAgents();
// Returns OpenAIAgentToolDef[] with name, description, parameters (Zod), execute
```

### getToolsForVercelAI

```typescript
import { getToolsForVercelAI, getToolsRecordForVercelAI } from '@carto/agentic-deckgl';

// As an array
const toolDefs = getToolsForVercelAI();

// As a record (for streamText({ tools: ... }))
const toolsRecord = getToolsRecordForVercelAI();
```

### getToolsForGoogleADK

```typescript
import { getToolsForGoogleADK } from '@carto/agentic-deckgl';

const toolDefs = getToolsForGoogleADK();
// Returns GoogleADKToolDef[] with name, description, parameters (Zod), execute
```

All converters accept an optional `toolNames` parameter to convert only specific tools:

```typescript
const subset = getToolsForVercelAI([TOOL_NAMES.SET_DECK_STATE, TOOL_NAMES.SET_MARKER]);
```

## Custom tool executors

The SDK converters provide default `execute` functions that validate parameters and return a frontend tool marker. On the frontend, you need a **tool executor** — a function that receives the tool name and validated parameters and applies them to your deck.gl map state.

The reference frontends in the repository each include a `tool-executor` that you can use as a starting point and customize for your application. The pattern is a factory function that maps each tool name to your own execution logic:

```typescript
import { TOOL_NAMES } from '@carto/agentic-deckgl';

function createToolExecutor(deckActions) {
  const executors = {
    [TOOL_NAMES.SET_DECK_STATE]: (params) => {
      // Apply view state, basemap, layers, widgets, effects
      // to your deck.gl instance using params
      if (params.initialViewState) {
        deckActions.setViewState(params.initialViewState);
      }
      if (params.layers) {
        deckActions.updateLayers(params.layers);
      }
      return { success: true, message: 'State updated' };
    },

    [TOOL_NAMES.SET_MARKER]: (params) => {
      // Add, remove, or clear markers on your map
      return { success: true, message: 'Marker placed' };
    },

    [TOOL_NAMES.SET_MASK_LAYER]: (params) => {
      // Apply spatial mask geometry, enable draw mode, or clear
      return { success: true, message: 'Mask applied' };
    },
  };

  return async (toolName, params) => {
    const executor = executors[toolName];
    if (!executor) return { success: false, message: `Unknown tool: ${toolName}` };
    return executor(params);
  };
}
```

This is where you control exactly how each tool call affects your application — for example, how layers are merged, how markers are rendered, or how mask geometries are fetched from CARTO tables. See the [frontend examples](https://github.com/CartoDB/carto-agentic-deckgl/tree/main/examples/frontend) for complete implementations in React, Vue, Angular, and Vanilla JS.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.carto.com/carto-for-developers/reference/agentic-deckgl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
