(null);
+ const autoPromptFired = useRef(false);
useEffect(() => {
if (sessionId) localStorage.setItem('devops-session-id', sessionId);
@@ -74,6 +75,7 @@ export default function ChatPage({ onSessionsChange, onNew }: Props) {
const send = async (text: string) => {
if (!sessionId || busy || !text.trim()) return;
+ setFollowUpQuestions([]);
const agentId = crypto.randomUUID();
setMessages(prev => [
@@ -135,6 +137,8 @@ export default function ChatPage({ onSessionsChange, onNew }: Props) {
}));
} else if (payload.type === 'done') {
patch(agentId, { streaming: false, usage: payload.usage as AgentMsg['usage'] });
+ const fq = payload.follow_up_questions;
+ if (Array.isArray(fq) && fq.length > 0) setFollowUpQuestions(fq as string[]);
} else if (payload.type === 'error') {
const msg = payload.message as string;
patch(agentId, { streaming: false, error: msg });
@@ -208,6 +212,19 @@ export default function ChatPage({ onSessionsChange, onNew }: Props) {
+ {followUpQuestions.length > 0 && !busy && (
+
+ {followUpQuestions.map((q, i) => (
+
+ ))}
+
+ )}
);
diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx
index 5797887..5e23bc5 100644
--- a/frontend/src/pages/DashboardPage.tsx
+++ b/frontend/src/pages/DashboardPage.tsx
@@ -70,11 +70,16 @@ export default function DashboardPage() {
const [error, setError] = useState(null);
useEffect(() => {
- fetch('/stats')
- .then(r => { if (!r.ok) throw new Error(r.statusText); return r.json(); })
- .then(setStats)
- .catch(e => setError(e.message))
- .finally(() => setLoading(false));
+ const load = () =>
+ fetch('/stats')
+ .then(r => { if (!r.ok) throw new Error(r.statusText); return r.json(); })
+ .then(setStats)
+ .catch(e => setError(e.message))
+ .finally(() => setLoading(false));
+
+ load();
+ const interval = setInterval(load, 30_000);
+ return () => clearInterval(interval);
}, []);
if (loading) {
diff --git a/src/api/routers/chat.py b/src/api/routers/chat.py
index 92ee226..769246b 100644
--- a/src/api/routers/chat.py
+++ b/src/api/routers/chat.py
@@ -251,7 +251,15 @@ def _flush_text_buf():
await save_turn(session_id, user_message, response_text, tool_calls_log, usage)
await notify_slack(session_id, tool_calls_log)
- yield f"data: {json.dumps({'type': 'done', 'usage': usage})}\n\n"
+ follow_up_questions: list[str] = []
+ for tc in tool_calls_log:
+ if tc["tool"] == "submit_investigation":
+ fq = tc["args"].get("follow_up_questions")
+ if isinstance(fq, list):
+ follow_up_questions = [q for q in fq if isinstance(q, str)]
+ break
+
+ yield f"data: {json.dumps({'type': 'done', 'usage': usage, 'follow_up_questions': follow_up_questions})}\n\n"
@router.post("/chat")
diff --git a/src/tools/final_answer.py b/src/tools/final_answer.py
index 0000f3a..bdf8d37 100644
--- a/src/tools/final_answer.py
+++ b/src/tools/final_answer.py
@@ -22,10 +22,16 @@ def submit_investigation(
confidence: VALID_CONFIDENCE,
services_affected: list[str],
recommended_follow_up: str,
+ follow_up_questions: list[str],
) -> str:
"""Submit the final structured investigation result. Call this exactly once when you have
gathered sufficient evidence and reached a conclusion. Do not output a JSON block in
- free text — call this tool instead."""
+ free text — call this tool instead.
+
+ follow_up_questions: 3 short drill-down questions the user might want to ask next,
+ e.g. ["What caused the spike at 14:32?", "Are retries configured on the Lambda?",
+ "Has this happened before this week?"].
+ """
return "Investigation result recorded."