hackagent.orchestrator.campaign.runner
Run a campaign.
run_campaign loads and resolves the campaign, then sends every goal
through every attack. Each goal moves through its own pipeline. A static
attack generates its requests up front::
attack.generate(goal) -> target.acomplete(request) -> attack.decode(reply)
-> panel.aevaluate(sample) -> tracker.record(attempt)
An iterative attack searches against the target with the same panel in hand, because each verdict decides whether it keeps going. Every exchange it judged becomes an attempt, carrying the part of the search tree that produced it, and none is judged twice::
attack.run(goal, target, judge) -> tracker.record(attempt per finding)
When evaluation.audit is enabled the panel is measured against
labelled samples first, because a report that arrives after the run is
spent cannot stop anything.
Shared semaphores cap how many goals are attacked, how many requests reach
the target, and how many samples are judged at once, across all attacks. An
error in one goal or request becomes an attempt with error set; setup
failures, a store that refuses a write, and the per-attack timeout fail an
attack, and stop its other goals so nothing writes into a finished run.
An on_event listener that raises stops the whole campaign; raising
:class:CampaignCancelled records the runs as cancelled rather than
failed. Cancelling the task that runs :func:arun_campaign does the same.
EventCallback
Receives (event_name, **payload). An audited run first emits
audit_finished (audit), then attack_started (attack,
run_id, expected_goals), a goal_finished per goal (attack,
run_id, goal_index, success, attempts, errors (distinct
messages of its failed attempts and abstaining judges), elapsed_s), and
attack_finished (attack, run_id, error).
CampaignCancelled Objects
class CampaignCancelled(Exception)
Raised by an on_event listener to stop a campaign.
The runs it leaves are recorded as cancelled, not failed.
run_campaign
def run_campaign(
source: str | Path | Mapping[str, Any] | CampaignSpec,
*,
on_event: Optional[EventCallback] = None,
build: ModelBuilder = build_model,
load: GoalLoader = load_goals,
store: Optional[Store] = None,
calibration: CalibrationLoader = load_calibration,
build_embed: EmbedderBuilder = build_embedder,
settings: Optional[Settings] = None,
resolved: Optional[ResolvedCampaign] = None) -> CampaignResult
Synchronous form of :func:arun_campaign.
Safe to call while an event loop is already running, as in a notebook.
arun_campaign
async def arun_campaign(
source: str | Path | Mapping[str, Any] | CampaignSpec,
*,
on_event: Optional[EventCallback] = None,
build: ModelBuilder = build_model,
load: GoalLoader = load_goals,
store: Optional[Store] = None,
calibration: CalibrationLoader = load_calibration,
build_embed: EmbedderBuilder = build_embedder,
settings: Optional[Settings] = None,
resolved: Optional[ResolvedCampaign] = None) -> CampaignResult
Load, resolve, audit, and execute a campaign, then write its outputs.
A supplied store stays owned by the caller; one opened here is
closed before returning. When evaluation.audit says stop, a
panel that fails raises :class:~.audit.AuditFailed and nothing is
attacked.
A caller that already resolved the campaign — to report what the run
will do before starting it — passes it as resolved, and the goals
and models it checked are the ones the run uses. It has to come from
the same campaign, or the report would describe a different run.