never ends
This commit is contained in:
@@ -15,7 +15,7 @@ paths = [
|
|||||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_livetoolssim.toml",
|
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_livetoolssim.toml",
|
||||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_liveexecutionsim.toml",
|
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_liveexecutionsim.toml",
|
||||||
]
|
]
|
||||||
active = "C:\\projects\\manual_slop\\tests\\artifacts\\temp_livetoolssim.toml"
|
active = "C:\\projects\\manual_slop\\tests\\artifacts\\temp_project.toml"
|
||||||
|
|
||||||
[gui.show_windows]
|
[gui.show_windows]
|
||||||
"Context Hub" = true
|
"Context Hub" = true
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ active = "main"
|
|||||||
|
|
||||||
[discussions.main]
|
[discussions.main]
|
||||||
git_commit = ""
|
git_commit = ""
|
||||||
last_updated = "2026-03-05T20:14:45"
|
last_updated = "2026-03-05T20:31:48"
|
||||||
history = []
|
history = []
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ class ApiHookClient:
|
|||||||
headers = {}
|
headers = {}
|
||||||
if self.api_key:
|
if self.api_key:
|
||||||
headers["X-API-KEY"] = self.api_key
|
headers["X-API-KEY"] = self.api_key
|
||||||
|
|
||||||
if method not in ('GET', 'POST', 'DELETE'):
|
if method not in ('GET', 'POST', 'DELETE'):
|
||||||
raise ValueError(f"Unsupported HTTP method: {method}")
|
raise ValueError(f"Unsupported HTTP method: {method}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if method == 'GET':
|
if method == 'GET':
|
||||||
response = requests.get(url, headers=headers, timeout=timeout)
|
response = requests.get(url, headers=headers, timeout=timeout)
|
||||||
@@ -26,7 +24,6 @@ class ApiHookClient:
|
|||||||
response = requests.post(url, json=data, headers=headers, timeout=timeout)
|
response = requests.post(url, json=data, headers=headers, timeout=timeout)
|
||||||
elif method == 'DELETE':
|
elif method == 'DELETE':
|
||||||
response = requests.delete(url, headers=headers, timeout=timeout)
|
response = requests.delete(url, headers=headers, timeout=timeout)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
return None
|
return None
|
||||||
@@ -53,10 +50,9 @@ class ApiHookClient:
|
|||||||
return {}
|
return {}
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def post_project(self, project_data: dict) -> dict[str, Any]:
|
def post_project(self, project_data: dict) -> dict[str, Any]:
|
||||||
return self._make_request('POST', '/api/project', data=project_data) or {}
|
return self._make_request('POST', '/api/project', data=project_data) or {}
|
||||||
|
|
||||||
def get_project(self) -> dict[str, Any]:
|
def get_project(self) -> dict[str, Any]:
|
||||||
"""Retrieves the current project state."""
|
"""Retrieves the current project state."""
|
||||||
return self._make_request('GET', '/api/project') or {}
|
return self._make_request('GET', '/api/project') or {}
|
||||||
@@ -69,7 +65,6 @@ class ApiHookClient:
|
|||||||
"""Updates the session history."""
|
"""Updates the session history."""
|
||||||
return self._make_request('POST', '/api/session', data={"session": {"entries": session_entries}}) or {}
|
return self._make_request('POST', '/api/session', data={"session": {"entries": session_entries}}) or {}
|
||||||
|
|
||||||
|
|
||||||
def get_events(self) -> list[dict[str, Any]]:
|
def get_events(self) -> list[dict[str, Any]]:
|
||||||
res = self._make_request('GET', '/api/events')
|
res = self._make_request('GET', '/api/events')
|
||||||
return res.get("events", []) if res else []
|
return res.get("events", []) if res else []
|
||||||
@@ -111,12 +106,10 @@ class ApiHookClient:
|
|||||||
state = self.get_gui_state()
|
state = self.get_gui_state()
|
||||||
if item in state:
|
if item in state:
|
||||||
return state[item]
|
return state[item]
|
||||||
|
|
||||||
# Fallback for thinking/live/prior which are in diagnostics
|
# Fallback for thinking/live/prior which are in diagnostics
|
||||||
diag = self.get_gui_diagnostics()
|
diag = self.get_gui_diagnostics()
|
||||||
if diag and item in diag:
|
if diag and item in diag:
|
||||||
return diag[item]
|
return diag[item]
|
||||||
|
|
||||||
# Map common indicator tags to diagnostics keys
|
# Map common indicator tags to diagnostics keys
|
||||||
mapping = {
|
mapping = {
|
||||||
"thinking_indicator": "thinking",
|
"thinking_indicator": "thinking",
|
||||||
@@ -126,7 +119,6 @@ class ApiHookClient:
|
|||||||
key = mapping.get(item)
|
key = mapping.get(item)
|
||||||
if diag and key and key in diag:
|
if diag and key and key in diag:
|
||||||
return diag[key]
|
return diag[key]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_text_value(self, item_tag: str) -> str | None:
|
def get_text_value(self, item_tag: str) -> str | None:
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ class TestGeminiCliAdapterParity(unittest.TestCase):
|
|||||||
mock_process.communicate.return_value = ('{"type": "message", "content": "hi"}', '')
|
mock_process.communicate.return_value = ('{"type": "message", "content": "hi"}', '')
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
self.adapter.send("test", model="gemini-2.0-flash")
|
self.adapter.send("test", model="gemini-2.0-flash")
|
||||||
|
|
||||||
args, _ = mock_popen.call_args
|
args, _ = mock_popen.call_args
|
||||||
cmd_list = args[0]
|
cmd_list = args[0]
|
||||||
self.assertIn("-m", cmd_list)
|
self.assertIn("-m", cmd_list)
|
||||||
@@ -38,7 +36,6 @@ class TestGeminiCliAdapterParity(unittest.TestCase):
|
|||||||
"parameters": {"path": "."},
|
"parameters": {"path": "."},
|
||||||
"tool_id": "call_abc"
|
"tool_id": "call_abc"
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_process = MagicMock()
|
mock_process = MagicMock()
|
||||||
stdout_output = (
|
stdout_output = (
|
||||||
json.dumps(tool_call_json) + "\n" +
|
json.dumps(tool_call_json) + "\n" +
|
||||||
@@ -47,7 +44,6 @@ class TestGeminiCliAdapterParity(unittest.TestCase):
|
|||||||
mock_process.communicate.return_value = (stdout_output, '')
|
mock_process.communicate.return_value = (stdout_output, '')
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
result = self.adapter.send("msg")
|
result = self.adapter.send("msg")
|
||||||
self.assertEqual(len(result["tool_calls"]), 1)
|
self.assertEqual(len(result["tool_calls"]), 1)
|
||||||
self.assertEqual(result["tool_calls"][0]["name"], "list_directory")
|
self.assertEqual(result["tool_calls"][0]["name"], "list_directory")
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ from src import mcp_client
|
|||||||
def test_gemini_cli_context_bleed_prevention() -> None:
|
def test_gemini_cli_context_bleed_prevention() -> None:
|
||||||
import src.ai_client as ai_client
|
import src.ai_client as ai_client
|
||||||
ai_client._gemini_cli_adapter = None
|
ai_client._gemini_cli_adapter = None
|
||||||
|
|
||||||
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
||||||
adapter = GeminiCliAdapter()
|
adapter = GeminiCliAdapter()
|
||||||
|
|
||||||
mock_process = MagicMock()
|
mock_process = MagicMock()
|
||||||
stdout_output = (
|
stdout_output = (
|
||||||
'{"type": "message", "role": "user", "content": "Echoed user prompt"}' + "\n" +
|
'{"type": "message", "role": "user", "content": "Echoed user prompt"}' + "\n" +
|
||||||
@@ -19,17 +17,14 @@ def test_gemini_cli_context_bleed_prevention() -> None:
|
|||||||
mock_process.communicate.return_value = (stdout_output, '')
|
mock_process.communicate.return_value = (stdout_output, '')
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
result = adapter.send("msg")
|
result = adapter.send("msg")
|
||||||
assert result["text"] == "Model response"
|
assert result["text"] == "Model response"
|
||||||
|
|
||||||
def test_gemini_cli_parameter_resilience() -> None:
|
def test_gemini_cli_parameter_resilience() -> None:
|
||||||
from src import mcp_client
|
from src import mcp_client
|
||||||
|
|
||||||
with patch('src.mcp_client.read_file', return_value="content") as mock_read:
|
with patch('src.mcp_client.read_file', return_value="content") as mock_read:
|
||||||
mcp_client.dispatch("read_file", {"file_path": "aliased.txt"})
|
mcp_client.dispatch("read_file", {"file_path": "aliased.txt"})
|
||||||
mock_read.assert_called_once_with("aliased.txt")
|
mock_read.assert_called_once_with("aliased.txt")
|
||||||
|
|
||||||
with patch('src.mcp_client.list_directory', return_value="files") as mock_list:
|
with patch('src.mcp_client.list_directory', return_value="files") as mock_list:
|
||||||
mcp_client.dispatch("list_directory", {"dir_path": "aliased_dir"})
|
mcp_client.dispatch("list_directory", {"dir_path": "aliased_dir"})
|
||||||
mock_list.assert_called_once_with("aliased_dir")
|
mock_list.assert_called_once_with("aliased_dir")
|
||||||
@@ -37,14 +32,11 @@ def test_gemini_cli_parameter_resilience() -> None:
|
|||||||
def test_gemini_cli_loop_termination() -> None:
|
def test_gemini_cli_loop_termination() -> None:
|
||||||
import src.ai_client as ai_client
|
import src.ai_client as ai_client
|
||||||
ai_client._gemini_cli_adapter = None
|
ai_client._gemini_cli_adapter = None
|
||||||
|
|
||||||
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
||||||
mock_process = MagicMock()
|
mock_process = MagicMock()
|
||||||
mock_process.communicate.return_value = ('{"type": "message", "content": "Final answer", "tool_calls": []}', "")
|
mock_process.communicate.return_value = ('{"type": "message", "content": "Final answer", "tool_calls": []}', "")
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||||
|
|
||||||
result = ai_client.send("context", "prompt")
|
result = ai_client.send("context", "prompt")
|
||||||
assert result == "Final answer"
|
assert result == "Final answer"
|
||||||
|
|||||||
@@ -4,13 +4,11 @@ from unittest.mock import patch, MagicMock
|
|||||||
def test_send_invokes_adapter_send() -> None:
|
def test_send_invokes_adapter_send() -> None:
|
||||||
import src.ai_client as ai_client
|
import src.ai_client as ai_client
|
||||||
ai_client._gemini_cli_adapter = None
|
ai_client._gemini_cli_adapter = None
|
||||||
|
|
||||||
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
||||||
mock_process = MagicMock()
|
mock_process = MagicMock()
|
||||||
mock_process.communicate.return_value = ('{"type": "message", "content": "Hello from mock adapter"}', '')
|
mock_process.communicate.return_value = ('{"type": "message", "content": "Hello from mock adapter"}', '')
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
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"
|
||||||
@@ -18,13 +16,11 @@ def test_send_invokes_adapter_send() -> None:
|
|||||||
def test_get_history_bleed_stats() -> None:
|
def test_get_history_bleed_stats() -> None:
|
||||||
import src.ai_client as ai_client
|
import src.ai_client as ai_client
|
||||||
ai_client._gemini_cli_adapter = None
|
ai_client._gemini_cli_adapter = None
|
||||||
|
|
||||||
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
with patch('src.gemini_cli_adapter.subprocess.Popen') as mock_popen:
|
||||||
mock_process = MagicMock()
|
mock_process = MagicMock()
|
||||||
mock_process.communicate.return_value = ('{"type": "message", "content": "txt"}', '')
|
mock_process.communicate.return_value = ('{"type": "message", "content": "txt"}', '')
|
||||||
mock_process.returncode = 0
|
mock_process.returncode = 0
|
||||||
mock_popen.return_value = mock_process
|
mock_popen.return_value = mock_process
|
||||||
|
|
||||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||||
ai_client.send("context", "msg")
|
ai_client.send("context", "msg")
|
||||||
stats = ai_client.get_history_bleed_stats()
|
stats = ai_client.get_history_bleed_stats()
|
||||||
|
|||||||
@@ -11,38 +11,28 @@ from src import ai_client
|
|||||||
|
|
||||||
def test_token_usage_tracking() -> None:
|
def test_token_usage_tracking() -> None:
|
||||||
ai_client.reset_session()
|
ai_client.reset_session()
|
||||||
|
|
||||||
with patch("src.ai_client._ensure_gemini_client"), \
|
with patch("src.ai_client._ensure_gemini_client"), \
|
||||||
patch("src.ai_client._gemini_client") as mock_client:
|
patch("src.ai_client._gemini_client") as mock_client:
|
||||||
|
|
||||||
mock_chat = MagicMock()
|
mock_chat = MagicMock()
|
||||||
mock_client.chats.create.return_value = mock_chat
|
mock_client.chats.create.return_value = mock_chat
|
||||||
|
|
||||||
mock_usage = SimpleNamespace(
|
mock_usage = SimpleNamespace(
|
||||||
prompt_token_count=100,
|
prompt_token_count=100,
|
||||||
candidates_token_count=50,
|
candidates_token_count=50,
|
||||||
total_token_count=150,
|
total_token_count=150,
|
||||||
cached_content_token_count=20
|
cached_content_token_count=20
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_part = SimpleNamespace(text="Mock Response", function_call=None)
|
mock_part = SimpleNamespace(text="Mock Response", function_call=None)
|
||||||
mock_content = SimpleNamespace(parts=[mock_part])
|
mock_content = SimpleNamespace(parts=[mock_part])
|
||||||
|
|
||||||
mock_candidate = SimpleNamespace()
|
mock_candidate = SimpleNamespace()
|
||||||
mock_candidate.content = mock_content
|
mock_candidate.content = mock_content
|
||||||
mock_candidate.finish_reason = SimpleNamespace(name="STOP")
|
mock_candidate.finish_reason = SimpleNamespace(name="STOP")
|
||||||
|
|
||||||
mock_response = SimpleNamespace()
|
mock_response = SimpleNamespace()
|
||||||
mock_response.candidates = [mock_candidate]
|
mock_response.candidates = [mock_candidate]
|
||||||
mock_response.usage_metadata = mock_usage
|
mock_response.usage_metadata = mock_usage
|
||||||
mock_response.text = "Mock Response"
|
mock_response.text = "Mock Response"
|
||||||
|
|
||||||
mock_chat.send_message.return_value = mock_response
|
mock_chat.send_message.return_value = mock_response
|
||||||
|
|
||||||
ai_client.set_provider("gemini", "gemini-2.5-flash-lite")
|
ai_client.set_provider("gemini", "gemini-2.5-flash-lite")
|
||||||
|
|
||||||
ai_client.send("Context", "Hello")
|
ai_client.send("Context", "Hello")
|
||||||
|
|
||||||
comms = ai_client.get_comms_log()
|
comms = ai_client.get_comms_log()
|
||||||
response_entries = [e for e in comms if e.get("direction") == "IN" and e["kind"] == "response"]
|
response_entries = [e for e in comms if e.get("direction") == "IN" and e["kind"] == "response"]
|
||||||
assert len(response_entries) > 0
|
assert len(response_entries) > 0
|
||||||
|
|||||||
Reference in New Issue
Block a user