From 072e46c1e1fece0513d0265e6ceb1c88e5cdbee5 Mon Sep 17 00:00:00 2001 From: pavilion4ik Date: Wed, 7 Jan 2026 04:45:22 +0200 Subject: [PATCH 1/4] feat: prevent UI from showing raw JSON when AI response is empty - Fixed backend LLM response handling to properly fallback when values are empty - Replaced dict.get(key, default) with value-or-default fallback logic - Added a shared "no response" message constant on the frontend - Updated frontend to show a friendly message instead of raw JSON responses # Conflicts: # frontend/src/ConfigurableAIAssistance.tsx # frontend/src/GetAIAssistanceButton.tsx # frontend/src/components/AIEducatorLibraryAssistComponent.tsx # frontend/src/components/AISidebarResponse.tsx --- .../workflows/orchestrators/orchestrators.py | 10 +++++----- frontend/src/ConfigurableAIAssistance.tsx | 3 ++- frontend/src/GetAIAssistanceButton.tsx | 3 ++- .../components/AIEducatorLibraryAssistComponent.tsx | 3 ++- frontend/src/components/AISidebarResponse.tsx | 3 ++- frontend/src/services/constants.js | 1 + 6 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 frontend/src/services/constants.js diff --git a/backend/openedx_ai_extensions/workflows/orchestrators/orchestrators.py b/backend/openedx_ai_extensions/workflows/orchestrators/orchestrators.py index ede6931a..59beea89 100644 --- a/backend/openedx_ai_extensions/workflows/orchestrators/orchestrators.py +++ b/backend/openedx_ai_extensions/workflows/orchestrators/orchestrators.py @@ -123,7 +123,7 @@ def run(self, input_data): # --- 7. Return Structured Non-Streaming Result --- # If execution reaches this point, we have a successful, non-streaming result (Dict). response_data = { - 'response': llm_result.get('response', 'No response available'), + 'response': llm_result.get('response') or 'No response available', 'status': 'completed', 'metadata': { 'tokens_used': llm_result.get('tokens_used'), @@ -242,7 +242,7 @@ def lazy_load_chat_history(self, input_data): } return { - "response": result.get("response", "{}"), + "response": result.get("response") or "{}", "status": "completed", } @@ -312,7 +312,7 @@ def run(self, input_data): "status": "SubmissionProcessor error", } return { - "response": history_result.get("response", "No response available"), + "response": history_result.get("response") or "No response available", "status": "completed", } @@ -359,7 +359,7 @@ def run(self, input_data): # --- BRANCH C: Handle Non-Streaming (Standard) --- messages = [ - {"role": "assistant", "content": llm_result.get("response", "")}, + {"role": "assistant", "content": llm_result.get("response") or ""}, ] if input_data: messages.insert(0, {"role": "user", "content": input_data}) @@ -382,7 +382,7 @@ def run(self, input_data): # 4. Return result return { - "response": llm_result.get("response", "No response available"), + "response": llm_result.get("response") or "No response available", "status": "completed", "metadata": { "tokens_used": llm_result.get("tokens_used"), diff --git a/frontend/src/ConfigurableAIAssistance.tsx b/frontend/src/ConfigurableAIAssistance.tsx index ca92ac1e..4f5635eb 100644 --- a/frontend/src/ConfigurableAIAssistance.tsx +++ b/frontend/src/ConfigurableAIAssistance.tsx @@ -24,6 +24,7 @@ import { } from './components'; import { PluginConfiguration } from './types'; import { WORKFLOW_ACTIONS } from './constants'; +import { NO_RESPONSE_MSG } from './services/constants'; /** * Component Registry @@ -184,7 +185,7 @@ const ConfigurableAIAssistance = ({ } else if (data.error) { throw new Error(data.error); } else { - setResponse(JSON.stringify(data, null, 2)); + setResponse(NO_RESPONSE_MSG); setHasAsked(true); } diff --git a/frontend/src/GetAIAssistanceButton.tsx b/frontend/src/GetAIAssistanceButton.tsx index ae2af73d..b606ac4b 100644 --- a/frontend/src/GetAIAssistanceButton.tsx +++ b/frontend/src/GetAIAssistanceButton.tsx @@ -18,6 +18,7 @@ interface GetAIAssistanceButtonProps { requestMessage?: string; buttonText?: string; } +import { NO_RESPONSE_MSG } from './services/constants'; /** * Main AI Assistant Plugin Component @@ -85,7 +86,7 @@ const GetAIAssistanceButton = ({ throw new Error(data.error); } else { // If API returns something but in unexpected format, try to use it - setResponse(JSON.stringify(data, null, 2)); + setResponse(NO_RESPONSE_MSG); setHasAsked(true); } diff --git a/frontend/src/components/AIEducatorLibraryAssistComponent.tsx b/frontend/src/components/AIEducatorLibraryAssistComponent.tsx index 80488eb9..f6e2a80b 100644 --- a/frontend/src/components/AIEducatorLibraryAssistComponent.tsx +++ b/frontend/src/components/AIEducatorLibraryAssistComponent.tsx @@ -11,6 +11,7 @@ import { AutoAwesome, Close } from '@openedx/paragon/icons'; import { getConfig } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { callWorkflowService, prepareContextData } from '../services'; +import { NO_RESPONSE_MSG } from '../services/constants'; import { WORKFLOW_ACTIONS } from '../constants'; interface AIEducatorLibraryAssistComponentProps { @@ -219,7 +220,7 @@ const AIEducatorLibraryAssistComponent = ({ } else { // Immediate response const immediateResponse = data.response || data.message || data.content - || data.result || JSON.stringify(data, null, 2); + || data.result || NO_RESPONSE_MSG; setResponse(immediateResponse); } diff --git a/frontend/src/components/AISidebarResponse.tsx b/frontend/src/components/AISidebarResponse.tsx index ba89a125..8469a93b 100644 --- a/frontend/src/components/AISidebarResponse.tsx +++ b/frontend/src/components/AISidebarResponse.tsx @@ -22,6 +22,7 @@ import { } from '../services'; import { AIChatMessage, AIModelResponse, PluginContext } from '../types'; import { WORKFLOW_ACTIONS } from '../constants'; +import { NO_RESPONSE_MSG } from '../services/constants'; /** * AI Sidebar Response Component @@ -427,7 +428,7 @@ const AISidebarResponse = ({ } else if (data.result) { aiResponse = data.result; } else { - aiResponse = JSON.stringify(data, null, 2); + aiResponse = NO_RESPONSE_MSG; } // Update the AI placeholder with the final response diff --git a/frontend/src/services/constants.js b/frontend/src/services/constants.js new file mode 100644 index 00000000..95788838 --- /dev/null +++ b/frontend/src/services/constants.js @@ -0,0 +1 @@ +export const NO_RESPONSE_MSG = 'The server responded, but no readable content was found. Please try again or contact support if the issue persists.'; From 89b748b7da1ee2cc012b1a94d8336f2a599ef7c7 Mon Sep 17 00:00:00 2001 From: pavilion4ik Date: Fri, 9 Jan 2026 18:22:53 +0200 Subject: [PATCH 2/4] feat: align NO_RESPONSE_MSG with backend value - Updated NO_RESPONSE_MSG to match the backend default message --- frontend/src/services/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/services/constants.js b/frontend/src/services/constants.js index 95788838..62e6d2d2 100644 --- a/frontend/src/services/constants.js +++ b/frontend/src/services/constants.js @@ -1 +1 @@ -export const NO_RESPONSE_MSG = 'The server responded, but no readable content was found. Please try again or contact support if the issue persists.'; +export const NO_RESPONSE_MSG = 'No response available'; From d7341d29861abd3dc055fa3c5723a4c2873de8c2 Mon Sep 17 00:00:00 2001 From: pavilion4ik Date: Fri, 13 Feb 2026 19:29:40 +0200 Subject: [PATCH 3/4] feat: replace NO_RESPONSE_MSG constant - Replaced NO_RESPONSE_MSG - Removed redundant constants.js file --- frontend/src/ConfigurableAIAssistance.tsx | 3 +-- frontend/src/GetAIAssistanceButton.tsx | 4 +--- frontend/src/components/AIEducatorLibraryAssistComponent.tsx | 3 +-- frontend/src/components/AISidebarResponse.tsx | 3 +-- frontend/src/constants.ts | 1 + frontend/src/services/constants.js | 1 - 6 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 frontend/src/services/constants.js diff --git a/frontend/src/ConfigurableAIAssistance.tsx b/frontend/src/ConfigurableAIAssistance.tsx index 4f5635eb..1a7b1b7d 100644 --- a/frontend/src/ConfigurableAIAssistance.tsx +++ b/frontend/src/ConfigurableAIAssistance.tsx @@ -23,8 +23,7 @@ import { AIEducatorLibraryResponseComponent, } from './components'; import { PluginConfiguration } from './types'; -import { WORKFLOW_ACTIONS } from './constants'; -import { NO_RESPONSE_MSG } from './services/constants'; +import { WORKFLOW_ACTIONS, NO_RESPONSE_MSG } from './constants'; /** * Component Registry diff --git a/frontend/src/GetAIAssistanceButton.tsx b/frontend/src/GetAIAssistanceButton.tsx index b606ac4b..ae9d2199 100644 --- a/frontend/src/GetAIAssistanceButton.tsx +++ b/frontend/src/GetAIAssistanceButton.tsx @@ -12,14 +12,12 @@ import { AIRequestComponent, AIResponseComponent, } from './components'; -import { WORKFLOW_ACTIONS } from './constants'; +import {NO_RESPONSE_MSG, WORKFLOW_ACTIONS} from './constants'; interface GetAIAssistanceButtonProps { requestMessage?: string; buttonText?: string; } -import { NO_RESPONSE_MSG } from './services/constants'; - /** * Main AI Assistant Plugin Component * Orchestrates the AI assistance flow using modular components diff --git a/frontend/src/components/AIEducatorLibraryAssistComponent.tsx b/frontend/src/components/AIEducatorLibraryAssistComponent.tsx index f6e2a80b..f8322a37 100644 --- a/frontend/src/components/AIEducatorLibraryAssistComponent.tsx +++ b/frontend/src/components/AIEducatorLibraryAssistComponent.tsx @@ -11,8 +11,7 @@ import { AutoAwesome, Close } from '@openedx/paragon/icons'; import { getConfig } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { callWorkflowService, prepareContextData } from '../services'; -import { NO_RESPONSE_MSG } from '../services/constants'; -import { WORKFLOW_ACTIONS } from '../constants'; +import { WORKFLOW_ACTIONS, NO_RESPONSE_MSG } from '../constants'; interface AIEducatorLibraryAssistComponentProps { courseId: string; diff --git a/frontend/src/components/AISidebarResponse.tsx b/frontend/src/components/AISidebarResponse.tsx index 8469a93b..4cde8932 100644 --- a/frontend/src/components/AISidebarResponse.tsx +++ b/frontend/src/components/AISidebarResponse.tsx @@ -21,8 +21,7 @@ import { formatErrorMessage, } from '../services'; import { AIChatMessage, AIModelResponse, PluginContext } from '../types'; -import { WORKFLOW_ACTIONS } from '../constants'; -import { NO_RESPONSE_MSG } from '../services/constants'; +import { WORKFLOW_ACTIONS, NO_RESPONSE_MSG } from '../constants'; /** * AI Sidebar Response Component diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts index f7c8468c..d0dca0be 100644 --- a/frontend/src/constants.ts +++ b/frontend/src/constants.ts @@ -27,3 +27,4 @@ export const WORKFLOW_ACTIONS = { } as const; export type WorkflowActionType = typeof WORKFLOW_ACTIONS[keyof typeof WORKFLOW_ACTIONS]; +export const NO_RESPONSE_MSG = 'No response available'; diff --git a/frontend/src/services/constants.js b/frontend/src/services/constants.js deleted file mode 100644 index 62e6d2d2..00000000 --- a/frontend/src/services/constants.js +++ /dev/null @@ -1 +0,0 @@ -export const NO_RESPONSE_MSG = 'No response available'; From 9826d03fa2422fd54e761e33735f0c36994072b0 Mon Sep 17 00:00:00 2001 From: pavilion4ik Date: Fri, 13 Feb 2026 19:33:11 +0200 Subject: [PATCH 4/4] fix: fix linter - Fixed linter --- frontend/src/GetAIAssistanceButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/GetAIAssistanceButton.tsx b/frontend/src/GetAIAssistanceButton.tsx index e0083719..2a50ed12 100644 --- a/frontend/src/GetAIAssistanceButton.tsx +++ b/frontend/src/GetAIAssistanceButton.tsx @@ -13,7 +13,7 @@ import { AIRequestComponent, AIResponseComponent, } from './components'; -import {NO_RESPONSE_MSG, WORKFLOW_ACTIONS} from './constants'; +import { NO_RESPONSE_MSG, WORKFLOW_ACTIONS } from './constants'; interface GetAIAssistanceButtonProps { requestMessage?: string;