from __future__ import annotations import asyncio import os import posixpath import re import shlex import shutil import sqlite3 import tempfile import json from pathlib import Path from harbor.agents.base import BaseAgent from harbor.environments.base import BaseEnvironment from harbor.models.agent.context import AgentContext _TERMINAL_BENCH_PREAMBLE = """You are running inside a Terminal-Bench task container. Use the available shell and file tools to inspect the working directory, make the required changes, and verify the result. Do not stop after describing what to do; only provide a final response after the task is actually complete. Terminal-Bench scoring depends on files in /app, not on the final message. Before you finish: - Create or modify the exact file(s) requested by the task under /app. - Keep a best-so-far version of every requested artifact on disk while you work. Do not wait until the end to create the target file. - Run a concrete verification command when possible. Inspect and run task-provided checkers under /app, such as check.py, test.py, or test_outputs.py, and use their output to iterate. - For pytest-style task files, prefer `python -m pytest /app/test_outputs.py -q`; running the file directly may silently execute no tests. - Treat task-provided expected-vs-actual output as authoritative feedback. If a checker reports expected values, timing, signal behavior, output schema, file names, or command style, update the artifact to satisfy that feedback before finishing. - Do not inspect verifier-owned paths such as /tests, hidden tests, prior verifier output, or reference solutions. Derive the solution from the task statement and task-provided files in /app. - Match a task-provided checker's execution style as closely as possible. If it uses subprocesses, signals, browser automation, timeouts, or parsers, reproduce that style in your own verification instead of relying only on a simpler in-process check. - Treat visible checker inputs as smoke tests, not the full grading set. Do not hard-code only visible examples, sample fixtures, or one local test path unless the task explicitly asks for a fixed lookup table; prefer a general artifact that should work on unseen verifier cases. - If a payload, script, data file, or other artifact passes a visible checker or local browser/parser/execution test, immediately write that passing content to the requested /app path and stop exploring. - Do not treat a narrow self-selected check as sufficient when broader task-like checks are available. Prefer the provided checker or a close reproduction of the hidden verifier's likely install/build/run path. - Treat a failing check as evidence about the implementation. Do not weaken its assertion or replace it with an easier check unless the task statement proves the original expectation is wrong. For signals, subprocesses, timing, concurrency, or parsers, reproduce the real mechanism rather than testing a convenient approximation. - For recovery, corruption, database, archive, or binary-forensics tasks, copy every original input and related sidecar file before opening it with a native application that may repair, checkpoint, migrate, truncate, or delete data. Inspect raw bytes first and perform destructive experiments only on copies. - If searching reveals the same defect pattern in additional source, generated, native-extension, or config files, either fix those matches too or run a concrete check proving they are irrelevant. - Do not edit task-provided checker/test files just to make local checks pass. Temporary scratch tests are fine, but avoid cleanup/delete commands unless the task requires them or you are removing a file you just created. Do not spend final run time cleaning /tmp or unrelated files. - If the task asks for a script or data artifact, verify that the required path exists and that the script/artifact can be executed or parsed from /app. - If a required download is extremely slow or stalls, do not wait indefinitely on one URL. Check for task-provided caches, official mirrors, release assets, package fixtures, or an equivalent source with the same expected file name/content, then verify the artifact before continuing. - For data-analysis or fitting tasks, confirm units and required transformations before fitting; do not assume a numeric column is already in the target unit. If named domain quantities imply expected physical ranges, compare them with the raw data axis and derive any needed scale/calibration before reporting parameters. - If a long build, install, training, server, or test command is running as a background task, prefer TaskGet with block=true and timeout=600000 to wait for it and read output in one tool call instead of polling every few seconds through repeated shell calls. - Avoid open-ended exploration after a viable artifact exists. Prefer one quick final check, then finish. - Keep assistant text concise. Put substantial code, data, experiments, and analysis in files or shell commands, not in long chat responses. Task: """ _VISIBLE_TEST_CONTEXT_SCRIPT = r""" set -eu tmp="${TMPDIR:-/tmp}/openspace-visible-test-files.$$" trap 'rm -f "$tmp"' EXIT { for path in \ /app/check.py \ /app/test.py \ /app/tests.py \ /app/test_outputs.py \ /app/package.json \ /app/pytest.ini do [ -f "$path" ] && printf '%s\n' "$path" done if [ -d /tests ]; then find /tests -maxdepth 3 -type f \ \( -name '*.py' -o -name '*.js' -o -name '*.ts' -o -name '*.sh' \ -o -name '*.json' -o -name '*.yaml' -o -name '*.yml' \ -o -name 'pytest.ini' -o -name 'package.json' \) \ | sort fi } | awk '!seen[$0]++' | head -20 > "$tmp" [ -s "$tmp" ] || exit 0 printf '# Visible Checker/Test Context\n' printf 'These files are already readable in the task container. Treat them as interface and smoke-test evidence, then implement a general solution for hidden cases.\n' while IFS= read -r file; do [ -r "$file" ] || continue bytes="$(wc -c < "$file" 2>/dev/null | tr -d ' ')" printf '\n## %s (%s bytes)\n' "$file" "${bytes:-unknown}" if [ "${bytes:-0}" -le 6000 ] 2>/dev/null; then sed -n '1,260p' "$file" else printf '\n### Head\n' sed -n '1,120p' "$file" printf '\n### High-signal lines\n' grep -nE '^[[:space:]]*(def test_|class Test|assert|REF[[:space:]]*=|EXPECTED|expected|subprocess|run_solution|verify_|pytest|unittest|describe\(|it\(|test\(|if __name__)' "$file" | head -120 || true printf '\n### Tail\n' tail -n 120 "$file" fi done < "$tmp" """ _AGENT_PYTHON = "/installed-agent/openspace-venv/bin/python" _REMOTE_STDOUT = "/installed-agent/openspace-stdout.txt" _REMOTE_STDERR = "/installed-agent/openspace-stderr.txt" _REMOTE_EVOLVED_SKILL_DIR = "/installed-agent/openspace-evolved-skills" _REMOTE_RUNTIME_DB = "/installed-agent/.openspace/openspace.db" _TRIAL_SUFFIX_RE = re.compile(r"__[A-Za-z0-9_.-]+$") _DEFAULT_ACTIVE_TOOL_NAMES = ( "write", "read", "edit", "grep", "glob", "ls", "bash", "TaskGet", "TaskList", ) _OPENSPACE_FAILURE_STATUS_RE = re.compile( r"Status:\s+(MODEL_ERROR|INCOMPLETE|ERROR|FAILED|ABORTED|MAX_TURNS|MAX_OUTPUT_TOKENS|EMPTY_RESPONSE)", re.IGNORECASE, ) _OPENSPACE_BENCHMARK_STOP_RE = re.compile( r"Status:\s+BENCH_[A-Z_]+|Execution completed:\s+bench_[a-z_]+", re.IGNORECASE, ) _ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-9;]*[A-Za-z]") _VERIFIER_SIGNAL_RE = re.compile( r"AssertionError|Expected\b|Got:|assert\b|FAILED\b|FAILURES|" r"short test summary|Traceback|Error:|Exception|timed out|timeout|" r"cleaned up|task started", re.IGNORECASE, ) _EXPECTED_VALUES_RE = re.compile( r"Expected\s+(?P