agentenv-framework-protocol 0.1.377__tar.gz → 0.1.379__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.377 → agentenv_framework_protocol-0.1.379}/PKG-INFO +39 -3
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/README.md +38 -2
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/pyproject.toml +1 -1
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/_declare.py +98 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/__init__.py +22 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/__main__.py +42 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/checks.py +726 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/client.py +82 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/fixture.py +208 -0
- agentenv_framework_protocol-0.1.379/src/agentenv_protocol/computer/conformance/report.py +43 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/driver.py +13 -2
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/platform.py +16 -0
- agentenv_framework_protocol-0.1.379/tests/probe_fake.py +210 -0
- agentenv_framework_protocol-0.1.379/tests/test_computer_conformance.py +257 -0
- agentenv_framework_protocol-0.1.379/tests/test_computer_conformance_checks.py +283 -0
- agentenv_framework_protocol-0.1.379/tests/test_computer_declare.py +116 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_driver.py +30 -1
- agentenv_framework_protocol-0.1.377/examples/computer_x11/Dockerfile +0 -19
- agentenv_framework_protocol-0.1.377/examples/computer_x11/README.md +0 -60
- agentenv_framework_protocol-0.1.377/examples/computer_x11/driver.py +0 -374
- agentenv_framework_protocol-0.1.377/examples/computer_x11/fixture.py +0 -173
- agentenv_framework_protocol-0.1.377/examples/computer_x11/start.sh +0 -9
- agentenv_framework_protocol-0.1.377/tests/test_computer_x11_example.py +0 -290
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/LICENSE +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/NOTICE +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/THIRD_PARTY_NOTICES.md +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/advanced_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/basic_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/custom_extensions_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/multimodal_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/reference_model.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/examples/streaming_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/client.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/card.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/checks.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/errors.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/extensions.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/frames.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/keys.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/linux.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/operations.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/queue.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/results.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/runtime.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/settings.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/spaces.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/computer/tools.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/errors.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/preflight.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/transfers.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/src/agentenv_protocol/types.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/computer_fake.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_agent.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_agent_examples.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_object_transfers.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_peer_agents.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_proxy.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_staging.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_a2a_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_agent_env_environment.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_client.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_dataplane.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_extensions.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_frames.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_queue.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_computer_spaces.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_data_objects.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_errors.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_extension_methods.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_intake.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_manifest.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_preflight.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_access.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_annotations.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_context_fastmcp.py +0 -0
- {agentenv_framework_protocol-0.1.377 → agentenv_framework_protocol-0.1.379}/tests/test_tool_context_injection.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentenv-framework-protocol
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.379
|
|
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
|
|
@@ -370,8 +370,8 @@ one as a `ComputerDriverEnvironment` subclass from `agentenv_protocol.computer`,
|
|
|
370
370
|
`computer` extra (`pip install 'agentenv-framework-protocol[computer]'`: mcp, uvicorn and Pillow).
|
|
371
371
|
The driver marks the methods that capture the screen and send input; the base class serves the
|
|
372
372
|
computer contract from them, so the tools, results and errors can't drift from it. A complete
|
|
373
|
-
driver for an X11 desktop
|
|
374
|
-
[`
|
|
373
|
+
driver for an X11 desktop is agent-env's reference driver, in its
|
|
374
|
+
[`drivers` bundle](https://github.com/scaleapi/agentenv-framework/tree/main/src/agent_env/drivers).
|
|
375
375
|
|
|
376
376
|
```python
|
|
377
377
|
from agentenv_protocol.computer import (
|
|
@@ -473,6 +473,42 @@ and `exec_timeout_s`. A driver reads them as `self.settings`, for example its ta
|
|
|
473
473
|
Every caller is `default` until agents carry an identity of their own; `caller_identity(context)`
|
|
474
474
|
names the caller whose latest frame and others' input a call uses.
|
|
475
475
|
|
|
476
|
+
`MyDriver.declaration(platform)` returns the card the class serves on a `Platform`, built without
|
|
477
|
+
running the driver, its operations or its dependencies.
|
|
478
|
+
|
|
479
|
+
### Checking a driver: the conformance probe
|
|
480
|
+
|
|
481
|
+
The probe checks a running driver against the contract through its card, tools and extensions. It
|
|
482
|
+
reports each check, and gives each extension the card declares a verdict: verified, unverified or
|
|
483
|
+
failed.
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
python -m agentenv_protocol.computer.conformance http://localhost:18765 [--level basic|full] [--json report.json]
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
from agentenv_protocol.computer.conformance import run_probe
|
|
491
|
+
|
|
492
|
+
report = await run_probe("http://localhost:18765", "full") # a ProbeReport
|
|
493
|
+
failed = [c for c in report.checks if c.status == "failed"]
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
The CLI exits 0 when no check failed, 1 when one did and 2 when it can't reach the driver.
|
|
497
|
+
|
|
498
|
+
| Level | Checks | Needs on the computer |
|
|
499
|
+
|---|---|---|
|
|
500
|
+
| `basic` | P0 ready and a screenshot; P1 the card and tool schemas; P2 native frames, regions and JPEG; P5 refusals and their codes; X the declared extensions (`computer-display`, `computer-spaces`, `computer-keyboard`, `computer-exec`, `data/get`, per-role tool access, the pointer) | nothing |
|
|
501
|
+
| `full` | `basic`, then P3 colours land where the mapping says; P4 clicks show their effect; P5 refusals change nothing; P6 typed and pressed keys arrive; P7 scrolls and drags arrive; P9 commands and `data/add` run as one unprivileged user; X pointer and keyboard input, `data/add` | Linux, `python3` with Tk, a 1280x800 screen or larger, `computer-exec` and `data/add` |
|
|
502
|
+
|
|
503
|
+
At `full` the probe writes the Fixture Desk, a Tk window (`conformance/fixture.py`), into
|
|
504
|
+
`~/.agentenv-probe` with `data/add` and starts it with `computer-exec`. It aims at the boxes the
|
|
505
|
+
window's widgets report, reads back what reached them, and then removes the fixture. When the
|
|
506
|
+
fixture can't be staged, the `full` checks are unverified rather than failed. The probe leaves out
|
|
507
|
+
the checks for an extension the card doesn't declare. P8 is not applicable to a driver without
|
|
508
|
+
leasing, and unverified for one with it until the probe has lease checks. The probe calls as the
|
|
509
|
+
default role; the tool-access check hides a tool from a role of its own, `agentenv-probe-<random>`,
|
|
510
|
+
and gives it back.
|
|
511
|
+
|
|
476
512
|
## A2A agent framework
|
|
477
513
|
|
|
478
514
|
The distribution exposes two unrelated decorators named `extension`:
|
|
@@ -319,8 +319,8 @@ one as a `ComputerDriverEnvironment` subclass from `agentenv_protocol.computer`,
|
|
|
319
319
|
`computer` extra (`pip install 'agentenv-framework-protocol[computer]'`: mcp, uvicorn and Pillow).
|
|
320
320
|
The driver marks the methods that capture the screen and send input; the base class serves the
|
|
321
321
|
computer contract from them, so the tools, results and errors can't drift from it. A complete
|
|
322
|
-
driver for an X11 desktop
|
|
323
|
-
[`
|
|
322
|
+
driver for an X11 desktop is agent-env's reference driver, in its
|
|
323
|
+
[`drivers` bundle](https://github.com/scaleapi/agentenv-framework/tree/main/src/agent_env/drivers).
|
|
324
324
|
|
|
325
325
|
```python
|
|
326
326
|
from agentenv_protocol.computer import (
|
|
@@ -422,6 +422,42 @@ and `exec_timeout_s`. A driver reads them as `self.settings`, for example its ta
|
|
|
422
422
|
Every caller is `default` until agents carry an identity of their own; `caller_identity(context)`
|
|
423
423
|
names the caller whose latest frame and others' input a call uses.
|
|
424
424
|
|
|
425
|
+
`MyDriver.declaration(platform)` returns the card the class serves on a `Platform`, built without
|
|
426
|
+
running the driver, its operations or its dependencies.
|
|
427
|
+
|
|
428
|
+
### Checking a driver: the conformance probe
|
|
429
|
+
|
|
430
|
+
The probe checks a running driver against the contract through its card, tools and extensions. It
|
|
431
|
+
reports each check, and gives each extension the card declares a verdict: verified, unverified or
|
|
432
|
+
failed.
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
python -m agentenv_protocol.computer.conformance http://localhost:18765 [--level basic|full] [--json report.json]
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from agentenv_protocol.computer.conformance import run_probe
|
|
440
|
+
|
|
441
|
+
report = await run_probe("http://localhost:18765", "full") # a ProbeReport
|
|
442
|
+
failed = [c for c in report.checks if c.status == "failed"]
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
The CLI exits 0 when no check failed, 1 when one did and 2 when it can't reach the driver.
|
|
446
|
+
|
|
447
|
+
| Level | Checks | Needs on the computer |
|
|
448
|
+
|---|---|---|
|
|
449
|
+
| `basic` | P0 ready and a screenshot; P1 the card and tool schemas; P2 native frames, regions and JPEG; P5 refusals and their codes; X the declared extensions (`computer-display`, `computer-spaces`, `computer-keyboard`, `computer-exec`, `data/get`, per-role tool access, the pointer) | nothing |
|
|
450
|
+
| `full` | `basic`, then P3 colours land where the mapping says; P4 clicks show their effect; P5 refusals change nothing; P6 typed and pressed keys arrive; P7 scrolls and drags arrive; P9 commands and `data/add` run as one unprivileged user; X pointer and keyboard input, `data/add` | Linux, `python3` with Tk, a 1280x800 screen or larger, `computer-exec` and `data/add` |
|
|
451
|
+
|
|
452
|
+
At `full` the probe writes the Fixture Desk, a Tk window (`conformance/fixture.py`), into
|
|
453
|
+
`~/.agentenv-probe` with `data/add` and starts it with `computer-exec`. It aims at the boxes the
|
|
454
|
+
window's widgets report, reads back what reached them, and then removes the fixture. When the
|
|
455
|
+
fixture can't be staged, the `full` checks are unverified rather than failed. The probe leaves out
|
|
456
|
+
the checks for an extension the card doesn't declare. P8 is not applicable to a driver without
|
|
457
|
+
leasing, and unverified for one with it until the probe has lease checks. The probe calls as the
|
|
458
|
+
default role; the tool-access check hides a tool from a role of its own, `agentenv-probe-<random>`,
|
|
459
|
+
and gives it back.
|
|
460
|
+
|
|
425
461
|
## A2A agent framework
|
|
426
462
|
|
|
427
463
|
The distribution exposes two unrelated decorators named `extension`:
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Read a computer driver class where its own dependencies may not be installed, as a ``computer_driver`` env's put
|
|
2
|
+
does: ``python -m agentenv_protocol.computer._declare <folder> <file> <class>`` imports the file with every module
|
|
3
|
+
not installed here standing in as an inert stub, and prints what the class declares for each platform it supports as
|
|
4
|
+
JSON. Nothing runs beyond defining the module and its classes, and a class that can't be defined even so exits 1
|
|
5
|
+
with why."""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import contextlib
|
|
9
|
+
import importlib.abc
|
|
10
|
+
import importlib.machinery
|
|
11
|
+
import importlib.util
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
import types
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from .card import COMPUTER
|
|
18
|
+
from .driver import ComputerDriverEnvironment
|
|
19
|
+
from .platform import supported
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _StubMeta(type):
|
|
23
|
+
def __getattr__(cls, name: str):
|
|
24
|
+
if name.startswith("__"):
|
|
25
|
+
raise AttributeError(name)
|
|
26
|
+
return cls
|
|
27
|
+
|
|
28
|
+
def __call__(cls, *args, **kwargs):
|
|
29
|
+
return cls
|
|
30
|
+
|
|
31
|
+
def __getitem__(cls, key):
|
|
32
|
+
return cls
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _Stub(metaclass=_StubMeta):
|
|
36
|
+
"""Whatever a stubbed module holds: itself again on any attribute, call or index, and a class to derive from."""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _StubModule(types.ModuleType):
|
|
40
|
+
__path__: list = []
|
|
41
|
+
|
|
42
|
+
def __getattr__(self, name: str):
|
|
43
|
+
if name.startswith("__"):
|
|
44
|
+
raise AttributeError(name)
|
|
45
|
+
return _Stub
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class _Stubs(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
49
|
+
"""Last on ``sys.meta_path``: a module no other finder finds imports as a stub."""
|
|
50
|
+
|
|
51
|
+
def find_spec(self, fullname, path, target=None):
|
|
52
|
+
return importlib.machinery.ModuleSpec(fullname, self, is_package=True)
|
|
53
|
+
|
|
54
|
+
def create_module(self, spec):
|
|
55
|
+
return _StubModule(spec.name)
|
|
56
|
+
|
|
57
|
+
def exec_module(self, module) -> None:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def declare(folder: Path, file: str, name: str) -> dict:
|
|
62
|
+
"""What the class ``name`` in ``folder/file`` declares: its card's name, its ``supports``, and for each platform
|
|
63
|
+
those name, the extensions it provides, its tools and the computer/v1 features. Raises ValueError for a class
|
|
64
|
+
that isn't a driver or declares no platform."""
|
|
65
|
+
sys.path.insert(0, str(folder))
|
|
66
|
+
sys.meta_path.append(_Stubs())
|
|
67
|
+
spec = importlib.util.spec_from_file_location("computer_driver_module", folder / file)
|
|
68
|
+
module = importlib.util.module_from_spec(spec)
|
|
69
|
+
spec.loader.exec_module(module)
|
|
70
|
+
cls = getattr(module, name, None)
|
|
71
|
+
if not (isinstance(cls, type) and issubclass(cls, ComputerDriverEnvironment)):
|
|
72
|
+
raise ValueError(f"{file} has no ComputerDriverEnvironment subclass named {name}")
|
|
73
|
+
platforms = [platform for entry in cls.supports for platform in supported(entry)]
|
|
74
|
+
if not platforms:
|
|
75
|
+
raise ValueError(f"{name} declares no platform: name them with @computer_driver(supports=[...])")
|
|
76
|
+
cards = [(platform, cls.declaration(platform)) for platform in platforms]
|
|
77
|
+
return {"name": cards[0][1].name, "supports": list(cls.supports), "platforms": [
|
|
78
|
+
{"platform": platform.as_dict(), "provides": [e.uri for e in card.capabilities.extensions],
|
|
79
|
+
"tools": [t.name for t in card.capabilities.tools],
|
|
80
|
+
"features": next(e.params for e in card.capabilities.extensions if e.uri == COMPUTER)}
|
|
81
|
+
for platform, card in cards]}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def main(argv: list[str]) -> int:
|
|
85
|
+
"""Print the declaration as the only output; what the module prints while it loads goes to stderr."""
|
|
86
|
+
folder, file, name = argv
|
|
87
|
+
try:
|
|
88
|
+
with contextlib.redirect_stdout(sys.stderr):
|
|
89
|
+
declared = declare(Path(folder), file, name)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"{type(e).__name__}: {e}", file=sys.stderr)
|
|
92
|
+
return 1
|
|
93
|
+
print(json.dumps(declared))
|
|
94
|
+
return 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""The conformance probe: checks a running computer driver against the contract through its card, tools and
|
|
2
|
+
extensions, and reports each check and each declared extension. ``basic`` needs nothing on the computer; ``full``
|
|
3
|
+
stages the Linux fixture with data/add and reads it back with computer-exec. Run it as
|
|
4
|
+
``python -m agentenv_protocol.computer.conformance <driver url> [--level basic|full] [--json report.json]``."""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from .checks import Probe
|
|
8
|
+
from .client import Driver
|
|
9
|
+
from .report import CheckResult, Level, ProbeReport, Status, Verdict
|
|
10
|
+
|
|
11
|
+
__all__ = ["run_probe", "ProbeReport", "CheckResult", "Level", "Status", "Verdict"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def run_probe(url: str, level: Level = "full", *, timeout_s: float = 60, ready_timeout_s: float = 60) -> ProbeReport:
|
|
15
|
+
"""Probe the driver serving its card at ``url``. ``ready_timeout_s`` is how long it may take to report ready."""
|
|
16
|
+
driver = await Driver.connect(url, timeout_s)
|
|
17
|
+
async with driver.session() as session:
|
|
18
|
+
probe = Probe(driver, session, ready_timeout_s)
|
|
19
|
+
await probe.basic()
|
|
20
|
+
if level == "full":
|
|
21
|
+
await probe.full()
|
|
22
|
+
return ProbeReport.of(level, driver.name, probe.results, driver.extensions)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""``python -m agentenv_protocol.computer.conformance <driver url>``: probe a running driver, print each check, and
|
|
2
|
+
exit 1 when one failed or 2 when the driver couldn't be reached."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from . import run_probe
|
|
11
|
+
|
|
12
|
+
_MARK = {"passed": "PASS", "failed": "FAIL", "unverified": "----", "not_applicable": "n/a "}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: list[str] | None = None) -> int:
|
|
16
|
+
parser = argparse.ArgumentParser(prog="python -m agentenv_protocol.computer.conformance",
|
|
17
|
+
description="Probe a running computer driver against the contract.")
|
|
18
|
+
parser.add_argument("url", help="where the driver serves its card, such as http://localhost:18765")
|
|
19
|
+
parser.add_argument("--level", choices=("basic", "full"), default="full")
|
|
20
|
+
parser.add_argument("--json", type=Path, help="also write the report to this file")
|
|
21
|
+
parser.add_argument("--timeout", type=float, default=60, help="seconds for each call, and to report ready")
|
|
22
|
+
args = parser.parse_args(argv)
|
|
23
|
+
try:
|
|
24
|
+
report = asyncio.run(run_probe(args.url, args.level, timeout_s=args.timeout, ready_timeout_s=args.timeout))
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(f"couldn't probe {args.url}: {type(e).__name__}: {e}", file=sys.stderr)
|
|
27
|
+
return 2
|
|
28
|
+
for result in report.checks:
|
|
29
|
+
detail = f": {result.detail}" if result.detail else ""
|
|
30
|
+
print(f"{_MARK[result.status]} {result.check} {result.name}{detail}")
|
|
31
|
+
counts = report.counts()
|
|
32
|
+
print(f"{report.driver}: {counts['passed']} passed, {counts['failed']} failed, {counts['unverified']} unverified, "
|
|
33
|
+
f"{counts['not_applicable']} not applicable at {report.level}")
|
|
34
|
+
for uri, verdict in report.extensions.items():
|
|
35
|
+
print(f" {verdict:10} {uri}")
|
|
36
|
+
if args.json:
|
|
37
|
+
args.json.write_text(report.model_dump_json(indent=1))
|
|
38
|
+
return 0 if report.passed else 1
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
sys.exit(main())
|