11import os
22import json
33import logging
4+ from collections import defaultdict
45from DB import (
56 get_session ,
67 Provider ,
1617 Agent ,
1718 AgentCommand ,
1819 Chain ,
20+ ChainStep ,
1921)
2022from Providers import get_providers , get_provider_options
2123from Agent import add_agent
2729)
2830
2931
32+ def _merge_command_duplicates (session , target_command , duplicates ):
33+ """Merge duplicate command rows into a target command instance."""
34+
35+ if not duplicates :
36+ return
37+
38+ for duplicate in duplicates :
39+ if duplicate .id == target_command .id :
40+ continue
41+
42+ # Move agent command associations
43+ agent_commands = (
44+ session .query (AgentCommand )
45+ .filter (AgentCommand .command_id == duplicate .id )
46+ .all ()
47+ )
48+ for agent_command in agent_commands :
49+ existing_ref = (
50+ session .query (AgentCommand )
51+ .filter (
52+ AgentCommand .agent_id == agent_command .agent_id ,
53+ AgentCommand .command_id == target_command .id ,
54+ )
55+ .first ()
56+ )
57+
58+ if existing_ref :
59+ if agent_command .state :
60+ existing_ref .state = True
61+ session .delete (agent_command )
62+ else :
63+ agent_command .command_id = target_command .id
64+
65+ # Move arguments linked to the duplicate command
66+ arguments = (
67+ session .query (Argument ).filter (Argument .command_id == duplicate .id ).all ()
68+ )
69+ for argument in arguments :
70+ existing_arg = (
71+ session .query (Argument )
72+ .filter_by (command_id = target_command .id , name = argument .name )
73+ .first ()
74+ )
75+ if existing_arg :
76+ session .delete (argument )
77+ else :
78+ argument .command_id = target_command .id
79+
80+ # Update chain steps that target the duplicate command
81+ session .query (ChainStep ).filter (
82+ ChainStep .target_command_id == duplicate .id
83+ ).update (
84+ {ChainStep .target_command_id : target_command .id },
85+ synchronize_session = False ,
86+ )
87+
88+ session .delete (duplicate )
89+
90+
3091def get_extension_category (session , extension_name ):
3192 """Get or create extension category based on extension class CATEGORY attribute"""
3293 from ExtensionsHub import (
@@ -134,6 +195,7 @@ def import_extensions():
134195
135196 ext = Extensions ()
136197 extensions_data = ext .get_extensions ()
198+ command_owner_map = defaultdict (set )
137199 # Delete "AGiXT Chains"
138200 if "AGiXT Chains" in extensions_data :
139201 del extensions_data ["AGiXT Chains" ]
@@ -142,6 +204,14 @@ def import_extensions():
142204 # del extensions_data["Custom Automation"]
143205 extension_settings_data = Extensions ().get_extension_settings ()
144206
207+ for extension_data in extensions_data :
208+ extension_name = extension_data ["extension_name" ]
209+ for command in extension_data .get ("commands" , []):
210+ friendly_name = command .get ("friendly_name" , "" ).strip ()
211+ if not friendly_name :
212+ continue
213+ command_owner_map [friendly_name .lower ()].add (extension_name )
214+
145215 # Create extension database tables during seed import
146216 create_extension_tables ()
147217
@@ -306,86 +376,60 @@ def import_extensions():
306376 # Process commands for this extension
307377 if "commands" in extension_data :
308378 for command_data in extension_data ["commands" ]:
309- if "friendly_name" not in command_data :
379+ command_name = command_data .get ("friendly_name" )
380+ if not command_name :
310381 continue
311382
312- command_name = command_data [ "friendly_name" ]
313- command_description = command_data .get ("description" , "" )
383+ command_key = command_name . strip (). lower ()
384+ shared_command = len ( command_owner_map .get (command_key , set ())) > 1
314385
315- # Check if this command exists in a different extension (moved command)
316- existing_in_other_extension = (
386+ commands_with_name = (
317387 session .query (Command )
318388 .join (Extension )
319- .filter (Command .name == command_name , Extension . id != extension . id )
320- .first ()
389+ .filter (Command .name == command_name )
390+ .all ()
321391 )
322392
323- if existing_in_other_extension :
393+ command = None
394+ duplicates_to_merge = []
324395
325- # Find or create command in current extension
326- command = (
327- session .query (Command )
328- .filter_by (extension_id = extension .id , name = command_name )
329- .first ()
330- )
331-
332- if not command :
333- command = Command (
334- extension_id = extension .id ,
335- name = command_name ,
336- )
337- session .add (command )
338- session .flush ()
339-
340- # Update all agent command references from old to new
341- agent_commands = (
342- session .query (AgentCommand )
343- .filter (
344- AgentCommand .command_id == existing_in_other_extension .id
396+ for db_command in commands_with_name :
397+ if db_command .extension_id == extension .id :
398+ if command is None :
399+ command = db_command
400+ else :
401+ duplicates_to_merge .append (db_command )
402+ elif not shared_command :
403+ duplicates_to_merge .append (db_command )
404+
405+ if command is None :
406+ if duplicates_to_merge :
407+ command = duplicates_to_merge .pop (0 )
408+ old_extension_name = (
409+ command .extension .name if command .extension else "Unknown"
345410 )
346- .all ()
347- )
348-
349- for agent_command in agent_commands :
350- # Check if agent already has a reference to the new command
351- existing_ref = (
352- session .query (AgentCommand )
353- .filter (
354- AgentCommand .agent_id == agent_command .agent_id ,
355- AgentCommand .command_id == command .id ,
411+ if old_extension_name .lower () != extension_name .lower ():
412+ logging .info (
413+ "Moving command '%s' from extension '%s' to '%s'" ,
414+ command_name ,
415+ old_extension_name ,
416+ extension_name ,
356417 )
357- .first ()
358- )
359-
360- if existing_ref :
361- # Merge - keep enabled if either was enabled
362- if agent_command .state :
363- existing_ref .state = True
364- session .delete (agent_command )
365- else :
366- # Update to point to new command
367- agent_command .command_id = command .id
368-
369- else :
370- # Normal case - find or create command in this extension
371- command = (
372- session .query (Command )
373- .filter_by (extension_id = extension .id , name = command_name )
374- .first ()
375- )
376-
377- if not command :
418+ command .extension_id = extension .id
419+ command .extension = extension
420+ else :
378421 command = Command (
379422 extension_id = extension .id ,
380423 name = command_name ,
381424 )
382425 session .add (command )
383426 session .flush ()
384427
428+ _merge_command_duplicates (session , command , duplicates_to_merge )
429+
385430 # Process command arguments if they exist
386431 if "command_args" in command_data :
387432 for arg_name , arg_type in command_data ["command_args" ].items ():
388- # Check if argument already exists
389433 existing_arg = (
390434 session .query (Argument )
391435 .filter_by (command_id = command .id , name = arg_name )
0 commit comments