Skip to content

Commit 55cd8bc

Browse files
Lumi-nodeclaude
andcommitted
Fix arena examples and tie handling
- Warriors now have overlapping domains so trials actually fire - Ties default to warlord (defender's advantage) - Mock warriors produce random latency for differentiation - Clean up TheArena themed output (less verbose) - Fix quick_battle reasoning display (single line) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 14b4133 commit 55cd8bc

5 files changed

Lines changed: 58 additions & 45 deletions

File tree

examples/quick_battle.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import asyncio
99
from orc import Warrior, Elder, TheArena
10-
from orc.judges import MetricsJudge
1110

1211

1312
async def main():
@@ -18,80 +17,81 @@ async def main():
1817
print("=" * 60)
1918
print()
2019

21-
# Create three Warriors with mock LLM clients (just strings)
20+
# Create three Warriors with OVERLAPPING domains
21+
# Domain overlap is what triggers challenges and trials!
2222
warriors = [
2323
Warrior(
2424
name="Grok",
25-
llm_client="mock_llm_1",
26-
system_prompt="You are a powerful orc warrior with exceptional strength.",
27-
temperature=0.5,
25+
llm_client="mock",
26+
system_prompt="You are a powerful orc warrior.",
2827
capabilities=["melee_combat", "strategy", "leadership"],
29-
domains=["combat", "tactics"],
28+
domains=["combat", "strategy"], # overlaps with Thrall on combat
3029
),
3130
Warrior(
3231
name="Thrall",
33-
llm_client="mock_llm_2",
34-
system_prompt="You are a wise orc shaman with magical powers.",
35-
temperature=0.3,
36-
capabilities=["magic", "healing", "elemental_control"],
37-
domains=["magic", "healing"],
32+
llm_client="mock",
33+
system_prompt="You are a wise orc shaman.",
34+
capabilities=["magic", "healing", "combat_magic"],
35+
domains=["combat", "magic"], # overlaps with Grok on combat, Sylvanas on magic
3836
),
3937
Warrior(
4038
name="Sylvanas",
41-
llm_client="mock_llm_3",
42-
system_prompt="You are a skilled orc ranger with unmatched archery.",
43-
temperature=0.6,
44-
capabilities=["archery", "stealth", "tracking"],
45-
domains=["ranged_combat", "hunting"],
39+
llm_client="mock",
40+
system_prompt="You are a cunning dark ranger.",
41+
capabilities=["archery", "dark_magic", "tactics"],
42+
domains=["combat", "magic", "strategy"], # overlaps with everyone
4643
),
4744
]
4845

49-
print(f"Warriors registered: {', '.join(w.name for w in warriors)}")
50-
print()
46+
print(f"Warriors: {', '.join(w.name for w in warriors)}")
47+
print(f"All three claim the 'combat' domain - expect blood!\n")
5148

52-
# Create an Elder judge (uses MetricsJudge by default)
49+
# Create an Elder judge (defaults to MetricsJudge)
5350
elder = Elder(
5451
evaluator_model="metrics_judge",
5552
evaluation_criteria="Evaluate based on accuracy and speed.",
5653
)
57-
print(f"Elder ready to judge")
58-
print()
5954

60-
# Create The Arena
55+
# Create The Arena with HIGH challenge probability for this demo
6156
arena = TheArena(
6257
warriors=warriors,
6358
elder=elder,
64-
challenge_probability=0.4,
59+
challenge_probability=0.8, # 80% chance of challenge when domains overlap
6560
)
6661

67-
# Run a few battles
62+
# Run battles - with overlapping domains, challenges WILL happen
6863
challenges = [
69-
"Defeat the invading army",
70-
"Retrieve the lost artifact",
71-
"Protect the village from darkness",
64+
"Lead the charge against the enemy fortress",
65+
"Cast a devastating spell on the battlefield",
66+
"Plan the siege of the northern stronghold",
67+
"Defend the war camp from a surprise attack",
68+
"Duel the enemy champion in single combat",
7269
]
7370

7471
for challenge in challenges:
7572
print(f"\n--- CHALLENGE: {challenge} ---")
7673
result = await arena.battle(challenge)
77-
print(f"Victory: {result.winner}")
78-
if result.verdict:
79-
print(f"Reasoning: {result.verdict.reasoning[:80]}...")
74+
if result.was_challenged and result.verdict:
75+
reason = result.verdict.reasoning.split("\n")[0][:80]
76+
print(f" TRIAL: {reason}")
77+
print(f" Victor: {result.winner}")
8078

79+
# Show final standings
8180
print("\n" + "=" * 60)
82-
print("LEADERBOARD")
81+
print("FINAL STANDINGS")
8382
print("=" * 60)
8483

85-
# Show leaderboard for each domain
86-
for domain in ["combat", "magic", "ranged_combat"]:
84+
for domain in ["combat", "magic", "strategy"]:
8785
leaderboard = arena.get_leaderboard(domain)
88-
print(f"\n{domain.upper()} DOMAIN:")
89-
for entry in leaderboard:
90-
status = " (Warlord)" if entry["is_warlord"] else ""
91-
print(
92-
f" {entry['agent']}: rep={entry['reputation']:.2f}, "
93-
f"wins={entry['wins']}, losses={entry['losses']}{status}"
94-
)
86+
if leaderboard:
87+
print(f"\n {domain.upper()} DOMAIN:")
88+
for i, entry in enumerate(leaderboard):
89+
crown = " [WARCHIEF]" if entry["is_warlord"] else ""
90+
print(
91+
f" {i+1}. {entry['agent']:12s} "
92+
f"Rep: {entry['reputation']:.2f} "
93+
f"W:{entry['wins']} L:{entry['losses']}{crown}"
94+
)
9595

9696
print("\n" + "=" * 60)
9797
print("Battle complete!")

orc/arena/trial.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ async def execute(self) -> TrialResult:
170170
# Judge evaluates
171171
verdict = await self.judge.evaluate(self.task, submissions)
172172

173-
# Determine winner
173+
# Determine winner (ties go to the defending warlord)
174174
winner = verdict.winner
175+
if verdict.is_tie or winner not in (self.warlord.name, self.challenger.name):
176+
winner = self.warlord.name
175177
winner_result = (
176178
warlord_result if winner == self.warlord.name else challenger_result
177179
)

orc/themed/the_arena.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,8 @@ def _themed_on_succession(self, old_warlord: str, new_warlord: str, domain: str)
117117

118118
def _themed_on_trial_complete(self, verdict: Any):
119119
"""Themed output when a trial completes."""
120-
print(f"\n⚖️ The Elder has spoken. Verdict: {verdict.reasoning[:100]}...")
120+
winner = verdict.winner
121+
if verdict.is_tie:
122+
print(f" ⚖️ The Elder declares a TIE — Warchief retains the throne!")
123+
else:
124+
print(f" ⚖️ The Elder has spoken: {winner} prevails!")

orc/themed/warrior.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
Each Warrior has a name, LLM client, system prompt, and capabilities.
66
"""
77

8+
import random
89
from typing import Any, Dict, List, Optional, Union
910

1011
from dynabots_core import TaskResult
@@ -91,13 +92,15 @@ async def process_task(
9192

9293
try:
9394
if isinstance(self.llm_client, str):
94-
# Mock mode: return success without calling LLM
95+
# Mock mode: simulate variable performance
96+
duration = random.randint(50, 500)
9597
return TaskResult.success(
9698
task_id=task_id,
9799
data={
98100
"response": f"Warrior {self.name} processed task: {task_description}",
99101
"model": self.llm_client,
100102
},
103+
duration_ms=duration,
101104
)
102105

103106
# Real LLM mode: call the provider

tests/test_trial.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ async def test_trial_result_winner_result(
9797

9898
assert result.winner_result is not None
9999
# Winner is determined by judge's verdict
100-
if result.verdict.winner == mock_agent_fast.name:
100+
# Ties or unrecognized names default to warlord (defender's advantage)
101+
if result.winner == mock_agent_fast.name:
101102
assert result.winner_result == result.warlord_result
102-
else:
103+
elif result.winner == mock_agent_slow.name:
103104
assert result.winner_result == result.challenger_result
105+
else:
106+
# Tie or fallback — warlord retains
107+
assert result.winner_result == result.warlord_result
104108

105109

106110
class TestTimeoutHandling:

0 commit comments

Comments
 (0)