Initial vLLM agent strategy

This commit is contained in:
2026-07-21 16:04:18 +08:00
commit d17bb21bbb
48 changed files with 3006 additions and 0 deletions

1
scripts/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""Utility scripts for the vLLM agent strategy."""

View File

@@ -0,0 +1,91 @@
from __future__ import annotations
import argparse
import json
import os
import sys
from typing import Any
import requests
BASE_URL = "https://modelhub.org.cn/agent_platform"
def get_token(args) -> str:
token = args.token or os.getenv("AGENT_PLATFORM_TOKEN") or os.getenv("AUTH_TOKEN")
if not token:
raise SystemExit("Missing token. Use --token, AGENT_PLATFORM_TOKEN, or AUTH_TOKEN.")
return token
def request(method: str, path: str, token: str, **kwargs) -> Any:
url = BASE_URL.rstrip("/") + path
headers = kwargs.pop("headers", {})
headers["Authorization"] = f"Bearer {token}"
if "json" in kwargs:
headers["Content-Type"] = "application/json"
resp = requests.request(method, url, headers=headers, timeout=60, **kwargs)
if resp.status_code == 204:
return {"status": 204, "message": "no content"}
try:
body = resp.json()
except Exception:
body = {"status_code": resp.status_code, "text": resp.text}
if resp.status_code >= 400:
raise SystemExit(json.dumps(body, ensure_ascii=False, indent=2))
return body
def print_json(data: Any) -> None:
print(json.dumps(data, ensure_ascii=False, indent=2))
def main():
parser = argparse.ArgumentParser(description="Agent platform API helper")
parser.add_argument("--token", default="", help="Bearer token; defaults to AGENT_PLATFORM_TOKEN or AUTH_TOKEN")
sub = parser.add_subparsers(dest="cmd", required=True)
sub.add_parser("me")
sub.add_parser("list")
create = sub.add_parser("create")
create.add_argument("--name", required=True)
create.add_argument("--repo-url", required=True)
create.add_argument("--tag", required=True)
for name in ["get", "sync", "deploy", "logs", "stop", "delete"]:
p = sub.add_parser(name)
p.add_argument("--strategy-id", required=True)
if name == "logs":
p.add_argument("--limit", type=int, default=100)
args = parser.parse_args()
token = get_token(args)
if args.cmd == "me":
print_json(request("GET", "/auth/me", token))
elif args.cmd == "list":
print_json(request("GET", "/strategies", token))
elif args.cmd == "create":
body = {"name": args.name, "repo_url": args.repo_url, "tag": args.tag}
data = request("POST", "/strategies", token, json=body)
print_json(data)
strategy_id = data.get("id")
if strategy_id:
print(f"\nSTRATEGY_ID={strategy_id}", file=sys.stderr)
elif args.cmd == "get":
print_json(request("GET", f"/strategies/{args.strategy_id}", token))
elif args.cmd == "sync":
print_json(request("POST", f"/strategies/{args.strategy_id}/sync", token))
elif args.cmd == "deploy":
print_json(request("POST", f"/strategies/{args.strategy_id}/deploy", token))
elif args.cmd == "logs":
print_json(request("GET", f"/strategies/{args.strategy_id}/logs", token, params={"limit": args.limit}))
elif args.cmd == "stop":
print_json(request("POST", f"/strategies/{args.strategy_id}/stop", token))
elif args.cmd == "delete":
print_json(request("DELETE", f"/strategies/{args.strategy_id}", token))
if __name__ == "__main__":
main()

31
scripts/dry_run_plan.py Normal file
View File

@@ -0,0 +1,31 @@
from __future__ import annotations
import argparse
from app.scheduler.budget import Budget
from app.scheduler.planner import Planner
from app.settings import load_settings
from app.storage.db import connect
from app.storage.repositories import Repository
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--limit", type=int, default=50)
args = parser.parse_args()
settings = load_settings(require_secrets=False)
conn = connect(settings.db_path)
try:
repo = Repository(conn)
Planner(repo, Budget(repo, settings.max_user_tasks), settings.default_gpu_alias_list).materialize_tasks()
rows = repo.due_tasks(("pending", "ready_to_submit", "waiting_download", "queue_full_backoff"), limit=args.limit)
for row in rows:
print(f"#{row['id']} priority={row['priority']} status={row['status']} {row['model_id']} -> {row['gpu_type']} ({row['gpu_alias']})")
print(f"budget used={repo.count_budgeted_tasks()} max={settings.max_user_tasks}")
finally:
conn.close()
if __name__ == "__main__":
main()

13
scripts/init_db.py Normal file
View File

@@ -0,0 +1,13 @@
from app.settings import load_settings
from app.storage.db import connect
def main():
settings = load_settings(require_secrets=False)
conn = connect(settings.db_path)
conn.close()
print(f"initialized db: {settings.db_path}")
if __name__ == "__main__":
main()

63
scripts/load_seed.py Normal file
View File

@@ -0,0 +1,63 @@
from __future__ import annotations
import argparse
import csv
from app.domain.priorities import ORIGIN_TO_PRIORITY, PRIORITY_LOW_CONFIDENCE
from app.settings import load_settings
from app.storage.db import connect
from app.storage.repositories import Repository
def flags_for_origin(origin: str) -> tuple[bool, bool, bool, bool]:
is_bounty = origin in {"manual_bounty", "bounty"}
is_promote = origin in {"manual_promote", "promote"}
downloaded = is_bounty or origin in {"manual_downloaded_by_others", "downloaded_by_others"}
self_download = origin in {"hf_seed", "self_download"}
return is_bounty, is_promote, downloaded, self_download
def load_seed(path: str, origin: str, repo: Repository) -> int:
priority = ORIGIN_TO_PRIORITY.get(origin, PRIORITY_LOW_CONFIDENCE)
count = 0
with open(path, newline="", encoding="utf-8") as fh:
reader = csv.DictReader(fh)
for row in reader:
model_id = (row.get("model_id") or "").strip()
if not model_id:
continue
is_bounty, is_promote, downloaded, self_download = flags_for_origin(origin)
repo.upsert_candidate(
model_id=model_id,
source=(row.get("source") or "HUGGING_FACE").strip(),
origin=origin,
priority=priority,
is_bounty=is_bounty,
is_promote=is_promote,
known_downloaded_by_others=downloaded,
self_download_allowed=self_download,
max_model_len=int(row.get("max_model_len") or 1024),
target_gpu_aliases=(row.get("gpu_aliases") or "").strip() or None,
notes=row.get("notes"),
)
count += 1
return count
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--file", required=True)
parser.add_argument("--origin", required=True, choices=sorted(ORIGIN_TO_PRIORITY))
args = parser.parse_args()
settings = load_settings(require_secrets=False)
conn = connect(settings.db_path)
try:
count = load_seed(args.file, args.origin, Repository(conn))
print(f"imported {count} candidates from {args.file} as {args.origin}")
finally:
conn.close()
if __name__ == "__main__":
main()

42
scripts/smoke_check.py Normal file
View File

@@ -0,0 +1,42 @@
from __future__ import annotations
import argparse
import json
from app.clients.modelhub import ModelHubClient
from app.domain.gpu import expand_gpu_aliases
from app.domain.vllm_configs import gen_vllm_config
from app.settings import load_settings
def redact(payload: dict) -> dict:
clone = dict(payload)
if "contestApiToken" in clone:
clone["contestApiToken"] = "***"
return clone
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--no-submit", action="store_true", help="Only print a redacted payload")
parser.add_argument("--model-id", default="Qwen/Qwen2.5-0.5B-Instruct")
parser.add_argument("--gpu-alias", default="k100")
args = parser.parse_args()
settings = load_settings(require_secrets=not args.no_submit)
client = ModelHubClient(settings)
pairs = expand_gpu_aliases([args.gpu_alias])
if not pairs:
raise SystemExit(f"unsupported gpu alias for vLLM: {args.gpu_alias}")
_, gpu_type = pairs[0]
config = gen_vllm_config(gpu_type, args.model_id, settings.default_max_model_len)
payload = client.build_contest_payload(args.model_id, gpu_type, config)
print(json.dumps(redact(payload), ensure_ascii=False, indent=2))
if args.no_submit:
return
result = client.create_contest_task(args.model_id, gpu_type, config)
print(result)
if __name__ == "__main__":
main()