Skip to content

Commit 0c6d896

Browse files
Merge pull request #470 from microsoft/macae-v3-fr-dev-92
Macae v3 fr dev 92
2 parents c5cfd6c + b0b90de commit 0c6d896

File tree

11 files changed

+294
-57
lines changed

11 files changed

+294
-57
lines changed

src/backend/v3/api/router.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,36 @@ async def user_clarification(
424424
)
425425
# Set the approval in the orchestration config
426426
if user_id and human_feedback.request_id:
427+
### validate rai
428+
if human_feedback.answer != None or human_feedback.answer !="":
429+
if not await rai_success(human_feedback.answer, False):
430+
track_event_if_configured(
431+
"RAI failed",
432+
{
433+
"status": "Plan Clarification ",
434+
"description": human_feedback.answer,
435+
"request_id": human_feedback.request_id,
436+
},
437+
)
438+
raise HTTPException(
439+
status_code=400,
440+
detail={
441+
"error_type": "RAI_VALIDATION_FAILED",
442+
"message": "Content Safety Check Failed",
443+
"description": "Your request contains content that doesn't meet our safety guidelines. Please modify your request to ensure it's appropriate and try again.",
444+
"suggestions": [
445+
"Remove any potentially harmful, inappropriate, or unsafe content",
446+
"Use more professional and constructive language",
447+
"Focus on legitimate business or educational objectives",
448+
"Ensure your request complies with content policies",
449+
],
450+
"user_action": "Please revise your request and try again",
451+
},
452+
)
453+
454+
455+
456+
427457
if (
428458
orchestration_config
429459
and human_feedback.request_id in orchestration_config.clarifications

src/backend/v3/models/messages.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ class UserClarificationResponse:
101101
"""Response for user clarification from the frontend."""
102102
request_id: str
103103
answer: str = ""
104+
plan_id: str = ""
105+
m_plan_id: str = ""
104106

105107
@dataclass(slots=True)
106108
class FinalResultMessage:

src/frontend/src/api/apiService.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,16 @@ export class APIService {
290290
* @returns Promise with response object
291291
*/
292292
async submitClarification(
293-
planId: string,
294-
sessionId: string,
295-
clarification: string
293+
request_id: string = "",
294+
answer: string = "",
295+
plan_id: string = "",
296+
m_plan_id: string = ""
296297
): Promise<{ status: string; session_id: string }> {
297298
const clarificationData: HumanClarification = {
298-
plan_id: planId,
299-
session_id: sessionId,
300-
human_clarification: clarification
299+
request_id,
300+
answer,
301+
plan_id,
302+
m_plan_id
301303
};
302304

303305
const response = await apiClient.post(
@@ -306,7 +308,7 @@ export class APIService {
306308
);
307309

308310
// Invalidate cached data
309-
this._cache.invalidate(new RegExp(`^(plan|steps)_${planId}`));
311+
this._cache.invalidate(new RegExp(`^(plan|steps)_${plan_id}`));
310312
this._cache.invalidate(new RegExp(`^plans_`));
311313

312314
return response;

src/frontend/src/components/content/streaming/StreamingAgentMessage.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@ import ReactMarkdown from "react-markdown";
33
import remarkGfm from "remark-gfm";
44
import rehypePrism from "rehype-prism";
55

6-
interface StreamingAgentMessageProps {
7-
agentMessages: AgentMessageData[];
8-
}
96

10-
const StreamingAgentMessage = ({ agentMessages }: StreamingAgentMessageProps) => {
7+
const StreamingAgentMessage = (agentMessages: AgentMessageData[]) => {
118
if (!agentMessages?.length) return null;
129

1310
// Filter out messages with empty content

src/frontend/src/models/agentMessage.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { Agent } from 'http';
12
import { BaseModel } from './plan';
3+
import { AgentMessageType, AgentType } from './enums';
24

35
/**
46
* Represents a message from an agent
@@ -20,9 +22,10 @@ export interface AgentMessage extends BaseModel {
2022

2123
export interface AgentMessageData {
2224
agent: string;
25+
agent_type: AgentMessageType;
2326
timestamp: number;
2427
steps: any[]; // intentionally always empty
2528
next_steps: []; // intentionally always empty
2629
raw_content: string;
2730
raw_data: string;
28-
}
31+
}

src/frontend/src/models/enums.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,9 @@ export enum WebsocketMessageType {
250250
USER_CLARIFICATION_REQUEST = "user_clarification_request",
251251
USER_CLARIFICATION_RESPONSE = "user_clarification_response",
252252
FINAL_RESULT_MESSAGE = "final_result_message"
253+
}
254+
255+
export enum AgentMessageType {
256+
HUMAN_AGENT = "Human_Agent",
257+
AI_AGENT = "AI_Agent",
253258
}

src/frontend/src/models/messages.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,10 @@ export interface HumanFeedback {
6565
* Message containing human clarification on a plan
6666
*/
6767
export interface HumanClarification {
68-
/** Plan identifier */
68+
request_id: string;
69+
answer: string;
6970
plan_id: string;
70-
/** Session identifier */
71-
session_id: string;
72-
/** Clarification from human */
73-
human_clarification: string;
71+
m_plan_id: string;
7472
}
7573

7674
/**
@@ -168,4 +166,10 @@ export interface ParsedPlanApprovalRequest {
168166
plan_id: string;
169167
parsedData: MPlanData;
170168
rawData: string;
169+
}
170+
171+
export interface ParsedUserClarification {
172+
type: WebsocketMessageType.USER_CLARIFICATION_REQUEST;
173+
question: string;
174+
request_id: string;
171175
}

src/frontend/src/pages/PlanPage.tsx

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState, useMemo } from "react"
22
import { useParams, useNavigate } from "react-router-dom";
33
import { Spinner, Text } from "@fluentui/react-components";
44
import { PlanDataService } from "../services/PlanDataService";
5-
import { ProcessedPlanData, PlanWithSteps, WebsocketMessageType, MPlanData, AgentMessageData } from "../models";
5+
import { ProcessedPlanData, PlanWithSteps, WebsocketMessageType, MPlanData, AgentMessageData, AgentMessageType, ParsedUserClarification } from "../models";
66
import PlanChat from "../components/content/PlanChat";
77
import PlanPanelRight from "../components/content/PlanPanelRight";
88
import PlanPanelLeft from "../components/content/PlanPanelLeft";
@@ -42,8 +42,9 @@ const PlanPage: React.FC = () => {
4242
const [planData, setPlanData] = useState<ProcessedPlanData | any>(null);
4343
const [allPlans, setAllPlans] = useState<ProcessedPlanData[]>([]);
4444
const [loading, setLoading] = useState<boolean>(true);
45-
const [submittingChatDisableInput, setSubmitting] = useState<boolean>(false);
45+
const [submittingChatDisableInput, setSubmittingChatDisableInput] = useState<boolean>(true);
4646
const [error, setError] = useState<Error | null>(null);
47+
const [clarificationMessage, setClarificationMessage] = useState<ParsedUserClarification | null>(null);
4748

4849
const [planApprovalRequest, setPlanApprovalRequest] = useState<MPlanData | null>(null);
4950
const [reloadLeftList, setReloadLeftList] = useState(true);
@@ -52,8 +53,7 @@ const PlanPage: React.FC = () => {
5253
const [wsConnected, setWsConnected] = useState(false);
5354
const [streamingMessages, setStreamingMessages] = useState<StreamingPlanUpdate[]>([]);
5455
const [streamingMessageBuffer, setStreamingMessageBuffer] = useState<string>("");
55-
// RAI Error state
56-
const [raiError, setRAIError] = useState<RAIErrorData | null>(null);
56+
5757

5858
const [agentMessages, setAgentMessages] = useState<AgentMessageData[]>([]);
5959
// Team config state
@@ -137,6 +137,19 @@ const PlanPage: React.FC = () => {
137137
useEffect(() => {
138138
const unsubscribe = webSocketService.on(WebsocketMessageType.USER_CLARIFICATION_REQUEST, (clarificationMessage: any) => {
139139
console.log('📋 Clarification Message', clarificationMessage);
140+
const agentMessageData = {
141+
agent: 'ProxyAgent',
142+
agent_type: AgentMessageType.AI_AGENT,
143+
timestamp: clarificationMessage.timestamp || Date.now(),
144+
steps: [], // intentionally always empty
145+
next_steps: [], // intentionally always empty
146+
raw_content: clarificationMessage.data.question || '',
147+
raw_data: clarificationMessage.data || '',
148+
} as AgentMessageData;
149+
console.log('✅ Parsed clarification message:', agentMessageData);
150+
setClarificationMessage(clarificationMessage.data as ParsedUserClarification | null);
151+
setAgentMessages(prev => [...prev, agentMessageData]);
152+
setSubmittingChatDisableInput(false);
140153
scrollToBottom();
141154

142155
});
@@ -154,6 +167,31 @@ const PlanPage: React.FC = () => {
154167
return () => unsubscribe();
155168
}, [scrollToBottom]);
156169

170+
171+
//WebsocketMessageType.FINAL_RESULT_MESSAGE
172+
useEffect(() => {
173+
const unsubscribe = webSocketService.on(WebsocketMessageType.FINAL_RESULT_MESSAGE, (finalMessage: any) => {
174+
console.log('📋 Final Result Message', finalMessage);
175+
const agentMessageData = {
176+
agent: 'ProxyAgent',
177+
agent_type: AgentMessageType.AI_AGENT,
178+
timestamp: Date.now(),
179+
steps: [], // intentionally always empty
180+
next_steps: [], // intentionally always empty
181+
raw_content: finalMessage.content || '',
182+
raw_data: finalMessage || '',
183+
} as AgentMessageData;
184+
console.log('✅ Parsed final result message:', agentMessageData);
185+
setAgentMessages(prev => [...prev, agentMessageData]);
186+
setSubmittingChatDisableInput(true);
187+
scrollToBottom();
188+
189+
});
190+
191+
return () => unsubscribe();
192+
}, [scrollToBottom]);
193+
194+
157195
//WebsocketMessageType.AGENT_MESSAGE
158196
useEffect(() => {
159197
const unsubscribe = webSocketService.on(WebsocketMessageType.AGENT_MESSAGE, (agentMessage: any) => {
@@ -325,24 +363,39 @@ const PlanPage: React.FC = () => {
325363
return;
326364
}
327365
setInput("");
328-
setRAIError(null); // Clear any previous RAI errors
366+
329367
if (!planData?.plan) return;
330-
setSubmitting(true);
368+
setSubmittingChatDisableInput(true);
331369
let id = showToast("Submitting clarification", "progress");
332370

333371
try {
334372
// Use legacy method for non-v3 backends
335-
await PlanDataService.submitClarification(
336-
planData.plan.id,
337-
planData.plan.session_id,
338-
chatInput
339-
);
340-
373+
const response = await PlanDataService.submitClarification({
374+
request_id: clarificationMessage?.request_id || "",
375+
answer: chatInput,
376+
plan_id: planData?.plan.id,
377+
m_plan_id: planApprovalRequest?.id || ""
378+
});
341379

380+
console.log("Clarification submitted successfully:", response);
342381
setInput("");
343382
dismissToast(id);
344383
showToast("Clarification submitted successfully", "success");
345-
await loadPlanData(false);
384+
setClarificationMessage(null);
385+
const agentMessageData = {
386+
agent: 'You',
387+
agent_type: AgentMessageType.HUMAN_AGENT,
388+
timestamp: Date.now(),
389+
steps: [], // intentionally always empty
390+
next_steps: [], // intentionally always empty
391+
raw_content: chatInput || '',
392+
raw_data: chatInput || '',
393+
} as AgentMessageData;
394+
395+
setAgentMessages(prev => [...prev, agentMessageData]);
396+
setSubmittingChatDisableInput(true);
397+
scrollToBottom();
398+
346399
} catch (error: any) {
347400
dismissToast(id);
348401

@@ -373,7 +426,7 @@ const PlanPage: React.FC = () => {
373426
],
374427
user_action: 'Please modify your input and try again.'
375428
};
376-
setRAIError(raiErrorData);
429+
377430
} else {
378431
// Handle other types of errors
379432
showToast(
@@ -385,7 +438,7 @@ const PlanPage: React.FC = () => {
385438
);
386439
}
387440
} finally {
388-
setSubmitting(false);
441+
setSubmittingChatDisableInput(false);
389442
}
390443
},
391444
[planData?.plan, showToast, dismissToast, loadPlanData]

0 commit comments

Comments
 (0)