agentprobe-testing 0.5.0__tar.gz → 0.5.1__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.
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/PKG-INFO +1 -1
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/README.md +19 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/__init__.py +3 -2
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/quickstart.py +60 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/PKG-INFO +1 -1
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/pyproject.toml +1 -1
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_quickstart.py +76 -1
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/LICENSE +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agents/__init__.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agents/base.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agents/rule_based.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agents/scripted.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agents/target_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/agreement.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/classifier.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/cli.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/diff.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domain.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/__init__.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/__init__.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/clean.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/complex_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/decoy.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/domain.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/entities.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/injector_prompt.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/rule_based_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/scenarios.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/split.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/tools.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/trap.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/feedback.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/generic_world.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/injection.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/injector.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/llm.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/playbook.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/reachability.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/registry.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/report.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/runner.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenario.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/__init__.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/clean.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/decoy.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/registry.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/split.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/scenarios/trap.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/termui.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/tools.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/trajectory.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/triage.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/validate_scenarios.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/world.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/SOURCES.txt +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/dependency_links.txt +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/entry_points.txt +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/requires.txt +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/top_level.txt +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/setup.cfg +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_domain.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_rule_based_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_scenarios.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_tools.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_agreement.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_classifier.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_cli.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_complex_access_control_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_diff.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_domain.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_feedback.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_generic_world.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_injection.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_injector.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_llm.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_package_api.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_playbook.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_reachability.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_registry.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_report.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_rule_based_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_runner.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_scenarios.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_target_agent.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_termui.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_tools.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_trajectory.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_triage.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_validate_scenarios.py +0 -0
- {agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_world.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentprobe-testing
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
|
@@ -18,6 +18,19 @@ adversarial content disguised as ordinary data (`PROMPT_INJECTION`).
|
|
|
18
18
|
|
|
19
19
|
## Quickstart
|
|
20
20
|
|
|
21
|
+
Using this in your own project (no need to clone this repo):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install agentprobe-testing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`import agentprobe as ap` afterward, same as everywhere else in this
|
|
28
|
+
README — the PyPI *distribution* name is `agentprobe-testing`, but the
|
|
29
|
+
Python package you import is still plain `agentprobe`.
|
|
30
|
+
|
|
31
|
+
To run the examples in this repo (or work on the library itself), clone
|
|
32
|
+
it and install from source instead:
|
|
33
|
+
|
|
21
34
|
```bash
|
|
22
35
|
pip install -e .
|
|
23
36
|
python examples/free_zero_cost_demo.py # no API key needed, no network calls at all
|
|
@@ -105,6 +118,12 @@ surface. The `access_control` domain lives at
|
|
|
105
118
|
top level, to keep this surface to the one domain most people reach for
|
|
106
119
|
first.
|
|
107
120
|
|
|
121
|
+
Testing your own agent instead of the built-in `TargetAgent`? Pass any
|
|
122
|
+
plain `(task, history) -> AgentAction` function as `agent` — no subclass
|
|
123
|
+
needed, `quick_test`/`wrap_agent` handle the wiring, and if your agent
|
|
124
|
+
already runs as a service you can POST to, `ap.http_agent(url)` builds
|
|
125
|
+
that function for you (see [USAGE.md](USAGE.md)).
|
|
126
|
+
|
|
108
127
|
Beyond one-scenario `quick_test()`, see [USAGE.md](USAGE.md) for: running
|
|
109
128
|
a whole domain at once (`quick_test_all`), a one-line pytest integration
|
|
110
129
|
(`assert_passes`), catching regressions between uploaded runs
|
|
@@ -44,7 +44,7 @@ from agentprobe.injector import (
|
|
|
44
44
|
RecordingInjector,
|
|
45
45
|
ReplayInjector,
|
|
46
46
|
)
|
|
47
|
-
from agentprobe.quickstart import assert_passes, quick_test, quick_test_all, wrap_agent
|
|
47
|
+
from agentprobe.quickstart import assert_passes, http_agent, quick_test, quick_test_all, wrap_agent
|
|
48
48
|
from agentprobe.registry import (
|
|
49
49
|
FetchedDomain,
|
|
50
50
|
RegressionResult,
|
|
@@ -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__ = "0.5.
|
|
63
|
+
__version__ = "0.5.1"
|
|
64
64
|
|
|
65
65
|
__all__ = [
|
|
66
66
|
"Agent",
|
|
@@ -93,6 +93,7 @@ __all__ = [
|
|
|
93
93
|
"check_regression",
|
|
94
94
|
"fetch_domain",
|
|
95
95
|
"get_latest_run",
|
|
96
|
+
"http_agent",
|
|
96
97
|
"injection_was_triggered",
|
|
97
98
|
"quick_test",
|
|
98
99
|
"quick_test_all",
|
|
@@ -9,6 +9,8 @@ what to do next, test it against one scenario."
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
import json
|
|
13
|
+
import urllib.request
|
|
12
14
|
from typing import Any, Callable, Optional
|
|
13
15
|
|
|
14
16
|
from agentprobe.agents.base import Agent, AgentAction
|
|
@@ -57,6 +59,64 @@ def wrap_agent(decide_fn: DecideFn) -> Callable[[], Agent]:
|
|
|
57
59
|
return lambda: _FunctionAgent(decide_fn)
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
HttpRequester = Callable[[str, dict, dict], dict] # (url, body, headers) -> response dict
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _default_http_requester(url: str, body: dict, headers: dict) -> dict:
|
|
66
|
+
data = json.dumps(body).encode("utf-8")
|
|
67
|
+
request = urllib.request.Request(
|
|
68
|
+
url,
|
|
69
|
+
data=data,
|
|
70
|
+
method="POST",
|
|
71
|
+
headers={"Content-Type": "application/json", "User-Agent": "agentprobe-client/0.5.0", **headers},
|
|
72
|
+
)
|
|
73
|
+
with urllib.request.urlopen(request, timeout=30) as resp: # noqa: S310 -- caller-supplied url, same trust model as any target agent's own API
|
|
74
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def http_agent(
|
|
78
|
+
url: str,
|
|
79
|
+
headers: Optional[dict] = None,
|
|
80
|
+
requester: Optional[HttpRequester] = None,
|
|
81
|
+
) -> Callable[[], Agent]:
|
|
82
|
+
"""Adapt a hosted HTTP agent into a target_factory for quick_test()/
|
|
83
|
+
run_robustness_pair() -- for when your real agent already runs as a
|
|
84
|
+
service you can POST to, instead of a Python function/object living in
|
|
85
|
+
this same process. No custom decide_fn to write: this builds one for
|
|
86
|
+
you and wraps it exactly like wrap_agent() does.
|
|
87
|
+
|
|
88
|
+
On every step, POSTs `{"task": <str>, "history": [...]}` as JSON to
|
|
89
|
+
`url` -- `history` is the same shape wrap_agent's decide_fn receives, a
|
|
90
|
+
list of `{"tool_name", "tool_args", "result", "ok"}` dicts covering
|
|
91
|
+
everything observed so far this run. Expects back JSON shaped like
|
|
92
|
+
either:
|
|
93
|
+
|
|
94
|
+
{"tool_name": "...", "tool_args": {...}} -- call this tool next
|
|
95
|
+
{"final_answer": "..."} -- done, this is the reply
|
|
96
|
+
|
|
97
|
+
Raises ValueError if a response matches neither shape, rather than
|
|
98
|
+
guessing what was meant. Pass `headers` (e.g.
|
|
99
|
+
`{"Authorization": "Bearer ..."}`) for an endpoint that needs auth, and
|
|
100
|
+
`requester` in tests instead of hitting the real network -- see
|
|
101
|
+
tests/test_quickstart.py.
|
|
102
|
+
"""
|
|
103
|
+
requester = requester if requester is not None else _default_http_requester
|
|
104
|
+
resolved_headers = headers or {}
|
|
105
|
+
|
|
106
|
+
def decide_fn(task: str, history: list[dict[str, Any]]) -> AgentAction:
|
|
107
|
+
response = requester(url, {"task": task, "history": history}, resolved_headers)
|
|
108
|
+
if "final_answer" in response:
|
|
109
|
+
return AgentAction(kind="final_answer", text=response["final_answer"])
|
|
110
|
+
if "tool_name" in response and "tool_args" in response:
|
|
111
|
+
return AgentAction(kind="tool_call", tool_name=response["tool_name"], tool_args=response["tool_args"])
|
|
112
|
+
raise ValueError(
|
|
113
|
+
f"http_agent: response from {url} must include either 'final_answer' or "
|
|
114
|
+
f"both 'tool_name' and 'tool_args', got keys {sorted(response.keys())}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return wrap_agent(decide_fn)
|
|
118
|
+
|
|
119
|
+
|
|
60
120
|
def quick_test(
|
|
61
121
|
scenario: Scenario,
|
|
62
122
|
agent: Callable[[], Agent] | DecideFn,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentprobe-testing
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
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 = "0.5.
|
|
3
|
+
version = "0.5.1"
|
|
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"]
|
|
@@ -3,7 +3,7 @@ import pytest
|
|
|
3
3
|
from agentprobe.agents.base import AgentAction
|
|
4
4
|
from agentprobe.agents.rule_based import RuleBasedAgent
|
|
5
5
|
from agentprobe.injector import HardcodedToolErrorInjector, Injector, NullInjector
|
|
6
|
-
from agentprobe.quickstart import assert_passes, quick_test, quick_test_all, wrap_agent
|
|
6
|
+
from agentprobe.quickstart import assert_passes, http_agent, quick_test, quick_test_all, wrap_agent
|
|
7
7
|
from agentprobe.report import Report
|
|
8
8
|
from agentprobe.scenarios.registry import BY_ID
|
|
9
9
|
|
|
@@ -52,6 +52,81 @@ def test_wrap_agent_gives_each_call_its_own_history_not_shared_across_instances(
|
|
|
52
52
|
assert action.tool_name == "get_ticket" # fresh history, not polluted by `first`
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
def make_requester(responses):
|
|
56
|
+
"""Returns each queued response in order, on every call -- the same
|
|
57
|
+
scripted-sequence pattern ScriptedAgent uses, since http_agent's whole
|
|
58
|
+
point is standing in for a real remote agent step by step."""
|
|
59
|
+
calls = []
|
|
60
|
+
responses = list(responses)
|
|
61
|
+
|
|
62
|
+
def requester(url, body, headers):
|
|
63
|
+
calls.append({"url": url, "body": body, "headers": headers})
|
|
64
|
+
return responses.pop(0)
|
|
65
|
+
|
|
66
|
+
requester.calls = calls
|
|
67
|
+
return requester
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_http_agent_drives_a_full_run_from_scripted_json_responses():
|
|
71
|
+
# mode="recovery" -- a robustness-mode run calls the target_factory
|
|
72
|
+
# twice (clean then chaos), which would drain this same scripted
|
|
73
|
+
# response queue twice over; recovery mode's single trajectory keeps
|
|
74
|
+
# this test's response list simple and matched 1:1 to real steps.
|
|
75
|
+
scenario = BY_ID["clean-1"]
|
|
76
|
+
requester = make_requester(
|
|
77
|
+
[
|
|
78
|
+
{"tool_name": "get_ticket", "tool_args": {"id": "T-1001"}},
|
|
79
|
+
{"tool_name": "issue_refund", "tool_args": {"ticket_id": "T-1001", "amount": 49.99}},
|
|
80
|
+
{"tool_name": "close_ticket", "tool_args": {"ticket_id": "T-1001", "resolution": "refunded"}},
|
|
81
|
+
{"final_answer": "done"},
|
|
82
|
+
]
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
report = quick_test(scenario, http_agent("https://example.com/agent", requester=requester), injector=NullInjector(), mode="recovery")
|
|
86
|
+
|
|
87
|
+
assert report._compute()["chaos_passed"] == 1
|
|
88
|
+
assert requester.calls[0]["url"] == "https://example.com/agent"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_http_agent_sends_task_and_history_as_the_request_body():
|
|
92
|
+
scenario = BY_ID["clean-1"]
|
|
93
|
+
requester = make_requester(
|
|
94
|
+
[
|
|
95
|
+
{"tool_name": "get_ticket", "tool_args": {"id": "T-1001"}},
|
|
96
|
+
{"final_answer": "done"},
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
quick_test(scenario, http_agent("https://example.com/agent", requester=requester), injector=NullInjector(), mode="recovery")
|
|
101
|
+
|
|
102
|
+
first_call, second_call = requester.calls
|
|
103
|
+
assert first_call["body"]["task"] == "Handle ticket T-1001."
|
|
104
|
+
assert first_call["body"]["history"] == []
|
|
105
|
+
assert second_call["body"]["history"][0]["tool_name"] == "get_ticket"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_http_agent_passes_through_custom_headers():
|
|
109
|
+
scenario = BY_ID["clean-1"]
|
|
110
|
+
requester = make_requester([{"final_answer": "done"}])
|
|
111
|
+
|
|
112
|
+
quick_test(
|
|
113
|
+
scenario,
|
|
114
|
+
http_agent("https://example.com/agent", headers={"Authorization": "Bearer secret"}, requester=requester),
|
|
115
|
+
injector=NullInjector(),
|
|
116
|
+
mode="recovery",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
assert requester.calls[0]["headers"] == {"Authorization": "Bearer secret"}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_http_agent_raises_a_clear_error_on_a_response_matching_neither_shape():
|
|
123
|
+
scenario = BY_ID["clean-1"]
|
|
124
|
+
requester = make_requester([{"something_else": "not a valid response"}])
|
|
125
|
+
|
|
126
|
+
with pytest.raises(ValueError, match="must include either 'final_answer' or"):
|
|
127
|
+
quick_test(scenario, http_agent("https://example.com/agent", requester=requester), injector=NullInjector(), mode="recovery")
|
|
128
|
+
|
|
129
|
+
|
|
55
130
|
def test_quick_test_runs_a_plain_function_end_to_end_and_reports_pass():
|
|
56
131
|
scenario = BY_ID["clean-1"]
|
|
57
132
|
report = quick_test(scenario, _clean1_decide, injector=NullInjector())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/__init__.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/agent.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/clean.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/decoy.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/domain.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/entities.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/scenarios.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/split.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/tools.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe/domains/access_control/trap.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/requires.txt
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/agentprobe_testing.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_rule_based_agent.py
RENAMED
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_access_control_scenarios.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentprobe_testing-0.5.0 → agentprobe_testing-0.5.1}/tests/test_complex_access_control_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|