Files
tkmind_go/evals/harbor/goose_harbor/goose_binary.py
T
2026-05-20 20:03:01 +00:00

232 lines
8.2 KiB
Python

from __future__ import annotations
import os
import shlex
from pathlib import Path
from tempfile import TemporaryDirectory
from harbor.agents.installed.base import with_prompt_template
from harbor.agents.installed.goose import Goose
from harbor.environments.base import BaseEnvironment
from harbor.models.agent.context import AgentContext
CONTAINER_GOOSE_PATH_ROOT = "/installed-agent/goose-profile"
CONTAINER_RECIPE_PATH = "/installed-agent/harbor-recipe.yaml"
CONTAINER_CA_BUNDLE_PATH = "/installed-agent/ca-certificates.crt"
class GooseBinaryAgent(Goose):
"""Run a caller-provided Goose binary in the benchmark environment."""
def __init__(
self,
*args,
goose_binary: str,
goose_profile: str,
install_goose_runtime_deps: bool = False,
**kwargs,
):
super().__init__(*args, **kwargs)
self.goose_binary = Path(goose_binary).expanduser().resolve()
self.goose_profile = Path(goose_profile).expanduser().resolve()
self.install_goose_runtime_deps = install_goose_runtime_deps
self.ca_bundle_env_path: str | None = None
@staticmethod
def name() -> str:
return "goose-binary"
def get_version_command(self) -> str | None:
return "/installed-agent/goose --version"
def _profile_source_target(self) -> tuple[Path, str]:
if not self.goose_profile.is_dir():
raise FileNotFoundError(f"Goose profile does not exist: {self.goose_profile}")
if (self.goose_profile / "config.yaml").is_file():
return self.goose_profile, f"{CONTAINER_GOOSE_PATH_ROOT}/config"
return self.goose_profile, CONTAINER_GOOSE_PATH_ROOT
def _run_env(self) -> dict[str, str]:
if not self.model_name or "/" not in self.model_name:
raise ValueError("Model name must be in the format provider/model_name")
provider, model = self.model_name.split("/", 1)
env = {
"GOOSE_MODEL": model,
"GOOSE_PROVIDER": provider,
"GOOSE_TELEMETRY_ENABLED": "false",
"GOOSE_TELEMETRY_OFF": "true",
"CONFIGURE": "false",
"GOOSE_PATH_ROOT": CONTAINER_GOOSE_PATH_ROOT,
"GOOSE_DISABLE_KEYRING": "true",
}
if self.ca_bundle_env_path:
env["SSL_CERT_FILE"] = self.ca_bundle_env_path
return env
def _host_ca_bundle(self) -> Path:
candidates = [
"SSL_CERT_FILE",
"REQUESTS_CA_BUNDLE",
"CURL_CA_BUNDLE",
]
for env_var in candidates:
value = os.environ.get(env_var)
if value and Path(value).expanduser().is_file():
return Path(value).expanduser().resolve()
for path in [
Path("/etc/ssl/certs/ca-certificates.crt"),
Path("/etc/ssl/cert.pem"),
Path("/opt/homebrew/etc/ca-certificates/cert.pem"),
]:
if path.is_file():
return path.resolve()
raise FileNotFoundError("Could not find a host CA bundle to copy into the task container")
async def _ensure_ca_bundle(self, environment: BaseEnvironment) -> None:
result = await self.exec_as_root(
environment,
command=(
"if [ -r /etc/ssl/certs/ca-certificates.crt ]; "
"then echo present; else echo missing; fi"
),
timeout_sec=10,
)
if result.stdout.strip() != "missing":
return
await environment.upload_file(self._host_ca_bundle(), CONTAINER_CA_BUNDLE_PATH)
await self.exec_as_root(
environment,
command=f"chmod 644 {shlex.quote(CONTAINER_CA_BUNDLE_PATH)}",
timeout_sec=10,
)
self.ca_bundle_env_path = CONTAINER_CA_BUNDLE_PATH
async def _install_goose_runtime_deps(self, environment: BaseEnvironment) -> None:
await self.exec_as_root(
environment,
command=(
"command -v apt-get >/dev/null 2>&1 || "
"(echo 'install_goose_runtime_deps requires apt-get in the task container' >&2; exit 1); "
"apt-get update && "
"DEBIAN_FRONTEND=noninteractive apt-get install -y libgomp1"
),
timeout_sec=300,
)
def _build_register_skills_command(self) -> str | None:
if not self.skills_dir:
return None
skills_target = f"{CONTAINER_GOOSE_PATH_ROOT}/config/skills"
return (
f"mkdir -p {shlex.quote(skills_target)} && "
f"cp -r {shlex.quote(self.skills_dir)}/* "
f"{shlex.quote(skills_target)}/ 2>/dev/null || true"
)
async def _agent_uid_gid(self, environment: BaseEnvironment) -> tuple[str, str]:
result = await self.exec_as_agent(
environment,
command="id -u && id -g",
timeout_sec=10,
)
ids = [line.strip() for line in result.stdout.splitlines() if line.strip()]
if len(ids) < 2:
raise RuntimeError(f"Could not determine agent uid/gid: {result.stdout!r}")
return ids[0], ids[1]
async def _chown_to_agent_user(
self,
environment: BaseEnvironment,
path: str,
*,
recursive: bool = False,
) -> None:
uid, gid = await self._agent_uid_gid(environment)
recursive_flag = "-R " if recursive else ""
await self.exec_as_root(
environment,
command=(
f"chown {recursive_flag}{shlex.quote(uid)}:{shlex.quote(gid)} "
f"{shlex.quote(path)}"
),
)
async def install(self, environment: BaseEnvironment) -> None:
if not self.goose_binary.is_file():
raise FileNotFoundError(f"Goose binary does not exist: {self.goose_binary}")
await environment.upload_file(self.goose_binary, "/installed-agent/goose")
await self.exec_as_root(environment, command="chmod 755 /installed-agent/goose")
if self.install_goose_runtime_deps:
await self._install_goose_runtime_deps(environment)
await self._ensure_ca_bundle(environment)
source, target = self._profile_source_target()
await self.exec_as_root(environment, command=f"mkdir -p {shlex.quote(target)}")
await environment.upload_dir(source, target)
await self._chown_to_agent_user(
environment, CONTAINER_GOOSE_PATH_ROOT, recursive=True
)
await self.exec_as_agent(
environment,
command=(
"mkdir -p ~/.local/bin && "
"ln -sf /installed-agent/goose ~/.local/bin/goose && "
"~/.local/bin/goose --version"
),
env={
"GOOSE_DISABLE_KEYRING": "true",
"GOOSE_TELEMETRY_ENABLED": "false",
"GOOSE_TELEMETRY_OFF": "true",
"CONFIGURE": "false",
},
timeout_sec=30,
)
@with_prompt_template
async def run(
self,
instruction: str,
environment: BaseEnvironment,
context: AgentContext,
) -> None:
env = self._run_env()
recipe_yaml = self._create_recipe_yaml(instruction)
skills_command = self._build_register_skills_command()
if skills_command:
await self.exec_as_agent(
environment,
command=skills_command,
env=env,
timeout_sec=10,
)
with TemporaryDirectory() as tmp_dir:
recipe_path = Path(tmp_dir) / "harbor-recipe.yaml"
recipe_path.write_text(recipe_yaml)
await environment.upload_file(recipe_path, CONTAINER_RECIPE_PATH)
await self._chown_to_agent_user(environment, CONTAINER_RECIPE_PATH)
cli_flags = self.build_cli_flags()
await self.exec_as_agent(
environment,
command=(
'export PATH="$HOME/.local/bin:$PATH" && '
f"goose run --recipe {shlex.quote(CONTAINER_RECIPE_PATH)} "
"--output-format stream-json "
+ ((cli_flags + " ") if cli_flags else "")
+ "2>&1 | stdbuf -oL tee /logs/agent/goose.txt"
),
env=env,
)