agentenv-framework-protocol 0.1.469__tar.gz → 0.1.471__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.469 → agentenv_framework_protocol-0.1.471}/PKG-INFO +4 -1
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/README.md +5 -2
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/pyproject.toml +6 -1
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/__init__.py +4 -1
- agentenv_framework_protocol-0.1.471/src/agentenv_protocol/computer/_x11.py +395 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/LICENSE +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/NOTICE +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/README.md +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/THIRD_PARTY_NOTICES.md +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/advanced_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/basic_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/custom_extensions_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/multimodal_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/reference_model.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/streaming_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/Dockerfile +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/Dockerfile.dockerignore +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/data/seed.json +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/env.toml +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/site.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/index.html +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/package-lock.json +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/package.json +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/src/main.js +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/src/style.css +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/website/notes/web/vite.config.js +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/browser_cdp.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/client.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/_declare.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/_linux.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/_load.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/_macos.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/_with_fds.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/app.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/app_data.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/app_runtime.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/apps.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/card.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/checks.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/__main__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/checks.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/client.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/fixture.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/mp4.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/page_fixture.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/conformance/report.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/driver.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/errors.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/frames.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/keys.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/launch.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/operations.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/platform.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/queue.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/recording.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/results.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/run_install_step.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/runtime.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/seed.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/serve.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/serve_app.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/session.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/settings.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/skill.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/spaces.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/svc.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/computer/tools.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/errors.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/preflight.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/transfers.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/types.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/clock.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/conformance.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/environment.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/errors.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/readiness.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/routes.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website/session.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website_browser/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website_browser/control.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website_browser/devtools.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website_browser/environment.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/src/agentenv_protocol/website_browser/shapes.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/computer_fake.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/probe_fake.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_agent.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_agent_examples.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_cdp_config.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_object_transfers.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_proxy.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_staging.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_browser_cdp.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_browser_state.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_client.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_app_data.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_app_server.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_conformance.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_conformance_checks.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_conformance_page.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_conformance_recording.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_declare.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_driver.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_extensions.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_frames.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_macos.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_page.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_queue.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_recording.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_seed.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_serve.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_spaces.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_computer_svc_forward.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_control_token.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_data_objects.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_errors.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_extension_methods.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_intake.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_manifest.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_preflight.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_annotations.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_context_fastmcp.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_tool_context_injection.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_api.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_browser.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_conformance.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_environment.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_mcp.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_notes_example.py +0 -0
- {agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_website_readiness.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.471
|
|
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
|
|
@@ -58,6 +58,9 @@ Requires-Dist: websockets>=13; extra == 'dev'
|
|
|
58
58
|
Provides-Extra: macos
|
|
59
59
|
Requires-Dist: pyobjc-framework-quartz>=11; (sys_platform == 'darwin') and extra == 'macos'
|
|
60
60
|
Requires-Dist: pyobjc-framework-screencapturekit>=11; (sys_platform == 'darwin') and extra == 'macos'
|
|
61
|
+
Provides-Extra: x11
|
|
62
|
+
Requires-Dist: mss<11,>=9; extra == 'x11'
|
|
63
|
+
Requires-Dist: python-xlib<0.34,>=0.33; extra == 'x11'
|
|
61
64
|
Description-Content-Type: text/markdown
|
|
62
65
|
|
|
63
66
|
# agentenv-framework-protocol
|
|
@@ -80,8 +80,11 @@ the container before using it.
|
|
|
80
80
|
## Register it
|
|
81
81
|
|
|
82
82
|
In a bundle, `env.toml` declares the env: copied to a bundle's `envs/notes/`, `agent-env bundle register <bundle>`
|
|
83
|
-
builds the image with that folder as its context. Its keys are `type`, `environment_name` and `backend_image
|
|
84
|
-
|
|
83
|
+
builds the image with that folder as its context. Its keys are `type`, `environment_name` and `backend_image`, and it
|
|
84
|
+
may name `domains`, the names the site is reached by, such as `domains = ["notes.example"]`. These win over the
|
|
85
|
+
card's; without them a computer reaches the site by the names its card declares (`notes.test`), or as
|
|
86
|
+
`notes.localhost` when it declares none. Two sites of one multi env can't claim one name. Without a bundle (`--domain`
|
|
87
|
+
names the site, and can be repeated):
|
|
85
88
|
|
|
86
89
|
```bash
|
|
87
90
|
agent-env env website put --id notes-site --server-dockerfile Dockerfile --server-docker-context .
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agentenv-framework-protocol"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.471"
|
|
4
4
|
description = "Open data-plane protocol and server SDK for agent environments."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -56,6 +56,11 @@ macos = [
|
|
|
56
56
|
"pyobjc-framework-Quartz>=11; sys_platform == 'darwin'",
|
|
57
57
|
"pyobjc-framework-ScreenCaptureKit>=11; sys_platform == 'darwin'",
|
|
58
58
|
]
|
|
59
|
+
# A Linux driver on X11Driver: mss captures the X display and XTEST sends its input, through python-xlib.
|
|
60
|
+
x11 = [
|
|
61
|
+
"mss>=9,<11",
|
|
62
|
+
"python-xlib>=0.33,<0.34",
|
|
63
|
+
]
|
|
59
64
|
dev = [
|
|
60
65
|
"a2a-sdk[http-server]>=0.3.26,<0.4",
|
|
61
66
|
"python-multipart>=0.0.13",
|
|
@@ -98,16 +98,18 @@ if TYPE_CHECKING:
|
|
|
98
98
|
)
|
|
99
99
|
from .driver import DEFAULT_IDENTITY, ComputerDriverEnvironment, DriverDeclaration, computer_driver
|
|
100
100
|
from ._macos import MacOSDriver
|
|
101
|
+
from ._x11 import X11Driver
|
|
101
102
|
from .recording import RecordedFrame, RecordedSegment, RecordHints, Recording, frames_in_thread
|
|
102
103
|
|
|
103
104
|
# The names whose modules need the computer extra (mcp, av and Pillow), by module; MacOSDriver's, the macos extra too,
|
|
104
|
-
# on first use of the Mac.
|
|
105
|
+
# on first use of the Mac, and X11Driver's, the x11 extra.
|
|
105
106
|
_ON_USE = {
|
|
106
107
|
"driver": ("ComputerDriverEnvironment", "computer_driver", "DEFAULT_IDENTITY", "DriverDeclaration"),
|
|
107
108
|
"card": ("COMPUTER", "COMPUTER_READY", "COMPUTER_DISPLAY", "COMPUTER_SPACES", "COMPUTER_POINTER",
|
|
108
109
|
"COMPUTER_KEYBOARD", "COMPUTER_PAGE", "COMPUTER_EXEC", "COMPUTER_RECORDING"),
|
|
109
110
|
"recording": ("Recording", "RecordHints", "RecordedFrame", "RecordedSegment", "frames_in_thread"),
|
|
110
111
|
"_macos": ("MacOSDriver",),
|
|
112
|
+
"_x11": ("X11Driver",),
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
|
|
@@ -120,6 +122,7 @@ def __getattr__(name: str) -> Any:
|
|
|
120
122
|
|
|
121
123
|
__all__ = [
|
|
122
124
|
"ComputerDriverEnvironment", "computer_driver", "DEFAULT_IDENTITY", "DriverDeclaration", "MacOSDriver",
|
|
125
|
+
"X11Driver",
|
|
123
126
|
"ComputerAppEnvironment", "computer_app", "install", "linux", "install_step", "ready_check", "Linux", "Service",
|
|
124
127
|
"Launch", "Ready", "Packages", "AptSource", "Download", "RunScript",
|
|
125
128
|
"AppDeclaration", "AppOs",
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"""computer/v1 on an X11 desktop on Linux, for the reference driver and for a driver whose software serves tools of its
|
|
2
|
+
own, as agent-desktop's does: mss captures the screen and XTEST, through python-xlib, sends the input. X calls run off
|
|
3
|
+
the event loop, one at a time, on a connection checked before each call and reopened when it drops, so the driver
|
|
4
|
+
outlives a restarted X server, and input that lets go of a button returns once the server has let go of it. It records
|
|
5
|
+
the display through FFmpeg's ``x11grab``, by PyAV. A driver subclasses ``X11Driver``, declares itself with
|
|
6
|
+
``computer_driver``, and serves its own tools beside these. Needs the ``x11`` extra: mss and python-xlib."""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import contextlib
|
|
11
|
+
import math
|
|
12
|
+
import os
|
|
13
|
+
import threading
|
|
14
|
+
import time
|
|
15
|
+
from collections import OrderedDict
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from typing import Any, AsyncIterator, Callable, Iterator
|
|
18
|
+
|
|
19
|
+
import av
|
|
20
|
+
import mss
|
|
21
|
+
from Xlib import X, XK
|
|
22
|
+
from Xlib import display as xdisplay
|
|
23
|
+
from Xlib.error import ConnectionClosedError, DisplayConnectionError
|
|
24
|
+
from Xlib.ext import xtest
|
|
25
|
+
|
|
26
|
+
from .driver import ComputerDriverEnvironment
|
|
27
|
+
from .errors import DeliveryFailed, DeviceUnavailable, Unsupported
|
|
28
|
+
from .operations import (Display, Image, ReadyCheck, capture, click, display, drag, key_down, key_up, pointer_down,
|
|
29
|
+
pointer_move, pointer_position, pointer_up, press, record, scroll, type_text)
|
|
30
|
+
from .platform import Platform
|
|
31
|
+
from .recording import RecordedFrame, RecordHints, Recording, frames_in_thread
|
|
32
|
+
from .settings import ComputerSettings
|
|
33
|
+
|
|
34
|
+
BUTTONS = {"left": 1, "middle": 2, "right": 3, "back": 8, "forward": 9}
|
|
35
|
+
#: The pointer state's bit for each button that has one.
|
|
36
|
+
BUTTON_MASKS = {"left": X.Button1Mask, "middle": X.Button2Mask, "right": X.Button3Mask}
|
|
37
|
+
SCROLL = {"up": 4, "down": 5, "left": 6, "right": 7}
|
|
38
|
+
#: W3C key values and their X keysym names; any other single character is typed as its own keysym.
|
|
39
|
+
KEYSYMS = {
|
|
40
|
+
"Enter": "Return", "Tab": "Tab", "Escape": "Escape", "Backspace": "BackSpace", "Delete": "Delete",
|
|
41
|
+
"ArrowUp": "Up", "ArrowDown": "Down", "ArrowLeft": "Left", "ArrowRight": "Right", "Home": "Home", "End": "End",
|
|
42
|
+
"PageUp": "Prior", "PageDown": "Next", "Insert": "Insert", "Control": "Control_L", "Shift": "Shift_L",
|
|
43
|
+
"Alt": "Alt_L", "Meta": "Super_L", "Super": "Super_L", "CapsLock": "Caps_Lock", "ContextMenu": "Menu",
|
|
44
|
+
"PrintScreen": "Print", "Pause": "Pause", " ": "space", **{f"F{n}": f"F{n}" for n in range(1, 25)},
|
|
45
|
+
}
|
|
46
|
+
TYPED = {"\n": "Return", "\t": "Tab"}
|
|
47
|
+
#: The pause between the presses of a double or triple click, in seconds.
|
|
48
|
+
CLICK_GAP_S = 0.04
|
|
49
|
+
#: How long a button's release may take to reach the app, and how often the driver looks.
|
|
50
|
+
RELEASE_WAIT_S = 5.0
|
|
51
|
+
RELEASE_POLL_S = 0.005
|
|
52
|
+
#: How far apart a drag's pointer moves are, in pixels.
|
|
53
|
+
DRAG_STEP_PX = 20
|
|
54
|
+
DROPPED = (ConnectionClosedError, DisplayConnectionError, OSError)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class X11Driver(ComputerDriverEnvironment):
|
|
58
|
+
"""The computer/v1 operations, the pointer and keyboard groups among them, on an X11 desktop."""
|
|
59
|
+
|
|
60
|
+
buttons = ("left", "right", "middle", "back", "forward")
|
|
61
|
+
max_click_count = 3
|
|
62
|
+
max_drag_points = 50
|
|
63
|
+
recording = Recording(max_fps=30)
|
|
64
|
+
|
|
65
|
+
def __init__(self, settings: ComputerSettings | None = None, platform: Platform | None = None) -> None:
|
|
66
|
+
super().__init__(settings, platform)
|
|
67
|
+
self._x: _Connection | None = None
|
|
68
|
+
self._x_lock = threading.Lock()
|
|
69
|
+
#: The keycodes each key held by @key_down pressed, which @key_up releases.
|
|
70
|
+
self._held: dict[str, list[int]] = {}
|
|
71
|
+
|
|
72
|
+
@display
|
|
73
|
+
async def screen(self) -> Display:
|
|
74
|
+
def read(c):
|
|
75
|
+
s = c.d.screen()
|
|
76
|
+
return Display(s.width_in_pixels, s.height_in_pixels, 1.0)
|
|
77
|
+
return await self._read(read)
|
|
78
|
+
|
|
79
|
+
@capture
|
|
80
|
+
async def grab(self) -> Image:
|
|
81
|
+
return await asyncio.to_thread(_grab)
|
|
82
|
+
|
|
83
|
+
@record
|
|
84
|
+
async def stream(self, hints: RecordHints) -> AsyncIterator[RecordedFrame]:
|
|
85
|
+
"""The display through FFmpeg's ``x11grab``. Its frames carry the wall clock, so each one's time is when it
|
|
86
|
+
was captured."""
|
|
87
|
+
size = await self.screen()
|
|
88
|
+
options = {"framerate": str(hints.fps), "video_size": f"{size.width}x{size.height}",
|
|
89
|
+
"draw_mouse": "1" if hints.cursor else "0"}
|
|
90
|
+
|
|
91
|
+
def frames() -> Iterator[RecordedFrame]:
|
|
92
|
+
with av.open(os.environ.get("DISPLAY", ":0"), format="x11grab", options=options) as source:
|
|
93
|
+
for frame in source.decode(video=0):
|
|
94
|
+
yield RecordedFrame(frame, datetime.fromtimestamp(frame.time, timezone.utc))
|
|
95
|
+
|
|
96
|
+
async for frame in frames_in_thread(frames):
|
|
97
|
+
yield frame
|
|
98
|
+
|
|
99
|
+
async def ready_checks(self) -> list[ReadyCheck]:
|
|
100
|
+
try:
|
|
101
|
+
has = await self._read(lambda c: c.d.has_extension("XTEST"))
|
|
102
|
+
except DeviceUnavailable as e:
|
|
103
|
+
return [ReadyCheck("xtest", False, e.message)]
|
|
104
|
+
return [ReadyCheck("xtest", bool(has), "XTEST available" if has else "XTEST missing")]
|
|
105
|
+
|
|
106
|
+
@click
|
|
107
|
+
async def click_at(self, x, y, button, count, modifiers) -> None:
|
|
108
|
+
syms = [_keysym(k) for k in modifiers]
|
|
109
|
+
|
|
110
|
+
def act(c):
|
|
111
|
+
held = c.hold(syms)
|
|
112
|
+
c.move(x, y)
|
|
113
|
+
for i in range(count):
|
|
114
|
+
c.button(button, True)
|
|
115
|
+
c.button(button, False)
|
|
116
|
+
if i + 1 < count:
|
|
117
|
+
c.d.sync()
|
|
118
|
+
time.sleep(CLICK_GAP_S)
|
|
119
|
+
c.released(button)
|
|
120
|
+
c.release(reversed(held))
|
|
121
|
+
await self._send(act)
|
|
122
|
+
|
|
123
|
+
@drag
|
|
124
|
+
async def drag_along(self, path, button, duration_ms, modifiers) -> None:
|
|
125
|
+
syms = [_keysym(k) for k in modifiers]
|
|
126
|
+
steps = _steps(path)
|
|
127
|
+
pause = duration_ms / 1000 / len(steps)
|
|
128
|
+
held: list[int] = []
|
|
129
|
+
|
|
130
|
+
def start(c):
|
|
131
|
+
held.extend(c.hold(syms))
|
|
132
|
+
c.move(*path[0])
|
|
133
|
+
c.button(button, True)
|
|
134
|
+
|
|
135
|
+
def finish(c):
|
|
136
|
+
c.button(button, False)
|
|
137
|
+
c.released(button)
|
|
138
|
+
c.release(reversed(held))
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
await self._send(start)
|
|
142
|
+
for px, py in steps:
|
|
143
|
+
await self._send(lambda c, px=px, py=py: c.move(px, py))
|
|
144
|
+
await asyncio.sleep(pause)
|
|
145
|
+
except BaseException:
|
|
146
|
+
with contextlib.suppress(Exception):
|
|
147
|
+
await self._send(finish)
|
|
148
|
+
raise
|
|
149
|
+
await self._send(finish)
|
|
150
|
+
|
|
151
|
+
@scroll
|
|
152
|
+
async def scroll_at(self, x, y, direction, amount, modifiers) -> None:
|
|
153
|
+
syms = [_keysym(k) for k in modifiers]
|
|
154
|
+
|
|
155
|
+
def act(c):
|
|
156
|
+
held = c.hold(syms)
|
|
157
|
+
c.move(x, y)
|
|
158
|
+
for _ in range(amount):
|
|
159
|
+
xtest.fake_input(c.d, X.ButtonPress, SCROLL[direction])
|
|
160
|
+
xtest.fake_input(c.d, X.ButtonRelease, SCROLL[direction])
|
|
161
|
+
c.release(reversed(held))
|
|
162
|
+
await self._send(act)
|
|
163
|
+
|
|
164
|
+
@pointer_move
|
|
165
|
+
async def move(self, x, y) -> None:
|
|
166
|
+
await self._send(lambda c: c.move(x, y))
|
|
167
|
+
|
|
168
|
+
@pointer_down
|
|
169
|
+
async def down(self, button) -> None:
|
|
170
|
+
await self._send(lambda c: c.button(button, True))
|
|
171
|
+
|
|
172
|
+
@pointer_up
|
|
173
|
+
async def up(self, button) -> None:
|
|
174
|
+
def act(c):
|
|
175
|
+
c.button(button, False)
|
|
176
|
+
c.released(button)
|
|
177
|
+
await self._send(act)
|
|
178
|
+
|
|
179
|
+
@pointer_position
|
|
180
|
+
async def where(self) -> tuple[int, int]:
|
|
181
|
+
def read(c):
|
|
182
|
+
p = c.d.screen().root.query_pointer()
|
|
183
|
+
return p.root_x, p.root_y
|
|
184
|
+
return await self._read(read)
|
|
185
|
+
|
|
186
|
+
@type_text
|
|
187
|
+
async def type_in(self, text) -> None:
|
|
188
|
+
syms = [XK.string_to_keysym(TYPED[ch]) if ch in TYPED else _keysym(ch) for ch in text]
|
|
189
|
+
await self._read(lambda c: c.check(syms))
|
|
190
|
+
for sym in syms:
|
|
191
|
+
hold = self.settings.tap_hold_ms / 1000
|
|
192
|
+
await self._send(lambda c, sym=sym: c.tap(sym, hold))
|
|
193
|
+
await asyncio.sleep(self.settings.type_delay_ms / 1000)
|
|
194
|
+
|
|
195
|
+
@press
|
|
196
|
+
async def press_keys(self, keys) -> None:
|
|
197
|
+
syms = [_keysym(k) for k in keys]
|
|
198
|
+
hold = self.settings.tap_hold_ms / 1000
|
|
199
|
+
|
|
200
|
+
def act(c):
|
|
201
|
+
pressed = c.hold(syms)
|
|
202
|
+
c.d.sync()
|
|
203
|
+
time.sleep(hold)
|
|
204
|
+
c.release(reversed(pressed))
|
|
205
|
+
await self._send(act)
|
|
206
|
+
|
|
207
|
+
@key_down
|
|
208
|
+
async def keys_down(self, keys) -> None:
|
|
209
|
+
syms = [_keysym(k) for k in keys]
|
|
210
|
+
|
|
211
|
+
def act(c):
|
|
212
|
+
for key, pressed in zip(keys, c.hold_each(syms)):
|
|
213
|
+
self._held.setdefault(key, []).extend(pressed)
|
|
214
|
+
await self._send(act)
|
|
215
|
+
|
|
216
|
+
@key_up
|
|
217
|
+
async def keys_up(self, keys) -> None:
|
|
218
|
+
def act(c):
|
|
219
|
+
for key in keys:
|
|
220
|
+
c.release(reversed(self._held.pop(key, None) or c.codes(_keysym(key))[-1:]))
|
|
221
|
+
await self._send(act)
|
|
222
|
+
|
|
223
|
+
async def _read(self, fn: Callable[[_Connection], Any]) -> Any:
|
|
224
|
+
return await asyncio.to_thread(self._x_call, fn, False)
|
|
225
|
+
|
|
226
|
+
async def _send(self, fn: Callable[[_Connection], Any]) -> Any:
|
|
227
|
+
return await asyncio.to_thread(self._x_call, fn, True)
|
|
228
|
+
|
|
229
|
+
def _x_call(self, fn: Callable[[_Connection], Any], sends_input: bool) -> Any:
|
|
230
|
+
"""``fn`` on a live connection. When the connection drops, a read is retried once on a new one; input is not
|
|
231
|
+
sent again, since some of it may have arrived."""
|
|
232
|
+
with self._x_lock:
|
|
233
|
+
for attempt in (1, 2):
|
|
234
|
+
c = self._connected()
|
|
235
|
+
try:
|
|
236
|
+
result = fn(c)
|
|
237
|
+
c.d.sync()
|
|
238
|
+
return result
|
|
239
|
+
except DROPPED as e:
|
|
240
|
+
self._x = None
|
|
241
|
+
if sends_input:
|
|
242
|
+
raise DeliveryFailed(f"the X connection dropped while sending input: {type(e).__name__}") from None
|
|
243
|
+
if attempt == 2:
|
|
244
|
+
raise DeviceUnavailable(f"the X server is unavailable: {type(e).__name__}") from None
|
|
245
|
+
|
|
246
|
+
def _connected(self) -> _Connection:
|
|
247
|
+
"""The connection, opened or reopened as needed and checked with a round trip before anything is sent."""
|
|
248
|
+
for attempt in (1, 2):
|
|
249
|
+
try:
|
|
250
|
+
if self._x is None:
|
|
251
|
+
self._x = _Connection()
|
|
252
|
+
self._held.clear()
|
|
253
|
+
self._x.d.sync()
|
|
254
|
+
return self._x
|
|
255
|
+
except DROPPED as e:
|
|
256
|
+
self._x = None
|
|
257
|
+
if attempt == 2:
|
|
258
|
+
raise DeviceUnavailable(f"the X server is unavailable: {type(e).__name__}") from None
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class _Connection:
|
|
262
|
+
"""One connection to the X server, with XTEST input on it. A character the keymap lacks is typed through a spare
|
|
263
|
+
keycode mapped to it, kept for that character and reused; once all are taken, the least recently used one that
|
|
264
|
+
no key holds down is mapped again."""
|
|
265
|
+
|
|
266
|
+
def __init__(self) -> None:
|
|
267
|
+
self.d = xdisplay.Display()
|
|
268
|
+
first = self.d.display.info.min_keycode
|
|
269
|
+
mapping = self.d.get_keyboard_mapping(first, self.d.display.info.max_keycode - first + 1)
|
|
270
|
+
self.width = len(mapping[0])
|
|
271
|
+
self.spare = [first + i for i, syms in enumerate(mapping) if not any(syms)]
|
|
272
|
+
self.mapped: OrderedDict[int, int] = OrderedDict()
|
|
273
|
+
self.shift = self.d.keysym_to_keycode(XK.string_to_keysym("Shift_L"))
|
|
274
|
+
|
|
275
|
+
def move(self, x, y) -> None:
|
|
276
|
+
xtest.fake_input(self.d, X.MotionNotify, x=int(x), y=int(y))
|
|
277
|
+
|
|
278
|
+
def button(self, button: str, down: bool) -> None:
|
|
279
|
+
xtest.fake_input(self.d, X.ButtonPress if down else X.ButtonRelease, BUTTONS[button])
|
|
280
|
+
|
|
281
|
+
def released(self, button: str) -> None:
|
|
282
|
+
"""Wait, up to RELEASE_WAIT_S, until the server has let go of ``button``. A window manager's passive grab holds
|
|
283
|
+
a click on a window until it replays it to the app, while keys reach the app at once, so a key sent before then
|
|
284
|
+
overtakes the click, and so do the next click's moves."""
|
|
285
|
+
deadline = time.monotonic() + RELEASE_WAIT_S
|
|
286
|
+
while self.d.screen().root.query_pointer().mask & BUTTON_MASKS.get(button, 0) and time.monotonic() < deadline:
|
|
287
|
+
time.sleep(RELEASE_POLL_S)
|
|
288
|
+
|
|
289
|
+
def hold(self, keysyms: list[int]) -> list[int]:
|
|
290
|
+
"""``hold_each``'s keycodes, in the order they were pressed."""
|
|
291
|
+
return [code for pressed in self.hold_each(keysyms) for code in pressed]
|
|
292
|
+
|
|
293
|
+
def hold_each(self, keysyms: list[int]) -> list[list[int]]:
|
|
294
|
+
"""Press what the keysyms need that isn't down already, Shift first where a character needs it; for each
|
|
295
|
+
keysym, the keycodes this pressed, so the caller releases only those. Every keycode is found before the first
|
|
296
|
+
press, so keysyms that can't all be held at once are refused with nothing sent."""
|
|
297
|
+
down = self._down()
|
|
298
|
+
planned: list[list[int]] = []
|
|
299
|
+
for keysym in keysyms:
|
|
300
|
+
planned.append(self.codes(keysym, busy=down | {code for codes in planned for code in codes}))
|
|
301
|
+
pressed = []
|
|
302
|
+
for codes in planned:
|
|
303
|
+
pressed.append([code for code in codes if code not in down])
|
|
304
|
+
for code in pressed[-1]:
|
|
305
|
+
xtest.fake_input(self.d, X.KeyPress, code)
|
|
306
|
+
down.add(code)
|
|
307
|
+
return pressed
|
|
308
|
+
|
|
309
|
+
def release(self, codes) -> None:
|
|
310
|
+
for code in codes:
|
|
311
|
+
xtest.fake_input(self.d, X.KeyRelease, code)
|
|
312
|
+
|
|
313
|
+
def tap(self, keysym: int, hold_s: float) -> None:
|
|
314
|
+
"""Type one character: its key pressed and released, with Shift around it when it needs Shift and nothing
|
|
315
|
+
holds Shift already."""
|
|
316
|
+
down = self._down()
|
|
317
|
+
*modifiers, code = self.codes(keysym, busy=down)
|
|
318
|
+
pressed = [m for m in modifiers if m not in down]
|
|
319
|
+
for m in pressed:
|
|
320
|
+
xtest.fake_input(self.d, X.KeyPress, m)
|
|
321
|
+
xtest.fake_input(self.d, X.KeyPress, code)
|
|
322
|
+
self.d.sync()
|
|
323
|
+
time.sleep(hold_s)
|
|
324
|
+
xtest.fake_input(self.d, X.KeyRelease, code)
|
|
325
|
+
self.release(reversed(pressed))
|
|
326
|
+
|
|
327
|
+
def codes(self, keysym: int, busy: set[int] = frozenset()) -> list[int]:
|
|
328
|
+
"""The keycodes that make ``keysym``: Shift and the key when it is the key's second level, else one key; a
|
|
329
|
+
keysym off the keymap is mapped to a spare keycode not in ``busy``."""
|
|
330
|
+
codes = self._on_keymap(keysym)
|
|
331
|
+
if codes is not None:
|
|
332
|
+
return codes
|
|
333
|
+
code = self._free(busy)
|
|
334
|
+
self.d.change_keyboard_mapping(code, [(keysym,) * self.width])
|
|
335
|
+
self.d.sync()
|
|
336
|
+
self.mapped[keysym] = code
|
|
337
|
+
return [code]
|
|
338
|
+
|
|
339
|
+
def check(self, keysyms: list[int]) -> None:
|
|
340
|
+
"""Refuse, before anything is sent, text with a character off the keymap when no spare keycode is free."""
|
|
341
|
+
if any(self._on_keymap(k) is None for k in keysyms):
|
|
342
|
+
self._free(self._down(), take=False)
|
|
343
|
+
|
|
344
|
+
def _free(self, busy: set[int], take: bool = True) -> int:
|
|
345
|
+
"""A spare keycode not in ``busy``, the least recently used mapped one when none is unmapped."""
|
|
346
|
+
if self.spare:
|
|
347
|
+
return self.spare.pop() if take else self.spare[-1]
|
|
348
|
+
for keysym, code in self.mapped.items():
|
|
349
|
+
if code not in busy:
|
|
350
|
+
if take:
|
|
351
|
+
del self.mapped[keysym]
|
|
352
|
+
return code
|
|
353
|
+
raise Unsupported("no spare keycode is free for a character off the X keymap: the server has none, or keys "
|
|
354
|
+
"hold them all down")
|
|
355
|
+
|
|
356
|
+
def _on_keymap(self, keysym: int) -> list[int] | None:
|
|
357
|
+
if keysym in self.mapped:
|
|
358
|
+
self.mapped.move_to_end(keysym)
|
|
359
|
+
return [self.mapped[keysym]]
|
|
360
|
+
code = self.d.keysym_to_keycode(keysym)
|
|
361
|
+
if code and self.d.keycode_to_keysym(code, 0) == keysym:
|
|
362
|
+
return [code]
|
|
363
|
+
if code and self.d.keycode_to_keysym(code, 1) == keysym:
|
|
364
|
+
return [self.shift, code]
|
|
365
|
+
return None
|
|
366
|
+
|
|
367
|
+
def _down(self) -> set[int]:
|
|
368
|
+
return {8 * i + bit for i, byte in enumerate(self.d.query_keymap()) for bit in range(8) if byte >> bit & 1}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _grab() -> Image:
|
|
372
|
+
try:
|
|
373
|
+
with mss.MSS() as m:
|
|
374
|
+
shot = m.grab(m.monitors[0])
|
|
375
|
+
return Image(shot.width, shot.height, bytes(shot.bgra), "BGRA")
|
|
376
|
+
except Exception as e:
|
|
377
|
+
raise DeviceUnavailable(f"capture failed: {type(e).__name__}: {e}") from None
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _steps(path: list) -> list[tuple[float, float]]:
|
|
381
|
+
"""The points a drag moves through after its start, about every DRAG_STEP_PX pixels."""
|
|
382
|
+
steps = []
|
|
383
|
+
for (x0, y0), (x1, y1) in zip(path, path[1:]):
|
|
384
|
+
n = max(2, int(math.hypot(x1 - x0, y1 - y0) / DRAG_STEP_PX))
|
|
385
|
+
steps += [(x0 + (x1 - x0) * k / n, y0 + (y1 - y0) * k / n) for k in range(1, n + 1)]
|
|
386
|
+
return steps
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _keysym(key: str) -> int:
|
|
390
|
+
if key in KEYSYMS:
|
|
391
|
+
return XK.string_to_keysym(KEYSYMS[key])
|
|
392
|
+
if len(key) == 1:
|
|
393
|
+
code = ord(key)
|
|
394
|
+
return code if code < 0x100 else 0x01000000 | code
|
|
395
|
+
raise Unsupported(f"this driver has no X keysym for {key!r}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/THIRD_PARTY_NOTICES.md
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/examples/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/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
|
|
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.469 → agentenv_framework_protocol-0.1.471}/tests/computer_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/probe_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/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.469 → agentenv_framework_protocol-0.1.471}/tests/test_a2a_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/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
|
|
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.469 → agentenv_framework_protocol-0.1.471}/tests/test_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_intake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/tests/test_manifest.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.469 → agentenv_framework_protocol-0.1.471}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|