diff --git a/bin/exec-constrained.py b/bin/exec-constrained.py index 58d45e2..98b24a6 100755 --- a/bin/exec-constrained.py +++ b/bin/exec-constrained.py @@ -82,7 +82,7 @@ WORK_DIR = '/home/super' class RateLimiter: """Token bucket per identity. Thread-safe.""" - def __init__(self, rate_per_min=20, burst=5): + def __init__(self, rate_per_min=60, burst=30): self.rate = rate_per_min / 60.0 self.burst = burst self._buckets = {} @@ -816,6 +816,23 @@ def _swarm_list_build(a): return [sys.executable, os.path.join(BIN_DIR, 'box-ctl.py'), 'swarm-list'] +def _swarm_results_validate(raw): + if not isinstance(raw, dict): + raise OpError('args must be an object') + allowed = {'swarm_id', 'id'} + for k in raw: + if k not in allowed: + raise OpError(f'unknown arg: {k}') + sid = raw.get('swarm_id') or raw.get('id') + if not isinstance(sid, str) or not TARGET_RE.fullmatch(sid): + raise OpError('swarm_id must match safe identifier') + return {'swarm_id': sid} + + +def _swarm_results_build(a): + return [sys.executable, os.path.join(BIN_DIR, 'box-ctl.py'), 'swarm-results', a['swarm_id']] + + # op -> {validate, build, timeout, side_effecting, description} OPS = { 'dm.send': { @@ -958,6 +975,11 @@ OPS = { 'timeout': 30, 'side_effecting': False, 'desc': 'List all subagent swarms and their counts', }, + 'swarm.results': { + 'validate': _swarm_results_validate, 'build': _swarm_results_build, + 'timeout': 30, 'side_effecting': False, + 'desc': 'Retrieve results and summaries for a completed swarm', + }, 'followup.create': { 'validate': _followup_create_validate, 'build': _followup_create_build, 'timeout': 30, 'side_effecting': True,