Skip to content

Refactor AI panel generation to remove table_name parameter and enhance prompt clarity#1637

Merged
Artuomka merged 2 commits into
mainfrom
backend_rework_panel_position_generation
Feb 26, 2026
Merged

Refactor AI panel generation to remove table_name parameter and enhance prompt clarity#1637
Artuomka merged 2 commits into
mainfrom
backend_rework_panel_position_generation

Conversation

@Artuomka

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings February 26, 2026 14:14
@Artuomka Artuomka enabled auto-merge February 26, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors AI-driven dashboard widget generation to remove the tableName query parameter and instead have the AI discover relevant tables via tool calls (getTablesList, getTableStructure), with updated prompts and E2E tests.

Changes:

  • Removed tableName from the generate-widget-with-AI controller API and data structure.
  • Updated the AI panel generation use case to run a streaming tool-call loop for schema discovery and improved prompt instructions.
  • Updated SaaS E2E tests to use the new endpoint contract and mock tool-call streaming.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
backend/test/ava-tests/saas-tests/dashboard-ai-widget-e2e.test.ts Updates E2E tests to call the endpoint without tableName and mocks tool-call streaming behavior.
backend/src/entities/visualizations/panel-position/use-cases/generate-panel-position-with-ai.use.case.ts Replaces table-bound prompting with a tool-loop approach; adds JSON extraction and updates EXPLAIN-based refinement flow.
backend/src/entities/visualizations/panel-position/panel-position.controller.ts Removes tableName query parameter from the API and updates Swagger docs/timeout.
backend/src/entities/visualizations/panel-position/data-structures/generate-panel-position-with-ai.ds.ts Removes table_name from the use case input structure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +113 to +115
let userEmail: string;
if (isConnectionTypeAgent(foundConnection.type)) {
userEmail = await this._dbContext.userRepository.getUserEmailOrReturnNull(userId);

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userEmail is declared but not initialized for non-agent connections, and getUserEmailOrReturnNull() can return null. This value is then passed into the tool loop where agent DAOs require a real email for getTablesFromDB/getTableStructure. Initialize userEmail to null/undefined explicitly, widen the parameter types accordingly, and for agent connections fail fast with a clear error if the email cannot be resolved.

Suggested change
let userEmail: string;
if (isConnectionTypeAgent(foundConnection.type)) {
userEmail = await this._dbContext.userRepository.getUserEmailOrReturnNull(userId);
let userEmail: string = '';
if (isConnectionTypeAgent(foundConnection.type)) {
const resolvedUserEmail = await this._dbContext.userRepository.getUserEmailOrReturnNull(userId);
if (!resolvedUserEmail) {
throw new BadRequestException(
'Unable to resolve user email for agent connection. A valid email is required to use AI tools.',
);
}
userEmail = resolvedUserEmail;

Copilot uses AI. Check for mistakes.
Comment on lines 404 to 407
try {
const explainQuery = `EXPLAIN ${query.replace(/;\s*$/, '')}`;
const result = await (dao as IDataAccessObject).executeRawQuery(explainQuery, tableName);
const result = await (dao as IDataAccessObject).executeRawQuery(explainQuery, '');
return { success: true, result: JSON.stringify(result, null, 2) };

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runExplainQuery calls executeRawQuery(explainQuery, '') without passing userEmail. For agent-backed connections, executeRawQuery requires both tableName and userEmail, so this will send an empty table name and an undefined email to the agent and likely fail. Pass through userEmail (and a meaningful table name if required by the agent) when calling executeRawQuery, similar to other places that execute queries against agent connections.

Copilot uses AI. Check for mistakes.

const firstBrace = response.indexOf('{');
if (firstBrace !== -1) {
return response.slice(firstBrace);

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractJsonFromResponse slices from the first { to the end of the response, but does not trim anything after the closing }. If the model returns valid JSON followed by any trailing text, JSON.parse will still fail even after cleanAIJsonResponse. Consider extracting up to the last } (or reusing the existing JSON sanitization helper) so the parser is resilient to common LLM formatting drift.

Suggested change
return response.slice(firstBrace);
const lastBrace = response.lastIndexOf('}');
if (lastBrace !== -1 && lastBrace > firstBrace) {
return response.slice(firstBrace, lastBrace + 1).trim();
}
return response.slice(firstBrace).trim();

Copilot uses AI. Check for mistakes.
@Artuomka Artuomka merged commit ba26acf into main Feb 26, 2026
17 of 19 checks passed
@Artuomka Artuomka deleted the backend_rework_panel_position_generation branch February 26, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants