agentenv-framework-protocol 0.1.474__tar.gz → 0.1.476__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.474 → agentenv_framework_protocol-0.1.476}/PKG-INFO +1 -1
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/pyproject.toml +1 -1
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_linux.py +23 -6
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/checks.py +63 -17
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/driver.py +3 -3
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/platform.py +6 -3
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_conformance.py +22 -1
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_driver.py +11 -5
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/LICENSE +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/NOTICE +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/README.md +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/THIRD_PARTY_NOTICES.md +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/advanced_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/basic_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/custom_extensions_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/multimodal_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/reference_model.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/streaming_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/Dockerfile +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/Dockerfile.dockerignore +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/README.md +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/data/seed.json +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/env.toml +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/site.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/index.html +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/package-lock.json +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/package.json +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/src/main.js +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/src/style.css +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/website/notes/web/vite.config.js +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/browser_cdp.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/client.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_declare.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_load.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_macos.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_with_fds.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/_x11.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/app.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/app_data.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/app_runtime.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/apps.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/card.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/checks.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/__main__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/client.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/fixture.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/mp4.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/page_fixture.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/conformance/report.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/errors.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/frames.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/keys.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/launch.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/operations.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/queue.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/recording.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/results.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/run_install_step.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/runtime.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/seed.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/serve.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/serve_app.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/session.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/settings.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/skill.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/spaces.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/svc.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/computer/tools.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/errors.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/preflight.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/transfers.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/types.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/clock.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/conformance.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/environment.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/errors.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/readiness.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/routes.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website/session.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/control.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/data.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/devtools.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/environment.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/src/agentenv_protocol/website_browser/shapes.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/computer_fake.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/probe_fake.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_agent.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_agent_examples.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_cdp_config.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_object_transfers.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_proxy.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_staging.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_browser_cdp.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_browser_data.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_browser_state.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_client.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_app_data.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_app_server.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_conformance_checks.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_conformance_page.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_conformance_recording.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_declare.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_extensions.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_frames.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_macos.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_page.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_queue.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_recording.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_seed.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_serve.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_spaces.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_computer_svc_forward.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_control_token.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_data_objects.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_errors.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_extension_methods.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_intake.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_manifest.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_preflight.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_annotations.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_context_fastmcp.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_tool_context_injection.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_api.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_browser.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_conformance.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_environment.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_mcp.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_website_notes_example.py +0 -0
- {agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/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.476
|
|
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
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
"""The base class's defaults for the OS operations on Linux
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"""The base class's defaults for the OS operations on Linux, macOS and Windows. The driver runs as the session user
|
|
2
|
+
inside the desktop session, so both act directly: a command inherits the session's environment, a file lands as that
|
|
3
|
+
user. A command runs in a process group of its own, which a timeout kills whole: on Windows, a new process group with no
|
|
4
|
+
console window, killed with its children by taskkill."""
|
|
4
5
|
from __future__ import annotations
|
|
5
6
|
|
|
6
7
|
import asyncio
|
|
7
8
|
import contextlib
|
|
8
9
|
import os
|
|
9
10
|
import signal
|
|
11
|
+
import subprocess
|
|
12
|
+
import sys
|
|
10
13
|
import tempfile
|
|
11
14
|
from pathlib import Path
|
|
12
15
|
|
|
@@ -22,6 +25,10 @@ POLL_S = 0.02
|
|
|
22
25
|
#: How much of a stream is read at a time.
|
|
23
26
|
READ_BYTES = 65536
|
|
24
27
|
_draining: set = set()
|
|
28
|
+
WINDOWS = sys.platform == "win32"
|
|
29
|
+
#: How a command starts: in a session, or on Windows, a process group, of its own, with no console window there.
|
|
30
|
+
_SPAWN = ({"creationflags": subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.CREATE_NO_WINDOW} if WINDOWS else
|
|
31
|
+
{"start_new_session": True})
|
|
25
32
|
|
|
26
33
|
|
|
27
34
|
async def run_in_session(argv: list[str], cwd: str | None, env: dict[str, str] | None, timeout_s: float, *,
|
|
@@ -33,15 +40,14 @@ async def run_in_session(argv: list[str], cwd: str | None, env: dict[str, str] |
|
|
|
33
40
|
try:
|
|
34
41
|
process = await asyncio.create_subprocess_exec(
|
|
35
42
|
*argv, cwd=workdir, env={**os.environ, **(env or {})}, stdin=asyncio.subprocess.DEVNULL,
|
|
36
|
-
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
|
|
43
|
+
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, **_SPAWN)
|
|
37
44
|
except (FileNotFoundError, PermissionError, NotADirectoryError) as e:
|
|
38
45
|
raise InvalidArgument(f"cannot run {argv[0]!r}: {e.strerror or e}") from None
|
|
39
46
|
outputs = [_Capped(output_bytes), _Capped(output_bytes)]
|
|
40
47
|
readers = [asyncio.ensure_future(out.read(stream)) for out, stream in zip(outputs, (process.stdout, process.stderr))]
|
|
41
48
|
timed_out = not await _exited(process, timeout_s)
|
|
42
49
|
if timed_out:
|
|
43
|
-
|
|
44
|
-
os.killpg(process.pid, signal.SIGKILL)
|
|
50
|
+
await _killed(process.pid)
|
|
45
51
|
await _exited(process, DRAIN_S)
|
|
46
52
|
_, pending = await asyncio.wait(readers, timeout=DRAIN_S)
|
|
47
53
|
for out in outputs:
|
|
@@ -54,6 +60,17 @@ async def run_in_session(argv: list[str], cwd: str | None, env: dict[str, str] |
|
|
|
54
60
|
stderr=bytes(stderr.kept), timed_out=timed_out, truncated=stdout.cut or stderr.cut)
|
|
55
61
|
|
|
56
62
|
|
|
63
|
+
async def _killed(pid: int) -> None:
|
|
64
|
+
"""The process group ``pid`` leads killed: on Windows, the process and its children."""
|
|
65
|
+
if WINDOWS:
|
|
66
|
+
killer = await asyncio.create_subprocess_exec("taskkill", "/F", "/T", "/PID", str(pid),
|
|
67
|
+
stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL)
|
|
68
|
+
await killer.wait()
|
|
69
|
+
return
|
|
70
|
+
with contextlib.suppress(ProcessLookupError):
|
|
71
|
+
os.killpg(pid, signal.SIGKILL)
|
|
72
|
+
|
|
73
|
+
|
|
57
74
|
async def _exited(process: asyncio.subprocess.Process, timeout_s: float) -> bool:
|
|
58
75
|
"""Whether the process exits within ``timeout_s``. Read from ``returncode``, which is set when the process exits:
|
|
59
76
|
``Process.wait()`` also waits for the pipes to close, which a background child can hold open."""
|
|
@@ -72,6 +72,25 @@ READ_DIGEST = ("import hashlib,json,sys;d=open(sys.argv[1],'rb').read();"
|
|
|
72
72
|
READ_CHUNK = ("import base64,sys;f=open(sys.argv[1],'rb');f.seek(int(sys.argv[2]));"
|
|
73
73
|
"print(base64.b64encode(f.read(int(sys.argv[3]))).decode())")
|
|
74
74
|
CHUNK_BYTES = 512 << 10
|
|
75
|
+
#: The probe's commands on a Windows computer, which has no POSIX shell or tools: Python one-liners on the python3 the
|
|
76
|
+
#: fixture runs on, writing bytes, so output carries no CRLF, and taskkill and the account checks Windows has.
|
|
77
|
+
WIN_ECHO = ("python3", "-c", "import sys;sys.stdout.buffer.write(b'probe\\n');sys.stderr.buffer.write(b'oops\\n');"
|
|
78
|
+
"sys.exit(3)")
|
|
79
|
+
WIN_SLEEP = ("python3", "-c", "import time;time.sleep(30)")
|
|
80
|
+
WIN_NOW = ("python3", "-c", "import time;print(time.time_ns())")
|
|
81
|
+
WIN_CAT = ("python3", "-c", "import sys;sys.stdout.buffer.write(open(sys.argv[1],'rb').read())")
|
|
82
|
+
WIN_TAIL = ("python3", "-c", "import sys;sys.stdout.buffer.write(b''.join(open(sys.argv[1],'rb').readlines()[-5:]))")
|
|
83
|
+
WIN_REMOVE = ("python3", "-c", "import os,shutil,sys;[shutil.rmtree(p,ignore_errors=True) if os.path.isdir(p) else "
|
|
84
|
+
"os.path.exists(p) and os.remove(p) for p in sys.argv[1:]]")
|
|
85
|
+
WIN_RMDIR = ("python3", "-c", "import os,sys;p=sys.argv[1];os.path.isdir(p) and not os.listdir(p) and os.rmdir(p)")
|
|
86
|
+
#: Starts the fixture detached, its output to its log, in a process group of its own with no console window; its pid.
|
|
87
|
+
WIN_START = ("python3", "-c", "import subprocess,sys;log=open(sys.argv[3],'wb');print(subprocess.Popen("
|
|
88
|
+
"[sys.executable,sys.argv[1],sys.argv[2]],stdout=log,stderr=subprocess.STDOUT,stdin=subprocess.DEVNULL,"
|
|
89
|
+
"creationflags=0x08000200).pid)")
|
|
90
|
+
#: A file's owner, its path in the command, since PowerShell takes what follows -Command as more of the command.
|
|
91
|
+
WIN_OWNER = "(Get-Acl -LiteralPath '{}').Owner"
|
|
92
|
+
#: The well-known SID of the local Administrators group, which an unprivileged user's token holds no enabled entry of.
|
|
93
|
+
ADMINISTRATORS = "S-1-5-32-544"
|
|
75
94
|
#: The checks only ``full`` runs, recorded unverified when the fixture can't be staged.
|
|
76
95
|
FULL_CHECKS = (("P3", "fixture colours land where the mapping says"), ("P4", "clicks show their effect"),
|
|
77
96
|
("P5", "refusals leave the fixture as it was"), ("P6", "typed and pressed keys arrive"),
|
|
@@ -98,6 +117,7 @@ class Probe:
|
|
|
98
117
|
self.fixture_pid: str | None = None
|
|
99
118
|
self.page = self.features.get("screen") == "page"
|
|
100
119
|
self.fixture = "page_fixture.py" if self.page else "fixture.py"
|
|
120
|
+
self.windows = (self.features.get("platform") or {}).get("os") == "windows"
|
|
101
121
|
self.desk = ""
|
|
102
122
|
self.tab: str | None = None
|
|
103
123
|
self.opened: list[str] = []
|
|
@@ -188,7 +208,7 @@ class Probe:
|
|
|
188
208
|
raise AssertionError(f"{name} {args} failed: {result.content[0].text}")
|
|
189
209
|
|
|
190
210
|
async def state(self) -> dict:
|
|
191
|
-
out = await self.
|
|
211
|
+
out = await self._cat(f"{STAGE}/state/state.json")
|
|
192
212
|
return json.loads(out["stdout"])
|
|
193
213
|
|
|
194
214
|
async def until(self, holds: Callable[[Any], bool],
|
|
@@ -394,24 +414,26 @@ class Probe:
|
|
|
394
414
|
cap = self.driver.params(COMPUTER_EXEC).get("max_output_bytes")
|
|
395
415
|
|
|
396
416
|
async def output() -> str | None:
|
|
397
|
-
out = await self.driver.run("sh", "-c", "echo probe; echo oops >&2; exit 3")
|
|
417
|
+
out = await self.driver.run(*(WIN_ECHO if self.windows else ("sh", "-c", "echo probe; echo oops >&2; exit 3")))
|
|
398
418
|
want = {"exit_code": 3, "stdout": "probe\n", "stderr": "oops\n", "timed_out": False}
|
|
399
419
|
return None if {k: out.get(k) for k in want} == want else f"it answered {out}"
|
|
400
420
|
|
|
401
421
|
async def timeout() -> str | None:
|
|
402
422
|
started = time.monotonic()
|
|
403
|
-
out = await self.driver.run("sh", "-c", "sleep 30", timeout_s=1)
|
|
423
|
+
out = await self.driver.run(*(WIN_SLEEP if self.windows else ("sh", "-c", "sleep 30")), timeout_s=1)
|
|
404
424
|
took = time.monotonic() - started
|
|
405
425
|
return None if out.get("timed_out") and took < 15 else f"after {took:.1f} s it answered {out}"
|
|
406
426
|
|
|
407
427
|
async def once() -> str | None:
|
|
408
|
-
request = {"argv":
|
|
428
|
+
request = {"argv": list(WIN_NOW if self.windows else ("sh", "-c", "date +%s%N")),
|
|
429
|
+
"request_id": f"{PROBE_ROLE}-once-{time.time_ns()}"}
|
|
409
430
|
first = await self.driver.invoke(COMPUTER_EXEC, "run", request)
|
|
410
431
|
again = await self.driver.invoke(COMPUTER_EXEC, "run", request)
|
|
411
432
|
return None if first == again else f"it ran twice: {first} then {again}"
|
|
412
433
|
|
|
413
434
|
async def capped() -> str | None:
|
|
414
|
-
out = await self.driver.run("
|
|
435
|
+
out = await self.driver.run(*(("python3", "-c", f"import sys;sys.stdout.buffer.write(b'a'*{cap + 1000})")
|
|
436
|
+
if self.windows else ("sh", "-c", f"head -c {cap + 1000} /dev/zero | tr '\\0' a")))
|
|
415
437
|
return None if out.get("truncated") and len(out["stdout"]) == cap else (
|
|
416
438
|
f"{len(out['stdout'])} bytes came back, truncated {out.get('truncated')}")
|
|
417
439
|
|
|
@@ -546,28 +568,32 @@ class Probe:
|
|
|
546
568
|
added = await self.driver.add_file(f"{STAGE}/{self.fixture}", source)
|
|
547
569
|
if "error" in added:
|
|
548
570
|
return f"data/add refused it: {added['error'].get('message')}"
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
571
|
+
if self.windows:
|
|
572
|
+
await self.driver.run(*WIN_REMOVE, f"{STAGE}/state")
|
|
573
|
+
started = await self.driver.run(*WIN_START, f"{STAGE}/{self.fixture}", f"{STAGE}/state", f"{STAGE}/fixture.log")
|
|
574
|
+
else:
|
|
575
|
+
await self.driver.run("sh", "-c", f"rm -rf {STAGE}/state")
|
|
576
|
+
started = await self.driver.run(
|
|
577
|
+
"sh", "-c", f"python3 {STAGE}/{self.fixture} {STAGE}/state > {STAGE}/fixture.log 2>&1 & echo $!")
|
|
552
578
|
self.fixture_pid = started["stdout"].strip() or None
|
|
553
579
|
deadline = time.monotonic() + FIXTURE_START_S
|
|
554
580
|
while time.monotonic() < deadline:
|
|
555
581
|
if self.page and self.tab is None and (problem := await self._open_desk()):
|
|
556
582
|
return problem
|
|
557
|
-
layout = await self.
|
|
583
|
+
layout = await self._cat(f"{STAGE}/state/layout.json")
|
|
558
584
|
if layout.get("exit_code") == 0 and layout["stdout"].strip():
|
|
559
585
|
self.layout = json.loads(layout["stdout"])
|
|
560
586
|
return None
|
|
561
|
-
state = await self.
|
|
587
|
+
state = await self._cat(f"{STAGE}/state/state.json")
|
|
562
588
|
if state.get("exit_code") == 0 and "error" in (failed := json.loads(state["stdout"] or "{}")):
|
|
563
589
|
return failed["error"]
|
|
564
590
|
await asyncio.sleep(0.5)
|
|
565
|
-
log = await self.driver.run("tail", "-n", "5", f"{STAGE}/fixture.log")
|
|
591
|
+
log = await self.driver.run(*(WIN_TAIL if self.windows else ("tail", "-n", "5")), f"{STAGE}/fixture.log")
|
|
566
592
|
return f"no layout after {FIXTURE_START_S:g} s: {log['stdout'].strip() or log['stderr'].strip()}"
|
|
567
593
|
|
|
568
594
|
async def _open_desk(self) -> str | None:
|
|
569
595
|
"""Once the page fixture's server has its port, the desk opened in a new tab, which is the probe's."""
|
|
570
|
-
port = await self.
|
|
596
|
+
port = await self._cat(f"{STAGE}/state/port")
|
|
571
597
|
if port.get("exit_code") != 0 or not port["stdout"].strip():
|
|
572
598
|
return None
|
|
573
599
|
self.desk = f"http://127.0.0.1:{port['stdout'].strip()}/"
|
|
@@ -588,10 +614,14 @@ class Probe:
|
|
|
588
614
|
await self.tool("computer_tabs", {"action": "close", "tab": tab})
|
|
589
615
|
left.remove(tab)
|
|
590
616
|
if self.fixture_pid:
|
|
591
|
-
await self.driver.run("kill", self.fixture_pid)
|
|
592
|
-
await self.driver.run("rm", "-rf", STAGE)
|
|
617
|
+
await self.driver.run(*(("taskkill", "/F", "/T", "/PID") if self.windows else ("kill",)), self.fixture_pid)
|
|
618
|
+
await self.driver.run(*(WIN_REMOVE if self.windows else ("rm", "-rf")), STAGE)
|
|
593
619
|
if self.upload:
|
|
594
|
-
await self.driver.run("rm", "-f", f"{UPLOADS}/{self.upload}")
|
|
620
|
+
await self.driver.run(*(WIN_REMOVE if self.windows else ("rm", "-f")), f"{UPLOADS}/{self.upload}")
|
|
621
|
+
|
|
622
|
+
async def _cat(self, path: str) -> dict:
|
|
623
|
+
"""``path``'s bytes as the computer's command answers them."""
|
|
624
|
+
return await self.driver.run(*(WIN_CAT if self.windows else ("cat",)), path)
|
|
595
625
|
|
|
596
626
|
async def _base(self) -> tuple[str, float, object]:
|
|
597
627
|
"""A fresh frame of the fixture: its id, the display's scale, and its image."""
|
|
@@ -605,6 +635,21 @@ class Probe:
|
|
|
605
635
|
math.floor((y + (h / 2 if dy is None else dy)) * scale))
|
|
606
636
|
|
|
607
637
|
async def _security(self) -> None:
|
|
638
|
+
async def one_account() -> str | None:
|
|
639
|
+
account = (await self.driver.run("whoami"))["stdout"].strip()
|
|
640
|
+
owner = (await self.driver.run("powershell", "-NoProfile", "-Command",
|
|
641
|
+
WIN_OWNER.format(f"{STAGE}/{self.fixture}")))["stdout"].strip()
|
|
642
|
+
groups = (await self.driver.run("whoami", "/groups"))["stdout"]
|
|
643
|
+
if any(ADMINISTRATORS in line and "Enabled group" in line for line in groups.splitlines()):
|
|
644
|
+
return f"commands run as {account}, an administrator"
|
|
645
|
+
return None if owner.lower() == account.lower() else (
|
|
646
|
+
f"data/add wrote as {owner}, commands run as {account}")
|
|
647
|
+
|
|
648
|
+
if self.windows:
|
|
649
|
+
await self.check("P9", "commands and data/add run as one unprivileged user", one_account, COMPUTER_EXEC,
|
|
650
|
+
*DATA_PLANE)
|
|
651
|
+
return
|
|
652
|
+
|
|
608
653
|
async def one_user() -> str | None:
|
|
609
654
|
uid = (await self.driver.run("id", "-u"))["stdout"].strip()
|
|
610
655
|
owner = (await self.driver.run(*OWNER, f"{STAGE}/{self.fixture}"))["stdout"].strip()
|
|
@@ -993,8 +1038,9 @@ class Probe:
|
|
|
993
1038
|
for recording_id in made:
|
|
994
1039
|
with contextlib.suppress(Exception):
|
|
995
1040
|
await self.driver.invoke(COMPUTER_RECORDING, "end", {"recording_id": recording_id})
|
|
996
|
-
await self.driver.run("rm", "-rf", f"{RECORDINGS_DIR}/{recording_id}")
|
|
997
|
-
await self.driver.run(
|
|
1041
|
+
await self.driver.run(*(WIN_REMOVE if self.windows else ("rm", "-rf")), f"{RECORDINGS_DIR}/{recording_id}")
|
|
1042
|
+
await self.driver.run(*((*WIN_RMDIR, RECORDINGS_DIR) if self.windows else
|
|
1043
|
+
("sh", "-c", f"rmdir {RECORDINGS_DIR} 2>/dev/null || true")))
|
|
998
1044
|
|
|
999
1045
|
async def _segments_match(self, wire: dict, fps: int) -> str | None:
|
|
1000
1046
|
"""What is wrong with a recording without a grant, read back from the computer, or None."""
|
|
@@ -219,13 +219,13 @@ class ComputerDriverEnvironment(Tools, Extensions, DataPlane, AgentEnvEnvironmen
|
|
|
219
219
|
if self._computer is None:
|
|
220
220
|
raise TypeError(f"{type(self).__qualname__}.__init__ must call super().__init__()")
|
|
221
221
|
|
|
222
|
-
# The defaults for the OS operations on Linux
|
|
222
|
+
# The defaults for the OS operations on Linux, macOS and Windows.
|
|
223
223
|
|
|
224
|
-
@default_for("run_in_session", os=["linux", "macos"])
|
|
224
|
+
@default_for("run_in_session", os=["linux", "macos", "windows"])
|
|
225
225
|
async def _computer_linux_run_in_session(self, argv: list, cwd: str | None, env: dict | None, timeout_s: float):
|
|
226
226
|
return await _linux.run_in_session(argv, cwd, env, timeout_s, output_bytes=self.settings.exec_output_bytes)
|
|
227
227
|
|
|
228
|
-
@default_for("write_files", os=["linux", "macos"])
|
|
228
|
+
@default_for("write_files", os=["linux", "macos", "windows"])
|
|
229
229
|
async def _computer_linux_write_files(self, files: dict) -> None:
|
|
230
230
|
await asyncio.to_thread(_linux.write_files, files)
|
|
231
231
|
|
|
@@ -28,14 +28,17 @@ class Platform:
|
|
|
28
28
|
|
|
29
29
|
def detect(environ: dict | None = None, os_release: Path = Path("/etc/os-release")) -> Platform:
|
|
30
30
|
"""The running platform: the OS, ``/etc/os-release``'s ID and VERSION_ID on Linux and the macOS version on macOS,
|
|
31
|
-
the machine, and the display: on Linux from
|
|
32
|
-
``DISPLAY`` (x11) or ``WAYLAND_DISPLAY``
|
|
31
|
+
Windows' marketing version (``11`` from build 22000) on Windows, the machine, and the display: on Linux from
|
|
32
|
+
``XDG_SESSION_TYPE``, ``none`` for a computer with no display, else ``DISPLAY`` (x11) or ``WAYLAND_DISPLAY``
|
|
33
|
+
(wayland); on macOS Aqua; on Windows the Desktop Window Manager (dwm)."""
|
|
33
34
|
environ = os.environ if environ is None else environ
|
|
34
35
|
name = _OS.get(sys.platform, sys.platform)
|
|
35
36
|
release = _os_release(os_release) if name == "linux" else {}
|
|
36
37
|
if name == "macos":
|
|
37
38
|
release = {"VERSION_ID": _platform.mac_ver()[0] or None}
|
|
38
|
-
|
|
39
|
+
if name == "windows":
|
|
40
|
+
release = {"VERSION_ID": "11" if sys.getwindowsversion().build >= 22000 else "10"}
|
|
41
|
+
display = {"macos": "aqua", "windows": "dwm"}.get(name)
|
|
39
42
|
if name == "linux":
|
|
40
43
|
session = (environ.get("XDG_SESSION_TYPE") or "").strip().lower()
|
|
41
44
|
if session in ("x11", "wayland", "none"):
|
|
@@ -34,6 +34,7 @@ from agentenv_protocol.computer import ( # noqa: E402
|
|
|
34
34
|
type_text,
|
|
35
35
|
)
|
|
36
36
|
from agentenv_protocol.computer.conformance import CheckResult, ProbeReport, run_probe # noqa: E402
|
|
37
|
+
from agentenv_protocol.computer import _linux # noqa: E402
|
|
37
38
|
from agentenv_protocol.computer.conformance import checks # noqa: E402
|
|
38
39
|
from agentenv_protocol.computer.conformance.client import Driver # noqa: E402
|
|
39
40
|
from agentenv_protocol import CONTROL_TOKEN_ENV # noqa: E402
|
|
@@ -167,7 +168,7 @@ async def test_each_app_a_driver_fronts_that_exports_is_asked_for_its_export_onc
|
|
|
167
168
|
|
|
168
169
|
@pytest.mark.asyncio
|
|
169
170
|
async def test_a_driver_without_exec_or_data_add_passes_basic_and_leaves_full_unverified():
|
|
170
|
-
report = await _probe(MinimalDriver(FakeScreen(640, 400), platform=Platform(os="
|
|
171
|
+
report = await _probe(MinimalDriver(FakeScreen(640, 400), platform=Platform(os="freebsd")))
|
|
171
172
|
assert report.passed, _failed(report)
|
|
172
173
|
unverified = [c for c in report.checks if c.status == "unverified"]
|
|
173
174
|
assert {c.check for c in unverified} == {"P3", "P4", "P5", "P6", "P7", "P9"}
|
|
@@ -176,6 +177,26 @@ async def test_a_driver_without_exec_or_data_add_passes_basic_and_leaves_full_un
|
|
|
176
177
|
assert report.extensions["urn:agentenv:computer/v1"] == "verified"
|
|
177
178
|
|
|
178
179
|
|
|
180
|
+
@pytest.mark.asyncio
|
|
181
|
+
async def test_a_windows_computer_is_probed_with_the_commands_windows_has(monkeypatch):
|
|
182
|
+
"""Its exec checks run Python one-liners rather than a POSIX shell; here they run on this machine's python3."""
|
|
183
|
+
sent = []
|
|
184
|
+
run = _linux.run_in_session
|
|
185
|
+
|
|
186
|
+
async def recorded(argv, *args, **kwargs):
|
|
187
|
+
sent.append(list(argv))
|
|
188
|
+
return await run(argv, *args, **kwargs)
|
|
189
|
+
|
|
190
|
+
monkeypatch.setattr(_linux, "run_in_session", recorded)
|
|
191
|
+
report = await _probe(MinimalDriver(FakeScreen(640, 400), platform=Platform(os="windows", arch="amd64")), "basic")
|
|
192
|
+
|
|
193
|
+
assert report.passed, _failed(report)
|
|
194
|
+
exec_checks = [c for c in report.checks if "urn:agentenv:computer-exec/v1" in c.extensions]
|
|
195
|
+
assert len(exec_checks) >= 4 and all(c.status == "passed" for c in exec_checks)
|
|
196
|
+
assert list(checks.WIN_ECHO) in sent and list(checks.WIN_SLEEP) in sent and list(checks.WIN_NOW) in sent
|
|
197
|
+
assert not [argv for argv in sent if argv[0] == "sh"]
|
|
198
|
+
|
|
199
|
+
|
|
179
200
|
class NeverReady(FixtureDriver):
|
|
180
201
|
async def ready_checks(self):
|
|
181
202
|
return [ReadyCheck("session", False, "no desktop session")]
|
|
@@ -10,6 +10,7 @@ pytest.importorskip("PIL")
|
|
|
10
10
|
import asyncio # noqa: E402
|
|
11
11
|
import base64 # noqa: E402
|
|
12
12
|
import io # noqa: E402
|
|
13
|
+
from types import SimpleNamespace # noqa: E402
|
|
13
14
|
|
|
14
15
|
from computer_fake import LINUX, FakeDriver, FakeScreen, MinimalDriver, http_client, mcp_session # noqa: E402
|
|
15
16
|
from mcp.server.fastmcp import FastMCP # noqa: E402
|
|
@@ -46,7 +47,7 @@ from agentenv_protocol.computer.tools import _modifiers # noqa: E402
|
|
|
46
47
|
|
|
47
48
|
MACOS = Platform(os="macos", arch="arm64")
|
|
48
49
|
#: A platform the base class has no OS defaults for.
|
|
49
|
-
|
|
50
|
+
FREEBSD = Platform(os="freebsd", arch="amd64")
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
def _required(namespace: dict) -> dict:
|
|
@@ -133,7 +134,7 @@ def test_a_driver_method_replaces_the_linux_default():
|
|
|
133
134
|
Driver = _define({"run": run_in_session(lambda self, *a: None)})
|
|
134
135
|
assert declared(Driver)["run_in_session"] == [("run", {})]
|
|
135
136
|
assert declared(MinimalDriver)["run_in_session"] == [("_computer_linux_run_in_session",
|
|
136
|
-
{"os": frozenset({"linux", "macos"})})]
|
|
137
|
+
{"os": frozenset({"linux", "macos", "windows"})})]
|
|
137
138
|
|
|
138
139
|
|
|
139
140
|
def test_the_platform_is_detected(tmp_path, monkeypatch):
|
|
@@ -148,6 +149,11 @@ def test_the_platform_is_detected(tmp_path, monkeypatch):
|
|
|
148
149
|
monkeypatch.setattr("agentenv_protocol.computer.platform.sys.platform", "darwin")
|
|
149
150
|
monkeypatch.setattr("agentenv_protocol.computer.platform._platform.mac_ver", lambda: ("26.5.2", ("", "", ""), ""))
|
|
150
151
|
assert detect({"DISPLAY": ":0"}, release) == Platform("macos", None, "26.5.2", "arm64", "aqua")
|
|
152
|
+
monkeypatch.setattr("agentenv_protocol.computer.platform.sys.platform", "win32")
|
|
153
|
+
monkeypatch.setattr("agentenv_protocol.computer.platform._platform.machine", lambda: "AMD64")
|
|
154
|
+
monkeypatch.setattr("agentenv_protocol.computer.platform.sys.getwindowsversion",
|
|
155
|
+
lambda: SimpleNamespace(build=26200), raising=False)
|
|
156
|
+
assert detect({}, release) == Platform("windows", None, "11", "amd64", "dwm")
|
|
151
157
|
|
|
152
158
|
|
|
153
159
|
def test_settings_come_from_one_json_value():
|
|
@@ -235,7 +241,7 @@ async def test_a_driver_whose_software_ships_a_skill_leads_with_it_and_the_compu
|
|
|
235
241
|
|
|
236
242
|
@pytest.mark.asyncio
|
|
237
243
|
async def test_a_minimal_driver_declares_only_what_it_has():
|
|
238
|
-
async with http_client(MinimalDriver(platform=
|
|
244
|
+
async with http_client(MinimalDriver(platform=FREEBSD)) as http:
|
|
239
245
|
card = (await http.get("/.well-known/agent-env.json")).json()
|
|
240
246
|
display_set = await http.post("/agentenv/ext/computer-display/set", json={"width": 1, "height": 1})
|
|
241
247
|
exec_run = await http.post("/agentenv/ext/computer-exec/run", json={"argv": ["true"], "request_id": "r"})
|
|
@@ -462,14 +468,14 @@ def test_a_driver_class_declares_what_it_serves_on_each_platform(monkeypatch):
|
|
|
462
468
|
raise AssertionError("declaration builds the card without the subclass's __init__")
|
|
463
469
|
|
|
464
470
|
linux = Declared.declaration(LINUX)
|
|
465
|
-
elsewhere = MinimalDriver.declaration(Platform(os="
|
|
471
|
+
elsewhere = MinimalDriver.declaration(Platform(os="freebsd"))
|
|
466
472
|
uris = lambda card: {e.uri for e in card.capabilities.extensions} # noqa: E731
|
|
467
473
|
assert linux.name == "declared" and len(linux.capabilities.tools) == 14
|
|
468
474
|
assert {"urn:agentenv:computer-pointer/v1", "urn:agentenv:computer-exec/v1"} <= uris(linux)
|
|
469
475
|
assert elsewhere.name == "MinimalDriver" and len(elsewhere.capabilities.tools) == 7
|
|
470
476
|
assert "urn:agentenv:computer-exec/v1" not in uris(elsewhere)
|
|
471
477
|
computer = next(e for e in elsewhere.capabilities.extensions if e.uri == "urn:agentenv:computer/v1")
|
|
472
|
-
assert computer.params["platform"] == {"os": "
|
|
478
|
+
assert computer.params["platform"] == {"os": "freebsd"}
|
|
473
479
|
|
|
474
480
|
|
|
475
481
|
def test_a_supports_entry_names_each_platform_it_covers():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/THIRD_PARTY_NOTICES.md
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/examples/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/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.474 → agentenv_framework_protocol-0.1.476}/tests/computer_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/probe_fake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/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.474 → agentenv_framework_protocol-0.1.476}/tests/test_a2a_proxy.py
RENAMED
|
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.474 → agentenv_framework_protocol-0.1.476}/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
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_intake.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/tests/test_manifest.py
RENAMED
|
File without changes
|
{agentenv_framework_protocol-0.1.474 → agentenv_framework_protocol-0.1.476}/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
|