Skip to content

Commit 520dfb6

Browse files
authored
Merge pull request #509 from microsoft/macae-v3-fr-dev-92
Macae v3 fr dev 92
2 parents 9e73d9c + 7ad2bb3 commit 520dfb6

File tree

11 files changed

+92
-37
lines changed

11 files changed

+92
-37
lines changed

src/backend/common/models/messages_kernel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class Plan(BaseDataModel):
125125
m_plan: Optional[Dict[str, Any]] = None
126126
summary: Optional[str] = None
127127
team_id: Optional[str] = None
128+
streaming_message: Optional[str] = None
128129
human_clarification_request: Optional[str] = None
129130
human_clarification_response: Optional[str] = None
130131

src/backend/v3/api/router.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,12 +1337,15 @@ async def get_plan_by_id(request: Request, plan_id: Optional[str] = Query(None)
13371337
team = await memory_store.get_team_by_id(team_id=plan.team_id)
13381338
agent_messages = await memory_store.get_agent_messages(plan_id=plan.plan_id)
13391339
mplan = plan.m_plan if plan.m_plan else None
1340+
streaming_message = plan.streaming_message if plan.streaming_message else ""
1341+
plan.streaming_message = "" # clear streaming message after retrieval
13401342
plan.m_plan = None # remove m_plan from plan object for response
13411343
return {
13421344
"plan": plan,
13431345
"team": team if team else None,
13441346
"messages": agent_messages,
13451347
"m_plan": mplan,
1348+
"streaming_message": streaming_message,
13461349
}
13471350
else:
13481351
track_event_if_configured(

src/backend/v3/common/services/plan_service.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ async def handle_agent_messages(
215215
await memory_store.add_agent_message(agent_msg)
216216
if agent_message.is_final:
217217
plan = await memory_store.get_plan(agent_msg.plan_id)
218+
plan.streaming_message = agent_message.streaming_message
218219
plan.overall_status = PlanStatus.completed
219220
await memory_store.update_plan(plan)
220221
return True

src/backend/v3/models/messages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class AgentMessageResponse:
146146
agent_type: AgentMessageType
147147
is_final: bool = False
148148
raw_data: str = None
149+
streaming_message: str = None
149150

150151

151152
class WebsocketMessageType(str, Enum):

src/frontend/src/api/apiService.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ export class APIService {
166166
plan: data.plan as Plan,
167167
messages: data.messages as AgentMessageBE[],
168168
m_plan: data.m_plan as MPlanBE | null,
169-
team: data.team as TeamConfigurationBE | null
169+
team: data.team as TeamConfigurationBE | null,
170+
streaming_message: data.streaming_message as string | null
170171
} as PlanFromAPI;
171172
if (useCache) {
172173
this._cache.set(cacheKey, results, 30000); // Cache for 30 seconds

src/frontend/src/components/content/PlanChat.tsx

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ import renderPlanResponse from "./streaming/StreamingPlanResponse";
3131
import { renderPlanExecutionMessage, renderThinkingState } from "./streaming/StreamingPlanState";
3232
import ContentNotFound from "../NotFound/ContentNotFound";
3333
import PlanChatBody from "./PlanChatBody";
34-
import renderBufferMessage from "./streaming/StreamingBufferMessage";
3534
import renderAgentMessages from "./streaming/StreamingAgentMessage";
35+
import StreamingBufferMessage from "./streaming/StreamingBufferMessage";
3636

3737
interface SimplifiedPlanChatProps extends PlanChatProps {
3838
onPlanReceived?: (planData: MPlanData) => void;
@@ -41,6 +41,7 @@ interface SimplifiedPlanChatProps extends PlanChatProps {
4141
waitingForPlan: boolean;
4242
messagesContainerRef: React.RefObject<HTMLDivElement>;
4343
streamingMessageBuffer: string;
44+
showBufferingText: boolean;
4445
agentMessages: AgentMessageData[];
4546
showProcessingPlanSpinner: boolean;
4647
showApprovalButtons: boolean;
@@ -63,26 +64,16 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
6364
waitingForPlan,
6465
messagesContainerRef,
6566
streamingMessageBuffer,
67+
showBufferingText,
6668
agentMessages,
6769
showProcessingPlanSpinner,
6870
showApprovalButtons,
6971
handleApprovePlan,
7072
handleRejectPlan,
7173
processingApproval
72-
73-
7474
}) => {
75-
const navigate = useNavigate();
76-
77-
const { showToast, dismissToast } = useInlineToaster();
7875
// States
7976

80-
81-
82-
83-
84-
85-
8677
if (!planData)
8778
return (
8879
<ContentNotFound subtitle="The requested page could not be found." />
@@ -119,8 +110,12 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
119110

120111
{showProcessingPlanSpinner && renderPlanExecutionMessage()}
121112
{/* Streaming plan updates */}
122-
{renderBufferMessage(streamingMessageBuffer)}
123-
113+
{showBufferingText && (
114+
<StreamingBufferMessage
115+
streamingMessageBuffer={streamingMessageBuffer}
116+
isStreaming={true}
117+
/>
118+
)}
124119
</div>
125120

126121
{/* Chat Input - only show if no plan is waiting for approval */}
@@ -132,7 +127,7 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
132127
OnChatSubmit={OnChatSubmit}
133128
waitingForPlan={waitingForPlan}
134129
loading={false} />
135-
130+
136131
</div>
137132
);
138133
};

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ interface StreamingBufferMessageProps {
1212
isStreaming?: boolean;
1313
}
1414

15-
const renderBufferMessage = (streamingMessageBuffer: string, isStreaming: boolean = false) => {
15+
// Convert to a proper React component instead of a function
16+
const StreamingBufferMessage: React.FC<StreamingBufferMessageProps> = ({
17+
streamingMessageBuffer,
18+
isStreaming = false
19+
}) => {
1620
const [isExpanded, setIsExpanded] = useState<boolean>(false);
1721
const [shouldFade, setShouldFade] = useState<boolean>(false);
1822
const contentRef = useRef<HTMLDivElement>(null);
@@ -51,11 +55,11 @@ const renderBufferMessage = (streamingMessageBuffer: string, isStreaming: boolea
5155
padding: '16px',
5256
fontSize: '14px',
5357
lineHeight: '1.5',
54-
height: isExpanded ? 'auto' : '256px', // Auto height when expanded
58+
height: isExpanded ? 'auto' : '256px',
5559
display: 'flex',
5660
flexDirection: 'column',
5761
position: 'relative',
58-
overflow: isExpanded ? 'visible' : 'hidden' // Allow overflow when expanded
62+
overflow: isExpanded ? 'visible' : 'hidden'
5963
}}>
6064
{/* Header */}
6165
<div style={{
@@ -185,7 +189,7 @@ const renderBufferMessage = (streamingMessageBuffer: string, isStreaming: boolea
185189
</div>
186190
)}
187191

188-
{/* Content area - expanded state (original behavior) */}
192+
{/* Content area - expanded state */}
189193
{isExpanded && (
190194
<div style={{
191195
padding: '12px',
@@ -221,4 +225,4 @@ const renderBufferMessage = (streamingMessageBuffer: string, isStreaming: boolea
221225
);
222226
};
223227

224-
export default renderBufferMessage;
228+
export default StreamingBufferMessage;

src/frontend/src/models/agentMessage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export interface AgentMessageResponse {
4848
/** Raw data associated with the message */
4949
raw_data: string;
5050

51+
streaming_message: string;
52+
5153
}
5254

5355
export interface FinalMessage {

src/frontend/src/models/plan.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ export interface PlanFromAPI {
216216
messages: AgentMessageBE[];
217217
m_plan: MPlanBE | null;
218218
team: TeamConfigurationBE | null;
219+
streaming_message: string | null;
219220
}
220221
/**
221222
* Interface for processed plan data
@@ -225,6 +226,7 @@ export interface ProcessedPlanData {
225226
team: TeamConfig | null;
226227
messages: AgentMessageData[];
227228
mplan: MPlanData | null;
229+
streaming_message: string | null;
228230
}
229231

230232

src/frontend/src/pages/PlanPage.tsx

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const PlanPage: React.FC = () => {
5252
const [wsConnected, setWsConnected] = useState<boolean>(false);
5353
const [streamingMessages, setStreamingMessages] = useState<StreamingPlanUpdate[]>([]);
5454
const [streamingMessageBuffer, setStreamingMessageBuffer] = useState<string>("");
55-
55+
const [showBufferingText, setShowBufferingText] = useState<boolean>(false);
5656
const [agentMessages, setAgentMessages] = useState<AgentMessageData[]>([]);
5757

5858
// Plan approval state - track when plan is approved
@@ -62,10 +62,10 @@ const PlanPage: React.FC = () => {
6262

6363

6464

65-
const processAgentMessage = useCallback((agentMessageData: AgentMessageData, planData: ProcessedPlanData, is_final: boolean = false) => {
65+
const processAgentMessage = useCallback((agentMessageData: AgentMessageData, planData: ProcessedPlanData, is_final: boolean = false, streaming_message: string = '') => {
6666

6767
// Persist / forward to backend (fire-and-forget with logging)
68-
const agentMessageResponse = PlanDataService.createAgentMessageResponse(agentMessageData, planData, is_final);
68+
const agentMessageResponse = PlanDataService.createAgentMessageResponse(agentMessageData, planData, is_final, streaming_message);
6969
console.log('📤 Persisting agent message:', agentMessageResponse);
7070
void apiService.sendAgentMessage(agentMessageResponse)
7171
.then(saved => {
@@ -82,9 +82,44 @@ const PlanPage: React.FC = () => {
8282
}, []);
8383

8484
const resetPlanVariables = useCallback(() => {
85-
86-
87-
}, []);
85+
setInput("");
86+
setPlanData(null);
87+
setLoading(true);
88+
setSubmittingChatDisableInput(true);
89+
setErrorLoading(false);
90+
setClarificationMessage(null);
91+
setProcessingApproval(false);
92+
setPlanApprovalRequest(null);
93+
setReloadLeftList(true);
94+
setWaitingForPlan(true);
95+
setShowProcessingPlanSpinner(false);
96+
setShowApprovalButtons(true);
97+
setContinueWithWebsocketFlow(false);
98+
setWsConnected(false);
99+
setStreamingMessages([]);
100+
setStreamingMessageBuffer("");
101+
setShowBufferingText(false);
102+
setAgentMessages([]);
103+
}, [
104+
setInput,
105+
setPlanData,
106+
setLoading,
107+
setSubmittingChatDisableInput,
108+
setErrorLoading,
109+
setClarificationMessage,
110+
setProcessingApproval,
111+
setPlanApprovalRequest,
112+
setReloadLeftList,
113+
setWaitingForPlan,
114+
setShowProcessingPlanSpinner,
115+
setShowApprovalButtons,
116+
setContinueWithWebsocketFlow,
117+
setWsConnected,
118+
setStreamingMessages,
119+
setStreamingMessageBuffer,
120+
setShowBufferingText,
121+
setAgentMessages
122+
]);
88123

89124
// Auto-scroll helper
90125
const scrollToBottom = useCallback(() => {
@@ -146,6 +181,7 @@ const PlanPage: React.FC = () => {
146181
//console.log('📋 Streaming Message', streamingMessage);
147182
// if is final true clear buffer and add final message to agent messages
148183
const line = PlanDataService.simplifyHumanClarification(streamingMessage.data.content);
184+
setShowBufferingText(true);
149185
setStreamingMessageBuffer(prev => prev + line);
150186
//scrollToBottom();
151187

@@ -175,7 +211,7 @@ const PlanPage: React.FC = () => {
175211
console.log('✅ Parsed clarification message:', agentMessageData);
176212
setClarificationMessage(clarificationMessage.data as ParsedUserClarification | null);
177213
setAgentMessages(prev => [...prev, agentMessageData]);
178-
setStreamingMessageBuffer("");
214+
setShowBufferingText(false);
179215
setShowProcessingPlanSpinner(false);
180216
setSubmittingChatDisableInput(false);
181217
scrollToBottom();
@@ -221,7 +257,8 @@ const PlanPage: React.FC = () => {
221257
console.log('✅ Parsed final result message:', agentMessageData);
222258
// we ignore the terminated message
223259
if (finalMessage?.data?.status === PlanStatus.COMPLETED) {
224-
setStreamingMessageBuffer("");
260+
261+
setShowBufferingText(true);
225262
setShowProcessingPlanSpinner(false);
226263
setAgentMessages(prev => [...prev, agentMessageData]);
227264
scrollToBottom();
@@ -232,14 +269,14 @@ const PlanPage: React.FC = () => {
232269
setPlanData({ ...planData });
233270
}
234271

235-
processAgentMessage(agentMessageData, planData, is_final);
272+
processAgentMessage(agentMessageData, planData, is_final, streamingMessageBuffer);
236273
}
237274

238275

239276
});
240277

241278
return () => unsubscribe();
242-
}, [scrollToBottom, planData, processAgentMessage]);
279+
}, [scrollToBottom, planData, processAgentMessage, streamingMessageBuffer]);
243280

244281
//WebsocketMessageType.AGENT_MESSAGE
245282
useEffect(() => {
@@ -340,7 +377,7 @@ const PlanPage: React.FC = () => {
340377
const loadPlanData = useCallback(
341378
async (useCache = true): Promise<ProcessedPlanData | null> => {
342379
if (!planId) return null;
343-
380+
resetPlanVariables();
344381
setLoading(true);
345382
try {
346383

@@ -364,6 +401,10 @@ const PlanPage: React.FC = () => {
364401
if (planResult?.mplan) {
365402
setPlanApprovalRequest(planResult.mplan);
366403
}
404+
if (planResult?.streaming_message && planResult.streaming_message.trim() !== "") {
405+
setStreamingMessageBuffer(planResult.streaming_message);
406+
setShowBufferingText(true);
407+
}
367408
setPlanData(planResult);
368409
return planResult;
369410
} catch (err) {
@@ -373,7 +414,7 @@ const PlanPage: React.FC = () => {
373414
setLoading(false);
374415
}
375416
},
376-
[planId, navigate]
417+
[planId, navigate, resetPlanVariables]
377418
);
378419

379420

@@ -595,6 +636,7 @@ const PlanPage: React.FC = () => {
595636
waitingForPlan={waitingForPlan}
596637
messagesContainerRef={messagesContainerRef}
597638
streamingMessageBuffer={streamingMessageBuffer}
639+
showBufferingText={showBufferingText}
598640
agentMessages={agentMessages}
599641
showProcessingPlanSpinner={showProcessingPlanSpinner}
600642
showApprovalButtons={showApprovalButtons}

0 commit comments

Comments
 (0)