Skip to content

Commit a527e1a

Browse files
added the Final message image rendering strcture to see Images in UI
1 parent 571bc88 commit a527e1a

3 files changed

Lines changed: 57 additions & 10 deletions

File tree

src/backend/agents/image_agent.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ async def _invoke_stream(
202202
self.user_id,
203203
message_type=WebsocketMessageType.AGENT_MESSAGE,
204204
)
205-
logger.info("ImageAgent '%s': image sent to user '%s' via WebSocket", self.agent_name, self.user_id)
205+
logger.info(
206+
"ImageAgent '%s': image sent to user '%s' via WebSocket "
207+
"(response_id=%s message_id=%s, NOT in orchestrator final text)",
208+
self.agent_name, self.user_id, response_id, message_id,
209+
)
206210
except Exception as ws_exc:
207211
logger.error("ImageAgent '%s': failed to send image via WebSocket: %s", self.agent_name, ws_exc)
208212

src/backend/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,16 @@ async def lifespan(app: FastAPI):
8181
for logger_name in packages:
8282
logging.getLogger(logger_name).setLevel(azure_level)
8383

84+
for _af_logger in ("agent_framework", "agent_framework.openai"):
85+
logging.getLogger(_af_logger).setLevel(azure_level)
86+
8487
logging.getLogger("opentelemetry.sdk").setLevel(logging.ERROR)
8588

8689
logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(logging.WARNING)
8790

91+
# Suppress noisy Azure Cosmos DB HTTP request/response logging
92+
logging.getLogger("azure.cosmos._cosmos_http_logging_policy").setLevel(logging.WARNING)
93+
8894
# Suppress noisy Azure Monitor exporter "Transmission succeeded" logs
8995
logging.getLogger("azure.monitor.opentelemetry.exporter.export._base").setLevel(logging.WARNING)
9096

src/backend/orchestration/orchestration_manager.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import logging
55
import uuid
6+
import re
67
from typing import List, Optional
78

89
import models.messages as messages
@@ -33,6 +34,26 @@
3334
# See localspec/bugs/framework/F1-tool-history-leak.md
3435
apply_tool_history_leak_patch()
3536

37+
_BARE_IMAGE_URL_RE = re.compile(
38+
r"(?<![\(\]])"
39+
r"(?<!\]\()"
40+
r"(https?://[^\s)]+?"
41+
r"(?:/api/v4/images/[^\s)]+?|[^\s)]+?\.(?:png|jpe?g|gif|webp)))"
42+
r"(?=[\s)\]]|$)",
43+
re.IGNORECASE,
44+
)
45+
46+
47+
def _embed_bare_image_urls(text: str) -> str:
48+
"""Wrap bare image URLs in markdown image syntax so the UI renders them inline.
49+
50+
Skips URLs already inside ``![alt](url)`` or ``[text](url)`` (handled by the
51+
negative lookbehinds), so it never double-wraps an existing markdown embed.
52+
"""
53+
if not text:
54+
return text
55+
return _BARE_IMAGE_URL_RE.sub(r"![Generated image](\1)", text)
56+
3657
class OrchestrationManager:
3758
"""Manager for handling orchestration logic using agent_framework Magentic workflow."""
3859

@@ -378,6 +399,21 @@ async def run_orchestration(self, user_id: str, input_task) -> None:
378399
# accumulated orchestrator streaming chunks.
379400
final_text = final_output_ref[0] or "".join(orchestrator_chunks)
380401

402+
final_text = _embed_bare_image_urls(final_text)
403+
404+
# Issue 1 diagnostic: confirm the final answer carries a renderable image
405+
# embed. has_image_markdown tracks TRUE markdown (![]) — the renderable form;
406+
# has_image_url tracks any image reference, even a bare URL.
407+
final_source = "executor" if final_output_ref[0] else "chunks"
408+
has_image_markdown = "![" in final_text
409+
has_image_url = "/api/v4/images/" in final_text
410+
self.logger.info(
411+
"[FINAL-ASSEMBLY] job=%s user=%s source=%s len=%d "
412+
"has_image_markdown=%s has_image_url=%s",
413+
job_id, user_id, final_source, len(final_text),
414+
has_image_markdown, has_image_url,
415+
)
416+
381417
# Log results
382418
self.logger.info("\nAgent responses:")
383419
self.logger.info(
@@ -721,15 +757,16 @@ async def _process_event_stream(
721757
executor, cb_err,
722758
)
723759

724-
try:
725-
await streaming_agent_response_callback(
726-
executor, output_data, False, user_id,
727-
)
728-
except Exception as cb_err:
729-
self.logger.error(
730-
"Error in streaming callback for %s: %s",
731-
executor, cb_err,
732-
)
760+
if executor != "magentic_orchestrator":
761+
try:
762+
await streaming_agent_response_callback(
763+
executor, output_data, False, user_id,
764+
)
765+
except Exception as cb_err:
766+
self.logger.error(
767+
"Error in streaming callback for %s: %s",
768+
executor, cb_err,
769+
)
733770

734771
# Executor completed
735772
elif (

0 commit comments

Comments
 (0)