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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""LiteLLM backend — wraps existing call_llm() logic."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
import time
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from axon.backends.base import BackendResult
|
|
9
|
+
from axon.backends.registry import register
|
|
10
|
+
|
|
11
|
+
log = logging.getLogger("axon.backend.litellm")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _now_iso() -> str:
|
|
15
|
+
return datetime.now().astimezone().isoformat(timespec="seconds")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@register("litellm")
|
|
19
|
+
class LiteLLMBackend:
|
|
20
|
+
name = "litellm"
|
|
21
|
+
|
|
22
|
+
def __init__(self, config: dict):
|
|
23
|
+
self._model = config.get("default_model", "anthropic/claude-sonnet-4-20250514")
|
|
24
|
+
self._api_base = config.get("api_base", "")
|
|
25
|
+
|
|
26
|
+
def call(self, prompt: str, task: dict) -> BackendResult:
|
|
27
|
+
from axon.llm import call_llm
|
|
28
|
+
started_at = _now_iso()
|
|
29
|
+
started_mono = time.monotonic()
|
|
30
|
+
log.info(
|
|
31
|
+
"LiteLLM start started_at=%s model=%s prompt_chars=%d api_base=%s",
|
|
32
|
+
started_at,
|
|
33
|
+
self._model,
|
|
34
|
+
len(prompt),
|
|
35
|
+
self._api_base or "",
|
|
36
|
+
)
|
|
37
|
+
thinking, answer, usage = call_llm(prompt, self._model, self._api_base)
|
|
38
|
+
log.info(
|
|
39
|
+
"LiteLLM finished started_at=%s finished_at=%s duration_s=%.2f answer_chars=%d thinking_chars=%d total_tokens=%s cost=%s",
|
|
40
|
+
started_at,
|
|
41
|
+
_now_iso(),
|
|
42
|
+
time.monotonic() - started_mono,
|
|
43
|
+
len(answer or ""),
|
|
44
|
+
len(thinking or ""),
|
|
45
|
+
usage.get("total_tokens", 0),
|
|
46
|
+
usage.get("cost", 0.0),
|
|
47
|
+
)
|
|
48
|
+
return BackendResult(thinking=thinking, answer=answer, usage=usage)
|
|
49
|
+
|
|
50
|
+
def display_name(self) -> str:
|
|
51
|
+
return self._model
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Backend registry and factory function."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from axon.backends.base import Backend
|
|
8
|
+
|
|
9
|
+
_REGISTRY: dict[str, type] = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(name: str):
|
|
13
|
+
"""Decorator to register a backend class by name."""
|
|
14
|
+
def wrapper(cls):
|
|
15
|
+
_REGISTRY[name] = cls
|
|
16
|
+
return cls
|
|
17
|
+
return wrapper
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def auto_detect_backend() -> str:
|
|
21
|
+
"""Pick the best available backend: claude-cli > codex-cli > litellm."""
|
|
22
|
+
import shutil
|
|
23
|
+
if shutil.which("claude"):
|
|
24
|
+
return "claude-cli"
|
|
25
|
+
if shutil.which("codex"):
|
|
26
|
+
return "codex-cli"
|
|
27
|
+
return "litellm"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def create_backend(backend_name: str, config: dict) -> Backend:
|
|
31
|
+
"""Create a backend instance by name.
|
|
32
|
+
|
|
33
|
+
If backend_name is "auto", detect the best available CLI tool.
|
|
34
|
+
Lazily imports backend modules so we don't pull in dependencies
|
|
35
|
+
(litellm, subprocess, etc.) until actually needed.
|
|
36
|
+
"""
|
|
37
|
+
if backend_name == "auto":
|
|
38
|
+
backend_name = auto_detect_backend()
|
|
39
|
+
|
|
40
|
+
# Ensure all backends are registered
|
|
41
|
+
_ensure_loaded()
|
|
42
|
+
|
|
43
|
+
if backend_name not in _REGISTRY:
|
|
44
|
+
available = ", ".join(sorted(_REGISTRY.keys()))
|
|
45
|
+
raise ValueError(f"Unknown backend '{backend_name}'. Available: {available}")
|
|
46
|
+
|
|
47
|
+
return _REGISTRY[backend_name](config)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_loaded = False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _ensure_loaded():
|
|
54
|
+
global _loaded
|
|
55
|
+
if _loaded:
|
|
56
|
+
return
|
|
57
|
+
_loaded = True
|
|
58
|
+
# Import backend modules to trigger @register decorators
|
|
59
|
+
import axon.backends.litellm_backend # noqa: F401
|
|
60
|
+
import axon.backends.claude_cli # noqa: F401
|
|
61
|
+
import axon.backends.codex_cli # noqa: F401
|