control-tower 6.0.0rc3__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.
- control_tower-6.0.0rc3/LICENSE +21 -0
- control_tower-6.0.0rc3/MANIFEST.in +2 -0
- control_tower-6.0.0rc3/PKG-INFO +88 -0
- control_tower-6.0.0rc3/README.md +35 -0
- control_tower-6.0.0rc3/pyproject.toml +229 -0
- control_tower-6.0.0rc3/setup.cfg +4 -0
- control_tower-6.0.0rc3/src/control_tower/__init__.py +3 -0
- control_tower-6.0.0rc3/src/control_tower/cli/__init__.py +3 -0
- control_tower-6.0.0rc3/src/control_tower/cli/base.py +215 -0
- control_tower-6.0.0rc3/src/control_tower/cli/cloud.py +132 -0
- control_tower-6.0.0rc3/src/control_tower/cli/completions/completion_callbacks.py +125 -0
- control_tower-6.0.0rc3/src/control_tower/cli/completions/completions_build.py +59 -0
- control_tower-6.0.0rc3/src/control_tower/cli/completions/completions_hooks.py +209 -0
- control_tower-6.0.0rc3/src/control_tower/cli/ct_cli_group.py +28 -0
- control_tower-6.0.0rc3/src/control_tower/cli/extras.py +89 -0
- control_tower-6.0.0rc3/src/control_tower/cli/login.py +77 -0
- control_tower-6.0.0rc3/src/control_tower/cli/main.py +44 -0
- control_tower-6.0.0rc3/src/control_tower/cli/mcp_meta.py +30 -0
- control_tower-6.0.0rc3/src/control_tower/cli/task_sets.py +133 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/claude_host.py +26 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/dashboard.py +265 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/dashboard_cli.py +19 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/README.md +80 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/cli.py +81 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/models.py +63 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/prompts/system.md +68 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/prompts/user.md +30 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/audit/task.py +278 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/generate/README.md +75 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/generate/cli.py +146 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/generate/prompts/system.md +62 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/generate/prompts/user.md +21 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/generate/task.py +361 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/shared/concurrency.py +72 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/shared/spec.md +79 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/env_description/shared/spec_loader.py +24 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/README.md +59 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/cli.py +115 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/prompts/analyze.md +44 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/prompts/check_tasks.md +29 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/prompts/coverage.md +27 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/prompts/fix.md +14 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/integration_test_quality/task.py +160 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/pairing_analysis/README.md +30 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/pairing_analysis/cli.py +82 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/pairing_analysis/prompts/turn1.md +59 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/pairing_analysis/prompts/turn2.md +43 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/pairing_analysis/task.py +390 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/prompts.py +28 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/run_cli.py +16 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/base.py +216 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/_json.py +31 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/chroma.py +285 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/docker.py +366 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/elasticsearch.py +293 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/filesystem.py +155 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/generated_manifest.json +13 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/influxdb.py +549 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/listener.py +82 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/minio.py +360 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/mongo.py +338 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/openldap.py +241 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/postgres.py +317 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/process.py +134 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/rabbitmq.py +369 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/redis.py +291 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/sqlite.py +309 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/sshd.py +270 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/checks/vault.py +376 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/cli.py +560 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/compose_analyzer.py +182 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/detection.py +236 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/dockerfile_analyzer.py +377 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/llm_generator.py +448 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/runner.py +445 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/scorer_idempotency/runtime_prober.py +378 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/storage.py +74 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/compare_side_tasks/README.md +25 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/compare_side_tasks/cli.py +25 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/compare_side_tasks/task.py +126 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/README.md +77 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/audits/base.py +129 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/audits/goal.py +95 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/audits/sd.py +103 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/cli.py +207 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/heuristics/base.py +53 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/heuristics/goal.py +215 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/heuristics/sd.py +222 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/prompts/goal/system.md +109 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/prompts/goal/user.md +21 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/prompts/sd/system.md +311 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/prompts/sd/user.md +26 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/sd_audit_labels.json +98 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/doc_audit/task.py +227 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/failure_type_audit/cli.py +138 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/failure_type_audit/prompts/system.md +9 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/failure_type_audit/prompts/user.md +21 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/failure_type_audit/task.py +227 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/README.md +56 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/cli.py +125 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/prompts/system.md +46 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/prompts/user.md +60 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/task.py +358 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/goal_completeness/viewer.py +142 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/README.md +46 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/cli.py +115 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/prompts/system.md +71 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/prompts/user.md +62 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/task.py +388 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/reward_hacking/viewer.py +122 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/README.md +45 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/cli.py +119 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/prompts/system.md +50 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/prompts/user.md +57 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/task.py +387 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/rt_alignment/viewer.py +128 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/side_task_review/README.md +47 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/side_task_review/cli.py +95 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/side_task_review/prompts/review.md +29 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/side_task_review/task.py +101 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/validate_cover/README.md +32 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/validate_cover/cli.py +97 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/validate_cover/task.py +94 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/task_analysis/validate_cover/validate_cover_prompt.md +35 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/timing_report/__init__.py +17 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/timing_report/cli.py +71 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/timing_report/report.py +327 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/README.md +49 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/cli.py +125 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/prompts/system.md +29 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/prompts/user.md +72 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/task.py +402 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability/viewer.py +159 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/README.md +52 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/cli.py +143 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/prompts/system.md +36 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/prompts/user.md +63 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/task.py +762 -0
- control_tower-6.0.0rc3/src/control_tower/ct_runs/traj_analysis/submit_guessability_verified/viewer.py +186 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/check.py +88 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/cli.py +532 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/external.py +648 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/__init__.py +42 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/eval_log.py +570 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/monitoring_bench.py +643 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/mythos_5_incident.py +243 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/shade_arena.py +590 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/importers/sleight_bench.py +489 -0
- control_tower-6.0.0rc3/src/control_tower/datasets/model.py +45 -0
- control_tower-6.0.0rc3/src/control_tower/defaults.py +16 -0
- control_tower-6.0.0rc3/src/control_tower/environments/build.py +204 -0
- control_tower-6.0.0rc3/src/control_tower/environments/env_args.py +128 -0
- control_tower-6.0.0rc3/src/control_tower/environments/environment.py +130 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/.dockerignore +2 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/Dockerfile +91 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/__main__.py +4 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/compose.yml +35 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/constants.py +43 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/assets.py +276 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/generate_ca.py +68 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/logs.py +241 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/network_mapping.py +24 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/tls.py +124 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/trajectory.py +17 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/core/webhook.py +213 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/env_values.py +17 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/malware/malware.c +143 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/forward_proxy.py +425 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/resolver.py +88 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/response_rules.py +192 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/shell_sessions.py +206 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/upstream_proxy.py +256 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/modules/upstream_specs.py +200 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/personas.py +150 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/requirements.txt +4 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/resolve_override.c +75 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/runtimes/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/runtimes/docker.py +2154 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/runtimes/hawk.py +173 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/runtimes/participants.py +30 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/runtimes/provisioning.py +44 -0
- control_tower-6.0.0rc3/src/control_tower/environments/internet_simulator/server.py +600 -0
- control_tower-6.0.0rc3/src/control_tower/environments/list_utils.py +562 -0
- control_tower-6.0.0rc3/src/control_tower/environments/registry.py +302 -0
- control_tower-6.0.0rc3/src/control_tower/environments/remote/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/environments/remote/json_model.py +82 -0
- control_tower-6.0.0rc3/src/control_tower/environments/remote/process.py +238 -0
- control_tower-6.0.0rc3/src/control_tower/environments/remote/remote.py +463 -0
- control_tower-6.0.0rc3/src/control_tower/environments/remote/sample.py +289 -0
- control_tower-6.0.0rc3/src/control_tower/environments/requirements.py +174 -0
- control_tower-6.0.0rc3/src/control_tower/environments/setting_runtime.py +173 -0
- control_tower-6.0.0rc3/src/control_tower/environments/settings.py +1222 -0
- control_tower-6.0.0rc3/src/control_tower/environments/settings.yml +24 -0
- control_tower-6.0.0rc3/src/control_tower/environments/settings_cli.py +642 -0
- control_tower-6.0.0rc3/src/control_tower/environments/source_utils.py +304 -0
- control_tower-6.0.0rc3/src/control_tower/environments/validate.py +141 -0
- control_tower-6.0.0rc3/src/control_tower/eval/README.md +38 -0
- control_tower-6.0.0rc3/src/control_tower/eval/__init__.py +11 -0
- control_tower-6.0.0rc3/src/control_tower/eval/blue.py +537 -0
- control_tower-6.0.0rc3/src/control_tower/eval/cli.py +563 -0
- control_tower-6.0.0rc3/src/control_tower/eval/dataset.py +810 -0
- control_tower-6.0.0rc3/src/control_tower/eval/dispatch.py +514 -0
- control_tower-6.0.0rc3/src/control_tower/eval/game_view.py +28 -0
- control_tower-6.0.0rc3/src/control_tower/eval/harness.py +151 -0
- control_tower-6.0.0rc3/src/control_tower/eval/history.py +224 -0
- control_tower-6.0.0rc3/src/control_tower/eval/metadata.py +43 -0
- control_tower-6.0.0rc3/src/control_tower/eval/monitor_cli.py +143 -0
- control_tower-6.0.0rc3/src/control_tower/eval/monitor_task.py +156 -0
- control_tower-6.0.0rc3/src/control_tower/eval/monitoring/__init__.py +5 -0
- control_tower-6.0.0rc3/src/control_tower/eval/monitoring/monitor.py +301 -0
- control_tower-6.0.0rc3/src/control_tower/eval/monitoring/posthoc.py +248 -0
- control_tower-6.0.0rc3/src/control_tower/eval/options.py +122 -0
- control_tower-6.0.0rc3/src/control_tower/eval/protocols_cli.py +140 -0
- control_tower-6.0.0rc3/src/control_tower/eval/red.py +328 -0
- control_tower-6.0.0rc3/src/control_tower/eval/registry.py +59 -0
- control_tower-6.0.0rc3/src/control_tower/eval/run.py +409 -0
- control_tower-6.0.0rc3/src/control_tower/eval/solver.py +167 -0
- control_tower-6.0.0rc3/src/control_tower/eval/task.py +54 -0
- control_tower-6.0.0rc3/src/control_tower/eval/task_messages.py +55 -0
- control_tower-6.0.0rc3/src/control_tower/eval/task_scorer_validation.py +90 -0
- control_tower-6.0.0rc3/src/control_tower/eval/task_selection.py +284 -0
- control_tower-6.0.0rc3/src/control_tower/eval/white.py +71 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/api_upload.py +216 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/convert.py +1173 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/io.py +211 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/merge.py +93 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/monitor_scores.py +13 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/run_metadata.py +15 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/s3_upload.py +167 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/seat.py +85 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/source.py +51 -0
- control_tower-6.0.0rc3/src/control_tower/eval_logs/utils.py +85 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/__init__.py +1 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/ami.py +62 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/aws_identity.py +9 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/bootstrap.sh +395 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/controller.py +2359 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/job.py +371 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/run_job.py +253 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/worker.py +1094 -0
- control_tower-6.0.0rc3/src/control_tower/fleet/worker_cli.py +68 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/__init__.py +11 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/config.py +92 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/download.py +93 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/middleman.py +56 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/model_closure.py +33 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/preflight.py +161 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/pull_envs.py +95 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/runner.py +1038 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/sandbox.py +472 -0
- control_tower-6.0.0rc3/src/control_tower/hawk/yaml_generator.py +215 -0
- control_tower-6.0.0rc3/src/control_tower/inspect_tasks.py +271 -0
- control_tower-6.0.0rc3/src/control_tower/live/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/live/agents.py +717 -0
- control_tower-6.0.0rc3/src/control_tower/live/assets/dev_container_extensions.json +3 -0
- control_tower-6.0.0rc3/src/control_tower/live/assets/pyrightconfig.json +4 -0
- control_tower-6.0.0rc3/src/control_tower/live/assets/settings.json +3 -0
- control_tower-6.0.0rc3/src/control_tower/live/cli.py +1045 -0
- control_tower-6.0.0rc3/src/control_tower/live/compose.py +272 -0
- control_tower-6.0.0rc3/src/control_tower/live/context/print_context.py +98 -0
- control_tower-6.0.0rc3/src/control_tower/live/context/task_getters.py +78 -0
- control_tower-6.0.0rc3/src/control_tower/live/context/traj_dir.py +326 -0
- control_tower-6.0.0rc3/src/control_tower/live/daemon.py +545 -0
- control_tower-6.0.0rc3/src/control_tower/live/integration_tests.py +96 -0
- control_tower-6.0.0rc3/src/control_tower/live/remote_sandbox.py +154 -0
- control_tower-6.0.0rc3/src/control_tower/live/rpc.py +55 -0
- control_tower-6.0.0rc3/src/control_tower/live/sandbox_ops.py +129 -0
- control_tower-6.0.0rc3/src/control_tower/live/score.py +366 -0
- control_tower-6.0.0rc3/src/control_tower/live/session.py +733 -0
- control_tower-6.0.0rc3/src/control_tower/live/setup.py +299 -0
- control_tower-6.0.0rc3/src/control_tower/live/task_state.py +139 -0
- control_tower-6.0.0rc3/src/control_tower/live/test.py +10 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/gen_traj.py +345 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/git_status.py +33 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/git_traj.py +748 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/git_traj_helpers/FORMAT.md +25 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/git_traj_helpers/call_insert.py +15 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/git_traj_helpers/call_str_replace.py +20 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/macros.py +117 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/solution.py +265 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/add.py +14 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/add_tool_call.py +98 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/bash.py +128 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/git_utils.py +93 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/input_utils.py +145 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/template_from.py +118 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/templ/tool_call_builder.py +119 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/tool_call_utils.py +289 -0
- control_tower-6.0.0rc3/src/control_tower/live/traj/traj.py +316 -0
- control_tower-6.0.0rc3/src/control_tower/live/tui/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/live/tui/popup.py +293 -0
- control_tower-6.0.0rc3/src/control_tower/live/tui/tui.py +1237 -0
- control_tower-6.0.0rc3/src/control_tower/live/tui/tui.tcss +32 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/collect_testers.py +130 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/commands.py +313 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/full_env_context/container_script.py +230 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/full_env_context/full_env_context.py +68 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/migrate_traj.py +83 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/patch.py +64 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/test_all.py +1349 -0
- control_tower-6.0.0rc3/src/control_tower/live/usage/upload_helpers.py +31 -0
- control_tower-6.0.0rc3/src/control_tower/metrics/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/metrics/audit.py +353 -0
- control_tower-6.0.0rc3/src/control_tower/metrics/control.py +110 -0
- control_tower-6.0.0rc3/src/control_tower/models/__init__.py +11 -0
- control_tower-6.0.0rc3/src/control_tower/models/aliases.py +59 -0
- control_tower-6.0.0rc3/src/control_tower/models/cache_scopes.py +26 -0
- control_tower-6.0.0rc3/src/control_tower/models/inspect_rates.py +32 -0
- control_tower-6.0.0rc3/src/control_tower/models/model_spec.py +284 -0
- control_tower-6.0.0rc3/src/control_tower/models/openrouter_provider.py +65 -0
- control_tower-6.0.0rc3/src/control_tower/models/pricing.py +168 -0
- control_tower-6.0.0rc3/src/control_tower/models/rates.py +290 -0
- control_tower-6.0.0rc3/src/control_tower/models/registry_hooks.py +166 -0
- control_tower-6.0.0rc3/src/control_tower/models/role_model.py +55 -0
- control_tower-6.0.0rc3/src/control_tower/models/usage_hooks.py +14 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/__init__.py +36 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/checklist.py +96 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/jev.py +198 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/jev_questions.yml +32 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/monitor.py +466 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/presets.yml +28 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/action-no-goals.md +75 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/action.md +83 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/goal-analysis.md +77 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/goals.md +82 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/no-history.md +42 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/orthogonal.md +107 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/quick-no-goals.md +62 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/quick.md +68 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/simple.md +21 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/strong-goals.md +104 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/strong.md +95 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/prompts/trajectory.md +18 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/registry.py +19 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/single_goal.py +96 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/steps/checklist.md +48 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/steps/single_goal.md +80 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/steps/single_goal_analysis.md +76 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/steps/three_scores.md +112 -0
- control_tower-6.0.0rc3/src/control_tower/monitors/three_scores.py +69 -0
- control_tower-6.0.0rc3/src/control_tower/policies/__init__.py +1 -0
- control_tower-6.0.0rc3/src/control_tower/policies/attack.py +199 -0
- control_tower-6.0.0rc3/src/control_tower/policies/honest.py +28 -0
- control_tower-6.0.0rc3/src/control_tower/policies/obvious_attack.py +69 -0
- control_tower-6.0.0rc3/src/control_tower/policies/prompts/attack.md +7 -0
- control_tower-6.0.0rc3/src/control_tower/policies/prompts/attack_planning.md +22 -0
- control_tower-6.0.0rc3/src/control_tower/policies/replay.py +227 -0
- control_tower-6.0.0rc3/src/control_tower/policies/scripted.py +123 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/__init__.py +1 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/block_all.py +43 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/block_every_other.py +44 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/defer_to_trusted.py +152 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/null_blue.py +33 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/prompts/trusted_editing.md +9 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/resample.py +83 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/trusted_editing.py +167 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/trusted_monitoring.py +116 -0
- control_tower-6.0.0rc3/src/control_tower/protocols/watcher.py +341 -0
- control_tower-6.0.0rc3/src/control_tower/py.typed +0 -0
- control_tower-6.0.0rc3/src/control_tower/runs/README.md +85 -0
- control_tower-6.0.0rc3/src/control_tower/runs/convert.py +102 -0
- control_tower-6.0.0rc3/src/control_tower/runs/convert_eval_log_to_run.py +91 -0
- control_tower-6.0.0rc3/src/control_tower/runs/io.py +189 -0
- control_tower-6.0.0rc3/src/control_tower/runs/models.py +123 -0
- control_tower-6.0.0rc3/src/control_tower/runs/producer.py +4 -0
- control_tower-6.0.0rc3/src/control_tower/runs/runs_cli.py +679 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/__init__.py +6 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/_alpine_rootfs.py +230 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/_ssh.py +426 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/cli.py +301 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/constants.py +33 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/docker.py +1024 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/docker_in_vm.py +517 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/firecracker.py +413 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/inspect_tools.py +39 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/intranet.py +226 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/intranet_guard/Dockerfile +4 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/intranet_guard/firewall.sh +110 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/qemu.py +292 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/replay/__init__.py +22 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/replay/environment.py +435 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/replay/score.py +37 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/shared_containers.py +325 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/__init__.py +20 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/actions.py +90 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/compose.py +166 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/environment.py +182 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/judge.py +159 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/prompts/judge.md +31 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/prompts/simulator.md +74 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/prompts/simulator_no_exec.md +22 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/scratch/compose.yaml +42 -0
- control_tower-6.0.0rc3/src/control_tower/sandbox/simulated/session.py +156 -0
- control_tower-6.0.0rc3/src/control_tower/scanners.py +123 -0
- control_tower-6.0.0rc3/src/control_tower/task/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/task/collection.py +64 -0
- control_tower-6.0.0rc3/src/control_tower/task/final_diff.py +88 -0
- control_tower-6.0.0rc3/src/control_tower/task/sample_metadata.py +35 -0
- control_tower-6.0.0rc3/src/control_tower/task/scorers.py +351 -0
- control_tower-6.0.0rc3/src/control_tower/task/select_utils.py +106 -0
- control_tower-6.0.0rc3/src/control_tower/task/selectors.py +49 -0
- control_tower-6.0.0rc3/src/control_tower/task/setup.py +96 -0
- control_tower-6.0.0rc3/src/control_tower/task/space.py +21 -0
- control_tower-6.0.0rc3/src/control_tower/task/strat_sets/model_registry_strats.txt +11 -0
- control_tower-6.0.0rc3/src/control_tower/task/task.py +456 -0
- control_tower-6.0.0rc3/src/control_tower/task/task_sets/__init__.py +176 -0
- control_tower-6.0.0rc3/src/control_tower/task/traj_dir.py +39 -0
- control_tower-6.0.0rc3/src/control_tower/task/workspace_baseline.py +581 -0
- control_tower-6.0.0rc3/src/control_tower/tools/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/tools/answer.py +53 -0
- control_tower-6.0.0rc3/src/control_tower/tools/bash_tools.py +37 -0
- control_tower-6.0.0rc3/src/control_tower/tools/declarations.py +23 -0
- control_tower-6.0.0rc3/src/control_tower/tools/diff_display_text_editor.py +66 -0
- control_tower-6.0.0rc3/src/control_tower/tools/registry.py +37 -0
- control_tower-6.0.0rc3/src/control_tower/tools/split_text_editor_tools.py +125 -0
- control_tower-6.0.0rc3/src/control_tower/tools/submit.py +35 -0
- control_tower-6.0.0rc3/src/control_tower/tools/task_tools.py +237 -0
- control_tower-6.0.0rc3/src/control_tower/tools/tool_calls.py +46 -0
- control_tower-6.0.0rc3/src/control_tower/tools/tool_registry.py +371 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/README.md +76 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/action.py +122 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/api.py +615 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/eval_trace_metadata.py +15 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/extended_thinking.py +56 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/format_history.py +119 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/from_eval_log.py +323 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/io.py +205 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/models.py +25 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/mongo_docs.py +392 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/monitor_score.py +159 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/sample.py +328 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/task_scores.py +108 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/text_editor_output.py +69 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/timing_utils.py +419 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/tool_calls.py +40 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/utils.py +74 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/viewer_api.py +578 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/viewer_auth.py +50 -0
- control_tower-6.0.0rc3/src/control_tower/trajectories/workspace_diff.py +16 -0
- control_tower-6.0.0rc3/src/control_tower/utils/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/utils/cli_args.py +20 -0
- control_tower-6.0.0rc3/src/control_tower/utils/direct_api_generator.py +151 -0
- control_tower-6.0.0rc3/src/control_tower/utils/docs_utils.py +15 -0
- control_tower-6.0.0rc3/src/control_tower/utils/env.py +163 -0
- control_tower-6.0.0rc3/src/control_tower/utils/file_patterns.py +92 -0
- control_tower-6.0.0rc3/src/control_tower/utils/fs.py +137 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/__init__.py +0 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/arg_type.py +41 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/base_model.py +63 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/custom_handlers.py +99 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/display.py +137 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/function_info.py +97 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/naming.py +5 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/registry.py +419 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/selection.py +68 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/signature_info.py +78 -0
- control_tower-6.0.0rc3/src/control_tower/utils/function_registry/validation.py +97 -0
- control_tower-6.0.0rc3/src/control_tower/utils/imports.py +35 -0
- control_tower-6.0.0rc3/src/control_tower/utils/paths.py +98 -0
- control_tower-6.0.0rc3/src/control_tower/utils/sanitize.py +74 -0
- control_tower-6.0.0rc3/src/control_tower/utils/serde.py +151 -0
- control_tower-6.0.0rc3/src/control_tower/utils/suggestions.py +25 -0
- control_tower-6.0.0rc3/src/control_tower/utils/time.py +18 -0
- control_tower-6.0.0rc3/src/control_tower/utils/transcript.py +20 -0
- control_tower-6.0.0rc3/src/control_tower/utils/versioning.py +383 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/PKG-INFO +88 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/SOURCES.txt +479 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/dependency_links.txt +1 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/entry_points.txt +5 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/requires.txt +34 -0
- control_tower-6.0.0rc3/src/control_tower.egg-info/top_level.txt +1 -0
- control_tower-6.0.0rc3/tests/test_correct_environments.py +34 -0
- control_tower-6.0.0rc3/tests/test_serde.py +41 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LinuxArena
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: control-tower
|
|
3
|
+
Version: 6.0.0rc3
|
|
4
|
+
Summary: Control Tower evaluation framework for AI control research
|
|
5
|
+
Author: LinuxArena
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://linuxarena.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/linuxarena/control-tower
|
|
9
|
+
Keywords: ai-control,agent-evaluation,evals,monitoring,sabotage
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: click==8.2.1
|
|
21
|
+
Requires-Dist: dnslib>=0.9.26
|
|
22
|
+
Requires-Dist: docstring-parser>=0.17
|
|
23
|
+
Requires-Dist: flask>=3.1.3
|
|
24
|
+
Requires-Dist: gitignore-parser==0.1.13
|
|
25
|
+
Requires-Dist: gitpython>=3.1.46
|
|
26
|
+
Requires-Dist: inspect-ai==0.3.268
|
|
27
|
+
Requires-Dist: inspect-scout==0.5.3
|
|
28
|
+
Requires-Dist: jsonlines>=4.0.0
|
|
29
|
+
Requires-Dist: inspect-swe==0.2.70
|
|
30
|
+
Requires-Dist: pick==2.6.0
|
|
31
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
32
|
+
Requires-Dist: python-dotenv==1.2.2
|
|
33
|
+
Requires-Dist: pytz>=2025.0
|
|
34
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
35
|
+
Requires-Dist: scipy>=1.17.0
|
|
36
|
+
Requires-Dist: tabulate>=0.10.0
|
|
37
|
+
Requires-Dist: tenacity>=9.1.4
|
|
38
|
+
Requires-Dist: textual>=8.1.1
|
|
39
|
+
Requires-Dist: tqdm>=4.67.3
|
|
40
|
+
Requires-Dist: unidiff==0.7.5
|
|
41
|
+
Requires-Dist: anthropic>=1.0.0
|
|
42
|
+
Requires-Dist: claude-agent-sdk>=0.1.50
|
|
43
|
+
Requires-Dist: openai>=3.1.0
|
|
44
|
+
Requires-Dist: boto3>=1.40.0
|
|
45
|
+
Requires-Dist: zstandard>=0.25.0
|
|
46
|
+
Requires-Dist: ct-setting-sdk<5,>=4.0.0rc1
|
|
47
|
+
Provides-Extra: hf
|
|
48
|
+
Requires-Dist: pyarrow>=17.0.0; extra == "hf"
|
|
49
|
+
Provides-Extra: providers
|
|
50
|
+
Requires-Dist: google-genai>=1.68.0; extra == "providers"
|
|
51
|
+
Requires-Dist: xai-sdk>=1.9.1; extra == "providers"
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
Welcome to Control Tower, a framework for AI control evaluations built on [Inspect](https://inspect.aisi.org.uk/) and developed by [EquiStamp](https://equistamp.com/), [Redwood Research](https://www.redwoodresearch.org/), and [Luthien](https://luthien.cc/).
|
|
55
|
+
|
|
56
|
+
> 🚨 Control Tower is in active development. [Star this repo](https://github.com/linuxarena/control-tower) to follow updates, or [Watch > Releases](https://github.com/linuxarena/control-tower/subscription) to get notified on new versions.
|
|
57
|
+
>
|
|
58
|
+
> Found a bug or have a question? [Open an issue](https://github.com/linuxarena/control-tower/issues), [submit a PR](https://github.com/linuxarena/control-tower/compare) or [book a call](https://calendar.app.google/j7K8yncsBvPfxomS7)
|
|
59
|
+
|
|
60
|
+
Control Tower provides many built-in components, including blue-team protocols, action- and trajectory-level monitors, control evaluations, safety-usefulness curves, and trajectory tooling. Environments and their main and side tasks come from separate settings repositories, and extensions (new protocols, policies, monitors, and scorers) can be provided by other Python packages.
|
|
61
|
+
|
|
62
|
+
See the [documentation](https://docs.linuxarena.ai) for an overview of Control Tower, a hands-on evaluation walkthrough, and development guides.
|
|
63
|
+
|
|
64
|
+
To get started:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/linuxarena/control-tower && cd control-tower
|
|
68
|
+
uv sync
|
|
69
|
+
alias ct='uv run ct' # add to your shell profile to keep it
|
|
70
|
+
cp .env.example .env # set ANTHROPIC_API_KEY (or OPENAI_API_KEY)
|
|
71
|
+
ct settings pull linuxarena
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Check the install without spending a model call. It takes a couple of minutes:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ct run eval --policy ct/test --task-file simple --tag test
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Then run a real eval. The first one builds the environment image, which takes about ten minutes:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
ct run eval --policy ct/attack -e linuxarena/clinical_trial -t adverse_reaction_followup_tracking -s suppress_safety_notifications
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
***
|
|
87
|
+
|
|
88
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for code style, typing, testing, and pull request conventions, and the [development setup guide](https://docs.linuxarena.ai/development/dev-setup) for local services, environment pulls, and shell completions.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Welcome to Control Tower, a framework for AI control evaluations built on [Inspect](https://inspect.aisi.org.uk/) and developed by [EquiStamp](https://equistamp.com/), [Redwood Research](https://www.redwoodresearch.org/), and [Luthien](https://luthien.cc/).
|
|
2
|
+
|
|
3
|
+
> 🚨 Control Tower is in active development. [Star this repo](https://github.com/linuxarena/control-tower) to follow updates, or [Watch > Releases](https://github.com/linuxarena/control-tower/subscription) to get notified on new versions.
|
|
4
|
+
>
|
|
5
|
+
> Found a bug or have a question? [Open an issue](https://github.com/linuxarena/control-tower/issues), [submit a PR](https://github.com/linuxarena/control-tower/compare) or [book a call](https://calendar.app.google/j7K8yncsBvPfxomS7)
|
|
6
|
+
|
|
7
|
+
Control Tower provides many built-in components, including blue-team protocols, action- and trajectory-level monitors, control evaluations, safety-usefulness curves, and trajectory tooling. Environments and their main and side tasks come from separate settings repositories, and extensions (new protocols, policies, monitors, and scorers) can be provided by other Python packages.
|
|
8
|
+
|
|
9
|
+
See the [documentation](https://docs.linuxarena.ai) for an overview of Control Tower, a hands-on evaluation walkthrough, and development guides.
|
|
10
|
+
|
|
11
|
+
To get started:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
git clone https://github.com/linuxarena/control-tower && cd control-tower
|
|
15
|
+
uv sync
|
|
16
|
+
alias ct='uv run ct' # add to your shell profile to keep it
|
|
17
|
+
cp .env.example .env # set ANTHROPIC_API_KEY (or OPENAI_API_KEY)
|
|
18
|
+
ct settings pull linuxarena
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Check the install without spending a model call. It takes a couple of minutes:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ct run eval --policy ct/test --task-file simple --tag test
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then run a real eval. The first one builds the environment image, which takes about ten minutes:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ct run eval --policy ct/attack -e linuxarena/clinical_trial -t adverse_reaction_followup_tracking -s suppress_safety_notifications
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
***
|
|
34
|
+
|
|
35
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for code style, typing, testing, and pull request conventions, and the [development setup guide](https://docs.linuxarena.ai/development/dev-setup) for local services, environment pulls, and shell completions.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "control-tower"
|
|
3
|
+
version = "6.0.0rc3"
|
|
4
|
+
description = "Control Tower evaluation framework for AI control research"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "LinuxArena" }]
|
|
10
|
+
keywords = ["ai-control", "agent-evaluation", "evals", "monitoring", "sabotage"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
# CLI and core runtime
|
|
22
|
+
"click==8.2.1",
|
|
23
|
+
"dnslib>=0.9.26",
|
|
24
|
+
"docstring-parser>=0.17",
|
|
25
|
+
"flask>=3.1.3",
|
|
26
|
+
"gitignore-parser==0.1.13",
|
|
27
|
+
"gitpython>=3.1.46",
|
|
28
|
+
"inspect-ai==0.3.268",
|
|
29
|
+
"inspect-scout==0.5.3",
|
|
30
|
+
"jsonlines>=4.0.0",
|
|
31
|
+
"inspect-swe==0.2.70",
|
|
32
|
+
"pick==2.6.0",
|
|
33
|
+
"pydantic-settings>=2.0",
|
|
34
|
+
"python-dotenv==1.2.2",
|
|
35
|
+
"pytz>=2025.0",
|
|
36
|
+
"pyyaml>=6.0.3",
|
|
37
|
+
"scipy>=1.17.0",
|
|
38
|
+
"tabulate>=0.10.0",
|
|
39
|
+
"tenacity>=9.1.4",
|
|
40
|
+
"textual>=8.1.1",
|
|
41
|
+
"tqdm>=4.67.3",
|
|
42
|
+
"unidiff==0.7.5",
|
|
43
|
+
|
|
44
|
+
# Primary model providers and agent SDKs (openai also backs OpenRouter)
|
|
45
|
+
"anthropic>=1.0.0",
|
|
46
|
+
"claude-agent-sdk>=0.1.50",
|
|
47
|
+
"openai>=3.1.0",
|
|
48
|
+
|
|
49
|
+
# Run storage and upload (`ct run eval --upload`)
|
|
50
|
+
"boto3>=1.40.0",
|
|
51
|
+
"zstandard>=0.25.0",
|
|
52
|
+
|
|
53
|
+
# The env API's wire contract, shared with every setting package
|
|
54
|
+
"ct-setting-sdk>=4.0.0rc1,<5",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[project.optional-dependencies]
|
|
58
|
+
hf = ["pyarrow>=17.0.0"]
|
|
59
|
+
providers = [
|
|
60
|
+
"google-genai>=1.68.0",
|
|
61
|
+
"xai-sdk>=1.9.1",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["setuptools"]
|
|
66
|
+
build-backend = "setuptools.build_meta"
|
|
67
|
+
|
|
68
|
+
[tool.setuptools.packages.find]
|
|
69
|
+
where = ["src"]
|
|
70
|
+
namespaces = true
|
|
71
|
+
exclude = ["experiments*"]
|
|
72
|
+
|
|
73
|
+
[tool.setuptools.package-data]
|
|
74
|
+
# Non-Python assets that must be available from installed wheels.
|
|
75
|
+
"*" = [
|
|
76
|
+
"*.md",
|
|
77
|
+
"*.txt",
|
|
78
|
+
"*.yml",
|
|
79
|
+
"*.yaml",
|
|
80
|
+
"*.json",
|
|
81
|
+
"*.jsonl",
|
|
82
|
+
"*.tcss",
|
|
83
|
+
"*.sh",
|
|
84
|
+
"py.typed",
|
|
85
|
+
]
|
|
86
|
+
"control_tower.sandbox.intranet_guard" = ["Dockerfile"]
|
|
87
|
+
"control_tower.environments.internet_simulator" = [
|
|
88
|
+
"Dockerfile",
|
|
89
|
+
".dockerignore",
|
|
90
|
+
"resolve_override.c",
|
|
91
|
+
"malware/malware.c",
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
[tool.setuptools.package-dir]
|
|
95
|
+
"" = "src"
|
|
96
|
+
|
|
97
|
+
[dependency-groups]
|
|
98
|
+
dev = [
|
|
99
|
+
"moto>=5.1.22",
|
|
100
|
+
"pyright==1.1.411", # kept for `--verifytypes` coverage gate; ty has no equivalent yet
|
|
101
|
+
"pytest==9.1.1",
|
|
102
|
+
"pytest-asyncio==1.4.0",
|
|
103
|
+
"pytest-xdist==3.8.0",
|
|
104
|
+
"ruff==0.15.20",
|
|
105
|
+
"ty==0.0.33", # primary type checker; pinned because pre-1.0
|
|
106
|
+
"vulture>=2.15",
|
|
107
|
+
"yamllint==1.38.0",
|
|
108
|
+
"yamlfix>=1.19.1",
|
|
109
|
+
]
|
|
110
|
+
# A group, not a dependency: PyPI rejects direct-URL requirements, and Apollo ships the SDK only as a GitHub wheel.
|
|
111
|
+
watcher = [
|
|
112
|
+
# 0.41.0 or later: the protocol reads `cost_usd` from each hook outcome.
|
|
113
|
+
"watcher-sdk @ https://github.com/ApolloResearch/watcher-bin/releases/download/v0.41.0/watcher_sdk-0.41.0-py3-none-any.whl",
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
[tool.uv]
|
|
117
|
+
default-groups = ["dev", "watcher"]
|
|
118
|
+
|
|
119
|
+
[tool.uv.sources]
|
|
120
|
+
ct-setting-sdk = { path = "packages/ct-setting-sdk", editable = true }
|
|
121
|
+
|
|
122
|
+
[project.scripts]
|
|
123
|
+
ct = "control_tower.cli.main:main"
|
|
124
|
+
|
|
125
|
+
[project.entry-points.inspect_ai]
|
|
126
|
+
# Registers ``control_tower/eval`` and ``control_tower/control_eval`` as discoverable
|
|
127
|
+
# Inspect AI @tasks (plus the ct_upload and ct_diagnostics hooks) after pip-installing control-tower.
|
|
128
|
+
control_tower = "control_tower.inspect_tasks"
|
|
129
|
+
|
|
130
|
+
[project.urls]
|
|
131
|
+
Homepage = "https://linuxarena.ai"
|
|
132
|
+
Repository = "https://github.com/linuxarena/control-tower"
|
|
133
|
+
|
|
134
|
+
[tool.ruff]
|
|
135
|
+
required-version = "==0.15.20"
|
|
136
|
+
src = []
|
|
137
|
+
extend-exclude = [
|
|
138
|
+
".settings/**",
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
[tool.ruff.lint]
|
|
142
|
+
extend-select = ["I", "UP", "ANN", "PLC0415", "S110"]
|
|
143
|
+
ignore = [
|
|
144
|
+
"ANN002", # missing type annotation for *args
|
|
145
|
+
"ANN003", # missing type annotation for **kwargs
|
|
146
|
+
"ANN204", # missing return type for __init__ / __new__ / dunder
|
|
147
|
+
"ANN401", # disallow Any — too strict for this codebase
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
[tool.ruff.lint.isort]
|
|
151
|
+
known-first-party = ["control_tower", "ct_setting_sdk"]
|
|
152
|
+
|
|
153
|
+
[tool.ruff.lint.per-file-ignores]
|
|
154
|
+
"tests/**" = ["ANN", "PLC0415"]
|
|
155
|
+
"packages/*/tests/**" = ["ANN", "PLC0415"]
|
|
156
|
+
"scripts/**" = ["PLC0415"]
|
|
157
|
+
# CLI convention: imports stay inside command functions so `ct` starts fast
|
|
158
|
+
"src/**/cli/**" = ["PLC0415"]
|
|
159
|
+
"src/**/cli.py" = ["PLC0415"]
|
|
160
|
+
"src/**/*_cli.py" = ["PLC0415"]
|
|
161
|
+
|
|
162
|
+
[tool.pytest.ini_options]
|
|
163
|
+
testpaths = ["tests", "packages/ct-setting-sdk/tests"]
|
|
164
|
+
markers = [
|
|
165
|
+
"integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
|
|
166
|
+
"slow: marks tests as slow running",
|
|
167
|
+
]
|
|
168
|
+
addopts = "-m 'not integration' --durations=10 --ignore=tests/replay_check/packages"
|
|
169
|
+
|
|
170
|
+
[tool.control_tower.typing]
|
|
171
|
+
verifytypes_min_completeness = 100.0
|
|
172
|
+
|
|
173
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
174
|
+
name = "only cli may import ct_runs (generation/orchestration tooling)"
|
|
175
|
+
sources = ["*"]
|
|
176
|
+
ignore_sources = ["cli", "ct_runs", "ct_runs.*"]
|
|
177
|
+
targets = ["ct_runs", "ct_runs.*"]
|
|
178
|
+
allowed_files = [
|
|
179
|
+
"src/control_tower/hawk/runner.py",
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
183
|
+
name = "ct_runs subpackages are independent except declared edges"
|
|
184
|
+
sources = ["ct_runs.*"]
|
|
185
|
+
targets = ["ct_runs", "ct_runs.*"]
|
|
186
|
+
allowed_edges = [
|
|
187
|
+
"ct_runs.* -> ct_runs.claude_host",
|
|
188
|
+
"ct_runs.* -> ct_runs.prompts",
|
|
189
|
+
"ct_runs.* -> ct_runs.storage",
|
|
190
|
+
"ct_runs.dashboard_cli -> ct_runs.dashboard",
|
|
191
|
+
"ct_runs.run_cli -> ct_runs.*",
|
|
192
|
+
"ct_runs.task_analysis -> ct_runs.traj_analysis",
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
196
|
+
name = "utils and defaults are leaves"
|
|
197
|
+
sources = ["utils", "defaults"]
|
|
198
|
+
targets = ["*"]
|
|
199
|
+
|
|
200
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
201
|
+
name = "monitors stand alone: they import only models, tools and utils"
|
|
202
|
+
sources = ["monitors"]
|
|
203
|
+
targets = ["*"]
|
|
204
|
+
allowed_edges = [
|
|
205
|
+
"monitors -> models",
|
|
206
|
+
"monitors -> tools",
|
|
207
|
+
"monitors -> utils",
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
211
|
+
name = "trajectories must not import live"
|
|
212
|
+
sources = ["trajectories"]
|
|
213
|
+
targets = ["live"]
|
|
214
|
+
|
|
215
|
+
[tool.ty.src]
|
|
216
|
+
include = [
|
|
217
|
+
".github/scripts",
|
|
218
|
+
"packages/ct-setting-sdk/src",
|
|
219
|
+
"scripts",
|
|
220
|
+
"src/control_tower",
|
|
221
|
+
"tests",
|
|
222
|
+
]
|
|
223
|
+
exclude = [
|
|
224
|
+
"**/node_modules",
|
|
225
|
+
".settings/**",
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
[tool.ty.environment]
|
|
229
|
+
python-version = "3.13"
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
import termios
|
|
6
|
+
import tty
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, cast
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from control_tower.cli.completions.completion_callbacks import (
|
|
14
|
+
completion_env_names,
|
|
15
|
+
completion_main_task_names,
|
|
16
|
+
completion_side_task_names,
|
|
17
|
+
)
|
|
18
|
+
from ct_setting_sdk.protocol.errors import ExpectedError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def getch() -> str:
|
|
22
|
+
"""Read a single character from stdin without requiring Enter.
|
|
23
|
+
|
|
24
|
+
Handles arrow keys by returning "left" or "right" strings.
|
|
25
|
+
"""
|
|
26
|
+
fd = sys.stdin.fileno()
|
|
27
|
+
old_settings = termios.tcgetattr(fd)
|
|
28
|
+
try:
|
|
29
|
+
tty.setraw(fd)
|
|
30
|
+
ch = sys.stdin.read(1)
|
|
31
|
+
if ch == "\x1b":
|
|
32
|
+
ch2 = sys.stdin.read(1)
|
|
33
|
+
if ch2 == "[":
|
|
34
|
+
ch3 = sys.stdin.read(1)
|
|
35
|
+
if ch3 == "D":
|
|
36
|
+
return "left"
|
|
37
|
+
elif ch3 == "C":
|
|
38
|
+
return "right"
|
|
39
|
+
return ch
|
|
40
|
+
finally:
|
|
41
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def clear_screen() -> None:
|
|
45
|
+
"""Clear the terminal screen."""
|
|
46
|
+
click.echo("\033[2J\033[H", nl=False)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def word_wrap(text: str, width: int) -> list[str]:
|
|
50
|
+
"""Wrap text to specified width, preserving line breaks."""
|
|
51
|
+
result = []
|
|
52
|
+
for paragraph in text.split("\n"):
|
|
53
|
+
if not paragraph.strip():
|
|
54
|
+
result.append("")
|
|
55
|
+
continue
|
|
56
|
+
words = paragraph.split()
|
|
57
|
+
current_line = ""
|
|
58
|
+
for word in words:
|
|
59
|
+
if len(current_line) + len(word) + 1 > width:
|
|
60
|
+
if current_line:
|
|
61
|
+
result.append(current_line)
|
|
62
|
+
current_line = word
|
|
63
|
+
else:
|
|
64
|
+
current_line += (" " if current_line else "") + word
|
|
65
|
+
if current_line:
|
|
66
|
+
result.append(current_line)
|
|
67
|
+
return result
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def load_jsonl(path: Path) -> list[dict[str, Any]]:
|
|
71
|
+
"""Load all non-empty lines from a JSONL file as dicts."""
|
|
72
|
+
results = []
|
|
73
|
+
with open(path) as f:
|
|
74
|
+
for line in f:
|
|
75
|
+
line = line.strip()
|
|
76
|
+
if line:
|
|
77
|
+
results.append(json.loads(line))
|
|
78
|
+
return results
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def select_audit_run(runs_dir: Path, title: str = "Select audit run") -> Path | None:
|
|
82
|
+
"""Interactive picker for audit run directories. Returns None if no runs or user cancels."""
|
|
83
|
+
from pick import Option, pick
|
|
84
|
+
|
|
85
|
+
if not runs_dir.exists():
|
|
86
|
+
click.secho(f"No runs found in {runs_dir}/", fg="yellow")
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
runs = sorted(
|
|
90
|
+
[d for d in runs_dir.iterdir() if d.is_dir()],
|
|
91
|
+
key=lambda p: p.stat().st_ctime,
|
|
92
|
+
reverse=True,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if not runs:
|
|
96
|
+
click.secho(f"No runs found in {runs_dir}/", fg="yellow")
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
options: list[Option] = []
|
|
100
|
+
for run in runs:
|
|
101
|
+
results_file = run / "results.jsonl"
|
|
102
|
+
count = 0
|
|
103
|
+
if results_file.exists():
|
|
104
|
+
count = sum(1 for _ in results_file.open())
|
|
105
|
+
label = f"{run.name} ({count} results)"
|
|
106
|
+
options.append(Option(label, run))
|
|
107
|
+
|
|
108
|
+
selected, _ = pick(
|
|
109
|
+
options,
|
|
110
|
+
title=title,
|
|
111
|
+
indicator="=>",
|
|
112
|
+
default_index=0,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return selected.value if isinstance(selected, Option) else Path(str(selected))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _build_param_map(click_params: list[click.Parameter]) -> dict[str, str]:
|
|
119
|
+
"""Build mapping from Python param names to CLI representations."""
|
|
120
|
+
param_map: dict[str, str] = {}
|
|
121
|
+
|
|
122
|
+
for param in click_params:
|
|
123
|
+
if not param.name:
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
param_name = param.name
|
|
127
|
+
if not isinstance(param_name, str):
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
if isinstance(param, click.Option):
|
|
131
|
+
if param.opts:
|
|
132
|
+
cli_name = cast(str, max(param.opts, key=len))
|
|
133
|
+
param_map[param_name] = cli_name
|
|
134
|
+
elif isinstance(param, click.Argument):
|
|
135
|
+
param_map[param_name] = param_name.upper()
|
|
136
|
+
|
|
137
|
+
return param_map
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _transform_error_message(message: str, click_params: list[click.Parameter]) -> str:
|
|
141
|
+
"""Transform parameter names in error message to CLI equivalents."""
|
|
142
|
+
param_map = _build_param_map(click_params)
|
|
143
|
+
|
|
144
|
+
for py_name, cli_name in param_map.items():
|
|
145
|
+
message = re.sub(rf"`{re.escape(py_name)}`", cli_name, message)
|
|
146
|
+
|
|
147
|
+
if "_" in py_name:
|
|
148
|
+
message = re.sub(rf"\b{re.escape(py_name)}\b", cli_name, message)
|
|
149
|
+
|
|
150
|
+
return message
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def handle_user_errors(f: Callable[..., object]) -> Callable[..., object]:
|
|
154
|
+
"""Decorator that converts ExpectedError exceptions to click.ClickException.
|
|
155
|
+
|
|
156
|
+
Apply this decorator to Click commands to ensure that ExpectedError exceptions
|
|
157
|
+
are displayed cleanly without a stack trace, while unexpected errors still
|
|
158
|
+
show full tracebacks for debugging.
|
|
159
|
+
|
|
160
|
+
Also transforms parameter names in error messages to their CLI equivalents:
|
|
161
|
+
- `param` (backtick-wrapped) -> --param
|
|
162
|
+
- param_name (with underscores) -> --param-name
|
|
163
|
+
|
|
164
|
+
Adds a --traceback flag to show full stack traces for expected errors.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
@functools.wraps(f)
|
|
168
|
+
def wrapper(*args: object, traceback: bool = False, **kwargs: object) -> object:
|
|
169
|
+
if traceback:
|
|
170
|
+
return f(*args, **kwargs)
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
return f(*args, **kwargs)
|
|
174
|
+
except ExpectedError as e:
|
|
175
|
+
message = str(e)
|
|
176
|
+
|
|
177
|
+
ctx = click.get_current_context(silent=True)
|
|
178
|
+
if ctx and ctx.command:
|
|
179
|
+
message = _transform_error_message(message, ctx.command.params)
|
|
180
|
+
|
|
181
|
+
raise click.ClickException(message) from None
|
|
182
|
+
|
|
183
|
+
return click.option(
|
|
184
|
+
"--traceback",
|
|
185
|
+
is_flag=True,
|
|
186
|
+
hidden=True,
|
|
187
|
+
help="Show full traceback for expected errors (for debugging)",
|
|
188
|
+
)(wrapper)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def task_override_options[F: Callable[..., object]](func: F) -> F:
|
|
192
|
+
"""Add -e/--env, -t/--main-task and -s/--side-task options with shell completion."""
|
|
193
|
+
func = click.option(
|
|
194
|
+
"-s",
|
|
195
|
+
"--side-task",
|
|
196
|
+
type=str,
|
|
197
|
+
shell_complete=completion_side_task_names,
|
|
198
|
+
help="Side task name",
|
|
199
|
+
)(func)
|
|
200
|
+
func = click.option(
|
|
201
|
+
"-t",
|
|
202
|
+
"--main-task",
|
|
203
|
+
type=str,
|
|
204
|
+
shell_complete=completion_main_task_names,
|
|
205
|
+
help="Main task name",
|
|
206
|
+
)(func)
|
|
207
|
+
func = click.option(
|
|
208
|
+
"-e",
|
|
209
|
+
"--env",
|
|
210
|
+
"environment",
|
|
211
|
+
type=str,
|
|
212
|
+
shell_complete=completion_env_names,
|
|
213
|
+
help="Environment name",
|
|
214
|
+
)(func)
|
|
215
|
+
return func
|