Skip to content

Commit 679a935

Browse files
authored
Fix AGS Cascading Delete Issue (microsoft#5804)
<!-- Thank you for your contribution! Please review https://microsoft.github.io/autogen/docs/Contribute before opening a pull request. --> <!-- Please add a reviewer to the assignee section when you create a PR. If you don't have the access to it, we will shortly find a reviewer and assign them to your PR. --> ## Why are these changes needed? > Hey Victor, this is maybe a bug, but when a session is delete, runs and messages for that session are not deleted, any reason why to keep them? @husseinmozannar The main fix is to add a pragma that ensures SQL lite enforces foreign key constraints. Also needed to update error messages for autoupgrade of databases. Also adds a test for cascade deletes and for parts of teammanager With this fix, - Messages get deleted when the run is deleted - Runs get deleted when sessiosn are deleted - Sessions get deleted when a team is deleted <!-- Please give a short summary of the change and the problem this solves. --> ## Related issue number <!-- For example: "Closes microsoft#1234" --> ## Checks - [ ] I've included any doc changes needed for <https://microsoft.github.io/autogen/>. See <https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to build and test documentation locally. - [ ] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [ ] I've made sure all auto checks have passed.
1 parent 8c9961e commit 679a935

File tree

7 files changed

+520
-198
lines changed

7 files changed

+520
-198
lines changed

python/packages/autogen-studio/autogenstudio/database/db_manager.py

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ def initialize_database(self, auto_upgrade: bool = False, force_init_alembic: bo
5151
return Response(message="Database initialization already in progress", status=False)
5252

5353
try:
54+
# Enable foreign key constraints for SQLite
55+
if "sqlite" in str(self.engine.url):
56+
with self.engine.connect() as conn:
57+
conn.execute(text("PRAGMA foreign_keys=ON"))
5458
inspector = inspect(self.engine)
5559
tables_exist = inspector.get_table_names()
5660
if not tables_exist:
@@ -221,6 +225,8 @@ def delete(self, model_class: SQLModel, filters: dict = None) -> Response:
221225

222226
with Session(self.engine) as session:
223227
try:
228+
if "sqlite" in str(self.engine.url):
229+
session.exec(text("PRAGMA foreign_keys=ON"))
224230
statement = select(model_class)
225231
if filters:
226232
conditions = [getattr(model_class, col) == value for col, value in filters.items()]

python/packages/autogen-studio/autogenstudio/database/schema_manager.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,10 @@ def check_and_upgrade(self) -> Tuple[bool, str]:
466466
if self.upgrade_schema():
467467
return True, "Schema was automatically upgraded"
468468
else:
469-
return False, "Automatic schema upgrade failed"
469+
return (
470+
False,
471+
"Automatic schema upgrade failed. You are seeing this message because there were differences in your current database schema and the most recent version of the Autogen Studio app database. You can ignore the error, or specifically, you can install AutoGen Studio in a new path `autogenstudio ui --appdir <new path>`.",
472+
)
470473

471474
return False, status
472475

python/packages/autogen-studio/autogenstudio/datamodel/db.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
from autogen_core import ComponentModel
99
from pydantic import ConfigDict
10-
from sqlalchemy import ForeignKey, Integer
10+
from sqlalchemy import UUID as SQLAlchemyUUID
11+
from sqlalchemy import ForeignKey, Integer, String
1112
from sqlmodel import JSON, Column, DateTime, Field, SQLModel, func
1213

1314
from .types import GalleryConfig, MessageConfig, MessageMeta, SettingsConfig, TeamResult
@@ -46,7 +47,9 @@ class Message(SQLModel, table=True):
4647
session_id: Optional[int] = Field(
4748
default=None, sa_column=Column(Integer, ForeignKey("session.id", ondelete="CASCADE"))
4849
)
49-
run_id: Optional[UUID] = Field(default=None, foreign_key="run.id")
50+
run_id: Optional[UUID] = Field(
51+
default=None, sa_column=Column(SQLAlchemyUUID, ForeignKey("run.id", ondelete="CASCADE"))
52+
)
5053

5154
message_meta: Optional[Union[MessageMeta, dict]] = Field(default={}, sa_column=Column(JSON))
5255

@@ -81,7 +84,7 @@ class Run(SQLModel, table=True):
8184

8285
__table_args__ = {"sqlite_autoincrement": True}
8386

84-
id: UUID = Field(default_factory=uuid4, primary_key=True, index=True)
87+
id: UUID = Field(default_factory=uuid4, sa_column=Column(SQLAlchemyUUID, primary_key=True, index=True, unique=True))
8588
created_at: datetime = Field(
8689
default_factory=datetime.now, sa_column=Column(DateTime(timezone=True), server_default=func.now())
8790
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
{
2+
"provider": "autogen_agentchat.teams.RoundRobinGroupChat",
3+
"component_type": "team",
4+
"version": 1,
5+
"component_version": 1,
6+
"description": "A team that runs a group chat with participants taking turns in a round-robin fashion\n to publish a message to all.",
7+
"label": "RoundRobinGroupChat",
8+
"config": {
9+
"participants": [
10+
{
11+
"provider": "autogen_agentchat.agents.AssistantAgent",
12+
"component_type": "agent",
13+
"version": 1,
14+
"component_version": 1,
15+
"description": "An agent that provides assistance with tool use.",
16+
"label": "AssistantAgent",
17+
"config": {
18+
"name": "planner_agent",
19+
"model_client": {
20+
"provider": "autogen_ext.models.openai.OpenAIChatCompletionClient",
21+
"component_type": "model",
22+
"version": 1,
23+
"component_version": 1,
24+
"description": "Chat completion client for OpenAI hosted models.",
25+
"label": "OpenAIChatCompletionClient",
26+
"config": {
27+
"model": "gpt-4"
28+
}
29+
},
30+
"tools": [],
31+
"handoffs": [],
32+
"model_context": {
33+
"provider": "autogen_core.model_context.UnboundedChatCompletionContext",
34+
"component_type": "chat_completion_context",
35+
"version": 1,
36+
"component_version": 1,
37+
"description": "An unbounded chat completion context that keeps a view of the all the messages.",
38+
"label": "UnboundedChatCompletionContext",
39+
"config": {}
40+
},
41+
"description": "A helpful assistant that can plan trips.",
42+
"system_message": "You are a helpful assistant that can suggest a travel plan for a user based on their request. Respond with a single sentence",
43+
"model_client_stream": false,
44+
"reflect_on_tool_use": false,
45+
"tool_call_summary_format": "{result}"
46+
}
47+
},
48+
{
49+
"provider": "autogen_agentchat.agents.AssistantAgent",
50+
"component_type": "agent",
51+
"version": 1,
52+
"component_version": 1,
53+
"description": "An agent that provides assistance with tool use.",
54+
"label": "AssistantAgent",
55+
"config": {
56+
"name": "local_agent",
57+
"model_client": {
58+
"provider": "autogen_ext.models.openai.OpenAIChatCompletionClient",
59+
"component_type": "model",
60+
"version": 1,
61+
"component_version": 1,
62+
"description": "Chat completion client for OpenAI hosted models.",
63+
"label": "OpenAIChatCompletionClient",
64+
"config": {
65+
"model": "gpt-4"
66+
}
67+
},
68+
"tools": [],
69+
"handoffs": [],
70+
"model_context": {
71+
"provider": "autogen_core.model_context.UnboundedChatCompletionContext",
72+
"component_type": "chat_completion_context",
73+
"version": 1,
74+
"component_version": 1,
75+
"description": "An unbounded chat completion context that keeps a view of the all the messages.",
76+
"label": "UnboundedChatCompletionContext",
77+
"config": {}
78+
},
79+
"description": "A local assistant that can suggest local activities or places to visit.",
80+
"system_message": "You are a helpful assistant that can suggest authentic and interesting local activities or places to visit for a user and can utilize any context information provided. Respond with a single sentence",
81+
"model_client_stream": false,
82+
"reflect_on_tool_use": false,
83+
"tool_call_summary_format": "{result}"
84+
}
85+
},
86+
{
87+
"provider": "autogen_agentchat.agents.AssistantAgent",
88+
"component_type": "agent",
89+
"version": 1,
90+
"component_version": 1,
91+
"description": "An agent that provides assistance with tool use.",
92+
"label": "AssistantAgent",
93+
"config": {
94+
"name": "language_agent",
95+
"model_client": {
96+
"provider": "autogen_ext.models.openai.OpenAIChatCompletionClient",
97+
"component_type": "model",
98+
"version": 1,
99+
"component_version": 1,
100+
"description": "Chat completion client for OpenAI hosted models.",
101+
"label": "OpenAIChatCompletionClient",
102+
"config": {
103+
"model": "gpt-4"
104+
}
105+
},
106+
"tools": [],
107+
"handoffs": [],
108+
"model_context": {
109+
"provider": "autogen_core.model_context.UnboundedChatCompletionContext",
110+
"component_type": "chat_completion_context",
111+
"version": 1,
112+
"component_version": 1,
113+
"description": "An unbounded chat completion context that keeps a view of the all the messages.",
114+
"label": "UnboundedChatCompletionContext",
115+
"config": {}
116+
},
117+
"description": "A helpful assistant that can provide language tips for a given destination.",
118+
"system_message": "You are a helpful assistant that can review travel plans, providing feedback on important/critical tips about how best to address language or communication challenges for the given destination. If the plan already includes language tips, you can mention that the plan is satisfactory, with rationale.Respond with a single sentence",
119+
"model_client_stream": false,
120+
"reflect_on_tool_use": false,
121+
"tool_call_summary_format": "{result}"
122+
}
123+
},
124+
{
125+
"provider": "autogen_agentchat.agents.AssistantAgent",
126+
"component_type": "agent",
127+
"version": 1,
128+
"component_version": 1,
129+
"description": "An agent that provides assistance with tool use.",
130+
"label": "AssistantAgent",
131+
"config": {
132+
"name": "travel_summary_agent",
133+
"model_client": {
134+
"provider": "autogen_ext.models.openai.OpenAIChatCompletionClient",
135+
"component_type": "model",
136+
"version": 1,
137+
"component_version": 1,
138+
"description": "Chat completion client for OpenAI hosted models.",
139+
"label": "OpenAIChatCompletionClient",
140+
"config": {
141+
"model": "gpt-4"
142+
}
143+
},
144+
"tools": [],
145+
"handoffs": [],
146+
"model_context": {
147+
"provider": "autogen_core.model_context.UnboundedChatCompletionContext",
148+
"component_type": "chat_completion_context",
149+
"version": 1,
150+
"component_version": 1,
151+
"description": "An unbounded chat completion context that keeps a view of the all the messages.",
152+
"label": "UnboundedChatCompletionContext",
153+
"config": {}
154+
},
155+
"description": "A helpful assistant that can summarize the travel plan.",
156+
"system_message": "You are a helpful assistant that can take in all of the suggestions and advice from the other agents and provide a detailed tfinal travel plan. You must ensure th b at the final plan is integrated and complete. YOUR FINAL RESPONSE MUST BE THE COMPLETE PLAN. When the plan is complete and all perspectives are integrated, you can respond with TERMINATE.Respond with a single sentence",
157+
"model_client_stream": false,
158+
"reflect_on_tool_use": false,
159+
"tool_call_summary_format": "{result}"
160+
}
161+
}
162+
],
163+
"termination_condition": {
164+
"provider": "autogen_agentchat.base.OrTerminationCondition",
165+
"component_type": "termination",
166+
"version": 1,
167+
"component_version": 1,
168+
"label": "OrTerminationCondition",
169+
"config": {
170+
"conditions": [
171+
{
172+
"provider": "autogen_agentchat.conditions.TextMentionTermination",
173+
"component_type": "termination",
174+
"version": 1,
175+
"component_version": 1,
176+
"description": "Terminate the conversation if a specific text is mentioned.",
177+
"label": "TextMentionTermination",
178+
"config": {
179+
"text": "TERMINATE"
180+
}
181+
},
182+
{
183+
"provider": "autogen_agentchat.conditions.MaxMessageTermination",
184+
"component_type": "termination",
185+
"version": 1,
186+
"component_version": 1,
187+
"description": "Terminate the conversation after a maximum number of messages have been exchanged.",
188+
"label": "MaxMessageTermination",
189+
"config": {
190+
"max_messages": 10,
191+
"include_agent_event": false
192+
}
193+
}
194+
]
195+
}
196+
}
197+
}
198+
}

0 commit comments

Comments
 (0)