WIP: STILL FIXING FUNDAMENTAL TRASH
This commit is contained in:
@@ -8,5 +8,5 @@ active = "main"
|
|||||||
|
|
||||||
[discussions.main]
|
[discussions.main]
|
||||||
git_commit = ""
|
git_commit = ""
|
||||||
last_updated = "2026-03-04T10:09:06"
|
last_updated = "2026-03-05T14:02:52"
|
||||||
history = []
|
history = []
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import ai_client
|
from src import ai_client
|
||||||
|
|
||||||
# Ensure project root is in path
|
# Ensure project root is in path
|
||||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
|
|
||||||
|
|
||||||
from ai_client import set_agent_tools, _build_anthropic_tools
|
from src.ai_client import set_agent_tools, _build_anthropic_tools
|
||||||
|
|
||||||
def test_set_agent_tools() -> None:
|
def test_set_agent_tools() -> None:
|
||||||
agent_tools = {"read_file": True, "list_directory": False}
|
agent_tools = {"read_file": True, "list_directory": False}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
import ai_client
|
from src import ai_client
|
||||||
|
|
||||||
def test_ai_client_send_gemini_cli() -> None:
|
def test_ai_client_send_gemini_cli() -> None:
|
||||||
"""
|
"""
|
||||||
@@ -10,8 +10,8 @@ def test_ai_client_send_gemini_cli() -> None:
|
|||||||
test_response = "This is a dummy response from the Gemini CLI."
|
test_response = "This is a dummy response from the Gemini CLI."
|
||||||
# Set provider to gemini_cli
|
# Set provider to gemini_cli
|
||||||
ai_client.set_provider("gemini_cli", "gemini-2.5-flash-lite")
|
ai_client.set_provider("gemini_cli", "gemini-2.5-flash-lite")
|
||||||
# 1. Mock 'ai_client.GeminiCliAdapter' (which we will add)
|
# 1. Mock 'src.ai_client.GeminiCliAdapter'
|
||||||
with patch('ai_client.GeminiCliAdapter') as MockAdapterClass:
|
with patch('src.ai_client.GeminiCliAdapter') as MockAdapterClass:
|
||||||
mock_adapter_instance = MockAdapterClass.return_value
|
mock_adapter_instance = MockAdapterClass.return_value
|
||||||
mock_adapter_instance.send.return_value = {"text": test_response, "tool_calls": []}
|
mock_adapter_instance.send.return_value = {"text": test_response, "tool_calls": []}
|
||||||
mock_adapter_instance.last_usage = {"total_tokens": 100}
|
mock_adapter_instance.last_usage = {"total_tokens": 100}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import ai_client
|
from src import ai_client
|
||||||
|
|
||||||
def test_list_models_gemini_cli() -> None:
|
def test_list_models_gemini_cli() -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
|
|
||||||
from src import ai_client
|
|
||||||
from src import models
|
|
||||||
from src import multi_agent_conductor
|
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
from src.models import Ticket, Track, WorkerContext
|
||||||
from src import ai_client
|
from src import ai_client
|
||||||
from src import models
|
|
||||||
from src import multi_agent_conductor
|
|
||||||
|
|
||||||
-> None:
|
def test_conductor_engine_initialization() -> None:
|
||||||
"""
|
"""
|
||||||
Test that ConductorEngine can be initialized with a models.Track.
|
Test that ConductorEngine can be initialized with a Track.
|
||||||
"""
|
"""
|
||||||
track = models.Track(id="test_track", description="Test models.Track")
|
track = Track(id="test_track", description="Test Track")
|
||||||
from src.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
|
||||||
@@ -21,13 +16,13 @@ def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytest.Monk
|
|||||||
"""
|
"""
|
||||||
Test that run iterates through executable tickets and calls the worker lifecycle.
|
Test that run iterates through executable tickets and calls the worker lifecycle.
|
||||||
"""
|
"""
|
||||||
ticket1 = models.Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||||
ticket2 = models.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 = models.Track(id="track1", description="src.models.Track 1", tickets=[ticket1, ticket2])
|
track = Track(id="track1", description="Track 1", tickets=[ticket1, ticket2])
|
||||||
from src.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("src.models.Ticket Count", 0, 2)
|
vlogger.log_state("Ticket Count", 0, 2)
|
||||||
vlogger.log_state("T1 Status", "todo", "todo")
|
vlogger.log_state("T1 Status", "todo", "todo")
|
||||||
vlogger.log_state("T2 Status", "todo", "todo")
|
vlogger.log_state("T2 Status", "todo", "todo")
|
||||||
|
|
||||||
@@ -43,11 +38,11 @@ def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytest.Monk
|
|||||||
return "Success"
|
return "Success"
|
||||||
mock_lifecycle.side_effect = side_effect
|
mock_lifecycle.side_effect = side_effect
|
||||||
engine.run()
|
engine.run()
|
||||||
|
|
||||||
vlogger.log_state("T1 Status Final", "todo", ticket1.status)
|
vlogger.log_state("T1 Status Final", "todo", ticket1.status)
|
||||||
vlogger.log_state("T2 Status Final", "todo", ticket2.status)
|
vlogger.log_state("T2 Status Final", "todo", ticket2.status)
|
||||||
|
|
||||||
# models.Track.get_executable_tickets() should be called repeatedly until all are done
|
# Track.get_executable_tickets() should be called repeatedly until all are done
|
||||||
# T1 should run first, then T2.
|
# T1 should run first, then T2.
|
||||||
assert mock_lifecycle.call_count == 2
|
assert mock_lifecycle.call_count == 2
|
||||||
assert ticket1.status == "completed"
|
assert ticket1.status == "completed"
|
||||||
@@ -62,15 +57,14 @@ def test_run_worker_lifecycle_calls_ai_client_send(monkeypatch: pytest.MonkeyPat
|
|||||||
"""
|
"""
|
||||||
Test that run_worker_lifecycle triggers the AI client and updates ticket status on success.
|
Test that run_worker_lifecycle triggers the AI client and updates ticket status on success.
|
||||||
"""
|
"""
|
||||||
ticket = models.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 src.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)
|
||||||
mock_send.return_value = "Task complete. I have updated the file."
|
mock_send.return_value = "Task complete. I have updated the file."
|
||||||
result = run_worker_lifecycle(ticket, context)
|
run_worker_lifecycle(ticket, context)
|
||||||
assert result == "Task complete. I have updated the file."
|
|
||||||
assert ticket.status == "completed"
|
assert ticket.status == "completed"
|
||||||
mock_send.assert_called_once()
|
mock_send.assert_called_once()
|
||||||
# Check if description was passed to send()
|
# Check if description was passed to send()
|
||||||
@@ -82,7 +76,7 @@ def test_run_worker_lifecycle_context_injection(monkeypatch: pytest.MonkeyPatch)
|
|||||||
"""
|
"""
|
||||||
Test that run_worker_lifecycle can take a context_files list and injects AST views into the prompt.
|
Test that run_worker_lifecycle can take a context_files list and injects AST views into the prompt.
|
||||||
"""
|
"""
|
||||||
ticket = models.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 src.multi_agent_conductor import run_worker_lifecycle
|
from src.multi_agent_conductor import run_worker_lifecycle
|
||||||
@@ -127,7 +121,7 @@ def test_run_worker_lifecycle_handles_blocked_response(monkeypatch: pytest.Monke
|
|||||||
"""
|
"""
|
||||||
Test that run_worker_lifecycle marks the ticket as blocked if the AI indicates it cannot proceed.
|
Test that run_worker_lifecycle marks the ticket as blocked if the AI indicates it cannot proceed.
|
||||||
"""
|
"""
|
||||||
ticket = models.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 src.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
|
||||||
@@ -145,13 +139,13 @@ def test_run_worker_lifecycle_step_mode_confirmation(monkeypatch: pytest.MonkeyP
|
|||||||
Verify that if confirm_execution is called (simulated by mocking ai_client.send to call its callback),
|
Verify that if confirm_execution is called (simulated by mocking ai_client.send to call its callback),
|
||||||
the flow works as expected.
|
the flow works as expected.
|
||||||
"""
|
"""
|
||||||
ticket = models.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 src.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("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
|
with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
|
||||||
patch("src.multi_agent_conductor.confirm_execution") as mock_confirm:
|
patch("src.multi_agent_conductor.confirm_execution") as mock_confirm:
|
||||||
@@ -165,10 +159,10 @@ def test_run_worker_lifecycle_step_mode_confirmation(monkeypatch: pytest.MonkeyP
|
|||||||
callback('{"tool": "read_file", "args": {"path": "test.txt"}}')
|
callback('{"tool": "read_file", "args": {"path": "test.txt"}}')
|
||||||
return "Success"
|
return "Success"
|
||||||
mock_send.side_effect = mock_send_side_effect
|
mock_send.side_effect = mock_send_side_effect
|
||||||
|
|
||||||
mock_event_queue = MagicMock()
|
mock_event_queue = MagicMock()
|
||||||
run_worker_lifecycle(ticket, context, event_queue=mock_event_queue)
|
run_worker_lifecycle(ticket, context, event_queue=mock_event_queue)
|
||||||
|
|
||||||
# Verify confirm_spawn was called because event_queue was present
|
# Verify confirm_spawn was called because event_queue was present
|
||||||
mock_spawn.assert_called_once()
|
mock_spawn.assert_called_once()
|
||||||
# Verify confirm_execution was called
|
# Verify confirm_execution was called
|
||||||
@@ -180,7 +174,7 @@ def test_run_worker_lifecycle_step_mode_rejection(monkeypatch: pytest.MonkeyPatc
|
|||||||
Verify that if confirm_execution returns False, the logic (in ai_client, which we simulate here)
|
Verify that if confirm_execution returns False, the logic (in ai_client, which we simulate here)
|
||||||
would prevent execution. In run_worker_lifecycle, we just check if it's passed.
|
would prevent execution. In run_worker_lifecycle, we just check if it's passed.
|
||||||
"""
|
"""
|
||||||
ticket = models.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 src.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
|
||||||
@@ -191,10 +185,10 @@ def test_run_worker_lifecycle_step_mode_rejection(monkeypatch: pytest.MonkeyPatc
|
|||||||
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."
|
||||||
|
|
||||||
mock_event_queue = MagicMock()
|
mock_event_queue = MagicMock()
|
||||||
run_worker_lifecycle(ticket, context, event_queue=mock_event_queue)
|
run_worker_lifecycle(ticket, context, event_queue=mock_event_queue)
|
||||||
|
|
||||||
# Verify it was passed to send
|
# Verify it was passed to send
|
||||||
args, kwargs = mock_send.call_args
|
args, kwargs = mock_send.call_args
|
||||||
assert kwargs["pre_tool_callback"] is not None
|
assert kwargs["pre_tool_callback"] is not None
|
||||||
@@ -205,7 +199,7 @@ def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytest.Monk
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
from src.multi_agent_conductor import ConductorEngine
|
from src.multi_agent_conductor import ConductorEngine
|
||||||
track = models.Track(id="dynamic_track", description="Dynamic models.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([
|
||||||
{
|
{
|
||||||
@@ -231,8 +225,8 @@ def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytest.Monk
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
engine.parse_json_tickets(tickets_json)
|
engine.parse_json_tickets(tickets_json)
|
||||||
|
|
||||||
vlogger.log_state("Parsed models.Ticket Count", 0, len(engine.track.tickets))
|
vlogger.log_state("Parsed Ticket Count", 0, len(engine.track.tickets))
|
||||||
assert len(engine.track.tickets) == 3
|
assert len(engine.track.tickets) == 3
|
||||||
assert engine.track.tickets[0].id == "T1"
|
assert engine.track.tickets[0].id == "T1"
|
||||||
assert engine.track.tickets[1].id == "T2"
|
assert engine.track.tickets[1].id == "T2"
|
||||||
@@ -252,10 +246,10 @@ def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytest.Monk
|
|||||||
calls = [call[0][0].id for call in mock_lifecycle.call_args_list]
|
calls = [call[0][0].id for call in mock_lifecycle.call_args_list]
|
||||||
t1_idx = calls.index("T1")
|
t1_idx = calls.index("T1")
|
||||||
t2_idx = calls.index("T2")
|
t2_idx = calls.index("T2")
|
||||||
|
|
||||||
vlogger.log_state("T1 Sequence Index", "N/A", t1_idx)
|
vlogger.log_state("T1 Sequence Index", "N/A", t1_idx)
|
||||||
vlogger.log_state("T2 Sequence Index", "N/A", t2_idx)
|
vlogger.log_state("T2 Sequence Index", "N/A", t2_idx)
|
||||||
|
|
||||||
assert t1_idx < t2_idx
|
assert t1_idx < t2_idx
|
||||||
# T3 can be anywhere relative to T1 and T2, but T1 < T2 is mandatory
|
# T3 can be anywhere relative to T1 and T2, but T1 < T2 is mandatory
|
||||||
assert "T3" in calls
|
assert "T3" in calls
|
||||||
@@ -266,7 +260,7 @@ def test_run_worker_lifecycle_pushes_response_via_queue(monkeypatch: pytest.Monk
|
|||||||
Test that run_worker_lifecycle pushes a 'response' event with the correct stream_id
|
Test that run_worker_lifecycle pushes a 'response' event with the correct stream_id
|
||||||
via _queue_put when event_queue is provided.
|
via _queue_put when event_queue is provided.
|
||||||
"""
|
"""
|
||||||
ticket = models.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=[])
|
||||||
mock_event_queue = MagicMock()
|
mock_event_queue = MagicMock()
|
||||||
mock_send = MagicMock(return_value="Task complete.")
|
mock_send = MagicMock(return_value="Task complete.")
|
||||||
@@ -290,7 +284,7 @@ def test_run_worker_lifecycle_token_usage_from_comms_log(monkeypatch: pytest.Mon
|
|||||||
Test that run_worker_lifecycle reads token usage from the comms log and
|
Test that run_worker_lifecycle reads token usage from the comms log and
|
||||||
updates engine.tier_usage['Tier 3'] with real input/output token counts.
|
updates engine.tier_usage['Tier 3'] with real input/output token counts.
|
||||||
"""
|
"""
|
||||||
ticket = models.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=[])
|
||||||
fake_comms = [
|
fake_comms = [
|
||||||
{"direction": "OUT", "kind": "request", "payload": {"message": "hello"}},
|
{"direction": "OUT", "kind": "request", "payload": {"message": "hello"}},
|
||||||
@@ -303,8 +297,7 @@ def test_run_worker_lifecycle_token_usage_from_comms_log(monkeypatch: pytest.Mon
|
|||||||
fake_comms, # after-send call
|
fake_comms, # after-send call
|
||||||
]))
|
]))
|
||||||
from src.multi_agent_conductor import run_worker_lifecycle, ConductorEngine
|
from src.multi_agent_conductor import run_worker_lifecycle, ConductorEngine
|
||||||
from src.models import models.Track
|
track = Track(id="test_track", description="Test")
|
||||||
track = models.Track(id="test_track", description="Test")
|
|
||||||
engine = ConductorEngine(track=track, auto_queue=True)
|
engine = ConductorEngine(track=track, auto_queue=True)
|
||||||
with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
|
with patch("src.multi_agent_conductor.confirm_spawn") as mock_spawn, \
|
||||||
patch("src.multi_agent_conductor._queue_put"):
|
patch("src.multi_agent_conductor._queue_put"):
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
import ai_client
|
from src import ai_client
|
||||||
|
|
||||||
@patch('ai_client.GeminiCliAdapter')
|
@patch('src.ai_client.GeminiCliAdapter')
|
||||||
def test_send_invokes_adapter_send(mock_adapter_class: Any) -> None:
|
def test_send_invokes_adapter_send(mock_adapter_class: Any) -> None:
|
||||||
mock_instance = mock_adapter_class.return_value
|
mock_instance = mock_adapter_class.return_value
|
||||||
mock_instance.send.return_value = {"text": "Hello from mock adapter", "tool_calls": []}
|
mock_instance.send.return_value = {"text": "Hello from mock adapter", "tool_calls": []}
|
||||||
@@ -11,13 +11,13 @@ def test_send_invokes_adapter_send(mock_adapter_class: Any) -> None:
|
|||||||
mock_instance.session_id = None
|
mock_instance.session_id = None
|
||||||
|
|
||||||
# Force reset to ensure our mock is used
|
# Force reset to ensure our mock is used
|
||||||
with patch('ai_client._gemini_cli_adapter', mock_instance):
|
with patch('src.ai_client._gemini_cli_adapter', mock_instance):
|
||||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||||
res = ai_client.send("context", "msg")
|
res = ai_client.send("context", "msg")
|
||||||
assert res == "Hello from mock adapter"
|
assert res == "Hello from mock adapter"
|
||||||
mock_instance.send.assert_called()
|
mock_instance.send.assert_called()
|
||||||
|
|
||||||
@patch('ai_client.GeminiCliAdapter')
|
@patch('src.ai_client.GeminiCliAdapter')
|
||||||
def test_get_history_bleed_stats(mock_adapter_class: Any) -> None:
|
def test_get_history_bleed_stats(mock_adapter_class: Any) -> None:
|
||||||
mock_instance = mock_adapter_class.return_value
|
mock_instance = mock_adapter_class.return_value
|
||||||
mock_instance.send.return_value = {"text": "txt", "tool_calls": []}
|
mock_instance.send.return_value = {"text": "txt", "tool_calls": []}
|
||||||
@@ -25,7 +25,7 @@ def test_get_history_bleed_stats(mock_adapter_class: Any) -> None:
|
|||||||
mock_instance.last_latency = 0.5
|
mock_instance.last_latency = 0.5
|
||||||
mock_instance.session_id = "sess"
|
mock_instance.session_id = "sess"
|
||||||
|
|
||||||
with patch('ai_client._gemini_cli_adapter', mock_instance):
|
with patch('src.ai_client._gemini_cli_adapter', mock_instance):
|
||||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||||
# Initialize by sending a message
|
# Initialize by sending a message
|
||||||
ai_client.send("context", "msg")
|
ai_client.send("context", "msg")
|
||||||
|
|||||||
@@ -1,36 +1,18 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch, MagicMock
|
||||||
from typing import Generator
|
from src.gui_2 import App
|
||||||
from gui_2 import App
|
from src import ai_client
|
||||||
import ai_client
|
|
||||||
from events import EventEmitter
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def app_instance() -> Generator[type[App], None, None]:
|
def app_instance(monkeypatch: pytest.MonkeyPatch) -> type[App]:
|
||||||
"""
|
"""Fixture to provide the App class with necessary environment variables."""
|
||||||
Fixture to create an instance of the gui_2.App class for testing.
|
monkeypatch.setenv("SLOP_TEST_HOOKS", "1")
|
||||||
It mocks functions that would render a window or block execution.
|
return App
|
||||||
"""
|
|
||||||
if not hasattr(ai_client, 'events') or ai_client.events is None:
|
|
||||||
ai_client.events = EventEmitter()
|
|
||||||
with (
|
|
||||||
patch('src.models.load_config', return_value={'ai': {}, 'projects': {}}),
|
|
||||||
patch('gui_2.save_config'),
|
|
||||||
patch('gui_2.project_manager'),
|
|
||||||
patch('gui_2.session_logger'),
|
|
||||||
patch('gui_2.immapp.run'),
|
|
||||||
patch('src.app_controller.AppController._load_active_project'),
|
|
||||||
patch('src.app_controller.AppController._fetch_models'),
|
|
||||||
patch.object(App, '_load_fonts'),
|
|
||||||
patch.object(App, '_post_init')
|
|
||||||
):
|
|
||||||
yield App
|
|
||||||
|
|
||||||
def test_app_subscribes_to_events(app_instance: type[App]) -> None:
|
def test_app_subscribes_to_events(app_instance: type[App]) -> None:
|
||||||
"""
|
"""
|
||||||
This test checks that the App's __init__ method subscribes the necessary
|
This test checks that the App's __init__ method subscribes the necessary
|
||||||
event handlers to the ai_client.events emitter.
|
event handlers to the ai_client.events emitter.
|
||||||
This test will fail until the event subscription logic is added to gui_2.App.
|
|
||||||
"""
|
"""
|
||||||
with patch.object(ai_client.events, 'on') as mock_on:
|
with patch.object(ai_client.events, 'on') as mock_on:
|
||||||
app = app_instance()
|
app = app_instance()
|
||||||
@@ -40,7 +22,4 @@ def test_app_subscribes_to_events(app_instance: type[App]) -> None:
|
|||||||
assert "request_start" in event_names
|
assert "request_start" in event_names
|
||||||
assert "response_received" in event_names
|
assert "response_received" in event_names
|
||||||
assert "tool_execution" in event_names
|
assert "tool_execution" in event_names
|
||||||
for call in calls:
|
# We don't check for __self__ anymore as they might be lambdas
|
||||||
handler = call.args[1]
|
|
||||||
assert hasattr(handler, '__self__')
|
|
||||||
assert handler.__self__ is app.controller
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
from gui_2 import App
|
from src.gui_2 import App
|
||||||
import ai_client
|
from src import ai_client
|
||||||
|
|
||||||
def test_mcp_tool_call_is_dispatched(app_instance: App) -> None:
|
def test_mcp_tool_call_is_dispatched(app_instance: App) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -33,9 +33,9 @@ def test_mcp_tool_call_is_dispatched(app_instance: App) -> None:
|
|||||||
mock_response_final.candidates = []
|
mock_response_final.candidates = []
|
||||||
mock_response_final.usage_metadata = DummyUsage()
|
mock_response_final.usage_metadata = DummyUsage()
|
||||||
# 4. Patch the necessary components
|
# 4. Patch the necessary components
|
||||||
with patch("ai_client._ensure_gemini_client"), \
|
with patch("src.ai_client._ensure_gemini_client"), \
|
||||||
patch("ai_client._gemini_client") as mock_client, \
|
patch("src.ai_client._gemini_client") as mock_client, \
|
||||||
patch('mcp_client.dispatch', return_value="file content") as mock_dispatch:
|
patch("src.mcp_client.dispatch", return_value="file content") as mock_dispatch:
|
||||||
mock_chat = mock_client.chats.create.return_value
|
mock_chat = mock_client.chats.create.return_value
|
||||||
mock_chat.send_message.side_effect = [mock_response_with_tool, mock_response_final]
|
mock_chat.send_message.side_effect = [mock_response_with_tool, mock_response_final]
|
||||||
ai_client.set_provider("gemini", "mock-model")
|
ai_client.set_provider("gemini", "mock-model")
|
||||||
|
|||||||
@@ -1,49 +1,38 @@
|
|||||||
|
|
||||||
from src import app_controller
|
|
||||||
from src import events
|
|
||||||
from src import gui_2
|
|
||||||
from src import models
|
|
||||||
from src import project_manager
|
|
||||||
from src import session_logger
|
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from src import app_controller
|
from src.gui_2 import App
|
||||||
from src import events
|
from src.events import UserRequestEvent
|
||||||
from src import gui_2
|
|
||||||
from src import models
|
|
||||||
from src import project_manager
|
|
||||||
from src import session_logger
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_gui() -> gui_2.App:
|
def mock_gui() -> App:
|
||||||
with (
|
with (
|
||||||
patch('src.models.load_config', return_value={
|
patch('src.models.load_config', return_value={
|
||||||
"ai": {"provider": "gemini", "model": "model-1"},
|
"ai": {"provider": "gemini", "model": "model-1"},
|
||||||
"projects": {"paths": [], "active": ""},
|
"projects": {"paths": [], "active": ""},
|
||||||
"gui": {"show_windows": {}}
|
"gui": {"show_windows": {}}
|
||||||
}),
|
}),
|
||||||
patch('src.gui_2.project_manager.load_project', return_value={}),
|
patch('src.project_manager.load_project', return_value={}),
|
||||||
patch('src.gui_2.project_manager.migrate_from_legacy_config', return_value={}),
|
patch('src.project_manager.migrate_from_legacy_config', return_value={}),
|
||||||
patch('src.gui_2.project_manager.save_project'),
|
patch('src.project_manager.save_project'),
|
||||||
patch('src.gui_2.session_logger.open_session'),
|
patch('src.session_logger.open_session'),
|
||||||
patch('src.app_controller.AppController._init_ai_and_hooks'),
|
patch('src.app_controller.AppController._init_ai_and_hooks'),
|
||||||
patch('src.app_controller.AppController._fetch_models')
|
patch('src.app_controller.AppController._fetch_models')
|
||||||
):
|
):
|
||||||
gui = gui_2.App()
|
gui = App()
|
||||||
return gui
|
return gui
|
||||||
|
|
||||||
def test_handle_generate_send_pushes_event(mock_gui: gui_2.App) -> None:
|
def test_handle_generate_send_pushes_event(mock_gui: App) -> None:
|
||||||
mock_gui._do_generate = MagicMock(return_value=(
|
mock_gui.controller._do_generate = MagicMock(return_value=(
|
||||||
"full_md", "path", [], "stable_md", "disc_text"
|
"full_md", "path", [], "stable_md", "disc_text"
|
||||||
))
|
))
|
||||||
mock_gui.ui_ai_input = "test prompt"
|
mock_gui.controller.ui_ai_input = "test prompt"
|
||||||
mock_gui.ui_files_base_dir = "."
|
mock_gui.controller.ui_files_base_dir = "."
|
||||||
# Mock event_queue.put
|
# Mock event_queue.put
|
||||||
mock_gui.event_queue.put = MagicMock()
|
mock_gui.controller.event_queue.put = MagicMock()
|
||||||
|
|
||||||
# No need to mock asyncio.run_coroutine_threadsafe now, it's a standard thread
|
# No need to mock asyncio.run_coroutine_threadsafe now, it's a standard thread
|
||||||
with patch('threading.Thread') as mock_thread:
|
with patch('threading.Thread') as mock_thread:
|
||||||
mock_gui._handle_generate_send()
|
mock_gui.controller._handle_generate_send()
|
||||||
# Verify thread was started
|
# Verify thread was started
|
||||||
assert mock_thread.called
|
assert mock_thread.called
|
||||||
# To test the worker logic inside, we'd need to invoke the target function
|
# To test the worker logic inside, we'd need to invoke the target function
|
||||||
@@ -51,20 +40,20 @@ def test_handle_generate_send_pushes_event(mock_gui: gui_2.App) -> None:
|
|||||||
# Let's extract the worker and run it.
|
# Let's extract the worker and run it.
|
||||||
target_worker = mock_thread.call_args[1]['target']
|
target_worker = mock_thread.call_args[1]['target']
|
||||||
target_worker()
|
target_worker()
|
||||||
|
|
||||||
# Verify the call to event_queue.put occurred.
|
# Verify the call to event_queue.put occurred.
|
||||||
mock_gui.event_queue.put.assert_called_once()
|
mock_gui.controller.event_queue.put.assert_called_once()
|
||||||
args, kwargs = mock_gui.event_queue.put.call_args
|
args, kwargs = mock_gui.controller.event_queue.put.call_args
|
||||||
assert args[0] == "user_request"
|
assert args[0] == "user_request"
|
||||||
event = args[1]
|
event = args[1]
|
||||||
assert isinstance(event, events.UserRequestEvent)
|
assert isinstance(event, UserRequestEvent)
|
||||||
assert event.prompt == "test prompt"
|
assert event.prompt == "test prompt"
|
||||||
assert event.stable_md == "stable_md"
|
assert event.stable_md == "stable_md"
|
||||||
assert event.disc_text == "disc_text"
|
assert event.disc_text == "disc_text"
|
||||||
assert event.base_dir == "."
|
assert event.base_dir == "."
|
||||||
|
|
||||||
def test_user_request_event_payload() -> None:
|
def test_user_request_event_payload() -> None:
|
||||||
payload = events.UserRequestEvent(
|
payload = UserRequestEvent(
|
||||||
prompt="hello",
|
prompt="hello",
|
||||||
stable_md="md",
|
stable_md="md",
|
||||||
file_items=[],
|
file_items=[],
|
||||||
@@ -79,7 +68,7 @@ def test_user_request_event_payload() -> None:
|
|||||||
assert d["base_dir"] == "."
|
assert d["base_dir"] == "."
|
||||||
|
|
||||||
def test_sync_event_queue() -> None:
|
def test_sync_event_queue() -> None:
|
||||||
from events import SyncEventQueue
|
from src.events import SyncEventQueue
|
||||||
q = SyncEventQueue()
|
q = SyncEventQueue()
|
||||||
q.put("test_event", {"data": 123})
|
q.put("test_event", {"data": 123})
|
||||||
name, payload = q.get()
|
name, payload = q.get()
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
|
|
||||||
from src import ai_client
|
|
||||||
from src import api_hook_client
|
|
||||||
from src import events
|
|
||||||
from src import gui_2
|
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import patch, ANY
|
from unittest.mock import patch, ANY
|
||||||
import time
|
import time
|
||||||
from src import ai_client
|
from src.gui_2 import App
|
||||||
from src import api_hook_client
|
from src.events import UserRequestEvent
|
||||||
from src import events
|
from src.api_hook_client import ApiHookClient
|
||||||
from src import gui_2
|
|
||||||
|
|
||||||
@pytest.mark.timeout(10)
|
@pytest.mark.timeout(10)
|
||||||
def test_user_request_integration_flow(mock_app: gui_2.App) -> None:
|
def test_user_request_integration_flow(mock_app: App) -> None:
|
||||||
"""
|
"""
|
||||||
Verifies that pushing a events.UserRequestEvent to the event_queue:
|
Verifies that pushing a UserRequestEvent to the event_queue:
|
||||||
1. Triggers ai_client.send
|
1. Triggers ai_client.send
|
||||||
2. Results in a 'response' event back to the queue
|
2. Results in a 'response' event back to the queue
|
||||||
3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks.
|
3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks.
|
||||||
@@ -28,8 +22,8 @@ def test_user_request_integration_flow(mock_app: gui_2.App) -> None:
|
|||||||
patch('src.ai_client.set_model_params'),
|
patch('src.ai_client.set_model_params'),
|
||||||
patch('src.ai_client.set_agent_tools')
|
patch('src.ai_client.set_agent_tools')
|
||||||
):
|
):
|
||||||
# 1. Create and push a events.UserRequestEvent
|
# 1. Create and push a UserRequestEvent
|
||||||
event = events.UserRequestEvent(
|
event = UserRequestEvent(
|
||||||
prompt="Hello AI",
|
prompt="Hello AI",
|
||||||
stable_md="Context",
|
stable_md="Context",
|
||||||
file_items=[],
|
file_items=[],
|
||||||
@@ -39,7 +33,7 @@ def test_user_request_integration_flow(mock_app: gui_2.App) -> None:
|
|||||||
# 2. Call the handler directly since start_services is mocked (no event loop thread)
|
# 2. Call the handler directly since start_services is mocked (no event loop thread)
|
||||||
app.controller._handle_request_event(event)
|
app.controller._handle_request_event(event)
|
||||||
# 3. Verify ai_client.send was called
|
# 3. Verify ai_client.send was called
|
||||||
assert mock_send.called, "src.ai_client.send was not called"
|
assert mock_send.called, "ai_client.send was not called"
|
||||||
mock_send.assert_called_once_with(
|
mock_send.assert_called_once_with(
|
||||||
"Context", "Hello AI", ".", [], "History",
|
"Context", "Hello AI", ".", [], "History",
|
||||||
pre_tool_callback=ANY,
|
pre_tool_callback=ANY,
|
||||||
@@ -52,17 +46,17 @@ def test_user_request_integration_flow(mock_app: gui_2.App) -> None:
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
success = False
|
success = False
|
||||||
while time.time() - start_time < 3:
|
while time.time() - start_time < 3:
|
||||||
app._process_pending_gui_tasks()
|
app.controller._process_pending_gui_tasks()
|
||||||
if app.ai_response == mock_response and app.ai_status == "done":
|
if app.controller.ai_response == mock_response and app.controller.ai_status == "done":
|
||||||
success = True
|
success = True
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
assert success, f"UI state was not updated. ai_response: '{app.ai_response}', status: '{app.ai_status}'"
|
assert success, f"UI state was not updated. ai_response: '{app.controller.ai_response}', status: '{app.controller.ai_status}'"
|
||||||
assert app.ai_response == mock_response
|
assert app.controller.ai_response == mock_response
|
||||||
assert app.ai_status == "done"
|
assert app.controller.ai_status == "done"
|
||||||
|
|
||||||
@pytest.mark.timeout(10)
|
@pytest.mark.timeout(10)
|
||||||
def test_user_request_error_handling(mock_app: gui_2.App) -> None:
|
def test_user_request_error_handling(mock_app: App) -> None:
|
||||||
"""
|
"""
|
||||||
Verifies that if ai_client.send raises an exception, the UI is updated with the error state.
|
Verifies that if ai_client.send raises an exception, the UI is updated with the error state.
|
||||||
"""
|
"""
|
||||||
@@ -73,7 +67,7 @@ def test_user_request_error_handling(mock_app: gui_2.App) -> None:
|
|||||||
patch('src.ai_client.set_model_params'),
|
patch('src.ai_client.set_model_params'),
|
||||||
patch('src.ai_client.set_agent_tools')
|
patch('src.ai_client.set_agent_tools')
|
||||||
):
|
):
|
||||||
event = events.UserRequestEvent(
|
event = UserRequestEvent(
|
||||||
prompt="Trigger Error",
|
prompt="Trigger Error",
|
||||||
stable_md="",
|
stable_md="",
|
||||||
file_items=[],
|
file_items=[],
|
||||||
@@ -85,18 +79,18 @@ def test_user_request_error_handling(mock_app: gui_2.App) -> None:
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
success = False
|
success = False
|
||||||
while time.time() - start_time < 5:
|
while time.time() - start_time < 5:
|
||||||
app._process_pending_gui_tasks()
|
app.controller._process_pending_gui_tasks()
|
||||||
if app.ai_status == "error" and "ERROR: API Failure" in app.ai_response:
|
if app.controller.ai_status == "error" and "ERROR: API Failure" in app.controller.ai_response:
|
||||||
success = True
|
success = True
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
assert success, f"Error state was not reflected in UI. status: {app.ai_status}, response: {app.ai_response}"
|
assert success, f"Error state was not reflected in UI. status: {app.controller.ai_status}, response: {app.controller.ai_response}"
|
||||||
|
|
||||||
def test_api_gui_state_live(live_gui) -> None:
|
def test_api_gui_state_live(live_gui) -> None:
|
||||||
client = api_hook_client.ApiHookClient()
|
client = ApiHookClient()
|
||||||
client.set_value('current_provider', 'anthropic')
|
client.set_value('current_provider', 'anthropic')
|
||||||
client.set_value('current_model', 'claude-3-haiku-20240307')
|
client.set_value('current_model', 'claude-3-haiku-20240307')
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
success = False
|
success = False
|
||||||
while time.time() - start_time < 10:
|
while time.time() - start_time < 10:
|
||||||
@@ -105,7 +99,7 @@ def test_api_gui_state_live(live_gui) -> None:
|
|||||||
success = True
|
success = True
|
||||||
break
|
break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
assert success, f"GUI state did not update. Got: {client.get_gui_state()}"
|
assert success, f"GUI state did not update. Got: {client.get_gui_state()}"
|
||||||
final_state = client.get_gui_state()
|
final_state = client.get_gui_state()
|
||||||
assert final_state['current_provider'] == 'anthropic'
|
assert final_state['current_provider'] == 'anthropic'
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
|
|
||||||
from src import ai_client
|
|
||||||
from src import events
|
|
||||||
from src import models
|
|
||||||
from src import multi_agent_conductor
|
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from src import ai_client
|
|
||||||
from src import events
|
|
||||||
from src import models
|
|
||||||
from src import multi_agent_conductor
|
from src import multi_agent_conductor
|
||||||
|
from src.models import Ticket, WorkerContext
|
||||||
|
from src import events
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from typing import Generator, Any
|
||||||
|
|
||||||
:
|
class MockDialog:
|
||||||
def __init__(self, approved: bool, final_payload: dict | None = None) -> None:
|
def __init__(self, approved: bool, final_payload: dict | None = None) -> None:
|
||||||
self.approved = approved
|
self.approved = approved
|
||||||
self.final_payload = final_payload
|
self.final_payload = final_payload
|
||||||
@@ -22,7 +19,7 @@ from src import multi_agent_conductor
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_ai_client() -> None:
|
def mock_ai_client() -> Generator[MagicMock, None, None]:
|
||||||
with patch("src.ai_client.send") as mock_send:
|
with patch("src.ai_client.send") as mock_send:
|
||||||
mock_send.return_value = "Task completed"
|
mock_send.return_value = "Task completed"
|
||||||
yield mock_send
|
yield mock_send
|
||||||
@@ -38,10 +35,10 @@ def test_confirm_spawn_pushed_to_queue() -> None:
|
|||||||
def run_confirm():
|
def run_confirm():
|
||||||
res = multi_agent_conductor.confirm_spawn(role, prompt, context_md, event_queue, ticket_id)
|
res = multi_agent_conductor.confirm_spawn(role, prompt, context_md, event_queue, ticket_id)
|
||||||
results.append(res)
|
results.append(res)
|
||||||
|
|
||||||
t = threading.Thread(target=run_confirm)
|
t = threading.Thread(target=run_confirm)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
# Wait for the event to appear in the queue
|
# Wait for the event to appear in the queue
|
||||||
event_name, payload = event_queue.get()
|
event_name, payload = event_queue.get()
|
||||||
assert event_name == "mma_spawn_approval"
|
assert event_name == "mma_spawn_approval"
|
||||||
@@ -50,10 +47,10 @@ def test_confirm_spawn_pushed_to_queue() -> None:
|
|||||||
assert payload["prompt"] == prompt
|
assert payload["prompt"] == prompt
|
||||||
assert payload["context_md"] == context_md
|
assert payload["context_md"] == context_md
|
||||||
assert "dialog_container" in payload
|
assert "dialog_container" in payload
|
||||||
|
|
||||||
# Simulate GUI injecting a dialog
|
# Simulate GUI injecting a dialog
|
||||||
payload["dialog_container"][0] = MockDialog(True, {"prompt": "Modified Prompt", "context_md": "Modified Context"})
|
payload["dialog_container"][0] = MockDialog(True, {"prompt": "Modified Prompt", "context_md": "Modified Context"})
|
||||||
|
|
||||||
t.join(timeout=5)
|
t.join(timeout=5)
|
||||||
assert not t.is_alive()
|
assert not t.is_alive()
|
||||||
approved, final_prompt, final_context = results[0]
|
approved, final_prompt, final_context = results[0]
|
||||||
@@ -63,9 +60,9 @@ def test_confirm_spawn_pushed_to_queue() -> None:
|
|||||||
|
|
||||||
@patch("src.multi_agent_conductor.confirm_spawn")
|
@patch("src.multi_agent_conductor.confirm_spawn")
|
||||||
def test_run_worker_lifecycle_approved(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
|
def test_run_worker_lifecycle_approved(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
|
||||||
ticket = models.Ticket(id="T1", description="desc", status="todo", assigned_to="user")
|
ticket = Ticket(id="T1", description="desc", status="todo", assigned_to="user")
|
||||||
context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
|
context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
|
||||||
event_queue = app_instance.event_queue
|
event_queue = app_instance.controller.event_queue
|
||||||
mock_confirm.return_value = (True, "Modified Prompt", "Modified Context")
|
mock_confirm.return_value = (True, "Modified Prompt", "Modified Context")
|
||||||
multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
|
multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
|
||||||
mock_confirm.assert_called_once()
|
mock_confirm.assert_called_once()
|
||||||
@@ -77,9 +74,9 @@ def test_run_worker_lifecycle_approved(mock_confirm: MagicMock, mock_ai_client:
|
|||||||
|
|
||||||
@patch("src.multi_agent_conductor.confirm_spawn")
|
@patch("src.multi_agent_conductor.confirm_spawn")
|
||||||
def test_run_worker_lifecycle_rejected(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
|
def test_run_worker_lifecycle_rejected(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
|
||||||
ticket = models.Ticket(id="T1", description="desc", status="todo", assigned_to="user")
|
ticket = Ticket(id="T1", description="desc", status="todo", assigned_to="user")
|
||||||
context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
|
context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
|
||||||
event_queue = app_instance.event_queue
|
event_queue = app_instance.controller.event_queue
|
||||||
mock_confirm.return_value = (False, "Original Prompt", "Original Context")
|
mock_confirm.return_value = (False, "Original Prompt", "Original Context")
|
||||||
result = multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
|
result = multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
|
||||||
mock_confirm.assert_called_once()
|
mock_confirm.assert_called_once()
|
||||||
|
|||||||
Reference in New Issue
Block a user