adversarial-workflow 0.6.2__py3-none-any.whl → 0.6.3__py3-none-any.whl
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/__main__.py +1 -0
- adversarial_workflow/cli.py +40 -10
- adversarial_workflow/evaluators/config.py +2 -0
- adversarial_workflow/evaluators/discovery.py +30 -0
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/METADATA +25 -3
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/RECORD +10 -10
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/WHEEL +0 -0
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/entry_points.txt +0 -0
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/licenses/LICENSE +0 -0
- {adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/top_level.txt +0 -0
adversarial_workflow/__main__.py
CHANGED
adversarial_workflow/cli.py
CHANGED
|
@@ -322,16 +322,20 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
322
322
|
f"{GREEN}✅ Setup Complete!{RESET}",
|
|
323
323
|
[
|
|
324
324
|
"Created:",
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
(
|
|
326
|
+
" ✓ .env (with your API keys - added to .gitignore)"
|
|
327
|
+
if (anthropic_key or openai_key)
|
|
328
|
+
else " ⚠️ .env (skipped - no API keys provided)"
|
|
329
|
+
),
|
|
328
330
|
" ✓ .adversarial/config.yml",
|
|
329
331
|
" ✓ .adversarial/scripts/ (3 workflow scripts)",
|
|
330
332
|
" ✓ .aider.conf.yml (aider configuration)",
|
|
331
333
|
"",
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
334
|
+
(
|
|
335
|
+
"Your configuration:"
|
|
336
|
+
if (anthropic_key or openai_key)
|
|
337
|
+
else "Configuration (no API keys yet):"
|
|
338
|
+
),
|
|
335
339
|
f" Author (implementation): {'Claude 3.5 Sonnet (Anthropic)' if anthropic_key else 'GPT-4o (OpenAI)' if openai_key else 'Not configured'}",
|
|
336
340
|
f" Evaluator: {'GPT-4o (OpenAI)' if openai_key else 'Claude 3.5 Sonnet (Anthropic)' if anthropic_key else 'Not configured'}",
|
|
337
341
|
f" Cost per workflow: {'~$0.02-0.10' if (anthropic_key and openai_key) else '~$0.05-0.15' if (anthropic_key or openai_key) else 'N/A'}",
|
|
@@ -2284,7 +2288,9 @@ def fetch_agent_template(url: str, template_type: str = "standard") -> Optional[
|
|
|
2284
2288
|
)
|
|
2285
2289
|
return None
|
|
2286
2290
|
else:
|
|
2287
|
-
print(
|
|
2291
|
+
print(
|
|
2292
|
+
f"{RED}❌ ERROR: {template_type} template not found in package{RESET}"
|
|
2293
|
+
)
|
|
2288
2294
|
return None
|
|
2289
2295
|
|
|
2290
2296
|
elif template_type == "custom" and url:
|
|
@@ -3082,8 +3088,8 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3082
3088
|
"--timeout",
|
|
3083
3089
|
"-t",
|
|
3084
3090
|
type=int,
|
|
3085
|
-
default=
|
|
3086
|
-
help="Timeout in seconds (default: 180)",
|
|
3091
|
+
default=None,
|
|
3092
|
+
help="Timeout in seconds (default: from evaluator config or 180, max: 600)",
|
|
3087
3093
|
)
|
|
3088
3094
|
# Store config for later execution
|
|
3089
3095
|
eval_parser.set_defaults(evaluator_config=config)
|
|
@@ -3096,10 +3102,34 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3096
3102
|
|
|
3097
3103
|
# Check for evaluator command first (has evaluator_config attribute)
|
|
3098
3104
|
if hasattr(args, "evaluator_config"):
|
|
3105
|
+
# Determine timeout: CLI flag > YAML config > default (180s)
|
|
3106
|
+
if args.timeout is not None:
|
|
3107
|
+
timeout = args.timeout
|
|
3108
|
+
source = "CLI override"
|
|
3109
|
+
elif args.evaluator_config.timeout != 180:
|
|
3110
|
+
timeout = args.evaluator_config.timeout
|
|
3111
|
+
source = "evaluator config"
|
|
3112
|
+
else:
|
|
3113
|
+
timeout = args.evaluator_config.timeout # 180 (default)
|
|
3114
|
+
source = "default"
|
|
3115
|
+
|
|
3116
|
+
# Validate CLI timeout (consistent with YAML validation)
|
|
3117
|
+
if timeout <= 0:
|
|
3118
|
+
print(f"{RED}Error: Timeout must be positive (> 0), got {timeout}{RESET}")
|
|
3119
|
+
return 1
|
|
3120
|
+
if timeout > 600:
|
|
3121
|
+
print(
|
|
3122
|
+
f"{YELLOW}Warning: Timeout {timeout}s exceeds maximum (600s), clamping to 600s{RESET}"
|
|
3123
|
+
)
|
|
3124
|
+
timeout = 600
|
|
3125
|
+
|
|
3126
|
+
# Log actual timeout and source
|
|
3127
|
+
print(f"Using timeout: {timeout}s ({source})")
|
|
3128
|
+
|
|
3099
3129
|
return run_evaluator(
|
|
3100
3130
|
args.evaluator_config,
|
|
3101
3131
|
args.file,
|
|
3102
|
-
timeout=
|
|
3132
|
+
timeout=timeout,
|
|
3103
3133
|
)
|
|
3104
3134
|
|
|
3105
3135
|
# Execute static commands
|
|
@@ -26,6 +26,7 @@ class EvaluatorConfig:
|
|
|
26
26
|
fallback_model: Fallback model if primary fails
|
|
27
27
|
aliases: Alternative command names
|
|
28
28
|
version: Evaluator version
|
|
29
|
+
timeout: Timeout in seconds (default: 180, max: 600)
|
|
29
30
|
source: "builtin" or "local" (set internally)
|
|
30
31
|
config_file: Path to YAML file if local (set internally)
|
|
31
32
|
"""
|
|
@@ -43,6 +44,7 @@ class EvaluatorConfig:
|
|
|
43
44
|
fallback_model: str | None = None
|
|
44
45
|
aliases: list[str] = field(default_factory=list)
|
|
45
46
|
version: str = "1.0.0"
|
|
47
|
+
timeout: int = 180 # Timeout in seconds (default: 180, max: 600)
|
|
46
48
|
|
|
47
49
|
# Metadata (set internally during discovery, not from YAML)
|
|
48
50
|
source: str = "builtin"
|
|
@@ -122,6 +122,35 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
122
122
|
f"Field '{field}' must be a string, got {type(value).__name__}: {value!r}"
|
|
123
123
|
)
|
|
124
124
|
|
|
125
|
+
# Validate timeout if present
|
|
126
|
+
if "timeout" in data:
|
|
127
|
+
timeout = data["timeout"]
|
|
128
|
+
# Handle null/empty values
|
|
129
|
+
if timeout is None or timeout == "":
|
|
130
|
+
raise EvaluatorParseError("Field 'timeout' cannot be null or empty")
|
|
131
|
+
# Check for bool before int (bool is subclass of int in Python)
|
|
132
|
+
# YAML parses 'yes'/'true' as True, 'no'/'false' as False
|
|
133
|
+
if isinstance(timeout, bool):
|
|
134
|
+
raise EvaluatorParseError(
|
|
135
|
+
f"Field 'timeout' must be an integer, got bool: {timeout!r}"
|
|
136
|
+
)
|
|
137
|
+
if not isinstance(timeout, int):
|
|
138
|
+
raise EvaluatorParseError(
|
|
139
|
+
f"Field 'timeout' must be an integer, got {type(timeout).__name__}: {timeout!r}"
|
|
140
|
+
)
|
|
141
|
+
# timeout=0 is invalid (does not disable timeout - use a large value instead)
|
|
142
|
+
if timeout <= 0:
|
|
143
|
+
raise EvaluatorParseError(
|
|
144
|
+
f"Field 'timeout' must be positive (> 0), got {timeout}"
|
|
145
|
+
)
|
|
146
|
+
if timeout > 600:
|
|
147
|
+
logger.warning(
|
|
148
|
+
"Timeout %ds exceeds maximum (600s), clamping to 600s in %s",
|
|
149
|
+
timeout,
|
|
150
|
+
yml_file.name,
|
|
151
|
+
)
|
|
152
|
+
data["timeout"] = 600
|
|
153
|
+
|
|
125
154
|
# Filter to known fields only (log unknown fields)
|
|
126
155
|
known_fields = {
|
|
127
156
|
"name",
|
|
@@ -134,6 +163,7 @@ def parse_evaluator_yaml(yml_file: Path) -> EvaluatorConfig:
|
|
|
134
163
|
"fallback_model",
|
|
135
164
|
"aliases",
|
|
136
165
|
"version",
|
|
166
|
+
"timeout",
|
|
137
167
|
}
|
|
138
168
|
unknown = set(data.keys()) - known_fields
|
|
139
169
|
if unknown:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adversarial-workflow
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: Multi-stage AI code review system preventing phantom work - Author/Evaluator pattern
|
|
5
5
|
Author: Fredrik Matheson
|
|
6
6
|
License: MIT
|
|
@@ -55,9 +55,30 @@ Evaluate proposals, sort out ideas, and prevent "phantom work" (AI claiming to i
|
|
|
55
55
|
- 🎯 **Tool-agnostic**: Use with Claude Code, Cursor, Aider, manual coding, or any workflow
|
|
56
56
|
- ✨ **Interactive onboarding**: Guided setup wizard gets you started in <5 minutes
|
|
57
57
|
|
|
58
|
-
## What's New in v0.6.
|
|
58
|
+
## What's New in v0.6.3
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
### Upgrade
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install --upgrade adversarial-workflow
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### v0.6.3 - Configurable Timeouts
|
|
67
|
+
|
|
68
|
+
- **Per-evaluator timeout**: Add `timeout: 300` to evaluator YAML for slow models like Mistral Large
|
|
69
|
+
- **CLI override**: Use `--timeout 400` to override YAML config on-the-fly
|
|
70
|
+
- **Timeout logging**: See which timeout source is used (CLI/YAML/default)
|
|
71
|
+
- **Safety limits**: Maximum 600 seconds to prevent runaway processes
|
|
72
|
+
|
|
73
|
+
### v0.6.2 - .env Loading & Stability
|
|
74
|
+
|
|
75
|
+
- **Automatic .env loading**: API keys in `.env` files are now loaded at CLI startup
|
|
76
|
+
- **Custom evaluator support**: Evaluators using `api_key_env: GEMINI_API_KEY` (or other keys) now work with `.env` files
|
|
77
|
+
- **Better diagnostics**: `adversarial check` correctly reports the number of variables loaded from `.env`
|
|
78
|
+
|
|
79
|
+
### v0.6.0 - Plugin Architecture
|
|
80
|
+
|
|
81
|
+
🔌 **Custom Evaluators** - Define your own evaluators without modifying the package:
|
|
61
82
|
|
|
62
83
|
```bash
|
|
63
84
|
# Create a custom evaluator
|
|
@@ -459,6 +480,7 @@ Starting with v0.6.0, you can define project-specific evaluators without modifyi
|
|
|
459
480
|
| `aliases` | No | Alternative command names |
|
|
460
481
|
| `log_prefix` | No | CLI output prefix |
|
|
461
482
|
| `fallback_model` | No | Fallback model if primary fails |
|
|
483
|
+
| `timeout` | No | Timeout in seconds (default: 180, max: 600) |
|
|
462
484
|
| `version` | No | Evaluator version (default: 1.0.0) |
|
|
463
485
|
|
|
464
486
|
### Listing Available Evaluators
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
adversarial_workflow/__init__.py,sha256=moTEp6nKU5F4B1YnJaSBmwhptkDP0ST5n--2hak9PRc,596
|
|
2
|
-
adversarial_workflow/__main__.py,sha256=
|
|
3
|
-
adversarial_workflow/cli.py,sha256=
|
|
2
|
+
adversarial_workflow/__main__.py,sha256=iM2jmO5YCFpGxfWiEhIYi_SsxVa0hRIE-MB7J0EcN7Y,120
|
|
3
|
+
adversarial_workflow/cli.py,sha256=FxjoC3KVUiwbOF7mWNPe6Zrk82fQcqyE8SPi5bo3ntI,111802
|
|
4
4
|
adversarial_workflow/evaluators/__init__.py,sha256=A9ZKUmjSMfyvEu6jDzYAFLxfkt_OQ4RGA10Bv_eO2i4,1267
|
|
5
5
|
adversarial_workflow/evaluators/builtins.py,sha256=u5LokYLe8ruEW2tunhOQaNSkpcZ9Ee2IeTkaC0dZDSY,1102
|
|
6
|
-
adversarial_workflow/evaluators/config.py,sha256=
|
|
7
|
-
adversarial_workflow/evaluators/discovery.py,sha256=
|
|
6
|
+
adversarial_workflow/evaluators/config.py,sha256=H_4vkto07rAqnz0qEYdzN_DH6WbvRPMIEdkEOFE58UI,1651
|
|
7
|
+
adversarial_workflow/evaluators/discovery.py,sha256=dPQ0dDy9anYjzLnG-V9gVrLkCVAVZ2tEE9dyFWqSvJc,8079
|
|
8
8
|
adversarial_workflow/evaluators/runner.py,sha256=JPVeigjGF2fRDVJLcGyDEuy9pCIp-LjmVAZyucMbdCU,9310
|
|
9
9
|
adversarial_workflow/templates/.aider.conf.yml.template,sha256=jT2jWIgsnmS3HLhoQWMTO3GV07bUcsT2keYw60jqiDw,183
|
|
10
10
|
adversarial_workflow/templates/.env.example.template,sha256=TmTlcgz44uZqIbqgXqdfHMl-0vVn96F_EGNohClFkb8,1821
|
|
@@ -25,9 +25,9 @@ adversarial_workflow/utils/colors.py,sha256=uRrG6KfIDBLo0F5_vPwms9NCm9-x8YXBiyZ4
|
|
|
25
25
|
adversarial_workflow/utils/config.py,sha256=NBoC_-YYukEVo6BgpX2cDyeqV-3tnn_sHNU9L1AuSLQ,1341
|
|
26
26
|
adversarial_workflow/utils/file_splitter.py,sha256=-zSWgAZ71DfX6dBu15Y4M84NBbJzq-0ENktbBEp9zvQ,12409
|
|
27
27
|
adversarial_workflow/utils/validation.py,sha256=ZiJxtm03kJXicfFTt0QZwpc9V_D8PkDOVYrJEDsafQI,2202
|
|
28
|
-
adversarial_workflow-0.6.
|
|
29
|
-
adversarial_workflow-0.6.
|
|
30
|
-
adversarial_workflow-0.6.
|
|
31
|
-
adversarial_workflow-0.6.
|
|
32
|
-
adversarial_workflow-0.6.
|
|
33
|
-
adversarial_workflow-0.6.
|
|
28
|
+
adversarial_workflow-0.6.3.dist-info/licenses/LICENSE,sha256=M-dOQlre-NmicyPa55hYOJUW8roGpCKEgtq-z0z1KCA,1073
|
|
29
|
+
adversarial_workflow-0.6.3.dist-info/METADATA,sha256=4dfW8_CURJEoooPFtdqtYu-R-BVj-SCC-AXg_teHklg,30835
|
|
30
|
+
adversarial_workflow-0.6.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
31
|
+
adversarial_workflow-0.6.3.dist-info/entry_points.txt,sha256=9H-iZ-yF1uKZ8P0G1suc6kWR0NvK7uPZJbhN7nvt1sE,62
|
|
32
|
+
adversarial_workflow-0.6.3.dist-info/top_level.txt,sha256=8irutNxLRjUbTlzfAibIpz7_ovkkF2h8ES69NQpv24c,21
|
|
33
|
+
adversarial_workflow-0.6.3.dist-info/RECORD,,
|
|
File without changes
|
{adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{adversarial_workflow-0.6.2.dist-info → adversarial_workflow-0.6.3.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|