vis-agent 0.2.47.dev7678__tar.gz → 0.2.48__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.
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/PKG-INFO +15 -14
- vis_agent-0.2.48/README.md +38 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/agents.json +57 -1
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/gateway.json +13 -0
- vis_agent-0.2.48/hatch_build.py +45 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/pyproject.toml +1 -1
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/__init__.py +4 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_client.py +18 -0
- vis_agent-0.2.48/src/blockether/vis/engine/_install.py +315 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_local.py +17 -6
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/agent.py +6 -6
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_contracts.py +3 -3
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_agent.py +14 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_gateway_performance.py +74 -6
- vis_agent-0.2.48/tests/test_install.py +235 -0
- vis_agent-0.2.47.dev7678/README.md +0 -37
- vis_agent-0.2.47.dev7678/hatch_build.py +0 -19
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/.gitignore +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/LICENSE +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-arguments.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-cases.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-copy.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-execution.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-groups.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-read-session.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-reads.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-results.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity-tables.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/activity.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/diff.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/live-primitives.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/session-health.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/fixtures/view.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/activity.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/automations.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/common.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/config.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/content.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/council.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/diff.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/evals.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/improve.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/provider.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/rooms.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/symbol.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/toggle.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/contracts/schema/view.json +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/examples/greeter/tests/test_greeter.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/__init__.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/_contracts.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/_outside.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/_wire.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/activity.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_agent.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_agents.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_council.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/engine/_extensions.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/__init__.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/_gateway.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/bench.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/check.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/compare.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/environment.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/grade.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/harbor.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/judge-rubric.toml +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/judge.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/labels.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/leaderboard.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/repeats.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/rounds.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/stages.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/stats.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/evals/trajectory.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/extension.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/extension_package.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/py.typed +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/rooms.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/src/blockether/vis/views.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/conftest.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/evals_atif.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_activity.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_agent.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_agent_extension_lifecycle.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_agent_extensions.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_agents.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_api_guides.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_attachments.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_authoring.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_catalog.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_catalog_recipe.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_ci_report_recipe.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_client.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_client_extensions_engine.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_code_quality_recipe.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_council.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_declarations.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_engine.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_engine_docstrings.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_bench.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_check.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_compare.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_environment.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_gateway.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_grade.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_guards.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_harbor.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_judge.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_labels.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_repeats.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_rounds.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_stages.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_stats.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_tasks.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_evals_trajectory.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_extension_package.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_extension_reference.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_goals.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_live_primitives.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_live_wait.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_local.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_method_typing.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_monitor_recipe.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_namespace.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_outside.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_providers.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_read_session.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_record_arguments.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_registration.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_repair_hooks.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_result_sequence.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_rooms.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_scoped_settings.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_sdk_bootstrap.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_sdk_guide.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_sdk_typing.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_structured_live.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_symbol_contract.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_testing.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_text_list_arguments.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_tools.py +0 -0
- {vis_agent-0.2.47.dev7678 → vis_agent-0.2.48}/tests/test_views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vis-agent
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.48
|
|
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
|
|
@@ -28,15 +28,18 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
# vis-agent
|
|
30
30
|
|
|
31
|
-
Python SDK for Vis
|
|
31
|
+
Python SDK for Vis agent sessions and extensions.
|
|
32
32
|
|
|
33
33
|
```sh
|
|
34
34
|
pip install vis-agent
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
the
|
|
37
|
+
You need Python 3.12+ on Linux or macOS and a configured model provider. You do not
|
|
38
|
+
have to install Vis first. A local run uses the installed `vis-agent` only when it is
|
|
39
|
+
the same release as the SDK. Otherwise the SDK downloads only that release's engine into
|
|
40
|
+
`~/.vis/sdk` and checks it against the release checksums. Set `VIS_NO_AUTO_INSTALL=1` to
|
|
41
|
+
turn this off. To download the engine ahead of time, for example in a container image, run
|
|
42
|
+
`python -c "from blockether.vis.engine import install; print(install())"`.
|
|
40
43
|
|
|
41
44
|
## Run a local agent
|
|
42
45
|
|
|
@@ -48,18 +51,16 @@ with Agent(project=".") as agent:
|
|
|
48
51
|
print(result["status"])
|
|
49
52
|
```
|
|
50
53
|
|
|
51
|
-
The SDK starts
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
process, use `LocalEngine`; see the [stdio guide](https://vis.blockether.com/python-sdk.html#use-stdio-from-the-python-sdk).
|
|
54
|
+
The SDK starts a private Vis process with a temporary session database and removes both
|
|
55
|
+
when the block ends. Tasks can incur provider charges and can change project files. To
|
|
56
|
+
choose the executable or share one process between agents, use `LocalEngine`. See the
|
|
57
|
+
[stdio guide](https://vis.blockether.com/python-sdk.html#use-stdio-from-the-python-sdk).
|
|
56
58
|
|
|
57
59
|
- [Python SDK guide](https://vis.blockether.com/python-sdk.html) — run a local
|
|
58
|
-
agent, continue a conversation or connect to a shared gateway.
|
|
59
|
-
available in SDK `0.2.3` and newer.
|
|
60
|
-
- [Decision models](https://vis.blockether.com/decision-models.html) — download
|
|
61
|
-
Laya or GLiNER2.5, train both heads offline, publish FP32 and select a version.
|
|
60
|
+
agent, continue a conversation or connect to a shared gateway.
|
|
62
61
|
- [Python API reference](https://vis.blockether.com/python-sdk-api/) — browse
|
|
63
62
|
classes, methods, signatures and types generated from the SDK source.
|
|
64
63
|
- [Extension guide](https://vis.blockether.com/extending.html) — add tools to Vis.
|
|
64
|
+
- [Decision models](https://vis.blockether.com/decision-models.html) — download
|
|
65
|
+
Laya or GLiNER2.5, train both heads offline, publish FP32 and select a version.
|
|
65
66
|
- [Documentation](https://vis.blockether.com) — browse all guides and reference pages.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# vis-agent
|
|
2
|
+
|
|
3
|
+
Python SDK for Vis agent sessions and extensions.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pip install vis-agent
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
You need Python 3.12+ on Linux or macOS and a configured model provider. You do not
|
|
10
|
+
have to install Vis first. A local run uses the installed `vis-agent` only when it is
|
|
11
|
+
the same release as the SDK. Otherwise the SDK downloads only that release's engine into
|
|
12
|
+
`~/.vis/sdk` and checks it against the release checksums. Set `VIS_NO_AUTO_INSTALL=1` to
|
|
13
|
+
turn this off. To download the engine ahead of time, for example in a container image, run
|
|
14
|
+
`python -c "from blockether.vis.engine import install; print(install())"`.
|
|
15
|
+
|
|
16
|
+
## Run a local agent
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from blockether.vis.engine import Agent
|
|
20
|
+
|
|
21
|
+
with Agent(project=".") as agent:
|
|
22
|
+
result = agent.run("Summarize this project without changing files.")
|
|
23
|
+
print(result["status"])
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The SDK starts a private Vis process with a temporary session database and removes both
|
|
27
|
+
when the block ends. Tasks can incur provider charges and can change project files. To
|
|
28
|
+
choose the executable or share one process between agents, use `LocalEngine`. See the
|
|
29
|
+
[stdio guide](https://vis.blockether.com/python-sdk.html#use-stdio-from-the-python-sdk).
|
|
30
|
+
|
|
31
|
+
- [Python SDK guide](https://vis.blockether.com/python-sdk.html) — run a local
|
|
32
|
+
agent, continue a conversation or connect to a shared gateway.
|
|
33
|
+
- [Python API reference](https://vis.blockether.com/python-sdk-api/) — browse
|
|
34
|
+
classes, methods, signatures and types generated from the SDK source.
|
|
35
|
+
- [Extension guide](https://vis.blockether.com/extending.html) — add tools to Vis.
|
|
36
|
+
- [Decision models](https://vis.blockether.com/decision-models.html) — download
|
|
37
|
+
Laya or GLiNER2.5, train both heads offline, publish FP32 and select a version.
|
|
38
|
+
- [Documentation](https://vis.blockether.com) — browse all guides and reference pages.
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"type": "integer",
|
|
28
28
|
"minimum": 1,
|
|
29
29
|
"maximum": 600,
|
|
30
|
-
"default":
|
|
30
|
+
"default": 120
|
|
31
31
|
},
|
|
32
32
|
"allowed_models": {
|
|
33
33
|
"type": "array",
|
|
@@ -80,6 +80,62 @@
|
|
|
80
80
|
],
|
|
81
81
|
"additionalProperties": false
|
|
82
82
|
},
|
|
83
|
+
"extend": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"session_id": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1
|
|
89
|
+
},
|
|
90
|
+
"iterations": {
|
|
91
|
+
"type": "integer",
|
|
92
|
+
"minimum": 1,
|
|
93
|
+
"maximum": 600
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"required": [
|
|
97
|
+
"session_id",
|
|
98
|
+
"iterations"
|
|
99
|
+
],
|
|
100
|
+
"additionalProperties": false
|
|
101
|
+
},
|
|
102
|
+
"deny": {
|
|
103
|
+
"type": "object",
|
|
104
|
+
"properties": {
|
|
105
|
+
"session_id": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"minLength": 1
|
|
108
|
+
},
|
|
109
|
+
"reason": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"minLength": 1,
|
|
112
|
+
"maxLength": 2000,
|
|
113
|
+
"pattern": "\\S"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"required": [
|
|
117
|
+
"session_id",
|
|
118
|
+
"reason"
|
|
119
|
+
],
|
|
120
|
+
"additionalProperties": false
|
|
121
|
+
},
|
|
122
|
+
"resume": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"properties": {
|
|
125
|
+
"session_id": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"minLength": 1
|
|
128
|
+
},
|
|
129
|
+
"task": {
|
|
130
|
+
"$ref": "#/$defs/spawn/properties/task"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"required": [
|
|
134
|
+
"session_id",
|
|
135
|
+
"task"
|
|
136
|
+
],
|
|
137
|
+
"additionalProperties": false
|
|
138
|
+
},
|
|
83
139
|
"route": {
|
|
84
140
|
"type": "object",
|
|
85
141
|
"properties": {
|
|
@@ -1226,6 +1226,16 @@
|
|
|
1226
1226
|
},
|
|
1227
1227
|
"path": "/v1/sessions/:sid/workspace/root"
|
|
1228
1228
|
},
|
|
1229
|
+
{
|
|
1230
|
+
"audience": "sdk",
|
|
1231
|
+
"operations": {
|
|
1232
|
+
"post": {
|
|
1233
|
+
"request": "json",
|
|
1234
|
+
"response": "json"
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
"path": "/v1/sessions/actions/archive"
|
|
1238
|
+
},
|
|
1229
1239
|
{
|
|
1230
1240
|
"audience": "sdk",
|
|
1231
1241
|
"operations": {
|
|
@@ -2383,6 +2393,9 @@
|
|
|
2383
2393
|
{
|
|
2384
2394
|
"const": "session.agent_name_updated"
|
|
2385
2395
|
},
|
|
2396
|
+
{
|
|
2397
|
+
"const": "session.created"
|
|
2398
|
+
},
|
|
2386
2399
|
{
|
|
2387
2400
|
"const": "session.deleted"
|
|
2388
2401
|
},
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Bundle the canonical contracts and the release tag of the matching Vis engine."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
9
|
+
|
|
10
|
+
# A beta SDK (X.Y.Z.devN) cannot name its engine from its version, so CI records it.
|
|
11
|
+
_TAG = re.compile(r"^(v\d+\.\d+\.\d+|beta-[0-9a-f]{40})$")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ContractResources(BuildHookInterface):
|
|
15
|
+
def initialize(self, version, build_data):
|
|
16
|
+
root = Path(self.root)
|
|
17
|
+
source = root / "contracts"
|
|
18
|
+
if not source.is_dir():
|
|
19
|
+
source = root.parent / "vis-contract/resources/vis-contract"
|
|
20
|
+
if not source.is_dir():
|
|
21
|
+
raise FileNotFoundError("canonical Vis contract resources are missing")
|
|
22
|
+
destination = (
|
|
23
|
+
"blockether/vis/_data" if self.target_name == "wheel" else "contracts"
|
|
24
|
+
)
|
|
25
|
+
build_data["force_include"][str(source)] = destination
|
|
26
|
+
self._release_tag(root, build_data)
|
|
27
|
+
|
|
28
|
+
def _release_tag(self, root, build_data):
|
|
29
|
+
"""Record VIS_SDK_RELEASE_TAG, or the tag of the sdist this wheel comes from."""
|
|
30
|
+
tag = os.environ.get("VIS_SDK_RELEASE_TAG", "").strip()
|
|
31
|
+
recorded = root / "release-tag"
|
|
32
|
+
if not tag and recorded.is_file():
|
|
33
|
+
tag = recorded.read_text(encoding="utf-8").strip()
|
|
34
|
+
if not tag:
|
|
35
|
+
return
|
|
36
|
+
if not _TAG.match(tag):
|
|
37
|
+
raise ValueError(f"VIS_SDK_RELEASE_TAG={tag!r} is not vX.Y.Z or beta-<sha>")
|
|
38
|
+
written = Path(tempfile.mkdtemp(prefix="vis-sdk-tag-")) / "release-tag"
|
|
39
|
+
written.write_text(f"{tag}\n", encoding="utf-8")
|
|
40
|
+
destination = (
|
|
41
|
+
"blockether/vis/engine/release-tag"
|
|
42
|
+
if self.target_name == "wheel"
|
|
43
|
+
else "release-tag"
|
|
44
|
+
)
|
|
45
|
+
build_data["force_include"][str(written)] = destination
|
|
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "vis-agent"
|
|
11
|
-
version = "0.2.
|
|
11
|
+
version = "0.2.48"
|
|
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"
|
|
@@ -33,6 +33,7 @@ from ._council import (
|
|
|
33
33
|
CouncilSource,
|
|
34
34
|
CouncilThread,
|
|
35
35
|
)
|
|
36
|
+
from ._install import InstallError, ensure_installed, install
|
|
36
37
|
from ._local import LocalEngine
|
|
37
38
|
|
|
38
39
|
__all__ = [
|
|
@@ -51,6 +52,7 @@ __all__ = [
|
|
|
51
52
|
"ExecutionLayer",
|
|
52
53
|
"GatewayClient",
|
|
53
54
|
"GatewayError",
|
|
55
|
+
"InstallError",
|
|
54
56
|
"JobEvent",
|
|
55
57
|
"JobEvents",
|
|
56
58
|
"JSONValue",
|
|
@@ -63,4 +65,6 @@ __all__ = [
|
|
|
63
65
|
"TransportError",
|
|
64
66
|
"Turn",
|
|
65
67
|
"VisTimeout",
|
|
68
|
+
"ensure_installed",
|
|
69
|
+
"install",
|
|
66
70
|
]
|
|
@@ -2183,6 +2183,24 @@ class ExecutionLayer(ABC):
|
|
|
2183
2183
|
)
|
|
2184
2184
|
return response.json()
|
|
2185
2185
|
|
|
2186
|
+
def post_sessions_archive(
|
|
2187
|
+
self,
|
|
2188
|
+
*,
|
|
2189
|
+
query: Query | None = None,
|
|
2190
|
+
timeout: float | None = None,
|
|
2191
|
+
body: JSONValue = None,
|
|
2192
|
+
) -> JSONValue:
|
|
2193
|
+
"""POST /v1/sessions/actions/archive — archive many sessions; skip working ones."""
|
|
2194
|
+
response = self._request(
|
|
2195
|
+
"POST",
|
|
2196
|
+
"/v1/sessions/actions/archive",
|
|
2197
|
+
path={},
|
|
2198
|
+
query=query,
|
|
2199
|
+
timeout=timeout,
|
|
2200
|
+
body=body,
|
|
2201
|
+
)
|
|
2202
|
+
return response.json()
|
|
2203
|
+
|
|
2186
2204
|
def get_sessions_search(
|
|
2187
2205
|
self, *, query: Query | None = None, timeout: float | None = None
|
|
2188
2206
|
) -> JSONValue:
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""Install the Vis engine that matches this SDK.
|
|
2
|
+
|
|
3
|
+
`ensure_installed()` returns the `vis-agent` command for this SDK. It uses an
|
|
4
|
+
installed Vis only when that build is the same release as the SDK. Otherwise it
|
|
5
|
+
downloads the release once into `$VIS_HOME/sdk/<tag>`. `install()` makes that
|
|
6
|
+
download now, for example while you build a container image.
|
|
7
|
+
|
|
8
|
+
The download is the engine bundle of one platform: the `vis-agent` launcher, the
|
|
9
|
+
native engine and its Python runtime. It has no terminal client, web app or desktop
|
|
10
|
+
app. The SDK checks the archive against the release `SHA256SUMS` and the build stamp
|
|
11
|
+
against the release tag. It does not change shell profiles, the installed track or a
|
|
12
|
+
running gateway. Set `VIS_NO_AUTO_INSTALL=1` to turn off the automatic download.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import fcntl
|
|
18
|
+
import hashlib
|
|
19
|
+
import importlib.metadata
|
|
20
|
+
import importlib.resources
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import platform
|
|
24
|
+
import re
|
|
25
|
+
import shutil
|
|
26
|
+
import sys
|
|
27
|
+
import tarfile
|
|
28
|
+
import tempfile
|
|
29
|
+
import urllib.error
|
|
30
|
+
import urllib.request
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
_COMMAND = "vis-agent"
|
|
34
|
+
_NATIVE = "vis-agent-native"
|
|
35
|
+
# A launcher with this file beside it always runs the native engine beside it.
|
|
36
|
+
_PINNED = "vis-agent.pinned"
|
|
37
|
+
_RELEASE = re.compile(r"^\d+\.\d+\.\d+$")
|
|
38
|
+
_STABLE = re.compile(r"^v\d+\.\d+\.\d+$")
|
|
39
|
+
_TAG = re.compile(r"^(v\d+\.\d+\.\d+|beta-[0-9a-f]{40})$")
|
|
40
|
+
_OFF = {"1", "true", "yes", "on"}
|
|
41
|
+
_CHUNK = 1 << 20
|
|
42
|
+
# Each network read must progress within this time; the engine bundle is large.
|
|
43
|
+
_READ_TIMEOUT = 120
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class InstallError(RuntimeError):
|
|
47
|
+
"""The SDK could not find or download the Vis engine."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _repository() -> str:
|
|
51
|
+
return os.environ.get("VIS_REPO_SLUG") or "Blockether/vis"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _vis_home() -> Path:
|
|
55
|
+
return Path(os.environ.get("VIS_HOME") or Path.home() / ".vis")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _cache_root() -> Path:
|
|
59
|
+
return _vis_home() / "sdk"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _embedded_tag() -> str | None:
|
|
63
|
+
"""Return the release tag that the wheel build recorded, if any."""
|
|
64
|
+
try:
|
|
65
|
+
text = (
|
|
66
|
+
importlib.resources.files("blockether.vis.engine")
|
|
67
|
+
.joinpath("release-tag")
|
|
68
|
+
.read_text(encoding="utf-8")
|
|
69
|
+
)
|
|
70
|
+
except (OSError, ModuleNotFoundError):
|
|
71
|
+
return None
|
|
72
|
+
tag = text.strip()
|
|
73
|
+
return tag if _TAG.match(tag) else None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _editable(distribution: importlib.metadata.Distribution) -> bool:
|
|
77
|
+
try:
|
|
78
|
+
url = json.loads(distribution.read_text("direct_url.json") or "{}")
|
|
79
|
+
except ValueError:
|
|
80
|
+
return False
|
|
81
|
+
return bool(url.get("dir_info", {}).get("editable"))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _sdk_tag() -> str | None:
|
|
85
|
+
"""Return the release tag of this SDK, or None for a development build.
|
|
86
|
+
|
|
87
|
+
A release SDK `X.Y.Z` uses `vX.Y.Z`. A beta SDK `X.Y.Z.devN` uses the
|
|
88
|
+
`beta-<sha>` tag that its wheel build recorded. An editable checkout is a
|
|
89
|
+
development build.
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
distribution = importlib.metadata.distribution("vis-agent")
|
|
93
|
+
except importlib.metadata.PackageNotFoundError:
|
|
94
|
+
return None
|
|
95
|
+
if _editable(distribution):
|
|
96
|
+
return None
|
|
97
|
+
version = distribution.version
|
|
98
|
+
if _RELEASE.match(version):
|
|
99
|
+
return f"v{version}"
|
|
100
|
+
return _embedded_tag()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _open(url: str):
|
|
104
|
+
return urllib.request.urlopen(url, timeout=_READ_TIMEOUT)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _fetch(url: str) -> bytes:
|
|
108
|
+
with _open(url) as response:
|
|
109
|
+
return response.read()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _fetch_file(url: str, target: Path) -> str:
|
|
113
|
+
"""Stream `url` into `target` and return its SHA-256."""
|
|
114
|
+
digest = hashlib.sha256()
|
|
115
|
+
with _open(url) as response, open(target, "wb") as output:
|
|
116
|
+
while chunk := response.read(_CHUNK):
|
|
117
|
+
digest.update(chunk)
|
|
118
|
+
output.write(chunk)
|
|
119
|
+
return digest.hexdigest()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _latest_tag() -> str:
|
|
123
|
+
url = f"https://github.com/{_repository()}/releases/latest"
|
|
124
|
+
with _open(url) as response:
|
|
125
|
+
tag = response.geturl().rstrip("/").rsplit("/", 1)[-1]
|
|
126
|
+
if not _STABLE.match(tag):
|
|
127
|
+
raise InstallError(f"could not find the latest Vis release at {url}")
|
|
128
|
+
return tag
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _expected_hash(sums: bytes, name: str) -> str:
|
|
132
|
+
for line in sums.decode("utf-8", "replace").splitlines():
|
|
133
|
+
parts = line.split()
|
|
134
|
+
if len(parts) == 2 and parts[1].lstrip("*") == name:
|
|
135
|
+
return parts[0].lower()
|
|
136
|
+
raise InstallError(f"SHA256SUMS has no entry for {name}")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _platform_asset() -> str:
|
|
140
|
+
"""Return the engine bundle name for this computer."""
|
|
141
|
+
machine = platform.machine().lower()
|
|
142
|
+
if sys.platform == "darwin" and machine == "arm64":
|
|
143
|
+
return "vis-agent-macos-arm64.tar.gz"
|
|
144
|
+
if sys.platform == "linux" and machine in ("x86_64", "amd64"):
|
|
145
|
+
return "vis-agent-linux-x64.tar.gz"
|
|
146
|
+
if sys.platform == "linux" and machine in ("aarch64", "arm64"):
|
|
147
|
+
return "vis-agent-linux-arm64.tar.gz"
|
|
148
|
+
raise InstallError(
|
|
149
|
+
f"Vis has no engine for {sys.platform} {machine}. "
|
|
150
|
+
"Use Linux (x64 or arm64) or macOS on Apple silicon."
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _stamp_matches(stamp: Path, tag: str) -> bool:
|
|
155
|
+
"""True when the build stamp `version commit track …` is the build of `tag`."""
|
|
156
|
+
try:
|
|
157
|
+
fields = stamp.read_text(encoding="utf-8").split()
|
|
158
|
+
except OSError:
|
|
159
|
+
return False
|
|
160
|
+
if len(fields) < 3:
|
|
161
|
+
return False
|
|
162
|
+
version, commit, track = fields[:3]
|
|
163
|
+
if tag.startswith("beta-"):
|
|
164
|
+
return track == "beta" and commit == tag.removeprefix("beta-")
|
|
165
|
+
return track == "release" and version == tag.removeprefix("v")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _executable(path: Path) -> bool:
|
|
169
|
+
return path.is_file() and os.access(path, os.X_OK)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _complete(directory: Path, tag: str) -> bool:
|
|
173
|
+
return (
|
|
174
|
+
_executable(directory / _COMMAND)
|
|
175
|
+
and _executable(directory / _NATIVE)
|
|
176
|
+
and (directory / _PINNED).is_file()
|
|
177
|
+
and (directory / "vis-agent-python" / "python").is_dir()
|
|
178
|
+
and _stamp_matches(directory / f"{_NATIVE}.build", tag)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _installed() -> str | None:
|
|
183
|
+
found = shutil.which(_COMMAND)
|
|
184
|
+
if found:
|
|
185
|
+
return found
|
|
186
|
+
candidate = Path.home() / ".local/bin" / _COMMAND
|
|
187
|
+
return str(candidate) if _executable(candidate) else None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _installed_matches(command: str, tag: str) -> bool:
|
|
191
|
+
"""True when the launcher `command` runs the native build of `tag`.
|
|
192
|
+
|
|
193
|
+
This follows the launcher: a pinned bundle runs the engine beside it, the `dev`
|
|
194
|
+
track runs source, and otherwise the engine beside the launcher wins over the
|
|
195
|
+
one in `$VIS_HOME/install`.
|
|
196
|
+
"""
|
|
197
|
+
bin_dir = Path(command).resolve().parent
|
|
198
|
+
install_dir = _vis_home() / "install"
|
|
199
|
+
bundled = bin_dir / _NATIVE
|
|
200
|
+
if not ((bin_dir / _PINNED).is_file() and _executable(bundled)):
|
|
201
|
+
try:
|
|
202
|
+
track = (install_dir / "track").read_text(encoding="utf-8").strip()
|
|
203
|
+
except OSError:
|
|
204
|
+
track = ""
|
|
205
|
+
if track == "dev":
|
|
206
|
+
return False
|
|
207
|
+
for native in (bundled, install_dir / _NATIVE):
|
|
208
|
+
if _executable(native):
|
|
209
|
+
return _stamp_matches(native.with_name(f"{_NATIVE}.build"), tag)
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _check_bundle(directory: Path, tag: str) -> None:
|
|
214
|
+
missing = [
|
|
215
|
+
name for name in (_COMMAND, _NATIVE) if not _executable(directory / name)
|
|
216
|
+
]
|
|
217
|
+
python = directory / "vis-agent-python"
|
|
218
|
+
if not (python / "python").is_dir() or not list(python.glob("libvispython.*")):
|
|
219
|
+
missing.append("vis-agent-python")
|
|
220
|
+
if missing:
|
|
221
|
+
raise InstallError(f"the Vis {tag} bundle has no {', '.join(missing)}")
|
|
222
|
+
if not _stamp_matches(directory / f"{_NATIVE}.build", tag):
|
|
223
|
+
raise InstallError(
|
|
224
|
+
f"the Vis {tag} bundle has the build stamp of another release"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _download(tag: str, directory: Path) -> None:
|
|
229
|
+
"""Download, check and unpack the engine bundle of `tag` into `directory`."""
|
|
230
|
+
asset = _platform_asset()
|
|
231
|
+
base = f"https://github.com/{_repository()}/releases/download/{tag}"
|
|
232
|
+
expected = _expected_hash(_fetch(f"{base}/SHA256SUMS"), asset)
|
|
233
|
+
with tempfile.TemporaryDirectory(dir=directory.parent, prefix=f".{tag}-") as work:
|
|
234
|
+
archive = Path(work) / asset
|
|
235
|
+
if _fetch_file(f"{base}/{asset}", archive) != expected:
|
|
236
|
+
raise InstallError(f"the {asset} of {tag} does not match SHA256SUMS")
|
|
237
|
+
bundle = Path(work) / "bundle"
|
|
238
|
+
with tarfile.open(archive) as tar:
|
|
239
|
+
tar.extractall(bundle, filter="data")
|
|
240
|
+
_check_bundle(bundle, tag)
|
|
241
|
+
(bundle / _PINNED).write_text(f"{tag}\n", encoding="utf-8")
|
|
242
|
+
if directory.exists():
|
|
243
|
+
shutil.rmtree(directory)
|
|
244
|
+
bundle.replace(directory)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _download_once(tag: str, *, force: bool = False) -> str:
|
|
248
|
+
root = _cache_root()
|
|
249
|
+
directory = root / tag
|
|
250
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
251
|
+
with open(root / f"{tag}.lock", "w") as lock:
|
|
252
|
+
# A second process waits here and then uses the finished download.
|
|
253
|
+
fcntl.flock(lock, fcntl.LOCK_EX)
|
|
254
|
+
if force or not _complete(directory, tag):
|
|
255
|
+
print(f"vis-agent: downloading Vis {tag} into {directory}", file=sys.stderr)
|
|
256
|
+
try:
|
|
257
|
+
_download(tag, directory)
|
|
258
|
+
except urllib.error.HTTPError as error:
|
|
259
|
+
if error.code == 404:
|
|
260
|
+
raise InstallError(
|
|
261
|
+
f"Vis {tag} has no engine at {error.url}. "
|
|
262
|
+
"Install the SDK version of a published Vis release."
|
|
263
|
+
) from None
|
|
264
|
+
raise InstallError(f"could not download Vis {tag}: {error}") from None
|
|
265
|
+
except (OSError, tarfile.TarError) as error:
|
|
266
|
+
raise InstallError(f"could not download Vis {tag}: {error}") from None
|
|
267
|
+
return str(directory / _COMMAND)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def install(*, force: bool = False) -> str:
|
|
271
|
+
"""Download the Vis engine of this SDK now and return its `vis-agent` path.
|
|
272
|
+
|
|
273
|
+
Use it to prepare a computer or a container image before the first run. It
|
|
274
|
+
downloads into `$VIS_HOME/sdk/<tag>` even when another Vis is installed, and
|
|
275
|
+
reuses a complete download unless `force` is true. A development build of the
|
|
276
|
+
SDK installs the latest stable release. `VIS_NO_AUTO_INSTALL` does not apply.
|
|
277
|
+
|
|
278
|
+
Raises:
|
|
279
|
+
InstallError: The platform has no engine, the release has no bundle, or the
|
|
280
|
+
download fails its checks.
|
|
281
|
+
"""
|
|
282
|
+
return _download_once(_sdk_tag() or _latest_tag(), force=force)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def ensure_installed() -> str:
|
|
286
|
+
"""Return the `vis-agent` command that matches this SDK, and download it when missing.
|
|
287
|
+
|
|
288
|
+
An installed `vis-agent` is used only when it runs the same release as the SDK.
|
|
289
|
+
Otherwise the SDK uses, or downloads, its own copy in `$VIS_HOME/sdk/<tag>`. A
|
|
290
|
+
development build of the SDK uses any installed command, or the latest stable
|
|
291
|
+
release.
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
InstallError: The download is turned off with `VIS_NO_AUTO_INSTALL`, or
|
|
295
|
+
`install()` fails.
|
|
296
|
+
"""
|
|
297
|
+
tag = _sdk_tag()
|
|
298
|
+
installed = _installed()
|
|
299
|
+
if tag is None and installed:
|
|
300
|
+
return installed
|
|
301
|
+
if tag is not None:
|
|
302
|
+
if installed and _installed_matches(installed, tag):
|
|
303
|
+
return installed
|
|
304
|
+
if _complete(_cache_root() / tag, tag):
|
|
305
|
+
return str(_cache_root() / tag / _COMMAND)
|
|
306
|
+
if (os.environ.get("VIS_NO_AUTO_INSTALL") or "").strip().lower() in _OFF:
|
|
307
|
+
wanted = f"Vis {tag}" if tag else f"the {_COMMAND} command"
|
|
308
|
+
raise InstallError(
|
|
309
|
+
f"{wanted} is not installed, and VIS_NO_AUTO_INSTALL turns off the "
|
|
310
|
+
"download. Install it, call install(), or pass executable=..."
|
|
311
|
+
)
|
|
312
|
+
try:
|
|
313
|
+
return install()
|
|
314
|
+
except OSError as error:
|
|
315
|
+
raise InstallError(f"could not download Vis: {error}") from None
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Owned local Vis subprocess, with the same session API and no HTTP listener.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Pass an executable, or keep the default `vis-agent`. The default runs the engine of
|
|
4
|
+
this SDK's release (see `ensure_installed`). There is no gateway discovery or
|
|
5
|
+
user-server shutdown. Each engine gets a temporary database and stderr log, and
|
|
6
|
+
closing discards them.
|
|
6
7
|
Supports Linux and macOS. Instances use one calling thread, like GatewayClient.
|
|
7
8
|
"""
|
|
8
9
|
|
|
@@ -34,6 +35,7 @@ from ._client import (
|
|
|
34
35
|
_PollingEvents,
|
|
35
36
|
_SessionPollingEvents,
|
|
36
37
|
)
|
|
38
|
+
from ._install import _COMMAND, InstallError, ensure_installed
|
|
37
39
|
|
|
38
40
|
# Errors quote at most this much of the engine's stderr, starting at a line.
|
|
39
41
|
_STDERR_TAIL = 4096
|
|
@@ -52,9 +54,12 @@ class LocalEngine(ExecutionLayer):
|
|
|
52
54
|
"""Own a private Vis process without starting an HTTP server.
|
|
53
55
|
|
|
54
56
|
Use this layer when you need to choose an executable, share one local process
|
|
55
|
-
between agents, or call the session API directly.
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
between agents, or call the session API directly. With the default `vis-agent`,
|
|
58
|
+
`connect` uses the installed command when it runs this SDK's release. Otherwise it
|
|
59
|
+
downloads that release once into `$VIS_HOME/sdk` and checks it against the release
|
|
60
|
+
checksums.
|
|
61
|
+
Set `VIS_NO_AUTO_INSTALL=1` to turn off the download. This class never discovers
|
|
62
|
+
a gateway. Supported platforms are Linux and macOS.
|
|
58
63
|
|
|
59
64
|
Args:
|
|
60
65
|
executable: Executable path/name or nonempty argument sequence. The SDK
|
|
@@ -160,6 +165,12 @@ class LocalEngine(ExecutionLayer):
|
|
|
160
165
|
raise TransportError("client is closed")
|
|
161
166
|
if self._process is not None:
|
|
162
167
|
return self
|
|
168
|
+
if self._command == [_COMMAND]:
|
|
169
|
+
try:
|
|
170
|
+
self._command = [ensure_installed()]
|
|
171
|
+
except InstallError as error:
|
|
172
|
+
self.close()
|
|
173
|
+
raise TransportError(f"could not start local engine: {error}") from None
|
|
163
174
|
self._home = tempfile.TemporaryDirectory(prefix="vis-sdk-")
|
|
164
175
|
env = {
|
|
165
176
|
**os.environ,
|