axio-tui 0.2.2__tar.gz → 0.3.2__tar.gz
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.
- axio_tui-0.3.2/.gitignore +12 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/Makefile +1 -1
- {axio_tui-0.2.2 → axio_tui-0.3.2}/PKG-INFO +4 -1
- {axio_tui-0.2.2 → axio_tui-0.3.2}/pyproject.toml +6 -1
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/transport_registry.py +33 -3
- {axio_tui-0.2.2 → axio_tui-0.3.2}/uv.lock +1 -1
- {axio_tui-0.2.2 → axio_tui-0.3.2}/.github/workflows/publish.yml +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/.github/workflows/tests.yml +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/LICENSE +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/README.md +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/__init__.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/__main__.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/app.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/args.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/plugin.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/prompt.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/screens.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/sqlite_context.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/src/axio_tui/tools.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/conftest.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_guard_screens.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_nav.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_plugin.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_plugin_toggle.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_sqlite_context.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_tool_status_widget.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_tools.py +0 -0
- {axio_tui-0.2.2 → axio_tui-0.3.2}/tests/test_transport_registry.py +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: axio-tui
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Textual TUI application for Axio
|
|
5
|
+
Project-URL: Homepage, https://github.com/axio-agent/axio-tui
|
|
6
|
+
Project-URL: Repository, https://github.com/axio-agent/axio-tui
|
|
5
7
|
License: MIT
|
|
6
8
|
License-File: LICENSE
|
|
9
|
+
Keywords: agent,ai,chat,llm,terminal,textual,tui
|
|
7
10
|
Requires-Python: >=3.12
|
|
8
11
|
Requires-Dist: aiosqlite>=0.20
|
|
9
12
|
Requires-Dist: argclass>=1.6
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "axio-tui"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
description = "Textual TUI application for Axio"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
license = {text = "MIT"}
|
|
8
|
+
keywords = ["llm", "agent", "ai", "tui", "textual", "terminal", "chat"]
|
|
8
9
|
dependencies = [
|
|
9
10
|
"axio",
|
|
10
11
|
"textual>=2.1.0",
|
|
@@ -34,6 +35,10 @@ vision = "axio_tui.tools:VisionAnalyze"
|
|
|
34
35
|
[project.scripts]
|
|
35
36
|
axio = "axio_tui.__main__:main"
|
|
36
37
|
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/axio-agent/axio-tui"
|
|
41
|
+
Repository = "https://github.com/axio-agent/axio-tui"
|
|
37
42
|
[build-system]
|
|
38
43
|
requires = ["hatchling"]
|
|
39
44
|
build-backend = "hatchling.build"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import logging
|
|
6
7
|
import os
|
|
7
8
|
from dataclasses import dataclass, field
|
|
@@ -67,7 +68,7 @@ class TransportRegistry:
|
|
|
67
68
|
# Determine API key: saved settings first, env second
|
|
68
69
|
env_key = os.environ.get(meta.api_key_env, "") if meta.api_key_env else ""
|
|
69
70
|
api_key = saved.get("api_key", "") or env_key
|
|
70
|
-
if not api_key:
|
|
71
|
+
if not api_key and meta.api_key_env:
|
|
71
72
|
logger.info("Transport %r: no API key (env %s), skipping", name, meta.api_key_env)
|
|
72
73
|
continue
|
|
73
74
|
|
|
@@ -84,6 +85,19 @@ class TransportRegistry:
|
|
|
84
85
|
logger.warning("Transport %r: fetch_models failed", name, exc_info=True)
|
|
85
86
|
self._transports[name] = transport
|
|
86
87
|
|
|
88
|
+
# Bulk-load providers from hub screens that expose load_config()
|
|
89
|
+
# (e.g. CustomHubScreen for openai-custom.* providers)
|
|
90
|
+
for screen_name, screen_cls in self._screens.items():
|
|
91
|
+
load = getattr(screen_cls, "load_config", None)
|
|
92
|
+
if not callable(load):
|
|
93
|
+
continue
|
|
94
|
+
try:
|
|
95
|
+
providers = await asyncio.to_thread(load, session)
|
|
96
|
+
for t in providers:
|
|
97
|
+
self.register_dynamic(f"{screen_name}.{t.name}", t)
|
|
98
|
+
except Exception:
|
|
99
|
+
logger.warning("Failed to bulk-load providers from %r", screen_name, exc_info=True)
|
|
100
|
+
|
|
87
101
|
@staticmethod
|
|
88
102
|
async def _load_settings(config: ProjectConfig, name: str) -> dict[str, str]:
|
|
89
103
|
"""Load saved transport settings from config, stripping the key prefix."""
|
|
@@ -114,7 +128,7 @@ class TransportRegistry:
|
|
|
114
128
|
meta = self._metas[name]
|
|
115
129
|
env_key = os.environ.get(meta.api_key_env, "") if meta.api_key_env else ""
|
|
116
130
|
api_key = settings.get("api_key", "") or env_key
|
|
117
|
-
if api_key:
|
|
131
|
+
if api_key or not meta.api_key_env:
|
|
118
132
|
kwargs: dict[str, Any] = {"api_key": api_key, "session": self._session}
|
|
119
133
|
for k, v in settings.items():
|
|
120
134
|
if k != "api_key" and v:
|
|
@@ -161,16 +175,32 @@ class TransportRegistry:
|
|
|
161
175
|
cls = self._classes[name]
|
|
162
176
|
kwargs: dict[str, Any] = {
|
|
163
177
|
"api_key": src.api_key,
|
|
178
|
+
"base_url": src.base_url,
|
|
164
179
|
"model": model,
|
|
165
180
|
"models": src.models,
|
|
166
181
|
"session": src.session,
|
|
167
182
|
}
|
|
168
|
-
# Apply saved settings
|
|
183
|
+
# Apply saved settings that aren't already set
|
|
169
184
|
for k, v in self._saved.get(name, {}).items():
|
|
170
185
|
if k not in kwargs and v:
|
|
171
186
|
kwargs[k] = v
|
|
172
187
|
return cls(**kwargs)
|
|
173
188
|
|
|
189
|
+
def register_dynamic(self, name: str, instance: Any) -> None:
|
|
190
|
+
"""Register a dynamically-created transport instance (e.g. custom providers)."""
|
|
191
|
+
self._transports[name] = instance
|
|
192
|
+
self._classes[name] = type(instance)
|
|
193
|
+
self._metas[name] = type(instance).META
|
|
194
|
+
|
|
195
|
+
def unregister_by_prefix(self, prefix: str) -> None:
|
|
196
|
+
"""Remove all transports whose names start with *prefix*."""
|
|
197
|
+
names = [n for n in list(self._transports) if n.startswith(prefix)]
|
|
198
|
+
for n in names:
|
|
199
|
+
del self._transports[n]
|
|
200
|
+
self._classes.pop(n, None)
|
|
201
|
+
self._metas.pop(n, None)
|
|
202
|
+
self._saved.pop(n, None)
|
|
203
|
+
|
|
174
204
|
def resolve(self, config_value: str) -> RoleBinding | None:
|
|
175
205
|
"""Parse a config value like ``"nebius:model_id"`` into a RoleBinding.
|
|
176
206
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|