Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ steps = [["python", "demo.py", "--agent", "naive", "--model", "stable"]]
```

Every step is an argv list. Steps run in order, and the first one that exits non-zero ends the
action. Unknown keys are errors. Limits: 50 actions, 20 steps each, 100 arguments per step.
action. Each step's output is followed by a line saying how it ended: `[done 路 2.1 s]`,
`[exit 3 路 0.4 s]`, `[stopped 路 5.0 s]` or `[timed out 路 1.0 s]`. Actions run with `FORCE_COLOR=1`
and `CLICOLOR_FORCE=1` (unless already set), so output may contain ANSI color codes; a page showing it
should render or strip them. Unknown keys are errors. Limits: 50 actions, 20 steps each, 100 arguments per step.

### Prepare a Lab

Expand Down
5 changes: 5 additions & 0 deletions src/agent_runtime/labs.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ async def _execute(self, run: Run, lab: PreparedLab, action: Action) -> None:
env["PATH"] = f"{lab.bin_dir}{os.pathsep}{env.get('PATH', '')}"
env["VIRTUAL_ENV"] = str(lab.bin_dir.parent)
env["PYTHONUNBUFFERED"] = "1"
# Output goes to a pipe, not a terminal, so programs would print no colors. The page that
# started the action renders ANSI colors, so ask for them (FORCE_COLOR and CLICOLOR_FORCE
# are the common conventions); a learner's NO_COLOR, if set, still wins in most tools.
env.setdefault("FORCE_COLOR", "1")
env.setdefault("CLICOLOR_FORCE", "1")
deadline = time.monotonic() + action.timeout
watchdog = asyncio.create_task(self._watch(run, deadline))
try:
Expand Down
18 changes: 16 additions & 2 deletions tests/test_labs.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
"import time\\nfor i in range(400):\\n print(i, flush=True)\\n time.sleep(0.05)",
]]

[actions.env]
label = "Prints its color settings"
steps = [[
"python", "-c",
"import os; print(os.environ.get('FORCE_COLOR'), os.environ.get('CLICOLOR_FORCE'))",
]]

[actions.hangs]
label = "Times out"
timeout = 1
Expand Down Expand Up @@ -141,7 +148,7 @@ class TestManifest:
def test_valid(self):
manifest = labs.parse_manifest(MANIFEST)
assert manifest.lab_id == "demo-lab"
assert list(manifest.actions) == ["hello", "two", "slow", "hangs"]
assert list(manifest.actions) == ["hello", "two", "slow", "env", "hangs"]
assert manifest.actions["two"].steps[1] == ("python", "-c", "import sys; sys.exit(3)")
assert manifest.actions["hello"].timeout == labs.DEFAULT_TIMEOUT
assert manifest.actions["hangs"].timeout == 1
Expand Down Expand Up @@ -213,7 +220,7 @@ class TestPrepare:
def test_asks_once_per_lab_version(self, client, lab_repo):
lab = _prepare(client, lab_repo)
assert lab["lab_id"] == "demo-lab" and lab["commit"] == lab_repo[1]
assert [a["name"] for a in lab["actions"]] == ["hello", "two", "slow", "hangs"]
assert [a["name"] for a in lab["actions"]] == ["hello", "two", "slow", "env", "hangs"]
assert len(client.prompts) == 1
prompt = client.prompts[0]
assert SITE in prompt and lab_repo[1] in prompt
Expand Down Expand Up @@ -279,6 +286,13 @@ def test_stop_and_one_run_at_a_time(self, client, lab_repo):
assert re.search(r"\[stopped 路 \d+\.\d s\]\n$", stopped["output"])
assert _start(client, lab, "hello").status_code == 200 # the lab is free again

def test_actions_are_asked_for_colors(self, client, lab_repo, monkeypatch):
monkeypatch.delenv("FORCE_COLOR", raising=False)
monkeypatch.delenv("CLICOLOR_FORCE", raising=False)
lab = _prepare(client, lab_repo)
done = _wait(client, _start(client, lab, "env").json()["run_id"])
assert "\n1 1\n" in done["output"], done["output"]

def test_timeout(self, client, lab_repo):
lab = _prepare(client, lab_repo)
done = _wait(client, _start(client, lab, "hangs").json()["run_id"])
Expand Down
Loading