Skip to content

Commit c0dc4f0

Browse files
liuzhengyang699codelion
authored andcommitted
fix(mars): match solution authors across string and integer IDs
1 parent 5ea4efc commit c0dc4f0

2 files changed

Lines changed: 96 additions & 6 deletions

File tree

‎optillm/mars/verifier.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,17 +178,19 @@ def _verify_single_solution(self, solution: AgentSolution, request_id: str = Non
178178
]
179179
}
180180

181-
def _select_verifier_agent(self, solution_agent_id: int) -> MARSAgent:
181+
def _select_verifier_agent(self, solution_agent_id: str | int) -> MARSAgent:
182182
"""Select an agent different from the solution creator for verification"""
183-
available_agents = [agent for agent in self.agents if agent.agent_id != solution_agent_id]
183+
# Solutions store string IDs, while the reasoning agents use integers.
184+
solution_agent_id = str(solution_agent_id)
185+
available_agents = [agent for agent in self.agents if str(agent.agent_id) != solution_agent_id]
184186
if not available_agents:
185187
# If no other agents available, use any agent
186188
available_agents = self.agents
187189

188190
# Prefer agents with different temperatures for diverse verification
189191
if len(available_agents) > 1:
190192
# Select agent with most different temperature
191-
solution_agent = next((a for a in self.agents if a.agent_id == solution_agent_id), None)
193+
solution_agent = next((a for a in self.agents if str(a.agent_id) == solution_agent_id), None)
192194
if solution_agent:
193195
solution_temp = solution_agent.temperature
194196
available_agents.sort(key=lambda a: abs(a.temperature - solution_temp), reverse=True)
@@ -215,7 +217,7 @@ def iterative_improvement(self, request_id: str = None) -> Dict[str, Any]:
215217

216218
if latest_verification['assessment'] in ['INCORRECT', 'INCOMPLETE']:
217219
# Find the original agent to improve their solution
218-
original_agent = next((a for a in self.agents if a.agent_id == solution.agent_id), None)
220+
original_agent = next((a for a in self.agents if str(a.agent_id) == str(solution.agent_id)), None)
219221

220222
if original_agent:
221223
try:
@@ -267,7 +269,7 @@ async def iterative_improvement_parallel(
267269
if solution.verification_results:
268270
latest_verification = solution.verification_results[-1]
269271
if latest_verification['assessment'] in ['INCORRECT', 'INCOMPLETE']:
270-
original_agent = next((a for a in self.agents if a.agent_id == solution.agent_id), None)
272+
original_agent = next((a for a in self.agents if str(a.agent_id) == str(solution.agent_id)), None)
271273
if original_agent:
272274
improvable_solutions.append((solution, original_agent, latest_verification))
273275

@@ -340,4 +342,4 @@ def final_consensus_check(self) -> bool:
340342
else:
341343
logger.info(f"No consensus: only {len(verified_solutions)} solutions verified (need {consensus_threshold})")
342344

343-
return has_consensus
345+
return has_consensus

‎tests/test_mars_agent_routing.py‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""Generated solutions must be verified by peers and refined by their author."""
2+
3+
import asyncio
4+
from types import SimpleNamespace
5+
from unittest.mock import Mock
6+
7+
import pytest
8+
9+
from optillm.mars.agent import MARSAgent
10+
from optillm.mars.verifier import MARSVerifier
11+
from optillm.mars.workspace import MARSWorkspace
12+
13+
14+
def response(text, reasoning_tokens=7):
15+
return SimpleNamespace(
16+
choices=[SimpleNamespace(message=SimpleNamespace(content=text))],
17+
usage=SimpleNamespace(total_tokens=20, reasoning_tokens=reasoning_tokens),
18+
)
19+
20+
21+
@pytest.mark.parametrize("parallel", [False, True])
22+
@pytest.mark.parametrize("author_id,verifier_id", [(0, 2), (1, 2), (2, 0)])
23+
def test_generated_solution_is_verified_and_improved_by_the_right_agents(
24+
parallel, author_id, verifier_id
25+
):
26+
config = {"max_tokens": 100, "max_verification_attempts": 1}
27+
workspace = MARSWorkspace("Solve 2x + 5 = 15.", config)
28+
feedback = "INCORRECT: the subtraction is wrong. Subtract 5 before dividing."
29+
agents = [MARSAgent(i, Mock(), "test-model", config) for i in range(3)]
30+
for agent in agents:
31+
agent.client.chat.completions.create.return_value = response(feedback)
32+
33+
author = agents[author_id]
34+
author.client.chat.completions.create.side_effect = [
35+
response("The answer is 10."),
36+
response("The answer is 5.", reasoning_tokens=11),
37+
]
38+
solution, _ = author.generate_solution(workspace.problem)
39+
assert solution.agent_id == str(author_id)
40+
workspace.add_solution(solution)
41+
verifier = MARSVerifier(agents, workspace, config)
42+
43+
if parallel:
44+
verification = asyncio.run(verifier.verify_solutions_parallel())
45+
else:
46+
verification = verifier.verify_solutions()
47+
48+
detail = verification["verification_details"][0]
49+
assert detail["verification_results"][0]["verifier_id"] == verifier_id
50+
assert solution.verification_results[-1]["assessment"] == "INCORRECT"
51+
52+
if parallel:
53+
improvement = asyncio.run(verifier.iterative_improvement_parallel())
54+
else:
55+
improvement = verifier.iterative_improvement()
56+
57+
assert improvement == {
58+
"solutions_improved": 1,
59+
"improvement_attempts": 1,
60+
"total_reasoning_tokens": 11,
61+
}
62+
assert solution.solution == "The answer is 5."
63+
assert solution.reasoning_tokens == 18
64+
assert author.client.chat.completions.create.call_count == 2
65+
prompt = author.client.chat.completions.create.call_args.kwargs["messages"][1]["content"]
66+
assert "The answer is 10." in prompt
67+
assert feedback in prompt
68+
for agent in agents:
69+
if agent.agent_id not in (author_id, verifier_id):
70+
agent.client.chat.completions.create.assert_not_called()
71+
72+
73+
@pytest.mark.parametrize("author_id,verifier_id", [(0, 2), (1, 2), (2, 0)])
74+
def test_integer_ids_still_choose_a_peer_with_a_different_temperature(author_id, verifier_id):
75+
agents = [MARSAgent(i, Mock(), "test-model", {}) for i in range(3)]
76+
verifier = MARSVerifier(agents, MARSWorkspace("problem", {}), {})
77+
78+
assert verifier._select_verifier_agent(author_id) is agents[verifier_id]
79+
80+
81+
def test_aggregated_and_single_agent_solutions_keep_the_fallback():
82+
agent = MARSAgent(0, Mock(), "test-model", {})
83+
workspace = MARSWorkspace("problem", {})
84+
verifier = MARSVerifier([agent], workspace, {})
85+
86+
assert verifier._select_verifier_agent("0") is agent
87+
assert verifier._select_verifier_agent("agg_123456") is agent
88+
assert MARSVerifier([], workspace, {})._select_verifier_agent("0") is None

0 commit comments

Comments
 (0)