Files
1jehuang--jcode/scripts/jcode_harbor_claude_agent.py
wehub-resource-sync a789495a98
CI / Quality Guardrails (push) Waiting to run
CI / Build & Test (macos-latest) (push) Waiting to run
CI / Build & Test (ubuntu-latest) (push) Waiting to run
CI / Build & Test (windows-latest) (push) Waiting to run
CI / Format (push) Waiting to run
CI / PowerShell Syntax (push) Waiting to run
CI / Windows Cross-Target Check (Linux) (push) Waiting to run
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:34 +08:00

330 lines
13 KiB
Python

from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any
from harbor.agents.base import BaseAgent
from harbor.environments.base import BaseEnvironment
from harbor.models.agent.context import AgentContext
IN_CONTAINER_HOME = "/tmp/jcode-home"
IN_CONTAINER_RUNTIME = "/tmp/jcode-runtime"
IN_CONTAINER_INPUT = "/tmp/jcode-input"
IN_CONTAINER_OUTPUT = "/tmp/jcode-output"
IN_CONTAINER_BINARY = "/usr/local/bin/jcode"
IN_CONTAINER_LIB_DIR = f"{IN_CONTAINER_RUNTIME}/lib"
IN_CONTAINER_CA_BUNDLE = f"{IN_CONTAINER_HOME}/ca-certificates.crt"
DEFAULT_BINARY_PATH = "/tmp/jcode-compat-dist/jcode-linux-x86_64.bin"
DEFAULT_CLAUDE_AUTH_PATH = "~/.jcode/auth.json"
DEFAULT_OPENROUTER_ENV_PATH = "~/.config/jcode/openrouter.env"
DEFAULT_ANTHROPIC_ENV_PATH = "~/.config/jcode/anthropic.env"
CA_BUNDLE_CANDIDATES = (
os.environ.get("JCODE_HARBOR_CA_BUNDLE"),
"/etc/ca-certificates/extracted/tls-ca-bundle.pem",
"/etc/ssl/certs/ca-certificates.crt",
)
def _resolve_existing_file(*, env_name: str, default_path: str | None = None, candidates: tuple[str | None, ...] = ()) -> Path:
raw_value = os.environ.get(env_name) or default_path
values = [raw_value, *candidates] if raw_value is not None else list(candidates)
checked: list[str] = []
for value in values:
if not value:
continue
candidate = Path(value).expanduser()
checked.append(str(candidate))
if candidate.exists() and candidate.is_file():
return candidate.resolve()
raise FileNotFoundError(f"Could not find a readable file for {env_name}. Checked: {checked}")
def _resolve_optional_existing_file(*, candidates: tuple[str | None, ...]) -> Path | None:
for value in candidates:
if not value:
continue
candidate = Path(value).expanduser()
if candidate.exists() and candidate.is_file():
return candidate.resolve()
return None
def _sibling_runtime_lib_candidates(binary: Path, stem: str) -> tuple[str, ...]:
return tuple(str(path) for path in sorted(binary.parent.glob(f"{stem}.so*")) if path.is_file())
def _load_key_from_env_file(env_path: str, env_var: str, *direct_env: str) -> str | None:
for name in direct_env:
value = os.environ.get(name)
if value and value.strip():
return value.strip()
path = Path(env_path).expanduser()
if path.exists() and path.is_file():
for line in path.read_text().splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, _, value = line.partition("=")
if key.strip() != env_var:
continue
value = value.strip().strip('"').strip("'")
else:
value = line
if value:
return value
return None
def _load_anthropic_key() -> str | None:
return _load_key_from_env_file(
os.environ.get("JCODE_HARBOR_ANTHROPIC_ENV", DEFAULT_ANTHROPIC_ENV_PATH),
"ANTHROPIC_API_KEY",
"ANTHROPIC_API_KEY",
"JCODE_HARBOR_ANTHROPIC_KEY",
)
def _load_openrouter_key() -> str | None:
# Priority: explicit env, then the jcode openrouter.env file (raw key per line).
direct = os.environ.get("OPENROUTER_API_KEY") or os.environ.get("JCODE_HARBOR_OPENROUTER_KEY")
if direct and direct.strip():
return direct.strip()
path = Path(os.environ.get("JCODE_HARBOR_OPENROUTER_ENV", DEFAULT_OPENROUTER_ENV_PATH)).expanduser()
if path.exists() and path.is_file():
for line in path.read_text().splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
# Support both "KEY=value" and bare "value" formats.
if "=" in line:
_, _, value = line.partition("=")
value = value.strip().strip('"').strip("'")
else:
value = line
if value:
return value
return None
JCODE_BINARY = _resolve_existing_file(
env_name="JCODE_HARBOR_BINARY",
default_path=DEFAULT_BINARY_PATH,
)
CA_BUNDLE = _resolve_existing_file(
env_name="JCODE_HARBOR_CA_BUNDLE",
candidates=CA_BUNDLE_CANDIDATES,
)
OPENSSL_RUNTIME_LIBS = tuple(
lib
for lib in (
_resolve_optional_existing_file(
candidates=(
os.environ.get("JCODE_HARBOR_LIBSSL"),
*_sibling_runtime_lib_candidates(JCODE_BINARY, "libssl"),
"/usr/lib/libssl.so.3",
"/usr/lib/x86_64-linux-gnu/libssl.so.3",
"/lib/x86_64-linux-gnu/libssl.so.3",
)
),
_resolve_optional_existing_file(
candidates=(
os.environ.get("JCODE_HARBOR_LIBCRYPTO"),
*_sibling_runtime_lib_candidates(JCODE_BINARY, "libcrypto"),
"/usr/lib/libcrypto.so.3",
"/usr/lib/x86_64-linux-gnu/libcrypto.so.3",
"/lib/x86_64-linux-gnu/libcrypto.so.3",
)
),
)
if lib is not None
)
def _benchmark_instruction_preamble() -> str:
return os.environ.get("JCODE_HARBOR_EXTRA_PREAMBLE", "")
def _load_final_payload(output_dir: Path) -> dict[str, Any] | None:
result_json_path = output_dir / "result.json"
if result_json_path.exists():
raw = result_json_path.read_text()
if raw.strip():
return json.loads(raw)
events_path = output_dir / "events.ndjson"
if not events_path.exists():
return None
final_done: dict[str, Any] | None = None
for line in events_path.read_text().splitlines():
line = line.strip()
if not line:
continue
try:
event = json.loads(line)
except json.JSONDecodeError:
continue
if event.get("type") == "done":
final_done = event
if final_done is None:
return None
payload = {
"session_id": final_done.get("session_id"),
"provider": final_done.get("provider"),
"model": final_done.get("model"),
"text": final_done.get("text", ""),
"usage": final_done.get("usage") or {},
}
result_json_path.write_text(json.dumps(payload, indent=2) + "\n")
return payload
class JcodeClaudeHarborAgent(BaseAgent):
"""Harbor adapter that runs jcode with Opus 4.8.
Default route is the native Anthropic API (provider=anthropic-api,
model=claude-opus-4-8) using ANTHROPIC_API_KEY. OpenRouter
(provider=openrouter, model=anthropic/claude-opus-4.8) and native Claude
OAuth (provider=claude via ~/.jcode/auth.json) are also supported.
"""
def __init__(self, logs_dir: Path, model_name: str | None = None, *args, **kwargs):
super().__init__(logs_dir, model_name, *args, **kwargs)
self._model_arg = model_name or "anthropic-api/claude-opus-4-8"
if "/" in self._model_arg:
self._provider_arg, self._jcode_model = self._model_arg.split("/", 1)
else:
self._provider_arg, self._jcode_model = "anthropic-api", self._model_arg
self._openrouter_key = _load_openrouter_key() if self._provider_arg == "openrouter" else None
self._anthropic_key = _load_anthropic_key() if self._provider_arg == "anthropic-api" else None
self._claude_auth: Path | None = None
if self._provider_arg == "claude":
self._claude_auth = _resolve_existing_file(
env_name="JCODE_HARBOR_CLAUDE_AUTH",
default_path=DEFAULT_CLAUDE_AUTH_PATH,
)
@staticmethod
def name() -> str:
return "jcode-harbor-claude"
def version(self) -> str | None:
return "compat-opus-4-8"
async def setup(self, environment: BaseEnvironment) -> None:
# NOTE: Do NOT symlink/override the container's system OpenSSL cert dir
# (e.g. ln -s ... /usr/lib/ssl/certs). The TB base images are often bare
# ubuntu:24.04 with no /etc/ssl/certs, and the per-task verifier runs
# `apt-get install ca-certificates curl` then bootstraps uv over https.
# Hijacking the system cert dir breaks the verifier's curl (error 77,
# "error setting certificate file") so tests never run. jcode itself
# gets its CA bundle via SSL_CERT_FILE/OPENSSL_CERT_FILE below, so no
# global cert override is needed.
await environment.exec(
(
"mkdir -p "
f"{IN_CONTAINER_HOME} {IN_CONTAINER_RUNTIME} {IN_CONTAINER_INPUT} {IN_CONTAINER_OUTPUT} "
f"{IN_CONTAINER_LIB_DIR} /usr/local/bin"
),
timeout_sec=30,
)
await environment.upload_file(JCODE_BINARY, IN_CONTAINER_BINARY)
await environment.exec(f"chmod +x {IN_CONTAINER_BINARY}", timeout_sec=30)
for lib in OPENSSL_RUNTIME_LIBS:
await environment.upload_file(lib, f"{IN_CONTAINER_LIB_DIR}/{lib.name}")
if self._claude_auth is not None:
await environment.upload_file(self._claude_auth, f"{IN_CONTAINER_HOME}/auth.json")
await environment.exec(f"chmod 600 {IN_CONTAINER_HOME}/auth.json", timeout_sec=30)
await environment.upload_file(CA_BUNDLE, IN_CONTAINER_CA_BUNDLE)
version_result = await environment.exec(
f"{IN_CONTAINER_BINARY} --quiet --no-update --no-selfdev version --json",
env={
"HOME": IN_CONTAINER_HOME,
"JCODE_HOME": IN_CONTAINER_HOME,
"JCODE_RUNTIME_DIR": IN_CONTAINER_RUNTIME,
"JCODE_NO_TELEMETRY": "1",
"LD_LIBRARY_PATH": IN_CONTAINER_LIB_DIR,
},
timeout_sec=60,
)
(self.logs_dir / "setup_version.json").write_text(version_result.stdout or "")
(self.logs_dir / "setup_version.stderr.txt").write_text(version_result.stderr or "")
(self.logs_dir / "setup_version.return_code.txt").write_text(str(version_result.return_code))
async def run(self, instruction: str, environment: BaseEnvironment, context: AgentContext) -> None:
self.logs_dir.mkdir(parents=True, exist_ok=True)
benchmark_instruction = f"{_benchmark_instruction_preamble()}{instruction}"
local_instruction = self.logs_dir / "instruction.txt"
local_instruction.write_text(benchmark_instruction)
await environment.upload_file(local_instruction, f"{IN_CONTAINER_INPUT}/instruction.txt")
env = {
"HOME": IN_CONTAINER_HOME,
"JCODE_HOME": IN_CONTAINER_HOME,
"JCODE_RUNTIME_DIR": IN_CONTAINER_RUNTIME,
"JCODE_NO_TELEMETRY": "1",
"JCODE_PROVIDER": self._provider_arg,
"JCODE_MODEL": self._jcode_model,
"JCODE_ANTHROPIC_REASONING_EFFORT": os.environ.get("JCODE_ANTHROPIC_REASONING_EFFORT", "high"),
"SSL_CERT_FILE": IN_CONTAINER_CA_BUNDLE,
"OPENSSL_CERT_FILE": IN_CONTAINER_CA_BUNDLE,
"LD_LIBRARY_PATH": IN_CONTAINER_LIB_DIR,
}
if self._openrouter_key:
env["OPENROUTER_API_KEY"] = self._openrouter_key
if self._anthropic_key:
env["ANTHROPIC_API_KEY"] = self._anthropic_key
result = await environment.exec(
command=(
'set -e; '
'workdir="${JCODE_TASK_WORKDIR:-}"; '
'if [ -z "$workdir" ]; then '
' if [ -d /app ]; then workdir=/app; else workdir="$(pwd)"; fi; '
'fi; '
f'instruction="$(cat {IN_CONTAINER_INPUT}/instruction.txt)"; '
f'{IN_CONTAINER_BINARY} --quiet --no-update --no-selfdev '
'--provider "$JCODE_PROVIDER" --model "$JCODE_MODEL" '
'-C "$workdir" run --ndjson "$instruction" '
f'> {IN_CONTAINER_OUTPUT}/events.ndjson 2> {IN_CONTAINER_OUTPUT}/stderr.txt'
),
env=env
)
(self.logs_dir / "exec_stdout.txt").write_text(result.stdout or "")
(self.logs_dir / "exec_stderr.txt").write_text(result.stderr or "")
(self.logs_dir / "exec_return_code.txt").write_text(str(result.return_code))
try:
await environment.download_dir(IN_CONTAINER_OUTPUT, self.logs_dir / "jcode-output")
except Exception as e: # noqa: BLE001
(self.logs_dir / "download_error.txt").write_text(str(e))
metadata: dict[str, Any] = {
"return_code": result.return_code,
"provider": self._provider_arg,
"model": self._jcode_model,
"jcode_binary": str(JCODE_BINARY),
}
output_dir = self.logs_dir / "jcode-output"
payload = _load_final_payload(output_dir)
if payload is not None:
usage = payload.get("usage") or {}
context.n_input_tokens = usage.get("input_tokens")
context.n_output_tokens = usage.get("output_tokens")
cache_read = usage.get("cache_read_input_tokens")
cache_create = usage.get("cache_creation_input_tokens")
if isinstance(cache_read, int) and isinstance(cache_create, int):
context.n_cache_tokens = cache_read + cache_create
elif isinstance(cache_read, int):
context.n_cache_tokens = cache_read
metadata["jcode_result"] = payload
context.metadata = metadata