Skip to content

Commit c17434c

Browse files
committed
Fix admin API, orchestrator, and conversation retrieval bugs
- admin.py: Use ContentSettings object for blob upload content_type - admin.py: Add required 'description' field mapping for Product model - orchestrator.py: Update HandoffBuilder to use .participants([...]) method - orchestrator.py: Pass agent instances instead of strings to set_coordinator/add_handoff - cosmos_service.py: Add cross-partition query fallback in get_conversation - cosmos_service.py: Add fallback logic to find correct partition key in delete_conversation
1 parent b6adf96 commit c17434c

3 files changed

Lines changed: 62 additions & 24 deletions

File tree

content-gen/src/backend/api/admin.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from typing import Any, Dict, List, Optional
1919

2020
from quart import Blueprint, request, jsonify
21+
from azure.storage.blob import ContentSettings
2122

2223
from backend.settings import app_settings
2324
from backend.services.cosmos_service import get_cosmos_service
@@ -129,7 +130,7 @@ async def upload_images():
129130
await blob_client.upload_blob(
130131
image_data,
131132
overwrite=True,
132-
content_settings={"content_type": content_type}
133+
content_settings=ContentSettings(content_type=content_type)
133134
)
134135

135136
results.append({
@@ -233,12 +234,15 @@ async def load_sample_data():
233234

234235
try:
235236
# Map incoming fields to Product model fields
237+
# Note: Product model requires 'description' field, map from incoming 'description' or 'marketing_description'
238+
description_value = product_data.get("description", product_data.get("marketing_description", ""))
236239
product_fields = {
237240
"product_name": product_data.get("product_name", ""),
238241
"sku": product_data.get("sku", ""),
242+
"description": description_value, # Required field
239243
"category": product_data.get("category", ""),
240244
"sub_category": product_data.get("sub_category", ""),
241-
"marketing_description": product_data.get("description", product_data.get("marketing_description", "")),
245+
"marketing_description": description_value, # Also set for backward compat
242246
"detailed_spec_description": product_data.get("detailed_spec_description", ""),
243247
"image_url": product_data.get("image_url", ""),
244248
"image_description": product_data.get("image_description", ""),

content-gen/src/backend/orchestrator.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -298,32 +298,32 @@ def initialize(self) -> None:
298298
self._workflow = (
299299
HandoffBuilder(
300300
name="content_generation_workflow",
301-
participants=[
302-
triage_agent,
303-
planning_agent,
304-
research_agent,
305-
text_content_agent,
306-
image_content_agent,
307-
compliance_agent,
308-
],
309301
)
310-
.set_coordinator("triage_agent")
302+
.participants([
303+
triage_agent,
304+
planning_agent,
305+
research_agent,
306+
text_content_agent,
307+
image_content_agent,
308+
compliance_agent,
309+
])
310+
.set_coordinator(triage_agent)
311311
# Triage can hand off to all specialists
312-
.add_handoff("triage_agent", [
313-
"planning_agent",
314-
"research_agent",
315-
"text_content_agent",
316-
"image_content_agent",
317-
"compliance_agent"
312+
.add_handoff(triage_agent, [
313+
planning_agent,
314+
research_agent,
315+
text_content_agent,
316+
image_content_agent,
317+
compliance_agent
318318
])
319319
# All specialists can hand back to triage
320-
.add_handoff("planning_agent", ["triage_agent"])
321-
.add_handoff("research_agent", ["triage_agent"])
320+
.add_handoff(planning_agent, [triage_agent])
321+
.add_handoff(research_agent, [triage_agent])
322322
# Content agents can request compliance check
323-
.add_handoff("text_content_agent", ["compliance_agent", "triage_agent"])
324-
.add_handoff("image_content_agent", ["compliance_agent", "triage_agent"])
323+
.add_handoff(text_content_agent, [compliance_agent, triage_agent])
324+
.add_handoff(image_content_agent, [compliance_agent, triage_agent])
325325
# Compliance can hand back to content agents for corrections or to triage
326-
.add_handoff("compliance_agent", ["text_content_agent", "image_content_agent", "triage_agent"])
326+
.add_handoff(compliance_agent, [text_content_agent, image_content_agent, triage_agent])
327327
.with_termination_condition(
328328
# Terminate after 10 user messages to prevent infinite loops
329329
lambda conv: sum(1 for msg in conv if msg.role.value == "user") >= 10

content-gen/src/backend/services/cosmos_service.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,21 +279,39 @@ async def get_conversation(
279279
280280
Args:
281281
conversation_id: Unique conversation identifier
282-
user_id: User ID for partition key
282+
user_id: User ID for partition key (may not match if conversation was created by different user)
283283
284284
Returns:
285285
Conversation data if found
286286
"""
287287
await self.initialize()
288288

289289
try:
290+
# First try direct read with provided user_id (fast path)
290291
item = await self._conversations_container.read_item(
291292
item=conversation_id,
292293
partition_key=user_id
293294
)
294295
return item
295296
except Exception:
296-
return None
297+
pass
298+
299+
# Fallback: cross-partition query to find conversation by ID
300+
# This handles cases where the conversation was created with a different user_id
301+
try:
302+
query = "SELECT * FROM c WHERE c.id = @id"
303+
params = [{"name": "@id", "value": conversation_id}]
304+
305+
async for item in self._conversations_container.query_items(
306+
query=query,
307+
parameters=params,
308+
max_item_count=1
309+
):
310+
return item
311+
except Exception:
312+
pass
313+
314+
return None
297315

298316
async def save_conversation(
299317
self,
@@ -499,14 +517,30 @@ async def delete_conversation(
499517
await self.initialize()
500518

501519
try:
520+
# First try to delete with provided user_id
502521
await self._conversations_container.delete_item(
503522
item=conversation_id,
504523
partition_key=user_id
505524
)
506525
return True
526+
except Exception:
527+
pass
528+
529+
# Fallback: find the conversation first to get the correct partition key
530+
try:
531+
conversation = await self.get_conversation(conversation_id, user_id)
532+
if conversation:
533+
actual_user_id = conversation.get("user_id", "")
534+
await self._conversations_container.delete_item(
535+
item=conversation_id,
536+
partition_key=actual_user_id
537+
)
538+
return True
507539
except Exception as e:
508540
logger.warning(f"Failed to delete conversation {conversation_id}: {e}")
509541
raise
542+
543+
return False
510544

511545

512546
# Singleton instance

0 commit comments

Comments
 (0)