Skip to content

Commit 847a4f9

Browse files
committed
Merge branch 'macae-v3-dev' into macae-v3-dev-mt-fr
2 parents 8abe10a + 92583ce commit 847a4f9

File tree

6 files changed

+67
-274
lines changed

6 files changed

+67
-274
lines changed

src/backend/app_kernel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ async def get_plans(
603603
request: Request,
604604
session_id: Optional[str] = Query(None),
605605
plan_id: Optional[str] = Query(None),
606+
team_id: Optional[str] = Query(None),
606607
):
607608
"""
608609
Retrieve plans for the current user.

src/backend/common/database/cosmosdb.py

Lines changed: 23 additions & 230 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ async def update_item(self, item: BaseDataModel) -> None:
129129
try:
130130
# Convert to dictionary and handle datetime serialization
131131
document = item.model_dump()
132-
document = json.loads(json.dumps(document, cls=DateTimeEncoder))
133-
132+
for key, value in list(document.items()):
133+
if isinstance(value, datetime.datetime):
134+
document[key] = value.isoformat()
134135
await self.container.upsert_item(body=document)
135136
except Exception as e:
136137
self.logger.error("Failed to update item in CosmosDB: %s", str(e))
@@ -164,7 +165,7 @@ async def query_items(
164165
items = self.container.query_items(query=query, parameters=parameters)
165166
result_list = []
166167
async for item in items:
167-
item["ts"] = item["_ts"]
168+
# item["ts"] = item["_ts"]
168169
try:
169170
result_list.append(model_class.model_validate(item))
170171
except Exception as validation_error:
@@ -352,91 +353,34 @@ async def delete_team(self, team_id: str) -> bool:
352353
try:
353354
# First find the team to get its document id and partition key
354355
team = await self.get_team(team_id)
356+
print(team)
355357
if team:
356-
# Use the session_id as partition key, or fall back to user_id if no session_id
357-
partition_key = (
358-
team.session_id
359-
if hasattr(team, "session_id") and team.session_id
360-
else team.user_id
361-
)
362-
await self.container.delete_item(
363-
item=team.id, partition_key=partition_key
364-
)
365-
return True
366-
return False
358+
await self.delete_item(item_id=team.id, partition_key=team.session_id)
359+
return True
367360
except Exception as e:
368361
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
369362
return False
370363

371-
async def delete_team_by_id(self, id: str) -> bool:
372-
"""Delete a team configuration by its document id.
373-
374-
Args:
375-
id: The document id of the team configuration to delete
376-
377-
Returns:
378-
True if team was found and deleted, False otherwise
379-
"""
364+
async def get_data_by_type_and_session_id(
365+
self, data_type: str, session_id: str
366+
) -> List[BaseDataModel]:
367+
"""Query the Cosmos DB for documents with the matching data_type, session_id and user_id."""
380368
await self._ensure_initialized()
369+
if self.container is None:
370+
return []
381371

372+
model_class = self.MODEL_CLASS_MAPPING.get(data_type, BaseDataModel)
382373
try:
383-
# First find the team to get its partition key
384-
team = await self.get_team_by_id(id)
385-
if team:
386-
# Debug logging
387-
logging.info(f"Attempting to delete team {id}")
388-
logging.info(f"Team user_id: {team.user_id}")
389-
logging.info(
390-
f"Team session_id: {getattr(team, 'session_id', 'NOT_SET')}"
391-
)
392-
393-
# Try different partition key strategies
394-
partition_keys_to_try = []
395-
396-
# Strategy 1: Use session_id if it exists
397-
if hasattr(team, "session_id") and team.session_id:
398-
partition_keys_to_try.append(team.session_id)
399-
logging.info(f"Will try session_id: {team.session_id}")
400-
401-
# Strategy 2: Use user_id as fallback
402-
if team.user_id:
403-
partition_keys_to_try.append(team.user_id)
404-
logging.info(f"Will try user_id: {team.user_id}")
405-
406-
# Strategy 3: Use current context session_id
407-
if self.session_id:
408-
partition_keys_to_try.append(self.session_id)
409-
logging.info(f"Will try context session_id: {self.session_id}")
410-
411-
# Strategy 4: Try null/empty partition key (for documents created without session_id)
412-
partition_keys_to_try.extend([None, ""])
413-
logging.info("Will try null and empty partition keys")
414-
415-
# Try each partition key until one works
416-
for partition_key in partition_keys_to_try:
417-
try:
418-
logging.info(
419-
f"Attempting delete with partition key: {partition_key}"
420-
)
421-
await self.container.delete_item(
422-
item=id, partition_key=partition_key
423-
)
424-
logging.info(
425-
f"Successfully deleted team {id} with partition key: {partition_key}"
426-
)
427-
return True
428-
except Exception as e:
429-
logging.warning(
430-
f"Delete failed with partition key {partition_key}: {str(e)}"
431-
)
432-
continue
433-
434-
logging.error(f"All partition key strategies failed for team {id}")
435-
return False
436-
return False
374+
query = "SELECT * FROM c WHERE c.session_id=@session_id AND c.user_id=@user_id AND c.data_type=@data_type ORDER BY c._ts ASC"
375+
parameters = [
376+
{"name": "@session_id", "value": session_id},
377+
{"name": "@data_type", "value": data_type},
378+
{"name": "@user_id", "value": self.user_id},
379+
]
380+
return await self.query_items(query, parameters, model_class)
437381
except Exception as e:
438-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
439-
return False
382+
logging.exception(f"Failed to query data by type from Cosmos DB: {e}")
383+
return []
440384

441385
# Data Management Operations
442386
async def get_data_by_type(self, data_type: str) -> List[BaseDataModel]:
@@ -487,154 +431,3 @@ async def update_team(self, team: TeamConfiguration) -> None:
487431
team: The TeamConfiguration to update
488432
"""
489433
await self.update_item(team)
490-
491-
async def get_team(self, team_id: str) -> Optional[TeamConfiguration]:
492-
"""Retrieve a specific team configuration by team_id.
493-
494-
Args:
495-
team_id: The team_id of the team configuration to retrieve
496-
497-
Returns:
498-
TeamConfiguration object or None if not found
499-
"""
500-
query = "SELECT * FROM c WHERE c.team_id=@team_id AND c.data_type=@data_type"
501-
parameters = [
502-
{"name": "@team_id", "value": team_id},
503-
{"name": "@data_type", "value": "team_config"},
504-
]
505-
teams = await self.query_items(query, parameters, TeamConfiguration)
506-
return teams[0] if teams else None
507-
508-
async def get_team_by_id(self, id: str) -> Optional[TeamConfiguration]:
509-
"""Retrieve a specific team configuration by its document id.
510-
511-
Args:
512-
id: The document id of the team configuration to retrieve
513-
514-
Returns:
515-
TeamConfiguration object or None if not found
516-
"""
517-
query = "SELECT * FROM c WHERE c.id=@id AND c.data_type=@data_type"
518-
parameters = [
519-
{"name": "@id", "value": id},
520-
{"name": "@data_type", "value": "team_config"},
521-
]
522-
teams = await self.query_items(query, parameters, TeamConfiguration)
523-
return teams[0] if teams else None
524-
525-
async def get_all_teams_by_user(self, user_id: str) -> List[TeamConfiguration]:
526-
"""Retrieve all team configurations for a specific user.
527-
528-
Args:
529-
user_id: The user_id to get team configurations for
530-
531-
Returns:
532-
List of TeamConfiguration objects
533-
"""
534-
query = "SELECT * FROM c WHERE c.user_id=@user_id AND c.data_type=@data_type ORDER BY c.created DESC"
535-
parameters = [
536-
{"name": "@user_id", "value": user_id},
537-
{"name": "@data_type", "value": "team_config"},
538-
]
539-
teams = await self.query_items(query, parameters, TeamConfiguration)
540-
return teams
541-
542-
async def delete_team(self, team_id: str) -> bool:
543-
"""Delete a team configuration by team_id.
544-
545-
Args:
546-
team_id: The team_id of the team configuration to delete
547-
548-
Returns:
549-
True if team was found and deleted, False otherwise
550-
"""
551-
await self.ensure_initialized()
552-
553-
try:
554-
# First find the team to get its document id and partition key
555-
team = await self.get_team(team_id)
556-
if team:
557-
# Use the session_id as partition key, or fall back to user_id if no session_id
558-
partition_key = (
559-
team.session_id
560-
if hasattr(team, "session_id") and team.session_id
561-
else team.user_id
562-
)
563-
await self._container.delete_item(
564-
item=team.id, partition_key=partition_key
565-
)
566-
return True
567-
return False
568-
except Exception as e:
569-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
570-
return False
571-
572-
async def delete_team_by_id(self, id: str) -> bool:
573-
"""Delete a team configuration by its document id.
574-
575-
Args:
576-
id: The document id of the team configuration to delete
577-
578-
Returns:
579-
True if team was found and deleted, False otherwise
580-
"""
581-
await self.ensure_initialized()
582-
583-
try:
584-
# First find the team to get its partition key
585-
team = await self.get_team_by_id(id)
586-
if team:
587-
# Debug logging
588-
logging.info(f"Attempting to delete team {id}")
589-
logging.info(f"Team user_id: {team.user_id}")
590-
logging.info(
591-
f"Team session_id: {getattr(team, 'session_id', 'NOT_SET')}"
592-
)
593-
594-
# Try different partition key strategies
595-
partition_keys_to_try = []
596-
597-
# Strategy 1: Use session_id if it exists
598-
if hasattr(team, "session_id") and team.session_id:
599-
partition_keys_to_try.append(team.session_id)
600-
logging.info(f"Will try session_id: {team.session_id}")
601-
602-
# Strategy 2: Use user_id as fallback
603-
if team.user_id:
604-
partition_keys_to_try.append(team.user_id)
605-
logging.info(f"Will try user_id: {team.user_id}")
606-
607-
# Strategy 3: Use current context session_id
608-
if self.session_id:
609-
partition_keys_to_try.append(self.session_id)
610-
logging.info(f"Will try context session_id: {self.session_id}")
611-
612-
# Strategy 4: Try null/empty partition key (for documents created without session_id)
613-
partition_keys_to_try.extend([None, ""])
614-
logging.info("Will try null and empty partition keys")
615-
616-
# Try each partition key until one works
617-
for partition_key in partition_keys_to_try:
618-
try:
619-
logging.info(
620-
f"Attempting delete with partition key: {partition_key}"
621-
)
622-
await self._container.delete_item(
623-
item=id, partition_key=partition_key
624-
)
625-
logging.info(
626-
f"Successfully deleted team {id} with partition key: {partition_key}"
627-
)
628-
return True
629-
except Exception as e:
630-
logging.warning(
631-
f"Delete failed with partition key {partition_key}: {str(e)}"
632-
)
633-
continue
634-
635-
logging.error(f"All partition key strategies failed for team {id}")
636-
return False
637-
return False
638-
except Exception as e:
639-
logging.exception(f"Failed to delete team from Cosmos DB: {e}")
640-
return False

src/backend/common/database/database_base.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ async def get_all_plans(self) -> List[Plan]:
105105
"""Retrieve all plans for the user."""
106106
pass
107107

108+
@abstractmethod
109+
async def get_data_by_type_and_session_id(
110+
self, data_type: str, session_id: str
111+
) -> List[BaseDataModel]:
112+
pass
113+
108114
# Step Operations
109115
@abstractmethod
110116
async def add_step(self, step: Step) -> None:
@@ -157,11 +163,6 @@ async def delete_team(self, team_id: str) -> bool:
157163
"""Delete a team configuration by team_id and return True if deleted."""
158164
pass
159165

160-
@abstractmethod
161-
async def delete_team_by_id(self, id: str) -> bool:
162-
"""Delete a team configuration by internal id and return True if deleted."""
163-
pass
164-
165166
# Data Management Operations
166167
@abstractmethod
167168
async def get_data_by_type(self, data_type: str) -> List[BaseDataModel]:

src/backend/common/models/messages_kernel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class TeamConfiguration(BaseDataModel):
178178

179179
team_id: str
180180
data_type: Literal["team_config"] = Field("team_config", Literal=True)
181+
session_id: str # Partition key
181182
name: str
182183
status: str
183184
created: str

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ async def validate_and_parse_team_config(
6767

6868
# Generate unique IDs and timestamps
6969
unique_team_id = str(uuid.uuid4())
70+
session_id = str(uuid.uuid4())
7071
current_timestamp = datetime.now(timezone.utc).isoformat()
7172

7273
# Validate agents array exists and is not empty
@@ -104,6 +105,7 @@ async def validate_and_parse_team_config(
104105
# Create team configuration
105106
team_config = TeamConfiguration(
106107
id=unique_team_id, # Use generated GUID
108+
session_id=session_id,
107109
team_id=unique_team_id, # Use generated GUID
108110
name=json_data["name"],
109111
status=json_data["status"],
@@ -253,17 +255,7 @@ async def delete_team_configuration(self, team_id: str, user_id: str) -> bool:
253255
"""
254256
try:
255257
# First, verify the configuration exists and belongs to the user
256-
team_config = await self.memory_context.get_team_by_id(team_id)
257-
258-
if team_config is None:
259-
self.logger.warning(
260-
"Team configuration not found for deletion: %s", team_id
261-
)
262-
return False
263-
264-
# Delete the configuration using the specific delete_team_by_id method
265-
success = await self.memory_context.delete_team_by_id(team_id)
266-
258+
success = await self.memory_context.delete_team(team_id)
267259
if success:
268260
self.logger.info("Successfully deleted team configuration: %s", team_id)
269261

0 commit comments

Comments
 (0)