vis-agent 0.3.3.dev7953__tar.gz → 0.3.4.dev7992__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.3.3.dev7953 → vis_agent-0.3.4.dev7992}/PKG-INFO +1 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/agents.json +9 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/evals.json +8 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/pyproject.toml +1 -1
- vis_agent-0.3.4.dev7992/release-tag +1 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/__init__.py +2 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_agent.py +8 -2
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_council.py +19 -4
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/__init__.py +38 -2
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/agent.py +133 -13
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/bench.py +3 -2
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/environment.py +1 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/grade.py +35 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/harbor.py +63 -6
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/labels.py +54 -8
- vis_agent-0.3.4.dev7992/src/blockether/vis/evals/lic.py +277 -0
- vis_agent-0.3.4.dev7992/src/blockether/vis/evals/longmemeval.py +413 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/repeats.py +33 -13
- vis_agent-0.3.4.dev7992/src/blockether/vis/evals/report.py +60 -0
- vis_agent-0.3.4.dev7992/src/blockether/vis/evals/reports.py +246 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/stages.py +18 -2
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/stats.py +79 -3
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/trajectory.py +57 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_agent.py +12 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_client.py +5 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_agent.py +53 -5
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_environment.py +13 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_grade.py +20 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_labels.py +38 -0
- vis_agent-0.3.4.dev7992/tests/test_evals_lic.py +114 -0
- vis_agent-0.3.4.dev7992/tests/test_evals_longmemeval.py +136 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_repeats.py +21 -0
- vis_agent-0.3.4.dev7992/tests/test_evals_report.py +127 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_stages.py +5 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_stats.py +84 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_tasks.py +80 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_trajectory.py +31 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_sdk_bootstrap.py +2 -0
- vis_agent-0.3.3.dev7953/release-tag +0 -1
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/.gitignore +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/LICENSE +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/README.md +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-arguments.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-cases.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-copy.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-execution.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-groups.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-read-session.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-reads.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-results.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-stream.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity-tables.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/activity.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/diff.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/live-primitives.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/session-health.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/fixtures/view.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/activity.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/automations.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/common.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/config.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/content.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/council.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/diff.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/gateway.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/improve.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/provider.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/rooms.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/symbol.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/toggle.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/contracts/schema/view.json +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/examples/greeter/tests/test_greeter.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/hatch_build.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/__init__.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/_contracts.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/_outside.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/_wire.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/activity.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_agents.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_client.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_extensions.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_host.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_install.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_local.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/engine/_models.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/_gateway.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/check.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/compare.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/judge-rubric.toml +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/judge.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/leaderboard.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/evals/rounds.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/extension.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/extension_package.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/py.typed +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/rooms.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/src/blockether/vis/views.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/conftest.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/evals_atif.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_activity.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_agent_extension_lifecycle.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_agent_extensions.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_agents.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_api_guides.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_attachments.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_authoring.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_catalog.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_catalog_recipe.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_ci_report_recipe.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_client_extensions_engine.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_code_quality_recipe.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_contracts.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_council.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_declarations.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_engine.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_engine_docstrings.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_bench.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_check.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_compare.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_gateway.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_guards.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_harbor.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_judge.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_evals_rounds.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_extension_package.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_extension_reference.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_gateway_performance.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_goals.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_install.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_live_primitives.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_live_wait.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_local.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_method_typing.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_models.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_monitor_recipe.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_namespace.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_outside.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_providers.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_read_session.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_record_arguments.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_registration.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_repair_hooks.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_result_sequence.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_rooms.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_scoped_settings.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_sdk_guide.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_sdk_typing.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_shortcuts_live.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_structured_live.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_symbol_contract.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_testing.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_text_list_arguments.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/tests/test_tools.py +0 -0
- {vis_agent-0.3.3.dev7953 → vis_agent-0.3.4.dev7992}/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.
|
|
3
|
+
Version: 0.3.4.dev7992
|
|
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
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
"additionalProperties": false
|
|
193
193
|
},
|
|
194
194
|
"grant": {
|
|
195
|
-
"$comment": "Add file rules to the grant of a subagent. A child without write rules writes
|
|
195
|
+
"$comment": "Add file rules to the grant of a subagent. A child without write rules already writes where its parent writes, so a write grant changes nothing for it. A write rule under a read_only or deny rule of the child fails.",
|
|
196
196
|
"type": "object",
|
|
197
197
|
"properties": {
|
|
198
198
|
"session_id": {
|
|
@@ -238,6 +238,10 @@
|
|
|
238
238
|
"task": {
|
|
239
239
|
"$ref": "#/$defs/spawn/properties/task"
|
|
240
240
|
},
|
|
241
|
+
"files": {
|
|
242
|
+
"$comment": "Replace the grant of the child for the follow-up task.",
|
|
243
|
+
"$ref": "#/$defs/files"
|
|
244
|
+
},
|
|
241
245
|
"timeout_secs": {
|
|
242
246
|
"$ref": "#/$defs/wait/properties/timeout_secs"
|
|
243
247
|
}
|
|
@@ -377,6 +381,10 @@
|
|
|
377
381
|
"type": "integer",
|
|
378
382
|
"minimum": 0
|
|
379
383
|
},
|
|
384
|
+
"question": {
|
|
385
|
+
"type": "string",
|
|
386
|
+
"minLength": 1
|
|
387
|
+
},
|
|
380
388
|
"usage": {
|
|
381
389
|
"type": [
|
|
382
390
|
"object",
|
|
@@ -580,7 +580,7 @@
|
|
|
580
580
|
"additionalProperties": false
|
|
581
581
|
},
|
|
582
582
|
"agreement": {
|
|
583
|
-
"description": "The agreement of automatic results with human labels, with Cohen kappa and advice.",
|
|
583
|
+
"description": "The agreement of automatic results with human labels, with Cohen kappa, Krippendorff alpha and advice.",
|
|
584
584
|
"type": "object",
|
|
585
585
|
"properties": {
|
|
586
586
|
"labelled": {
|
|
@@ -598,6 +598,12 @@
|
|
|
598
598
|
"null"
|
|
599
599
|
]
|
|
600
600
|
},
|
|
601
|
+
"alpha": {
|
|
602
|
+
"type": [
|
|
603
|
+
"number",
|
|
604
|
+
"null"
|
|
605
|
+
]
|
|
606
|
+
},
|
|
601
607
|
"disagreements": {
|
|
602
608
|
"type": "array",
|
|
603
609
|
"items": {
|
|
@@ -612,6 +618,7 @@
|
|
|
612
618
|
"labelled",
|
|
613
619
|
"agreement_percent",
|
|
614
620
|
"kappa",
|
|
621
|
+
"alpha",
|
|
615
622
|
"disagreements",
|
|
616
623
|
"advice"
|
|
617
624
|
],
|
|
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "vis-agent"
|
|
11
|
-
version = "0.3.
|
|
11
|
+
version = "0.3.4.dev7992"
|
|
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-a96abba81be1cb50ca4ae87bc76d6453711765db
|
|
@@ -4,7 +4,7 @@ For installation, workflows and lifecycle choices, use the
|
|
|
4
4
|
[Python SDK guide](https://vis.blockether.com/python-sdk.html).
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from ._agent import Agent, StructuredOutputError
|
|
7
|
+
from ._agent import Agent, StructuredOutputError, final_answer
|
|
8
8
|
from ._agents import Subagent, SubagentRecord
|
|
9
9
|
from ._client import (
|
|
10
10
|
Event,
|
|
@@ -70,5 +70,6 @@ __all__ = [
|
|
|
70
70
|
"Turn",
|
|
71
71
|
"VisTimeout",
|
|
72
72
|
"ensure_installed",
|
|
73
|
+
"final_answer",
|
|
73
74
|
"install",
|
|
74
75
|
]
|
|
@@ -239,7 +239,13 @@ def _syntax_message(answer: str, error: json.JSONDecodeError) -> str:
|
|
|
239
239
|
return f"not valid JSON: {error.msg} at {where}"
|
|
240
240
|
|
|
241
241
|
|
|
242
|
-
def
|
|
242
|
+
def final_answer(turn: dict) -> str | None:
|
|
243
|
+
"""Return the final answer text of the turn record `turn`, or None.
|
|
244
|
+
|
|
245
|
+
A turn record has no `answer` field. The answer is the Markdown of the last
|
|
246
|
+
`prose` block in `turn["content"]`. A turn without that block, or with only
|
|
247
|
+
blank text in it, gives None.
|
|
248
|
+
"""
|
|
243
249
|
content = turn.get("content")
|
|
244
250
|
if not isinstance(content, list):
|
|
245
251
|
return None
|
|
@@ -397,7 +403,7 @@ def _run(
|
|
|
397
403
|
{"turn": turn, "answer": None, "errors": [_turn_problem(turn)]}
|
|
398
404
|
)
|
|
399
405
|
raise StructuredOutputError(f"{name} turn did not complete", attempts)
|
|
400
|
-
answer =
|
|
406
|
+
answer = final_answer(turn)
|
|
401
407
|
result, problems = contract.validate(answer)
|
|
402
408
|
if not problems:
|
|
403
409
|
return result
|
|
@@ -316,15 +316,27 @@ class Council:
|
|
|
316
316
|
return self._records("/cancel", {"session_id": session_id}, "cancel")[0]
|
|
317
317
|
|
|
318
318
|
def resume(
|
|
319
|
-
self,
|
|
319
|
+
self,
|
|
320
|
+
session_id: str,
|
|
321
|
+
task: str,
|
|
322
|
+
*,
|
|
323
|
+
files: dict[str, list[str]] | None = None,
|
|
324
|
+
timeout_secs: int = 240,
|
|
320
325
|
) -> SubagentRecord:
|
|
321
326
|
"""Give a finished subagent a follow-up task in its own session, then wait for it.
|
|
322
327
|
|
|
323
328
|
The parent must be active, as for ``spawn``: an idle parent gets
|
|
324
329
|
``inactive-session``. The child keeps its whole context. A child without
|
|
325
330
|
iterations left needs ``extend`` first. A running child needs ``wait``.
|
|
331
|
+
``files`` replaces the file grant of the child for the follow-up task.
|
|
326
332
|
"""
|
|
327
|
-
body
|
|
333
|
+
body: dict[str, Any] = {
|
|
334
|
+
"session_id": session_id,
|
|
335
|
+
"task": task,
|
|
336
|
+
"timeout_secs": timeout_secs,
|
|
337
|
+
}
|
|
338
|
+
if files is not None:
|
|
339
|
+
body["files"] = files
|
|
328
340
|
return self._records("/resume", body, "resume", timeout_secs)[0]
|
|
329
341
|
|
|
330
342
|
def extend(self, session_id: str, iterations: int) -> SubagentRecord:
|
|
@@ -343,8 +355,11 @@ class Council:
|
|
|
343
355
|
def grant(self, session_id: str, files: dict[str, list[str]]) -> SubagentRecord:
|
|
344
356
|
"""Add ``write``, ``read_only`` or ``deny`` file rules to the grant of a subagent.
|
|
345
357
|
|
|
346
|
-
A grant gives at most your own access.
|
|
347
|
-
|
|
358
|
+
A grant gives at most your own access. A write rule that the child can already
|
|
359
|
+
write changes nothing. A write rule under a ``read_only`` or ``deny`` rule of the
|
|
360
|
+
child fails: use ``resume`` with ``files`` for a new scope. The record has a
|
|
361
|
+
``warning`` for unchanged write rules and for an active sibling that can write
|
|
362
|
+
the same files.
|
|
348
363
|
"""
|
|
349
364
|
body = {"session_id": session_id, "files": files}
|
|
350
365
|
return self._records("/grant", body, "grant")[0]
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""Evaluation tools: write and run Harbor tasks, read the results and compare them.
|
|
2
2
|
|
|
3
3
|
Write a Vis task with `write_task`, and run tasks with the Vis agent with `run_tasks`.
|
|
4
|
-
|
|
4
|
+
Give `write_task` a list of user messages for a task with several turns.
|
|
5
|
+
Read one Vis run with `load_trajectory` or `parse_trajectory`, and join the turns of
|
|
6
|
+
one session with `merge_trajectories`. Read the cases of a
|
|
5
7
|
Harbor dataset with `read_tasks`, and the trials of a job or round with `read_trials`.
|
|
6
8
|
Count the trials with `case_results` or `summarize`. Seal a finished round with
|
|
7
9
|
`seal_round`. Compare two results with `compare_cases`, or test paired changes with
|
|
@@ -10,7 +12,9 @@ Count the trials with `case_results` or `summarize`. Seal a finished round with
|
|
|
10
12
|
then score and diagnose it with `bench_report` and `diagnose`. Keep human cause labels
|
|
11
13
|
with `save_label`. Place a round on a Harbor Hub board with `read_leaderboard`. Check
|
|
12
14
|
automatic causes against human labels with `agreement`, and judge stages with
|
|
13
|
-
`stage_agreement`.
|
|
15
|
+
`stage_agreement`. Estimate pass@k and pass^k with `pass_at_k` and `pass_all_k`, and
|
|
16
|
+
the agreement of several raters with `krippendorff_alpha`. Build all of it for one
|
|
17
|
+
round with `round_report`, or run `python -m blockether.vis.evals.report`. For installation and sessions, use the
|
|
14
18
|
[Python SDK guide](https://vis.blockether.com/python-sdk.html).
|
|
15
19
|
"""
|
|
16
20
|
|
|
@@ -51,19 +55,24 @@ from .harbor import (
|
|
|
51
55
|
seal_digest,
|
|
52
56
|
seal_round,
|
|
53
57
|
seal_rows,
|
|
58
|
+
split_turns,
|
|
54
59
|
summarize,
|
|
55
60
|
write_task,
|
|
56
61
|
)
|
|
57
62
|
from .labels import (
|
|
63
|
+
ALPHA_RELIABLE,
|
|
64
|
+
ALPHA_TENTATIVE,
|
|
58
65
|
KAPPA_REVIEW,
|
|
59
66
|
KAPPA_TRUST,
|
|
60
67
|
MIN_LABELS,
|
|
61
68
|
STAGES,
|
|
62
69
|
Agreement,
|
|
63
70
|
agreement,
|
|
71
|
+
alpha_advice,
|
|
64
72
|
kappa_advice,
|
|
65
73
|
majority,
|
|
66
74
|
sample_agreement,
|
|
75
|
+
sample_alpha,
|
|
67
76
|
)
|
|
68
77
|
from .leaderboard import (
|
|
69
78
|
LEADERBOARD_URL,
|
|
@@ -75,6 +84,14 @@ from .leaderboard import (
|
|
|
75
84
|
standing,
|
|
76
85
|
)
|
|
77
86
|
from .repeats import RepeatStats, repeat_stats, task_attempts
|
|
87
|
+
from .reports import (
|
|
88
|
+
REPORT_FILE,
|
|
89
|
+
RepeatRow,
|
|
90
|
+
RoundReport,
|
|
91
|
+
render_report,
|
|
92
|
+
round_report,
|
|
93
|
+
write_report,
|
|
94
|
+
)
|
|
78
95
|
from .rounds import round_summary
|
|
79
96
|
from .stages import (
|
|
80
97
|
StageAgreement,
|
|
@@ -91,8 +108,11 @@ from .stats import (
|
|
|
91
108
|
cohen_kappa,
|
|
92
109
|
detectable_change,
|
|
93
110
|
effective_size,
|
|
111
|
+
krippendorff_alpha,
|
|
94
112
|
mcnemar_exact,
|
|
95
113
|
paired_change,
|
|
114
|
+
pass_all_k,
|
|
115
|
+
pass_at_k,
|
|
96
116
|
wilson_interval,
|
|
97
117
|
)
|
|
98
118
|
from .trajectory import (
|
|
@@ -103,10 +123,13 @@ from .trajectory import (
|
|
|
103
123
|
Trajectory,
|
|
104
124
|
TrajectoryMetrics,
|
|
105
125
|
load_trajectory,
|
|
126
|
+
merge_trajectories,
|
|
106
127
|
parse_trajectory,
|
|
107
128
|
)
|
|
108
129
|
|
|
109
130
|
__all__ = [
|
|
131
|
+
"ALPHA_RELIABLE",
|
|
132
|
+
"ALPHA_TENTATIVE",
|
|
110
133
|
"CAUSES",
|
|
111
134
|
"EARLY_STOP_SHARE",
|
|
112
135
|
"KAPPA_REVIEW",
|
|
@@ -115,6 +138,7 @@ __all__ = [
|
|
|
115
138
|
"MIN_LABELS",
|
|
116
139
|
"NEAR_MISS_RATIO",
|
|
117
140
|
"NOTE_LIMIT",
|
|
141
|
+
"REPORT_FILE",
|
|
118
142
|
"STAGES",
|
|
119
143
|
"Agreement",
|
|
120
144
|
"BenchReport",
|
|
@@ -128,7 +152,9 @@ __all__ = [
|
|
|
128
152
|
"Leaderboard",
|
|
129
153
|
"LeaderboardRow",
|
|
130
154
|
"OutcomeCount",
|
|
155
|
+
"RepeatRow",
|
|
131
156
|
"RepeatStats",
|
|
157
|
+
"RoundReport",
|
|
132
158
|
"RouteTest",
|
|
133
159
|
"RunSummary",
|
|
134
160
|
"StageAgreement",
|
|
@@ -143,6 +169,7 @@ __all__ = [
|
|
|
143
169
|
"VisStanding",
|
|
144
170
|
"agent_limits",
|
|
145
171
|
"agreement",
|
|
172
|
+
"alpha_advice",
|
|
146
173
|
"attempt_cause",
|
|
147
174
|
"attempt_outcome",
|
|
148
175
|
"bench_report",
|
|
@@ -159,6 +186,7 @@ __all__ = [
|
|
|
159
186
|
"judge_errors",
|
|
160
187
|
"judged_samples",
|
|
161
188
|
"kappa_advice",
|
|
189
|
+
"krippendorff_alpha",
|
|
162
190
|
"latest_trials",
|
|
163
191
|
"leaderboard_row",
|
|
164
192
|
"load_labels",
|
|
@@ -166,21 +194,28 @@ __all__ = [
|
|
|
166
194
|
"load_trajectory",
|
|
167
195
|
"majority",
|
|
168
196
|
"mcnemar_exact",
|
|
197
|
+
"merge_trajectories",
|
|
169
198
|
"paired_change",
|
|
170
199
|
"parse_trajectory",
|
|
200
|
+
"pass_all_k",
|
|
201
|
+
"pass_at_k",
|
|
171
202
|
"read_leaderboard",
|
|
172
203
|
"read_tasks",
|
|
173
204
|
"read_trial",
|
|
174
205
|
"read_trials",
|
|
206
|
+
"render_report",
|
|
175
207
|
"repeat_stats",
|
|
208
|
+
"round_report",
|
|
176
209
|
"round_summary",
|
|
177
210
|
"run_tasks",
|
|
178
211
|
"sample_agreement",
|
|
212
|
+
"sample_alpha",
|
|
179
213
|
"save_label",
|
|
180
214
|
"save_stage_label",
|
|
181
215
|
"seal_digest",
|
|
182
216
|
"seal_round",
|
|
183
217
|
"seal_rows",
|
|
218
|
+
"split_turns",
|
|
184
219
|
"stage_agreement",
|
|
185
220
|
"standing",
|
|
186
221
|
"summarize",
|
|
@@ -188,5 +223,6 @@ __all__ = [
|
|
|
188
223
|
"task_attempts",
|
|
189
224
|
"task_note",
|
|
190
225
|
"wilson_interval",
|
|
226
|
+
"write_report",
|
|
191
227
|
"write_task",
|
|
192
228
|
]
|
|
@@ -11,6 +11,12 @@ directory:
|
|
|
11
11
|
- ``stderr.txt``: the error output of the CLI.
|
|
12
12
|
- ``trajectory.json``: the ATIF trajectory of the session.
|
|
13
13
|
- ``run.json``: the provider, the model, the exit code and the wall time.
|
|
14
|
+
|
|
15
|
+
A line with only ``<!-- vis:turn -->`` in the instruction starts the next user
|
|
16
|
+
turn. The agent then sends each message as one CLI turn of the same session, with
|
|
17
|
+
``--session-id``. ``turns/<n>.json`` keeps the trajectory of turn n, and
|
|
18
|
+
``trajectory.json`` joins all turns. Other Harbor agents get the whole text as one
|
|
19
|
+
prompt.
|
|
14
20
|
"""
|
|
15
21
|
|
|
16
22
|
from __future__ import annotations
|
|
@@ -36,9 +42,12 @@ from pydantic import Field
|
|
|
36
42
|
from ..engine._install import ensure_installed
|
|
37
43
|
from .environment import HostEnvironment
|
|
38
44
|
from .grade import RUN_FILE, STDERR_FILE, TRACE_FILE, TRAJECTORY_FILE
|
|
45
|
+
from .harbor import split_turns
|
|
39
46
|
from .trajectory import load_trajectory as load_vis_trajectory
|
|
47
|
+
from .trajectory import merge_trajectories
|
|
40
48
|
|
|
41
49
|
DEFAULT_COMMAND = "vis-agent"
|
|
50
|
+
TURNS_DIR = "turns"
|
|
42
51
|
CLASSPATH_TIMEOUT_SEC = 120
|
|
43
52
|
_NATIVE_MAGIC = (
|
|
44
53
|
b"\x7fELF",
|
|
@@ -76,6 +85,10 @@ class VisOptions(AgentOptions):
|
|
|
76
85
|
command: str | None = Field(
|
|
77
86
|
default=None, description="Shell prefix that replaces the engine, for tests."
|
|
78
87
|
)
|
|
88
|
+
append_system: str | None = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
description="File whose text each trial adds to the system prompt.",
|
|
91
|
+
)
|
|
79
92
|
|
|
80
93
|
|
|
81
94
|
@functools.cache
|
|
@@ -114,12 +127,20 @@ class ProviderUnavailableError(RuntimeError):
|
|
|
114
127
|
"""The provider refused the turn, so the trial measures nothing about Vis."""
|
|
115
128
|
|
|
116
129
|
|
|
130
|
+
SCORED_PROVIDER_CODES = frozenset({"provider_context_overflow"})
|
|
131
|
+
"""Provider error codes that the agent causes, so the trial keeps its score.
|
|
132
|
+
|
|
133
|
+
A conversation that grows past the context window shows how the agent manages
|
|
134
|
+
its context, for example that it did not fold. Such a trial fails its checks.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
|
|
117
138
|
def provider_failure(trace: Path) -> str | None:
|
|
118
139
|
"""Return the provider error that ended the turn in ``trace``, or None.
|
|
119
140
|
|
|
120
141
|
A provider quota or outage ends the turn with an error block whose code
|
|
121
142
|
starts with ``provider_``. Such a trial is an infrastructure error, not a
|
|
122
|
-
wrong answer.
|
|
143
|
+
wrong answer. The codes in ``SCORED_PROVIDER_CODES`` are not returned.
|
|
123
144
|
"""
|
|
124
145
|
try:
|
|
125
146
|
lines = trace.read_text(encoding="utf-8").splitlines()
|
|
@@ -138,12 +159,21 @@ def provider_failure(trace: Path) -> str | None:
|
|
|
138
159
|
if not isinstance(block, dict) or block.get("type") != "error":
|
|
139
160
|
continue
|
|
140
161
|
code = str(block.get("code"))
|
|
141
|
-
if code.startswith("provider_"):
|
|
162
|
+
if code.startswith("provider_") and code not in SCORED_PROVIDER_CODES:
|
|
142
163
|
return f"{code}: {block.get('title') or 'provider error'}"
|
|
143
164
|
return None
|
|
144
165
|
return None
|
|
145
166
|
|
|
146
167
|
|
|
168
|
+
def _session_id(trajectory: Path) -> str | None:
|
|
169
|
+
"""Return the session id of the trajectory file, or None."""
|
|
170
|
+
try:
|
|
171
|
+
value = json.loads(trajectory.read_text(encoding="utf-8")).get("session_id")
|
|
172
|
+
except (OSError, ValueError, AttributeError):
|
|
173
|
+
return None
|
|
174
|
+
return value if isinstance(value, str) and value else None
|
|
175
|
+
|
|
176
|
+
|
|
147
177
|
def check_native_binary(path: str) -> None:
|
|
148
178
|
"""Refuse a launcher script: the measurement must use the native image."""
|
|
149
179
|
with open(path, "rb") as executable:
|
|
@@ -165,6 +195,10 @@ class VisAgent(BaseAgent):
|
|
|
165
195
|
(``VIS_HARBOR_NATIVE_BIN``), ``source`` (``VIS_HARBOR_SOURCE``). Without them, the
|
|
166
196
|
agent runs the ``vis-agent`` CLI of the SDK's release. When the installed CLI is
|
|
167
197
|
missing or another release, setup downloads that release once into the SDK cache.
|
|
198
|
+
|
|
199
|
+
``append_system`` (``VIS_HARBOR_APPEND_SYSTEM``) names a file. Each trial writes
|
|
200
|
+
its text to ``.vis/APPEND_SYSTEM.md`` in the workspace, so two runs can compare a
|
|
201
|
+
prompt rule on the same tasks. A task that has that file already is an error.
|
|
168
202
|
"""
|
|
169
203
|
|
|
170
204
|
capabilities = AgentCapabilities(atif=True)
|
|
@@ -197,6 +231,12 @@ class VisAgent(BaseAgent):
|
|
|
197
231
|
source = options.source or self._setting("VIS_HARBOR_SOURCE")
|
|
198
232
|
self.source = Path(source).resolve() if source else None
|
|
199
233
|
self.engine_override = options.command
|
|
234
|
+
append_system = options.append_system or self._setting(
|
|
235
|
+
"VIS_HARBOR_APPEND_SYSTEM"
|
|
236
|
+
)
|
|
237
|
+
self.append_system = (
|
|
238
|
+
Path(append_system).read_text(encoding="utf-8") if append_system else None
|
|
239
|
+
)
|
|
200
240
|
self.classpath: str | None = None
|
|
201
241
|
self.installed_command: str | None = None
|
|
202
242
|
self.model_name = f"{self.provider}/{self.model}"
|
|
@@ -229,10 +269,12 @@ class VisAgent(BaseAgent):
|
|
|
229
269
|
return [*arguments, "--persist"]
|
|
230
270
|
|
|
231
271
|
def shell_command(self) -> str:
|
|
232
|
-
"""Return the bash command of one
|
|
272
|
+
"""Return the bash command of one CLI turn.
|
|
233
273
|
|
|
234
274
|
Paths and the prompt stay in environment variables. Then the path
|
|
235
|
-
translation of the host environment cannot change them.
|
|
275
|
+
translation of the host environment cannot change them. A later turn
|
|
276
|
+
continues the session in ``VIS_HARBOR_SESSION_ID``. Each turn appends to the
|
|
277
|
+
trace and the error output.
|
|
236
278
|
"""
|
|
237
279
|
if self.engine_override:
|
|
238
280
|
engine = self.engine_override
|
|
@@ -246,15 +288,30 @@ class VisAgent(BaseAgent):
|
|
|
246
288
|
return (
|
|
247
289
|
"unset VIS_GATEWAY_URL; "
|
|
248
290
|
f"{engine} {arguments} "
|
|
249
|
-
|
|
291
|
+
'${VIS_HARBOR_SESSION_ID:+--session-id "$VIS_HARBOR_SESSION_ID"} '
|
|
292
|
+
'--trajectory "$VIS_HARBOR_AGENT_LOGS/$VIS_HARBOR_TRAJECTORY" '
|
|
250
293
|
'"$VIS_HARBOR_PROMPT" '
|
|
251
|
-
f'
|
|
252
|
-
f'2
|
|
294
|
+
f'>> "$VIS_HARBOR_AGENT_LOGS/{TRACE_FILE}" '
|
|
295
|
+
f'2>> "$VIS_HARBOR_AGENT_LOGS/{STDERR_FILE}"'
|
|
253
296
|
)
|
|
254
297
|
|
|
255
|
-
def process_env(
|
|
256
|
-
|
|
298
|
+
def process_env(
|
|
299
|
+
self,
|
|
300
|
+
instruction: str,
|
|
301
|
+
runtime: Path,
|
|
302
|
+
*,
|
|
303
|
+
trajectory: str = TRAJECTORY_FILE,
|
|
304
|
+
session_id: str | None = None,
|
|
305
|
+
) -> dict[str, str]:
|
|
306
|
+
"""Return the variables of one CLI turn, with a database for this trial.
|
|
307
|
+
|
|
308
|
+
``trajectory`` is the trajectory path relative to the agent logs. With
|
|
309
|
+
``session_id``, the turn continues that session.
|
|
310
|
+
"""
|
|
257
311
|
env = dict(self._extra_env)
|
|
312
|
+
env["VIS_HARBOR_TRAJECTORY"] = trajectory
|
|
313
|
+
if session_id:
|
|
314
|
+
env["VIS_HARBOR_SESSION_ID"] = session_id
|
|
258
315
|
env["VIS_DB_PATH"] = str(runtime / "vis.mdb")
|
|
259
316
|
env["VIS_EXTENSIONS_DIR"] = self._setting("VIS_EXTENSIONS_DIR") or str(
|
|
260
317
|
runtime / "extensions"
|
|
@@ -291,6 +348,11 @@ class VisAgent(BaseAgent):
|
|
|
291
348
|
async def run(
|
|
292
349
|
self, instruction: str, environment: BaseEnvironment, context: AgentContext
|
|
293
350
|
) -> None:
|
|
351
|
+
turns = split_turns(instruction)
|
|
352
|
+
if self.append_system is not None:
|
|
353
|
+
if not isinstance(environment, HostEnvironment):
|
|
354
|
+
raise TypeError("append_system needs the HostEnvironment workspace")
|
|
355
|
+
self._write_append_system(Path(environment.workspace))
|
|
294
356
|
runtime = Path(tempfile.mkdtemp(prefix="vis_harbor_runtime_"))
|
|
295
357
|
record = {
|
|
296
358
|
"provider": self.provider,
|
|
@@ -301,23 +363,81 @@ class VisAgent(BaseAgent):
|
|
|
301
363
|
"is_cancelled": False,
|
|
302
364
|
}
|
|
303
365
|
started = time.monotonic()
|
|
366
|
+
if len(turns) > 1:
|
|
367
|
+
record["turns"] = []
|
|
304
368
|
try:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
369
|
+
if len(turns) == 1:
|
|
370
|
+
result = await environment.exec(
|
|
371
|
+
self.shell_command(), env=self.process_env(instruction, runtime)
|
|
372
|
+
)
|
|
373
|
+
record["exit_code"] = result.return_code
|
|
374
|
+
else:
|
|
375
|
+
await self._run_turns(turns, environment, runtime, record)
|
|
309
376
|
except asyncio.CancelledError:
|
|
310
377
|
record["is_cancelled"] = True
|
|
311
378
|
raise
|
|
312
379
|
finally:
|
|
313
380
|
record["wall_s"] = round(time.monotonic() - started, 3)
|
|
314
381
|
self.logs_dir.mkdir(parents=True, exist_ok=True)
|
|
382
|
+
if len(turns) > 1:
|
|
383
|
+
self._join_turns()
|
|
315
384
|
(self.logs_dir / RUN_FILE).write_text(json.dumps(record, indent=2) + "\n")
|
|
316
385
|
shutil.rmtree(runtime, ignore_errors=True)
|
|
317
386
|
self.populate_context_post_run(context)
|
|
318
387
|
if failure := provider_failure(self.logs_dir / TRACE_FILE):
|
|
319
388
|
raise ProviderUnavailableError(failure)
|
|
320
389
|
|
|
390
|
+
def _write_append_system(self, workspace: Path) -> None:
|
|
391
|
+
target = workspace / ".vis" / "APPEND_SYSTEM.md"
|
|
392
|
+
if target.exists():
|
|
393
|
+
raise ValueError(
|
|
394
|
+
"append_system cannot replace the .vis/APPEND_SYSTEM.md of the task"
|
|
395
|
+
)
|
|
396
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
397
|
+
target.write_text(self.append_system or "", encoding="utf-8")
|
|
398
|
+
|
|
399
|
+
async def _run_turns(
|
|
400
|
+
self,
|
|
401
|
+
turns: list[str],
|
|
402
|
+
environment: BaseEnvironment,
|
|
403
|
+
runtime: Path,
|
|
404
|
+
record: dict,
|
|
405
|
+
) -> None:
|
|
406
|
+
"""Send each message as one turn of one session; stop at a failed turn."""
|
|
407
|
+
(self.logs_dir / TURNS_DIR).mkdir(parents=True, exist_ok=True)
|
|
408
|
+
session_id = None
|
|
409
|
+
for number, message in enumerate(turns, start=1):
|
|
410
|
+
name = f"{TURNS_DIR}/{number}.json"
|
|
411
|
+
env = self.process_env(
|
|
412
|
+
message, runtime, trajectory=name, session_id=session_id
|
|
413
|
+
)
|
|
414
|
+
result = await environment.exec(self.shell_command(), env=env)
|
|
415
|
+
record["exit_code"] = result.return_code
|
|
416
|
+
record["turns"].append({"exit_code": result.return_code})
|
|
417
|
+
if result.return_code != 0 or provider_failure(self.logs_dir / TRACE_FILE):
|
|
418
|
+
return
|
|
419
|
+
if session_id is None:
|
|
420
|
+
session_id = _session_id(self.logs_dir / name)
|
|
421
|
+
if session_id is None:
|
|
422
|
+
raise RuntimeError("the first turn wrote no persisted session id")
|
|
423
|
+
|
|
424
|
+
def _join_turns(self) -> None:
|
|
425
|
+
"""Write ``trajectory.json`` from the trajectories of the finished turns."""
|
|
426
|
+
documents = []
|
|
427
|
+
number = 1
|
|
428
|
+
while (path := self.logs_dir / TURNS_DIR / f"{number}.json").is_file():
|
|
429
|
+
try:
|
|
430
|
+
documents.append(json.loads(path.read_text(encoding="utf-8")))
|
|
431
|
+
except (OSError, ValueError) as error:
|
|
432
|
+
self.logger.warning("Cannot read %s: %s", path, error)
|
|
433
|
+
break
|
|
434
|
+
number += 1
|
|
435
|
+
if documents:
|
|
436
|
+
merged = merge_trajectories(documents)
|
|
437
|
+
(self.logs_dir / TRAJECTORY_FILE).write_text(
|
|
438
|
+
json.dumps(merged, indent=2) + "\n", encoding="utf-8"
|
|
439
|
+
)
|
|
440
|
+
|
|
321
441
|
def populate_context_post_run(self, context: AgentContext) -> None:
|
|
322
442
|
"""Copy the token and cost totals of the trajectory into ``context``."""
|
|
323
443
|
path = self.logs_dir / TRAJECTORY_FILE
|
|
@@ -87,8 +87,9 @@ class BenchReport:
|
|
|
87
87
|
`_ci95` value is a 95% Wilson interval in percent. A second round of the same size
|
|
88
88
|
cannot detect a change below `detectable_change_points`. `attempts_per_task` is the
|
|
89
89
|
most common scored attempt count of a task. When it is more than one,
|
|
90
|
-
`pass_at_k_percent` and `pass_all_k_percent` give the
|
|
91
|
-
least one or all of
|
|
90
|
+
`pass_at_k_percent` and `pass_all_k_percent` give the unbiased pass@k and pass^k with
|
|
91
|
+
that count as k: the chance that at least one or all of k attempts solve a task.
|
|
92
|
+
Each task uses all its scored attempts. Otherwise they are None.
|
|
92
93
|
`unstable_tasks` lists tasks with mixed results. `estimated_metered_cost_usd` and
|
|
93
94
|
`cost_per_solved_usd` use metered API prices. They are not subscription charges.
|
|
94
95
|
"""
|
|
@@ -37,7 +37,7 @@ GIT_SETUP = (
|
|
|
37
37
|
("git", "config", "user.email", "t@t.co"),
|
|
38
38
|
("git", "config", "user.name", "t"),
|
|
39
39
|
("git", "add", "-A"),
|
|
40
|
-
("git", "commit", "-
|
|
40
|
+
("git", "commit", "-q", "--allow-empty", "-m", "init"),
|
|
41
41
|
)
|
|
42
42
|
_SAFE_PATH = re.compile(r"[\w./-]+")
|
|
43
43
|
_BEFORE_PATH = r"(?<![\w./-])"
|
|
@@ -25,6 +25,8 @@ import hashlib
|
|
|
25
25
|
import json
|
|
26
26
|
import os
|
|
27
27
|
import re
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
28
30
|
from collections.abc import Iterable, Mapping
|
|
29
31
|
from dataclasses import dataclass
|
|
30
32
|
from pathlib import Path
|
|
@@ -38,6 +40,7 @@ TRAJECTORY_FILE = "trajectory.json"
|
|
|
38
40
|
RUN_FILE = "run.json"
|
|
39
41
|
REWARD_FILE = "reward.json"
|
|
40
42
|
GRADE_FILE = "grade.json"
|
|
43
|
+
ANSWER_PROGRAM_TIMEOUT_SEC = 120
|
|
41
44
|
|
|
42
45
|
|
|
43
46
|
TERMINAL_ACTIVITY_STATES = {"succeeded", "failed", "cancelled"}
|
|
@@ -1040,6 +1043,32 @@ def _workspace_text(work: str, name: str) -> str:
|
|
|
1040
1043
|
return ""
|
|
1041
1044
|
|
|
1042
1045
|
|
|
1046
|
+
def answer_program_problem(program: str, answer: str, work: str) -> str | None:
|
|
1047
|
+
"""Run the Python file ``program`` on the final answer; return its failure.
|
|
1048
|
+
|
|
1049
|
+
The program gets the answer on its standard input and runs in the workspace
|
|
1050
|
+
``work``. Exit code 0 accepts the answer, and the result is None. Otherwise the
|
|
1051
|
+
result names the last line of the program's error output.
|
|
1052
|
+
"""
|
|
1053
|
+
try:
|
|
1054
|
+
completed = subprocess.run(
|
|
1055
|
+
[sys.executable, program],
|
|
1056
|
+
input=answer,
|
|
1057
|
+
capture_output=True,
|
|
1058
|
+
text=True,
|
|
1059
|
+
cwd=work,
|
|
1060
|
+
timeout=ANSWER_PROGRAM_TIMEOUT_SEC,
|
|
1061
|
+
check=False,
|
|
1062
|
+
)
|
|
1063
|
+
except subprocess.TimeoutExpired:
|
|
1064
|
+
return f"answer program ran longer than {ANSWER_PROGRAM_TIMEOUT_SEC} s"
|
|
1065
|
+
if completed.returncode == 0:
|
|
1066
|
+
return None
|
|
1067
|
+
lines = (completed.stderr or completed.stdout).strip().splitlines()
|
|
1068
|
+
reason = lines[-1] if lines else f"exit code {completed.returncode}"
|
|
1069
|
+
return f"answer program rejected the answer: {reason}"
|
|
1070
|
+
|
|
1071
|
+
|
|
1043
1072
|
def grade_trial(
|
|
1044
1073
|
sc: Mapping[str, Any], work: str | os.PathLike[str], trial: TrialFiles
|
|
1045
1074
|
) -> Grade:
|
|
@@ -1186,6 +1215,10 @@ def grade_trial(
|
|
|
1186
1215
|
for s in sc.get("want_answer") or []:
|
|
1187
1216
|
if s not in answer:
|
|
1188
1217
|
checks.fail("answer", f"answer missing {s!r}")
|
|
1218
|
+
if program := sc.get("want_answer_program"):
|
|
1219
|
+
checks.use("answer")
|
|
1220
|
+
if problem := answer_program_problem(program, answer, work):
|
|
1221
|
+
checks.fail("answer", problem)
|
|
1189
1222
|
if sc.get("want_forms"):
|
|
1190
1223
|
checks.use("forms")
|
|
1191
1224
|
for needle in sc.get("want_forms") or []:
|
|
@@ -1545,6 +1578,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1545
1578
|
if getattr(args, name) is None:
|
|
1546
1579
|
parser.error(f"--{name.replace('_', '-')} is required outside Vis Harbor")
|
|
1547
1580
|
checks = json.loads(args.checks.read_text())
|
|
1581
|
+
if program := checks.get("want_answer_program"):
|
|
1582
|
+
checks["want_answer_program"] = str(args.checks.parent / program)
|
|
1548
1583
|
if args.task:
|
|
1549
1584
|
checks["id"] = args.task
|
|
1550
1585
|
grade = grade_trial(checks, args.workspace, load_trial(args.agent_logs))
|