FreeGridv1.6.0한국어

AI assistant

Let people ask the grid in plain words. Your server asks a model and answers with checked actions: sorting, filters, groups, formats, computed columns and charts, each with an undo.

Live demoAI assistant

Ask in plain words; your server turns it into sorting, filters, groups, formats and charts. Every answer can be undone.

Code for this demo
import { createGrid, type Row } from '@freegridjs/core';
import { button, separator, text, tr, type DemoContext } from '../ui';
import '../data'; // registers the grid's language packs

export default function mount(ctx: DemoContext) {
  const { lang } = ctx;
  const h = (en: string, ko: string) => tr(lang, { en, ko });
  const regions = lang === 'ko' ? ['서울', '부산', '대구', '광주'] : ['East', 'West', 'North', 'South'];
  const products = lang === 'ko' ? ['노트북', '모니터', '키보드', '마우스', '책상'] : ['Laptop', 'Monitor', 'Keyboard', 'Mouse', 'Desk'];
  const prices = [1290, 320, 59, 25, 410];
  const data: Row[] = Array.from({ length: 120 }, (_, i) => {
    const p = (i * 7) % 5;
    return {
      id: i + 1,
      date: `2026-${String(1 + (i % 12)).padStart(2, '0')}-${String(1 + ((i * 3) % 28)).padStart(2, '0')}`,
      region: regions[i % 4],
      product: products[p],
      qty: 1 + ((i * 13) % 17),
      price: prices[p],
    };
  });
  const suggestions = lang === 'ko'
    ? ['지역별로 묶어 줘', '수량 10 이상 강조', '수량 상위 5개', '금액 컬럼 추가', '지역별 차트', '초기화']
    : ['Group by region', 'Highlight qty above 10', 'Top 5 by qty', 'Add an amount column', 'Chart by region', 'Reset'];
  const grid = createGrid(ctx.host, {
    columns: [
      { field: 'date', header: h('Date', '날짜'), type: 'date', width: 110 },
      { field: 'region', header: h('Region', '지역'), width: 100 },
      { field: 'product', header: h('Product', '제품'), width: 120 },
      { field: 'qty', header: h('Qty', '수량'), type: 'number', width: 80 },
      { field: 'price', header: h('Price', '단가'), type: 'number', format: '#,##0', width: 100 },
    ],
    data, locale: lang, getRowId: r => String(r.id),
    // this demo's endpoint reads a few phrases; a real one asks a model (see "Server examples")
    assistant: { url: '/api/demo-assistant', sampleRows: 3, suggestions },
  });
  grid.on('assistantAnswer', e => ctx.log(`assistantAnswer → ${e.applied.map(a => a.type).join(', ') || '-'}${e.skipped.length ? ` (${h('skipped', '건너뜀')} ${e.skipped.length})` : ''}`));

  text(ctx, h('Open the assistant and ask in plain words. This demo server only knows a few phrases; your server asks a model and understands anything. Each answer has an Undo.',
    '어시스턴트를 열고 말로 요청해 보세요. 이 데모 서버는 몇 가지 표현만 알아듣지만, 실제 서버는 모델에게 물어 어떤 요청이든 처리합니다. 답마다 되돌리기가 있습니다.'));
  separator(ctx);
  button(ctx, h('Open AI assistant', 'AI 어시스턴트 열기'), () => grid.openAssistant());
  button(ctx, h('Ask: group by region', '요청: 지역별로 묶기'), async () => {
    const res = await grid.askAssistant(suggestions[0]);
    ctx.log(res.message);
  });
  return grid;
}

With the AI assistant on, people ask in plain words: "only Seoul, biggest amounts first", "late orders in red", "a chart of totals by region". The grid sends the request to your server; your server asks a model (Claude or another) and answers with a list of actions: sorting, filters, grouping, pivots, conditional formats, computed columns, summary rows and charts. The model API key stays on the server and never reaches the browser.

Setup

const grid = createGrid(el, {
  columns, data,
  assistant: {
    url: '/api/grid-ai',                 // your server (the model API key stays there)
    sampleRows: 5,                       // example rows sent along; 0 sends none
    suggestions: ['Sales by region', 'Highlight late orders', 'Add an amount column'],
    context: () => ({ screen: 'Order management' }),
  },
});

grid.openAssistant();                                  // the chat panel (also in the right-click menu)
const res = await grid.askAssistant('Top 10 customers this month');   // or from code
console.log(res.message, res.applied, res.skipped);
res.undo();                                            // put the grid back

What goes to the server

Not the rows: column summaries (type, blanks, distinct values, min, max, average, the most frequent values), the current view, and sampleRows example rows. For screens with personal data, sampleRows: 0 sends no rows at all.

// what the grid sends (POST JSON)
{
  "prompt": "Only Seoul, biggest amounts first",
  "locale": "en",
  "rowCount": 1200, "totalRows": 1200,
  "columns": [
    { "id": "region", "header": "Region", "distinct": 4, "top": [{ "value": "Seoul", "count": 410 }] },
    { "id": "amount", "header": "Amount", "type": "number", "min": 1200, "max": 980000, "avg": 41250 }
  ],
  "sample": [ { "region": "Seoul", "amount": 32000 } ],
  "state": { "sort": [], "filters": {}, "groupBy": [], "conditionalFormats": [] }
}

// what the server answers
{
  "message": "Showing Seoul orders, largest amounts first.",
  "actions": [
    { "type": "filter", "colId": "region", "model": { "type": "set", "values": ["Seoul"] } },
    { "type": "sort", "sort": [{ "colId": "amount", "dir": "desc" }] }
  ]
}

Actions and safety

The grid checks every action before it runs it. Unknown columns, bad filter models, formulas that do not parse and unknown actions are skipped and reported in skipped. No action runs code. Every answer has an Undo that puts sorting, filters, columns and formats back.

NameTypeDescription
sort / filter / clearFilters / quickFilter / advancedFilter{ type, sort } / { type, colId, model }Sorting and filters, with the same models as setSort and setFilter.
groupBy / pivot{ type, colIds, expand? } / { type, pivot }Group rows or switch to a pivot table.
showColumns / hideColumns{ type, colIds }Show or hide columns.
conditionalFormat / clearConditionalFormats{ type, format }Add a conditional format.
addColumn{ type, column: { id, header, formula, type } }A computed column; the formula must parse.
summary / chart / message{ type, summary } / { type, chartType, colIds } / { type, text }Summary rows, a chart over columns, or just an answer.

The server

Node (Express) and Python (FastAPI) servers are in examples/ai-assistant in the repository. Both use the model's tool use with the same prompt to get answers in the format above. In production, put the route behind your login and keep a rate limit.

// Node (Express) + Claude: the full example is examples/ai-assistant/node/assistant.js
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();   // ANTHROPIC_API_KEY from the environment

app.post('/api/grid-ai', requireLogin, async (req, res) => {
  const out = await client.messages.create({
    model: 'claude-sonnet-5-5',
    max_tokens: 2048,
    system: SYSTEM_PROMPT,                         // the action list and the rules
    tools: [GRID_ACTIONS_TOOL],
    tool_choice: { type: 'tool', name: 'grid_actions' },
    messages: [{ role: 'user', content: JSON.stringify(req.body) }],
  });
  const input = out.content.find(b => b.type === 'tool_use')?.input ?? {};
  res.json({ message: input.message ?? '', actions: input.actions ?? [] });
});

The demo above talks to a rule-based server that knows a few phrases, so it costs nothing to try. A real server asks a model and understands free-form requests.

Questions about this page

Can users ask a FreeGrid grid questions in plain language?

Yes. With the assistant option the grid sends the request and column summaries to your server, which asks an AI model and answers with checked actions such as sorting, filters, grouping, formats and charts.

Does the AI assistant send my data to the model?

Only what your server forwards. The grid sends column summaries and a few sample rows (sampleRows, 0 for none), and the model API key stays on your server.