Bug
Affects main at commit 313fe64, confirmed April 20, 2026, when running against a completed Step 4 report with the Step 5 "Enter Deep Interaction" chat panel.
Sending any query through the Step 5 Report Agent chat triggers a frontend TypeError on render. The backend completes the request successfully (HTTP 200 with a well-formed response body) but no message ever appears in the chat panel.
Stack trace
TypeError: content.replace is not a function
at renderMarkdown (Step5Interaction.vue:~152)
The error fires inside the renderMarkdown helper when it attempts content.replace(...) on a non-string input.
Root cause
There is a contract mismatch between the /api/report/chat endpoint and the chat panel that renders its response.
Backend — backend/app/api/report.py, the chat_with_report_agent handler:
result = agent.chat(message=message, chat_history=chat_history)
return jsonify({"success": True, "data": {"response": result, "simulation_id": simulation_id}})
ReportAgent.chat() in backend/app/services/report_agent.py returns a dict, not a string:
{
"response": "...", # the actual text
"tool_calls": [...],
"sources": [...]
}
So data.response in the JSON payload is the entire dict object, not a string.
Frontend — frontend/src/components/Step5Interaction.vue, in sendToReportAgent:
content: res.data.response || res.data.answer || 'No response',
The dict is truthy, gets stored as msg.content, then renderMarkdown(msg.content) on the chat-message template call site calls .replace() on an object and throws.
This is LLM-agnostic — reproducible with any backend completion model (Ollama, OpenAI-compatible, etc.), because the shape mismatch is entirely in how ReportAgent.chat()'s return value is packaged for the HTTP response.
Reproduction
Step 1. Complete any simulation through Step 4 so a report artifact exists.
Step 2. Open the report and click Enter Deep Interaction to open the Step 5 chat panel.
Step 3. Send any query (e.g., "Summarize the key findings").
Step 4. Observe: backend returns HTTP 200 with a valid body, browser DevTools Network tab shows the successful response, but the chat panel stays blank and the browser console shows the TypeError above.
Suggested fix
Minimal backend change in backend/app/api/report.py, chat_with_report_agent handler — extract the string out of the dict before returning, and surface tool_calls and sources as sibling fields so future frontend work can render them without a second backend change:
result = agent.chat(message=message, chat_history=chat_history)
return jsonify({"success": True, "data": {
"response": result.get("response", ""),
"tool_calls": result.get("tool_calls", []),
"sources": result.get("sources", []),
"simulation_id": simulation_id
}})
This restores the documented frontend contract with no change to ReportAgent behavior.
Alternatively, Step5Interaction.vue's sendToReportAgent could be hardened to accept either shape (typeof x === 'string' ? x : x?.response), though the backend fix is the cleaner of the two.
Bug
Affects
mainat commit313fe64, confirmed April 20, 2026, when running against a completed Step 4 report with the Step 5 "Enter Deep Interaction" chat panel.Sending any query through the Step 5 Report Agent chat triggers a frontend
TypeErroron render. The backend completes the request successfully (HTTP 200 with a well-formed response body) but no message ever appears in the chat panel.Stack trace
The error fires inside the
renderMarkdownhelper when it attemptscontent.replace(...)on a non-string input.Root cause
There is a contract mismatch between the
/api/report/chatendpoint and the chat panel that renders its response.Backend —
backend/app/api/report.py, thechat_with_report_agenthandler:ReportAgent.chat()inbackend/app/services/report_agent.pyreturns a dict, not a string:{ "response": "...", # the actual text "tool_calls": [...], "sources": [...] }So
data.responsein the JSON payload is the entire dict object, not a string.Frontend —
frontend/src/components/Step5Interaction.vue, insendToReportAgent:The dict is truthy, gets stored as
msg.content, thenrenderMarkdown(msg.content)on the chat-message template call site calls.replace()on an object and throws.This is LLM-agnostic — reproducible with any backend completion model (Ollama, OpenAI-compatible, etc.), because the shape mismatch is entirely in how
ReportAgent.chat()'s return value is packaged for the HTTP response.Reproduction
Step 1. Complete any simulation through Step 4 so a report artifact exists.
Step 2. Open the report and click Enter Deep Interaction to open the Step 5 chat panel.
Step 3. Send any query (e.g., "Summarize the key findings").
Step 4. Observe: backend returns HTTP 200 with a valid body, browser DevTools Network tab shows the successful response, but the chat panel stays blank and the browser console shows the
TypeErrorabove.Suggested fix
Minimal backend change in
backend/app/api/report.py,chat_with_report_agenthandler — extract the string out of the dict before returning, and surfacetool_callsandsourcesas sibling fields so future frontend work can render them without a second backend change:This restores the documented frontend contract with no change to
ReportAgentbehavior.Alternatively,
Step5Interaction.vue'ssendToReportAgentcould be hardened to accept either shape (typeof x === 'string' ? x : x?.response), though the backend fix is the cleaner of the two.