Merge origin/main into pr-27248 (resolving run_agent.py = ours)

run_agent.py taken from HEAD (the extracted forwarder structure). The 25
run_agent.py fixes that landed on main during the PR's life need to be
ported into the agent/* extracted modules in follow-up commits.
This commit is contained in:
teknium1
2026-05-16 23:16:52 -07:00
355 changed files with 32716 additions and 4195 deletions
+104 -2
View File
@@ -2269,6 +2269,60 @@ class TestParallelScopePathNormalization:
assert not _should_parallelize_tool_batch([tc1, tc2])
class TestMcpParallelToolBatch:
"""Integration test: _should_parallelize_tool_batch respects MCP parallel flag."""
def test_mcp_tools_default_sequential(self):
"""MCP tools without supports_parallel_tool_calls are sequential."""
from run_agent import _should_parallelize_tool_batch
tc1 = _mock_tool_call(name="mcp_github_list_repos", arguments='{"org":"openai"}', call_id="c1")
tc2 = _mock_tool_call(name="mcp_github_search_code", arguments='{"q":"test"}', call_id="c2")
assert not _should_parallelize_tool_batch([tc1, tc2])
def test_mcp_tools_parallel_when_server_opted_in(self):
"""MCP tools from a parallel-safe server can run concurrently."""
from run_agent import _should_parallelize_tool_batch
from tools.mcp_tool import _parallel_safe_servers, _lock
with _lock:
_parallel_safe_servers.add("github")
try:
tc1 = _mock_tool_call(name="mcp_github_list_repos", arguments='{"org":"openai"}', call_id="c1")
tc2 = _mock_tool_call(name="mcp_github_search_code", arguments='{"q":"test"}', call_id="c2")
assert _should_parallelize_tool_batch([tc1, tc2])
finally:
with _lock:
_parallel_safe_servers.discard("github")
def test_mixed_mcp_and_builtin_parallel(self):
"""MCP parallel tools mixed with built-in parallel-safe tools."""
from run_agent import _should_parallelize_tool_batch
from tools.mcp_tool import _parallel_safe_servers, _lock
with _lock:
_parallel_safe_servers.add("docs")
try:
tc1 = _mock_tool_call(name="mcp_docs_search", arguments='{"query":"api"}', call_id="c1")
tc2 = _mock_tool_call(name="web_search", arguments='{"query":"test"}', call_id="c2")
assert _should_parallelize_tool_batch([tc1, tc2])
finally:
with _lock:
_parallel_safe_servers.discard("docs")
def test_mixed_parallel_and_serial_mcp_servers(self):
"""One parallel MCP server + one non-parallel MCP server = sequential."""
from run_agent import _should_parallelize_tool_batch
from tools.mcp_tool import _parallel_safe_servers, _lock
with _lock:
_parallel_safe_servers.add("docs")
# "github" is NOT in _parallel_safe_servers
try:
tc1 = _mock_tool_call(name="mcp_docs_search", arguments='{"query":"api"}', call_id="c1")
tc2 = _mock_tool_call(name="mcp_github_list_repos", arguments='{"org":"openai"}', call_id="c2")
assert not _should_parallelize_tool_batch([tc1, tc2])
finally:
with _lock:
_parallel_safe_servers.discard("docs")
class TestHandleMaxIterations:
def test_returns_summary(self, agent):
resp = _mock_response(content="Here is a summary of what I did.")
@@ -2524,8 +2578,9 @@ class TestRunConversation:
assert [call["api_call_count"] for call in pre_request_calls] == [1, 2]
assert [call["api_call_count"] for call in post_request_calls] == [1, 2]
assert all(call["session_id"] == agent.session_id for call in pre_request_calls)
assert all("message_count" in c and "messages" not in c for c in pre_request_calls)
assert all("usage" in c and "response" not in c for c in post_request_calls)
assert all("message_count" in c and isinstance(c.get("request_messages"), list) for c in pre_request_calls)
assert any(msg.get("role") == "user" and msg.get("content") == "search something" for msg in pre_request_calls[0]["request_messages"])
assert all("usage" in c and "response" in c and "assistant_message" in c for c in post_request_calls)
def test_content_with_tool_calls_stays_silent_for_non_cli_quiet_mode(self, agent):
self._setup_agent(agent)
@@ -3691,6 +3746,37 @@ class TestCredentialPoolRecovery:
assert retry_same is False
agent._swap_credential.assert_called_once_with(next_entry)
def test_recover_with_pool_rotates_usage_limit_429_immediately(self, agent):
next_entry = SimpleNamespace(label="secondary")
captured = {}
class _Pool:
def current(self):
return SimpleNamespace(label="primary")
def mark_exhausted_and_rotate(self, *, status_code, error_context=None):
captured["status_code"] = status_code
captured["error_context"] = error_context
return next_entry
agent._credential_pool = _Pool()
agent._swap_credential = MagicMock()
recovered, retry_same = agent._recover_with_credential_pool(
status_code=429,
has_retried_429=False,
error_context={
"reason": "usage_limit_reached",
"message": "The usage limit has been reached",
},
)
assert recovered is True
assert retry_same is False
assert captured["status_code"] == 429
assert captured["error_context"]["reason"] == "usage_limit_reached"
agent._swap_credential.assert_called_once_with(next_entry)
def test_recover_with_pool_refreshes_on_401(self, agent):
"""401 with successful refresh should swap to refreshed credential."""
@@ -3777,6 +3863,22 @@ class TestCredentialPoolRecovery:
assert context["message"] == "Weekly credits exhausted."
assert context["reset_at"] == "2026-04-12T10:30:00Z"
def test_extract_api_error_context_uses_type_as_reason(self, agent):
error = SimpleNamespace(
body={
"error": {
"type": "usage_limit_reached",
"message": "The usage limit has been reached",
}
},
response=SimpleNamespace(headers={}),
)
context = agent._extract_api_error_context(error)
assert context["reason"] == "usage_limit_reached"
assert context["message"] == "The usage limit has been reached"
def test_recover_with_pool_passes_error_context_on_rotated_429(self, agent):
next_entry = SimpleNamespace(label="secondary")
captured = {}