vtx-coding-agent 0.1.1__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.
- vtx/__init__.py +63 -0
- vtx/async_utils.py +40 -0
- vtx/builtin_skills/github/SKILL.md +139 -0
- vtx/builtin_skills/init/SKILL.md +74 -0
- vtx/builtin_skills/review/SKILL.md +73 -0
- vtx/builtin_skills/skill-builder/SKILL.md +133 -0
- vtx/cli.py +90 -0
- vtx/config.py +741 -0
- vtx/context/__init__.py +15 -0
- vtx/context/_xml.py +8 -0
- vtx/context/agent_mds.py +128 -0
- vtx/context/git.py +64 -0
- vtx/context/loader.py +41 -0
- vtx/context/skills.py +423 -0
- vtx/core/__init__.py +47 -0
- vtx/core/compaction.py +89 -0
- vtx/core/errors.py +17 -0
- vtx/core/handoff.py +51 -0
- vtx/core/scratchpad.py +54 -0
- vtx/core/types.py +197 -0
- vtx/defaults/__init__.py +0 -0
- vtx/defaults/config.yml +53 -0
- vtx/diff_display.py +12 -0
- vtx/events.py +224 -0
- vtx/gh_cli.py +82 -0
- vtx/git_branch.py +90 -0
- vtx/headless.py +127 -0
- vtx/llm/__init__.py +93 -0
- vtx/llm/base.py +217 -0
- vtx/llm/context_length.py +150 -0
- vtx/llm/dynamic_models.py +735 -0
- vtx/llm/model_fetcher.py +279 -0
- vtx/llm/models.py +78 -0
- vtx/llm/oauth/__init__.py +59 -0
- vtx/llm/oauth/copilot.py +358 -0
- vtx/llm/oauth/dynamic.py +236 -0
- vtx/llm/oauth/openai.py +400 -0
- vtx/llm/phase_parser.py +270 -0
- vtx/llm/provider.yaml +280 -0
- vtx/llm/provider_catalog.py +230 -0
- vtx/llm/providers/__init__.py +45 -0
- vtx/llm/providers/anthropic_sdk.py +256 -0
- vtx/llm/providers/mock.py +249 -0
- vtx/llm/providers/openai_sdk.py +246 -0
- vtx/llm/providers/sanitize.py +14 -0
- vtx/llm/sdk/__init__.py +13 -0
- vtx/llm/sdk/anthropic.py +382 -0
- vtx/llm/sdk/base.py +82 -0
- vtx/llm/sdk/openai.py +344 -0
- vtx/llm/tool_parser.py +161 -0
- vtx/loop.py +272 -0
- vtx/notify.py +109 -0
- vtx/permissions.py +114 -0
- vtx/prompts/__init__.py +45 -0
- vtx/prompts/builder.py +86 -0
- vtx/prompts/env.py +58 -0
- vtx/prompts/identity.py +166 -0
- vtx/prompts/tooling.py +36 -0
- vtx/py.typed +0 -0
- vtx/runtime.py +580 -0
- vtx/session.py +868 -0
- vtx/sounds/completion.wav +0 -0
- vtx/sounds/error.wav +0 -0
- vtx/sounds/permission.wav +0 -0
- vtx/themes.py +1104 -0
- vtx/tools/__init__.py +68 -0
- vtx/tools/_read_image.py +106 -0
- vtx/tools/_tool_utils.py +90 -0
- vtx/tools/base.py +36 -0
- vtx/tools/bash.py +371 -0
- vtx/tools/edit.py +261 -0
- vtx/tools/find.py +132 -0
- vtx/tools/read.py +238 -0
- vtx/tools/skill.py +278 -0
- vtx/tools/web.py +238 -0
- vtx/tools/write.py +88 -0
- vtx/tools_manager.py +216 -0
- vtx/turn.py +789 -0
- vtx/ui/__init__.py +0 -0
- vtx/ui/agent_runner.py +417 -0
- vtx/ui/app.py +665 -0
- vtx/ui/app_protocol.py +29 -0
- vtx/ui/autocomplete.py +440 -0
- vtx/ui/blocks.py +735 -0
- vtx/ui/chat.py +613 -0
- vtx/ui/clipboard.py +59 -0
- vtx/ui/commands/__init__.py +100 -0
- vtx/ui/commands/auth.py +306 -0
- vtx/ui/commands/base.py +122 -0
- vtx/ui/commands/models.py +144 -0
- vtx/ui/commands/sessions.py +388 -0
- vtx/ui/commands/settings.py +286 -0
- vtx/ui/completion_ui.py +313 -0
- vtx/ui/export.py +703 -0
- vtx/ui/floating_list.py +370 -0
- vtx/ui/formatting.py +287 -0
- vtx/ui/input.py +760 -0
- vtx/ui/latex.py +349 -0
- vtx/ui/launch.py +108 -0
- vtx/ui/path_complete.py +228 -0
- vtx/ui/prompt_history.py +102 -0
- vtx/ui/queue_ui.py +141 -0
- vtx/ui/selection_mode.py +18 -0
- vtx/ui/session_ui.py +235 -0
- vtx/ui/startup.py +124 -0
- vtx/ui/styles.py +327 -0
- vtx/ui/tool_output.py +34 -0
- vtx/ui/tree.py +437 -0
- vtx/ui/welcome.py +51 -0
- vtx/ui/widgets.py +558 -0
- vtx/update_check.py +49 -0
- vtx/version.py +22 -0
- vtx_coding_agent-0.1.1.dist-info/METADATA +259 -0
- vtx_coding_agent-0.1.1.dist-info/RECORD +117 -0
- vtx_coding_agent-0.1.1.dist-info/WHEEL +4 -0
- vtx_coding_agent-0.1.1.dist-info/entry_points.txt +2 -0
- vtx_coding_agent-0.1.1.dist-info/licenses/LICENSE +201 -0
vtx/llm/model_fetcher.py
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""Auto-fetch model lists from provider /models endpoints.
|
|
2
|
+
|
|
3
|
+
When a provider has ``fetch_models: true`` in provider.yaml, this module
|
|
4
|
+
can fetch ``<base_url>/models``, parse the response, and cache the result
|
|
5
|
+
to ``~/.vtx/models/<provider>.json`` with a configurable TTL.
|
|
6
|
+
|
|
7
|
+
Fetching is opt-in: call ``refresh_provider_models(slug)`` or
|
|
8
|
+
``refresh_all_provider_models()`` to trigger a fetch. The catalog
|
|
9
|
+
only reads from cache, never blocks on network I/O.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import time
|
|
18
|
+
from contextlib import suppress
|
|
19
|
+
from dataclasses import asdict, dataclass
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
import httpx
|
|
24
|
+
|
|
25
|
+
from .models import ApiType, Model
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
CACHE_DIR = "models"
|
|
30
|
+
DEFAULT_COOLDOWN = 60 # minutes
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class FetchedModel:
|
|
35
|
+
id: str
|
|
36
|
+
name: str
|
|
37
|
+
context_length: int = 0
|
|
38
|
+
max_output_tokens: int = 0
|
|
39
|
+
supports_images: bool = False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_cache_dir() -> Path:
|
|
43
|
+
from ..config import get_config_dir
|
|
44
|
+
|
|
45
|
+
env = os.environ.get("VTX_MODELS_CACHE_DIR")
|
|
46
|
+
return Path(env) if env else get_config_dir() / CACHE_DIR
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _cache_path(provider_slug: str) -> Path:
|
|
50
|
+
return _get_cache_dir() / f"{provider_slug}.json"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _read_cache(provider_slug: str) -> list[FetchedModel] | None:
|
|
54
|
+
path = _cache_path(provider_slug)
|
|
55
|
+
try:
|
|
56
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
57
|
+
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
fetched_at = data.get("fetched_at", 0)
|
|
61
|
+
cooldown = data.get("cooldown_minutes", DEFAULT_COOLDOWN) * 60
|
|
62
|
+
if time.time() - fetched_at > cooldown:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
models = []
|
|
66
|
+
for entry in data.get("models", []):
|
|
67
|
+
models.append(
|
|
68
|
+
FetchedModel(
|
|
69
|
+
id=entry["id"],
|
|
70
|
+
name=entry.get("name", entry["id"]),
|
|
71
|
+
context_length=entry.get("context_length", 0),
|
|
72
|
+
max_output_tokens=entry.get("max_output_tokens", 0),
|
|
73
|
+
supports_images=entry.get("supports_images", False),
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
return models
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _write_cache(provider_slug: str, models: list[FetchedModel], cooldown_minutes: int) -> None:
|
|
80
|
+
path = _cache_path(provider_slug)
|
|
81
|
+
try:
|
|
82
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
data = {
|
|
84
|
+
"fetched_at": time.time(),
|
|
85
|
+
"cooldown_minutes": cooldown_minutes,
|
|
86
|
+
"models": [asdict(m) for m in models],
|
|
87
|
+
}
|
|
88
|
+
tmp = path.with_suffix(".json.tmp")
|
|
89
|
+
tmp.write_text(json.dumps(data, indent=2), encoding="utf-8")
|
|
90
|
+
tmp.replace(path)
|
|
91
|
+
except OSError as exc:
|
|
92
|
+
logger.warning("Failed to write model cache for %s: %s", provider_slug, exc)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _resolve_api_key(provider) -> str | None:
|
|
96
|
+
if provider.api_key_env:
|
|
97
|
+
key = os.environ.get(provider.api_key_env)
|
|
98
|
+
if key:
|
|
99
|
+
return key
|
|
100
|
+
if provider.api_key_optional:
|
|
101
|
+
return "vtx-local"
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _parse_models(raw_models: list[dict[str, Any]], parser_config) -> list[FetchedModel]:
|
|
106
|
+
models: list[FetchedModel] = []
|
|
107
|
+
for raw in raw_models:
|
|
108
|
+
model_id = raw.get(parser_config.id_field, "")
|
|
109
|
+
if not model_id:
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
name = raw.get(parser_config.name_field, model_id)
|
|
113
|
+
if isinstance(name, str) and ":" in name:
|
|
114
|
+
candidate = name.split(":", 1)[1].strip()
|
|
115
|
+
if candidate:
|
|
116
|
+
name = candidate
|
|
117
|
+
|
|
118
|
+
context_length = 0
|
|
119
|
+
ctx_val = raw.get(parser_config.context_field)
|
|
120
|
+
if ctx_val is not None:
|
|
121
|
+
with suppress(TypeError, ValueError):
|
|
122
|
+
context_length = int(ctx_val)
|
|
123
|
+
|
|
124
|
+
max_output = 0
|
|
125
|
+
out_val = raw.get(parser_config.output_field)
|
|
126
|
+
if out_val is not None:
|
|
127
|
+
with suppress(TypeError, ValueError):
|
|
128
|
+
max_output = int(out_val)
|
|
129
|
+
|
|
130
|
+
supports_images = False
|
|
131
|
+
arch = raw.get("architecture")
|
|
132
|
+
if isinstance(arch, dict):
|
|
133
|
+
modalities = arch.get("input_modalities", [])
|
|
134
|
+
supports_images = "image" in modalities if isinstance(modalities, list) else False
|
|
135
|
+
if not supports_images:
|
|
136
|
+
modalities = raw.get("input_modalities")
|
|
137
|
+
supports_images = isinstance(modalities, list) and "image" in modalities
|
|
138
|
+
|
|
139
|
+
models.append(
|
|
140
|
+
FetchedModel(
|
|
141
|
+
id=model_id,
|
|
142
|
+
name=name,
|
|
143
|
+
context_length=context_length,
|
|
144
|
+
max_output_tokens=max_output,
|
|
145
|
+
supports_images=supports_images,
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return models
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _raw_model_list(payload: Any) -> list[dict[str, Any]]:
|
|
153
|
+
if isinstance(payload, list):
|
|
154
|
+
return [m for m in payload if isinstance(m, dict)]
|
|
155
|
+
if isinstance(payload, dict):
|
|
156
|
+
for key in ("data", "models", "results"):
|
|
157
|
+
val = payload.get(key)
|
|
158
|
+
if isinstance(val, list):
|
|
159
|
+
return [m for m in val if isinstance(m, dict)]
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _fetch_models_sync(provider) -> list[FetchedModel]:
|
|
164
|
+
"""Fetch models from a provider's /models endpoint (sync, with network)."""
|
|
165
|
+
if not provider.fetch_models or not provider.base_url:
|
|
166
|
+
return []
|
|
167
|
+
|
|
168
|
+
api_key = _resolve_api_key(provider)
|
|
169
|
+
base = provider.base_url.rstrip("/")
|
|
170
|
+
url = f"{base}{provider.models_endpoint}"
|
|
171
|
+
|
|
172
|
+
headers = {"Accept": "application/json"}
|
|
173
|
+
if api_key and api_key != "vtx-local":
|
|
174
|
+
headers["Authorization"] = f"Bearer {api_key}"
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
with httpx.Client(timeout=10.0) as client:
|
|
178
|
+
resp = client.get(url, headers=headers)
|
|
179
|
+
if resp.status_code >= 400:
|
|
180
|
+
logger.debug("Failed to fetch models for %s: %s", provider.slug, resp.status_code)
|
|
181
|
+
return []
|
|
182
|
+
payload = resp.json()
|
|
183
|
+
except Exception as exc:
|
|
184
|
+
logger.debug("Error fetching models for %s: %s", provider.slug, exc)
|
|
185
|
+
return []
|
|
186
|
+
|
|
187
|
+
raw_models = _raw_model_list(payload)
|
|
188
|
+
if not raw_models:
|
|
189
|
+
return []
|
|
190
|
+
|
|
191
|
+
models = _parse_models(raw_models, provider.model_parser)
|
|
192
|
+
cooldown = provider.model_parser.cooldown_minutes
|
|
193
|
+
_write_cache(provider.slug, models, cooldown)
|
|
194
|
+
return models
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def refresh_provider_models(slug: str) -> int:
|
|
198
|
+
"""Force-refresh a single provider's model cache. Returns model count."""
|
|
199
|
+
from .provider_catalog import get
|
|
200
|
+
|
|
201
|
+
provider = get(slug)
|
|
202
|
+
if provider is None or not provider.fetch_models:
|
|
203
|
+
return 0
|
|
204
|
+
models = _fetch_models_sync(provider)
|
|
205
|
+
return len(models)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def refresh_all_provider_models() -> dict[str, int]:
|
|
209
|
+
"""Force-refresh all providers. Returns {slug: model_count}."""
|
|
210
|
+
from .provider_catalog import list_providers
|
|
211
|
+
|
|
212
|
+
results: dict[str, int] = {}
|
|
213
|
+
for p in list_providers():
|
|
214
|
+
if not p.fetch_models:
|
|
215
|
+
continue
|
|
216
|
+
models = _fetch_models_sync(p)
|
|
217
|
+
results[p.slug] = len(models)
|
|
218
|
+
return results
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def get_fetched_models(provider) -> list[Model]:
|
|
222
|
+
"""Get fetched models from cache only (no network). Returns empty if not cached."""
|
|
223
|
+
if not provider.fetch_models:
|
|
224
|
+
return []
|
|
225
|
+
|
|
226
|
+
cached = _read_cache(provider.slug)
|
|
227
|
+
if cached is None:
|
|
228
|
+
return []
|
|
229
|
+
|
|
230
|
+
family_to_api = {
|
|
231
|
+
"openai_compat": ApiType(ApiType.OPENAI_SDK),
|
|
232
|
+
"anthropic": ApiType(ApiType.ANTHROPIC),
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
from .context_length import context_length_manager
|
|
236
|
+
|
|
237
|
+
models: list[Model] = []
|
|
238
|
+
for entry in cached:
|
|
239
|
+
limits = context_length_manager.get_limits(entry.id)
|
|
240
|
+
is_matched = entry.id in context_length_manager._limits or any(
|
|
241
|
+
entry.id.lower() in k.lower() or k.lower() in entry.id.lower()
|
|
242
|
+
for k in context_length_manager._limits
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
max_tokens = entry.max_output_tokens or provider.max_tokens
|
|
246
|
+
supports_images = entry.supports_images or provider.supports_vision
|
|
247
|
+
supports_thinking = provider.supports_thinking
|
|
248
|
+
context_window = entry.context_length or None
|
|
249
|
+
|
|
250
|
+
if is_matched:
|
|
251
|
+
if context_window is None or context_window == 0:
|
|
252
|
+
context_window = limits.context
|
|
253
|
+
if max_tokens == 0 or max_tokens == provider.max_tokens:
|
|
254
|
+
max_tokens = limits.output
|
|
255
|
+
if not supports_thinking:
|
|
256
|
+
supports_thinking = limits.supports_reasoning
|
|
257
|
+
if not supports_images:
|
|
258
|
+
supports_images = limits.supports_vision
|
|
259
|
+
supports_tools = limits.supports_tools
|
|
260
|
+
supports_audio = limits.supports_audio
|
|
261
|
+
else:
|
|
262
|
+
supports_tools = provider.supports_tools
|
|
263
|
+
supports_audio = False
|
|
264
|
+
|
|
265
|
+
models.append(
|
|
266
|
+
Model(
|
|
267
|
+
id=entry.id,
|
|
268
|
+
provider=provider.slug,
|
|
269
|
+
api=family_to_api[provider.family],
|
|
270
|
+
base_url=provider.base_url or "",
|
|
271
|
+
max_tokens=max_tokens,
|
|
272
|
+
supports_images=supports_images,
|
|
273
|
+
supports_thinking=supports_thinking,
|
|
274
|
+
context_window=context_window,
|
|
275
|
+
supports_tools=supports_tools,
|
|
276
|
+
supports_audio=supports_audio,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
return models
|
vtx/llm/models.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model types and catalog.
|
|
3
|
+
|
|
4
|
+
Model metadata is fetched dynamically via the provider catalog
|
|
5
|
+
and models.dev API. Only the type definitions live here.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
DEFAULT_MAX_TOKENS = 16384
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ApiType:
|
|
14
|
+
OPENAI_COMPLETIONS = "openai-completions"
|
|
15
|
+
OPENAI_SDK = "openai-sdk"
|
|
16
|
+
ANTHROPIC = "anthropic"
|
|
17
|
+
|
|
18
|
+
_VALUES: frozenset[str] = frozenset({OPENAI_COMPLETIONS, OPENAI_SDK, ANTHROPIC})
|
|
19
|
+
|
|
20
|
+
def __init__(self, value: str):
|
|
21
|
+
if value not in self._VALUES:
|
|
22
|
+
raise ValueError(f"Invalid ApiType: {value}")
|
|
23
|
+
self.value = value
|
|
24
|
+
|
|
25
|
+
def __eq__(self, other):
|
|
26
|
+
if isinstance(other, ApiType):
|
|
27
|
+
return self.value == other.value
|
|
28
|
+
if isinstance(other, str):
|
|
29
|
+
return self.value == other
|
|
30
|
+
return NotImplemented
|
|
31
|
+
|
|
32
|
+
def __hash__(self):
|
|
33
|
+
return hash(self.value)
|
|
34
|
+
|
|
35
|
+
def __repr__(self):
|
|
36
|
+
return f"ApiType({self.value!r})"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class Model:
|
|
41
|
+
id: str
|
|
42
|
+
provider: str
|
|
43
|
+
api: ApiType
|
|
44
|
+
base_url: str
|
|
45
|
+
max_tokens: int
|
|
46
|
+
supports_images: bool
|
|
47
|
+
supports_thinking: bool
|
|
48
|
+
context_window: int | None = None
|
|
49
|
+
supports_tools: bool = True
|
|
50
|
+
supports_audio: bool = False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_model(model_id: str, provider: str | None = None) -> Model | None:
|
|
54
|
+
from .dynamic_models import find_dynamic_model
|
|
55
|
+
from .provider_catalog import find_model
|
|
56
|
+
|
|
57
|
+
model = find_model(model_id, provider)
|
|
58
|
+
if model is None:
|
|
59
|
+
model = find_dynamic_model(model_id, provider)
|
|
60
|
+
return model
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_all_models() -> list[Model]:
|
|
64
|
+
from .dynamic_models import get_dynamic_models
|
|
65
|
+
from .provider_catalog import get_all_catalog_models
|
|
66
|
+
|
|
67
|
+
merged: list[Model] = get_all_catalog_models()
|
|
68
|
+
merged.extend(get_dynamic_models())
|
|
69
|
+
return merged
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_models_by_provider(provider: str) -> list[Model]:
|
|
73
|
+
return [m for m in get_all_models() if m.provider == provider]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_max_tokens(model_id: str) -> int:
|
|
77
|
+
model = get_model(model_id)
|
|
78
|
+
return model.max_tokens if model else DEFAULT_MAX_TOKENS
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from .copilot import (
|
|
2
|
+
COPILOT_HEADERS,
|
|
3
|
+
CopilotCredentials,
|
|
4
|
+
clear_credentials,
|
|
5
|
+
get_base_url_from_token,
|
|
6
|
+
get_copilot_auth_path,
|
|
7
|
+
get_valid_token,
|
|
8
|
+
is_copilot_logged_in,
|
|
9
|
+
load_credentials,
|
|
10
|
+
login,
|
|
11
|
+
)
|
|
12
|
+
from .dynamic import (
|
|
13
|
+
DynamicProviderStatus,
|
|
14
|
+
clear_api_key,
|
|
15
|
+
get_dynamic_api_key,
|
|
16
|
+
get_dynamic_auth_path,
|
|
17
|
+
get_provider_status,
|
|
18
|
+
has_api_key,
|
|
19
|
+
load_api_key,
|
|
20
|
+
save_api_key,
|
|
21
|
+
)
|
|
22
|
+
from .openai import (
|
|
23
|
+
OpenAICredentials,
|
|
24
|
+
clear_openai_credentials,
|
|
25
|
+
get_openai_auth_path,
|
|
26
|
+
get_valid_openai_credentials,
|
|
27
|
+
get_valid_openai_token,
|
|
28
|
+
is_openai_logged_in,
|
|
29
|
+
load_openai_credentials,
|
|
30
|
+
)
|
|
31
|
+
from .openai import login as openai_login
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"COPILOT_HEADERS",
|
|
35
|
+
"CopilotCredentials",
|
|
36
|
+
"DynamicProviderStatus",
|
|
37
|
+
"OpenAICredentials",
|
|
38
|
+
"clear_api_key",
|
|
39
|
+
"clear_credentials",
|
|
40
|
+
"clear_openai_credentials",
|
|
41
|
+
"get_base_url_from_token",
|
|
42
|
+
"get_copilot_auth_path",
|
|
43
|
+
"get_dynamic_api_key",
|
|
44
|
+
"get_dynamic_auth_path",
|
|
45
|
+
"get_openai_auth_path",
|
|
46
|
+
"get_provider_status",
|
|
47
|
+
"get_valid_openai_credentials",
|
|
48
|
+
"get_valid_openai_token",
|
|
49
|
+
"get_valid_token",
|
|
50
|
+
"has_api_key",
|
|
51
|
+
"is_copilot_logged_in",
|
|
52
|
+
"is_openai_logged_in",
|
|
53
|
+
"load_api_key",
|
|
54
|
+
"load_credentials",
|
|
55
|
+
"load_openai_credentials",
|
|
56
|
+
"login",
|
|
57
|
+
"openai_login",
|
|
58
|
+
"save_api_key",
|
|
59
|
+
]
|