WIP: PAIN3

This commit is contained in:
2026-03-05 15:10:53 -05:00
parent fca57841c6
commit 8784d05db4
12 changed files with 72 additions and 52 deletions

View File

@@ -8,5 +8,5 @@ active = "main"
[discussions.main] [discussions.main]
git_commit = "" git_commit = ""
last_updated = "2026-03-05T14:39:44" last_updated = "2026-03-05T14:42:31"
history = [] history = []

View File

@@ -290,7 +290,11 @@ def reset_session() -> None:
_gemini_cache = None _gemini_cache = None
_gemini_cache_md_hash = None _gemini_cache_md_hash = None
_gemini_cache_created_at = None _gemini_cache_created_at = None
_gemini_cli_adapter = None
# Preserve binary_path if adapter exists
old_path = _gemini_cli_adapter.binary_path if _gemini_cli_adapter else "gemini"
_gemini_cli_adapter = GeminiCliAdapter(binary_path=old_path)
_anthropic_client = None _anthropic_client = None
with _anthropic_history_lock: with _anthropic_history_lock:

View File

@@ -137,8 +137,8 @@ class ApiHookClient:
return {"performance": diag} return {"performance": diag}
def get_mma_status(self) -> dict[str, Any]: def get_mma_status(self) -> dict[str, Any]:
"""Convenience to get the current MMA engine status. Returns FULL state.""" """Retrieves the dedicated MMA engine status."""
return self.get_gui_state() return self._make_request('GET', '/api/gui/mma_status') or {}
def get_node_status(self, node_id: str) -> dict[str, Any]: def get_node_status(self, node_id: str) -> dict[str, Any]:
"""Retrieves status for a specific node in the MMA DAG.""" """Retrieves status for a specific node in the MMA DAG."""

View File

@@ -298,6 +298,7 @@ class AppController:
'show_confirm_modal': 'show_confirm_modal', 'show_confirm_modal': 'show_confirm_modal',
'mma_epic_input': 'ui_epic_input', 'mma_epic_input': 'ui_epic_input',
'mma_status': 'mma_status', 'mma_status': 'mma_status',
'ai_status': 'ai_status',
'mma_active_tier': 'active_tier', 'mma_active_tier': 'active_tier',
'ui_new_track_name': 'ui_new_track_name', 'ui_new_track_name': 'ui_new_track_name',
'ui_new_track_desc': 'ui_new_track_desc', 'ui_new_track_desc': 'ui_new_track_desc',
@@ -409,10 +410,10 @@ class AppController:
"collapsed": False, "collapsed": False,
"ts": project_manager.now_ts() "ts": project_manager.now_ts()
}) })
elif action == "mma_stream_append": elif action in ("mma_stream", "mma_stream_append"):
payload = task.get("payload", {}) # Some events might have these at top level, some in a 'payload' dict
stream_id = payload.get("stream_id") stream_id = task.get("stream_id") or task.get("payload", {}).get("stream_id")
text = payload.get("text", "") text = task.get("text") or task.get("payload", {}).get("text", "")
if stream_id: if stream_id:
if stream_id not in self.mma_streams: if stream_id not in self.mma_streams:
self.mma_streams[stream_id] = "" self.mma_streams[stream_id] = ""
@@ -421,7 +422,11 @@ class AppController:
self.proposed_tracks = task.get("payload", []) self.proposed_tracks = task.get("payload", [])
self._show_track_proposal_modal = True self._show_track_proposal_modal = True
elif action == "mma_state_update": elif action == "mma_state_update":
payload = task.get("payload", {}) # Handle both internal (nested) and hook-server (flattened) payloads
payload = task.get("payload")
if not isinstance(payload, dict):
payload = task # Fallback to task if payload missing or wrong type
self.mma_status = payload.get("status", "idle") self.mma_status = payload.get("status", "idle")
self.active_tier = payload.get("active_tier") self.active_tier = payload.get("active_tier")
self.mma_tier_usage = payload.get("tier_usage", self.mma_tier_usage) self.mma_tier_usage = payload.get("tier_usage", self.mma_tier_usage)
@@ -783,12 +788,11 @@ class AppController:
break break
if event_name == "user_request": if event_name == "user_request":
threading.Thread(target=self._handle_request_event, args=(payload,), daemon=True).start() threading.Thread(target=self._handle_request_event, args=(payload,), daemon=True).start()
elif event_name == "response": elif event_name == "gui_task":
with self._pending_gui_tasks_lock: with self._pending_gui_tasks_lock:
self._pending_gui_tasks.append({ # Directly append the task from the hook server.
"action": "handle_ai_response", # It already contains 'action' and any necessary fields.
"payload": payload self._pending_gui_tasks.append(payload)
})
elif event_name == "mma_state_update": elif event_name == "mma_state_update":
with self._pending_gui_tasks_lock: with self._pending_gui_tasks_lock:
self._pending_gui_tasks.append({ self._pending_gui_tasks.append({
@@ -803,6 +807,7 @@ class AppController:
}) })
elif event_name in ("mma_spawn_approval", "mma_step_approval"): elif event_name in ("mma_spawn_approval", "mma_step_approval"):
with self._pending_gui_tasks_lock: with self._pending_gui_tasks_lock:
# These payloads already contain the 'action' field
self._pending_gui_tasks.append(payload) self._pending_gui_tasks.append(payload)
def _handle_request_event(self, event: events.UserRequestEvent) -> None: def _handle_request_event(self, event: events.UserRequestEvent) -> None:
@@ -1679,13 +1684,17 @@ class AppController:
def _cb_accept_tracks(self) -> None: def _cb_accept_tracks(self) -> None:
self._show_track_proposal_modal = False self._show_track_proposal_modal = False
def _bg_task() -> None: def _bg_task() -> None:
sys.stderr.write("[DEBUG] _cb_accept_tracks _bg_task started\n")
# Generate skeletons once # Generate skeletons once
self._set_status("Phase 2: Generating skeletons for all tracks...") self._set_status("Phase 2: Generating skeletons for all tracks...")
parser = file_cache.ASTParser(language="python") sys.stderr.write("[DEBUG] Creating ASTParser...\n")
parser = ASTParser(language="python")
generated_skeletons = "" generated_skeletons = ""
try: try:
# Use a local copy of files to avoid concurrent modification issues # Use a local copy of files to avoid concurrent modification issues
files_to_scan = list(self.files) files_to_scan = list(self.files)
sys.stderr.write(f"[DEBUG] Scanning {len(files_to_scan)} files for skeletons...\n")
for i, file_path in enumerate(files_to_scan): for i, file_path in enumerate(files_to_scan):
try: try:
self._set_status(f"Phase 2: Scanning files ({i+1}/{len(files_to_scan)})...") self._set_status(f"Phase 2: Scanning files ({i+1}/{len(files_to_scan)})...")
@@ -1695,12 +1704,13 @@ class AppController:
code = f.read() code = f.read()
generated_skeletons += f"\nFile: {file_path}\n{parser.get_skeleton(code)}\n" generated_skeletons += f"\nFile: {file_path}\n{parser.get_skeleton(code)}\n"
except Exception as e: except Exception as e:
print(f"Error parsing skeleton for {file_path}: {e}") sys.stderr.write(f"[DEBUG] Error parsing skeleton for {file_path}: {e}\n")
except Exception as e: except Exception as e:
sys.stderr.write(f"[DEBUG] Error in scan loop: {e}\n")
self._set_status(f"Error generating skeletons: {e}") self._set_status(f"Error generating skeletons: {e}")
print(f"Error generating skeletons: {e}")
return # Exit if skeleton generation fails return # Exit if skeleton generation fails
sys.stderr.write("[DEBUG] Skeleton generation complete. Starting tracks...\n")
# Now loop through tracks and call _start_track_logic with generated skeletons # Now loop through tracks and call _start_track_logic with generated skeletons
total_tracks = len(self.proposed_tracks) total_tracks = len(self.proposed_tracks)
for i, track_data in enumerate(self.proposed_tracks): for i, track_data in enumerate(self.proposed_tracks):
@@ -1708,6 +1718,7 @@ class AppController:
self._set_status(f"Processing track {i+1} of {total_tracks}: '{title}'...") self._set_status(f"Processing track {i+1} of {total_tracks}: '{title}'...")
self._start_track_logic(track_data, skeletons_str=generated_skeletons) # Pass skeletons self._start_track_logic(track_data, skeletons_str=generated_skeletons) # Pass skeletons
sys.stderr.write("[DEBUG] All tracks started. Refreshing...\n")
with self._pending_gui_tasks_lock: with self._pending_gui_tasks_lock:
self._pending_gui_tasks.append({'action': 'refresh_from_project'}) # Ensure UI refresh after tracks are started self._pending_gui_tasks.append({'action': 'refresh_from_project'}) # Ensure UI refresh after tracks are started
self._set_status(f"All {total_tracks} tracks accepted and execution started.") self._set_status(f"All {total_tracks} tracks accepted and execution started.")
@@ -1797,6 +1808,12 @@ class AppController:
meta = models.Metadata(id=track_id, name=title, status="todo", created_at=datetime.now(), updated_at=datetime.now()) meta = models.Metadata(id=track_id, name=title, status="todo", created_at=datetime.now(), updated_at=datetime.now())
state = models.TrackState(metadata=meta, discussion=[], tasks=tickets) state = models.TrackState(metadata=meta, discussion=[], tasks=tickets)
project_manager.save_track_state(track_id, state, self.ui_files_base_dir) project_manager.save_track_state(track_id, state, self.ui_files_base_dir)
# Add to memory and notify UI
self.tracks.append({"id": track_id, "title": title, "status": "todo"})
with self._pending_gui_tasks_lock:
self._pending_gui_tasks.append({'action': 'refresh_from_project'})
# 4. Initialize ConductorEngine and run loop # 4. Initialize ConductorEngine and run loop
engine = multi_agent_conductor.ConductorEngine(track, self.event_queue, auto_queue=not self.mma_step_mode) engine = multi_agent_conductor.ConductorEngine(track, self.event_queue, auto_queue=not self.mma_step_mode)
# Use current full markdown context for the track execution # Use current full markdown context for the track execution

View File

@@ -14,7 +14,7 @@ import json
from typing import Any, Optional, TYPE_CHECKING, Union from typing import Any, Optional, TYPE_CHECKING, Union
from pathlib import Path from pathlib import Path
if TYPE_CHECKING: if TYPE_CHECKING:
from models import TrackState from src.models import TrackState
TS_FMT: str = "%Y-%m-%dT%H:%M:%S" TS_FMT: str = "%Y-%m-%dT%H:%M:%S"
def now_ts() -> str: def now_ts() -> str:
@@ -248,7 +248,7 @@ def load_track_state(track_id: str, base_dir: Union[str, Path] = ".") -> Optiona
""" """
Loads a TrackState object from conductor/tracks/<track_id>/state.toml. Loads a TrackState object from conductor/tracks/<track_id>/state.toml.
""" """
from models import TrackState from src.models import TrackState
state_file = Path(base_dir) / "conductor" / "tracks" / track_id / "state.toml" state_file = Path(base_dir) / "conductor" / "tracks" / track_id / "state.toml"
if not state_file.exists(): if not state_file.exists():
return None return None

View File

@@ -1,7 +1,7 @@
import pytest import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from models import Ticket, Track, WorkerContext from src.models import Ticket, Track, WorkerContext
import ai_client from src import ai_client
# These tests define the expected interface for multi_agent_conductor.py # These tests define the expected interface for multi_agent_conductor.py
# which will be implemented in the next phase of TDD. # which will be implemented in the next phase of TDD.
@@ -11,7 +11,7 @@ def test_conductor_engine_initialization() -> None:
Test that ConductorEngine can be initialized with a Track. Test that ConductorEngine can be initialized with a Track.
""" """
track = Track(id="test_track", description="Test Track") track = Track(id="test_track", description="Test Track")
from multi_agent_conductor import ConductorEngine from src.multi_agent_conductor import ConductorEngine
engine = ConductorEngine(track=track, auto_queue=True) engine = ConductorEngine(track=track, auto_queue=True)
assert engine.track == track assert engine.track == track
@@ -23,7 +23,7 @@ async def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytes
ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1") ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="worker2", depends_on=["T1"]) ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="worker2", depends_on=["T1"])
track = Track(id="track1", description="Track 1", tickets=[ticket1, ticket2]) track = Track(id="track1", description="Track 1", tickets=[ticket1, ticket2])
from multi_agent_conductor import ConductorEngine from src.multi_agent_conductor import ConductorEngine
engine = ConductorEngine(track=track, auto_queue=True) engine = ConductorEngine(track=track, auto_queue=True)
vlogger.log_state("Ticket Count", 0, 2) vlogger.log_state("Ticket Count", 0, 2)
@@ -34,7 +34,7 @@ async def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytes
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
# We mock run_worker_lifecycle as it is expected to be in the same module # We mock run_worker_lifecycle as it is expected to be in the same module
with patch("multi_agent_conductor.run_worker_lifecycle") as mock_lifecycle: with patch("src.multi_agent_conductor.run_worker_lifecycle") as mock_lifecycle:
# Mocking lifecycle to mark ticket as complete so dependencies can be resolved # Mocking lifecycle to mark ticket as complete so dependencies can be resolved
def side_effect(ticket, context, *args, **kwargs): def side_effect(ticket, context, *args, **kwargs):
@@ -64,7 +64,7 @@ async def test_run_worker_lifecycle_calls_ai_client_send(monkeypatch: pytest.Mon
""" """
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1") ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[]) context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
# Mock ai_client.send using monkeypatch # Mock ai_client.send using monkeypatch
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
@@ -86,12 +86,12 @@ async def test_run_worker_lifecycle_context_injection(monkeypatch: pytest.Monkey
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1") ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[]) context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
context_files = ["primary.py", "secondary.py"] context_files = ["primary.py", "secondary.py"]
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
# Mock ai_client.send using monkeypatch # Mock ai_client.send using monkeypatch
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
# We mock ASTParser which is expected to be imported in multi_agent_conductor # We mock ASTParser which is expected to be imported in multi_agent_conductor
with patch("multi_agent_conductor.ASTParser") as mock_ast_parser_class, \ with patch("src.multi_agent_conductor.ASTParser") as mock_ast_parser_class, \
patch("builtins.open", new_callable=MagicMock) as mock_open: patch("builtins.open", new_callable=MagicMock) as mock_open:
# Setup open mock to return different content for different files # Setup open mock to return different content for different files
file_contents = { file_contents = {
@@ -131,7 +131,7 @@ async def test_run_worker_lifecycle_handles_blocked_response(monkeypatch: pytest
""" """
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1") ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[]) context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
# Mock ai_client.send using monkeypatch # Mock ai_client.send using monkeypatch
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
@@ -150,14 +150,14 @@ async def test_run_worker_lifecycle_step_mode_confirmation(monkeypatch: pytest.M
""" """
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True) ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True)
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[]) context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
# Mock ai_client.send using monkeypatch # Mock ai_client.send using monkeypatch
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
# Important: confirm_spawn is called first if event_queue is present! # Important: confirm_spawn is called first if event_queue is present!
with patch("multi_agent_conductor.confirm_spawn") as mock_spawn, \ with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
patch("multi_agent_conductor.confirm_execution") as mock_confirm: patch("src.multi_agent_conductor.confirm_execution") as mock_confirm:
mock_spawn.return_value = (True, "mock prompt", "mock context") mock_spawn.return_value = (True, "mock prompt", "mock context")
mock_confirm.return_value = True mock_confirm.return_value = True
@@ -186,12 +186,12 @@ async def test_run_worker_lifecycle_step_mode_rejection(monkeypatch: pytest.Monk
""" """
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True) ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True)
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[]) context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
# Mock ai_client.send using monkeypatch # Mock ai_client.send using monkeypatch
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
with patch("multi_agent_conductor.confirm_spawn") as mock_spawn, \ with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
patch("multi_agent_conductor.confirm_execution") as mock_confirm: patch("src.multi_agent_conductor.confirm_execution") as mock_confirm:
mock_spawn.return_value = (True, "mock prompt", "mock context") mock_spawn.return_value = (True, "mock prompt", "mock context")
mock_confirm.return_value = False mock_confirm.return_value = False
mock_send.return_value = "Task failed because tool execution was rejected." mock_send.return_value = "Task failed because tool execution was rejected."
@@ -209,7 +209,7 @@ async def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytes
Test that parse_json_tickets correctly populates the track and run executes them in dependency order. Test that parse_json_tickets correctly populates the track and run executes them in dependency order.
""" """
import json import json
from multi_agent_conductor import ConductorEngine from src.multi_agent_conductor import ConductorEngine
track = Track(id="dynamic_track", description="Dynamic Track") track = Track(id="dynamic_track", description="Dynamic Track")
engine = ConductorEngine(track=track, auto_queue=True) engine = ConductorEngine(track=track, auto_queue=True)
tickets_json = json.dumps([ tickets_json = json.dumps([
@@ -246,7 +246,7 @@ async def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytes
mock_send = MagicMock() mock_send = MagicMock()
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
# Mock run_worker_lifecycle to mark tickets as complete # Mock run_worker_lifecycle to mark tickets as complete
with patch("multi_agent_conductor.run_worker_lifecycle") as mock_lifecycle: with patch("src.multi_agent_conductor.run_worker_lifecycle") as mock_lifecycle:
def side_effect(ticket, context, *args, **kwargs): def side_effect(ticket, context, *args, **kwargs):
ticket.mark_complete() ticket.mark_complete()
return "Success" return "Success"
@@ -279,9 +279,9 @@ def test_run_worker_lifecycle_pushes_response_via_queue(monkeypatch: pytest.Monk
mock_send = MagicMock(return_value="Task complete.") mock_send = MagicMock(return_value="Task complete.")
monkeypatch.setattr(ai_client, 'send', mock_send) monkeypatch.setattr(ai_client, 'send', mock_send)
monkeypatch.setattr(ai_client, 'reset_session', MagicMock()) monkeypatch.setattr(ai_client, 'reset_session', MagicMock())
from multi_agent_conductor import run_worker_lifecycle from src.multi_agent_conductor import run_worker_lifecycle
with patch("multi_agent_conductor.confirm_spawn") as mock_spawn, \ with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
patch("multi_agent_conductor._queue_put") as mock_queue_put: patch("src.multi_agent_conductor._queue_put") as mock_queue_put:
mock_spawn.return_value = (True, "prompt", "context") mock_spawn.return_value = (True, "prompt", "context")
run_worker_lifecycle(ticket, context, event_queue=mock_event_queue, loop=mock_loop) run_worker_lifecycle(ticket, context, event_queue=mock_event_queue, loop=mock_loop)
mock_queue_put.assert_called_once() mock_queue_put.assert_called_once()
@@ -309,14 +309,13 @@ def test_run_worker_lifecycle_token_usage_from_comms_log(monkeypatch: pytest.Mon
[], # baseline call (before send) [], # baseline call (before send)
fake_comms, # after-send call fake_comms, # after-send call
])) ]))
from multi_agent_conductor import run_worker_lifecycle, ConductorEngine from src.multi_agent_conductor import run_worker_lifecycle, ConductorEngine
from models import Track from src.models import Track
track = Track(id="test_track", description="Test") track = Track(id="test_track", description="Test")
engine = ConductorEngine(track=track, auto_queue=True) engine = ConductorEngine(track=track, auto_queue=True)
with patch("multi_agent_conductor.confirm_spawn") as mock_spawn, \ with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
patch("multi_agent_conductor._queue_put"): patch("src.multi_agent_conductor._queue_put"):
mock_spawn.return_value = (True, "prompt", "ctx") mock_spawn.return_value = (True, "prompt", "ctx")
run_worker_lifecycle(ticket, context, event_queue=MagicMock(), loop=MagicMock(), engine=engine) run_worker_lifecycle(ticket, context, event_queue=MagicMock(), loop=MagicMock(), engine=engine)
assert engine.tier_usage["Tier 3"]["input"] == 120 assert engine.tier_usage["Tier 3"]["input"] == 120
assert engine.tier_usage["Tier 3"]["output"] == 45 assert engine.tier_usage["Tier 3"]["output"] == 45

View File

@@ -2,7 +2,7 @@
import pytest import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from gui_2 import App from gui_2 import App
from models import Track from src.models import Track
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def setup_mock_app(mock_app: App): def setup_mock_app(mock_app: App):

View File

@@ -1,4 +1,4 @@
from models import Ticket, Track, WorkerContext from src.models import Ticket, Track, WorkerContext
def test_ticket_instantiation() -> None: def test_ticket_instantiation() -> None:
""" """

View File

@@ -1,8 +1,8 @@
import pytest import pytest
from typing import Any from typing import Any
import json import json
from project_manager import get_all_tracks, save_track_state from src.project_manager import get_all_tracks, save_track_state
from models import TrackState, Metadata, Ticket from src.models import TrackState, Metadata, Ticket
from datetime import datetime from datetime import datetime
def test_get_all_tracks_empty(tmp_path: Any) -> None: def test_get_all_tracks_empty(tmp_path: Any) -> None:

View File

@@ -1,7 +1,7 @@
import pytest import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
import multi_agent_conductor import multi_agent_conductor
from models import Ticket, WorkerContext from src.models import Ticket, WorkerContext
import events import events
import asyncio import asyncio
import concurrent.futures import concurrent.futures

View File

@@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
# Import the real models # Import the real models
from models import TrackState, Metadata, Ticket from src.models import TrackState, Metadata, Ticket
# Import the persistence functions from project_manager # Import the persistence functions from project_manager
from project_manager import save_track_state, load_track_state from project_manager import save_track_state, load_track_state

View File

@@ -1,7 +1,7 @@
from datetime import datetime, timezone, timedelta from datetime import datetime, timezone, timedelta
# Import necessary classes from models.py # Import necessary classes from models.py
from models import Metadata, TrackState, Ticket from src.models import Metadata, TrackState, Ticket
# --- Pytest Tests --- # --- Pytest Tests ---