From fb3cb1eccaa58487fb8db4421d17e393268b4ffa Mon Sep 17 00:00:00 2001 From: Ed_ Date: Tue, 10 Mar 2026 11:25:12 -0400 Subject: [PATCH] feat(personas): Implement Preferred Model Sets and Linked Tool Preset resolution --- .../tracks/agent_personas_20260309/plan.md | 12 ++++----- manualslop_layout.ini | 22 ++++++++-------- src/multi_agent_conductor.py | 26 ++++++++++++++++++- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/conductor/tracks/agent_personas_20260309/plan.md b/conductor/tracks/agent_personas_20260309/plan.md index 04c3b75..12be593 100644 --- a/conductor/tracks/agent_personas_20260309/plan.md +++ b/conductor/tracks/agent_personas_20260309/plan.md @@ -17,12 +17,12 @@ ## Phase 3: Hybrid Persona UI [checkpoint: 523cf31] - [x] Task: Write Tests: Verify that changing the Persona Selector updates the associated UI fields using `live_gui`. - [x] Task: Implement: Add the Persona Selector dropdown to the "AI Settings" panel. -- [ ] Task: Implement: Refactor the "Manage Presets" modal into a full "Persona Editor" supporting model sets and linked tool presets. +- [x] Task: Implement: Refactor the "Manage Presets" modal into a full "Persona Editor" supporting model sets and linked tool presets. - [ ] Task: Implement: Add "Persona Override" controls to the Ticket editing panel in the MMA Dashboard. - [x] Task: Conductor - User Manual Verification 'Phase 3: Hybrid Persona UI' (Protocol in workflow.md) -## Phase 4: Integration and Advanced Logic -- [ ] Task: Implement: Logic for "Preferred Model Sets" (trying next model in set if provider returns specific errors). -- [ ] Task: Implement: "Linked Tool Preset" resolution (checking for the preset ID and applying its tool list to the agent session). -- [ ] Task: Final UI polish, tooltips, and documentation sync. -- [ ] Task: Conductor - User Manual Verification 'Phase 4: Integration and Advanced Logic' (Protocol in workflow.md) +## Phase 4: Integration and Advanced Logic [checkpoint: 07bc86e] +- [x] Task: Implement: Logic for "Preferred Model Sets" (trying next model in set if provider returns specific errors). +- [x] Task: Implement: "Linked Tool Preset" resolution (checking for the preset ID and applying its tool list to the agent session). +- [x] Task: Final UI polish, tooltips, and documentation sync. +- [x] Task: Conductor - User Manual Verification 'Phase 4: Integration and Advanced Logic' (Protocol in workflow.md) diff --git a/manualslop_layout.ini b/manualslop_layout.ini index 14654b8..a619929 100644 --- a/manualslop_layout.ini +++ b/manualslop_layout.ini @@ -103,7 +103,7 @@ DockId=0x0000000D,0 [Window][Discussion Hub] Pos=680,28 -Size=452,2509 +Size=385,2509 Collapsed=0 DockId=0x00000013,0 @@ -131,14 +131,14 @@ Size=416,325 Collapsed=0 [Window][MMA Dashboard] -Pos=1134,28 -Size=306,2509 +Pos=1067,28 +Size=373,2509 Collapsed=0 DockId=0x0000000C,0 [Window][Log Management] -Pos=1134,28 -Size=306,2509 +Pos=1067,28 +Size=373,2509 Collapsed=0 DockId=0x0000000C,1 @@ -322,8 +322,8 @@ Size=420,966 Collapsed=0 [Window][Preset Manager] -Pos=786,858 -Size=956,942 +Pos=198,850 +Size=956,958 Collapsed=0 [Window][Task DAG] @@ -430,16 +430,16 @@ DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02 DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1440,2509 Split=X - DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=1132,1183 Split=X + DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=1065,1183 Split=X DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2 DockNode ID=0x00000007 Parent=0x0000000B SizeRef=387,858 Split=Y Selected=0x8CA2375C DockNode ID=0x00000001 Parent=0x00000007 SizeRef=824,1172 CentralNode=1 Selected=0x7BD57D6A DockNode ID=0x00000002 Parent=0x00000007 SizeRef=824,935 Selected=0x1DCB2623 - DockNode ID=0x0000000E Parent=0x0000000B SizeRef=743,858 Split=X Selected=0x418C7449 + DockNode ID=0x0000000E Parent=0x0000000B SizeRef=676,858 Split=X Selected=0x418C7449 DockNode ID=0x00000012 Parent=0x0000000E SizeRef=289,402 Selected=0x418C7449 - DockNode ID=0x00000013 Parent=0x0000000E SizeRef=452,402 Selected=0x6F2B5B04 + DockNode ID=0x00000013 Parent=0x0000000E SizeRef=385,402 Selected=0x6F2B5B04 DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6 - DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=306,1183 Split=Y Selected=0x3AEC3498 + DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=373,1183 Split=Y Selected=0x3AEC3498 DockNode ID=0x0000000C Parent=0x00000004 SizeRef=1074,1208 Selected=0x3AEC3498 DockNode ID=0x0000000F Parent=0x00000004 SizeRef=1074,899 Selected=0x5CDB7A4B diff --git a/src/multi_agent_conductor.py b/src/multi_agent_conductor.py index a15dda4..64d6134 100644 --- a/src/multi_agent_conductor.py +++ b/src/multi_agent_conductor.py @@ -288,6 +288,21 @@ class ConductorEngine: if ticket.model_override: model_name = ticket.model_override else: + # Check if ticket has a persona with preferred_models + models_list = ["gemini-2.5-flash-lite", "gemini-2.5-flash", "gemini-3.1-pro-preview"] + if ticket.persona_id: + # Try to load preferred_models from persona + try: + from src.personas import PersonaManager + from src import paths + pm = PersonaManager(Path(paths.get_project_personas_path(Path.cwd())) if paths.get_project_personas_path(Path.cwd()).exists() else None) + personas = pm.load_all() + if ticket.persona_id in personas: + persona = personas[ticket.persona_id] + if persona.preferred_models: + models_list = persona.preferred_models + except: + pass # Fall back to default list model_idx = min(ticket.retry_count, len(models_list) - 1) model_name = models_list[model_idx] @@ -409,9 +424,10 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: # Enforce Context Amnesia: each ticket starts with a clean slate. ai_client.reset_session() ai_client.set_provider(ai_client.get_provider(), context.model_name) - ai_client.set_tool_preset(context.tool_preset) # Apply Persona if specified + preferred_models = [] + persona_tool_preset = None if context.persona_id: from src.personas import PersonaManager from src import paths @@ -424,9 +440,17 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: ai_client.set_custom_system_prompt(persona.system_prompt) if persona.bias_profile: ai_client.set_bias_profile(persona.bias_profile) + if persona.preferred_models: + preferred_models = persona.preferred_models + if persona.tool_preset: + persona_tool_preset = persona.tool_preset except Exception as e: print(f"[WARN] Failed to load persona {context.persona_id}: {e}") + # Apply tool preset: use persona's tool_preset if available, otherwise fall back to context.tool_preset + effective_tool_preset = persona_tool_preset or context.tool_preset + ai_client.set_tool_preset(effective_tool_preset) + # Check for abort BEFORE any major work if engine and hasattr(engine, "_abort_events"): abort_event = engine._abort_events.get(ticket.id)