AI Assistant: Integration between AiIntegration, GridCommands, AiAssistant and AiChat#33564
AI Assistant: Integration between AiIntegration, GridCommands, AiAssistant and AiChat#33564dmirgaev wants to merge 3 commits into
Conversation
actualize tests for AIAssistantIntegrationController implement buildContext method pass response schema to AI Integration from AI controller fix option types and add todos to move them to d.ts implement getCustomizedResponseTitle method add a command list to both controllers temporarily add the specification add getGridCommandList method to be able to override it in a simple way Replace CommandResults type with simple CommandResult[] and remove it from types as redundant
There was a problem hiding this comment.
Pull request overview
This PR wires the grid AI assistant end-to-end by connecting AIIntegration request execution to GridCommands (including response schema generation + grid context building) and then displaying the results in AIChat, with DataGrid-specific command/extra-context extensions.
Changes:
- Replaces the
CommandResultsalias usage withCommandResult[]across AI chat/assistant plumbing. - Extends
AIAssistantIntegrationController.sendRequestto accept a per-requestresponseSchemaand anextraContextselector, and implementsbuildContext(...)to serialize current grid state. - Introduces a core command registry (
commandsCore) and a DataGrid override controller that supplies DataGrid-specific commands and extra context options.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/utils.ts | Updates command typing and command-error detection used for message status/icon rendering. |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/types.ts | Stops re-exporting CommandResults; keeps CommandResult. |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts | Updates command list rendering to accept CommandResult[]. |
| packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts | Adjusts tests for the new command array typing. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/types.ts | Adds JSON schema/context-related types and updates AI message command typing. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/grid_commands.ts | Minor cleanup of TODO comments; command execution/schema generation remains the same. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/commands/index.ts | Adds a core list of built-in grid AI commands and exports commandsCore. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_integration_controller.ts | Adds responseSchema + extraContext inputs and implements grid/column context building. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts | Uses generated response schema/context, adds response title customization logic, and initializes default command list. |
| packages/devextreme/js/__internal/grids/grid_core/ai_assistant/tests/ai_assistant_integration_controller.integration.test.ts | Expands integration tests for schema passing, abort behavior, and context building. |
| packages/devextreme/js/__internal/grids/data_grid/ai_assistant/commands/index.ts | Builds a DataGrid command set by extending core commands with grouping/summary. |
| packages/devextreme/js/__internal/grids/data_grid/ai_assistant/ai_assistant.ts | Switches DataGrid to use a DataGrid-specific AI assistant controller. |
| packages/devextreme/js/__internal/grids/data_grid/ai_assistant/ai_assistant_controller.ts | Adds DataGrid overrides for command list and extra context options. |
Comments suppressed due to low confidence (3)
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts:92
- The rejection message
'Default error message'is a placeholder and is user-visible througherror.message. Replace it with a localized and actionable message (or reuse an existing localization key) to avoid shipping placeholder text.
if (!response?.actions || !Array.isArray(response.actions) || !response.actions.length) {
// TODO: need to localize default error message when there are no commands
return Promise.reject(new Error('Default error message'));
}
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts:97
- The rejection message
'Received invalid commands'is hard-coded and not localized. Consider using a localized message (and include basic context like validation failure) since this string will be shown to end users.
if (!this.gridCommands?.validate(response.actions)) {
// TODO: need to localize error message on validation fail
return Promise.reject(new Error('Received invalid commands'));
}
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts:190
new Error('Grid commands not initialized')is user-visible viafailAIMessageand is currently a hard-coded English internal detail. Replace with a localized, user-facing message (and/or ensure this situation cannot happen afterinit()).
if (!responseSchema) {
// TODO: Change error message
const error = new Error('Grid commands not initialized');
this.failAIMessage(aiMessage.id, error);
this.setProcessing(false);
reject(error);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (3)
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/types.ts:118
GridContext.selection.selectedRowKeysis typed as(string | number)[], but grid selection keys can be any type (e.g., composite/object keys). This makes the context typing incorrect and forces unsafe casts elsewhere. Consider widening this tounknown[](orArray<TKey>/any[]), matching grid option typings, to avoid losing type support for valid key shapes.
search: {
searchText: string;
};
selection: {
selectedRowKeys: (string | number)[];
};
}
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_integration_controller.ts:75
- If
onAIAssistantRequestCreatingsetsargs.cancel = true,sendRequestreturns without invoking any callback and without settingthis.abort. Callers (e.g.,AIAssistantController) currently set their ownprocessingflag before callingsendRequest, so this path can leave the request promise pending indefinitely. Consider either notifying viacallbacks(e.g.,onError/onAbort) when cancelled, or returning a boolean indicating whether a request was actually started so the caller can cleanly resolve/reject and reset state.
this.executeAction('onAIAssistantRequestCreating', args);
if (args.cancel) {
return;
}
packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_controller.ts:222
- The
// TODO: Change error messagecomments inside the.failandonErrorhandlers are misindented relative to the surrounding block, which is likely to trip formatting/lint rules and makes the nested callback harder to read. Please align these comments with the rest of the block indentation.
resolve();
})
.fail((errorMessage) => {
// TODO: Change error message
const error = errorMessage instanceof Error
? errorMessage
: new Error(String(errorMessage));
this.failAIMessage(aiMessage.id, error);
this.setProcessing(false);
reject(error);
});
},
onError: (error: Error): void => {
// TODO: Change error message
this.failAIMessage(aiMessage.id, error);
this.setProcessing(false);
| dataType: DataType | undefined; | ||
| visible: boolean; | ||
| sortOrder: SortOrder | undefined; | ||
| sortIndex: number | undefined; | ||
| filterValue: string | number | boolean | null | undefined; | ||
| fixed: boolean | undefined; | ||
| fixedPosition: FixedPosition | undefined; | ||
| width: number | string | undefined; |
| return {}; | ||
| public buildContext(extraContext: GridExtraContextOption | null): GridContext { | ||
| const dataController = this.getController('data'); | ||
| const selectedRowKeys = (this.option('selectedRowKeys') ?? []) as (string | number)[]; |
| const aiIntegration = this.getAIIntegration(); | ||
| if (!aiIntegration) { | ||
|
|
||
| if (aiIntegration === null) { | ||
| errors.log('E1068'); | ||
| return; | ||
| } |
| private sendRequestToAICore(aiMessage: AIMessage): Promise<void> { | ||
| this.setProcessing(true); | ||
|
|
||
| return new Promise((resolve, reject) => { | ||
| this.aiAssistantIntegrationController?.sendRequest(aiMessage.prompt, { | ||
| onComplete: (response: ExecuteGridAssistantCommandResult): void => { | ||
| fromPromise(this.processResponse(response)) | ||
| .done((commands: CommandResults) => { | ||
| this.completeAIMessage(aiMessage.id, commands); | ||
| this.setProcessing(false); | ||
| resolve(); | ||
| }) | ||
| .fail((errorMessage) => { | ||
| const error = errorMessage instanceof Error | ||
| ? errorMessage | ||
| : new Error(String(errorMessage)); | ||
|
|
||
| this.failAIMessage(aiMessage.id, error); | ||
| this.setProcessing(false); | ||
| reject(error); | ||
| }); | ||
| }, | ||
| onError: (error: Error): void => { | ||
| this.failAIMessage(aiMessage.id, error); | ||
| this.setProcessing(false); | ||
| reject(error); | ||
| }, | ||
| onAbort: (): void => { | ||
| const error = new Error(messageLocalization.format('dxDataGrid-aiAssistantAbortMessage')); | ||
|
|
||
| this.failAIMessage(aiMessage.id, error); | ||
| this.setProcessing(false); | ||
| reject(error); | ||
| const responseSchema = this.gridCommands?.buildResponseSchema(); | ||
| const extraContext = this.getGridExtraContext(); | ||
|
|
||
| if (!responseSchema) { | ||
| // TODO: Change error message | ||
| const error = new Error('Grid commands not initialized'); | ||
|
|
||
| this.failAIMessage(aiMessage.id, error); | ||
| this.setProcessing(false); | ||
| reject(error); | ||
| return; | ||
| } | ||
|
|
||
| this.aiAssistantIntegrationController?.sendRequest( | ||
| aiMessage.prompt, | ||
| responseSchema, | ||
| extraContext, | ||
| { | ||
| onComplete: (response: ExecuteGridAssistantCommandResult): void => { | ||
| fromPromise(this.processResponse(response)) | ||
| .done((commands: CommandResult[]) => { | ||
| const commandNames = this.getCommandNames(response.actions); | ||
|
|
||
| this.completeAIMessage(aiMessage.id, commands, commandNames); | ||
| this.setProcessing(false); |
No description provided.