diff --git a/src/backend/v3/api/router.py b/src/backend/v3/api/router.py index d133715aa..ba57bd9f7 100644 --- a/src/backend/v3/api/router.py +++ b/src/backend/v3/api/router.py @@ -235,18 +235,7 @@ async def process_request( ) raise HTTPException( status_code=400, - detail={ - "error_type": "RAI_VALIDATION_FAILED", - "message": "Content Safety Check Failed", - "description": "Your request contains content that doesn't meet our safety guidelines. Please modify your request to ensure it's appropriate and try again.", - "suggestions": [ - "Remove any potentially harmful, inappropriate, or unsafe content", - "Use more professional and constructive language", - "Focus on legitimate business or educational objectives", - "Ensure your request complies with content policies", - ], - "user_action": "Please revise your request and try again", - }, + detail="Request contains content that doesn't meet our safety guidelines, try again.", ) authenticated_user = get_authenticated_user_details(request_headers=request.headers) @@ -256,7 +245,7 @@ async def process_request( track_event_if_configured( "UserIdNotFound", {"status_code": 400, "detail": "no user"} ) - raise HTTPException(status_code=400, detail="no user") + raise HTTPException(status_code=400, detail="no user found") # if not input_task.team_id: # track_event_if_configured( diff --git a/src/frontend/src/components/content/HomeInput.tsx b/src/frontend/src/components/content/HomeInput.tsx index 9e7202ab4..0de34dac9 100644 --- a/src/frontend/src/components/content/HomeInput.tsx +++ b/src/frontend/src/components/content/HomeInput.tsx @@ -114,36 +114,19 @@ const HomeInput: React.FC = ({ dismissToast(id); } } catch (error: any) { + console.log("Error creating plan:", error); + let errorMessage = "Unable to create plan. Please try again."; dismissToast(id); // Check if this is an RAI validation error - let errorDetail = null; try { - // Try to parse the error detail if it's a string - if (typeof error?.response?.data?.detail === 'string') { - errorDetail = JSON.parse(error.response.data.detail); - } else { - errorDetail = error?.response?.data?.detail; - } + // errorDetail = JSON.parse(error); + errorMessage = error?.message || errorMessage; } catch (parseError) { - // If parsing fails, use the original error - errorDetail = error?.response?.data?.detail; + console.error("Error parsing error detail:", parseError); } - // Handle RAI validation errors - just show description as toast - if (errorDetail?.error_type === 'RAI_VALIDATION_FAILED') { - const description = errorDetail.description || - "Your request contains content that doesn't meet our safety guidelines. Please try rephrasing."; - showToast(description, "error"); - } else { - // Handle other errors with toast messages - const errorMessage = errorDetail?.description || - errorDetail?.message || - error?.response?.data?.message || - error?.message || - "Something went wrong. Please try again."; - - showToast(errorMessage, "error"); - } + + showToast(errorMessage, "error"); } finally { setInput(""); setSubmitting(false); diff --git a/src/frontend/src/components/content/PlanChatBody.tsx b/src/frontend/src/components/content/PlanChatBody.tsx index 44347859b..5848e8724 100644 --- a/src/frontend/src/components/content/PlanChatBody.tsx +++ b/src/frontend/src/components/content/PlanChatBody.tsx @@ -41,11 +41,7 @@ const PlanChatBody: React.FC = ({ onChange={setInput} onEnter={() => OnChatSubmit(input)} disabledChat={submittingChatDisableInput} - placeholder={ - waitingForPlan - ? "Creating plan..." - : "Type your message here..." - } + placeholder="Type your message here..." style={{ fontSize: '16px', borderRadius: '8px', @@ -68,7 +64,7 @@ const PlanChatBody: React.FC = ({ backgroundColor: 'transparent', border: 'none', color: (submittingChatDisableInput || !input.trim()) - ? 'var(--colorNeutralForegroundDisabled)' + ? 'var(--colorNeutralForegroundDisabled)' : 'var(--colorBrandForeground1)', flexShrink: 0, }} diff --git a/src/frontend/src/components/content/PlanPanelLeft.tsx b/src/frontend/src/components/content/PlanPanelLeft.tsx index b6febf79c..4962b21b9 100644 --- a/src/frontend/src/components/content/PlanPanelLeft.tsx +++ b/src/frontend/src/components/content/PlanPanelLeft.tsx @@ -79,6 +79,13 @@ const PlanPanelLeft: React.FC = ({ setUserInfo(getUserInfoGlobal()); }, [loadPlansData, setUserInfo]); + + useEffect(() => { + console.log("Reload tasks changed:", reloadTasks); + if (reloadTasks) { + loadPlansData(); + } + }, [loadPlansData, setUserInfo, reloadTasks]); useEffect(() => { if (plans) { const { inProgress, completed } = @@ -215,7 +222,7 @@ const PlanPanelLeft: React.FC = ({
{/* User Card */} diff --git a/src/frontend/src/pages/PlanPage.tsx b/src/frontend/src/pages/PlanPage.tsx index 5c0670ac8..a6eafd0f1 100644 --- a/src/frontend/src/pages/PlanPage.tsx +++ b/src/frontend/src/pages/PlanPage.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState, useMemo } from "react" import { useParams, useNavigate } from "react-router-dom"; import { Spinner, Text } from "@fluentui/react-components"; import { PlanDataService } from "../services/PlanDataService"; -import { ProcessedPlanData, WebsocketMessageType, MPlanData, AgentMessageData, AgentMessageType, ParsedUserClarification, AgentType, PlanStatus, FinalMessage } from "../models"; +import { ProcessedPlanData, WebsocketMessageType, MPlanData, AgentMessageData, AgentMessageType, ParsedUserClarification, AgentType, PlanStatus, FinalMessage, TeamConfig } from "../models"; import PlanChat from "../components/content/PlanChat"; import PlanPanelRight from "../components/content/PlanPanelRight"; import PlanPanelLeft from "../components/content/PlanPanelLeft"; @@ -48,6 +48,7 @@ const PlanPage: React.FC = () => { const [showProcessingPlanSpinner, setShowProcessingPlanSpinner] = useState(false); const [showApprovalButtons, setShowApprovalButtons] = useState(true); const [continueWithWebsocketFlow, setContinueWithWebsocketFlow] = useState(false); + const [selectedTeam, setSelectedTeam] = useState(null); // WebSocket connection state const [wsConnected, setWsConnected] = useState(false); const [streamingMessages, setStreamingMessages] = useState([]); @@ -261,6 +262,7 @@ const PlanPage: React.FC = () => { setShowBufferingText(true); setShowProcessingPlanSpinner(false); setAgentMessages(prev => [...prev, agentMessageData]); + setSelectedTeam(planData?.team || null); scrollToBottom(); // Persist the agent message const is_final = true; @@ -270,13 +272,19 @@ const PlanPage: React.FC = () => { } processAgentMessage(agentMessageData, planData, is_final, streamingMessageBuffer); + + setTimeout(() => { + console.log('✅ Plan completed, refreshing left list'); + setReloadLeftList(true); + }, 1000); + } }); return () => unsubscribe(); - }, [scrollToBottom, planData, processAgentMessage, streamingMessageBuffer]); + }, [scrollToBottom, planData, processAgentMessage, streamingMessageBuffer, setSelectedTeam, setReloadLeftList]); //WebsocketMessageType.AGENT_MESSAGE useEffect(() => { @@ -409,6 +417,8 @@ const PlanPage: React.FC = () => { return planResult; } catch (err) { console.log("Failed to load plan data:", err); + setErrorLoading(true); + setPlanData(null); return null; } finally { setLoading(false); @@ -564,6 +574,15 @@ const PlanPage: React.FC = () => { return ( + { }} + onTeamUpload={async () => { }} + isHomePage={false} + selectedTeam={selectedTeam} + />
{ onTeamSelect={() => { }} onTeamUpload={async () => { }} isHomePage={false} - selectedTeam={null} + selectedTeam={selectedTeam} /> diff --git a/src/frontend/src/services/PlanDataService.tsx b/src/frontend/src/services/PlanDataService.tsx index 70cd64e6b..18770a114 100644 --- a/src/frontend/src/services/PlanDataService.tsx +++ b/src/frontend/src/services/PlanDataService.tsx @@ -893,16 +893,30 @@ export class PlanDataService { } // Capture the inside of UserClarificationResponse(...) - const outerMatch = line.match(/Human clarification:\s*UserClarificationResponse\((.*?)\)/s); + const outerMatch = line.match(/Human clarification:\s*UserClarificationResponse\((.*)\)$/s); if (!outerMatch) return line; const inner = outerMatch[1]; - // Find answer= '...' | "..." - const answerMatch = inner.match(/answer=(?:"((?:\\.|[^"])*)"|'((?:\\.|[^'])*)')/); - if (!answerMatch) return line; + // Find answer= '...' | "..." - Updated regex to handle the full content properly + const answerMatch = inner.match(/answer='([^']*(?:''[^']*)*)'/); + if (!answerMatch) { + // Try double quotes if single quotes don't work + const doubleQuoteMatch = inner.match(/answer="([^"]*(?:""[^"]*)*)"/); + if (!doubleQuoteMatch) return line; - let answer = answerMatch[1] ?? answerMatch[2] ?? ''; + let answer = doubleQuoteMatch[1]; + answer = answer + .replace(/\\n/g, '\n') + .replace(/\\'/g, "'") + .replace(/\\"/g, '"') + .replace(/\\\\/g, '\\') + .trim(); + + return `Human clarification: ${answer}`; + } + + let answer = answerMatch[1]; // Unescape common sequences answer = answer .replace(/\\n/g, '\n') diff --git a/src/frontend/src/services/TaskService.tsx b/src/frontend/src/services/TaskService.tsx index bb8651a3b..ebf9106a8 100644 --- a/src/frontend/src/services/TaskService.tsx +++ b/src/frontend/src/services/TaskService.tsx @@ -195,28 +195,10 @@ export class TaskService { try { return await apiService.createPlan(inputTask); } catch (error: any) { + // You can customize this logic as needed let message = "Unable to create plan. Please try again."; - if (error?.response?.data?.detail) { - const detail = error.response.data.detail; - if (typeof detail === 'string' && detail.includes('RAI_VALIDATION_FAILED')) { - message = "Your request contains content that doesn't meet our safety guidelines. Please rephrase and try again."; - } else if (detail.includes('quota') || detail.includes('limit')) { - message = "Service is currently at capacity. Please try again in a few minutes."; - } else if (detail.includes('unauthorized') || detail.includes('forbidden')) { - message = "You don't have permission to create plans. Please contact your administrator."; - } else { - message = detail; - } - } else if (error?.response?.data?.message) { - message = error.response.data.message; - } else if (error?.message) { - if (error.message.includes('Network Error') || error.message.includes('fetch')) { - message = "Network error. Please check your connection and try again."; - } else { - message = error.message; - } - } + throw new Error(message); } }