feat: route profiled ops runs through Glas

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02b6f-7db1-7222-918b-e813a6bda38d
This commit is contained in:
tegwick 2026-08-22 23:55:29 +02:00
parent 68ab94581a
commit 0f01c3e421
17 changed files with 895 additions and 11 deletions

View file

@ -14,9 +14,9 @@
## Developer Workflow
```bash
# Install (editable, pulls in the llm-connect sibling checkout)
# Install (editable, including the governed profile-execution siblings)
python3 -m venv .venv && source .venv/bin/activate
pip install -e . -e ../llm-connect pytest
pip install -e . -e ../llm-connect -e ../sand-boxer -e ../glas-harness pytest
# Test
PYTHONPATH=".:$HOME/llm-connect" python3 -m pytest tests/ -q

View file

@ -28,6 +28,6 @@ image-export: image ## Save image tar for k3s import
deploy-rsync: ## Rsync tree to railiance01:~/rein-aharness
rsync -az --delete \
--exclude '.git' --exclude '__pycache__' --exclude '.pytest_cache' \
--exclude '.git' --exclude '.venv' --exclude '__pycache__' --exclude '.pytest_cache' \
--exclude 'llm_connect_vendor' --exclude '*.egg-info' \
./ railiance01:rein-aharness/

View file

@ -58,6 +58,11 @@ rein-aharness claim-loop
# Install user service: ./deploy/scripts/install-claim-loop-user.sh
# Docs: docs/ops-run-claim-loop.md
# A queued harness_profile_ref is authoritative: the claim worker builds a
# Glas ExecutionRequest and invokes its resolver/gateway. Install the sibling
# runtime packages in the claim-loop venv:
pip install -e ../sand-boxer -e ../glas-harness
# Legacy: issue-core tickets (external / Forgejo projection only — not FI/Binky ops)
export ISSUE_CORE_URL=http://127.0.0.1:8765 ISSUE_CORE_API_KEY=…
rein-aharness poll --source=issue-core

View file

@ -13,6 +13,7 @@
| workplan | REIN-A-0001 | finished | — | workplans/REIN-A-0001-statehub-bootstrap.md |
| workplan | REIN-A-0002 | finished | — | workplans/REIN-A-0002-ops-run-claim-loop.md |
| workplan | REIN-A-0003 | finished | — | workplans/REIN-A-0003-binky-weekly-review-approach.md |
| workplan | REIN-A-0004 | active | — | workplans/REIN-A-0004-glas-profiled-ops-runs.md |
| task | HARNESS-WP-0001-T01 | done | — | workplans/HARNESS-WP-0001-harness-foundation.md |
| task | HARNESS-WP-0001-T02 | done | — | workplans/HARNESS-WP-0001-harness-foundation.md |
| task | HARNESS-WP-0001-T03 | done | — | workplans/HARNESS-WP-0001-harness-foundation.md |
@ -36,3 +37,7 @@
| task | REIN-A-0003-T01 | done | — | workplans/REIN-A-0003-binky-weekly-review-approach.md |
| task | REIN-A-0003-T02 | done | — | workplans/REIN-A-0003-binky-weekly-review-approach.md |
| task | REIN-A-0003-T03 | done | — | workplans/REIN-A-0003-binky-weekly-review-approach.md |
| task | REIN-A-0004-T01 | done | — | workplans/REIN-A-0004-glas-profiled-ops-runs.md |
| task | REIN-A-0004-T02 | done | — | workplans/REIN-A-0004-glas-profiled-ops-runs.md |
| task | REIN-A-0004-T03 | done | — | workplans/REIN-A-0004-glas-profiled-ops-runs.md |
| task | REIN-A-0004-T04 | progress | — | workplans/REIN-A-0004-glas-profiled-ops-runs.md |

View file

@ -24,7 +24,10 @@ fi
# Ensure package entrypoint exists
if [[ ! -x "${ROOT}/.venv/bin/rein-aharness" ]]; then
echo "warning: ${ROOT}/.venv/bin/rein-aharness missing; install with: cd ${ROOT} && uv sync"
echo "warning: ${ROOT}/.venv/bin/rein-aharness missing; install the worker environment first"
elif ! "${ROOT}/.venv/bin/python" -c 'import glas_harness, sandboxer' >/dev/null 2>&1; then
echo "warning: profiled ops runs require sibling runtimes; install with:"
echo " ${ROOT}/.venv/bin/pip install -e ${ROOT}/../sand-boxer -e ${ROOT}/../glas-harness"
fi
systemctl --user daemon-reload

View file

@ -9,16 +9,24 @@ Does **not** require issue-core or Forgejo for FI / Binky-style ops.
```text
activity-core emit_tasks
→ INSERT ops_run (open) + dual-write activity_task_spawn
→ INSERT ops_run (open, optional harness_profile_ref) + activity_task_spawn
rein-aharness claim-loop
POST /ops-runs/claim
select_approach(labels, definition, hint)
execute (fi-research-brief | brief-daily | mail-* | agent-session)
harness_profile_ref present? ─ yes → Glas ExecutionRequest → gateway
│ no
└─→ select_approach(labels, definition, hint) → legacy executor
POST complete | fail(+reopen)
```
`harness_profile_ref` is authoritative under ACT-ADR-006. A profiled row never
consults `approach_hint`, `select_approach`, or a legacy executor, including
after profile resolution refusal. The claim worker sends the complete
`GatewayResult` to Activity Core; Activity Core persists its allowlisted
`ExecutionEvidence` and drops direct tool output/error. Profile-absent rows keep
the legacy coexistence path until the migration flag is enabled upstream.
## Environment
| Variable | Default | Meaning |
@ -55,7 +63,8 @@ export ACTIVITY_CORE_WORKER_TOKEN=… # from actcore-runtime-secre
| labels `agent-session` | agentic `run` (TaskSpec) |
| none | fail ops_run (no silent drop) |
Optional `approach_hint` on the ops_run overrides matching.
For a profile-absent legacy row, optional `approach_hint` overrides matching.
It has no effect when `harness_profile_ref` is present.
Add a row: edit `rein_aharness/approaches.py` (`APPROACH_RULES` + `execute_approach`)
and tests in `tests/test_approaches.py`. Prefer cheapest correct path
@ -91,6 +100,8 @@ rein-aharness run --from-issue-core
```bash
# From rein-aharness checkout on railiance01
python3 -m venv .venv
.venv/bin/pip install -e . -e ../llm-connect -e ../sand-boxer -e ../glas-harness
./deploy/scripts/install-claim-loop-user.sh
# Or manually:

View file

@ -13,9 +13,12 @@ rein-aharness = "rein_aharness.cli:main"
[tool.uv.sources]
llm-connect = { path = "../llm-connect", editable = true }
glas-harness = { path = "../glas-harness", editable = true }
sandboxer = { path = "../sand-boxer", editable = true }
[project.optional-dependencies]
llm = ["llm-connect"]
glas = ["glas-harness", "sandboxer"]
dev = ["pytest>=8"]
[build-system]

View file

@ -23,6 +23,11 @@ from rein_aharness.approaches import (
execute_approach,
select_approach,
)
from rein_aharness.glas_execution import (
GLAS_APPROACH,
GlasExecutionError,
execute_profiled_run,
)
from rein_aharness.ops_run_client import (
ActivityCoreOpsClient,
OpsRun,
@ -105,7 +110,7 @@ def process_one(
return ProcessResult(claimed=False, empty=True, reason="queue empty")
run = claimed[0]
approach = select_approach(run)
approach = GLAS_APPROACH if run.harness_profile_ref else select_approach(run)
logger.info(
"claimed run_id=%s approach=%s title=%r labels=%s",
run.id,
@ -140,6 +145,13 @@ def process_one(
detail={"dry_run": True},
)
if run.harness_profile_ref:
return _process_profiled_run(
client,
run,
report_to_hub=report_to_hub,
)
hb = _Heartbeat(client, run.id, cfg.lease_seconds)
hb.start()
try:
@ -207,6 +219,84 @@ def process_one(
)
def _process_profiled_run(
client: ActivityCoreOpsClient,
run: OpsRun,
*,
report_to_hub: bool,
) -> ProcessResult:
"""Execute a profiled row without consulting or falling back to legacy routing."""
hb = _Heartbeat(client, run.id, client.config.lease_seconds)
hb.start()
try:
try:
gateway_result = execute_profiled_run(
run,
client.config,
report_to_hub=report_to_hub,
)
except GlasExecutionError as exc:
reason = str(exc)
try:
out = client.fail(
run.id,
error=reason,
reopen=False,
result={"ok": False, "approach": GLAS_APPROACH, "reason": reason},
)
except OpsRunError as close_exc:
return ProcessResult(
claimed=True,
run_id=run.id,
approach=GLAS_APPROACH,
ok=False,
reason=f"close ops_run failed: {close_exc}; {reason}",
)
return ProcessResult(
claimed=True,
run_id=run.id,
approach=GLAS_APPROACH,
ok=False,
reason=reason,
ops_state=out.state,
)
finally:
hb.stop()
evidence = gateway_result["evidence"]
ok = gateway_result["ok"]
reason = str(evidence.get("error") or evidence.get("outcome") or "Glas execution failed")
try:
if ok:
out = client.complete(run.id, result=gateway_result)
else:
out = client.fail(
run.id,
error=reason,
reopen=False,
result=gateway_result,
)
except OpsRunError as exc:
return ProcessResult(
claimed=True,
run_id=run.id,
approach=GLAS_APPROACH,
ok=False,
reason=f"close ops_run failed: {exc}; gateway_ok={ok} {reason}",
detail={"execution_evidence": evidence},
)
return ProcessResult(
claimed=True,
run_id=run.id,
approach=GLAS_APPROACH,
ok=ok,
reason="" if ok else reason,
ops_state=out.state,
detail={"execution_evidence": evidence},
)
def poll_peek(client: ActivityCoreOpsClient | None = None) -> list[dict[str, Any]]:
"""List open ops_runs with selected approach (no claim)."""
client = client or ActivityCoreOpsClient()
@ -220,7 +310,10 @@ def poll_peek(client: ActivityCoreOpsClient | None = None) -> list[dict[str, Any
"state": run.state,
"labels": run.labels,
"target_repo": run.target_repo,
"approach": select_approach(run),
"approach": (
GLAS_APPROACH if run.harness_profile_ref else select_approach(run)
),
"harness_profile_ref": run.harness_profile_ref,
"created_at": run.raw.get("created_at"),
}
)

View file

@ -0,0 +1,91 @@
"""Profile-authoritative execution of activity-core ops runs through Glas.
Glas and sand-boxer are sibling runtime packages rather than hard dependencies
of rein-aharness's legacy paths. Imports therefore stay at the execution edge:
profile-absent coexistence continues to work, while a profiled row fails closed
with an actionable error if the governed runtime is not installed.
"""
from __future__ import annotations
from collections.abc import Callable
from typing import Any
from rein_aharness.ops_run_client import OpsRun, OpsRunConfig, resolve_ops_target
GLAS_APPROACH = "glas-profile"
_SCALAR_REFS = (
"correlation_id",
"assignment_ref",
"role_ref",
"duty_ref",
)
_LIST_REFS = ("goal_refs", "resource_envelope_refs")
class GlasExecutionError(RuntimeError):
"""The authoritative Glas invocation could not produce a GatewayResult."""
def _request_kwargs(run: OpsRun, config: OpsRunConfig, report_to_hub: bool) -> dict[str, Any]:
if not run.harness_profile_ref:
raise GlasExecutionError(f"ops_run {run.id} has no harness_profile_ref")
refs = run.execution_refs
kwargs: dict[str, Any] = {
"harness_profile_ref": run.harness_profile_ref,
"repo": str(resolve_ops_target(run, config)),
"title": run.title or "(untitled)",
"description": run.description or "",
"actor": config.worker_id,
"project": "rein-aharness",
"request_id": run.id,
"report_to_hub": report_to_hub,
}
for key in _SCALAR_REFS:
value = refs.get(key)
if isinstance(value, str) and value:
kwargs[key] = value
for key in _LIST_REFS:
value = refs.get(key)
if isinstance(value, list):
kwargs[key] = [item for item in value if isinstance(item, str)]
return kwargs
def execute_profiled_run(
run: OpsRun,
config: OpsRunConfig,
*,
report_to_hub: bool = True,
request_factory: Callable[..., Any] | None = None,
gateway: Callable[[Any], Any] | None = None,
) -> dict[str, Any]:
"""Invoke Glas and return its complete JSON-compatible GatewayResult."""
if request_factory is None or gateway is None:
try:
from glas_harness.contract import ExecutionRequest
from glas_harness.gateway import run_execution
except ImportError as exc:
raise GlasExecutionError(
"profiled ops_run requires glas-harness with sand-boxer support; "
"install the sibling checkouts into the claim-worker environment"
) from exc
request_factory = request_factory or ExecutionRequest
gateway = gateway or run_execution
try:
request = request_factory(**_request_kwargs(run, config, report_to_hub))
result = gateway(request)
raw = result.model_dump(mode="json") if hasattr(result, "model_dump") else result
except GlasExecutionError:
raise
except Exception as exc:
raise GlasExecutionError(f"Glas gateway invocation failed: {exc}") from exc
if not isinstance(raw, dict) or not isinstance(raw.get("ok"), bool):
raise GlasExecutionError("Glas gateway returned an invalid GatewayResult")
if not isinstance(raw.get("evidence"), dict):
raise GlasExecutionError("Glas GatewayResult is missing execution evidence")
return raw

View file

@ -28,6 +28,8 @@ _SAFE_RESPONSE_METADATA_KEYS = frozenset(
"created_at",
}
)
_SAFE_ERROR_KEYS = ("error", "provider_status", "provider", "model")
_MAX_ERROR_MESSAGE_CHARS = 400
class LLMConnectError(RuntimeError):
@ -60,9 +62,10 @@ class LLMConnectClient:
json=payload,
timeout=self.timeout_seconds,
)
resp.raise_for_status()
except httpx.HTTPError as exc:
raise LLMConnectError(f"llm-connect request failed: {exc}") from exc
if resp.status_code >= 400:
raise LLMConnectError(_llm_connect_error_text(resp))
try:
data = resp.json()
except ValueError as exc:
@ -74,6 +77,27 @@ class LLMConnectClient:
return content
def _llm_connect_error_text(resp: httpx.Response) -> str:
"""Keep llm-connect's safe cause without copying an upstream response blob."""
base = f"llm-connect returned HTTP {resp.status_code}"
try:
body = resp.json()
except ValueError:
return base
if not isinstance(body, dict):
return base
parts = [
f"{key}={body[key]}"
for key in _SAFE_ERROR_KEYS
if body.get(key) not in (None, "")
]
message = body.get("message")
if isinstance(message, str) and message.strip():
parts.append(f"message={message.strip()[:_MAX_ERROR_MESSAGE_CHARS]}")
return f"{base}: " + "; ".join(parts) if parts else base
def get_llm_connect_client() -> LLMConnectClient:
base_url = os.environ.get("LLM_CONNECT_URL", "").strip()
if not base_url:

View file

@ -56,6 +56,8 @@ class OpsRun:
source_id: str = ""
triggering_event_id: str = ""
approach_hint: str | None = None
harness_profile_ref: str | None = None
execution_refs: dict[str, Any] = field(default_factory=dict)
result: dict[str, Any] = field(default_factory=dict)
raw: dict[str, Any] = field(default_factory=dict)
@ -78,6 +80,8 @@ class OpsRun:
source_id=str(data.get("source_id") or ""),
triggering_event_id=str(data.get("triggering_event_id") or ""),
approach_hint=data.get("approach_hint"),
harness_profile_ref=data.get("harness_profile_ref"),
execution_refs=dict(data.get("execution_refs") or {}),
result=dict(data.get("result") or {}),
raw=data,
)

View file

@ -6,6 +6,7 @@ from unittest.mock import MagicMock, patch
from rein_aharness.approaches import ApproachResult, APPROACH_FI_RESEARCH_BRIEF
from rein_aharness.claim_loop import process_one, poll_peek
from rein_aharness.glas_execution import GLAS_APPROACH, GlasExecutionError
from rein_aharness.ops_run_client import OpsRun, OpsRunConfig, ActivityCoreOpsClient
@ -95,3 +96,90 @@ def test_poll_peek() -> None:
rows = poll_peek(client)
assert len(rows) == 1
assert rows[0]["approach"] == APPROACH_FI_RESEARCH_BRIEF
def test_profiled_run_uses_glas_and_completes_with_full_result() -> None:
client = MagicMock(spec=ActivityCoreOpsClient)
client.config = OpsRunConfig(worker_id="w", lease_seconds=90)
run = _claimed_run()
run.harness_profile_ref = "harness.agent-dev-local@1.0.0"
run.approach_hint = "fi-research-brief"
client.claim.return_value = [run]
client.complete.return_value = OpsRun(
id=run.id,
activity_definition_id="def",
idempotency_key="k",
target_repo=run.target_repo,
title=run.title,
description="",
state="succeeded",
)
gateway_result = {
"ok": True,
"evidence": {
"outcome": "succeeded",
"profile_ref": run.harness_profile_ref,
"sandbox_id": "sbx-1",
},
"tool_output": "not copied into ProcessResult.detail",
"tool_error": None,
}
with (
patch("rein_aharness.claim_loop.execute_profiled_run", return_value=gateway_result),
patch("rein_aharness.claim_loop.select_approach") as select,
patch("rein_aharness.claim_loop.execute_approach") as execute,
):
result = process_one(client)
assert result.ok is True
assert result.approach == GLAS_APPROACH
assert result.detail == {"execution_evidence": gateway_result["evidence"]}
client.complete.assert_called_once_with(run.id, result=gateway_result)
client.fail.assert_not_called()
select.assert_not_called()
execute.assert_not_called()
def test_profile_refusal_fails_terminally_without_legacy_fallback() -> None:
client = MagicMock(spec=ActivityCoreOpsClient)
client.config = OpsRunConfig(worker_id="w", lease_seconds=90)
run = _claimed_run()
run.harness_profile_ref = "harness.unknown@9.9.9"
run.approach_hint = "fi-research-brief"
client.claim.return_value = [run]
client.fail.return_value = OpsRun(
id=run.id,
activity_definition_id="def",
idempotency_key="k",
target_repo=run.target_repo,
title=run.title,
description="",
state="failed",
)
with (
patch(
"rein_aharness.claim_loop.execute_profiled_run",
side_effect=GlasExecutionError("unknown harness profile"),
),
patch("rein_aharness.claim_loop.select_approach") as select,
patch("rein_aharness.claim_loop.execute_approach") as execute,
):
result = process_one(client)
assert result.ok is False
assert result.ops_state == "failed"
assert client.fail.call_args.kwargs["reopen"] is False
select.assert_not_called()
execute.assert_not_called()
def test_poll_peek_reports_authoritative_profile_route() -> None:
client = MagicMock(spec=ActivityCoreOpsClient)
run = _claimed_run()
run.harness_profile_ref = "harness.agent-dev-local@1.0.0"
client.list_open.return_value = [run]
with patch("rein_aharness.claim_loop.select_approach") as select:
rows = poll_peek(client)
assert rows[0]["approach"] == GLAS_APPROACH
assert rows[0]["harness_profile_ref"] == run.harness_profile_ref
select.assert_not_called()

View file

@ -0,0 +1,93 @@
"""Tests for the authoritative activity-core -> Glas consumer boundary."""
from __future__ import annotations
import subprocess
from pathlib import Path
import pytest
from rein_aharness.glas_execution import GlasExecutionError, execute_profiled_run
from rein_aharness.ops_run_client import OpsRun, OpsRunConfig
def _repo(tmp_path: Path) -> Path:
repo = tmp_path / "target"
repo.mkdir()
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
return repo
def _run(repo: Path) -> OpsRun:
return OpsRun(
id="run-1",
activity_definition_id="def-1",
idempotency_key="key-1",
target_repo="target",
title="Governed task",
description="Do the bounded work",
state="claimed",
harness_profile_ref="harness.agent-dev-local@1.0.0",
approach_hint="agent-session",
execution_refs={
"correlation_id": "corr-1",
"assignment_ref": "assignment:1",
"role_ref": "role:1",
"duty_ref": "duty:1",
"goal_refs": ["goal:1"],
"resource_envelope_refs": ["resource:1"],
"unknown": "must-not-cross",
},
)
def test_profiled_run_builds_complete_execution_request(tmp_path: Path) -> None:
repo = _repo(tmp_path)
captured = {}
def request_factory(**kwargs):
captured.update(kwargs)
return kwargs
expected = {
"ok": True,
"evidence": {"outcome": "succeeded", "profile_ref": "profile"},
"tool_output": "direct caller output",
"tool_error": None,
}
result = execute_profiled_run(
_run(repo),
OpsRunConfig(worker_id="rein-aharness@test", repo_roots=(str(tmp_path),)),
report_to_hub=False,
request_factory=request_factory,
gateway=lambda request: expected,
)
assert result is expected
assert captured == {
"harness_profile_ref": "harness.agent-dev-local@1.0.0",
"repo": str(repo.resolve()),
"title": "Governed task",
"description": "Do the bounded work",
"actor": "rein-aharness@test",
"project": "rein-aharness",
"request_id": "run-1",
"correlation_id": "corr-1",
"assignment_ref": "assignment:1",
"role_ref": "role:1",
"duty_ref": "duty:1",
"goal_refs": ["goal:1"],
"resource_envelope_refs": ["resource:1"],
"report_to_hub": False,
}
def test_profiled_run_rejects_invalid_gateway_result(tmp_path: Path) -> None:
repo = _repo(tmp_path)
with pytest.raises(GlasExecutionError, match="invalid GatewayResult"):
execute_profiled_run(
_run(repo),
OpsRunConfig(repo_roots=(str(tmp_path),)),
request_factory=lambda **kwargs: kwargs,
gateway=lambda request: {"evidence": {}},
)

View file

@ -169,6 +169,8 @@ def test_llm_connect_client_complete(monkeypatch) -> None:
import rein_aharness.llm_connect_client as mod
class FakeResp:
status_code = 200
def raise_for_status(self) -> None:
return None
@ -187,6 +189,68 @@ def test_llm_connect_client_complete(monkeypatch) -> None:
assert client.last_response_metadata.get("model") == "test-model"
class _ErrorResp:
def __init__(self, status_code: int, body) -> None:
self.status_code = status_code
self._body = body
def json(self):
if isinstance(self._body, Exception):
raise self._body
return self._body
def test_llm_connect_error_preserves_safe_provider_cause(monkeypatch) -> None:
import rein_aharness.llm_connect_client as mod
response = _ErrorResp(
502,
{
"error": "provider_api_error",
"provider_status": 401,
"provider": "openrouter",
"model": "model-1",
"message": "No auth credentials found",
"api_key": "sk-must-not-appear",
"raw_response": {"authorization": "Bearer secret"},
},
)
monkeypatch.setattr(mod.httpx, "post", lambda *args, **kwargs: response)
with pytest.raises(LLMConnectError) as excinfo:
LLMConnectClient("http://llm.test").complete("hi")
text = str(excinfo.value)
assert "HTTP 502" in text
assert "error=provider_api_error" in text
assert "provider_status=401" in text
assert "provider=openrouter" in text
assert "model=model-1" in text
assert "message=No auth credentials found" in text
assert "sk-must-not-appear" not in text
assert "authorization" not in text
def test_llm_connect_error_message_is_bounded(monkeypatch) -> None:
import rein_aharness.llm_connect_client as mod
response = _ErrorResp(502, {"error": "provider_api_error", "message": "x" * 5000})
monkeypatch.setattr(mod.httpx, "post", lambda *args, **kwargs: response)
with pytest.raises(LLMConnectError) as excinfo:
LLMConnectClient("http://llm.test").complete("hi")
assert len(str(excinfo.value)) < 600
@pytest.mark.parametrize("body", [ValueError("not json"), ["unexpected"]])
def test_llm_connect_error_without_usable_body_reports_status(monkeypatch, body) -> None:
import rein_aharness.llm_connect_client as mod
response = _ErrorResp(504, body)
monkeypatch.setattr(mod.httpx, "post", lambda *args, **kwargs: response)
with pytest.raises(LLMConnectError, match="llm-connect returned HTTP 504"):
LLMConnectClient("http://llm.test").complete("hi")
def test_get_client_requires_env(monkeypatch) -> None:
monkeypatch.delenv("LLM_CONNECT_URL", raising=False)
with pytest.raises(LLMConnectError, match="LLM_CONNECT_URL"):

View file

@ -31,10 +31,20 @@ def test_ops_run_from_api() -> None:
"labels": ["automated", "research-brief"],
"state": "open",
"attempt": 0,
"harness_profile_ref": "harness.agent-dev-local@1.0.0",
"execution_refs": {
"correlation_id": "corr-1",
"goal_refs": ["goal:42@1"],
},
}
)
assert row.target_repo == "freedom-intelligence"
assert "research-brief" in row.labels
assert row.harness_profile_ref == "harness.agent-dev-local@1.0.0"
assert row.execution_refs == {
"correlation_id": "corr-1",
"goal_refs": ["goal:42@1"],
}
def test_config_from_env(monkeypatch: pytest.MonkeyPatch) -> None:

287
uv.lock generated
View file

@ -1,6 +1,24 @@
version = 1
requires-python = ">=3.11"
[[package]]
name = "annotated-doc"
version = "0.0.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302 },
]
[[package]]
name = "annotated-types"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427 },
]
[[package]]
name = "anyio"
version = "4.14.2"
@ -32,6 +50,41 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
]
[[package]]
name = "fastapi"
version = "0.141.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-doc" },
{ name = "pydantic" },
{ name = "starlette" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8a/02/91e3416a8fdd715abb903a952a6bec7cdd8d14eed55d415fc8595524c319/fastapi-0.141.1.tar.gz", hash = "sha256:e8822fc40db1e1858054d7a949a888695bc9bdce70139178e33bd2871a453ca1", size = 425799 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl", hash = "sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3", size = 131954 },
]
[[package]]
name = "glas-harness"
version = "0.1.0"
source = { editable = "../glas-harness" }
dependencies = [
{ name = "httpx" },
{ name = "pydantic" },
{ name = "pyyaml" },
]
[package.metadata]
requires-dist = [
{ name = "httpx", specifier = ">=0.27" },
{ name = "pydantic", specifier = ">=2.0" },
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8" },
{ name = "pyyaml", specifier = ">=6.0" },
{ name = "sandboxer", marker = "extra == 'sandbox'", editable = "../sand-boxer" },
]
[[package]]
name = "h11"
version = "0.16.0"
@ -110,6 +163,27 @@ dev = [
{ name = "ruff", specifier = ">=0.4" },
]
[[package]]
name = "markdown-it-py"
version = "4.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687 },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
]
[[package]]
name = "packaging"
version = "26.3"
@ -128,6 +202,123 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 },
]
[[package]]
name = "pydantic"
version = "2.13.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262 },
]
[[package]]
name = "pydantic-core"
version = "2.46.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872 },
{ url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255 },
{ url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827 },
{ url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051 },
{ url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314 },
{ url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146 },
{ url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685 },
{ url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420 },
{ url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122 },
{ url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573 },
{ url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139 },
{ url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433 },
{ url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513 },
{ url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114 },
{ url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298 },
{ url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158 },
{ url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724 },
{ url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742 },
{ url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418 },
{ url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274 },
{ url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940 },
{ url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516 },
{ url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854 },
{ url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306 },
{ url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044 },
{ url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133 },
{ url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464 },
{ url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823 },
{ url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919 },
{ url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604 },
{ url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306 },
{ url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906 },
{ url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802 },
{ url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446 },
{ url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757 },
{ url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275 },
{ url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467 },
{ url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417 },
{ url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782 },
{ url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782 },
{ url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334 },
{ url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986 },
{ url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693 },
{ url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819 },
{ url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411 },
{ url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079 },
{ url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179 },
{ url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926 },
{ url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785 },
{ url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733 },
{ url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534 },
{ url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732 },
{ url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627 },
{ url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141 },
{ url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325 },
{ url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990 },
{ url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978 },
{ url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354 },
{ url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238 },
{ url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251 },
{ url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593 },
{ url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226 },
{ url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605 },
{ url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777 },
{ url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641 },
{ url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404 },
{ url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219 },
{ url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594 },
{ url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542 },
{ url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146 },
{ url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309 },
{ url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736 },
{ url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575 },
{ url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624 },
{ url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325 },
{ url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589 },
{ url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552 },
{ url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984 },
{ url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417 },
{ url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527 },
{ url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024 },
{ url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696 },
{ url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590 },
{ url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782 },
{ url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146 },
{ url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492 },
{ url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604 },
{ url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828 },
{ url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000 },
{ url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286 },
{ url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071 },
]
[[package]]
name = "pygments"
version = "2.20.0"
@ -221,16 +412,85 @@ dependencies = [
dev = [
{ name = "pytest" },
]
glas = [
{ name = "glas-harness" },
{ name = "sandboxer" },
]
llm = [
{ name = "llm-connect" },
]
[package.metadata]
requires-dist = [
{ name = "glas-harness", marker = "extra == 'glas'", editable = "../glas-harness" },
{ name = "httpx", specifier = ">=0.27" },
{ name = "llm-connect", marker = "extra == 'llm'", editable = "../llm-connect" },
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8" },
{ name = "pyyaml", specifier = ">=6.0" },
{ name = "sandboxer", marker = "extra == 'glas'", editable = "../sand-boxer" },
]
[[package]]
name = "rich"
version = "15.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654 },
]
[[package]]
name = "sandboxer"
version = "0.0.0"
source = { editable = "../sand-boxer" }
dependencies = [
{ name = "fastapi" },
{ name = "httpx" },
{ name = "pydantic" },
{ name = "pyyaml" },
{ name = "typer" },
]
[package.metadata]
requires-dist = [
{ name = "fastapi", specifier = ">=0.115" },
{ name = "httpx", specifier = ">=0.27" },
{ name = "pydantic", specifier = ">=2.0" },
{ name = "pyyaml", specifier = ">=6.0" },
{ name = "typer", specifier = ">=0.12" },
]
[package.metadata.requires-dev]
dev = [
{ name = "pytest", specifier = ">=8.0" },
{ name = "ruff", specifier = ">=0.6" },
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.32" },
]
[[package]]
name = "shellingham"
version = "1.5.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
]
[[package]]
name = "starlette"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b5/b4/205b0d5241d934e8add0c38aa924c4f9fb7330834ff11e5444db964ec3f9/starlette-1.6.0.tar.gz", hash = "sha256:d4e3ac5e546444960c710297a3c9fc3f7ebae1b7e963f3d36173b49da535be9b", size = 2716969 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c", size = 75969 },
]
[[package]]
@ -242,6 +502,21 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 },
]
[[package]]
name = "typer"
version = "0.27.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-doc" },
{ name = "colorama", marker = "platform_system == 'Windows'" },
{ name = "rich" },
{ name = "shellingham" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ae/40/4a3db7990d1f62a53182aa96eaef57aeb2886a27f90a195bc66713565d31/typer-0.27.1.tar.gz", hash = "sha256:a79bef8469a79c45498e7b814ecf8d603cc7644e9acbd9e19cac0334240b18df", size = 203994 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl", hash = "sha256:53150287edd11baeb4e4722c8e394fcdf8181c0ae89485cba8d25c778d5edd56", size = 122874 },
]
[[package]]
name = "typing-extensions"
version = "4.16.0"
@ -250,3 +525,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571 },
]
[[package]]
name = "typing-inspection"
version = "0.4.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", size = 76928 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", size = 14750 },
]

View file

@ -0,0 +1,103 @@
---
id: REIN-A-0004
type: workplan
title: "Profile-driven ops-run execution through Glas"
domain: infotech
repo: rein-aharness
status: active
owner: codex
topic_slug: rein-aharness
priority: high
created: "2026-08-22"
updated: "2026-08-22"
related:
- ACTIVITY-WP-0032
- ACT-ADR-006
---
# REIN-A-0004 — Profile-driven ops-run execution through Glas
## Origin
Activity Core handoff `4ed3422a-b42c-4408-843c-f63c3e86cf3e` reports that
the claim consumer currently drops `harness_profile_ref` and `execution_refs`.
A profiled row would consequently enter the legacy `select_approach` path and
could execute a different constellation than the producer authorized.
The related handoff `69710949-9726-4fd0-aef3-1c7075870410` reports that
llm-connect provider errors lose their safe structured status at this boundary,
making a provider 401 look like an undifferentiated 502 transport failure.
## Carry the profile selector and attribution references
```task
id: REIN-A-0004-T01
status: done
priority: high
```
Extend `OpsRun.from_api` with `harness_profile_ref` and the allowlisted
`execution_refs`. Preserve the queued selector verbatim for the authoritative
Glas resolver; do not translate it into an approach hint.
**Done 2026-08-22:** both fields are normalized onto `OpsRun` and covered by
the API projection test.
## Route profiled rows through the Glas gateway
```task
id: REIN-A-0004-T02
status: done
priority: high
```
For a row with a profile, resolve its target checkout, build the Glas
`ExecutionRequest`, and invoke `run_execution` before any sandbox is created by
this consumer. Complete or fail the ops run with the full `GatewayResult`.
Profile refusal and gateway failure are terminal and never fall back to
`select_approach`. Profile-absent rows retain the legacy coexistence path.
**Done 2026-08-22:** `glas_execution.py` resolves the queued checkout, maps the
complete contract 1.0 request (including attribution refs), and invokes Glas
through lazy runtime imports. The claim loop branches on profile presence
before legacy selection and sends the full `GatewayResult` to Activity Core.
Its own returned detail retains only `ExecutionEvidence`. Tests prove success,
terminal refusal, no legacy fallback, and profile-aware queue inspection. A
real sibling-package probe of `harness.unknown@9.9.9` returned
`refused/resolution` with no sandbox id.
## Preserve safe llm-connect provider failure context
```task
id: REIN-A-0004-T03
status: done
priority: medium
```
On an HTTP error, retain only llm-connect's allowlisted `error`,
`provider_status`, `provider`, and `model` fields plus a bounded message. Never
copy the raw provider response or credential material into an ops-run result.
**Done 2026-08-22:** HTTP errors retain exactly the four safe diagnostic fields
plus a 400-character message. Tests cover the upstream 401 hidden behind 502,
redaction-by-allowlist, bounding, and unusable bodies.
## Deploy and coordinate one production proof
```task
id: REIN-A-0004-T04
status: progress
priority: high
```
Install the Glas and sand-boxer sibling packages into the railiance01 claim
worker environment, deploy the source-tested consumer, and coordinate one
low-risk profiled definition with Activity Core. Evidence must show the queued
profile, resolved rein/model/sandbox/outcome, and teardown/commit facts.
**Progress 2026-08-22:** source verification is green (96 tests, compilation,
and diff checks). Packaging exposes the local Glas/sand-boxer extra and the
deployment rsync now excludes `.venv`, preventing workstation-bound shebangs
from overwriting the live worker environment. railiance01 is healthy on the
legacy worker but still needs the Glas checkout/package install, deployment,
restart, and coordinated pilot.