agentprobe-testing 1.2.0__tar.gz → 1.3.0__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.
Files changed (109) hide show
  1. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/PKG-INFO +1 -1
  2. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/__init__.py +1 -1
  3. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/priority.py +14 -0
  4. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/quickstart.py +5 -0
  5. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/PKG-INFO +1 -1
  6. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/pyproject.toml +1 -1
  7. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_priority.py +49 -0
  8. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/LICENSE +0 -0
  9. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/README.md +0 -0
  10. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/__init__.py +0 -0
  11. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/base.py +0 -0
  12. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/browser_agent.py +0 -0
  13. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/rule_based.py +0 -0
  14. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/scripted.py +0 -0
  15. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agents/target_agent.py +0 -0
  16. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/agreement.py +0 -0
  17. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/classifier.py +0 -0
  18. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/cli.py +0 -0
  19. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/diff.py +0 -0
  20. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domain.py +0 -0
  21. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/__init__.py +0 -0
  22. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/__init__.py +0 -0
  23. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/agent.py +0 -0
  24. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/clean.py +0 -0
  25. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/complex_agent.py +0 -0
  26. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/decoy.py +0 -0
  27. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/domain.py +0 -0
  28. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/entities.py +0 -0
  29. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/injector_prompt.py +0 -0
  30. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/rule_based_agent.py +0 -0
  31. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/scenarios.py +0 -0
  32. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/split.py +0 -0
  33. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/tools.py +0 -0
  34. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/access_control/trap.py +0 -0
  35. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/__init__.py +0 -0
  36. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/agent.py +0 -0
  37. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/clean.py +0 -0
  38. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/domain.py +0 -0
  39. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/entities.py +0 -0
  40. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/injector_prompt.py +0 -0
  41. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/rule_based_agent.py +0 -0
  42. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/scenarios.py +0 -0
  43. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/tools.py +0 -0
  44. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/domains/web_browsing/trap.py +0 -0
  45. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/feedback.py +0 -0
  46. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/generic_world.py +0 -0
  47. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/injection.py +0 -0
  48. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/injector.py +0 -0
  49. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/llm.py +0 -0
  50. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/playbook.py +0 -0
  51. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/reachability.py +0 -0
  52. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/registry.py +0 -0
  53. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/report.py +0 -0
  54. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/runner.py +0 -0
  55. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenario.py +0 -0
  56. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/__init__.py +0 -0
  57. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/clean.py +0 -0
  58. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/decoy.py +0 -0
  59. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/registry.py +0 -0
  60. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/split.py +0 -0
  61. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/scenarios/trap.py +0 -0
  62. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/summarize.py +0 -0
  63. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/termui.py +0 -0
  64. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/tools.py +0 -0
  65. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/trajectory.py +0 -0
  66. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/triage.py +0 -0
  67. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/validate_scenarios.py +0 -0
  68. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe/world.py +0 -0
  69. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/SOURCES.txt +0 -0
  70. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/dependency_links.txt +0 -0
  71. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/entry_points.txt +0 -0
  72. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/requires.txt +0 -0
  73. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/agentprobe_testing.egg-info/top_level.txt +0 -0
  74. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/setup.cfg +0 -0
  75. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_access_control_agent.py +0 -0
  76. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_access_control_domain.py +0 -0
  77. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_access_control_rule_based_agent.py +0 -0
  78. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_access_control_scenarios.py +0 -0
  79. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_access_control_tools.py +0 -0
  80. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_agreement.py +0 -0
  81. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_browser_agent.py +0 -0
  82. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_classifier.py +0 -0
  83. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_cli.py +0 -0
  84. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_complex_access_control_agent.py +0 -0
  85. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_diff.py +0 -0
  86. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_domain.py +0 -0
  87. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_failures.py +0 -0
  88. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_feedback.py +0 -0
  89. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_generic_world.py +0 -0
  90. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_injection.py +0 -0
  91. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_injector.py +0 -0
  92. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_llm.py +0 -0
  93. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_package_api.py +0 -0
  94. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_playbook.py +0 -0
  95. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_quickstart.py +0 -0
  96. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_reachability.py +0 -0
  97. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_registry.py +0 -0
  98. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_report.py +0 -0
  99. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_rule_based_agent.py +0 -0
  100. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_runner.py +0 -0
  101. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_scenarios.py +0 -0
  102. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_target_agent.py +0 -0
  103. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_termui.py +0 -0
  104. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_tools.py +0 -0
  105. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_trajectory.py +0 -0
  106. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_triage.py +0 -0
  107. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_validate_scenarios.py +0 -0
  108. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_web_browsing_domain.py +0 -0
  109. {agentprobe_testing-1.2.0 → agentprobe_testing-1.3.0}/tests/test_world.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentprobe-testing
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Adaptive chaos-testing for LLM agents: a live model-driven Injector that reads an agent's real trajectory and decides where to break something, instead of scripting perturbations in advance.
5
5
  License: Business Source License 1.1
6
6
 
@@ -60,7 +60,7 @@ from agentprobe.scenario import CommitPattern, FactPattern, GoalSpec, Scenario
60
60
  from agentprobe.scenarios.registry import ALL_SCENARIOS as TICKET_SCENARIOS
61
61
  from agentprobe.scenarios.registry import BY_ID as TICKET_SCENARIOS_BY_ID
62
62
 
63
- __version__ = "1.2.0"
63
+ __version__ = "1.3.0"
64
64
 
65
65
  __all__ = [
66
66
  "Agent",
@@ -118,6 +118,20 @@ def rank(issues: list[dict], overrides: Optional[dict[str, str]] = None) -> list
118
118
  return ranked
119
119
 
120
120
 
121
+ def clean_overrides(raw: object) -> dict[str, str]:
122
+ """Keep only well-formed {FAILURE_KIND: "High"|"Medium"|"Low"} entries from
123
+ whatever a caller hands in (the hosted runner gets this from the website's
124
+ saved edits, over the wire), so a malformed or hostile value can never
125
+ reach a report."""
126
+ if not isinstance(raw, dict):
127
+ return {}
128
+ return {
129
+ k: v
130
+ for k, v in raw.items()
131
+ if isinstance(k, str) and isinstance(v, str) and v in TIERS and 1 <= len(k) <= 40 and k.replace("_", "").isalnum() and k.upper() == k
132
+ }
133
+
134
+
121
135
  def encode(issues: list[dict]) -> str:
122
136
  """ASCII-only JSON, base64'd, so it can sit inside an HTML comment with no
123
137
  escaping concerns. The website reads it back to re-rank a stored report
@@ -18,6 +18,7 @@ from agentprobe.agents.base import Agent, AgentAction
18
18
  from agentprobe.domain import Domain, TICKET_DOMAIN
19
19
  from agentprobe.injection import injection_was_triggered
20
20
  from agentprobe.injector import Injector, NullInjector, RecordingInjector, serialize_armed_injection
21
+ from agentprobe.priority import clean_overrides
21
22
  from agentprobe.report import InjectionRecord, Report
22
23
  from agentprobe.runner import run_recovery, run_robustness_pair
23
24
  from agentprobe.scenario import Scenario
@@ -162,6 +163,7 @@ def quick_test(
162
163
  domain_key: Optional[str] = None,
163
164
  record_injections: bool = False,
164
165
  summarize_failures: bool = False,
166
+ priority_overrides: Optional[dict] = None,
165
167
  ) -> Report:
166
168
  """Run one scenario and get back a ready Report -- the one-call version
167
169
  of run_robustness_pair()/run_recovery() + Report(). `agent` can be a
@@ -214,6 +216,7 @@ def quick_test(
214
216
  chaos_trajectories=[chaos],
215
217
  injection_records=injection_records,
216
218
  injector_cost_usd=_injector_cost_usd(injector),
219
+ priority_overrides=clean_overrides(priority_overrides),
217
220
  )
218
221
  if recording is not None:
219
222
  # Stashed here (not a Report field -- Report is a general-purpose
@@ -249,6 +252,7 @@ def quick_test_all(
249
252
  record_injections: bool = False,
250
253
  max_duration_seconds: Optional[float] = None,
251
254
  summarize_failures: bool = False,
255
+ priority_overrides: Optional[dict] = None,
252
256
  ) -> Report:
253
257
  """Run every scenario in `scenarios` (a dict[str, Scenario] -- e.g.
254
258
  TICKET_SCENARIOS or a FetchedDomain's .scenarios -- or a plain list of
@@ -352,6 +356,7 @@ def quick_test_all(
352
356
  chaos_trajectories=all_chaos,
353
357
  injection_records=all_records,
354
358
  injector_cost_usd=total_injector_cost,
359
+ priority_overrides=clean_overrides(priority_overrides),
355
360
  )
356
361
  report._scenarios_run = len(all_chaos)
357
362
  if summarize_failures:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentprobe-testing
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Adaptive chaos-testing for LLM agents: a live model-driven Injector that reads an agent's real trajectory and decides where to break something, instead of scripting perturbations in advance.
5
5
  License: Business Source License 1.1
6
6
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentprobe-testing"
3
- version = "1.2.0"
3
+ version = "1.3.0"
4
4
  description = "Adaptive chaos-testing for LLM agents: a live model-driven Injector that reads an agent's real trajectory and decides where to break something, instead of scripting perturbations in advance."
5
5
  requires-python = ">=3.11"
6
6
  dependencies = ["anthropic>=1.0.0", "python-dotenv>=1.0.0"]
@@ -139,3 +139,52 @@ def test_html_stays_script_free_and_the_text_report_lists_priorities():
139
139
  out = r.render()
140
140
  assert "priorities (automated estimate -- review before acting):" in out
141
141
  assert "1. [High] Trusts a tool that did nothing -- 1 scenario(s)" in out
142
+
143
+
144
+ # --- overrides flowing in from outside (the hosted runner / Temporal worker) ---
145
+
146
+ def test_clean_overrides_keeps_only_well_formed_entries():
147
+ from agentprobe.priority import clean_overrides
148
+
149
+ assert clean_overrides({"FALSE_SUCCESS": "High", "STALE_READ": "Low"}) == {"FALSE_SUCCESS": "High", "STALE_READ": "Low"}
150
+ dirty = {"false_success": "High", "STALE READ": "Low", "TOOL_ERROR": "Urgent", "DISTRACTOR": 3, 5: "High", "X" * 41: "High", "": "High", "OK_KIND": "Medium"}
151
+ assert clean_overrides(dirty) == {"OK_KIND": "Medium"}
152
+ for junk in (None, "High", ["High"], 7):
153
+ assert clean_overrides(junk) == {}
154
+
155
+
156
+ def test_quick_test_ranks_with_the_overrides_it_is_given():
157
+ from agentprobe.agents.scripted import ScriptedAgent
158
+ from agentprobe.injector import NullInjector
159
+ from agentprobe.quickstart import quick_test
160
+ from agentprobe.scenarios.registry import BY_ID
161
+
162
+ agent = lambda: ScriptedAgent(script=[("get_ticket", {"id": "T-1001"})]) # never finishes -> the chaos run fails
163
+ report = quick_test(BY_ID["clean-1"], agent, injector=NullInjector(), mode="recovery", priority_overrides={"UNATTRIBUTED": "High", "BAD": "nope", "x": "Low"})
164
+ assert report.priority_overrides == {"UNATTRIBUTED": "High"} # junk dropped
165
+ ranked = report.priorities()
166
+ assert [(r["kind"], r["tier"], r["edited"]) for r in ranked] == [("UNATTRIBUTED", "High", True)]
167
+ assert "priority--high'>High</span> <span class='muted'>(edited)" in report.render_html()
168
+
169
+
170
+ def test_quick_test_without_overrides_ranks_automatically():
171
+ from agentprobe.agents.scripted import ScriptedAgent
172
+ from agentprobe.injector import NullInjector
173
+ from agentprobe.quickstart import quick_test
174
+ from agentprobe.scenarios.registry import BY_ID
175
+
176
+ report = quick_test(BY_ID["clean-1"], lambda: ScriptedAgent(script=[("get_ticket", {"id": "T-1001"})]), injector=NullInjector(), mode="recovery")
177
+ assert report.priority_overrides == {}
178
+ assert [(r["tier"], r["edited"]) for r in report.priorities()] == [("Medium", False)]
179
+
180
+
181
+ def test_quick_test_all_carries_the_overrides_onto_the_combined_report():
182
+ from agentprobe.agents.scripted import ScriptedAgent
183
+ from agentprobe.injector import NullInjector
184
+ from agentprobe.quickstart import quick_test_all
185
+ from agentprobe.scenarios.registry import BY_ID
186
+
187
+ scenarios = {k: BY_ID[k] for k in ("clean-1", "clean-2")}
188
+ report = quick_test_all(scenarios, lambda: ScriptedAgent(script=[("get_ticket", {"id": "T-1001"})]), injector_factory=NullInjector, mode="recovery", priority_overrides={"UNATTRIBUTED": "Low"})
189
+ assert report.priority_overrides == {"UNATTRIBUTED": "Low"}
190
+ assert all(r["tier"] == "Low" and r["edited"] for r in report.priorities())