harness-run 0.4.0__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.
- harness_run-0.4.0/.dockerignore +12 -0
- harness_run-0.4.0/.github/workflows/ci.yml +40 -0
- harness_run-0.4.0/.github/workflows/publish.yml +104 -0
- harness_run-0.4.0/.gitignore +13 -0
- harness_run-0.4.0/CHANGELOG.md +50 -0
- harness_run-0.4.0/DESIGN.md +932 -0
- harness_run-0.4.0/LICENSE +202 -0
- harness_run-0.4.0/Makefile +85 -0
- harness_run-0.4.0/PKG-INFO +248 -0
- harness_run-0.4.0/README.md +216 -0
- harness_run-0.4.0/SECURITY.md +27 -0
- harness_run-0.4.0/TESTING.md +343 -0
- harness_run-0.4.0/dev/Dockerfile +44 -0
- harness_run-0.4.0/dev/README.md +53 -0
- harness_run-0.4.0/dev/chat.py +354 -0
- harness_run-0.4.0/dev/live_interactive_probe.py +210 -0
- harness_run-0.4.0/dev/live_limits_probe.py +375 -0
- harness_run-0.4.0/dev/live_model_attribution.py +224 -0
- harness_run-0.4.0/dev/live_openrouter_probe.py +560 -0
- harness_run-0.4.0/dev/live_openrouter_remote_probe.py +653 -0
- harness_run-0.4.0/dev/live_resume_probe.py +81 -0
- harness_run-0.4.0/dev/live_smoke.py +639 -0
- harness_run-0.4.0/dev/live_two_turn_probe.py +92 -0
- harness_run-0.4.0/dev/live_usage_probe.py +239 -0
- harness_run-0.4.0/dev/openrouter_endpoints.py +153 -0
- harness_run-0.4.0/docs/configuration.md +221 -0
- harness_run-0.4.0/docs/gcp-setup.md +129 -0
- harness_run-0.4.0/docs/getting-started.md +128 -0
- harness_run-0.4.0/docs/harnesses-and-models.md +110 -0
- harness_run-0.4.0/docs/local-runtime.md +118 -0
- harness_run-0.4.0/docs/observability.md +94 -0
- harness_run-0.4.0/docs/openrouter.md +259 -0
- harness_run-0.4.0/docs/runs-and-sessions.md +206 -0
- harness_run-0.4.0/docs/sandbox-runtime.md +169 -0
- harness_run-0.4.0/docs/secrets-and-security.md +131 -0
- harness_run-0.4.0/docs/structured-output.md +29 -0
- harness_run-0.4.0/examples/minimal/README.md +43 -0
- harness_run-0.4.0/examples/minimal/agent.py +73 -0
- harness_run-0.4.0/examples/sandbox/README.md +37 -0
- harness_run-0.4.0/examples/sandbox/deploy_and_run.py +132 -0
- harness_run-0.4.0/harness_run/__init__.py +41 -0
- harness_run-0.4.0/harness_run/checkpoint/__init__.py +12 -0
- harness_run-0.4.0/harness_run/checkpoint/session_store.py +136 -0
- harness_run-0.4.0/harness_run/checkpoint/workspace.py +122 -0
- harness_run-0.4.0/harness_run/config.py +331 -0
- harness_run-0.4.0/harness_run/conformance.py +196 -0
- harness_run-0.4.0/harness_run/control.py +278 -0
- harness_run-0.4.0/harness_run/events.py +116 -0
- harness_run-0.4.0/harness_run/harness/__init__.py +37 -0
- harness_run-0.4.0/harness_run/harness/_local_sdk.py +32 -0
- harness_run-0.4.0/harness_run/harness/_openrouter_proxy.py +538 -0
- harness_run-0.4.0/harness_run/harness/_shared.py +307 -0
- harness_run-0.4.0/harness_run/harness/_usage.py +113 -0
- harness_run-0.4.0/harness_run/harness/base.py +36 -0
- harness_run-0.4.0/harness_run/harness/claude_code.py +1046 -0
- harness_run-0.4.0/harness_run/harness/codex.py +1482 -0
- harness_run-0.4.0/harness_run/harness/context.py +107 -0
- harness_run-0.4.0/harness_run/harness/pricing.py +141 -0
- harness_run-0.4.0/harness_run/harness/translate.py +204 -0
- harness_run-0.4.0/harness_run/integrations/__init__.py +28 -0
- harness_run-0.4.0/harness_run/integrations/git.py +203 -0
- harness_run-0.4.0/harness_run/integrations/github.py +17 -0
- harness_run-0.4.0/harness_run/ports/__init__.py +20 -0
- harness_run-0.4.0/harness_run/ports/blobstore.py +296 -0
- harness_run-0.4.0/harness_run/ports/secrets.py +57 -0
- harness_run-0.4.0/harness_run/runtime/__init__.py +11 -0
- harness_run-0.4.0/harness_run/runtime/_run.py +232 -0
- harness_run-0.4.0/harness_run/runtime/base.py +295 -0
- harness_run-0.4.0/harness_run/runtime/local.py +616 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/__init__.py +17 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/_image.py +291 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/backend.py +2004 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/handoff.py +201 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/history.py +149 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/model_token.py +80 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/project_setup.py +1359 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/provider.py +468 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/resources.py +292 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/roster.py +237 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/scoped_gcs.py +288 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/stream.py +264 -0
- harness_run-0.4.0/harness_run/runtime/sandbox/worker.py +806 -0
- harness_run-0.4.0/harness_run/runtime/venv.py +102 -0
- harness_run-0.4.0/harness_run/skills.py +106 -0
- harness_run-0.4.0/harness_run/spec.py +604 -0
- harness_run-0.4.0/harness_run/structured.py +89 -0
- harness_run-0.4.0/pyproject.toml +93 -0
- harness_run-0.4.0/tests/codex_fakes.py +284 -0
- harness_run-0.4.0/tests/conftest.py +59 -0
- harness_run-0.4.0/tests/fakes.py +133 -0
- harness_run-0.4.0/tests/sandbox_fakes.py +223 -0
- harness_run-0.4.0/tests/test_background_tasks.py +664 -0
- harness_run-0.4.0/tests/test_blobstore.py +146 -0
- harness_run-0.4.0/tests/test_cab_literals.py +35 -0
- harness_run-0.4.0/tests/test_checkpoint_events.py +94 -0
- harness_run-0.4.0/tests/test_checkpoint_secrets.py +32 -0
- harness_run-0.4.0/tests/test_claude_resume.py +99 -0
- harness_run-0.4.0/tests/test_client_credentials.py +79 -0
- harness_run-0.4.0/tests/test_codex_checkpoint_failures.py +134 -0
- harness_run-0.4.0/tests/test_codex_harness.py +1511 -0
- harness_run-0.4.0/tests/test_codex_policy.py +28 -0
- harness_run-0.4.0/tests/test_config.py +241 -0
- harness_run-0.4.0/tests/test_config_secrets.py +61 -0
- harness_run-0.4.0/tests/test_config_transport.py +158 -0
- harness_run-0.4.0/tests/test_control.py +624 -0
- harness_run-0.4.0/tests/test_dev_probe_teardown.py +136 -0
- harness_run-0.4.0/tests/test_dispatch_ownership.py +452 -0
- harness_run-0.4.0/tests/test_exec.py +264 -0
- harness_run-0.4.0/tests/test_handoff.py +117 -0
- harness_run-0.4.0/tests/test_harness_conformance.py +101 -0
- harness_run-0.4.0/tests/test_harness_options.py +511 -0
- harness_run-0.4.0/tests/test_history.py +89 -0
- harness_run-0.4.0/tests/test_local_extra.py +84 -0
- harness_run-0.4.0/tests/test_local_runtime.py +573 -0
- harness_run-0.4.0/tests/test_local_venv.py +140 -0
- harness_run-0.4.0/tests/test_openrouter_endpoints.py +7 -0
- harness_run-0.4.0/tests/test_openrouter_proxy.py +623 -0
- harness_run-0.4.0/tests/test_project_setup.py +598 -0
- harness_run-0.4.0/tests/test_provider_templates.py +169 -0
- harness_run-0.4.0/tests/test_reattach_config.py +48 -0
- harness_run-0.4.0/tests/test_reattach_running_turn.py +428 -0
- harness_run-0.4.0/tests/test_repos.py +91 -0
- harness_run-0.4.0/tests/test_resources.py +132 -0
- harness_run-0.4.0/tests/test_retention.py +45 -0
- harness_run-0.4.0/tests/test_roster.py +165 -0
- harness_run-0.4.0/tests/test_sandbox_deploy.py +328 -0
- harness_run-0.4.0/tests/test_sandbox_runtime.py +867 -0
- harness_run-0.4.0/tests/test_scoped_gcs.py +372 -0
- harness_run-0.4.0/tests/test_session_cleanup.py +145 -0
- harness_run-0.4.0/tests/test_session_store.py +19 -0
- harness_run-0.4.0/tests/test_skills.py +55 -0
- harness_run-0.4.0/tests/test_spec.py +201 -0
- harness_run-0.4.0/tests/test_stderr_capture.py +99 -0
- harness_run-0.4.0/tests/test_stream.py +231 -0
- harness_run-0.4.0/tests/test_structured.py +46 -0
- harness_run-0.4.0/tests/test_token_refresh.py +191 -0
- harness_run-0.4.0/tests/test_translate.py +108 -0
- harness_run-0.4.0/tests/test_turn_boundaries.py +185 -0
- harness_run-0.4.0/tests/test_usage.py +83 -0
- harness_run-0.4.0/tests/test_warm_pool.py +260 -0
- harness_run-0.4.0/tests/test_worker_metadata_server.py +103 -0
- harness_run-0.4.0/tests/test_workspace.py +139 -0
- harness_run-0.4.0/tests/test_zero_budget.py +43 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# All tests are offline unit tests (fake harness, mocked GCP/uv/git-over-network) — CI
|
|
4
|
+
# needs no cloud credentials or API keys and bills nothing beyond the runner. Keep it
|
|
5
|
+
# that way: anything that talks to Vertex/Anthropic belongs in a manually-run script,
|
|
6
|
+
# not under `pytest -q`.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main] # PRs are covered by the pull_request trigger — no double runs
|
|
11
|
+
pull_request:
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 15
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
python-version: ["3.12", "3.13"] # full requires-python range (>=3.12,<3.14)
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v5
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
cache-dependency-glob: pyproject.toml # no lockfile — key the cache off deps
|
|
35
|
+
- name: Install (runtime + dev group)
|
|
36
|
+
run: uv pip install --system -e . --group dev
|
|
37
|
+
- name: Lint
|
|
38
|
+
run: ruff check .
|
|
39
|
+
- name: Test
|
|
40
|
+
run: pytest -q -n auto
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes a release to PyPI, https://pypi.org/project/harness-run/, through PyPI's Trusted
|
|
4
|
+
# Publishing (OpenID Connect): no API token is stored in this repository. PyPI is configured
|
|
5
|
+
# to trust this exact workflow file in this repository when it runs in the `pypi` GitHub
|
|
6
|
+
# environment; that trust is set up on the PyPI project's Publishing page, not here. TestPyPI
|
|
7
|
+
# trusts the same file in the `testpypi` environment.
|
|
8
|
+
#
|
|
9
|
+
# A release is a tag `vX.Y.Z` on `main`, and X.Y.Z must equal `version` in pyproject.toml
|
|
10
|
+
# (the build job refuses otherwise; see the release checklist at the top of CHANGELOG.md).
|
|
11
|
+
# Plain pushes publish nothing. Running the workflow by hand (workflow_dispatch) publishes the
|
|
12
|
+
# checked-out version to TestPyPI instead, as a dry run of the release path:
|
|
13
|
+
# pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ harness-run==X.Y.Z
|
|
14
|
+
# TestPyPI never accepts the same version twice, so a repeated dry run needs a version bump.
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
tags: ["v[0-9]*"]
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
concurrency:
|
|
25
|
+
group: publish-${{ github.ref }}
|
|
26
|
+
cancel-in-progress: false # never cancel an upload half-way
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
build:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
timeout-minutes: 10
|
|
32
|
+
outputs:
|
|
33
|
+
version: ${{ steps.version.outputs.version }}
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.12"
|
|
39
|
+
- name: Install uv
|
|
40
|
+
uses: astral-sh/setup-uv@v5
|
|
41
|
+
|
|
42
|
+
- name: Check the tag against pyproject.toml
|
|
43
|
+
id: version
|
|
44
|
+
run: |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
declared=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
|
47
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
48
|
+
if [[ "$GITHUB_REF_TYPE" == "tag" && "$tag" != "$declared" ]]; then
|
|
49
|
+
echo "::error::tag $GITHUB_REF_NAME does not match pyproject version $declared; bump the version first (CHANGELOG.md, release checklist)"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
echo "version=$declared" >> "$GITHUB_OUTPUT"
|
|
53
|
+
echo "building harness-run $declared"
|
|
54
|
+
|
|
55
|
+
- name: Build sdist and wheel
|
|
56
|
+
run: |
|
|
57
|
+
set -euo pipefail
|
|
58
|
+
uv build
|
|
59
|
+
uvx twine check --strict dist/*
|
|
60
|
+
ls -l dist/
|
|
61
|
+
|
|
62
|
+
- uses: actions/upload-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: dist
|
|
65
|
+
path: dist/
|
|
66
|
+
if-no-files-found: error
|
|
67
|
+
|
|
68
|
+
publish:
|
|
69
|
+
if: github.ref_type == 'tag'
|
|
70
|
+
needs: build
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
timeout-minutes: 10
|
|
73
|
+
environment:
|
|
74
|
+
name: pypi
|
|
75
|
+
url: https://pypi.org/project/harness-run/${{ needs.build.outputs.version }}/
|
|
76
|
+
permissions:
|
|
77
|
+
id-token: write # mint the OIDC token PyPI exchanges for a short-lived upload token
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/download-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: dist
|
|
82
|
+
path: dist/
|
|
83
|
+
- name: Upload to PyPI
|
|
84
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
85
|
+
|
|
86
|
+
publish-testpypi:
|
|
87
|
+
if: github.event_name == 'workflow_dispatch'
|
|
88
|
+
needs: build
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
timeout-minutes: 10
|
|
91
|
+
environment:
|
|
92
|
+
name: testpypi
|
|
93
|
+
url: https://test.pypi.org/project/harness-run/${{ needs.build.outputs.version }}/
|
|
94
|
+
permissions:
|
|
95
|
+
id-token: write
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/download-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: dist
|
|
100
|
+
path: dist/
|
|
101
|
+
- name: Upload to TestPyPI
|
|
102
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
103
|
+
with:
|
|
104
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `harness-run` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
Versioning is [SemVer](https://semver.org/)-style with the usual 0.x caveat:
|
|
7
|
+
**minor releases (0.X) may contain backwards-incompatible changes**; patch
|
|
8
|
+
releases (0.X.Y) do not. Every incompatible change is listed under a
|
|
9
|
+
**Backwards-incompatible** heading together with update notes describing how to
|
|
10
|
+
migrate.
|
|
11
|
+
|
|
12
|
+
Releases are git tags (`vX.Y.Z`) on `main`, published to [PyPI](https://pypi.org/project/harness-run/)
|
|
13
|
+
by `.github/workflows/publish.yml` through PyPI's Trusted Publishing; install a specific release with
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pip install "harness-run==X.Y.Z"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Release checklist: update this file (move the `Unreleased` section into a new
|
|
20
|
+
version heading with the date), bump `version` in `pyproject.toml`, merge that
|
|
21
|
+
commit to `main` (PR), tag the merge commit `vX.Y.Z` and push the tag. The
|
|
22
|
+
publish workflow refuses a tag whose version differs from `pyproject.toml`; once
|
|
23
|
+
it has uploaded the release, create the GitHub Release for the tag with this
|
|
24
|
+
file's section as the notes.
|
|
25
|
+
|
|
26
|
+
The workflow needs no token: PyPI and TestPyPI trust `publish.yml` from this repository
|
|
27
|
+
running in the `pypi` and `testpypi` GitHub environments (Trusted Publishing, configured on
|
|
28
|
+
the PyPI side under the project's Publishing settings and on the GitHub side under Settings
|
|
29
|
+
→ Environments). To rehearse a release, run the workflow by hand from the Actions tab or with
|
|
30
|
+
`gh workflow run publish.yml`: it builds the checked-out version and uploads it to TestPyPI
|
|
31
|
+
only, where it can be checked with
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "harness-run==X.Y.Z"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
TestPyPI never accepts the same version twice, so a second rehearsal needs a version bump.
|
|
38
|
+
|
|
39
|
+
## 0.4.0 — 2026-09-23
|
|
40
|
+
|
|
41
|
+
First public release.
|
|
42
|
+
|
|
43
|
+
`harness-run` was developed at [Zyte](https://www.zyte.com) as an internal library
|
|
44
|
+
(`remote-agent-toolkit`, versions 0.1.0–0.3.1) and is released here under the Apache-2.0
|
|
45
|
+
license with a new name. It runs coding agents — Claude Code and Codex, with Anthropic, OpenAI,
|
|
46
|
+
Vertex AI and OpenRouter models — locally and in GCP Agent Sandbox through one API: declarative
|
|
47
|
+
`AgentSpec`s, multi-turn sessions with checkpoint/resume, streaming events, structured output,
|
|
48
|
+
skills, MCP servers, repository setup, per-run secrets and usage/cost reporting. The
|
|
49
|
+
[README](README.md) and [docs/](docs/) describe the release; the development history before it
|
|
50
|
+
is in the git log.
|