agentenv-framework-protocol 0.1.418__tar.gz → 0.1.420__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.
Files changed (113) hide show
  1. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/PKG-INFO +19 -5
  2. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/README.md +18 -4
  3. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/pyproject.toml +1 -1
  4. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/agent_env_environment.py +11 -2
  5. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/client.py +6 -0
  6. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/__init__.py +2 -1
  7. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/app.py +142 -25
  8. agentenv_framework_protocol-0.1.420/src/agentenv_protocol/computer/app_data.py +217 -0
  9. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/app_runtime.py +21 -2
  10. agentenv_framework_protocol-0.1.420/src/agentenv_protocol/computer/apps.py +125 -0
  11. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/checks.py +14 -2
  12. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/client.py +3 -2
  13. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/dataplane.py +30 -21
  14. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/driver.py +32 -5
  15. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/runtime.py +4 -0
  16. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/serve_app.py +4 -2
  17. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/session.py +33 -1
  18. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_client.py +8 -0
  19. agentenv_framework_protocol-0.1.420/tests/test_computer_app_data.py +280 -0
  20. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_app_server.py +56 -1
  21. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_conformance.py +23 -2
  22. agentenv_framework_protocol-0.1.418/src/agentenv_protocol/computer/apps.py +0 -63
  23. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/.gitignore +0 -0
  24. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/LICENSE +0 -0
  25. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/NOTICE +0 -0
  26. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/THIRD_PARTY_NOTICES.md +0 -0
  27. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/__init__.py +0 -0
  28. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/advanced_agent.py +0 -0
  29. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/basic_agent.py +0 -0
  30. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/custom_extensions_agent.py +0 -0
  31. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/multimodal_agent.py +0 -0
  32. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/reference_model.py +0 -0
  33. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/examples/streaming_agent.py +0 -0
  34. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/__init__.py +0 -0
  35. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
  36. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
  37. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
  38. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
  39. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/framework.py +0 -0
  40. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/peer_agents.py +0 -0
  41. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/proxy.py +0 -0
  42. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
  43. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
  44. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
  45. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
  46. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/_declare.py +0 -0
  47. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/_linux.py +0 -0
  48. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/_load.py +0 -0
  49. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/card.py +0 -0
  50. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/checks.py +0 -0
  51. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/__init__.py +0 -0
  52. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/__main__.py +0 -0
  53. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/fixture.py +0 -0
  54. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/mp4.py +0 -0
  55. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/conformance/report.py +0 -0
  56. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/errors.py +0 -0
  57. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/extensions.py +0 -0
  58. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/frames.py +0 -0
  59. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/keys.py +0 -0
  60. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/launch.py +0 -0
  61. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/manifest.py +0 -0
  62. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/operations.py +0 -0
  63. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/platform.py +0 -0
  64. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/queue.py +0 -0
  65. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/recording.py +0 -0
  66. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/results.py +0 -0
  67. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/run_install_step.py +0 -0
  68. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/serve.py +0 -0
  69. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/settings.py +0 -0
  70. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/skill.py +0 -0
  71. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/spaces.py +0 -0
  72. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/computer/tools.py +0 -0
  73. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/errors.py +0 -0
  74. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/manifest.py +0 -0
  75. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/preflight.py +0 -0
  76. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/tool_access.py +0 -0
  77. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/tool_client.py +0 -0
  78. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/tool_context.py +0 -0
  79. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/transfers.py +0 -0
  80. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/src/agentenv_protocol/types.py +0 -0
  81. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/computer_fake.py +0 -0
  82. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/probe_fake.py +0 -0
  83. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_agent.py +0 -0
  84. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_agent_examples.py +0 -0
  85. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_object_transfers.py +0 -0
  86. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_peer_agents.py +0 -0
  87. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_proxy.py +0 -0
  88. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_staging.py +0 -0
  89. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_a2a_trajectory_log.py +0 -0
  90. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_agent_env_environment.py +0 -0
  91. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_conformance_checks.py +0 -0
  92. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_conformance_recording.py +0 -0
  93. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_dataplane.py +0 -0
  94. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_declare.py +0 -0
  95. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_driver.py +0 -0
  96. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_extensions.py +0 -0
  97. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_frames.py +0 -0
  98. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_queue.py +0 -0
  99. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_recording.py +0 -0
  100. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_serve.py +0 -0
  101. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_computer_spaces.py +0 -0
  102. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_data_objects.py +0 -0
  103. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_errors.py +0 -0
  104. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_extension_methods.py +0 -0
  105. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_intake.py +0 -0
  106. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_manifest.py +0 -0
  107. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_preflight.py +0 -0
  108. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_tool_access.py +0 -0
  109. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_tool_annotations.py +0 -0
  110. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_tool_client.py +0 -0
  111. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_tool_context.py +0 -0
  112. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/tests/test_tool_context_fastmcp.py +0 -0
  113. {agentenv_framework_protocol-0.1.418 → agentenv_framework_protocol-0.1.420}/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.418
3
+ Version: 0.1.420
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
@@ -561,8 +561,8 @@ driver has them, through the `served_tools`, `served_extensions` and `served_ope
561
561
  or a `transfers.ReadObject` read grant under the marker's `read`, and writes them atomically.
562
562
  `data/get` returns the files under the `paths` it's given, relative to the home, or under the
563
563
  card's `default_data_paths` (`Desktop`, `Documents`, `Downloads`) when it's given none, inline or
564
- uploaded under a `write_namespace` grant. An environment whose `@get_data` hook takes no `paths`
565
- refuses them.
564
+ uploaded under a `write_namespace` grant, leaving out the paths its apps keep their data in. An
565
+ environment whose `@get_data` hook takes no `paths` refuses them.
566
566
  - **The card** (the name from `ENVIRONMENT_NAME`, then `@computer_driver`'s), and per-role tool
567
567
  access (`tool_access` is on).
568
568
 
@@ -730,8 +730,10 @@ class MailApp(ComputerAppEnvironment):
730
730
  naming one the app declares no install for is refused when the class is read. A step reads
731
731
  `self.build_settings`; a deploy's `self.settings` aren't known at build, and reading one raises
732
732
  `AttributeError` (`python -m agentenv_protocol.computer.run_install_step <file>:<Class> <method>`).
733
- - **Its skill** is a file of its folder (`skill = "skill.md"`) or an `@agent_skill` method, not both;
734
- its data hooks are the usual `@add_data`, `@get_data` and `@reset_data`.
733
+ - **Its skill** is a file of its folder (`skill = "skill.md"`) or an `@agent_skill` method, not both.
734
+ - **Its data** is under the `paths` its OS's decorator names, relative to the session user's home,
735
+ none inside another (`@linux(..., paths=["Mail", ".config/mail/accounts.json"])`), or what its own
736
+ `@add_data`, `@get_data` and `@reset_data` hooks serve instead (below).
735
737
  - **`Settings`** is typed; a computer hands each app the values a deploy gives it, as one JSON value
736
738
  in `APP_SETTINGS_ENV` (`AGENTENV_APP_SETTINGS`, the apps' values by name), and the base class reads
737
739
  its own, by `ENVIRONMENT_NAME`, as `self.settings`. A `SecretStr` field is a secret.
@@ -757,6 +759,18 @@ folder: the computer is ready once every app's server answers and each `boot` ap
757
759
  no launch, says it's ready; a `demand` app counts once something launches it. What the server does
758
760
  in the session (`agentenv_protocol.computer.session`) is Linux's.
759
761
 
762
+ The server serves the app's data plane and its skill. With `paths` alone, `data/add` writes the files
763
+ it's given under them and refuses any other path, or one a link leads out of them; `data/get`
764
+ returns the files there, a file tree; and `data/reset` puts them back as the server found them when
765
+ it first started on this boot, which is the app as installed. Hooks serve what they mark instead.
766
+ A hook's `data/add` parts come as they were sent, inline or as a read grant, and
767
+ `part_bytes(part)` returns a part's bytes either way. Either way the base class takes data calls and
768
+ launches one at a time, runs a load and a reset with the app stopped and relaunches it after,
769
+ follows a failed load with a reset, and fails a call that runs past `data_timeout_s` (300 s); a sync
770
+ hook runs in a thread, which the reset and relaunch after it wait for. The driver fronts its apps:
771
+ its card lists each one's card as a child environment, rooted at `/svc/<app>/`, where it forwards
772
+ requests to the app's server.
773
+
760
774
  `MailApp.declaration()` returns what the class declares, an `AppDeclaration`, which a `computer_app`
761
775
  env stores, and `python -m agentenv_protocol.computer._declare <folder> <file> <class>` prints it as
762
776
  JSON, or a driver's `DriverDeclaration`, without the class's own dependencies installed.
@@ -505,8 +505,8 @@ driver has them, through the `served_tools`, `served_extensions` and `served_ope
505
505
  or a `transfers.ReadObject` read grant under the marker's `read`, and writes them atomically.
506
506
  `data/get` returns the files under the `paths` it's given, relative to the home, or under the
507
507
  card's `default_data_paths` (`Desktop`, `Documents`, `Downloads`) when it's given none, inline or
508
- uploaded under a `write_namespace` grant. An environment whose `@get_data` hook takes no `paths`
509
- refuses them.
508
+ uploaded under a `write_namespace` grant, leaving out the paths its apps keep their data in. An
509
+ environment whose `@get_data` hook takes no `paths` refuses them.
510
510
  - **The card** (the name from `ENVIRONMENT_NAME`, then `@computer_driver`'s), and per-role tool
511
511
  access (`tool_access` is on).
512
512
 
@@ -674,8 +674,10 @@ class MailApp(ComputerAppEnvironment):
674
674
  naming one the app declares no install for is refused when the class is read. A step reads
675
675
  `self.build_settings`; a deploy's `self.settings` aren't known at build, and reading one raises
676
676
  `AttributeError` (`python -m agentenv_protocol.computer.run_install_step <file>:<Class> <method>`).
677
- - **Its skill** is a file of its folder (`skill = "skill.md"`) or an `@agent_skill` method, not both;
678
- its data hooks are the usual `@add_data`, `@get_data` and `@reset_data`.
677
+ - **Its skill** is a file of its folder (`skill = "skill.md"`) or an `@agent_skill` method, not both.
678
+ - **Its data** is under the `paths` its OS's decorator names, relative to the session user's home,
679
+ none inside another (`@linux(..., paths=["Mail", ".config/mail/accounts.json"])`), or what its own
680
+ `@add_data`, `@get_data` and `@reset_data` hooks serve instead (below).
679
681
  - **`Settings`** is typed; a computer hands each app the values a deploy gives it, as one JSON value
680
682
  in `APP_SETTINGS_ENV` (`AGENTENV_APP_SETTINGS`, the apps' values by name), and the base class reads
681
683
  its own, by `ENVIRONMENT_NAME`, as `self.settings`. A `SecretStr` field is a secret.
@@ -701,6 +703,18 @@ folder: the computer is ready once every app's server answers and each `boot` ap
701
703
  no launch, says it's ready; a `demand` app counts once something launches it. What the server does
702
704
  in the session (`agentenv_protocol.computer.session`) is Linux's.
703
705
 
706
+ The server serves the app's data plane and its skill. With `paths` alone, `data/add` writes the files
707
+ it's given under them and refuses any other path, or one a link leads out of them; `data/get`
708
+ returns the files there, a file tree; and `data/reset` puts them back as the server found them when
709
+ it first started on this boot, which is the app as installed. Hooks serve what they mark instead.
710
+ A hook's `data/add` parts come as they were sent, inline or as a read grant, and
711
+ `part_bytes(part)` returns a part's bytes either way. Either way the base class takes data calls and
712
+ launches one at a time, runs a load and a reset with the app stopped and relaunches it after,
713
+ follows a failed load with a reset, and fails a call that runs past `data_timeout_s` (300 s); a sync
714
+ hook runs in a thread, which the reset and relaunch after it wait for. The driver fronts its apps:
715
+ its card lists each one's card as a child environment, rooted at `/svc/<app>/`, where it forwards
716
+ requests to the app's server.
717
+
704
718
  `MailApp.declaration()` returns what the class declares, an `AppDeclaration`, which a `computer_app`
705
719
  env stores, and `python -m agentenv_protocol.computer._declare <folder> <file> <class>` prints it as
706
720
  JSON, or a driver's `DriverDeclaration`, without the class's own dependencies installed.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentenv-framework-protocol"
3
- version = "0.1.418"
3
+ version = "0.1.420"
4
4
  description = "Open data-plane protocol and server SDK for agent environments."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -14,7 +14,8 @@ import sys
14
14
  import types
15
15
  import uuid
16
16
  from abc import ABC, abstractmethod
17
- from typing import Annotated, Any, Callable, ClassVar, Literal, NamedTuple, Union, get_args, get_origin, get_type_hints
17
+ from typing import (Annotated, Any, Callable, ClassVar, Literal, NamedTuple, Optional, Union, get_args, get_origin,
18
+ get_type_hints)
18
19
 
19
20
  from pydantic import TypeAdapter, ValidationError
20
21
  from pydantic.fields import FieldInfo
@@ -376,7 +377,10 @@ class AgentEnvApplication(ABC):
376
377
  return self.environment_card
377
378
 
378
379
  async def _serve_card(self, request: Request) -> Response:
379
- return _json_response(self.environment_card.model_dump())
380
+ card = self.environment_card
381
+ if isinstance(self.handler, AgentEnvEnvironment) and (children := await self.handler.children_environments()):
382
+ card = card.model_copy(update={"children_environments": children})
383
+ return _json_response(card.model_dump())
380
384
 
381
385
  async def update_tool(self, name: str, *, description: str) -> None:
382
386
  """Change a served tool's description after the mount: on the card and in tools/list alike."""
@@ -662,6 +666,11 @@ class AgentEnvEnvironment:
662
666
  """Declaration-only extensions to advertise, like ``intake/v1``: a promise with params and no handler."""
663
667
  return []
664
668
 
669
+ async def children_environments(self) -> Optional[list[EnvironmentCard]]:
670
+ """The environments this one fronts, as each serves its card with its paths under this one's, listed on the card
671
+ each time it's served; None for none."""
672
+ return None
673
+
665
674
  def served_extensions(self, extensions: list[EnvironmentExtension]) -> list[EnvironmentExtension]:
666
675
  """The ``@extension`` handlers' extensions to serve, chosen at mount: one left out is not served, and of one served
667
676
  with ``op``, only the methods its returned descriptor still lists."""
@@ -147,6 +147,12 @@ def intake_declaration(card: dict) -> dict | None:
147
147
  return params if params else None
148
148
 
149
149
 
150
+ def operations(card: dict) -> list[str] | None:
151
+ """The data-plane methods a card declares it serves (``capabilities.operations``), or None when it declares none,
152
+ as an older card doesn't."""
153
+ return (card.get("capabilities") or {}).get("operations")
154
+
155
+
150
156
  def find_tool(card: dict, name: str) -> dict | None:
151
157
  """Return the MCP tool advertised under `name`, or None.
152
158
 
@@ -67,6 +67,7 @@ from .operations import (
67
67
  type_text,
68
68
  write_files,
69
69
  )
70
+ from .dataplane import part_bytes
70
71
  from .keys import PRINTABLE_KEYS
71
72
  from .manifest import ManifestSegment, RecordingManifest
72
73
  from .platform import Platform
@@ -107,7 +108,7 @@ __all__ = [
107
108
  "ComputerAppEnvironment", "computer_app", "install", "linux", "install_step", "ready_check", "Linux", "Service",
108
109
  "Launch", "Ready", "Packages", "AptSource", "Download", "RunScript",
109
110
  "AppDeclaration", "AppOs",
110
- "APP_SETTINGS_ENV",
111
+ "APP_SETTINGS_ENV", "part_bytes",
111
112
  "Display", "Image", "Effect", "ExecResult", "ReadyCheck", "Platform", "ComputerSettings", "SETTINGS_ENV",
112
113
  "PRINTABLE_KEYS",
113
114
  "display", "set_display", "capture", "click", "drag", "scroll", "type_text", "press",
@@ -1,24 +1,32 @@
1
1
  """ComputerAppEnvironment: software on a computer, an AgentEnvEnvironment whose class also declares what it is for a
2
2
  computer: the platforms it supports and the permissions it needs (``@computer_app``); for each OS, how it installs and
3
3
  launches there and what differs there (``@linux``, or ``@install`` for any OS type); its install steps and ready checks,
4
- each on every OS or on those it names; its skill, its typed ``Settings`` and its ``BuildSettings``. A ``computer_app``
5
- env's put reads that declaration from the class; its data hooks are the base class's. Its name is its env's
6
- ``environment_name``. On the computer the class runs as the app's own server (``serve_app``), which launches the app,
7
- adds its launcher and says whether it's ready (``computer-app/v1``), as declared for the OS it runs on."""
4
+ each on every OS or on those it names; its skill, its typed ``Settings`` and its ``BuildSettings``; and its data, the
5
+ ``paths`` it keeps it in under the session user's home or its own ``@add_data``, ``@get_data`` and ``@reset_data``
6
+ hooks. A ``computer_app`` env's put reads that declaration from the class. Its name is its env's ``environment_name``.
7
+ On the computer the class runs as the app's own server (``serve_app``), which launches the app, adds its launcher, says
8
+ whether it's ready (``computer-app/v1``), serves its skill, and serves its data plane, stopping the app around a load
9
+ and a reset, as declared for the OS it runs on."""
8
10
  from __future__ import annotations
9
11
 
10
12
  import functools
11
13
  import inspect
14
+ import itertools
12
15
  import json
13
16
  import os
14
17
  from dataclasses import dataclass
15
18
  from pathlib import Path, PurePosixPath
16
19
  from typing import Annotated, Any, Callable, ClassVar, Literal, Optional, Union
17
20
 
18
- from pydantic import AfterValidator, BaseModel, ConfigDict, Field, create_model, field_validator, model_validator
21
+ from pydantic import (AfterValidator, BaseModel, ConfigDict, Field, TypeAdapter, ValidationError, create_model,
22
+ field_validator, model_validator)
19
23
 
20
- from ..agent_env_environment import _EXT_ATTR, _OP_ATTR, AgentEnvEnvironment, extension
21
- from ..types import METHOD_ADD, METHOD_GET, METHOD_RESET, SKILL_EXTENSION_URI
24
+ from ..agent_env_environment import (_EXT_ATTR, _OP_ATTR, OP_ADD_DATA, OP_GET_DATA, OP_RESET_DATA, AgentEnvEnvironment,
25
+ add_data, agent_skill, extension, get_data, reset_data)
26
+ from ..transfers import RelativePath, WriteNamespaceGrant
27
+ from ..types import (METHOD_ADD, METHOD_GET, METHOD_RESET, SKILL_EXTENSION_URI, EnvironmentExtension, IntakeDeclaration,
28
+ IntakeFormat, intake_extension)
29
+ from .app_data import AppDataPlane
22
30
  from .app_runtime import AppRuntime
23
31
  from .errors import InvalidArgument
24
32
  from .platform import detect
@@ -27,7 +35,8 @@ from .platform import detect
27
35
  APP_SETTINGS_ENV = "AGENTENV_APP_SETTINGS"
28
36
  _INSTALL_STEP_ATTR = "_aee_install_step"
29
37
  _READY_CHECK_ATTR = "_aee_ready_check"
30
- _DATA_METHODS = {"reset_data": METHOD_RESET, "add_data": METHOD_ADD, "get_data": METHOD_GET}
38
+ _DATA_METHODS = {OP_RESET_DATA: METHOD_RESET, OP_ADD_DATA: METHOD_ADD, OP_GET_DATA: METHOD_GET}
39
+ _PATHS = TypeAdapter(list[RelativePath])
31
40
  #: What a launch's window can be matched by, as the session lists each window.
32
41
  WINDOW_KEYS = frozenset({"class", "instance", "title"})
33
42
  #: The framework extension an app's own server serves: its launch as params, and its ``launch`` and ``ready`` methods.
@@ -207,13 +216,15 @@ class AppReadyCheck(BaseModel):
207
216
 
208
217
  class AppOs(BaseModel):
209
218
  """What an app declares for one OS type: ``install``, how that OS installs it, as the OS type's install model gives
210
- it; its ``launch`` there; and its ``skill``, ``settings`` and ``build_settings`` there when they differ from the
211
- class's, the schemas with the class's fields added."""
219
+ it; its ``launch`` there; the ``paths`` it keeps its data in there, relative to the session user's home; and its
220
+ ``skill``, ``settings`` and ``build_settings`` there when they differ from the class's, the schemas with the class's
221
+ fields added."""
212
222
 
213
223
  model_config = ConfigDict(extra="forbid")
214
224
 
215
225
  install: dict[str, Any]
216
226
  launch: Optional[Launch] = None
227
+ paths: Optional[list[str]] = None
217
228
  skill: Optional[AppSkill] = None
218
229
  settings: Optional[dict[str, Any]] = None
219
230
  build_settings: Optional[dict[str, Any]] = None
@@ -258,6 +269,7 @@ class _OsDeclared:
258
269
 
259
270
  install: BaseModel
260
271
  launch: Optional[Launch]
272
+ paths: tuple[str, ...]
261
273
  skill: Optional[str]
262
274
  settings: Optional[type[BaseModel]]
263
275
  build_settings: Optional[type[BaseModel]]
@@ -274,17 +286,26 @@ def computer_app(*, supports: Optional[list] = None, permissions: Optional[list[
274
286
  return deco
275
287
 
276
288
 
277
- def install(os_type: str, spec: BaseModel, *, launch: Optional[Launch] = None, skill: Optional[str] = None,
278
- settings: Optional[type[BaseModel]] = None,
289
+ def install(os_type: str, spec: BaseModel, *, launch: Optional[Launch] = None, paths: Optional[list[str]] = None,
290
+ skill: Optional[str] = None, settings: Optional[type[BaseModel]] = None,
279
291
  build_settings: Optional[type[BaseModel]] = None) -> Callable:
280
292
  """Declare how a computer of ``os_type`` installs the app, ``spec`` being that OS type's install model, and what is
281
- the app's own there: its ``launch``; its ``skill``, a file of its folder, instead of the class's; and ``settings``
282
- and ``build_settings``, models whose fields add to the class's ``Settings`` and ``BuildSettings`` there. ``@linux``
283
- is this for Linux; an OS type a plugin adds is declared with it."""
293
+ the app's own there: its ``launch``; the ``paths`` it keeps its data in, relative to the session user's home, which
294
+ serve its data plane when it has no data hooks; its ``skill``, a file of its folder, instead of the class's; and
295
+ ``settings`` and ``build_settings``, models whose fields add to the class's ``Settings`` and ``BuildSettings`` there.
296
+ ``@linux`` is this for Linux; an OS type a plugin adds is declared with it."""
297
+ try:
298
+ owned = tuple(_PATHS.validate_python(list(paths or [])))
299
+ except ValidationError:
300
+ raise ValueError(f"paths are normalized paths relative to the session user's home, not {paths!r}") from None
301
+ if overlapping := [f"{a!r} and {b!r}" for a, b in itertools.combinations(owned, 2)
302
+ if PurePosixPath(a).is_relative_to(b) or PurePosixPath(b).is_relative_to(a)]:
303
+ raise ValueError(f"an app's paths each hold files of their own, but {'; '.join(overlapping)} overlap")
304
+
284
305
  def deco(cls: type) -> type:
285
306
  if not (isinstance(cls, type) and issubclass(cls, ComputerAppEnvironment)):
286
307
  raise TypeError("@install decorates a ComputerAppEnvironment subclass")
287
- cls._installs = {**cls._installs, os_type: _OsDeclared(spec, launch, skill, settings, build_settings)}
308
+ cls._installs = {**cls._installs, os_type: _OsDeclared(spec, launch, owned, skill, settings, build_settings)}
288
309
  return cls
289
310
  return deco
290
311
 
@@ -292,12 +313,13 @@ def install(os_type: str, spec: BaseModel, *, launch: Optional[Launch] = None, s
292
313
  def linux(*, files: str = ".", packages: Optional[Packages] = None, python: Optional[str] = None,
293
314
  sources: Optional[list[AptSource]] = None, downloads: Optional[list[Download]] = None,
294
315
  run: Optional[list[RunScript]] = None, services: Optional[list[Service]] = None,
295
- ports: Optional[list[int]] = None, launch: Optional[Launch] = None, skill: Optional[str] = None,
296
- settings: Optional[type[BaseModel]] = None, build_settings: Optional[type[BaseModel]] = None) -> Callable:
316
+ ports: Optional[list[int]] = None, launch: Optional[Launch] = None, paths: Optional[list[str]] = None,
317
+ skill: Optional[str] = None, settings: Optional[type[BaseModel]] = None,
318
+ build_settings: Optional[type[BaseModel]] = None) -> Callable:
297
319
  """``@install`` for Linux: how a Linux computer installs the app, ``Linux``'s fields, and what is its own there."""
298
320
  return install("linux", Linux(files=files, packages=packages, python=python, sources=sources, downloads=downloads,
299
321
  run=run, services=services or [], ports=ports),
300
- launch=launch, skill=skill, settings=settings, build_settings=build_settings)
322
+ launch=launch, paths=paths, skill=skill, settings=settings, build_settings=build_settings)
301
323
 
302
324
 
303
325
  def install_step(scope: Literal["system", "session"] = "system", *,
@@ -328,15 +350,41 @@ def _named(os_types: Union[str, list[str], None]) -> Optional[list[str]]:
328
350
  class ComputerAppEnvironment(AgentEnvEnvironment):
329
351
  """Subclass it, declare it with ``@computer_app`` and an OS decorator for each OS (``@linux``), and set ``skill`` as
330
352
  a class attribute; a deploy's settings arrive as ``self.settings``, those its env fixes at build as
331
- ``self.build_settings``, and its launch as ``self.launch``, each as declared for the OS it runs on."""
353
+ ``self.build_settings``, and its launch and paths as ``self.launch`` and ``self.paths``, each as declared for the OS
354
+ it runs on.
355
+
356
+ Its data plane is its ``@add_data``, ``@get_data`` and ``@reset_data`` hooks, or, with none, defaults on its
357
+ ``paths``, which the base class serves around its contract (``app_data.AppDataPlane``): one call at a time, a load
358
+ and a reset with the app stopped and relaunched after, a load that fails followed by a reset, and each call within
359
+ ``data_timeout_s``."""
332
360
 
333
361
  supports: ClassVar[list] = []
334
362
  permissions: ClassVar[list[str]] = []
335
363
  _installs: ClassVar[dict[str, _OsDeclared]] = {}
364
+ #: Its data hooks' method names, by the operation each serves.
365
+ _data_hooks: ClassVar[dict[str, str]] = {}
336
366
  _computer_app: Optional[AppRuntime] = None
367
+ _computer_app_data: Optional[AppDataPlane] = None
337
368
  launch: Optional[Launch] = None
369
+ paths: list[str] = []
338
370
  #: A file of the app's folder holding its skill for agents, when no ``@agent_skill`` method writes it.
339
371
  skill: ClassVar[Optional[str]] = None
372
+ #: How long one of its data calls may take, a hook or its paths' default, before it fails.
373
+ data_timeout_s: ClassVar[float] = 300.0
374
+
375
+ def __init_subclass__(cls, **kwargs: Any) -> None:
376
+ """Take the class's data hooks over, for the base class's handlers to serve around its contract; and serve its
377
+ skill file unless it writes its skill itself."""
378
+ super().__init_subclass__(**kwargs)
379
+ hooks = dict(cls._data_hooks)
380
+ for name, member in vars(cls).items():
381
+ if (op := getattr(member, _OP_ATTR, None)) in _DATA_METHODS:
382
+ hooks[op] = name
383
+ delattr(member, _OP_ATTR)
384
+ cls._data_hooks = hooks
385
+ if any(getattr(getattr(member, _EXT_ATTR, None), "uri", None) == SKILL_EXTENSION_URI
386
+ for member in vars(cls).values()):
387
+ cls._computer_app_skill = None
340
388
 
341
389
  class Settings(BaseModel):
342
390
  """The app's settings: an app declares its own; a ``SecretStr`` field is a secret."""
@@ -350,12 +398,17 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
350
398
  values = json.loads(os.environ.get(APP_SETTINGS_ENV) or "{}").get(os.environ.get("ENVIRONMENT_NAME"), {})
351
399
  self.settings = cls.settings_on(on).model_validate(values)
352
400
  self.build_settings = _built_settings(cls, on)
353
- self.launch = declared.launch if (declared := cls._installs.get(on)) is not None else None
401
+ declared = cls._installs.get(on)
402
+ self.launch = declared.launch if declared is not None else None
403
+ self.paths = list(declared.paths) if declared is not None else []
354
404
  ready = self.launch.ready if self.launch is not None else None
355
405
  self._computer_app = AppRuntime(
356
406
  self.launch, {fn.__name__: getattr(self, fn.__name__) for fn in _methods(cls)
357
407
  if hasattr(fn, _READY_CHECK_ATTR) and _runs_on(getattr(fn, _READY_CHECK_ATTR), on)},
358
408
  ready.timeout_s if ready is not None else DEFAULT_TIMEOUT_S)
409
+ self._computer_app_data = AppDataPlane(
410
+ self._computer_app, {op: getattr(self, name) for op, name in cls._data_hooks.items()}, self.paths,
411
+ cls.data_timeout_s)
359
412
 
360
413
  @classmethod
361
414
  def settings_on(cls, os_type: Optional[str]) -> type[BaseModel]:
@@ -375,7 +428,7 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
375
428
  async def _computer_app_launch(self) -> dict:
376
429
  if self.launch is None:
377
430
  raise InvalidArgument(f"{type(self).__name__} declares no launch")
378
- return {"pid": await self._computer_app_runtime().launch_app()}
431
+ return {"pid": await self._computer_app_data_plane().launch()}
379
432
 
380
433
  @extension(COMPUTER_APP, op="ready", method="GET")
381
434
  async def _computer_app_ready(self) -> dict:
@@ -386,11 +439,61 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
386
439
  raise TypeError(f"{type(self).__qualname__}.__init__ must call super().__init__()")
387
440
  return self._computer_app
388
441
 
442
+ def _computer_app_data_plane(self) -> AppDataPlane:
443
+ self._computer_app_runtime()
444
+ return self._computer_app_data
445
+
389
446
  def extension_params(self, uri: str) -> dict:
390
447
  if uri == COMPUTER_APP:
391
- return {"launch": self.launch.model_dump(mode="json", exclude_none=True) if self.launch else None}
448
+ return {"launch": self.launch.model_dump(mode="json", exclude_none=True) if self.launch else None,
449
+ "paths": self.paths}
392
450
  return super().extension_params(uri)
393
451
 
452
+ def served_operations(self, operations: list[str]) -> list[str]:
453
+ """Its hooks' operations, or with none, all three when it has paths."""
454
+ served = ({_DATA_METHODS[op] for op in self._data_hooks} if self._data_hooks
455
+ else set(_DATA_METHODS.values()) if self.paths else set())
456
+ return [op for op in operations if op in served]
457
+
458
+ def served_extensions(self, extensions: list[EnvironmentExtension]) -> list[EnvironmentExtension]:
459
+ """Without its skill file on this OS, no skill, unless it writes one itself."""
460
+ own_skill = getattr(type(self), "_computer_app_skill", None) is not None
461
+ if own_skill and self._computer_app_skill_file() is None:
462
+ extensions = [extension for extension in extensions if extension.uri != SKILL_EXTENSION_URI]
463
+ return super().served_extensions(extensions)
464
+
465
+ def declared_extensions(self) -> list[EnvironmentExtension]:
466
+ """With its paths serving its data, a file tree: ``data/get`` returns a part per file."""
467
+ declared = super().declared_extensions()
468
+ if self.paths and not self._data_hooks:
469
+ tree = IntakeDeclaration(get=[IntakeFormat(part="file", format="file-tree")],
470
+ add=[IntakeFormat(part="file", format="file-tree", load="additive")])
471
+ declared.append(intake_extension(tree, f"data/add writes files under the app's paths, "
472
+ f"{', '.join(self.paths)}; data/get returns them; data/reset puts "
473
+ "them back as installed."))
474
+ return declared
475
+
476
+ @add_data
477
+ async def _computer_app_add_data(self, parts: list) -> None:
478
+ await self._computer_app_data_plane().call(OP_ADD_DATA, parts)
479
+
480
+ @get_data
481
+ async def _computer_app_get_data(self, write_namespace: Optional[WriteNamespaceGrant] = None) -> list:
482
+ return await self._computer_app_data_plane().call(OP_GET_DATA, write_namespace)
483
+
484
+ @reset_data
485
+ async def _computer_app_reset_data(self) -> None:
486
+ await self._computer_app_data_plane().call(OP_RESET_DATA)
487
+
488
+ @agent_skill
489
+ def _computer_app_skill(self) -> tuple[str, str]:
490
+ return _skill_parts(Path(self._computer_app_skill_file()).read_text(), os.environ.get("ENVIRONMENT_NAME", ""))
491
+
492
+ def _computer_app_skill_file(self) -> Optional[str]:
493
+ """The file of the app's folder holding its skill on this OS, or the class's."""
494
+ declared = type(self)._installs.get(detect().os)
495
+ return declared.skill if declared is not None and declared.skill is not None else type(self).skill
496
+
394
497
  @classmethod
395
498
  def declaration(cls) -> AppDeclaration:
396
499
  """What the class declares. Raises ValueError for a skill declared twice, a build setting that's a secret, or
@@ -404,7 +507,8 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
404
507
  "it in Settings")
405
508
  methods = _methods(cls)
406
509
  skill_methods = [fn.__name__ for fn in methods
407
- if getattr(getattr(fn, _EXT_ATTR, None), "uri", None) == SKILL_EXTENSION_URI]
510
+ if getattr(getattr(fn, _EXT_ATTR, None), "uri", None) == SKILL_EXTENSION_URI
511
+ and not fn.__name__.startswith("_computer_app_")]
408
512
  if cls.skill is not None and skill_methods:
409
513
  raise ValueError(f"{cls.__name__} declares its skill twice: skill = {cls.skill!r} and @agent_skill "
410
514
  f"{skill_methods[0]}")
@@ -425,6 +529,7 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
425
529
  supports=cls.supports, permissions=cls.permissions,
426
530
  os={os_type: AppOs(
427
531
  install=declared.install.model_dump(mode="json", exclude_none=True), launch=declared.launch,
532
+ paths=list(declared.paths) or None,
428
533
  skill=AppSkill(file=declared.skill) if declared.skill is not None else None,
429
534
  settings=cls.settings_on(os_type).model_json_schema() if declared.settings is not None else None,
430
535
  build_settings=(cls.build_settings_on(os_type).model_json_schema()
@@ -433,11 +538,23 @@ class ComputerAppEnvironment(AgentEnvEnvironment):
433
538
  settings=cls.Settings.model_json_schema(), build_settings=build if build.get("properties") else None,
434
539
  skill=AppSkill(file=cls.skill) if cls.skill is not None else
435
540
  AppSkill(method=skill_methods[0]) if skill_methods else None,
436
- data=sorted({_DATA_METHODS[op] for fn in methods if (op := getattr(fn, _OP_ATTR, None)) in _DATA_METHODS}),
541
+ data=sorted(_DATA_METHODS[op] for op in cls._data_hooks),
437
542
  install_steps=steps, ready_checks=checks,
438
543
  )
439
544
 
440
545
 
546
+ def _skill_parts(text: str, name: str) -> tuple[str, str]:
547
+ """A skill file's description and body: from its frontmatter's ``description`` when it has one."""
548
+ if text.startswith("---\n") and (end := text.find("\n---", 4)) != -1:
549
+ front, body = text[4:end], text[end + 4:].lstrip("\n")
550
+ description = next((line.partition(":")[2].strip().strip("'\"") for line in front.splitlines()
551
+ if line.startswith("description:")), "")
552
+ if description:
553
+ return description, body
554
+ text = body
555
+ return f"How to use {name} on this computer.", text
556
+
557
+
441
558
  def _secret_at(schema: dict, path: str = "") -> Optional[str]:
442
559
  """Where in ``schema``, a JSON schema, a secret is, a ``SecretStr``'s ``writeOnly``: in it or any of its subschemas,
443
560
  a field's, a list's items or a nested model's definition; None when it holds none. A default or a field's name