axnwork-cli 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- axnwork_cli-0.2.0.dist-info/METADATA +13 -0
- axnwork_cli-0.2.0.dist-info/RECORD +23 -0
- axnwork_cli-0.2.0.dist-info/WHEEL +5 -0
- axnwork_cli-0.2.0.dist-info/entry_points.txt +2 -0
- axnwork_cli-0.2.0.dist-info/top_level.txt +1 -0
- axon/__init__.py +0 -0
- axon/api.py +83 -0
- axon/backends/__init__.py +5 -0
- axon/backends/base.py +23 -0
- axon/backends/claude_cli.py +290 -0
- axon/backends/codex_cli.py +223 -0
- axon/backends/litellm_backend.py +51 -0
- axon/backends/registry.py +61 -0
- axon/cli.py +595 -0
- axon/config.py +55 -0
- axon/display.py +364 -0
- axon/history.py +133 -0
- axon/llm.py +214 -0
- axon/log.py +44 -0
- axon/mining.py +671 -0
- axon/providers.py +44 -0
- axon/session.py +26 -0
- axon/wallet.py +45 -0
axon/providers.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Fetch available models from LLM provider APIs."""
|
|
2
|
+
import httpx
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def fetch_models(provider: str, api_key: str, api_base: str = "") -> list[dict]:
|
|
6
|
+
"""Fetch models from provider. Returns list of {label, value}."""
|
|
7
|
+
try:
|
|
8
|
+
if provider == "anthropic" and api_key:
|
|
9
|
+
resp = httpx.get("https://api.anthropic.com/v1/models", headers={
|
|
10
|
+
"x-api-key": api_key, "anthropic-version": "2023-06-01",
|
|
11
|
+
}, timeout=10)
|
|
12
|
+
if resp.status_code == 200:
|
|
13
|
+
models = [m["id"] for m in resp.json().get("data", [])]
|
|
14
|
+
models = [m for m in models if "claude-2" not in m and "instant" not in m]
|
|
15
|
+
models.sort(reverse=True)
|
|
16
|
+
return [{"label": m, "value": f"anthropic/{m}"} for m in models]
|
|
17
|
+
|
|
18
|
+
if provider == "openai" and api_key:
|
|
19
|
+
resp = httpx.get("https://api.openai.com/v1/models", headers={
|
|
20
|
+
"Authorization": f"Bearer {api_key}",
|
|
21
|
+
}, timeout=10)
|
|
22
|
+
if resp.status_code == 200:
|
|
23
|
+
prefixes = ("gpt-", "o1", "o3", "o4", "gpt4", "gpt5", "chatgpt")
|
|
24
|
+
models = [m["id"] for m in resp.json().get("data", []) if m["id"].startswith(prefixes)]
|
|
25
|
+
models.sort(reverse=True)
|
|
26
|
+
return [{"label": m, "value": f"openai/{m}"} for m in models]
|
|
27
|
+
|
|
28
|
+
if provider == "deepseek" and api_key:
|
|
29
|
+
resp = httpx.get("https://api.deepseek.com/v1/models", headers={
|
|
30
|
+
"Authorization": f"Bearer {api_key}",
|
|
31
|
+
}, timeout=10)
|
|
32
|
+
if resp.status_code == 200:
|
|
33
|
+
models = sorted(m["id"] for m in resp.json().get("data", []))
|
|
34
|
+
return [{"label": m, "value": f"deepseek/{m}"} for m in models]
|
|
35
|
+
|
|
36
|
+
if provider == "ollama":
|
|
37
|
+
base = api_base or "http://localhost:11434"
|
|
38
|
+
resp = httpx.get(f"{base}/api/tags", timeout=5)
|
|
39
|
+
if resp.status_code == 200:
|
|
40
|
+
models = sorted(m["name"] for m in resp.json().get("models", []))
|
|
41
|
+
return [{"label": m, "value": f"ollama/{m}"} for m in models]
|
|
42
|
+
except Exception:
|
|
43
|
+
pass
|
|
44
|
+
return []
|
axon/session.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Mining session persistence."""
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from axon.config import AXON_HOME
|
|
5
|
+
|
|
6
|
+
SESSIONS_DIR = AXON_HOME / "sessions"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load_session(task_id: str) -> dict | None:
|
|
10
|
+
path = SESSIONS_DIR / f"{task_id}.json"
|
|
11
|
+
if not path.exists():
|
|
12
|
+
return None
|
|
13
|
+
try:
|
|
14
|
+
return json.loads(path.read_text())
|
|
15
|
+
except Exception:
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def save_session(task_id: str, data: dict):
|
|
20
|
+
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
(SESSIONS_DIR / f"{task_id}.json").write_text(json.dumps(data, indent=2))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def delete_session(task_id: str):
|
|
25
|
+
path = SESSIONS_DIR / f"{task_id}.json"
|
|
26
|
+
path.unlink(missing_ok=True)
|
axon/wallet.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""ETH wallet — generate, load, sign."""
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from eth_account import Account
|
|
5
|
+
from eth_account.messages import encode_defunct
|
|
6
|
+
|
|
7
|
+
from axon.config import AXON_HOME
|
|
8
|
+
|
|
9
|
+
WALLET_FILE = AXON_HOME / "wallet.json"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def generate_wallet() -> dict:
|
|
13
|
+
"""Generate a new ETH wallet. Returns {address, private_key}."""
|
|
14
|
+
acct = Account.create()
|
|
15
|
+
return {"address": acct.address, "private_key": acct.key.hex()}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def save_wallet(wallet: dict):
|
|
19
|
+
"""Save wallet to ~/.axon/wallet.json"""
|
|
20
|
+
WALLET_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
WALLET_FILE.write_text(json.dumps(wallet, indent=2) + "\n")
|
|
22
|
+
WALLET_FILE.chmod(0o600) # owner-only read/write
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def load_wallet() -> dict | None:
|
|
26
|
+
"""Load wallet from disk. Returns {address, private_key} or None."""
|
|
27
|
+
if not WALLET_FILE.exists():
|
|
28
|
+
return None
|
|
29
|
+
try:
|
|
30
|
+
return json.loads(WALLET_FILE.read_text())
|
|
31
|
+
except Exception:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def sign_message(message: str, private_key: str) -> str:
|
|
36
|
+
"""Sign a message with private key. Returns hex signature."""
|
|
37
|
+
msg = encode_defunct(text=message)
|
|
38
|
+
signed = Account.sign_message(msg, private_key=private_key)
|
|
39
|
+
return signed.signature.hex()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_address() -> str:
|
|
43
|
+
"""Get wallet address or empty string."""
|
|
44
|
+
wallet = load_wallet()
|
|
45
|
+
return wallet["address"] if wallet else ""
|