-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathbitsec.py
More file actions
executable file
·175 lines (141 loc) · 5.39 KB
/
Copy pathbitsec.py
File metadata and controls
executable file
·175 lines (141 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python3
"""
bitsec.py
Bitsec CLI utility for miners and validators.
Operations are signed with a Bittensor wallet hotkey.
"""
import asyncio
import os
import subprocess
import sys
from pathlib import Path
import typer
from typer import Option, Argument
from config import settings
from loggers.logger import get_logger
from validator.platform_client import PlatformClient
from validator.models.platform import User, UserRole, AgentCode
from validator.manager import SandboxManager
from validator.proxy.models import derive_provider_from_api_key
logger = get_logger()
# -------------------------------------------------------
# Typer apps
# -------------------------------------------------------
app = typer.Typer(help="Bitsec CLI for miners and validators", pretty_exceptions_enable=False)
miner_app = typer.Typer(help="Miner operations")
validator_app = typer.Typer(help="Validator operations")
# Register sub-apps
app.add_typer(miner_app, name="miner")
app.add_typer(validator_app, name="validator")
# -------------------------------------------------------
# Helpers
# -------------------------------------------------------
def get_platform_client(wallet: str | None = None) -> PlatformClient:
wallet_name = wallet or settings.wallet_name
return PlatformClient(settings.platform_url, wallet_name=wallet_name)
# -------------------------------------------------------
# Original helper functions (unchanged)
# -------------------------------------------------------
def create_user(
email: str,
name: str | None,
client: PlatformClient,
is_miner: bool = True,
) -> None:
"""Register a miner or validator (depending on role)."""
user = User(
email=email,
name=name,
role=UserRole.MINER if is_miner else UserRole.VALIDATOR,
)
user = client.create_user(user)
logger.info(f"{user['role']} User {user['email']} created with hotkey: {user['hotkey']}")
# -------------------------------------------------------
# Miner commands
# -------------------------------------------------------
@miner_app.command("create")
def miner_create(
email: str = Argument(..., help="Email of the miner"),
name: str | None = Argument(None, help="Optional name"),
wallet: str | None = Option(None, help="Bittensor wallet name"),
):
"""Create a miner user on the platform (registers with hotkey)."""
client = get_platform_client(wallet)
create_user(email=email, name=name, client=client, is_miner=True)
@miner_app.command("submit")
def miner_submit(
execution_api_key: str = Option(
...,
prompt="Execution API key",
hide_input=True,
help="Your execution API key (prefix must be cpk_ or sk-or-; will be sent to the platform)",
),
wallet: str | None = Option(None, help="Bittensor wallet name"),
):
"""Submit the miner agent code to the platform."""
agent_path = Path("miner/agent.py")
if not agent_path.exists():
raise FileNotFoundError(agent_path)
derive_provider_from_api_key(execution_api_key)
code_str = agent_path.read_text(encoding="utf-8")
agent_code = AgentCode(code=code_str, execution_api_key=execution_api_key)
client = get_platform_client(wallet)
agent = client.submit_agent(agent_code)
logger.info(f"Agent submitted: Agent ID {agent['id']} version {agent['version']}")
@miner_app.command("cancel-agent")
def miner_cancel_agent(
agent_id: int = Argument(..., help="Agent ID to cancel"),
wallet: str | None = Option(None, help="Bittensor wallet name"),
):
"""Cancel a submitted miner agent execution before evaluation."""
client = get_platform_client(wallet)
client.cancel_agent(agent_id)
logger.info(f"Agent cancellation requested: Agent ID {agent_id}")
@miner_app.command("run")
def miner_run():
"""Run the agent execution and evaluation locally via Docker (recommended)."""
env = os.environ.copy()
env["LOCAL"] = "true"
cmd = ["docker", "compose", "up", "--build"]
subprocess.run(cmd, env=env, check=True)
@miner_app.command("run-no-docker")
def miner_run_no_docker():
"""Run the agent execution and evaluation locally as a script"""
os.environ["LOCAL"] = "true"
manager = SandboxManager(is_local=True)
asyncio.run(manager.run())
@miner_app.command("execute-agent")
def miner_execute_agent():
"""Run the miner agent script locally on a single project."""
cmd = [sys.executable, "miner/agent.py"]
subprocess.run(cmd, env=os.environ.copy(), check=True)
# -------------------------------------------------------
# Validator commands
# -------------------------------------------------------
@validator_app.command("create")
def validator_create(
email: str = Argument(..., help="Email of the validator"),
name: str | None = Argument(None, help="Optional name"),
wallet: str | None = Option(None, help="Bittensor wallet name"),
):
"""Create a validator account."""
client = get_platform_client(wallet)
create_user(email=email, name=name, client=client, is_miner=False)
@validator_app.command("run")
def validator_run():
"""Run the validator."""
cmd = [
"docker",
"compose",
"-f",
"docker-compose.validator.yaml",
"up",
"--build",
"-d",
]
subprocess.run(cmd, check=True)
# -------------------------------------------------------
# Entry point
# -------------------------------------------------------
if __name__ == "__main__":
app()