adversarial-workflow 0.6.3__tar.gz → 0.6.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/PKG-INFO +2 -2
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/__init__.py +1 -1
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/cli.py +49 -131
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/discovery.py +5 -15
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/runner.py +2 -7
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/evaluate_plan.sh.template +1 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/proofread_content.sh.template +1 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/review_implementation.sh.template +1 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/validate_tests.sh.template +1 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/config.py +1 -3
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/file_splitter.py +2 -6
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/validation.py +1 -3
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/PKG-INFO +2 -2
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/pyproject.toml +2 -2
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_cli_dynamic_commands.py +4 -12
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_env_loading.py +1 -3
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_evaluate.py +3 -9
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_evaluator_discovery.py +1 -3
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_list_evaluators.py +2 -6
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/LICENSE +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/README.md +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/__main__.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/__init__.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/builtins.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/config.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/.aider.conf.yml.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/.env.example.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/README.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/agent-context/AGENT-SYSTEM-GUIDE.md +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/agent-context/README.md.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/agent-context/agent-handoffs-minimal.json.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/agent-context/agent-handoffs.json.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/agent-context/current-state.json.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/config.yml.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/templates/example-task.md.template +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/__init__.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/colors.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/SOURCES.txt +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/dependency_links.txt +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/entry_points.txt +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/requires.txt +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/top_level.txt +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/setup.cfg +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/setup.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_cli.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_config.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_evaluator_config.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_evaluator_runner.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_file_splitter.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_python_version.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_scripts_project.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_split_command.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_timeout_integration.py +0 -0
- {adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_utils_validation.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adversarial-workflow
|
|
3
|
-
Version: 0.6.
|
|
4
|
-
Summary: Multi-stage AI
|
|
3
|
+
Version: 0.6.5
|
|
4
|
+
Summary: Multi-stage AI evaluation system for task plans, code review, and test validation
|
|
5
5
|
Author: Fredrik Matheson
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/movito/adversarial-workflow
|
|
@@ -29,7 +29,7 @@ from typing import Dict, List, Optional, Tuple
|
|
|
29
29
|
import yaml
|
|
30
30
|
from dotenv import dotenv_values, load_dotenv
|
|
31
31
|
|
|
32
|
-
__version__ = "0.6.
|
|
32
|
+
__version__ = "0.6.5"
|
|
33
33
|
|
|
34
34
|
# ANSI color codes for better output
|
|
35
35
|
RESET = "\033[0m"
|
|
@@ -180,7 +180,9 @@ def create_env_file_interactive(
|
|
|
180
180
|
env_content += "# DO NOT COMMIT THIS FILE\n\n"
|
|
181
181
|
|
|
182
182
|
if anthropic_key:
|
|
183
|
-
env_content +=
|
|
183
|
+
env_content += (
|
|
184
|
+
f"# Anthropic API Key (Claude 3.5 Sonnet)\nANTHROPIC_API_KEY={anthropic_key}\n\n"
|
|
185
|
+
)
|
|
184
186
|
|
|
185
187
|
if openai_key:
|
|
186
188
|
env_content += f"# OpenAI API Key (GPT-4o)\nOPENAI_API_KEY={openai_key}\n\n"
|
|
@@ -255,9 +257,7 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
255
257
|
],
|
|
256
258
|
)
|
|
257
259
|
|
|
258
|
-
anthropic_key = prompt_user(
|
|
259
|
-
"Paste your Anthropic API key (or Enter to skip)", secret=True
|
|
260
|
-
)
|
|
260
|
+
anthropic_key = prompt_user("Paste your Anthropic API key (or Enter to skip)", secret=True)
|
|
261
261
|
|
|
262
262
|
if anthropic_key:
|
|
263
263
|
is_valid, message = validate_api_key(anthropic_key, "anthropic")
|
|
@@ -281,9 +281,7 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
281
281
|
],
|
|
282
282
|
)
|
|
283
283
|
|
|
284
|
-
openai_key = prompt_user(
|
|
285
|
-
"Paste your OpenAI API key (or Enter to skip)", secret=True
|
|
286
|
-
)
|
|
284
|
+
openai_key = prompt_user("Paste your OpenAI API key (or Enter to skip)", secret=True)
|
|
287
285
|
|
|
288
286
|
if openai_key:
|
|
289
287
|
is_valid, message = validate_api_key(openai_key, "openai")
|
|
@@ -613,9 +611,7 @@ def init(project_path: str = ".", interactive: bool = True) -> int:
|
|
|
613
611
|
print(" 3. Then run: adversarial init")
|
|
614
612
|
print()
|
|
615
613
|
print(f"{BOLD}HELP:{RESET}")
|
|
616
|
-
print(
|
|
617
|
-
" New to git? https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"
|
|
618
|
-
)
|
|
614
|
+
print(" New to git? https://git-scm.com/book/en/v2/Getting-Started-Installing-Git")
|
|
619
615
|
return 1
|
|
620
616
|
|
|
621
617
|
# Pre-flight validation: Check package integrity
|
|
@@ -649,9 +645,7 @@ def init(project_path: str = ".", interactive: bool = True) -> int:
|
|
|
649
645
|
print(f" • {template}")
|
|
650
646
|
print()
|
|
651
647
|
print(f"{BOLD}FIX:{RESET}")
|
|
652
|
-
print(
|
|
653
|
-
" 1. Report this issue: https://github.com/movito/adversarial-workflow/issues"
|
|
654
|
-
)
|
|
648
|
+
print(" 1. Report this issue: https://github.com/movito/adversarial-workflow/issues")
|
|
655
649
|
print(
|
|
656
650
|
" 2. Or try reinstalling: pip install --upgrade --force-reinstall adversarial-workflow"
|
|
657
651
|
)
|
|
@@ -1030,13 +1024,9 @@ def check() -> int:
|
|
|
1030
1024
|
else:
|
|
1031
1025
|
status_parts = []
|
|
1032
1026
|
if error_count > 0:
|
|
1033
|
-
status_parts.append(
|
|
1034
|
-
f"{error_count} error" + ("s" if error_count != 1 else "")
|
|
1035
|
-
)
|
|
1027
|
+
status_parts.append(f"{error_count} error" + ("s" if error_count != 1 else ""))
|
|
1036
1028
|
if warning_count > 0:
|
|
1037
|
-
status_parts.append(
|
|
1038
|
-
f"{warning_count} warning" + ("s" if warning_count != 1 else "")
|
|
1039
|
-
)
|
|
1029
|
+
status_parts.append(f"{warning_count} warning" + ("s" if warning_count != 1 else ""))
|
|
1040
1030
|
if info_count > 0:
|
|
1041
1031
|
status_parts.append(f"{info_count} info")
|
|
1042
1032
|
|
|
@@ -1088,20 +1078,14 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1088
1078
|
# Helper functions for tracking check results
|
|
1089
1079
|
def check_pass(category: str, message: str, detail: str = None):
|
|
1090
1080
|
nonlocal passed
|
|
1091
|
-
results[category].append(
|
|
1092
|
-
{"status": "pass", "message": message, "detail": detail}
|
|
1093
|
-
)
|
|
1081
|
+
results[category].append({"status": "pass", "message": message, "detail": detail})
|
|
1094
1082
|
if not json_output:
|
|
1095
1083
|
print(f" {GREEN}✅{RESET} {message}")
|
|
1096
1084
|
passed += 1
|
|
1097
1085
|
|
|
1098
|
-
def check_warn(
|
|
1099
|
-
category: str, message: str, detail: str = None, recommendation: str = None
|
|
1100
|
-
):
|
|
1086
|
+
def check_warn(category: str, message: str, detail: str = None, recommendation: str = None):
|
|
1101
1087
|
nonlocal warnings
|
|
1102
|
-
results[category].append(
|
|
1103
|
-
{"status": "warn", "message": message, "detail": detail}
|
|
1104
|
-
)
|
|
1088
|
+
results[category].append({"status": "warn", "message": message, "detail": detail})
|
|
1105
1089
|
if not json_output:
|
|
1106
1090
|
print(f" {YELLOW}⚠️{RESET} {message}")
|
|
1107
1091
|
if detail and verbose:
|
|
@@ -1110,9 +1094,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1110
1094
|
recommendations.append(recommendation)
|
|
1111
1095
|
warnings += 1
|
|
1112
1096
|
|
|
1113
|
-
def check_fail(
|
|
1114
|
-
category: str, message: str, fix: str = None, recommendation: str = None
|
|
1115
|
-
):
|
|
1097
|
+
def check_fail(category: str, message: str, fix: str = None, recommendation: str = None):
|
|
1116
1098
|
nonlocal errors
|
|
1117
1099
|
results[category].append({"status": "fail", "message": message, "fix": fix})
|
|
1118
1100
|
if not json_output:
|
|
@@ -1124,9 +1106,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1124
1106
|
errors += 1
|
|
1125
1107
|
|
|
1126
1108
|
def check_info(category: str, message: str, detail: str = None):
|
|
1127
|
-
results[category].append(
|
|
1128
|
-
{"status": "info", "message": message, "detail": detail}
|
|
1129
|
-
)
|
|
1109
|
+
results[category].append({"status": "info", "message": message, "detail": detail})
|
|
1130
1110
|
if not json_output:
|
|
1131
1111
|
print(f" {CYAN}ℹ️{RESET} {message}")
|
|
1132
1112
|
if detail and verbose:
|
|
@@ -1258,23 +1238,13 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1258
1238
|
)
|
|
1259
1239
|
if git_status.returncode == 0:
|
|
1260
1240
|
modified = len(
|
|
1261
|
-
[
|
|
1262
|
-
l
|
|
1263
|
-
for l in git_status.stdout.splitlines()
|
|
1264
|
-
if l.startswith(" M")
|
|
1265
|
-
]
|
|
1241
|
+
[l for l in git_status.stdout.splitlines() if l.startswith(" M")]
|
|
1266
1242
|
)
|
|
1267
1243
|
untracked = len(
|
|
1268
|
-
[
|
|
1269
|
-
l
|
|
1270
|
-
for l in git_status.stdout.splitlines()
|
|
1271
|
-
if l.startswith("??")
|
|
1272
|
-
]
|
|
1244
|
+
[l for l in git_status.stdout.splitlines() if l.startswith("??")]
|
|
1273
1245
|
)
|
|
1274
1246
|
if modified == 0 and untracked == 0:
|
|
1275
|
-
check_pass(
|
|
1276
|
-
"dependencies", f"Git: {version} (working tree clean)"
|
|
1277
|
-
)
|
|
1247
|
+
check_pass("dependencies", f"Git: {version} (working tree clean)")
|
|
1278
1248
|
else:
|
|
1279
1249
|
check_info(
|
|
1280
1250
|
"dependencies",
|
|
@@ -1311,11 +1281,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1311
1281
|
aider_version = subprocess.run(
|
|
1312
1282
|
["aider", "--version"], capture_output=True, text=True, timeout=2
|
|
1313
1283
|
)
|
|
1314
|
-
version = (
|
|
1315
|
-
aider_version.stdout.strip()
|
|
1316
|
-
if aider_version.returncode == 0
|
|
1317
|
-
else "unknown"
|
|
1318
|
-
)
|
|
1284
|
+
version = aider_version.stdout.strip() if aider_version.returncode == 0 else "unknown"
|
|
1319
1285
|
check_pass("dependencies", f"Aider: {version} (functional)")
|
|
1320
1286
|
except:
|
|
1321
1287
|
check_pass("dependencies", "Aider: installed")
|
|
@@ -1459,9 +1425,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1459
1425
|
json.load(f)
|
|
1460
1426
|
check_pass("agent_coordination", "current-state.json - Valid JSON")
|
|
1461
1427
|
except json.JSONDecodeError as e:
|
|
1462
|
-
check_fail(
|
|
1463
|
-
"agent_coordination", f"current-state.json - Invalid JSON: {e}"
|
|
1464
|
-
)
|
|
1428
|
+
check_fail("agent_coordination", f"current-state.json - Invalid JSON: {e}")
|
|
1465
1429
|
else:
|
|
1466
1430
|
check_info("agent_coordination", "current-state.json not found (optional)")
|
|
1467
1431
|
|
|
@@ -1505,9 +1469,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1505
1469
|
with open(script_path) as f:
|
|
1506
1470
|
content = f.read()
|
|
1507
1471
|
if "#!/bin/bash" in content or "#!/usr/bin/env bash" in content:
|
|
1508
|
-
check_pass(
|
|
1509
|
-
"workflow_scripts", f"{script_name} - Executable, valid"
|
|
1510
|
-
)
|
|
1472
|
+
check_pass("workflow_scripts", f"{script_name} - Executable, valid")
|
|
1511
1473
|
else:
|
|
1512
1474
|
check_warn(
|
|
1513
1475
|
"workflow_scripts",
|
|
@@ -1781,9 +1743,7 @@ def verify_token_count(task_file: str, log_file: str) -> None:
|
|
|
1781
1743
|
f" Difference: {expected_tokens - actual_tokens:,} tokens ({100 - int(actual_tokens/expected_tokens*100)}% less)"
|
|
1782
1744
|
)
|
|
1783
1745
|
print()
|
|
1784
|
-
print(
|
|
1785
|
-
f"{BOLD}Note:{RESET} Large files may not be fully processed by evaluator."
|
|
1786
|
-
)
|
|
1746
|
+
print(f"{BOLD}Note:{RESET} Large files may not be fully processed by evaluator.")
|
|
1787
1747
|
print(f" Consider splitting into smaller documents (<1,000 lines).")
|
|
1788
1748
|
print()
|
|
1789
1749
|
|
|
@@ -1964,9 +1924,7 @@ def evaluate(task_file: str) -> int:
|
|
|
1964
1924
|
print(f"{RED}❌ ERROR: OpenAI rate limit exceeded{RESET}")
|
|
1965
1925
|
print()
|
|
1966
1926
|
print(f"{BOLD}WHY:{RESET}")
|
|
1967
|
-
print(
|
|
1968
|
-
" Your task file is too large for your OpenAI organization's rate limit"
|
|
1969
|
-
)
|
|
1927
|
+
print(" Your task file is too large for your OpenAI organization's rate limit")
|
|
1970
1928
|
print()
|
|
1971
1929
|
|
|
1972
1930
|
# Extract file size for helpful message
|
|
@@ -2013,9 +1971,7 @@ def evaluate(task_file: str) -> int:
|
|
|
2013
1971
|
print()
|
|
2014
1972
|
print(f"{BOLD}FIX:{RESET}")
|
|
2015
1973
|
print(" Option 1 (RECOMMENDED): Use WSL (Windows Subsystem for Linux)")
|
|
2016
|
-
print(
|
|
2017
|
-
" 1. Install WSL: https://learn.microsoft.com/windows/wsl/install"
|
|
2018
|
-
)
|
|
1974
|
+
print(" 1. Install WSL: https://learn.microsoft.com/windows/wsl/install")
|
|
2019
1975
|
print(" 2. Open WSL terminal")
|
|
2020
1976
|
print(" 3. Reinstall package in WSL: pip install adversarial-workflow")
|
|
2021
1977
|
print()
|
|
@@ -2186,9 +2142,7 @@ def validate(test_command: Optional[str] = None) -> int:
|
|
|
2186
2142
|
return 1
|
|
2187
2143
|
|
|
2188
2144
|
try:
|
|
2189
|
-
result = subprocess.run(
|
|
2190
|
-
[script, test_command], timeout=600
|
|
2191
|
-
) # 10 minutes for tests
|
|
2145
|
+
result = subprocess.run([script, test_command], timeout=600) # 10 minutes for tests
|
|
2192
2146
|
except subprocess.TimeoutExpired:
|
|
2193
2147
|
print(f"{RED}❌ ERROR: Test validation timed out (>10 minutes){RESET}")
|
|
2194
2148
|
return 1
|
|
@@ -2241,9 +2195,7 @@ def select_agent_template() -> Dict[str, str]:
|
|
|
2241
2195
|
elif choice == "3":
|
|
2242
2196
|
print()
|
|
2243
2197
|
print(f"{CYAN}Custom Template URL:{RESET}")
|
|
2244
|
-
print(
|
|
2245
|
-
" Example: https://raw.githubusercontent.com/user/repo/main/agent-handoffs.json"
|
|
2246
|
-
)
|
|
2198
|
+
print(" Example: https://raw.githubusercontent.com/user/repo/main/agent-handoffs.json")
|
|
2247
2199
|
print()
|
|
2248
2200
|
url = prompt_user("Template URL")
|
|
2249
2201
|
if url:
|
|
@@ -2283,14 +2235,10 @@ def fetch_agent_template(url: str, template_type: str = "standard") -> Optional[
|
|
|
2283
2235
|
with open(template_path, "r") as f:
|
|
2284
2236
|
return f.read()
|
|
2285
2237
|
except Exception as e:
|
|
2286
|
-
print(
|
|
2287
|
-
f"{RED}❌ ERROR: Could not read {template_type} template: {e}{RESET}"
|
|
2288
|
-
)
|
|
2238
|
+
print(f"{RED}❌ ERROR: Could not read {template_type} template: {e}{RESET}")
|
|
2289
2239
|
return None
|
|
2290
2240
|
else:
|
|
2291
|
-
print(
|
|
2292
|
-
f"{RED}❌ ERROR: {template_type} template not found in package{RESET}"
|
|
2293
|
-
)
|
|
2241
|
+
print(f"{RED}❌ ERROR: {template_type} template not found in package{RESET}")
|
|
2294
2242
|
return None
|
|
2295
2243
|
|
|
2296
2244
|
elif template_type == "custom" and url:
|
|
@@ -2390,9 +2338,11 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2390
2338
|
return 0
|
|
2391
2339
|
|
|
2392
2340
|
# 3. Interactive questions (4 max)
|
|
2393
|
-
use_delegation = prompt_user(
|
|
2394
|
-
"
|
|
2395
|
-
|
|
2341
|
+
use_delegation = prompt_user("Use delegation/tasks/ structure? (recommended)", "Y").lower() in [
|
|
2342
|
+
"y",
|
|
2343
|
+
"yes",
|
|
2344
|
+
"",
|
|
2345
|
+
]
|
|
2396
2346
|
|
|
2397
2347
|
organize_docs = prompt_user("Organize root docs into docs/?", "n").lower() in [
|
|
2398
2348
|
"y",
|
|
@@ -2469,9 +2419,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2469
2419
|
print(
|
|
2470
2420
|
f" {CYAN}ℹ️{RESET} Original tasks/ preserved (remove manually if desired)"
|
|
2471
2421
|
)
|
|
2472
|
-
print(
|
|
2473
|
-
f" {CYAN}ℹ️{RESET} Rollback: rm -rf tasks && mv tasks.backup tasks"
|
|
2474
|
-
)
|
|
2422
|
+
print(f" {CYAN}ℹ️{RESET} Rollback: rm -rf tasks && mv tasks.backup tasks")
|
|
2475
2423
|
|
|
2476
2424
|
except Exception as e:
|
|
2477
2425
|
print(f" {RED}❌{RESET} Migration failed: {e}")
|
|
@@ -2485,9 +2433,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2485
2433
|
print(f"{BOLD}Documentation Organization:{RESET}")
|
|
2486
2434
|
|
|
2487
2435
|
# Find markdown files in root
|
|
2488
|
-
root_docs = [
|
|
2489
|
-
f for f in os.listdir(".") if f.endswith(".md") and not f.startswith(".")
|
|
2490
|
-
]
|
|
2436
|
+
root_docs = [f for f in os.listdir(".") if f.endswith(".md") and not f.startswith(".")]
|
|
2491
2437
|
|
|
2492
2438
|
if len(root_docs) > 0:
|
|
2493
2439
|
print(f" Found {len(root_docs)} markdown file(s) in root")
|
|
@@ -2507,9 +2453,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2507
2453
|
moved_count += 1
|
|
2508
2454
|
|
|
2509
2455
|
if moved_count > 0:
|
|
2510
|
-
print(
|
|
2511
|
-
f" {GREEN}✅{RESET} Organized {moved_count} doc(s) into docs/"
|
|
2512
|
-
)
|
|
2456
|
+
print(f" {GREEN}✅{RESET} Organized {moved_count} doc(s) into docs/")
|
|
2513
2457
|
else:
|
|
2514
2458
|
print(f" {CYAN}ℹ️{RESET} No docs needed organizing")
|
|
2515
2459
|
|
|
@@ -2562,9 +2506,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2562
2506
|
print(f" {RED}❌{RESET} Failed to fetch agent template")
|
|
2563
2507
|
return 1
|
|
2564
2508
|
else:
|
|
2565
|
-
print(
|
|
2566
|
-
f" {CYAN}ℹ️{RESET} Skipped agent-handoffs.json (manual setup requested)"
|
|
2567
|
-
)
|
|
2509
|
+
print(f" {CYAN}ℹ️{RESET} Skipped agent-handoffs.json (manual setup requested)")
|
|
2568
2510
|
|
|
2569
2511
|
# Render current-state.json
|
|
2570
2512
|
current_state_template = templates_dir / "current-state.json.template"
|
|
@@ -2579,9 +2521,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2579
2521
|
# Render README.md
|
|
2580
2522
|
readme_template = templates_dir / "README.md.template"
|
|
2581
2523
|
if readme_template.exists():
|
|
2582
|
-
render_template(
|
|
2583
|
-
str(readme_template), ".agent-context/README.md", template_vars
|
|
2584
|
-
)
|
|
2524
|
+
render_template(str(readme_template), ".agent-context/README.md", template_vars)
|
|
2585
2525
|
print(f" {GREEN}✅{RESET} Created .agent-context/README.md")
|
|
2586
2526
|
|
|
2587
2527
|
# Copy AGENT-SYSTEM-GUIDE.md if it exists and isn't already there
|
|
@@ -2620,9 +2560,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2620
2560
|
|
|
2621
2561
|
except Exception as e:
|
|
2622
2562
|
print(f" {YELLOW}⚠️{RESET} Could not update config: {e}")
|
|
2623
|
-
print(
|
|
2624
|
-
f" Manually set task_directory: delegation/tasks/ in .adversarial/config.yml"
|
|
2625
|
-
)
|
|
2563
|
+
print(f" Manually set task_directory: delegation/tasks/ in .adversarial/config.yml")
|
|
2626
2564
|
|
|
2627
2565
|
# 9. Update .gitignore
|
|
2628
2566
|
print()
|
|
@@ -2676,9 +2614,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2676
2614
|
verification_checks.append((f"current-state.json invalid: {e}", False))
|
|
2677
2615
|
|
|
2678
2616
|
# Check directories exist
|
|
2679
|
-
verification_checks.append(
|
|
2680
|
-
(".agent-context/ exists", os.path.exists(".agent-context"))
|
|
2681
|
-
)
|
|
2617
|
+
verification_checks.append((".agent-context/ exists", os.path.exists(".agent-context")))
|
|
2682
2618
|
|
|
2683
2619
|
if use_delegation:
|
|
2684
2620
|
verification_checks.append(
|
|
@@ -2783,9 +2719,7 @@ def split(
|
|
|
2783
2719
|
|
|
2784
2720
|
# Check if splitting is recommended
|
|
2785
2721
|
if lines <= max_lines:
|
|
2786
|
-
print(
|
|
2787
|
-
f"{GREEN}✅ File is under recommended limit ({max_lines} lines){RESET}"
|
|
2788
|
-
)
|
|
2722
|
+
print(f"{GREEN}✅ File is under recommended limit ({max_lines} lines){RESET}")
|
|
2789
2723
|
print("No splitting needed.")
|
|
2790
2724
|
return 0
|
|
2791
2725
|
|
|
@@ -2803,9 +2737,7 @@ def split(
|
|
|
2803
2737
|
splits = split_by_phases(content)
|
|
2804
2738
|
print(f"\n💡 Suggested splits (by phases):")
|
|
2805
2739
|
else:
|
|
2806
|
-
print(
|
|
2807
|
-
f"{RED}Error: Unknown strategy '{strategy}'. Use 'sections' or 'phases'.{RESET}"
|
|
2808
|
-
)
|
|
2740
|
+
print(f"{RED}Error: Unknown strategy '{strategy}'. Use 'sections' or 'phases'.{RESET}")
|
|
2809
2741
|
return 1
|
|
2810
2742
|
|
|
2811
2743
|
# Display split preview
|
|
@@ -2977,26 +2909,18 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
2977
2909
|
subparsers.add_parser("doctor", help="Alias for 'check'")
|
|
2978
2910
|
|
|
2979
2911
|
# health command
|
|
2980
|
-
health_parser = subparsers.add_parser(
|
|
2981
|
-
"health", help="Comprehensive system health check"
|
|
2982
|
-
)
|
|
2912
|
+
health_parser = subparsers.add_parser("health", help="Comprehensive system health check")
|
|
2983
2913
|
health_parser.add_argument(
|
|
2984
2914
|
"--verbose", "-v", action="store_true", help="Show detailed diagnostics"
|
|
2985
2915
|
)
|
|
2986
|
-
health_parser.add_argument(
|
|
2987
|
-
"--json", action="store_true", help="Output in JSON format"
|
|
2988
|
-
)
|
|
2916
|
+
health_parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
2989
2917
|
|
|
2990
2918
|
# agent command (with subcommands)
|
|
2991
2919
|
agent_parser = subparsers.add_parser("agent", help="Agent coordination commands")
|
|
2992
|
-
agent_subparsers = agent_parser.add_subparsers(
|
|
2993
|
-
dest="agent_subcommand", help="Agent subcommand"
|
|
2994
|
-
)
|
|
2920
|
+
agent_subparsers = agent_parser.add_subparsers(dest="agent_subcommand", help="Agent subcommand")
|
|
2995
2921
|
|
|
2996
2922
|
# agent onboard subcommand
|
|
2997
|
-
onboard_parser = agent_subparsers.add_parser(
|
|
2998
|
-
"onboard", help="Set up agent coordination system"
|
|
2999
|
-
)
|
|
2923
|
+
onboard_parser = agent_subparsers.add_parser("onboard", help="Set up agent coordination system")
|
|
3000
2924
|
onboard_parser.add_argument(
|
|
3001
2925
|
"--path", default=".", help="Project path (default: current directory)"
|
|
3002
2926
|
)
|
|
@@ -3005,12 +2929,8 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3005
2929
|
subparsers.add_parser("review", help="Run Phase 3: Code review")
|
|
3006
2930
|
|
|
3007
2931
|
# validate command
|
|
3008
|
-
validate_parser = subparsers.add_parser(
|
|
3009
|
-
|
|
3010
|
-
)
|
|
3011
|
-
validate_parser.add_argument(
|
|
3012
|
-
"test_command", nargs="?", help="Test command to run (optional)"
|
|
3013
|
-
)
|
|
2932
|
+
validate_parser = subparsers.add_parser("validate", help="Run Phase 4: Test validation")
|
|
2933
|
+
validate_parser.add_argument("test_command", nargs="?", help="Test command to run (optional)")
|
|
3014
2934
|
|
|
3015
2935
|
# split command
|
|
3016
2936
|
split_parser = subparsers.add_parser(
|
|
@@ -3056,9 +2976,7 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3056
2976
|
# Only warn for user-defined evaluators, not built-ins
|
|
3057
2977
|
# Built-in conflicts are intentional (e.g., 'review' command vs 'review' evaluator)
|
|
3058
2978
|
if getattr(config, "source", None) != "builtin":
|
|
3059
|
-
logger.warning(
|
|
3060
|
-
"Evaluator '%s' conflicts with CLI command; skipping", name
|
|
3061
|
-
)
|
|
2979
|
+
logger.warning("Evaluator '%s' conflicts with CLI command; skipping", name)
|
|
3062
2980
|
# Mark as registered to prevent alias re-registration attempts
|
|
3063
2981
|
registered_configs.add(id(config))
|
|
3064
2982
|
continue
|
|
@@ -51,9 +51,7 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
51
51
|
|
|
52
52
|
# Ensure parsed data is a dict (YAML can parse scalars, lists, etc.)
|
|
53
53
|
if not isinstance(data, dict):
|
|
54
|
-
raise EvaluatorParseError(
|
|
55
|
-
f"YAML must be a mapping, got {type(data).__name__}: {yml_file}"
|
|
56
|
-
)
|
|
54
|
+
raise EvaluatorParseError(f"YAML must be a mapping, got {type(data).__name__}: {yml_file}")
|
|
57
55
|
|
|
58
56
|
# Validate required fields exist
|
|
59
57
|
required = [
|
|
@@ -91,9 +89,7 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
91
89
|
elif isinstance(aliases, str):
|
|
92
90
|
data["aliases"] = [aliases]
|
|
93
91
|
elif not isinstance(aliases, list):
|
|
94
|
-
raise EvaluatorParseError(
|
|
95
|
-
f"aliases must be string or list, got {type(aliases).__name__}"
|
|
96
|
-
)
|
|
92
|
+
raise EvaluatorParseError(f"aliases must be string or list, got {type(aliases).__name__}")
|
|
97
93
|
|
|
98
94
|
# Validate alias names - must be strings with valid format
|
|
99
95
|
for alias in data.get("aliases", []):
|
|
@@ -131,18 +127,14 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
131
127
|
# Check for bool before int (bool is subclass of int in Python)
|
|
132
128
|
# YAML parses 'yes'/'true' as True, 'no'/'false' as False
|
|
133
129
|
if isinstance(timeout, bool):
|
|
134
|
-
raise EvaluatorParseError(
|
|
135
|
-
f"Field 'timeout' must be an integer, got bool: {timeout!r}"
|
|
136
|
-
)
|
|
130
|
+
raise EvaluatorParseError(f"Field 'timeout' must be an integer, got bool: {timeout!r}")
|
|
137
131
|
if not isinstance(timeout, int):
|
|
138
132
|
raise EvaluatorParseError(
|
|
139
133
|
f"Field 'timeout' must be an integer, got {type(timeout).__name__}: {timeout!r}"
|
|
140
134
|
)
|
|
141
135
|
# timeout=0 is invalid (does not disable timeout - use a large value instead)
|
|
142
136
|
if timeout <= 0:
|
|
143
|
-
raise EvaluatorParseError(
|
|
144
|
-
f"Field 'timeout' must be positive (> 0), got {timeout}"
|
|
145
|
-
)
|
|
137
|
+
raise EvaluatorParseError(f"Field 'timeout' must be positive (> 0), got {timeout}")
|
|
146
138
|
if timeout > 600:
|
|
147
139
|
logger.warning(
|
|
148
140
|
"Timeout %ds exceeds maximum (600s), clamping to 600s in %s",
|
|
@@ -167,9 +159,7 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
167
159
|
}
|
|
168
160
|
unknown = set(data.keys()) - known_fields
|
|
169
161
|
if unknown:
|
|
170
|
-
logger.warning(
|
|
171
|
-
"Unknown fields in %s: %s", yml_file.name, ", ".join(sorted(unknown))
|
|
172
|
-
)
|
|
162
|
+
logger.warning("Unknown fields in %s: %s", yml_file.name, ", ".join(sorted(unknown)))
|
|
173
163
|
|
|
174
164
|
# Build filtered data dict
|
|
175
165
|
filtered_data = {k: v for k, v in data.items() if k in known_fields}
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/runner.py
RENAMED
|
@@ -227,10 +227,7 @@ def _execute_script(
|
|
|
227
227
|
|
|
228
228
|
# Validate output
|
|
229
229
|
file_basename = Path(file_path).stem
|
|
230
|
-
log_file = (
|
|
231
|
-
Path(project_config["log_directory"])
|
|
232
|
-
/ f"{file_basename}-{config.output_suffix}.md"
|
|
233
|
-
)
|
|
230
|
+
log_file = Path(project_config["log_directory"]) / f"{file_basename}-{config.output_suffix}.md"
|
|
234
231
|
|
|
235
232
|
is_valid, verdict, message = validate_evaluation_output(str(log_file))
|
|
236
233
|
|
|
@@ -241,9 +238,7 @@ def _execute_script(
|
|
|
241
238
|
return _report_verdict(verdict, log_file, config)
|
|
242
239
|
|
|
243
240
|
|
|
244
|
-
def _report_verdict(
|
|
245
|
-
verdict: str | None, log_file: Path, config: EvaluatorConfig
|
|
246
|
-
) -> int:
|
|
241
|
+
def _report_verdict(verdict: str | None, log_file: Path, config: EvaluatorConfig) -> int:
|
|
247
242
|
"""Report the evaluation verdict to terminal."""
|
|
248
243
|
print()
|
|
249
244
|
if verdict == "APPROVED":
|
|
@@ -140,6 +140,7 @@ echo ""
|
|
|
140
140
|
aider \
|
|
141
141
|
--model "$EVALUATOR_MODEL" \
|
|
142
142
|
--yes \
|
|
143
|
+
--no-detect-urls \
|
|
143
144
|
--no-gitignore \
|
|
144
145
|
--read "$TASK_FILE" "${ARTIFACTS_DIR}${TASK_NUM}-final-implementation.diff" "${ARTIFACTS_DIR}${TASK_NUM}-test-output.txt" \
|
|
145
146
|
--message "You are a REVIEWER performing test validation and analysis.
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/config.py
RENAMED
|
@@ -24,9 +24,7 @@ def load_config(config_path: str = ".adversarial/config.yml") -> dict[str, Any]:
|
|
|
24
24
|
with open(config_path) as f:
|
|
25
25
|
file_config = yaml.safe_load(f) or {}
|
|
26
26
|
if not isinstance(file_config, dict):
|
|
27
|
-
raise ValueError(
|
|
28
|
-
f"Config file must be a mapping, got {type(file_config).__name__}"
|
|
29
|
-
)
|
|
27
|
+
raise ValueError(f"Config file must be a mapping, got {type(file_config).__name__}")
|
|
30
28
|
config.update(file_config)
|
|
31
29
|
|
|
32
30
|
# Override with environment variables
|
|
@@ -141,9 +141,7 @@ def split_by_sections(content: str, max_lines: int = 500) -> List[Dict[str, Any]
|
|
|
141
141
|
is_section_boundary = re.match(r"^#+\s+", line.strip())
|
|
142
142
|
approaching_limit = len(current_split_lines) >= max_lines * 0.8
|
|
143
143
|
|
|
144
|
-
if len(current_split_lines) >= max_lines or (
|
|
145
|
-
is_section_boundary and approaching_limit
|
|
146
|
-
):
|
|
144
|
+
if len(current_split_lines) >= max_lines or (is_section_boundary and approaching_limit):
|
|
147
145
|
# Create split
|
|
148
146
|
split_content = "\n".join(current_split_lines)
|
|
149
147
|
splits.append(
|
|
@@ -318,9 +316,7 @@ def split_at_lines(content: str, line_numbers: List[int]) -> List[Dict[str, Any]
|
|
|
318
316
|
return splits
|
|
319
317
|
|
|
320
318
|
|
|
321
|
-
def generate_split_files(
|
|
322
|
-
original: str, splits: List[Dict[str, Any]], output_dir: str
|
|
323
|
-
) -> List[str]:
|
|
319
|
+
def generate_split_files(original: str, splits: List[Dict[str, Any]], output_dir: str) -> List[str]:
|
|
324
320
|
"""Generate split files with metadata and cross-references.
|
|
325
321
|
|
|
326
322
|
Args:
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/validation.py
RENAMED
|
@@ -47,9 +47,7 @@ def validate_evaluation_output(
|
|
|
47
47
|
"concerns",
|
|
48
48
|
]
|
|
49
49
|
|
|
50
|
-
has_evaluation_content = any(
|
|
51
|
-
marker in content_lower for marker in evaluation_markers
|
|
52
|
-
)
|
|
50
|
+
has_evaluation_content = any(marker in content_lower for marker in evaluation_markers)
|
|
53
51
|
if not has_evaluation_content:
|
|
54
52
|
return (
|
|
55
53
|
False,
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/PKG-INFO
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adversarial-workflow
|
|
3
|
-
Version: 0.6.
|
|
4
|
-
Summary: Multi-stage AI
|
|
3
|
+
Version: 0.6.5
|
|
4
|
+
Summary: Multi-stage AI evaluation system for task plans, code review, and test validation
|
|
5
5
|
Author: Fredrik Matheson
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/movito/adversarial-workflow
|
|
@@ -5,9 +5,9 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "adversarial-workflow"
|
|
7
7
|
|
|
8
|
-
version = "0.6.
|
|
8
|
+
version = "0.6.5"
|
|
9
9
|
|
|
10
|
-
description = "Multi-stage AI
|
|
10
|
+
description = "Multi-stage AI evaluation system for task plans, code review, and test validation"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "Fredrik Matheson"}
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/tests/test_cli_dynamic_commands.py
RENAMED
|
@@ -78,9 +78,7 @@ output_suffix: CUSTOM-TEST
|
|
|
78
78
|
monkeypatch.chdir(tmp_path)
|
|
79
79
|
|
|
80
80
|
result = run_cli(["--help"], cwd=tmp_path)
|
|
81
|
-
assert
|
|
82
|
-
"custom" in result.stdout
|
|
83
|
-
), f"'custom' not found in help output:\n{result.stdout}"
|
|
81
|
+
assert "custom" in result.stdout, f"'custom' not found in help output:\n{result.stdout}"
|
|
84
82
|
assert "Custom test evaluator" in result.stdout
|
|
85
83
|
|
|
86
84
|
def test_multiple_local_evaluators_in_help(self, tmp_path, monkeypatch, run_cli):
|
|
@@ -351,9 +349,7 @@ class TestBackwardsCompatibility:
|
|
|
351
349
|
class TestGracefulDegradation:
|
|
352
350
|
"""Test graceful degradation on errors."""
|
|
353
351
|
|
|
354
|
-
def test_help_works_without_local_evaluators_dir(
|
|
355
|
-
self, tmp_path, monkeypatch, run_cli
|
|
356
|
-
):
|
|
352
|
+
def test_help_works_without_local_evaluators_dir(self, tmp_path, monkeypatch, run_cli):
|
|
357
353
|
"""CLI help works even without .adversarial/evaluators/ directory."""
|
|
358
354
|
adv_dir = tmp_path / ".adversarial"
|
|
359
355
|
adv_dir.mkdir(parents=True)
|
|
@@ -422,9 +418,7 @@ class TestReviewCommandBackwardsCompatibility:
|
|
|
422
418
|
# Review should NOT have --timeout flag (that's for evaluators)
|
|
423
419
|
assert "--timeout" not in result.stdout
|
|
424
420
|
|
|
425
|
-
def test_review_command_not_overridden_by_evaluator(
|
|
426
|
-
self, tmp_path, monkeypatch, run_cli
|
|
427
|
-
):
|
|
421
|
+
def test_review_command_not_overridden_by_evaluator(self, tmp_path, monkeypatch, run_cli):
|
|
428
422
|
"""Review command cannot be overridden by local evaluator."""
|
|
429
423
|
adv_dir = tmp_path / ".adversarial"
|
|
430
424
|
adv_dir.mkdir(parents=True)
|
|
@@ -492,9 +486,7 @@ aliases:
|
|
|
492
486
|
assert "--path" in result_init.stdout
|
|
493
487
|
assert "--interactive" in result_init.stdout
|
|
494
488
|
|
|
495
|
-
def test_evaluator_with_conflicting_name_and_alias(
|
|
496
|
-
self, tmp_path, monkeypatch, run_cli
|
|
497
|
-
):
|
|
489
|
+
def test_evaluator_with_conflicting_name_and_alias(self, tmp_path, monkeypatch, run_cli):
|
|
498
490
|
"""Evaluator with conflicting name doesn't crash when alias is processed."""
|
|
499
491
|
adv_dir = tmp_path / ".adversarial"
|
|
500
492
|
adv_dir.mkdir(parents=True)
|
|
@@ -94,9 +94,7 @@ class TestCheckEnvCount:
|
|
|
94
94
|
"""
|
|
95
95
|
# Create .env with 3 variables
|
|
96
96
|
(tmp_path / ".env").write_text(
|
|
97
|
-
"OPENAI_API_KEY=sk-test\n"
|
|
98
|
-
"ANTHROPIC_API_KEY=ant-test\n"
|
|
99
|
-
"CUSTOM_KEY=custom-value\n"
|
|
97
|
+
"OPENAI_API_KEY=sk-test\n" "ANTHROPIC_API_KEY=ant-test\n" "CUSTOM_KEY=custom-value\n"
|
|
100
98
|
)
|
|
101
99
|
|
|
102
100
|
# Remove keys from environment to isolate test
|
|
@@ -49,9 +49,7 @@ class TestEvaluate:
|
|
|
49
49
|
|
|
50
50
|
@patch("shutil.which")
|
|
51
51
|
@patch("adversarial_workflow.cli.load_config")
|
|
52
|
-
def test_evaluate_aider_not_found(
|
|
53
|
-
self, mock_load_config, mock_which, tmp_path, capsys
|
|
54
|
-
):
|
|
52
|
+
def test_evaluate_aider_not_found(self, mock_load_config, mock_which, tmp_path, capsys):
|
|
55
53
|
"""Test evaluate when aider is not available."""
|
|
56
54
|
# Create a test file
|
|
57
55
|
task_file = tmp_path / "test_task.md"
|
|
@@ -411,9 +409,7 @@ class TestVerifyTokenCount:
|
|
|
411
409
|
|
|
412
410
|
@patch("adversarial_workflow.cli.estimate_file_tokens")
|
|
413
411
|
@patch("adversarial_workflow.cli.extract_token_count_from_log")
|
|
414
|
-
def test_verify_token_count_normal(
|
|
415
|
-
self, mock_extract, mock_estimate, tmp_path, capsys
|
|
416
|
-
):
|
|
412
|
+
def test_verify_token_count_normal(self, mock_extract, mock_estimate, tmp_path, capsys):
|
|
417
413
|
"""Test normal token count verification."""
|
|
418
414
|
task_file = tmp_path / "task.md"
|
|
419
415
|
log_file = tmp_path / "log.md"
|
|
@@ -433,9 +429,7 @@ class TestVerifyTokenCount:
|
|
|
433
429
|
|
|
434
430
|
@patch("adversarial_workflow.cli.estimate_file_tokens")
|
|
435
431
|
@patch("adversarial_workflow.cli.extract_token_count_from_log")
|
|
436
|
-
def test_verify_token_count_low_warning(
|
|
437
|
-
self, mock_extract, mock_estimate, tmp_path, capsys
|
|
438
|
-
):
|
|
432
|
+
def test_verify_token_count_low_warning(self, mock_extract, mock_estimate, tmp_path, capsys):
|
|
439
433
|
"""Test token count verification warns on suspiciously low usage."""
|
|
440
434
|
task_file = tmp_path / "task.md"
|
|
441
435
|
log_file = tmp_path / "log.md"
|
|
@@ -388,9 +388,7 @@ fallback_model: yes
|
|
|
388
388
|
"""
|
|
389
389
|
)
|
|
390
390
|
|
|
391
|
-
with pytest.raises(
|
|
392
|
-
EvaluatorParseError, match="'fallback_model' must be a string"
|
|
393
|
-
):
|
|
391
|
+
with pytest.raises(EvaluatorParseError, match="'fallback_model' must be a string"):
|
|
394
392
|
parse_evaluator_yaml(yml)
|
|
395
393
|
|
|
396
394
|
def test_parse_with_valid_timeout(self, tmp_path):
|
|
@@ -53,9 +53,7 @@ aliases:
|
|
|
53
53
|
result = run_cli(["--help"])
|
|
54
54
|
assert "list-evaluators" in result.stdout
|
|
55
55
|
|
|
56
|
-
def test_list_evaluators_skips_alias_duplicates(
|
|
57
|
-
self, tmp_path, monkeypatch, run_cli
|
|
58
|
-
):
|
|
56
|
+
def test_list_evaluators_skips_alias_duplicates(self, tmp_path, monkeypatch, run_cli):
|
|
59
57
|
"""Aliases do not cause duplicate entries in output."""
|
|
60
58
|
eval_dir = tmp_path / ".adversarial" / "evaluators"
|
|
61
59
|
eval_dir.mkdir(parents=True)
|
|
@@ -80,9 +78,7 @@ aliases:
|
|
|
80
78
|
assert result.stdout.count("Knowledge evaluation") == 1
|
|
81
79
|
assert "aliases: knowledge, research" in result.stdout
|
|
82
80
|
|
|
83
|
-
def test_list_evaluators_shows_version_if_not_default(
|
|
84
|
-
self, tmp_path, monkeypatch, run_cli
|
|
85
|
-
):
|
|
81
|
+
def test_list_evaluators_shows_version_if_not_default(self, tmp_path, monkeypatch, run_cli):
|
|
86
82
|
"""Shows version only when it differs from default 1.0.0."""
|
|
87
83
|
eval_dir = tmp_path / ".adversarial" / "evaluators"
|
|
88
84
|
eval_dir.mkdir(parents=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/evaluators/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/__init__.py
RENAMED
|
File without changes
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow/utils/colors.py
RENAMED
|
File without changes
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adversarial_workflow-0.6.3 → adversarial_workflow-0.6.5}/adversarial_workflow.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|