ask from tally-ai turns a question into a Tally query. The model answers in query text, the text is parsed against your schema, and only a query that parses is returned. The model never applies free text to a view.
It works with any model the AI SDK can call: a provider package, a gateway model id or your own provider.
How it works
1
Prompt
describeSchema(schema, options) builds the system prompt: the query grammar, every visible
column with its type, operators, enum values, aliases and limits, the examples you pass, and
today’s date.2
Answer
The model returns structured output with two fields: the query text and one short sentence
explaining it.
3
Parse
The text is parsed with
parseQuery against the schema. A query that parses is printed in its
canonical form and returned.4
Repair
Parse errors go back to the model with a request for a corrected query. After the last repair
round,
ask throws.Usage
ask.ts
Options
Hidden columns are left out of the prompt. Columns with
filterable, sortable or groupable set to false are described with those limits. A description on a column is passed to the model as is.
Errors
When no attempt parses,ask throws an AskError. Its message is the first parse error of the last attempt. question holds the question and attempts holds every answer with its parse errors.
errors.ts
In the filter bar
createAskHandler returns the handler for the ai prop of <Tally>. It takes the same options without schema, which comes from the grid.
accounts.tsx
askPlaceholder. Text that does not parse as a query, or reads like a sentence, goes to the handler. The answer lands as filter chips. Rename the strings with the askPlaceholder and asking labels.
Keys in the browser
Model calls need an API key. Keep it on the server. Add a same-origin route that forwards model requests and adds the key, and point the provider’s base URL at it.ask, designColumn and withAiColumns then run in the browser. The playground does this in examples/playground/server, with a body size limit and a rate limit per client.
Your own agent loop
describeSchema(schema, { examples, context, now }) returns the same system prompt ask uses. Use it when you drive the model yourself, then validate the answer with parseQuery.