hackagent 0.4.1__tar.gz → 0.4.3__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.
- {hackagent-0.4.1 → hackagent-0.4.3}/PKG-INFO +6 -1
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/orchestrator.py +67 -3
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/attack.py +149 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/completions.py +48 -37
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/evaluation.py +10 -2
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/evaluators.py +134 -31
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/generate.py +84 -43
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/base.py +3 -2
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/baseline/evaluation.py +138 -8
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/baseline/generation.py +105 -31
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/pair/attack.py +187 -42
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/commands/agent.py +1 -1
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/commands/attack.py +24 -5
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/attacks.py +1 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/config.py +37 -1
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/widgets/logs.py +32 -5
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/utils.py +1 -0
- hackagent-0.4.3/hackagent/datasets/__init__.py +63 -0
- hackagent-0.4.3/hackagent/datasets/base.py +99 -0
- hackagent-0.4.3/hackagent/datasets/presets.py +223 -0
- hackagent-0.4.3/hackagent/datasets/providers/__init__.py +23 -0
- hackagent-0.4.3/hackagent/datasets/providers/file.py +236 -0
- hackagent-0.4.3/hackagent/datasets/providers/huggingface.py +183 -0
- hackagent-0.4.3/hackagent/datasets/registry.py +247 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/__init__.py +6 -4
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/adapters/__init__.py +31 -11
- hackagent-0.4.3/hackagent/router/adapters/base.py +662 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/adapters/google_adk.py +42 -50
- hackagent-0.4.1/hackagent/router/adapters/litellm_adapter.py → hackagent-0.4.3/hackagent/router/adapters/litellm.py +115 -204
- hackagent-0.4.3/hackagent/router/adapters/ollama.py +510 -0
- hackagent-0.4.1/hackagent/router/adapters/openai_adapter.py → hackagent-0.4.3/hackagent/router/adapters/openai.py +95 -217
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/router.py +216 -12
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/tracking/__init__.py +15 -2
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/tracking/decorators.py +1 -1
- hackagent-0.4.1/hackagent/router/tracking/tracker.py → hackagent-0.4.3/hackagent/router/tracking/step.py +141 -9
- hackagent-0.4.3/hackagent/router/tracking/tracker.py +646 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/types.py +5 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/pyproject.toml +12 -3
- hackagent-0.4.1/hackagent/router/adapters/base.py +0 -63
- {hackagent-0.4.1 → hackagent-0.4.3}/.gitignore +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/LICENSE +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/README.md +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/agent.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/__init__.py +0 -0
- {hackagent-0.4.1/hackagent/api/user → hackagent-0.4.3/hackagent/api/agent}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/agent/agent_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/run → hackagent-0.4.3/hackagent/api/apilogs}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/apilogs/apilogs_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/apilogs/apilogs_retrieve.py +0 -0
- {hackagent-0.4.1/hackagent/api/result → hackagent-0.4.3/hackagent/api/attack}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/attack/attack_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/prompt → hackagent-0.4.3/hackagent/api/checkout}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/checkout/checkout_create.py +0 -0
- {hackagent-0.4.1/hackagent/api/organization → hackagent-0.4.3/hackagent/api/generate}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/generate/generate_create.py +0 -0
- {hackagent-0.4.1/hackagent/api/key → hackagent-0.4.3/hackagent/api/judge}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/judge/judge_create.py +0 -0
- {hackagent-0.4.1/hackagent/api/judge → hackagent-0.4.3/hackagent/api/key}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/key/key_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/key/key_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/key/key_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/key/key_retrieve.py +0 -0
- {hackagent-0.4.1/hackagent/api/generate → hackagent-0.4.3/hackagent/api/organization}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_me_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/organization/organization_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/checkout → hackagent-0.4.3/hackagent/api/prompt}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/prompt/prompt_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/attack → hackagent-0.4.3/hackagent/api/result}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_trace_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/result/result_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/apilogs → hackagent-0.4.3/hackagent/api/run}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_result_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_run_tests_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/run/run_update.py +0 -0
- {hackagent-0.4.1/hackagent/api/agent → hackagent-0.4.3/hackagent/api/user}/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_create.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_destroy.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_me_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_me_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_partial_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_retrieve.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/api/user/user_update.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/base.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/objectives/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/objectives/base.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/objectives/harmful_behavior.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/objectives/jailbreak.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/objectives/policy_violation.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/registry.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/evaluators.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/metrics.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/progress.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/templates.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/shared/utils.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/config.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/advprefix/utils.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/baseline/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/baseline/attack.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/baseline/config.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/pair/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/attacks/techniques/pair/config.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/commands/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/commands/config.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/commands/results.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/config.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/main.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/actions_logger.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/app.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/base.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/logger.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/agents.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/dashboard.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/views/results.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/widgets/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/cli/tui/widgets/actions.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/client.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/errors.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/logger.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/agent.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/agent_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/api_token_log.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/attack.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/attack_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/checkout_session_request_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/checkout_session_response.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/choice.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/choice_message.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/evaluation_status_enum.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/generate_error_response.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/generate_request_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/generate_success_response.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/generic_error_response.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/message_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/organization.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/organization_minimal.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/organization_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_agent_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_api_token_log_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_attack_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_organization_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_prompt_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_result_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_run_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_user_api_key_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/paginated_user_profile_list.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_agent_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_attack_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_organization_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_prompt_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_result_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_run_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/patched_user_profile_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/prompt.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/prompt_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/result.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/result_list_evaluation_status.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/result_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/run.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/run_list_status.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/run_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/status_enum.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/step_type_enum.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/trace.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/trace_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/usage.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/user_api_key.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/user_api_key_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/user_profile.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/user_profile_minimal.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/models/user_profile_request.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/router/tracking/context.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/types.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/utils.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/vulnerabilities/__init__.py +0 -0
- {hackagent-0.4.1 → hackagent-0.4.3}/hackagent/vulnerabilities/prompts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hackagent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: HackAgent is an open-source security toolkit to detect vulnerabilities of your AI Agents.
|
|
5
5
|
Author-email: AI Security Lab <ais@ai4i.it>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -13,15 +13,20 @@ Classifier: Programming Language :: Python :: 3
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
17
|
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: attrs>=21.0.0
|
|
17
19
|
Requires-Dist: click>=8.1.0
|
|
18
20
|
Requires-Dist: litellm>=1.69.2
|
|
19
21
|
Requires-Dist: openai>=1.0.0
|
|
20
22
|
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
21
24
|
Requires-Dist: pyyaml>=6.0.0
|
|
22
25
|
Requires-Dist: requests>=2.31.0
|
|
23
26
|
Requires-Dist: rich>=14.0.0
|
|
24
27
|
Requires-Dist: textual>=1.0.0
|
|
28
|
+
Provides-Extra: datasets
|
|
29
|
+
Requires-Dist: datasets>=2.14.0; extra == 'datasets'
|
|
25
30
|
Description-Content-Type: text/markdown
|
|
26
31
|
|
|
27
32
|
<div align="center">
|
|
@@ -204,22 +204,86 @@ class AttackOrchestrator:
|
|
|
204
204
|
Extract parameters for attack execution.
|
|
205
205
|
|
|
206
206
|
Override this method for custom parameter handling.
|
|
207
|
-
Default implementation extracts 'goals' from config
|
|
207
|
+
Default implementation extracts 'goals' from config, either directly
|
|
208
|
+
as a list or by loading them from a dataset source.
|
|
208
209
|
|
|
209
210
|
Args:
|
|
210
|
-
attack_config: Full attack configuration
|
|
211
|
+
attack_config: Full attack configuration. Can contain either:
|
|
212
|
+
- goals: Direct list of goal strings
|
|
213
|
+
- dataset: Configuration for loading goals from a dataset source
|
|
211
214
|
|
|
212
215
|
Returns:
|
|
213
216
|
Parameters to pass to technique's run() method
|
|
214
217
|
|
|
215
218
|
Raises:
|
|
216
|
-
ValueError: If
|
|
219
|
+
ValueError: If neither 'goals' nor 'dataset' is provided, or if format is invalid
|
|
217
220
|
"""
|
|
221
|
+
# Check for direct goals first
|
|
218
222
|
goals = attack_config.get("goals")
|
|
223
|
+
dataset_config = attack_config.get("dataset")
|
|
224
|
+
|
|
225
|
+
if goals is not None and dataset_config is not None:
|
|
226
|
+
logger.warning(
|
|
227
|
+
"Both 'goals' and 'dataset' provided. Using 'goals' directly."
|
|
228
|
+
)
|
|
229
|
+
dataset_config = None
|
|
230
|
+
|
|
231
|
+
if dataset_config is not None:
|
|
232
|
+
# Load goals from dataset source
|
|
233
|
+
goals = self._load_goals_from_dataset(dataset_config)
|
|
234
|
+
elif goals is None:
|
|
235
|
+
raise ValueError(
|
|
236
|
+
f"'{self.attack_type}' requires either 'goals' (list) or 'dataset' (config)"
|
|
237
|
+
)
|
|
238
|
+
|
|
219
239
|
if not isinstance(goals, list):
|
|
220
240
|
raise ValueError(f"'goals' must be a list for {self.attack_type}")
|
|
241
|
+
|
|
242
|
+
if len(goals) == 0:
|
|
243
|
+
raise ValueError(f"'goals' list is empty for {self.attack_type}")
|
|
244
|
+
|
|
245
|
+
logger.info(f"Prepared {len(goals)} goals for {self.attack_type} attack")
|
|
221
246
|
return {"goals": goals}
|
|
222
247
|
|
|
248
|
+
def _load_goals_from_dataset(self, dataset_config: Dict[str, Any]) -> list:
|
|
249
|
+
"""
|
|
250
|
+
Load goals from a dataset configuration.
|
|
251
|
+
|
|
252
|
+
Supports loading from:
|
|
253
|
+
- Pre-configured presets (e.g., "agentharm", "strongreject")
|
|
254
|
+
- HuggingFace datasets
|
|
255
|
+
- Local files (JSON, CSV, JSONL, TXT)
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
dataset_config: Dataset configuration dictionary with keys:
|
|
259
|
+
- preset (str, optional): Name of a pre-configured preset
|
|
260
|
+
- provider (str, optional): "huggingface" or "file"
|
|
261
|
+
- path (str, optional): Dataset path or file path
|
|
262
|
+
- goal_field (str, optional): Field containing goal text
|
|
263
|
+
- split (str, optional): Dataset split (for HuggingFace)
|
|
264
|
+
- limit (int, optional): Maximum goals to load
|
|
265
|
+
- shuffle (bool, optional): Shuffle before selecting
|
|
266
|
+
- seed (int, optional): Random seed for shuffling
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
List of goal strings
|
|
270
|
+
|
|
271
|
+
Raises:
|
|
272
|
+
ValueError: If dataset configuration is invalid
|
|
273
|
+
ImportError: If required dependencies are not available
|
|
274
|
+
"""
|
|
275
|
+
from hackagent.datasets import load_goals_from_config
|
|
276
|
+
|
|
277
|
+
logger.info(f"Loading goals from dataset: {dataset_config}")
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
goals = load_goals_from_config(dataset_config)
|
|
281
|
+
logger.info(f"Loaded {len(goals)} goals from dataset")
|
|
282
|
+
return goals
|
|
283
|
+
except Exception as e:
|
|
284
|
+
logger.error(f"Failed to load goals from dataset: {e}", exc_info=True)
|
|
285
|
+
raise ValueError(f"Failed to load goals from dataset: {e}") from e
|
|
286
|
+
|
|
223
287
|
def _get_attack_impl_kwargs(
|
|
224
288
|
self,
|
|
225
289
|
attack_config: Dict[str, Any],
|
|
@@ -17,6 +17,12 @@ Prefix generation pipeline attack based on the BaseAttack class.
|
|
|
17
17
|
|
|
18
18
|
This module implements a complete pipeline for generating, filtering, and selecting prefixes
|
|
19
19
|
using uncensored and target language models, adapted as an attack module.
|
|
20
|
+
|
|
21
|
+
Result Tracking:
|
|
22
|
+
Uses Tracker to create one Result per goal, with traces for each
|
|
23
|
+
prefix generation, completion, and evaluation step. This provides better
|
|
24
|
+
organization where each Result represents a complete attack attempt on
|
|
25
|
+
a single goal.
|
|
20
26
|
"""
|
|
21
27
|
|
|
22
28
|
import copy
|
|
@@ -26,6 +32,7 @@ from typing import Any, Dict, List, Optional
|
|
|
26
32
|
from hackagent.client import AuthenticatedClient
|
|
27
33
|
from hackagent.models import StatusEnum
|
|
28
34
|
from hackagent.router.router import AgentRouter
|
|
35
|
+
from hackagent.router.tracking import Tracker
|
|
29
36
|
from hackagent.attacks.techniques.base import BaseAttack
|
|
30
37
|
|
|
31
38
|
# Import step execution functions from same package
|
|
@@ -210,6 +217,7 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
210
217
|
"surrogate_attack_prompt",
|
|
211
218
|
"_run_id", # For real-time result tracking
|
|
212
219
|
"_client", # For real-time result tracking
|
|
220
|
+
"_tracker", # For per-goal result tracking via Tracker
|
|
213
221
|
],
|
|
214
222
|
"input_data_arg_name": "goals",
|
|
215
223
|
"required_args": ["logger", "client", "config", "agent_router"],
|
|
@@ -224,6 +232,7 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
224
232
|
"n_samples",
|
|
225
233
|
"_run_id",
|
|
226
234
|
"_client",
|
|
235
|
+
"_tracker", # For per-goal result tracking via Tracker
|
|
227
236
|
],
|
|
228
237
|
"input_data_arg_name": "input_data",
|
|
229
238
|
"required_args": ["logger", "config", "agent_router"],
|
|
@@ -248,6 +257,7 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
248
257
|
"max_ce",
|
|
249
258
|
"_run_id", # For real-time result tracking
|
|
250
259
|
"_client", # For real-time result tracking
|
|
260
|
+
"_tracker", # For per-goal result tracking via Tracker
|
|
251
261
|
],
|
|
252
262
|
"input_data_arg_name": "input_data",
|
|
253
263
|
"required_args": ["logger", "client", "config"],
|
|
@@ -259,6 +269,9 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
259
269
|
"""
|
|
260
270
|
Executes the full prefix generation pipeline.
|
|
261
271
|
|
|
272
|
+
Uses Tracker to create one Result per goal, with traces for each
|
|
273
|
+
step of prefix generation, completion, and evaluation.
|
|
274
|
+
|
|
262
275
|
Args:
|
|
263
276
|
goals: A list of goal strings to generate prefixes for.
|
|
264
277
|
|
|
@@ -272,6 +285,38 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
272
285
|
# Initialize tracking using base class method
|
|
273
286
|
self.tracker = self._initialize_tracking("advprefix", goals)
|
|
274
287
|
|
|
288
|
+
# Initialize Tracker for per-goal result tracking
|
|
289
|
+
run_id = self.config.get("_run_id")
|
|
290
|
+
client = self.config.get("_client")
|
|
291
|
+
|
|
292
|
+
goal_tracker = None
|
|
293
|
+
if run_id and client:
|
|
294
|
+
goal_tracker = Tracker(
|
|
295
|
+
client=client,
|
|
296
|
+
run_id=run_id,
|
|
297
|
+
logger=self.logger,
|
|
298
|
+
attack_type="advprefix",
|
|
299
|
+
)
|
|
300
|
+
self.logger.info("📊 Using Tracker for per-goal result tracking")
|
|
301
|
+
|
|
302
|
+
# Create goal results upfront
|
|
303
|
+
for i, goal in enumerate(goals):
|
|
304
|
+
goal_tracker.create_goal_result(
|
|
305
|
+
goal=goal,
|
|
306
|
+
goal_index=i,
|
|
307
|
+
initial_metadata={
|
|
308
|
+
"n_candidates_per_goal": self.config.get(
|
|
309
|
+
"n_candidates_per_goal", 5
|
|
310
|
+
),
|
|
311
|
+
"n_prefixes_per_goal": self.config.get(
|
|
312
|
+
"n_prefixes_per_goal", 2
|
|
313
|
+
),
|
|
314
|
+
},
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Pass tracker through config for sub-modules
|
|
318
|
+
self.config["_tracker"] = goal_tracker
|
|
319
|
+
|
|
275
320
|
# Execute pipeline using base class method
|
|
276
321
|
start_step = self.config.get("start_step", 1) - 1
|
|
277
322
|
|
|
@@ -280,6 +325,18 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
280
325
|
self._get_pipeline_steps(), goals, start_step
|
|
281
326
|
)
|
|
282
327
|
|
|
328
|
+
# Finalize goal results based on evaluation
|
|
329
|
+
if goal_tracker:
|
|
330
|
+
self._finalize_goal_results(goal_tracker, goals, results)
|
|
331
|
+
|
|
332
|
+
# Log summary
|
|
333
|
+
summary = goal_tracker.get_summary()
|
|
334
|
+
self.logger.info(
|
|
335
|
+
f"Tracker summary: {summary['successful_attacks']}/{summary['total_goals']} "
|
|
336
|
+
f"successful ({summary['success_rate']:.1f}%), "
|
|
337
|
+
f"{summary['total_traces']} total traces"
|
|
338
|
+
)
|
|
339
|
+
|
|
283
340
|
# Finalize using base class method
|
|
284
341
|
self._finalize_pipeline(results)
|
|
285
342
|
|
|
@@ -289,3 +346,95 @@ class AdvPrefixAttack(BaseAttack):
|
|
|
289
346
|
if self.tracker:
|
|
290
347
|
self.tracker.update_run_status(StatusEnum.FAILED)
|
|
291
348
|
raise
|
|
349
|
+
|
|
350
|
+
def _finalize_goal_results(
|
|
351
|
+
self,
|
|
352
|
+
goal_tracker: Tracker,
|
|
353
|
+
goals: List[str],
|
|
354
|
+
results: Optional[List[Dict]],
|
|
355
|
+
) -> None:
|
|
356
|
+
"""
|
|
357
|
+
Finalize goal results based on evaluation data.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
goal_tracker: Tracker instance
|
|
361
|
+
goals: Original list of goals
|
|
362
|
+
results: Pipeline results (list of prefix dicts)
|
|
363
|
+
"""
|
|
364
|
+
if not results:
|
|
365
|
+
# Mark all goals as failed if no results
|
|
366
|
+
for i, goal in enumerate(goals):
|
|
367
|
+
ctx = goal_tracker.get_goal_context(i)
|
|
368
|
+
if ctx and not ctx.is_finalized:
|
|
369
|
+
goal_tracker.finalize_goal(
|
|
370
|
+
ctx=ctx,
|
|
371
|
+
success=False,
|
|
372
|
+
evaluation_notes="AdvPrefix attack: No prefixes generated",
|
|
373
|
+
)
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
# Group results by goal
|
|
377
|
+
goal_results: Dict[str, List[Dict]] = {}
|
|
378
|
+
for r in results:
|
|
379
|
+
goal = r.get("goal", "unknown")
|
|
380
|
+
if goal not in goal_results:
|
|
381
|
+
goal_results[goal] = []
|
|
382
|
+
goal_results[goal].append(r)
|
|
383
|
+
|
|
384
|
+
# Finalize each goal
|
|
385
|
+
for i, goal in enumerate(goals):
|
|
386
|
+
ctx = goal_tracker.get_goal_context(i)
|
|
387
|
+
if not ctx or ctx.is_finalized:
|
|
388
|
+
continue
|
|
389
|
+
|
|
390
|
+
prefixes = goal_results.get(goal, [])
|
|
391
|
+
|
|
392
|
+
if not prefixes:
|
|
393
|
+
goal_tracker.finalize_goal(
|
|
394
|
+
ctx=ctx,
|
|
395
|
+
success=False,
|
|
396
|
+
evaluation_notes="AdvPrefix attack: No prefixes selected for goal",
|
|
397
|
+
)
|
|
398
|
+
continue
|
|
399
|
+
|
|
400
|
+
# Check if any prefix was successful (based on evaluation scores)
|
|
401
|
+
# A prefix is considered successful if it has high eval scores
|
|
402
|
+
success_threshold = 0.5
|
|
403
|
+
best_score = 0
|
|
404
|
+
for prefix_data in prefixes:
|
|
405
|
+
# Check various evaluation columns
|
|
406
|
+
for eval_col in [
|
|
407
|
+
"eval_nj",
|
|
408
|
+
"eval_jb",
|
|
409
|
+
"eval_hb",
|
|
410
|
+
"eval_nj_mean",
|
|
411
|
+
"eval_jb_mean",
|
|
412
|
+
]:
|
|
413
|
+
score = prefix_data.get(eval_col, 0)
|
|
414
|
+
if isinstance(score, (int, float)) and score > best_score:
|
|
415
|
+
best_score = score
|
|
416
|
+
|
|
417
|
+
is_success = best_score >= success_threshold
|
|
418
|
+
|
|
419
|
+
# Add evaluation trace
|
|
420
|
+
goal_tracker.add_evaluation_trace(
|
|
421
|
+
ctx=ctx,
|
|
422
|
+
evaluation_result={
|
|
423
|
+
"num_prefixes_selected": len(prefixes),
|
|
424
|
+
"best_score": best_score,
|
|
425
|
+
"is_success": is_success,
|
|
426
|
+
},
|
|
427
|
+
score=best_score,
|
|
428
|
+
explanation=f"Selected {len(prefixes)} prefixes, best score: {best_score:.2f}",
|
|
429
|
+
evaluator_name="advprefix_aggregation",
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
goal_tracker.finalize_goal(
|
|
433
|
+
ctx=ctx,
|
|
434
|
+
success=is_success,
|
|
435
|
+
evaluation_notes=f"AdvPrefix attack: {len(prefixes)} prefixes selected, best score {best_score:.2f}",
|
|
436
|
+
final_metadata={
|
|
437
|
+
"num_prefixes_selected": len(prefixes),
|
|
438
|
+
"best_score": best_score,
|
|
439
|
+
},
|
|
440
|
+
)
|
|
@@ -143,7 +143,7 @@ def _get_completion_via_router(
|
|
|
143
143
|
This helper function sends a single adversarial prefix (optionally combined
|
|
144
144
|
with a surrogate attack prompt) to the target agent and collects the generated
|
|
145
145
|
completion. Session management for ADK agents is handled automatically by the
|
|
146
|
-
|
|
146
|
+
ADKAgent.
|
|
147
147
|
|
|
148
148
|
Args:
|
|
149
149
|
agent_router: AgentRouter instance configured for the target agent.
|
|
@@ -171,7 +171,7 @@ def _get_completion_via_router(
|
|
|
171
171
|
|
|
172
172
|
Note:
|
|
173
173
|
For ADK agents, session management is handled automatically by the
|
|
174
|
-
|
|
174
|
+
ADKAgent. The function handles surrogate prompt formatting with
|
|
175
175
|
placeholder replacement or simple concatenation based on template format.
|
|
176
176
|
|
|
177
177
|
Errors are captured in the error_message field rather than raising
|
|
@@ -209,7 +209,7 @@ def _get_completion_via_router(
|
|
|
209
209
|
if n_samples is not None and n_samples > 0:
|
|
210
210
|
request_data["n"] = n_samples # Common key for number of completions
|
|
211
211
|
|
|
212
|
-
# Session management is now handled by the
|
|
212
|
+
# Session management is now handled by the ADKAgent (no need to pass session_id/user_id)
|
|
213
213
|
|
|
214
214
|
# Prepare result structure
|
|
215
215
|
result_dict = {
|
|
@@ -219,37 +219,17 @@ def _get_completion_via_router(
|
|
|
219
219
|
"raw_response_headers": None,
|
|
220
220
|
"raw_response_body": None,
|
|
221
221
|
"adapter_specific_events": None,
|
|
222
|
+
"agent_specific_data": None,
|
|
222
223
|
"error_message": None,
|
|
223
224
|
"log_message": None, # For per-prefix logging by the main loop
|
|
224
|
-
"result_id": None, # ID for updating evaluation status later
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
# Use
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
run_id=run_id,
|
|
234
|
-
client=client,
|
|
235
|
-
)
|
|
236
|
-
# route_with_tracking returns {"response": ..., "result_id": ...}
|
|
237
|
-
response = tracking_result.get("response", tracking_result)
|
|
238
|
-
# Capture result_id for later evaluation updates
|
|
239
|
-
result_dict["result_id"] = tracking_result.get("result_id")
|
|
240
|
-
if result_dict["result_id"]:
|
|
241
|
-
logger_instance.debug(
|
|
242
|
-
f"Captured result_id={result_dict['result_id']} for evaluation tracking"
|
|
243
|
-
)
|
|
244
|
-
else:
|
|
245
|
-
logger_instance.warning(
|
|
246
|
-
f"⚠️ Using fallback route_request (run_id={run_id}, client={client is not None})"
|
|
247
|
-
)
|
|
248
|
-
# Fallback to standard routing without tracking
|
|
249
|
-
response = agent_router.route_request(
|
|
250
|
-
registration_key=agent_reg_key,
|
|
251
|
-
request_data=request_data,
|
|
252
|
-
)
|
|
227
|
+
# Use simple route_request (no automatic result creation)
|
|
228
|
+
# Tracker handles per-goal result tracking instead of scattered per-call results
|
|
229
|
+
response = agent_router.route_request(
|
|
230
|
+
registration_key=agent_reg_key,
|
|
231
|
+
request_data=request_data,
|
|
232
|
+
)
|
|
253
233
|
|
|
254
234
|
# Update result_dict with response data
|
|
255
235
|
result_dict["raw_request_payload"] = (
|
|
@@ -263,6 +243,7 @@ def _get_completion_via_router(
|
|
|
263
243
|
agent_specific = response.get("agent_specific_data", {})
|
|
264
244
|
if agent_specific:
|
|
265
245
|
result_dict["adapter_specific_events"] = agent_specific.get("adk_events_list")
|
|
246
|
+
result_dict["agent_specific_data"] = agent_specific
|
|
266
247
|
|
|
267
248
|
# Log agent actions for visibility
|
|
268
249
|
_log_agent_actions(logger, agent_specific, original_index)
|
|
@@ -373,6 +354,7 @@ def execute(
|
|
|
373
354
|
# Extract tracking information from config
|
|
374
355
|
run_id = config.get("_run_id")
|
|
375
356
|
client = config.get("_client")
|
|
357
|
+
tracker = config.get("_tracker")
|
|
376
358
|
|
|
377
359
|
logger.info(
|
|
378
360
|
f"📊 Tracking context: run_id={run_id}, client={'Present' if client else 'Missing'}"
|
|
@@ -380,6 +362,9 @@ def execute(
|
|
|
380
362
|
if not run_id or not client:
|
|
381
363
|
logger.warning("⚠️ Missing tracking context - results will NOT be created!")
|
|
382
364
|
|
|
365
|
+
if tracker:
|
|
366
|
+
logger.info("📊 Using Tracker for per-goal result tracking")
|
|
367
|
+
|
|
383
368
|
# --- Completion Parameters from config ---
|
|
384
369
|
request_timeout = 120
|
|
385
370
|
max_new_tokens = config.get("max_new_tokens_completion", 256)
|
|
@@ -412,6 +397,38 @@ def execute(
|
|
|
412
397
|
client=client, # Pass for real-time tracking
|
|
413
398
|
)
|
|
414
399
|
completion_results_list.append(result)
|
|
400
|
+
|
|
401
|
+
# Add trace to the correct goal's Result via Tracker
|
|
402
|
+
goal = record.get("goal", "")
|
|
403
|
+
if tracker and goal:
|
|
404
|
+
goal_ctx = tracker.get_goal_context_by_goal(goal)
|
|
405
|
+
if goal_ctx:
|
|
406
|
+
completion_text = result.get("completion")
|
|
407
|
+
response_payload = {
|
|
408
|
+
"generated_text": completion_text,
|
|
409
|
+
"raw_response_body": result.get("raw_response_body"),
|
|
410
|
+
"raw_response_status": result.get("raw_response_status"),
|
|
411
|
+
}
|
|
412
|
+
tracker.add_interaction_trace(
|
|
413
|
+
ctx=goal_ctx,
|
|
414
|
+
request=result.get("raw_request_payload") or {},
|
|
415
|
+
response=response_payload,
|
|
416
|
+
step_name="Target Completion",
|
|
417
|
+
metadata={
|
|
418
|
+
"prefix": prefix_text,
|
|
419
|
+
"surrogate_attack_prompt": actual_surrogate_prompt_str,
|
|
420
|
+
"error_message": result.get("error_message"),
|
|
421
|
+
"adapter_specific_events": result.get(
|
|
422
|
+
"adapter_specific_events"
|
|
423
|
+
),
|
|
424
|
+
"agent_specific_data": result.get(
|
|
425
|
+
"agent_specific_data"
|
|
426
|
+
),
|
|
427
|
+
"raw_response_status": result.get(
|
|
428
|
+
"raw_response_status"
|
|
429
|
+
),
|
|
430
|
+
},
|
|
431
|
+
)
|
|
415
432
|
except Exception as e:
|
|
416
433
|
logger.error(
|
|
417
434
|
f"Exception during synchronous completion for original index {index}: {e}",
|
|
@@ -449,14 +466,8 @@ def execute(
|
|
|
449
466
|
"adapter_specific_events"
|
|
450
467
|
)
|
|
451
468
|
result["error_message"] = completion_result.get("error_message")
|
|
452
|
-
# Pass through result_id for evaluation status updates
|
|
453
|
-
result["result_id"] = completion_result.get("result_id")
|
|
454
469
|
results.append(result)
|
|
455
470
|
|
|
456
|
-
|
|
457
|
-
result_ids_in_output = [r.get("result_id") for r in results if r.get("result_id")]
|
|
458
|
-
logger.info(
|
|
459
|
-
f"📊 Completions execute returning {len(results)} results with {len(result_ids_in_output)} result_ids"
|
|
460
|
-
)
|
|
471
|
+
logger.info(f"📊 Completions execute returning {len(results)} results")
|
|
461
472
|
|
|
462
473
|
return results
|
|
@@ -36,7 +36,7 @@ import logging
|
|
|
36
36
|
import math
|
|
37
37
|
from collections import defaultdict
|
|
38
38
|
from dataclasses import fields
|
|
39
|
-
from typing import Any, Dict, List, Optional
|
|
39
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
40
40
|
from uuid import UUID
|
|
41
41
|
|
|
42
42
|
from hackagent.api.result import result_partial_update
|
|
@@ -49,6 +49,9 @@ from hackagent.client import AuthenticatedClient
|
|
|
49
49
|
from hackagent.models import EvaluationStatusEnum, PatchedResultRequest
|
|
50
50
|
from hackagent.router.types import AgentTypeEnum
|
|
51
51
|
|
|
52
|
+
if TYPE_CHECKING:
|
|
53
|
+
from hackagent.router.tracking import Tracker
|
|
54
|
+
|
|
52
55
|
from .config import EvaluationPipelineConfig, EvaluatorConfig
|
|
53
56
|
from .utils import handle_empty_input, log_errors
|
|
54
57
|
|
|
@@ -143,6 +146,10 @@ class EvaluationPipeline:
|
|
|
143
146
|
self._tracking_client = (
|
|
144
147
|
config.get("_client") if isinstance(config, dict) else None
|
|
145
148
|
)
|
|
149
|
+
# Extract tracker for per-goal result tracking
|
|
150
|
+
self._tracker: Optional["Tracker"] = (
|
|
151
|
+
config.get("_tracker") if isinstance(config, dict) else None
|
|
152
|
+
)
|
|
146
153
|
|
|
147
154
|
self.config = (
|
|
148
155
|
EvaluationPipelineConfig.from_dict(config)
|
|
@@ -516,12 +523,13 @@ class EvaluationPipeline:
|
|
|
516
523
|
return None
|
|
517
524
|
|
|
518
525
|
evaluator_config = EvaluatorConfig(**filtered_config)
|
|
519
|
-
# Pass tracking context to the evaluator
|
|
526
|
+
# Pass tracking context and tracker to the evaluator
|
|
520
527
|
evaluator = evaluator_class(
|
|
521
528
|
client=self.client,
|
|
522
529
|
config=evaluator_config,
|
|
523
530
|
run_id=self._run_id,
|
|
524
531
|
tracking_client=self._tracking_client,
|
|
532
|
+
tracker=self._tracker,
|
|
525
533
|
)
|
|
526
534
|
evaluated_data = evaluator.evaluate(data)
|
|
527
535
|
|