agentenv-framework-protocol 0.1.439__tar.gz → 0.1.441__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.
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/PKG-INFO +5 -3
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/README.md +4 -2
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/pyproject.toml +1 -1
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/checks.py +15 -8
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/website_browser.py +21 -2
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_conformance.py +34 -3
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_conformance_checks.py +1 -1
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_website_browser.py +36 -1
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/LICENSE +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/NOTICE +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/THIRD_PARTY_NOTICES.md +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/advanced_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/basic_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/custom_extensions_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/multimodal_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/reference_model.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/streaming_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/client.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/_declare.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/_linux.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/_load.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/_with_fds.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/app.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/app_data.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/app_runtime.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/apps.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/card.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/checks.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/__main__.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/client.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/fixture.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/mp4.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/conformance/report.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/driver.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/errors.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/frames.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/keys.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/launch.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/operations.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/platform.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/queue.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/recording.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/results.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/run_install_step.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/runtime.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/serve.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/serve_app.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/session.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/settings.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/skill.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/spaces.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/computer/tools.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/errors.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/preflight.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/transfers.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/src/agentenv_protocol/types.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/computer_fake.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/probe_fake.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_agent.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_agent_examples.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_cdp_config.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_object_transfers.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_proxy.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_staging.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_client.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_app_data.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_app_server.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_conformance_recording.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_declare.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_driver.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_extensions.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_frames.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_queue.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_recording.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_serve.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_computer_spaces.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_control_token.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_data_objects.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_errors.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_extension_methods.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_intake.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_manifest.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_preflight.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_annotations.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_context_fastmcp.py +0 -0
- {agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_tool_context_injection.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentenv-framework-protocol
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.441
|
|
4
4
|
Summary: Open data-plane protocol and server SDK for agent environments.
|
|
5
5
|
Project-URL: Homepage, https://www.agentenvframework.com
|
|
6
6
|
Project-URL: Documentation, https://www.agentenvframework.com/docs
|
|
@@ -846,8 +846,10 @@ are the profile's template. The base class adds:
|
|
|
846
846
|
the pipe rather than a second copy, which would hand its window to the first and exit. The ready check
|
|
847
847
|
`devtools_answers` asks `Browser.getVersion` over the pipe.
|
|
848
848
|
- **Its control connection**, `self.control`, a `BrowserControl` over the pipe. At each launch it attaches
|
|
849
|
-
to every page with flattened sessions
|
|
850
|
-
|
|
849
|
+
to every page with flattened sessions, telling each page it attached to as it opened, a popup say, to run, and keeps a
|
|
850
|
+
record, `since` its server started: open tabs in opened order, each with its URL and title as the browser has them
|
|
851
|
+
when the record is read (Chrome sends no event for a title), the one whose page has focus `active`; `closed_tabs`,
|
|
852
|
+
each as of its page's last load, with `closed_at` and
|
|
851
853
|
`closed_by` (`agentenv`, over this connection; `unknown`, anyone else; `exit` or `stop`, when the browser
|
|
852
854
|
ended on its own or its server stopped it); `downloads`, into `~/Downloads`, each with its state
|
|
853
855
|
and, completed, its size and sha256; and `dialogs`, each with its type, message, answer and who gave it.
|
|
@@ -790,8 +790,10 @@ are the profile's template. The base class adds:
|
|
|
790
790
|
the pipe rather than a second copy, which would hand its window to the first and exit. The ready check
|
|
791
791
|
`devtools_answers` asks `Browser.getVersion` over the pipe.
|
|
792
792
|
- **Its control connection**, `self.control`, a `BrowserControl` over the pipe. At each launch it attaches
|
|
793
|
-
to every page with flattened sessions
|
|
794
|
-
|
|
793
|
+
to every page with flattened sessions, telling each page it attached to as it opened, a popup say, to run, and keeps a
|
|
794
|
+
record, `since` its server started: open tabs in opened order, each with its URL and title as the browser has them
|
|
795
|
+
when the record is read (Chrome sends no event for a title), the one whose page has focus `active`; `closed_tabs`,
|
|
796
|
+
each as of its page's last load, with `closed_at` and
|
|
795
797
|
`closed_by` (`agentenv`, over this connection; `unknown`, anyone else; `exit` or `stop`, when the browser
|
|
796
798
|
ended on its own or its server stopped it); `downloads`, into `~/Downloads`, each with its state
|
|
797
799
|
and, completed, its size and sha256; and `dialogs`, each with its type, message, answer and who gave it.
|
|
@@ -13,6 +13,7 @@ import uuid
|
|
|
13
13
|
from collections.abc import Awaitable, Callable
|
|
14
14
|
from datetime import datetime
|
|
15
15
|
from importlib import resources
|
|
16
|
+
from typing import Any
|
|
16
17
|
|
|
17
18
|
from mcp import ClientSession
|
|
18
19
|
from mcp.types import CallToolResult
|
|
@@ -152,6 +153,10 @@ class Probe:
|
|
|
152
153
|
raise AssertionError(f"computer_screenshot failed: {result.content[0].text}")
|
|
153
154
|
return result, image(result)
|
|
154
155
|
|
|
156
|
+
async def pixel(self, x: int, y: int) -> tuple[int, int, int]:
|
|
157
|
+
"""The pixel at frame pixel (x, y) of a new frame."""
|
|
158
|
+
return (await self.shot())[1].getpixel((x, y))
|
|
159
|
+
|
|
155
160
|
async def act(self, name: str, args: dict) -> None:
|
|
156
161
|
result = await self.tool(name, args)
|
|
157
162
|
if result.isError:
|
|
@@ -161,13 +166,15 @@ class Probe:
|
|
|
161
166
|
out = await self.driver.run("cat", f"{STAGE}/state/state.json")
|
|
162
167
|
return json.loads(out["stdout"])
|
|
163
168
|
|
|
164
|
-
async def until(self, holds: Callable[[
|
|
165
|
-
|
|
169
|
+
async def until(self, holds: Callable[[Any], bool],
|
|
170
|
+
read: Callable[[], Awaitable[Any]] | None = None) -> tuple[bool, Any]:
|
|
171
|
+
"""Whether what ``read`` gives, the fixture's state unless it's given, comes to satisfy ``holds`` within
|
|
172
|
+
SETTLE_S, and what it last gave."""
|
|
166
173
|
deadline = time.monotonic() + SETTLE_S
|
|
167
174
|
while True:
|
|
168
|
-
|
|
169
|
-
if holds(
|
|
170
|
-
return holds(
|
|
175
|
+
seen = await (read or self.state)()
|
|
176
|
+
if holds(seen) or time.monotonic() > deadline:
|
|
177
|
+
return holds(seen), seen
|
|
171
178
|
await asyncio.sleep(POLL_S)
|
|
172
179
|
|
|
173
180
|
async def settled(self, holds: Callable[[dict], bool], show: Callable[[dict], object]) -> str | None:
|
|
@@ -588,8 +595,8 @@ class Probe:
|
|
|
588
595
|
problem = await self.settled(lambda s: s["cells"].get("2,3") == 1, lambda s: s["cells"])
|
|
589
596
|
if problem:
|
|
590
597
|
return problem
|
|
591
|
-
|
|
592
|
-
return None if
|
|
598
|
+
shows, pixel = await self.until(lambda p: p == (255, 0, 0), lambda: self.pixel(x, y))
|
|
599
|
+
return None if shows else f"no frame within {SETTLE_S:g} s shows it: the last shows {pixel}"
|
|
593
600
|
|
|
594
601
|
async def norm_space() -> str | None:
|
|
595
602
|
x, y = cell(5, 5)
|
|
@@ -636,7 +643,7 @@ class Probe:
|
|
|
636
643
|
return await self.settled(lambda s: s["saved_count"] == 1 and s["subscribed"],
|
|
637
644
|
lambda s: (s["saved_count"], s["subscribed"]))
|
|
638
645
|
|
|
639
|
-
await self.check("P4", "a click in frame space hits its cell, and
|
|
646
|
+
await self.check("P4", "a click in frame space hits its cell, and a frame shows it", frame_space)
|
|
640
647
|
if self.driver.declares(COMPUTER_SPACES):
|
|
641
648
|
await self.check("P4", "a click in norm space hits its cell", norm_space, COMPUTER_SPACES)
|
|
642
649
|
if "right" in buttons:
|
|
@@ -260,13 +260,26 @@ class BrowserControl:
|
|
|
260
260
|
return visible
|
|
261
261
|
|
|
262
262
|
async def record(self) -> dict:
|
|
263
|
-
"""The record ``since`` it started: open ``tabs``, each with whether it's ``active``,
|
|
264
|
-
``downloads`` and ``dialogs``."""
|
|
263
|
+
"""The record ``since`` it started: open ``tabs``, each with its URL and title now and whether it's ``active``,
|
|
264
|
+
``closed_tabs``, ``downloads`` and ``dialogs``."""
|
|
265
|
+
await self._refresh()
|
|
265
266
|
active = await self.active_tab()
|
|
266
267
|
return {"since": self.since, "tabs": [{**tab, "active": tab["id"] == active} for tab in self.tabs.values()],
|
|
267
268
|
"closed_tabs": list(self.closed_tabs), "downloads": list(self.downloads.values()),
|
|
268
269
|
"dialogs": list(self.dialog_log)}
|
|
269
270
|
|
|
271
|
+
async def _refresh(self, target: Optional[str] = None) -> None:
|
|
272
|
+
"""The URL and title of the tab ``target``, or of every open tab, as the browser has them now: it sends no
|
|
273
|
+
event when a page's title changes."""
|
|
274
|
+
try:
|
|
275
|
+
infos = (await self.devtools.call("Target.getTargets", {"filter": PAGES},
|
|
276
|
+
timeout_s=ACTIVE_CHECK_TIMEOUT_S))["targetInfos"]
|
|
277
|
+
except (ConnectionError, DevToolsError, asyncio.TimeoutError, KeyError):
|
|
278
|
+
return
|
|
279
|
+
for info in infos:
|
|
280
|
+
if target in (None, info["targetId"]) and (tab := self.tabs.get(info["targetId"])) is not None:
|
|
281
|
+
tab.update(url=info.get("url", tab["url"]), title=info.get("title", tab["title"]))
|
|
282
|
+
|
|
270
283
|
def _event(self, message: dict) -> None:
|
|
271
284
|
handler = getattr(self, "_on_" + message.get("method", "").replace(".", "_"), None)
|
|
272
285
|
if handler is not None:
|
|
@@ -295,10 +308,16 @@ class BrowserControl:
|
|
|
295
308
|
if params["targetInfo"].get("type") == "page":
|
|
296
309
|
self._sessions[params["sessionId"]] = params["targetInfo"]["targetId"]
|
|
297
310
|
self._spawn(self.devtools.call("Page.enable", session_id=params["sessionId"]))
|
|
311
|
+
# A page attached as it opens, a popup say, waits for this before it navigates.
|
|
312
|
+
self._spawn(self.devtools.call("Runtime.runIfWaitingForDebugger", session_id=params["sessionId"]))
|
|
298
313
|
|
|
299
314
|
def _on_Target_detachedFromTarget(self, params: dict, session: Optional[str]) -> None:
|
|
300
315
|
self._sessions.pop(params["sessionId"], None)
|
|
301
316
|
|
|
317
|
+
def _on_Page_loadEventFired(self, params: dict, session: Optional[str]) -> None:
|
|
318
|
+
if (target := self._sessions.get(session)) is not None:
|
|
319
|
+
self._spawn(self._refresh(target))
|
|
320
|
+
|
|
302
321
|
def _on_Page_javascriptDialogOpening(self, params: dict, session: Optional[str]) -> None:
|
|
303
322
|
dialog = {"tab": self._sessions.get(session), "type": params.get("type"), "message": params.get("message", ""),
|
|
304
323
|
"url": params.get("url", ""), "opened_at": _now(), "answer": None, "by": None}
|
|
@@ -85,12 +85,43 @@ async def test_a_driver_given_a_control_token_passes_with_it_and_refuses_calls_w
|
|
|
85
85
|
assert not unauthorized.passed and "401 unauthorized" in _failed(unauthorized)[0]
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
class StaleFrame(FixtureDriver):
|
|
89
|
+
"""Its first ``stale`` captures after a click are from before the click, as when an app records a click before it
|
|
90
|
+
repaints."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, stale: int = 1, **kwargs) -> None:
|
|
93
|
+
super().__init__(**kwargs)
|
|
94
|
+
self.stale, self.left, self.before_click = stale, 0, None
|
|
95
|
+
|
|
96
|
+
@click
|
|
97
|
+
async def click_at(self, x, y, button, count, modifiers):
|
|
98
|
+
self.before_click, self.left = self.screen.image.copy(), self.stale
|
|
99
|
+
return await super().click_at(x, y, button, count, modifiers)
|
|
100
|
+
|
|
101
|
+
@capture
|
|
102
|
+
async def grab(self):
|
|
103
|
+
if not self.left:
|
|
104
|
+
return self.screen.image.copy()
|
|
105
|
+
self.left -= 1
|
|
106
|
+
return self.before_click.copy()
|
|
107
|
+
|
|
108
|
+
|
|
88
109
|
@pytest.mark.asyncio
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
@pytest.mark.parametrize("driver", [lambda: FixtureDriver(settings=ComputerSettings(default_space="norm")), StaleFrame],
|
|
111
|
+
ids=["default-space-norm", "stale-first-frame"])
|
|
112
|
+
async def test_a_driver_whose_default_space_is_norm_or_whose_first_frame_after_a_click_is_stale_passes_at_full(driver):
|
|
113
|
+
report = await _probe(driver())
|
|
91
114
|
assert report.passed, _failed(report)
|
|
92
115
|
|
|
93
116
|
|
|
117
|
+
@pytest.mark.asyncio
|
|
118
|
+
async def test_frames_that_never_show_a_click_the_fixture_saw_fail_p4_with_the_last_pixel(monkeypatch):
|
|
119
|
+
monkeypatch.setattr(checks, "SETTLE_S", 0.5)
|
|
120
|
+
report = await _probe(StaleFrame(stale=10**6))
|
|
121
|
+
failed = next(c for c in report.checks if c.name == "a click in frame space hits its cell, and a frame shows it")
|
|
122
|
+
assert (failed.status, failed.detail) == ("failed", "no frame within 0.5 s shows it: the last shows (255, 255, 255)")
|
|
123
|
+
|
|
124
|
+
|
|
94
125
|
@pytest.mark.asyncio
|
|
95
126
|
async def test_a_tool_already_hidden_from_the_probes_role_stays_hidden():
|
|
96
127
|
with served(FixtureDriver()) as url:
|
|
@@ -195,7 +226,7 @@ class ExitZero(FixtureDriver):
|
|
|
195
226
|
@pytest.mark.asyncio
|
|
196
227
|
@pytest.mark.parametrize("driver, broken", [
|
|
197
228
|
(NeverReady, "computer-ready reports ready"),
|
|
198
|
-
(ClicksOff, "a click in frame space hits its cell, and
|
|
229
|
+
(ClicksOff, "a click in frame space hits its cell, and a frame shows it"),
|
|
199
230
|
(ShiftedCapture, "markers at odd and even pixels read back in frame pixels"),
|
|
200
231
|
(AsciiOnly, "Unicode and mixed-case text arrives whole"),
|
|
201
232
|
(SwappedScroll, "scrolls up, down, left and right each arrive that many times"),
|
|
@@ -229,7 +229,7 @@ async def test_effects_without_spaces_right_or_double_clicks_leave_those_out_and
|
|
|
229
229
|
assert "a click in norm space hits its cell" not in got and "a right click arrives as one" not in got
|
|
230
230
|
assert "a double click arrives as one" not in got and "norm points land on the same pixels" not in got
|
|
231
231
|
assert got["16 clicks sent at once all land"] == ("failed", "16 of 16 were refused")
|
|
232
|
-
assert got["a click in frame space hits its cell, and
|
|
232
|
+
assert got["a click in frame space hits its cell, and a frame shows it"][1].startswith("AssertionError")
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
@pytest.mark.asyncio
|
|
@@ -3,7 +3,8 @@ for each; a subclass refused for carrying one of them; the start tabs, the time
|
|
|
3
3
|
its launch run with no desktop when alone; a CDP connection over a new debugging pipe at each launch, which its ready
|
|
4
4
|
check asks, and a browser launched again when its server restarts; its shared memory in files only on a small
|
|
5
5
|
/dev/shm; an empty cache and the deploy's prompt answers in its profile at each launch; its policies, card params and
|
|
6
|
-
skill; and an app that isn't a browser
|
|
6
|
+
skill; its record's titles read from the browser, which sends no event for a page's; and an app that isn't a browser
|
|
7
|
+
launched and declared as before."""
|
|
7
8
|
from __future__ import annotations
|
|
8
9
|
|
|
9
10
|
import asyncio
|
|
@@ -492,6 +493,40 @@ async def test_its_control_records_tabs_in_opened_order_and_who_closed_each_and_
|
|
|
492
493
|
assert devtools.calls[2][1] == {"behavior": "default", "eventsEnabled": True}
|
|
493
494
|
|
|
494
495
|
|
|
496
|
+
@pytest.mark.asyncio
|
|
497
|
+
async def test_each_page_it_attaches_to_is_told_to_run_so_a_popup_it_attached_to_as_it_opened_navigates(tmp_path):
|
|
498
|
+
devtools = StubDevTools()
|
|
499
|
+
control = BrowserControl(devtools, "agent")
|
|
500
|
+
await control.attach()
|
|
501
|
+
devtools.send("Target.attachedToTarget", {"sessionId": "s-popup", "waitingForDebugger": True, **_page("popup")})
|
|
502
|
+
await asyncio.sleep(0)
|
|
503
|
+
|
|
504
|
+
assert ("Page.enable", {}, "s-popup") in devtools.calls
|
|
505
|
+
assert ("Runtime.runIfWaitingForDebugger", {}, "s-popup") in devtools.calls
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
@pytest.mark.asyncio
|
|
509
|
+
async def test_its_record_reads_each_tabs_title_when_read_and_when_its_page_loads_since_no_event_says(tmp_path):
|
|
510
|
+
now = {"a": "Inbox", "b": "Draft"}
|
|
511
|
+
devtools = StubDevTools({"Target.getTargets": lambda params, session: {"targetInfos": [
|
|
512
|
+
_page(target, f"https://mail.test/{target}", title)["targetInfo"] for target, title in now.items()]}})
|
|
513
|
+
control = BrowserControl(devtools, "agent")
|
|
514
|
+
await control.attach()
|
|
515
|
+
for target in ("a", "b"):
|
|
516
|
+
devtools.send("Target.targetCreated", _page(target, f"https://mail.test/{target}", f"mail.test/{target}"))
|
|
517
|
+
devtools.send("Target.attachedToTarget", {"sessionId": f"s-{target}", **_page(target)})
|
|
518
|
+
devtools.send("Page.loadEventFired", {"timestamp": 1}, session="s-b")
|
|
519
|
+
await asyncio.sleep(0)
|
|
520
|
+
del now["b"]
|
|
521
|
+
devtools.send("Target.targetDestroyed", {"targetId": "b"})
|
|
522
|
+
now["a"] = "Inbox (1)"
|
|
523
|
+
record = await control.record()
|
|
524
|
+
|
|
525
|
+
assert [(tab["id"], tab["title"]) for tab in record["tabs"]] == [("a", "Inbox (1)")]
|
|
526
|
+
assert [(tab["id"], tab["title"]) for tab in record["closed_tabs"]] == [("b", "Draft")]
|
|
527
|
+
assert ("Target.getTargets", {"filter": [{"type": "page"}]}, None) in devtools.calls
|
|
528
|
+
|
|
529
|
+
|
|
495
530
|
@pytest.mark.asyncio
|
|
496
531
|
@pytest.mark.parametrize("dialogs, kind, sent, answer, by", [
|
|
497
532
|
("accept", "prompt", {"accept": True, "promptText": "yes"}, "accepted", "agentenv"),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/THIRD_PARTY_NOTICES.md
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/examples/basic_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
|
|
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
|
|
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
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/computer_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/probe_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_a2a_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_client.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
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_intake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_manifest.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.439 → agentenv_framework_protocol-0.1.441}/tests/test_preflight.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|