AI Toolkit (Enterprise)
The AI Toolkit in apex-grid-enterprise turns a natural-language prompt into a grid change (sort, filter, group, pivot, …) or an answer about the data. It is provider-agnostic: you supply an aiAdapter, and the toolkit handles building the request from the grid's schema and applying the resulting state patch.
Wiring an adapter
Assign an adapter to aiAdapter. The toolkit ships a Claude adapter and a mock adapter, or you can provide your own (request) => Promise<AIResponse>:
import { createClaudeAdapter } from 'apex-grid-enterprise';
grid.aiAdapter = createClaudeAdapter({ endpoint: '/api/grid-ai' });
Without an adapter, runPrompt rejects. The entire AI Toolkit is an enterprise feature.
Running a prompt
runPrompt(prompt, options?) returns a discriminated AIResult:
// control mode (default): the AI produces a state patch, which is applied
const result = await grid.runPrompt('group by region and sum revenue');
if (result.mode === 'control') {
console.log('applied:', result.result.applied);
console.log('warnings:', result.warnings);
// roll it back:
// result.undo();
}
// ask mode: get an answer, change nothing
const answer = await grid.runPrompt('which region has the highest revenue?', { mode: 'ask' });
if (answer.mode === 'ask') console.log(answer.answer);
RunPromptOptions | Description |
|---|---|
mode | 'control' (default) applies a patch; 'ask' returns an answer only |
signal | AbortSignal forwarded to the adapter for cancellation |
Control result carries the sanitized patch, the setState result (applied/skipped/warnings), merged warnings, and an idempotent undo() that restores the pre-prompt snapshot. Ask result carries just answer.
The Claude adapter
createClaudeAdapter(config) supports two transports:
// Production: POST { prompt, mode, schema, data } to your backend (key stays server-side)
grid.aiAdapter = createClaudeAdapter({ endpoint: '/api/grid-ai' });
// Development only: call Anthropic directly from the browser
grid.aiAdapter = createClaudeAdapter({
apiKey: import.meta.env.VITE_ANTHROPIC_KEY,
dangerouslyAllowBrowser: true,
});
ClaudeAdapterConfig | Description |
|---|---|
endpoint | Production transport: POST the request to your backend |
apiKey | Dev transport: call Anthropic directly (requires dangerouslyAllowBrowser) |
dangerouslyAllowBrowser | Acknowledge the in-browser key is exposed to the page (dev only) |
model | Model id; defaults to claude-opus-4-8 |
maxTokens | Max output tokens; defaults to 1024 |
maxDataRows | Rows of current data included in the prompt (0 disables); defaults to 50 |
system | Extra system-prompt text appended to the built-in grid instructions |
fetch | Override fetch (proxy transport), e.g. to add auth headers |
client | Supply the Anthropic client instead of the bundled dynamic import |
The recommended production setup is the endpoint proxy so your API key never reaches the browser. Your endpoint receives { prompt, mode, schema, data } and calls Anthropic server-side.
Mock adapter (no network)
For demos and tests, createMockAdapter returns an adapter driven by rules:
import { createMockAdapter } from 'apex-grid-enterprise';
grid.aiAdapter = createMockAdapter({
rules: [
{ match: /group by region/i, patch: { modules: { grouping: { groupBy: ['region'] } } } },
],
});
How it stays safe
The toolkit builds the request from getSchema() and sanitizes the returned patch against that schema (sanitizePatch) before applying it via setState, so an out-of-range or malformed patch is degraded rather than throwing. Everything an AI can do is expressible as a GridState patch — see State Persistence.
React example
import { useEffect, useRef, useState } from 'react'
import 'apex-grid-enterprise/define'
import { createClaudeAdapter } from 'apex-grid-enterprise'
export default function AIGrid() {
const ref = useRef<any>(null)
const [prompt, setPrompt] = useState('')
useEffect(() => {
const grid = ref.current
grid.columns = columns
grid.data = data
grid.aiAdapter = createClaudeAdapter({ endpoint: '/api/grid-ai' })
}, [])
const run = async () => {
const result = await ref.current.runPrompt(prompt)
if (result.mode === 'control') console.log('applied', result.result.applied)
}
return (
<div>
<input value={prompt} onChange={(e) => setPrompt(e.target.value)} />
<button onClick={run}>Run</button>
<apex-grid-enterprise ref={ref} style={{ height: 480 }} />
</div>
)
}