vis-agent 0.3.4.dev8082__tar.gz → 0.3.4.dev8095__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 (157) hide show
  1. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/PKG-INFO +1 -1
  2. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/gateway.json +0 -20
  3. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/view.json +3 -4
  4. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/pyproject.toml +1 -1
  5. vis_agent-0.3.4.dev8095/release-tag +1 -0
  6. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_client.py +2 -50
  7. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_local.py +20 -1
  8. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/extension.py +105 -54
  9. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_client.py +5 -42
  10. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_contracts.py +4 -4
  11. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_engine.py +2 -2
  12. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_live_primitives.py +52 -41
  13. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_live_wait.py +4 -4
  14. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_local.py +34 -0
  15. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_outside.py +35 -35
  16. vis_agent-0.3.4.dev8082/release-tag +0 -1
  17. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/.gitignore +0 -0
  18. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/LICENSE +0 -0
  19. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/README.md +0 -0
  20. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-arguments.json +0 -0
  21. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-cases.json +0 -0
  22. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-copy.json +0 -0
  23. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-execution.json +0 -0
  24. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-groups.json +0 -0
  25. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-read-session.json +0 -0
  26. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-reads.json +0 -0
  27. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-results.json +0 -0
  28. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-stream.json +0 -0
  29. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity-tables.json +0 -0
  30. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/activity.json +0 -0
  31. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/diff.json +0 -0
  32. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/live-primitives.json +0 -0
  33. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/session-health.json +0 -0
  34. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/fixtures/view.json +0 -0
  35. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/activity.json +0 -0
  36. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/agents.json +0 -0
  37. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/automations.json +0 -0
  38. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/common.json +0 -0
  39. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/config.json +0 -0
  40. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/content.json +0 -0
  41. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/council.json +0 -0
  42. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/diff.json +0 -0
  43. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/evals.json +0 -0
  44. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/provider.json +0 -0
  45. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/rooms.json +0 -0
  46. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/symbol.json +0 -0
  47. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/contracts/schema/toggle.json +0 -0
  48. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/examples/greeter/tests/test_greeter.py +0 -0
  49. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/hatch_build.py +0 -0
  50. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/__init__.py +0 -0
  51. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/_contracts.py +0 -0
  52. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/_outside.py +0 -0
  53. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/_wire.py +0 -0
  54. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/activity.py +0 -0
  55. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/__init__.py +0 -0
  56. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_agent.py +0 -0
  57. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_agents.py +0 -0
  58. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_council.py +0 -0
  59. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_extensions.py +0 -0
  60. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_host.py +0 -0
  61. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_install.py +0 -0
  62. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_models.py +0 -0
  63. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/engine/_speech.py +0 -0
  64. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/__init__.py +0 -0
  65. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/_gateway.py +0 -0
  66. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/agent.py +0 -0
  67. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/bench.py +0 -0
  68. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/check.py +0 -0
  69. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/compare.py +0 -0
  70. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/environment.py +0 -0
  71. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/grade.py +0 -0
  72. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/harbor.py +0 -0
  73. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/judge-rubric.toml +0 -0
  74. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/judge.py +0 -0
  75. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/labels.py +0 -0
  76. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/leaderboard.py +0 -0
  77. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/lic.py +0 -0
  78. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/longmemeval.py +0 -0
  79. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/mrcr.py +0 -0
  80. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/repeats.py +0 -0
  81. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/report.py +0 -0
  82. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/reports.py +0 -0
  83. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/rounds.py +0 -0
  84. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/stages.py +0 -0
  85. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/stats.py +0 -0
  86. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/evals/trajectory.py +0 -0
  87. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/extension_package.py +0 -0
  88. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/py.typed +0 -0
  89. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/rooms.py +0 -0
  90. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/src/blockether/vis/views.py +0 -0
  91. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/conftest.py +0 -0
  92. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/evals_atif.py +0 -0
  93. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_activity.py +0 -0
  94. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_agent.py +0 -0
  95. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_agent_extension_lifecycle.py +0 -0
  96. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_agent_extensions.py +0 -0
  97. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_agents.py +0 -0
  98. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_api_guides.py +0 -0
  99. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_attachments.py +0 -0
  100. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_authoring.py +0 -0
  101. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_catalog.py +0 -0
  102. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_catalog_recipe.py +0 -0
  103. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_ci_report_recipe.py +0 -0
  104. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_client_extensions_engine.py +0 -0
  105. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_code_quality_recipe.py +0 -0
  106. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_council.py +0 -0
  107. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_declarations.py +0 -0
  108. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_engine_docstrings.py +0 -0
  109. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_agent.py +0 -0
  110. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_bench.py +0 -0
  111. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_check.py +0 -0
  112. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_compare.py +0 -0
  113. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_environment.py +0 -0
  114. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_gateway.py +0 -0
  115. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_grade.py +0 -0
  116. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_guards.py +0 -0
  117. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_harbor.py +0 -0
  118. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_judge.py +0 -0
  119. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_labels.py +0 -0
  120. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_lic.py +0 -0
  121. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_longmemeval.py +0 -0
  122. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_mrcr.py +0 -0
  123. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_repeats.py +0 -0
  124. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_report.py +0 -0
  125. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_rounds.py +0 -0
  126. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_stages.py +0 -0
  127. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_stats.py +0 -0
  128. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_tasks.py +0 -0
  129. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_evals_trajectory.py +0 -0
  130. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_extension_package.py +0 -0
  131. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_extension_reference.py +0 -0
  132. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_gateway_performance.py +0 -0
  133. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_goals.py +0 -0
  134. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_install.py +0 -0
  135. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_method_typing.py +0 -0
  136. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_models.py +0 -0
  137. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_monitor_recipe.py +0 -0
  138. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_namespace.py +0 -0
  139. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_providers.py +0 -0
  140. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_read_session.py +0 -0
  141. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_record_arguments.py +0 -0
  142. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_registration.py +0 -0
  143. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_repair_hooks.py +0 -0
  144. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_result_sequence.py +0 -0
  145. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_rooms.py +0 -0
  146. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_scoped_settings.py +0 -0
  147. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_sdk_bootstrap.py +0 -0
  148. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_sdk_guide.py +0 -0
  149. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_sdk_typing.py +0 -0
  150. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_shortcuts_live.py +0 -0
  151. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_speech.py +0 -0
  152. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_structured_live.py +0 -0
  153. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_symbol_contract.py +0 -0
  154. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_testing.py +0 -0
  155. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_text_list_arguments.py +0 -0
  156. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_tools.py +0 -0
  157. {vis_agent-0.3.4.dev8082 → vis_agent-0.3.4.dev8095}/tests/test_views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vis-agent
3
- Version: 0.3.4.dev8082
3
+ Version: 0.3.4.dev8095
4
4
  Summary: The Vis Python SDK — author extensions and control local or remote engines.
5
5
  Project-URL: Homepage, https://vis.blockether.com
6
6
  Project-URL: Documentation, https://vis.blockether.com
@@ -1300,26 +1300,6 @@
1300
1300
  },
1301
1301
  "path": "/v1/sessions/:sid/views/live/:view-id/log"
1302
1302
  },
1303
- {
1304
- "audience": "sdk",
1305
- "operations": {
1306
- "get": {
1307
- "request": "none",
1308
- "response": "json"
1309
- }
1310
- },
1311
- "path": "/v1/views/live"
1312
- },
1313
- {
1314
- "audience": "sdk",
1315
- "operations": {
1316
- "post": {
1317
- "request": "json",
1318
- "response": "json"
1319
- }
1320
- },
1321
- "path": "/v1/views/:view-id/actions"
1322
- },
1323
1303
  {
1324
1304
  "audience": "sdk",
1325
1305
  "operations": {
@@ -1666,8 +1666,7 @@
1666
1666
  "type": "string",
1667
1667
  "enum": [
1668
1668
  "inline",
1669
- "panel",
1670
- "header"
1669
+ "panel"
1671
1670
  ],
1672
1671
  "default": "inline"
1673
1672
  },
@@ -1702,12 +1701,12 @@
1702
1701
  "$ref": "common.json#/$defs/non_blank_string"
1703
1702
  },
1704
1703
  "extension": {
1705
- "description": "The extension that owns this panel or header view.",
1704
+ "description": "The extension that owns this panel view.",
1706
1705
  "$ref": "common.json#/$defs/non_blank_string",
1707
1706
  "readOnly": true
1708
1707
  },
1709
1708
  "is_stale": {
1710
- "description": "True for the saved picture of an owned view after a gateway restart, until its extension opens the same key again.",
1709
+ "description": "True for the saved picture of an owned view after a gateway restart, until its extension loads again.",
1711
1710
  "type": "boolean",
1712
1711
  "readOnly": true
1713
1712
  },
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
8
8
 
9
9
  [project]
10
10
  name = "vis-agent"
11
- version = "0.3.4.dev8082"
11
+ version = "0.3.4.dev8095"
12
12
  description = "The Vis Python SDK — author extensions and control local or remote engines."
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.12"
@@ -0,0 +1 @@
1
+ beta-c428acf40f21470926388d77ec4b78cb8e5ffd2d
@@ -418,26 +418,6 @@ class ExecutionLayer(ABC):
418
418
  """
419
419
  return Session(self, sid)
420
420
 
421
- def header_views(self) -> list[LiveView]:
422
- """Read the header views of this machine as typed `LiveView` records.
423
-
424
- A header view belongs to no session. Its events come on the fleet stream.
425
- """
426
- data = _field(self.get_views_live(), "views", list)
427
- try:
428
- return [LiveView.from_wire(item) for item in data]
429
- except ValueError:
430
- raise ProtocolError("invalid live View response") from None
431
-
432
- def header_view_action(self, view_id: str, action: str, **values):
433
- """Send an operator action to a header view and return the JSON response.
434
-
435
- `values` supplies the action-specific fields of the operator action schema.
436
- """
437
- body = {**values, "action": action}
438
- validate("view", "operator_action", body)
439
- return self.post_view_actions(view_id, body=body)
440
-
441
421
  def create_session(
442
422
  self,
443
423
  *,
@@ -3002,34 +2982,6 @@ class ExecutionLayer(ABC):
3002
2982
  )
3003
2983
  return response.json()
3004
2984
 
3005
- def get_views_live(
3006
- self, *, query: Query | None = None, timeout: float | None = None
3007
- ) -> JSONValue:
3008
- """GET /v1/views/live — json response."""
3009
- response = self._request(
3010
- "GET", "/v1/views/live", path={}, query=query, timeout=timeout
3011
- )
3012
- return response.json()
3013
-
3014
- def post_view_actions(
3015
- self,
3016
- view_id: str,
3017
- *,
3018
- query: Query | None = None,
3019
- timeout: float | None = None,
3020
- body: JSONValue = None,
3021
- ) -> JSONValue:
3022
- """POST /v1/views/:view-id/actions — json response."""
3023
- response = self._request(
3024
- "POST",
3025
- "/v1/views/:view-id/actions",
3026
- path={"view-id": view_id},
3027
- query=query,
3028
- timeout=timeout,
3029
- body=body,
3030
- )
3031
- return response.json()
3032
-
3033
2985
  def post_voice(
3034
2986
  self,
3035
2987
  *,
@@ -3658,8 +3610,8 @@ class Session:
3658
3610
  """Read current live views as typed `blockether.vis.views.LiveView` records.
3659
3611
 
3660
3612
  This fetches a snapshot and does not subscribe to future updates. Use
3661
- `events` to follow view events. A `placement` (`inline`, `panel` or
3662
- `header`) keeps only those views. Malformed view data raises
3613
+ `events` to follow view events. A `placement` (`inline` or `panel`)
3614
+ keeps only those views. Malformed view data raises
3663
3615
  `ProtocolError`.
3664
3616
  """
3665
3617
  query = None if placement is None else {"placement": str(placement)}
@@ -4,7 +4,8 @@ Pass an executable, or keep the default `vis-agent`. The default runs the engine
4
4
  this SDK's release (see `ensure_installed`). There is no gateway discovery or
5
5
  user-server shutdown. Each engine gets a temporary database and stderr log, and
6
6
  closing discards them.
7
- Supports Linux and macOS. Instances use one calling thread, like GatewayClient.
7
+ Supports Linux and macOS. Threads can share an instance: its requests take turns on
8
+ the one stdio pipe.
8
9
  """
9
10
 
10
11
  from __future__ import annotations
@@ -17,6 +18,7 @@ import select
17
18
  import signal
18
19
  import subprocess
19
20
  import tempfile
21
+ import threading
20
22
  import time
21
23
  from email.message import Message
22
24
  from pathlib import Path
@@ -150,6 +152,8 @@ class LocalEngine(ExecutionLayer):
150
152
  self._exit_status = None
151
153
  self._stderr_tail = ""
152
154
  self._cleanup_complete = False
155
+ # The stdio frames carry no request ids, so only one exchange can be in flight.
156
+ self._exchange = threading.RLock()
153
157
 
154
158
  def session_options(self, project=".") -> dict:
155
159
  """Resolve an existing local directory before the caller changes directory."""
@@ -197,6 +201,10 @@ class LocalEngine(ExecutionLayer):
197
201
  failure or close, create a new one. A startup failure cleans up the process and
198
202
  temporary database before the error propagates.
199
203
  """
204
+ with self._exchange:
205
+ return self._connect()
206
+
207
+ def _connect(self):
200
208
  if self._closed:
201
209
  raise TransportError("client is closed")
202
210
  if self._process is not None:
@@ -262,6 +270,17 @@ class LocalEngine(ExecutionLayer):
262
270
  data = (json.dumps(request, allow_nan=False) + "\n").encode()
263
271
  if len(data) > 67108864:
264
272
  raise ValueError("local request exceeds 64 MiB")
273
+ if not self._exchange.acquire(timeout=max(0.0, deadline - time.monotonic())):
274
+ raise VisTimeout("local engine request timed out")
275
+ try:
276
+ return self._exchange_frame(data, deadline)
277
+ finally:
278
+ self._exchange.release()
279
+
280
+ def _exchange_frame(self, data, deadline):
281
+ """Write one request frame and read its reply. The caller holds `_exchange`."""
282
+ if self._process is None or self._process.stdin is None:
283
+ raise TransportError("client is closed")
265
284
  try:
266
285
  offset = 0
267
286
  while offset < len(data):
@@ -129,7 +129,7 @@ class Host(Protocol):
129
129
  def live(self, envelope_json: str, listener: Any = None) -> str:
130
130
  """Open, patch, read or close a live view.
131
131
 
132
- On `open`, `listener(event)` gets each human event of a panel or header view.
132
+ On `open`, `listener(event)` gets each human event of a panel view.
133
133
 
134
134
  `state` accepts timeout_ms (0..86400000) and after_seq (nonnegative).
135
135
  A positive timeout blocks until the sequence differs or the view closes.
@@ -3914,12 +3914,12 @@ def ask(title, nodes, **options):
3914
3914
  # documents.
3915
3915
  #
3916
3916
  # answer = vis.ask('Deploy', [
3917
- # vis.heading('Target'),
3918
- # vis.paragraph('Staging pages nobody.'),
3919
- # vis.row(vis.select('env', ['staging', 'prod'], label='Where',
3917
+ # vis.ui.heading('Target'),
3918
+ # vis.ui.paragraph('Staging pages nobody.'),
3919
+ # vis.ui.row(vis.ui.select('env', ['staging', 'prod'], label='Where',
3920
3920
  # is_required=True),
3921
- # vis.slider('canary', min=0, max=100, step=5)),
3922
- # vis.password('token', label='Deploy token', is_required=True),
3921
+ # vis.ui.slider('canary', min=0, max=100, step=5)),
3922
+ # vis.ui.password('token', label='Deploy token', is_required=True),
3923
3923
  # ])
3924
3924
  #
3925
3925
  # A builder is a plain dict, so a form stays printable and can be assembled in a
@@ -3934,56 +3934,56 @@ def _node(type_name, name, spec):
3934
3934
  return node
3935
3935
 
3936
3936
 
3937
- def plaintext(name, **spec):
3937
+ def _ui_plaintext(name, **spec):
3938
3938
  # One typed line, answered as a string.
3939
3939
  return _node("plaintext", name, spec)
3940
3940
 
3941
3941
 
3942
- def password(name, **spec):
3942
+ def _ui_password(name, **spec):
3943
3943
  # A masked line, answered as an opaque 'vis-secret:' handle: `reveal` it on
3944
3944
  # the trusted side, never log it.
3945
3945
  return _node("password", name, spec)
3946
3946
 
3947
3947
 
3948
- def multiline(name, **spec):
3948
+ def _ui_multiline(name, **spec):
3949
3949
  # A text box, answered as a string that keeps its newlines.
3950
3950
  return _node("multiline", name, spec)
3951
3951
 
3952
3952
 
3953
- def select(name, options, **spec):
3954
- # Choose exactly ONE of `options` (plain strings, or `vis.option(...)`
3953
+ def _ui_select(name, options, **spec):
3954
+ # Choose exactly ONE of `options` (plain strings, or `vis.ui.option(...)`
3955
3955
  # pairs); answered as the chosen value.
3956
3956
  spec["options"] = list(options)
3957
3957
  return _node("select", name, spec)
3958
3958
 
3959
3959
 
3960
- def multiselect(name, options, **spec):
3960
+ def _ui_multiselect(name, options, **spec):
3961
3961
  # Choose ANY of `options`; answered as a list, empty when nothing is ticked.
3962
3962
  spec["options"] = list(options)
3963
3963
  return _node("multiselect", name, spec)
3964
3964
 
3965
3965
 
3966
- def checkbox(name, **spec):
3966
+ def _ui_checkbox(name, **spec):
3967
3967
  # One box, answered as a bool. `is_required=True` means it must end up
3968
3968
  # TICKED, not merely present.
3969
3969
  return _node("checkbox", name, spec)
3970
3970
 
3971
3971
 
3972
- def slider(name, **spec):
3972
+ def _ui_slider(name, **spec):
3973
3973
  # A number on a track: min / max / step, 0 / 100 / 1 by default, answered as
3974
3974
  # a NUMBER. It is `range` on the wire; the builder is `slider` so it never
3975
3975
  # shadows the builtin.
3976
3976
  return _node("range", name, spec)
3977
3977
 
3978
3978
 
3979
- def otp(name, **spec):
3979
+ def _ui_otp(name, **spec):
3980
3980
  # A one-time code in digit boxes: min_length / max_length say how many
3981
3981
  # (6 by default, 12 at most), digits only, paste fills the boxes. A code is a
3982
3982
  # credential, so it answers with a `vis-secret:` handle like a password.
3983
3983
  return _node("otp", name, spec)
3984
3984
 
3985
3985
 
3986
- def option(value, label=None):
3986
+ def _ui_option(value, label=None):
3987
3987
  # One entry of a select / multiselect: the value that is ANSWERED and the
3988
3988
  # words shown for it. Given no label, the value shows itself.
3989
3989
  return {"value": value} if label is None else {"value": value, "label": label}
@@ -4016,20 +4016,20 @@ def _group(direction, fields):
4016
4016
  return group
4017
4017
 
4018
4018
 
4019
- def row(*fields):
4020
- # Lay these nodes out side by side: `vis.row(vis.text("host"), vis.text("port"))`
4021
- # on a form, `vis.row("reading", vis.table("hosts", ...), vis.status("why"))`
4019
+ def _ui_row(*fields):
4020
+ # Lay these nodes out side by side: `vis.ui.row(vis.text("host"), vis.text("port"))`
4021
+ # on a form, `vis.ui.row("reading", vis.ui.table("hosts", ...), vis.ui.status("why"))`
4022
4022
  # in a live view.
4023
4023
  return _group("row", fields)
4024
4024
 
4025
4025
 
4026
- def column(*fields):
4026
+ def _ui_column(*fields):
4027
4027
  # Stack these nodes, the default arrangement: worth saying out loud inside a
4028
4028
  # `row`.
4029
4029
  return _group("column", fields)
4030
4030
 
4031
4031
 
4032
- def grid(*fields, max_columns=None):
4032
+ def _ui_grid(*fields, max_columns=None):
4033
4033
  """Lay ``fields`` out in equal columns that wrap into aligned rows.
4034
4034
 
4035
4035
  ``max_columns`` (1 to 12) caps the columns. A narrow surface shows fewer
@@ -4041,7 +4041,7 @@ def grid(*fields, max_columns=None):
4041
4041
  return node
4042
4042
 
4043
4043
 
4044
- def wrap(*fields):
4044
+ def _ui_wrap(*fields):
4045
4045
  """Put ``fields`` side by side at their own width, wrapping onto new lines.
4046
4046
 
4047
4047
  Use it for buttons, stats, statuses and links that keep a natural width.
@@ -4049,7 +4049,7 @@ def wrap(*fields):
4049
4049
  return _group("wrap", fields)
4050
4050
 
4051
4051
 
4052
- def group(*children, direction="column", **spec):
4052
+ def _ui_group(*children, direction="column", **spec):
4053
4053
  """Group ``children`` with optional ``label``, ``description`` and folding.
4054
4054
 
4055
4055
  A leading string is the group id. A submit button inside a group collects
@@ -4060,7 +4060,7 @@ def group(*children, direction="column", **spec):
4060
4060
  return node
4061
4061
 
4062
4062
 
4063
- def card(node_id, title, **spec):
4063
+ def _ui_card(node_id, title, **spec):
4064
4064
  """A titled card with optional ``text``, ``tone`` and ``meta`` lines.
4065
4065
 
4066
4066
  With ``is_selectable=True`` the human can activate it like a button, and
@@ -4069,7 +4069,7 @@ def card(node_id, title, **spec):
4069
4069
  return _live_node("card", node_id, dict(spec, title=str(title)))
4070
4070
 
4071
4071
 
4072
- def heading(text, live_text=None, **spec):
4072
+ def _ui_heading(text, live_text=None, **spec):
4073
4073
  """Form heading, or live ``heading(id, text, level=1..6)``."""
4074
4074
  if live_text is not None:
4075
4075
  return _live_node(
@@ -4080,7 +4080,7 @@ def heading(text, live_text=None, **spec):
4080
4080
  return {"type": "heading", "text": str(text)}
4081
4081
 
4082
4082
 
4083
- def paragraph(text, live_text=None, **spec):
4083
+ def _ui_paragraph(text, live_text=None, **spec):
4084
4084
  """Form Markdown prose, or live ``paragraph(id, text)`` with inline Markdown."""
4085
4085
  if live_text is not None:
4086
4086
  return _live_node("paragraph", text, dict(spec, text=str(live_text)))
@@ -4280,9 +4280,9 @@ def list_sessions(search=None):
4280
4280
  # surface repaints, and the extension carries straight on. The human watches it
4281
4281
  # move and may stop it; the model reads the finished picture as DATA.
4282
4282
  #
4283
- # with vis.live('CI', [vis.status('now', 'Polling'),
4284
- # vis.table('jobs', columns=[vis.table_column('job', 'Job'),
4285
- # vis.table_column('state', 'State')])]) as view:
4283
+ # with vis.live('CI', [vis.ui.status('now', 'Polling'),
4284
+ # vis.ui.table('jobs', columns=[vis.ui.table_column('job', 'Job'),
4285
+ # vis.ui.table_column('state', 'State')])]) as view:
4286
4286
  # for job in poll():
4287
4287
  # view['jobs'].upsert(job.id, [job.name, job.state], tone=job.tone)
4288
4288
  # view['now'].set('Finished', tone='ok')
@@ -4692,7 +4692,7 @@ class LiveView:
4692
4692
  self._seq = 0
4693
4693
  self._cursor = 0
4694
4694
  self._listeners = []
4695
- # A panel or header view gets its events from the host, as callbacks.
4695
+ # A panel view gets its events from the host, as callbacks.
4696
4696
  self._is_pushed = False
4697
4697
  if on_event is not None:
4698
4698
  self.on_event(on_event)
@@ -4986,7 +4986,7 @@ class LiveView:
4986
4986
  def on_event(self, callback):
4987
4987
  """Call `callback(event)` for each event that `events` or `sleep` reads.
4988
4988
 
4989
- A panel or header view opened with `vis.live(..., on_event=...)` gets its
4989
+ A panel view opened with `vis.live(..., on_event=...)` gets its
4990
4990
  events from the host instead. Each one runs as an extension callback with
4991
4991
  the view session bound, also when no extension code waits on the view.
4992
4992
  Returns the callback, so you can use this method as a decorator.
@@ -5183,17 +5183,17 @@ def live(title, nodes, placement=None, key=None, on_event=None, **options):
5183
5183
  `vis.ask` documents. There is no cancellable flag: a human can always stop
5184
5184
  watching, and the verdict says they did (`is_from_human`) and why (`note`).
5185
5185
 
5186
- `placement` is `inline` (the default), `panel` (one session) or `header`
5187
- (this machine). Only extension code opens a panel or header view, and it
5188
- needs a `key`: the extension and the key own one view, so opening the same
5189
- key again replaces it. Such a view stays open after the call returns. It
5186
+ `placement` is `inline` (the default) or `panel` (the side panel of one
5187
+ session). Only extension code opens a panel view, and it needs a `key`:
5188
+ the extension and the key own one view, so opening the same key again
5189
+ replaces it. Such a view stays open after the call returns. It
5190
5190
  closes on `close()` or when the extension unloads. `on_event(event)` then
5191
5191
  runs for each human change, submit or activate, with the view session bound.
5192
5192
 
5193
5193
  The view is mounted at once and nothing blocks — use it as a context
5194
5194
  manager so it closes itself:
5195
5195
 
5196
- with vis.live('Deploy', [vis.steps('plan', steps=[...])]) as view:
5196
+ with vis.live('Deploy', [vis.ui.steps('plan', steps=[...])]) as view:
5197
5197
  view['plan'].set('build', tone='running')
5198
5198
 
5199
5199
  Closing answers the verdict: `is_completed`, `reason`, the finished picture
@@ -5504,7 +5504,7 @@ class _LiveRecorder:
5504
5504
  def live(self, envelope_json, listener=None):
5505
5505
  """Record and apply one envelope emitted by the extension.
5506
5506
 
5507
- A `listener` gets each simulated event of a panel or header view, as the
5507
+ A `listener` gets each simulated event of a panel view, as the
5508
5508
  host gives it to `on_event` callbacks.
5509
5509
  """
5510
5510
  import json
@@ -5801,8 +5801,8 @@ testing = _Testing()
5801
5801
  # here talks to the host, and `vis.live` is what carries it to the engine that
5802
5802
  # judges it.
5803
5803
  #
5804
- # Layout is the FORM's own vocabulary, not a second one: `vis.row("reading",
5805
- # table, status)` stands its nodes side by side and `vis.column(...)` stacks them,
5804
+ # Layout is the FORM's own vocabulary, not a second one: `vis.ui.row("reading",
5805
+ # table, status)` stands its nodes side by side and `vis.ui.column(...)` stacks them,
5806
5806
  # with a live group taking the id every op addresses. It is DECLARED once and no
5807
5807
  # op carries it, so a layout never rearranges itself while a human is reading it.
5808
5808
 
@@ -5814,7 +5814,7 @@ def _live_node(type_name, node_id, spec):
5814
5814
  return node
5815
5815
 
5816
5816
 
5817
- def disclosure(node_id, label, *nodes, default_expanded=False):
5817
+ def _ui_disclosure(node_id, label, *nodes, default_expanded=False):
5818
5818
  """A collapsible column.
5819
5819
 
5820
5820
  Local choices survive updates, and receipts start collapsed.
@@ -5832,17 +5832,17 @@ def disclosure(node_id, label, *nodes, default_expanded=False):
5832
5832
  )
5833
5833
 
5834
5834
 
5835
- def divider(node_id):
5835
+ def _ui_divider(node_id):
5836
5836
  """A static horizontal rule across its live container. Add or drop it by id."""
5837
5837
  return _live_node("divider", node_id, {})
5838
5838
 
5839
5839
 
5840
- def code(node_id, text, *, language=None, **spec):
5840
+ def _ui_code(node_id, text, *, language=None, **spec):
5841
5841
  """Literal code. Whitespace is kept, and content is never executed."""
5842
5842
  return _live_node("code", node_id, dict(spec, text=str(text), language=language))
5843
5843
 
5844
5844
 
5845
- def spinner(node_id, text="Working", *, variant="braille", is_active=True, **spec):
5845
+ def _ui_spinner(node_id, text="Working", *, variant="braille", is_active=True, **spec):
5846
5846
  """A braille, dots, line or pulse indicator. Receipts never animate."""
5847
5847
  return _live_node(
5848
5848
  "spinner",
@@ -5851,7 +5851,7 @@ def spinner(node_id, text="Working", *, variant="braille", is_active=True, **spe
5851
5851
  )
5852
5852
 
5853
5853
 
5854
- def button(node_id, label, *, is_disabled=False, **spec):
5854
+ def _ui_button(node_id, label, *, is_disabled=False, **spec):
5855
5855
  """An operator action. Accepted presses increment ``clicks`` in ``view.state()``.
5856
5856
 
5857
5857
  No callback or code crosses the wire. The producer decides how to respond.
@@ -5862,27 +5862,27 @@ def button(node_id, label, *, is_disabled=False, **spec):
5862
5862
  )
5863
5863
 
5864
5864
 
5865
- def status(node_id, text=None, **spec):
5865
+ def _ui_status(node_id, text=None, **spec):
5866
5866
  # One line saying what is happening right now: text, tone, detail, label.
5867
5867
  return _live_node("status", node_id, dict(spec, text=text))
5868
5868
 
5869
5869
 
5870
- def progress(node_id, **spec):
5870
+ def _ui_progress(node_id, **spec):
5871
5871
  # A bar: value (0..1), or done/total. Neither is indeterminate.
5872
5872
  return _live_node("progress", node_id, spec)
5873
5873
 
5874
5874
 
5875
- def stat(node_id, stats=None, **spec):
5875
+ def _ui_stat(node_id, stats=None, **spec):
5876
5876
  # A strip of counters, each `{'id': ..., 'label': ..., 'value_text': ...}`.
5877
5877
  return _live_node("stat", node_id, dict(spec, stats=stats))
5878
5878
 
5879
5879
 
5880
- def steps(node_id, steps=None, **spec):
5880
+ def _ui_steps(node_id, steps=None, **spec):
5881
5881
  # A checklist, each `{'id': ..., 'label': ..., 'tone': ...}`.
5882
5882
  return _live_node("steps", node_id, dict(spec, steps=steps))
5883
5883
 
5884
5884
 
5885
- def output(node_id, **spec):
5885
+ def _ui_output(node_id, **spec):
5886
5886
  """Durable output with an independent disclosure, collapsed by default.
5887
5887
 
5888
5888
  ``default_expanded=True`` opens an active log initially. Updates preserve the local
@@ -5896,7 +5896,7 @@ def output(node_id, **spec):
5896
5896
  return _live_node("log", node_id, spec)
5897
5897
 
5898
5898
 
5899
- def table(node_id, columns=None, **spec):
5899
+ def _ui_table(node_id, columns=None, **spec):
5900
5900
  # Rows keyed by id. `order` declares how they paint — 'insertion' (the
5901
5901
  # default), 'newest-first', or {'by': 'duration', 'dir': 'desc'}.
5902
5902
  # `is_selectable=True` makes rows controls; `selected_ids` is shared state.
@@ -5905,17 +5905,17 @@ def table(node_id, columns=None, **spec):
5905
5905
  return _live_node("table", node_id, dict(spec, columns=columns))
5906
5906
 
5907
5907
 
5908
- def table_column(column_id, label=None, **spec):
5908
+ def _ui_table_column(column_id, label=None, **spec):
5909
5909
  # One declared column: the id a cell sits under, its header, its align.
5910
5910
  return _live_item(column_id, dict(spec, label=label))
5911
5911
 
5912
5912
 
5913
- def table_row(row_id, cells, **spec):
5913
+ def _ui_table_row(row_id, cells, **spec):
5914
5914
  # One declared row: the id every later upsert addresses, and its cells.
5915
5915
  return _live_item(row_id, dict(spec, cells=[_cell(c) for c in cells]))
5916
5916
 
5917
5917
 
5918
- def table_group(group_id, label=None, **spec):
5918
+ def _ui_table_group(group_id, label=None, **spec):
5919
5919
  # One declared group of a table: the id a row's `parent` names, the `label`
5920
5920
  # painted over it instead of that id, and optionally `tone`, `order` and
5921
5921
  # `is_open`. Renaming the label never moves the group, because rows point at
@@ -5923,6 +5923,57 @@ def table_group(group_id, label=None, **spec):
5923
5923
  return _live_item(group_id, dict(spec, label=label))
5924
5924
 
5925
5925
 
5926
- def link(node_id, links=None, **spec):
5926
+ def _ui_link(node_id, links=None, **spec):
5927
5927
  # Pointers a human can open: url, path or attachment.
5928
5928
  return _live_node("link", node_id, dict(spec, links=links))
5929
+
5930
+
5931
+ class _UI:
5932
+ """Components for live views and forms.
5933
+
5934
+ `vis.live` and `vis.ask` take the same components, so one input or layout
5935
+ works in both. Each builder returns plain data and talks to no host.
5936
+ """
5937
+
5938
+ # Inputs
5939
+ plaintext = staticmethod(_ui_plaintext)
5940
+ password = staticmethod(_ui_password)
5941
+ multiline = staticmethod(_ui_multiline)
5942
+ select = staticmethod(_ui_select)
5943
+ multiselect = staticmethod(_ui_multiselect)
5944
+ checkbox = staticmethod(_ui_checkbox)
5945
+ slider = staticmethod(_ui_slider)
5946
+ otp = staticmethod(_ui_otp)
5947
+ option = staticmethod(_ui_option)
5948
+
5949
+ # Layout
5950
+ row = staticmethod(_ui_row)
5951
+ column = staticmethod(_ui_column)
5952
+ grid = staticmethod(_ui_grid)
5953
+ wrap = staticmethod(_ui_wrap)
5954
+ group = staticmethod(_ui_group)
5955
+ card = staticmethod(_ui_card)
5956
+ disclosure = staticmethod(_ui_disclosure)
5957
+
5958
+ # Text and links
5959
+ heading = staticmethod(_ui_heading)
5960
+ paragraph = staticmethod(_ui_paragraph)
5961
+ divider = staticmethod(_ui_divider)
5962
+ code = staticmethod(_ui_code)
5963
+ link = staticmethod(_ui_link)
5964
+
5965
+ # Live state
5966
+ spinner = staticmethod(_ui_spinner)
5967
+ button = staticmethod(_ui_button)
5968
+ status = staticmethod(_ui_status)
5969
+ progress = staticmethod(_ui_progress)
5970
+ stat = staticmethod(_ui_stat)
5971
+ steps = staticmethod(_ui_steps)
5972
+ output = staticmethod(_ui_output)
5973
+ table = staticmethod(_ui_table)
5974
+ table_column = staticmethod(_ui_table_column)
5975
+ table_row = staticmethod(_ui_table_row)
5976
+ table_group = staticmethod(_ui_table_group)
5977
+
5978
+
5979
+ ui = _UI()
@@ -954,54 +954,17 @@ def test_snapshot_info_reads_the_manifest_without_a_request():
954
954
  GatewayClient.snapshot_info(damaged)
955
955
 
956
956
 
957
- def test_header_views_read_and_act_through_the_machine_routes():
958
- view = {
959
- "id": "v1",
960
- "title": "Build",
961
- "placement": "header",
962
- "key": "build",
963
- "extension": "forge",
964
- "nodes": [
965
- {
966
- "id": "go",
967
- "type": "button",
968
- "label": "Rerun",
969
- "action": "activate",
970
- "is_disabled": False,
971
- "clicks": 0,
972
- }
973
- ],
974
- "seq": 0,
975
- "created_at": 1,
976
- "timeout_ms": 0,
977
- "channel_ids": ["app"],
978
- }
979
-
957
+ def test_live_views_filter_by_placement_on_the_session_route():
980
958
  def respond(method, path, body):
981
959
  if path.startswith(("/v1/capabilities", "/v1/clients")):
982
960
  return compatible(method, path, body)
983
- if path == "/v1/views/live":
984
- return 200, {"views": [view]}
985
- if path.startswith("/v1/sessions/s1/views/live"):
986
- return 200, {"views": []}
987
- return 200, {"is_accepted": True}
961
+ return 200, {"views": []}
988
962
 
989
963
  with endpoint(respond) as (url, calls), GatewayClient(url) as client:
990
- [header] = client.header_views()
991
- assert (header.placement, header.key, header.extension) == (
992
- "header",
993
- "build",
994
- "forge",
995
- )
996
- assert client.header_view_action("v1", "activate", node_id="go")["is_accepted"]
997
964
  assert client.session("s1").live_views(placement="panel") == []
998
965
  sent = [
999
- (method, path, json.loads(body or b"null"))
1000
- for method, path, _, body in calls
966
+ (method, path)
967
+ for method, path, _, _ in calls
1001
968
  if not path.startswith(("/v1/capabilities", "/v1/clients"))
1002
969
  ]
1003
- assert sent == [
1004
- ("GET", "/v1/views/live", None),
1005
- ("POST", "/v1/views/v1/actions", {"node_id": "go", "action": "activate"}),
1006
- ("GET", "/v1/sessions/s1/views/live?placement=panel", None),
1007
- ]
970
+ assert sent == [("GET", "/v1/sessions/s1/views/live?placement=panel")]