feat(mma): Complete Phase 7 implementation: MMA Dashboard, HITL Step Modal, and Memory Mutator

This commit is contained in:
2026-02-26 21:48:41 -05:00
parent 63a82e0d15
commit 332fc4d774
5 changed files with 105 additions and 26 deletions

View File

@@ -102,17 +102,50 @@ class ConductorEngine:
model_name="gemini-2.5-flash-lite",
messages=[]
)
run_worker_lifecycle(ticket, context)
run_worker_lifecycle(ticket, context, event_queue=self.event_queue)
await self._push_state(active_tier="Tier 2 (Tech Lead)")
def confirm_execution(payload: str) -> bool:
def confirm_execution(payload: str, event_queue: events.AsyncEventQueue, ticket_id: str) -> bool:
"""
Placeholder for external confirmation function.
In a real scenario, this might trigger a UI prompt.
Pushes an approval request to the GUI and waits for response.
"""
return True
import threading
import time
import asyncio
# We use a list container so the GUI can inject the actual Dialog object back to us
# since the dialog is created in the GUI thread.
dialog_container = [None]
task = {
"action": "mma_step_approval",
"ticket_id": ticket_id,
"payload": payload,
"dialog_container": dialog_container
}
# Push to queue
try:
loop = asyncio.get_event_loop()
if loop.is_running():
asyncio.run_coroutine_threadsafe(event_queue.put("mma_step_approval", task), loop)
else:
event_queue._queue.put_nowait(("mma_step_approval", task))
except Exception:
# Fallback if no loop
event_queue._queue.put_nowait(("mma_step_approval", task))
def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: List[str] = None):
# Wait for the GUI to create the dialog and for the user to respond
start = time.time()
while dialog_container[0] is None and time.time() - start < 60:
time.sleep(0.1)
if dialog_container[0]:
approved, final_payload = dialog_container[0].wait()
return approved
return False
def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: List[str] = None, event_queue: events.AsyncEventQueue = None):
"""
Simulates the lifecycle of a single agent working on a ticket.
Calls the AI client and updates the ticket status based on the response.
@@ -150,11 +183,17 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files:
# In a real scenario, we would pass md_content from the aggregator
# and manage the conversation history in the context.
# HITL Clutch: pass the queue and ticket_id to confirm_execution
def clutch_callback(payload: str) -> bool:
if not event_queue:
return True
return confirm_execution(payload, event_queue, ticket.id)
response = ai_client.send(
md_content="",
user_message=user_message,
base_dir=".",
pre_tool_callback=confirm_execution if ticket.step_mode else None,
pre_tool_callback=clutch_callback if ticket.step_mode else None,
qa_callback=ai_client.run_tier4_analysis
)