Contents
Getting started
Using Codepanion
Connecting your tools
Charts in a thread
Ask for a trend, a breakdown or a single headline number and the agent answers with a chart. It queries your database with the grouping already in the query, sends the rows to the sandbox in your browser under a name, and then calls render_chart with that name and a small specification: the chart type, the category field, the measures, and an optional field to split the rows into series.
The chart is drawn in your browser from rows the model never saw. What the model gets back is an acknowledgement: the title, the type, how many categories and which series. That is all it needs to write the sentence under the picture, and it is all that goes into the stored conversation alongside the drawn data.
Three chart types, chosen by what the question is asking for:
barCompare a measure across categories. Several measures draw side by side; a stacked bar shows a total divided into its parts.lineChange over an ordered axis, usually time.statOne number, large. For "how many right now" questions where an axis would only get in the way.
A missing value is drawn as a gap rather than as zero. Negative values hang below the baseline. There is no dual-axis chart on purpose: two measures with different scales are two charts.
Per day, per week, per month
Most trend questions are "per something". The structured query the agent writes can bucket a date or time column by hour, day, week, month or year as part of the grouping, and order by the bucket or by an aggregate, so the whole aggregation happens in your database and only the totals come back.
{
"table": "payment_attempts",
"where": [{ "column": "status", "op": "=", "value": "failed" }],
"groupBy": {
"buckets": [{ "column": "created_at", "unit": "day", "alias": "day" }],
"aggregates": [{ "function": "count", "column": "*", "alias": "failures" }]
},
"orderBy": [{ "column": "day", "dir": "asc" }]
}On SQL Server the bucket compiles to the DATEADD(DATEDIFF()) idiom, which every supported version understands, and on PostgreSQL to date_trunc. Everything else about the query is unchanged: names are checked against the discovered schema, values travel as parameters, and the statement is read-only and capped.
If a query with a bucket goes through an on-prem connector running an older build, that build does not know the bucket and answers that a grouping needs at least one column. Pull the current image and restart the connector; nothing else needs reconfiguring.
Saved reports
A chart drawn from a query carries Save as report. Give it a name and the query, the environment it ran against and the chart specification are kept together under Reports. Opening a report runs the query again, through the same read-only path the agent uses, and draws the same chart over today's rows, with the rows themselves in a table underneath.
That is the whole feature. It exists for the support engineer who knows exactly which number they need every Monday and whose change-control process means a new report on the reporting server is a fortnight away. Rename it, run it again, delete it when it has done its job.
Not everything can be saved
A chart drawn over rows the agent reshaped with run_js has no single query behind it, so it cannot be saved. Ask the agent to express the grouping in the query instead; it will usually manage, and the chart then becomes a report.
Limits and what we record
A chart holds at most 1000 categories and 12 series. Past that the agent is told to aggregate rather than handed something unreadable. A report's query runs under the same row, size and time caps as any other database query, and the browser tool only appears on a live streamed turn, the same as run_js.
Every chart the agent draws is written to the audit log with its outcome, the dataset it drew from, its type and title, and how many categories and series it holds. Every report a person runs is written with who ran it, which environment, and the exact query. Creating, renaming and deleting a report are audited too.