feat: add Ask AI CE stubs and shared file wiring#41692
Conversation
Add minimal CE stubs and EE re-export shims so the Ask AI feature (implemented entirely in the EE repo) can integrate with shared files. New CE stub files: - ce/selectors/aiAssistantSelectors.ts (returns false/null/[]) - ce/actions/aiAssistantActions.ts (action creators + types) - ce/components/editorComponents/GPT/AISidePanel.tsx (returns null) - ce/components/editorComponents/GlobalAISidePanel/index.tsx (returns null) New EE re-export shims: - ee/selectors/aiAssistantSelectors.ts - ee/actions/aiAssistantActions.ts - ee/components/editorComponents/GPT/AISidePanel.tsx - ee/components/editorComponents/GlobalAISidePanel/index.tsx Updated existing CE files: - GPT/trigger.tsx: added isAISupportedMode, hasApiKey param to isAIEnabled - GPT/index.tsx: re-exports AISidePanel - ReduxActionConstants.tsx: added 9 new AI action types Updated shared files: - CodeEditor/index.tsx: AI selector/action imports, componentDidMount load - CodeEditor/generateQuickCommands.tsx: AI slash command updates - DynamicTextField.tsx: AIAssisted auto-detection for editor modes - StaticLayout.tsx, AnimatedLayout.tsx: render GlobalAISidePanel
WalkthroughAdds typed AI assistant Redux actions/constants/selectors, placeholder CE/EE AI side panel components and re-exports, CodeEditor refactor to dispatch Redux-driven open-with-context, editor-mode gating updates, and mounts a global AI side panel into app layouts. (≈33 words) Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CodeEditor
participant Redux as Redux (Actions & Selectors)
participant GlobalPanel as GlobalAISidePanel
User->>CodeEditor: Click AskAIButton
activate CodeEditor
CodeEditor->>CodeEditor: Extract editor context (cursor, fn, mode, value)
CodeEditor->>Redux: Dispatch openAIPanelWithContext(context)
deactivate CodeEditor
activate Redux
Redux->>Redux: Update AI state (isAIPanelOpen = true, context)
Redux->>GlobalPanel: Provide state via selectors / connect
deactivate Redux
activate GlobalPanel
GlobalPanel->>User: Render AI side panel with context
deactivate GlobalPanel
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/client/src/components/editorComponents/CodeEditor/index.tsx`:
- Around line 347-352: Replace the stale instance field AIEnabled with a derived
accessor: add a getAIEnabled() method that returns
isAIEnabled(this.props.featureFlags, this.props.mode, this.props.hasAIApiKey) &&
Boolean(this.props.AIAssisted), remove any assignments to this.AIEnabled
(including in constructor and componentDidUpdate), and update all call sites
(e.g., the lines referenced: 1213, 1437, 1744, 1813 and the other occurrences
around 589-598) to call this.getAIEnabled() so the value is always computed from
current props; also remove or update the incomplete componentDidUpdate logic
that attempted to recalc AIEnabled so it no longer mutates instance state.
- Around line 1749-1789: The onClick handler is using this.props.input.value
which can be stale — compute currentValue from the live editor before the
try/catch (use this.editor.getValue() when this.editor exists, falling back to
this.props.input.value or ""), then pass that currentValue into
openAIPanelWithContext and also reuse it in the catch fallback instead of an
empty string; update the onClick block around getAIContext, editor.getValue(),
and this.props.openAIPanelWithContext (and keep getEditorIdentifier(entity info)
and getAIContext usage intact).
- Around line 355-359: The component currently only calls loadAISettings() in
componentDidMount(), so when AIAssisted flips from false to true after mount the
config never loads; add a componentDidUpdate(prevProps) method that checks if
prevProps.AIAssisted was false and this.props.AIAssisted is true and
this.props.isAIConfigLoaded is false, and if so call
this.props.loadAISettings(); reuse the same guards as componentDidMount to avoid
duplicate loads and keep behavior consistent with existing load logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bde01aee-ac44-4ff2-ab5b-474ea8d7e969
📒 Files selected for processing (16)
app/client/src/ce/actions/aiAssistantActions.tsapp/client/src/ce/components/editorComponents/GPT/AISidePanel.tsxapp/client/src/ce/components/editorComponents/GPT/index.tsxapp/client/src/ce/components/editorComponents/GPT/trigger.tsxapp/client/src/ce/components/editorComponents/GlobalAISidePanel/index.tsxapp/client/src/ce/constants/ReduxActionConstants.tsxapp/client/src/ce/selectors/aiAssistantSelectors.tsapp/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsxapp/client/src/components/editorComponents/CodeEditor/index.tsxapp/client/src/components/editorComponents/form/fields/DynamicTextField.tsxapp/client/src/ee/actions/aiAssistantActions.tsapp/client/src/ee/components/editorComponents/GPT/AISidePanel.tsxapp/client/src/ee/components/editorComponents/GlobalAISidePanel/index.tsxapp/client/src/ee/selectors/aiAssistantSelectors.tsapp/client/src/pages/AppIDE/layouts/AnimatedLayout.tsxapp/client/src/pages/AppIDE/layouts/StaticLayout.tsx
💤 Files with no reviewable changes (1)
- app/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsx
|
This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected. |
Sync aiAssistantActions.ts to add databaseSchema/datasourceType fields and JSDoc comments matching the EE branch. Fix aiAssistantSelectors.ts lint errors by using eslint-disable comments instead of underscore-prefix parameter names, matching the EE approach.
…gration - Replace stale AIEnabled instance field with getAIEnabled() derived accessor that always computes from current props, preventing stale state when featureFlags/mode/AIAssisted change - Add loadAISettings() call in componentDidUpdate when AIAssisted transitions from false to true after mount - Use live editor value via this.editor.getValue() instead of potentially stale this.props.input.value for AI panel context - Reuse currentValue in catch fallback instead of empty string
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/client/src/components/editorComponents/CodeEditor/index.tsx`:
- Around line 1746-1786: When getAIContext() throws, the catch block currently
calls openAIPanelWithContext only with mode and currentValue, losing stable
metadata; update the catch to pass the same editorId (from
getEditorIdentifier(this.props)), entityName/entityId/propertyPath (from
entityInformation), and any other available fields (mode, currentValue) so the
fallback mirrors the success call—locate getAIContext, openAIPanelWithContext,
getEditorIdentifier, and entityInformation references in this click handler and
add editorId: getEditorIdentifier(this.props), entityName:
entityInformation?.entityName, entityId: entityInformation?.entityId,
propertyPath: entityInformation?.propertyPath to the object passed in the catch
branch.
- Around line 354-358: When handling the Ask AI fallback, preserve contextual
metadata by computing or extracting editorId, entityName, entityId, and
propertyPath outside the try/catch that calls getAIContext() (or re-computing
them in the catch) so they remain available if getAIContext() throws; then call
openAIPanelWithContext() in the catch with mode, currentValue and the preserved
editorId/entityName/entityId/propertyPath values instead of only mode and
currentValue. Update the code paths around getAIContext(),
openAIPanelWithContext(), and any local variables used in that block to ensure
those identifiers are set before the try or explicitly populated in the catch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f1f7c927-a930-42bf-965d-a2d6ca2678cd
📒 Files selected for processing (1)
app/client/src/components/editorComponents/CodeEditor/index.tsx
| componentDidMount(): void { | ||
| // Load AI settings if this is an AI-assisted editor and settings aren't loaded yet | ||
| if (this.props.AIAssisted && !this.props.isAIConfigLoaded) { | ||
| this.props.loadAISettings(); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
echo "=== loadAISettings definitions and call sites ==="
rg -n -C3 '\bloadAISettings\b' app/client/src
echo
echo "=== AI config loaded/loading state flags ==="
rg -n -C3 'isAIConfigLoaded|AIConfigLoaded|LOAD_AI_SETTINGS|AI_SETTINGS' app/client/src
echo
echo "=== AIAssisted call sites feeding CodeEditor ==="
rg -n -C2 'AIAssisted\s*[:=]' app/client/srcRepository: appsmithorg/appsmith
Length of output: 9893
🏁 Script executed:
#!/bin/bash
set -e
echo "=== AI Assistant Saga Implementation ==="
find app/client/src -name "*aiAssistant*saga*" -o -name "*AI*saga*" | head -20
echo
echo "=== AI Assistant Reducer Implementation ==="
find app/client/src -name "*aiAssistant*reducer*" -o -name "*AI*reducer*" | head -20
echo
echo "=== Search for LOAD_AI_SETTINGS handling in sagas ==="
rg -n 'LOAD_AI_SETTINGS' app/client/src --type ts --type tsx -A5 -B2
echo
echo "=== Search for AI settings reducer state structure ==="
rg -n 'aiAssistant|AIAssistant' app/client/src -g '*.ts' -g '*.tsx' | grep -i 'reducer\|initial.*state' | head -20Repository: appsmithorg/appsmith
Length of output: 249
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Search for AI-related saga files ==="
find app/client/src -type f -name "*.ts" -o -name "*.tsx" | xargs grep -l "LOAD_AI_SETTINGS\|aiAssistant.*saga" 2>/dev/null | head -20
echo
echo "=== Search for LOAD_AI_SETTINGS handling ==="
rg 'LOAD_AI_SETTINGS' app/client/src -A 5 -B 2 | head -100
echo
echo "=== Look for AI reducer files in typical locations ==="
find app/client/src -path "*/reducers/*" -type f | xargs grep -l "ai\|AI" 2>/dev/null | head -10
echo
echo "=== Check for loading state or in-flight guard ==="
rg 'aiSettings.*loading|AISettings.*loading|inFlight|isLoading' app/client/src | head -20Repository: appsmithorg/appsmith
Length of output: 4167
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Search for LOAD_AI_SETTINGS case/handler in all files ==="
rg 'case.*LOAD_AI_SETTINGS|LOAD_AI_SETTINGS.*case|handleLoadAI|reduceLoadAI' app/client/src -B2 -A8
echo
echo "=== Check if LOAD_AI_SETTINGS is handled in any reducer ==="
find app/client/src -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "LOAD_AI_SETTINGS" {} \;
echo
echo "=== Search for aiAssistant reducer in ee directory ==="
find app/client/src/ee -type f -name "*aiAssistant*" -o -name "*reducer*" | grep -i ai
echo
echo "=== Look for all reducers in ee directory ==="
find app/client/src/ee -path "*/reducers/*" -type f | head -20Repository: appsmithorg/appsmith
Length of output: 125
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Search EE directory for AI-related reducers/sagas ==="
find app/client/src/ee -type f \( -name "*.ts" -o -name "*.tsx" \) | xargs grep -l "LOAD_AI_SETTINGS\|aiAssistant.*reducer\|aiAssistant.*saga" 2>/dev/null | head -20
echo
echo "=== List all files in ee/reducers and ee/sagas ==="
find app/client/src/ee -path "*/reducers/*" -o -path "*/sagas/*" -type f | head -30
echo
echo "=== Check what's in ee/selectors/aiAssistantSelectors ==="
cat app/client/src/ee/selectors/aiAssistantSelectors.ts 2>/dev/null | head -60
echo
echo "=== Check what's in ee/actions/aiAssistantActions ==="
find app/client/src/ee -name "*aiAssistant*" -type fRepository: appsmithorg/appsmith
Length of output: 1990
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Check EE aiAssistantActions content ==="
cat app/client/src/ee/actions/aiAssistantActions.ts
echo
echo "=== Search all reducers for AI action handling ==="
rg 'aiAssistant|AIAssistant|LOAD_AI|UPDATE_AI' app/client/src/ee/reducers app/client/src/ce/reducers -B2 -A5
echo
echo "=== Check if there's any middleware processing AI actions ==="
rg 'LOAD_AI_SETTINGS|loadAISettings' app/client/src/ee app/client/src/ce -g '*.ts' -g '*.tsx'Repository: appsmithorg/appsmith
Length of output: 206
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Search for any aiAssistant reducer file ==="
find app/client/src -name "*aiAssistant*reducer*" -o -name "*reducer*" -type f | xargs grep -l "aiAssistant\|AIAssistant" 2>/dev/null
echo
echo "=== Search entire codebase for LOAD_AI_SETTINGS handler ==="
rg 'case.*LOAD_AI_SETTINGS|LOAD_AI_SETTINGS.*:' app/client/src
echo
echo "=== Check for saga files handling AI ==="
find app/client/src -name "*saga*" -type f | xargs grep -l "LOAD_AI_SETTINGS\|loadAISettings" 2>/dev/null
echo
echo "=== Look in uiReducers index for possible aiAssistant reducer ==="
cat app/client/src/ee/reducers/uiReducers/index.tsx | grep -A 50 "export"Repository: appsmithorg/appsmith
Length of output: 113
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Check ee/reducers/uiReducers/index.tsx ==="
head -200 app/client/src/ee/reducers/uiReducers/index.tsx
echo
echo "=== Check ce/reducers/uiReducers/index.tsx ==="
head -200 app/client/src/ce/reducers/uiReducers/index.tsx
echo
echo "=== Simple grep for any AI reducer state ==="
rg 'aiAssistant|AIAssistant' app/client/src/ce/reducers app/client/src/ee/reducersRepository: appsmithorg/appsmith
Length of output: 5808
🏁 Script executed:
#!/bin/bash
set -e
echo "=== Check Ask AI click handler around lines 1741-1791 ==="
sed -n '1730,1800p' app/client/src/components/editorComponents/CodeEditor/index.tsx
echo
echo "=== Check getAIContext function ==="
rg 'getAIContext' app/client/src/components/editorComponents/CodeEditor/index.tsx -A 20 -B 5Repository: appsmithorg/appsmith
Length of output: 4704
Include available context in the Ask AI fallback path.
When getAIContext() throws, the catch block only passes mode and currentValue to openAIPanelWithContext(), losing available metadata like editorId, entityName, entityId, and propertyPath that are computed or available outside the try block. Move these values outside the try/catch or compute them separately in the catch to preserve context even when AI context extraction fails.
Code location
Lines 1761–1790 in app/client/src/components/editorComponents/CodeEditor/index.tsx
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/client/src/components/editorComponents/CodeEditor/index.tsx` around lines
354 - 358, When handling the Ask AI fallback, preserve contextual metadata by
computing or extracting editorId, entityName, entityId, and propertyPath outside
the try/catch that calls getAIContext() (or re-computing them in the catch) so
they remain available if getAIContext() throws; then call
openAIPanelWithContext() in the catch with mode, currentValue and the preserved
editorId/entityName/entityId/propertyPath values instead of only mode and
currentValue. Update the code paths around getAIContext(),
openAIPanelWithContext(), and any local variables used in that block to ensure
those identifiers are set before the try or explicitly populated in the catch.
| onClick={() => { | ||
| const currentValue = this.editor | ||
| ? this.editor.getValue() | ||
| : typeof this.props.input.value === "string" | ||
| ? this.props.input.value | ||
| : ""; | ||
|
|
||
| try { | ||
| let aiContext = { | ||
| functionName: "", | ||
| cursorLineNumber: 0, | ||
| functionString: "", | ||
| }; | ||
|
|
||
| if (this.editor) { | ||
| const cursorPosition = this.editor.getCursor(); | ||
|
|
||
| aiContext = getAIContext({ | ||
| cursorPosition, | ||
| editor: this.editor, | ||
| }); | ||
| } | ||
|
|
||
| this.props.openAIPanelWithContext({ | ||
| functionName: aiContext.functionName, | ||
| cursorLineNumber: aiContext.cursorLineNumber, | ||
| functionString: aiContext.functionString, | ||
| mode: this.props.mode, | ||
| currentValue, | ||
| editorId: getEditorIdentifier(this.props), | ||
| entityName: entityInformation?.entityName, | ||
| entityId: entityInformation?.entityId, | ||
| propertyPath: entityInformation?.propertyPath, | ||
| }); | ||
| } catch (error) { | ||
| // eslint-disable-next-line no-console | ||
| console.error("Error opening AI panel:", error); | ||
| this.props.openAIPanelWithContext({ | ||
| mode: this.props.mode, | ||
| currentValue, | ||
| }); |
There was a problem hiding this comment.
Preserve stable editor metadata in the error fallback.
If getAIContext() throws, the fallback only sends mode and currentValue. editorId, entityName, entityId, and propertyPath are already available outside the failing code path, so dropping them makes the fallback materially less useful than it needs to be.
🔧 Suggested fix
<AskAIButton
entity={entityInformation}
mode={this.props.mode}
onClick={() => {
const currentValue = this.editor
? this.editor.getValue()
: typeof this.props.input.value === "string"
? this.props.input.value
: "";
+ const baseContext = {
+ mode: this.props.mode,
+ currentValue,
+ editorId: getEditorIdentifier(this.props),
+ entityName: entityInformation?.entityName,
+ entityId: entityInformation?.entityId,
+ propertyPath: entityInformation?.propertyPath,
+ };
try {
let aiContext = {
functionName: "",
cursorLineNumber: 0,
@@
this.props.openAIPanelWithContext({
+ ...baseContext,
functionName: aiContext.functionName,
cursorLineNumber: aiContext.cursorLineNumber,
functionString: aiContext.functionString,
- mode: this.props.mode,
- currentValue,
- editorId: getEditorIdentifier(this.props),
- entityName: entityInformation?.entityName,
- entityId: entityInformation?.entityId,
- propertyPath: entityInformation?.propertyPath,
});
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error opening AI panel:", error);
- this.props.openAIPanelWithContext({
- mode: this.props.mode,
- currentValue,
- });
+ this.props.openAIPanelWithContext(baseContext);
}
}}
/>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/client/src/components/editorComponents/CodeEditor/index.tsx` around lines
1746 - 1786, When getAIContext() throws, the catch block currently calls
openAIPanelWithContext only with mode and currentValue, losing stable metadata;
update the catch to pass the same editorId (from
getEditorIdentifier(this.props)), entityName/entityId/propertyPath (from
entityInformation), and any other available fields (mode, currentValue) so the
fallback mirrors the success call—locate getAIContext, openAIPanelWithContext,
getEditorIdentifier, and entityInformation references in this click handler and
add editorId: getEditorIdentifier(this.props), entityName:
entityInformation?.entityName, entityId: entityInformation?.entityId,
propertyPath: entityInformation?.propertyPath to the object passed in the catch
branch.
Summary
trigger.tsx,GPT/index.tsx) to match the new API surface expected by shared filesReduxActionConstants.tsxCodeEditor,DynamicTextField, IDE layouts) with the imports and conditional rendering hooks for Ask AIWhat this PR does NOT do
This PR does not add any AI functionality to the community edition. All CE stubs return
null,false, or[]. The actual Ask AI implementation lives entirely in the EE repo and will be enabled via thelicense_ask_ai_config_enabledfeature flag.Changes
New CE stub files (all return null/false)
ce/selectors/aiAssistantSelectors.tsce/actions/aiAssistantActions.tsce/components/editorComponents/GPT/AISidePanel.tsxce/components/editorComponents/GlobalAISidePanel/index.tsxNew EE re-export shims
ee/selectors/aiAssistantSelectors.tsee/actions/aiAssistantActions.tsee/components/editorComponents/GPT/AISidePanel.tsxee/components/editorComponents/GlobalAISidePanel/index.tsxUpdated existing CE files
GPT/trigger.tsx— addedisAISupportedMode()export andhasApiKeyparameter toisAIEnabled()GPT/index.tsx— re-exportsAISidePanelReduxActionConstants.tsx— 9 new AI action type constantsUpdated shared files
CodeEditor/index.tsx— AI selector/action imports, AI settings loading incomponentDidMountCodeEditor/generateQuickCommands.tsx— slash command updatesDynamicTextField.tsx—AIAssistedauto-detection for editor modesStaticLayout.tsx,AnimatedLayout.tsx— render<GlobalAISidePanel />Test plan
ee/imports correctly through the re-export shimsSummary by CodeRabbit
New Features
UI
Automation
/ok-to-test tags="@tag.All"
Tip
🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/24498281185
Commit: 73dce4d
Cypress dashboard.
Tags:
@tag.AllSpec:
Thu, 16 Apr 2026 09:39:26 UTC