-
Notifications
You must be signed in to change notification settings - Fork 22
Add data-query category: AL query-generation benchmark #740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Onat Buyukakkus (onbuyuka)
wants to merge
29
commits into
main
Choose a base branch
from
onbuyuka/data-query-category
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
e3dc7fa
Add data-query category: AL query-generation benchmark
0d46002
Merge remote-tracking branch 'origin/main' into onbuyuka/data-query-c…
8d08fbe
Fix pre-commit: ruff-format + ty (Sequence[Mapping] for result_sets_m…
f62ace6
Register data-query in Get-BCBenchDatasetPath (container setup)
a06dec4
data-query: clear workspace contents instead of rmtree (dir is mounte…
ec5dfee
data-query: drop invalid 'Extensible' property from wrapped API query…
614dea7
data-query: don't crash the job on a gold-query compile failure
5761e0e
data-query: normalize query object name and use per-object API entity…
237c930
data-query: use proven Invoke-AppBuildAndPublish + in-container OData…
d7ad1dd
data-query: build Basic auth header by hand for the in-container ODat…
8268f07
data-query: calibrate prompts + fix the intersection gold query
2a41a6c
data-query: add 5 more deterministically-scorable tasks (6 -> 11)
129c5ef
data-query: address PR review feedback (scoring integrity + robustness)
afde215
data-query: fix invalid Count columns in gold queries and skill
56f2335
data-query: exclude unscorable results from the bceval export too
faf22ba
data-query: validate the gold query before evaluating the agent's
45715a3
Withhold gold queries from the agent's filesystem during generation
adfca7c
Merge remote-tracking branch 'origin/main' into onbuyuka/data-query-c…
1c9aa72
Harden gold withholding: also hide the .git object database from the …
d24eb18
Add --skills dispatch flag to toggle agent skills per run
cad29ec
Normalize only numeric result values, preserve Code strings verbatim
979a388
Merge branch 'main' into onbuyuka/data-query-category
haoranpb 9820ae7
Simplify data-query harness per owner review
3ccb00d
Merge origin/main through PR #761
haoranpb f0921f5
uptake PR#761 with better extensibility
haoranpb 96fd0b4
uptake the file sysmte operation
haoranpb ee06e26
the latest release is 28.3 I believe
haoranpb 231a27e
Merge branch 'main' of https://github.com/microsoft/BC-Bench into onb…
haoranpb c218e13
uptake `bootstrap_app_json` util function
haoranpb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| {"instance_id": "dataquery__outstanding-sales-value-by-customer-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "sales"}, "nl_prompt": "For each customer, what is the total outstanding value across their open sales orders? Include the customer's number and name.", "ordered": false, "gold_query": "query 50100 OutstandingSalesByCustomer\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(Customer; Customer)\n {\n column(No; \"No.\") { }\n column(Name; Name) { }\n dataitem(SalesLine; \"Sales Line\")\n {\n DataItemLink = \"Sell-to Customer No.\" = Customer.\"No.\";\n DataItemTableFilter = \"Document Type\" = const(Order);\n column(TotalOutstanding; \"Outstanding Amount\") { Method = Sum; }\n }\n }\n }\n}"} | ||
| {"instance_id": "dataquery__total-sold-quantity-by-item-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "inventory"}, "nl_prompt": "What is the total sold quantity per item across all posted sales invoice lines? Return each item number and its total quantity.", "ordered": false, "gold_query": "query 50100 SoldQuantityByItem\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(SalesInvoiceLine; \"Sales Invoice Line\")\n {\n DataItemTableFilter = Type = const(Item);\n column(ItemNo; \"No.\") { }\n column(TotalQuantity; Quantity) { Method = Sum; }\n }\n }\n}"} | ||
| {"instance_id": "dataquery__avg-invoice-amount-by-country-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "finance"}, "nl_prompt": "For each country/region, what is the average posted sales invoice line amount? Group the posted sales invoice lines by the bill-to customer's country/region code.", "ordered": false, "gold_query": "query 50100 AvgInvoiceAmountByCountry\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(Customer; Customer)\n {\n column(CountryRegionCode; \"Country/Region Code\") { }\n dataitem(SalesInvoiceHeader; \"Sales Invoice Header\")\n {\n DataItemLink = \"Bill-to Customer No.\" = Customer.\"No.\";\n dataitem(SalesInvoiceLine; \"Sales Invoice Line\")\n {\n DataItemLink = \"Document No.\" = SalesInvoiceHeader.\"No.\";\n column(AvgAmount; Amount) { Method = Average; }\n }\n }\n }\n }\n}"} | ||
| {"instance_id": "dataquery__total-purchase-amount-by-vendor-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "purchasing"}, "nl_prompt": "What is the total posted purchase invoice amount per vendor? Include the vendor's number and name.", "ordered": false, "gold_query": "query 50100 PurchaseAmountByVendor\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(Vendor; Vendor)\n {\n column(No; \"No.\") { }\n column(Name; Name) { }\n dataitem(PurchInvLine; \"Purch. Inv. Line\")\n {\n DataItemLink = \"Buy-from Vendor No.\" = Vendor.\"No.\";\n column(TotalAmount; Amount) { Method = Sum; }\n }\n }\n }\n}"} | ||
| {"instance_id": "dataquery__items-on-both-open-orders-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "inventory"}, "nl_prompt": "Which items appear on both open sales orders and open purchase orders? Return the item numbers.", "ordered": false, "gold_query": "query 50100 ItemsOnBothOpenOrders\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(SalesLine; \"Sales Line\")\n {\n DataItemTableFilter = \"Document Type\" = const(Order), Type = const(Item);\n column(ItemNo; \"No.\") { }\n dataitem(PurchaseLine; \"Purchase Line\")\n {\n DataItemLink = \"No.\" = SalesLine.\"No.\";\n DataItemTableFilter = \"Document Type\" = const(Order), Type = const(Item);\n }\n }\n }\n}"} | ||
| {"instance_id": "dataquery__opportunity-count-by-status-1", "repo": "dataquery/bc", "environment_setup_version": "26.0", "created_at": "2026-07-10", "metadata": {"area": "crm"}, "nl_prompt": "How many CRM opportunities are there in each status?", "ordered": false, "gold_query": "query 50100 OpportunityCountByStatus\n{\n QueryType = Normal;\n\n elements\n {\n dataitem(Opportunity; Opportunity)\n {\n column(Status; Status) { }\n column(OpportunityCount; \"No.\") { Method = Count; }\n }\n }\n}"} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| --- | ||
| layout: default | ||
| title: Data Query - BC-Bench | ||
| --- | ||
|
|
||
| # Data Query | ||
|
|
||
| This category benchmarks an agent's ability to **generate Business Central AL queries** from a natural-language data question — an offline query-generation benchmark. There is **no MCP server and no live server in the loop**: the agent writes an AL query, and the query is evaluated deterministically. | ||
|
|
||
| Given a question, the agent authors a single AL `query` object and writes it to `query.al`. The harness then **compiles and runs both the generated query and a gold reference query** against a fixed dataset (the BC container's Contoso demo data) and compares the result sets. | ||
|
|
||
| ## How it is scored | ||
|
|
||
| Data Query is **execution-based** (like bug-fix), with no LLM judge: | ||
|
|
||
| - **build** — the generated query compiled and ran. | ||
| - **resolved** (the headline `ResolutionRate`) — the generated query's result set **matches the gold query's**. Rows are compared by value (numbers normalized, column names/order ignored); row order is ignored unless the entry marks the question as `ordered`. | ||
|
|
||
| To execute a query, the harness wraps it as an API query (injecting `APIPublisher`/`APIGroup`/`APIVersion`/`EntitySetName`), publishes a throwaway app to the container, and reads the query's OData endpoint. This runs on the `GitHub-BCBench` self-hosted runner (`requires_container = True`). | ||
|
|
||
| > This complements the AI Test Toolkit evals in the BC platform repo: those test the **MCP server** end-to-end, while BC-Bench benchmarks **models/agents** on query generation. | ||
|
|
||
| ## Dataset | ||
|
|
||
| Each entry has an `nl_prompt` (the question) and a `gold_query` (the reference AL query whose result set defines "correct"), plus `environment_setup_version` (the BC artifact) and `ordered`. See `dataset/dataquery.jsonl`. | ||
|
|
||
| ## Running it (no local containers) | ||
|
|
||
| Trigger it from the GitHub **Actions** tab — the self-hosted `GitHub-BCBench` runner provisions the BC container for you (a stock **sandbox artifact with Cronus/Contoso demo data** — no special build is needed, since the query is just compiled and run): | ||
|
|
||
| 1. Actions → **Evaluation with GitHub Copilot** (or **Evaluation with Claude Code**) → **Run workflow**. | ||
| 2. Set **category** = `data-query`, pick a **model**, leave **test-run** = `true` for a quick 2-entry run. | ||
| 3. The run: provisions the container → the agent writes `query.al` → the harness compiles + runs the generated and gold queries → compares result sets → `summarize-results` reports `ResolutionRate` / `BuildRate`. | ||
|
|
||
| `data-query` sets `requires_container = True`; its container setup **skips the repo clone** (there is no repo — the agent generates from scratch) and just stands up the sandbox container. | ||
|
|
||
| ### Local (optional) | ||
|
|
||
| ```bash | ||
| uv run bcbench evaluate copilot dataquery__outstanding-sales-value-by-customer-1 \ | ||
| --category data-query --container-name <bc-sandbox> --username admin --password <pw> | ||
| ``` | ||
|
|
||
| The optional `al-mcp` / `al-lsp` levers give the agent AL compiler/language-server feedback while it authors the query. | ||
|
|
||
| [← Back to Home](index.md) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
...bench/agent/shared/instructions/dataquery-bc/skills/al-query-authoring/SKILL.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| --- | ||
| name: al-query-authoring | ||
| description: Guide for authoring Business Central AL query objects that answer data questions (joins, aggregates, filters, sorting). Use this when asked to write an AL query that returns Business Central data such as customers, vendors, items, sales, purchases, projects, or opportunities. | ||
| --- | ||
|
|
||
| Write a single, compilable AL `query` object that returns exactly the data needed to answer | ||
| the question. Reference real Business Central tables and fields — a query that does not | ||
| compile, or returns the wrong data, fails. | ||
|
|
||
| ## Structure | ||
|
|
||
| ```al | ||
| query 50100 TopCustomersBySales | ||
| { | ||
| QueryType = Normal; | ||
|
|
||
| elements | ||
| { | ||
| dataitem(Customer; Customer) | ||
| { | ||
| column(No; "No.") { } | ||
| column(Name; Name) { } | ||
| dataitem(SalesLine; "Sales Line") | ||
| { | ||
| DataItemLink = "Sell-to Customer No." = Customer."No."; | ||
| DataItemTableFilter = "Document Type" = const(Order); | ||
| column(OutstandingAmount; "Outstanding Amount") { Method = Sum; } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Rules of thumb | ||
|
|
||
| - **Aggregate** a column with a method: `column(Total; "Amount (LCY)") { Method = Sum; }` | ||
| (also `Average`, `Count`, `Min`, `Max`). Non-aggregated columns become the GROUP BY. | ||
| - **Join** by nesting a `dataitem` and linking it: `DataItemLink = "<child field>" = Parent."<field>";`. | ||
| - **Filter** rows with `DataItemTableFilter = "<field>" = const(<value>);` (e.g. an Option | ||
| like `Document Type`) or a range/expression. | ||
| - **Order** with `OrderBy { descending(<column>); }` when the question asks for ranking or | ||
| "top N" (combine with `TopNumberOfRows` where appropriate). | ||
|
onbuyuka marked this conversation as resolved.
Outdated
|
||
| - **Quote** any field or table name that contains spaces or special characters: `"No."`, | ||
| `"Sales Line"`, `"Amount (LCY)"`. | ||
| - Prefer stored fields; FlowFields and Option fields are supported. | ||
|
|
||
| ## Common pitfalls | ||
|
|
||
| - Don't invent table or field names — use the real Business Central schema. | ||
| - Return only the columns the question needs; extra or missing columns change the result set. | ||
| - One `query` object per file. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.