coding-cli-runtime 0.1.0__tar.gz → 0.2.0__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.
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/CHANGELOG.md +30 -18
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/PKG-INFO +34 -1
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/README.md +33 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/pyproject.toml +2 -2
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/__init__.py +27 -1
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/auth.py +25 -9
- coding_cli_runtime-0.2.0/src/coding_cli_runtime/provider_contracts.py +476 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime.egg-info/PKG-INFO +34 -1
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime.egg-info/SOURCES.txt +3 -0
- coding_cli_runtime-0.2.0/tests/test_coverage_gaps.py +905 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_packaging.py +9 -3
- coding_cli_runtime-0.2.0/tests/test_provider_contracts.py +322 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/CONTRIBUTING.md +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/LICENSE +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/MANIFEST.in +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/setup.cfg +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/codex_cli.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/contracts.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/copilot_reasoning_baseline.json +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/copilot_reasoning_logs.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/failure_classification.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/json_io.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/provider_controls.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/provider_specs.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/py.typed +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/reasoning.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/redaction.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/schema_validation.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/schemas/normalized_run_result.v1.json +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/schemas/reasoning_metadata.v1.json +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/session_execution.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/session_logs.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime/subprocess_runner.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime.egg-info/dependency_links.txt +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/src/coding_cli_runtime.egg-info/top_level.txt +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_copilot_reasoning_logs.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_package_resources.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_playground_probe_smoke.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_provider_catalog_resolution.py +0 -0
- {coding_cli_runtime-0.1.0 → coding_cli_runtime-0.2.0}/tests/test_runtime_parity.py +0 -0
|
@@ -6,38 +6,50 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.0] - 2026-04-08
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **ProviderContract API** — structured, nested metadata for all four provider CLIs
|
|
13
|
+
(Claude, Codex, Gemini, Copilot). Composed of `AuthContract`, `PathContract`,
|
|
14
|
+
`HeadlessContract`, `PromptTransport`, `ApprovalContract`, `SandboxContract`.
|
|
15
|
+
- `get_provider_contract(provider_id)` — returns structured contract for a provider.
|
|
16
|
+
- `build_env_overlay(contract, api_key, base_url)` — builds provider-specific env
|
|
17
|
+
var overlay from contract metadata.
|
|
18
|
+
- `resolve_config_paths(contract, containerized)` — resolves host and container
|
|
19
|
+
config directory paths.
|
|
20
|
+
- `render_prompt(transport, prompt)` — resolves prompt delivery into argv args +
|
|
21
|
+
stdin text based on provider transport mode.
|
|
22
|
+
- `PromptPayload` dataclass for resolved prompt delivery.
|
|
23
|
+
- `__version__` attribute in `coding_cli_runtime`.
|
|
24
|
+
- `CONTRIBUTING.md`, `MANIFEST.in`, `.pre-commit-config.yaml`.
|
|
25
|
+
- PyPI / Python / Build / License badges in `README.md`.
|
|
26
|
+
- `bump-my-version` configuration syncing `pyproject.toml` and `__init__.py`.
|
|
27
|
+
- `ruff`, `mypy` (strict), and `pytest-cov` added to dev dependencies.
|
|
28
|
+
- CI quality gates: ruff check, ruff format, mypy, pytest-cov.
|
|
29
|
+
- README section documenting the new ProviderContract API with examples.
|
|
30
|
+
- 75 new tests for provider contracts, helpers, internal builder, failure
|
|
31
|
+
classification, codex_cli, schema validation (including nested), reasoning,
|
|
32
|
+
redaction, json_io, provider_controls, and auth. Package coverage 47% → 62%.
|
|
33
|
+
|
|
9
34
|
### Changed
|
|
10
35
|
- Consolidated `shared_cli_runtime` into `coding_cli_runtime`. The package now
|
|
11
36
|
ships a single top-level package; the `shared_cli_runtime` directory is removed.
|
|
12
37
|
- `MANIFEST.in` and docs updated to reference `coding_cli_runtime` paths.
|
|
13
|
-
- Minimum Python version remains `>=3.10`.
|
|
14
38
|
- `run_interactive_session()` observability kwargs (`provider_label`, `job_name`,
|
|
15
39
|
`phase_tag`, `process_label`, `timeout_seconds`) now have sensible defaults so
|
|
16
40
|
external callers don't need to supply internal batch-system labels.
|
|
17
41
|
- Provider model catalogs are now resolved with a three-tier fallback:
|
|
18
42
|
user override file > live CLI discovery > hardcoded fallback.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- **All providers**: place a JSON file at
|
|
22
|
-
`~/.config/coding-cli-runtime/providers/<provider>.json` (or set
|
|
23
|
-
`CODING_CLI_RUNTIME_CONFIG_DIR`) to override the model list and default
|
|
24
|
-
model without waiting for a package update.
|
|
25
|
-
|
|
26
|
-
### Added
|
|
27
|
-
- `__version__` attribute in both `coding_cli_runtime` and `shared_cli_runtime`.
|
|
28
|
-
- `CONTRIBUTING.md`, `MANIFEST.in`, `.pre-commit-config.yaml`.
|
|
29
|
-
- PyPI / Python / Build / License badges in `README.md`.
|
|
30
|
-
- `bump-my-version` configuration syncing `pyproject.toml` and both `__init__.py` files.
|
|
31
|
-
- `ruff`, `mypy` (strict), and `pytest-cov` added to dev dependencies.
|
|
32
|
-
- CI quality gates: ruff check, ruff format, mypy, pytest-cov.
|
|
33
|
-
|
|
34
|
-
### Changed
|
|
43
|
+
- `auth.py`: `_PROVIDER_ENV_HINTS` now derived from `provider_contracts.py`
|
|
44
|
+
(single source of truth for auth env var names).
|
|
35
45
|
- `CliRunResult.command` type widened from `tuple[str, ...]` to `Sequence[str]`.
|
|
36
46
|
- Publish workflow path corrected (`shared-cli-runtime` → `coding-cli-runtime`).
|
|
37
47
|
|
|
38
48
|
### Fixed
|
|
39
|
-
- mypy strict compliance: return-type annotations, per-module overrides
|
|
49
|
+
- mypy strict compliance: return-type annotations, per-module overrides.
|
|
40
50
|
- ruff lint and format compliance across all source and test files.
|
|
51
|
+
- Copilot BYOK (`COPILOT_PROVIDER_API_KEY`) now discoverable via contract
|
|
52
|
+
but not reported as "required" in `resolve_auth()` — BYOK is opt-in.
|
|
41
53
|
|
|
42
54
|
## [0.1.0] - 2026-04-07
|
|
43
55
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-cli-runtime
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Reusable CLI runtime primitives for provider-backed automation workflows
|
|
5
5
|
Author-email: LLM Eval maintainers <llm-eval-maintainers@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -148,6 +148,38 @@ else:
|
|
|
148
148
|
Works for all four providers. Recognizes auth failures, rate limits,
|
|
149
149
|
network transients, and other provider-specific error patterns.
|
|
150
150
|
|
|
151
|
+
### Look up provider contract metadata
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from coding_cli_runtime import get_provider_contract, build_env_overlay, resolve_config_paths, render_prompt
|
|
155
|
+
|
|
156
|
+
# Get structured metadata for any supported provider
|
|
157
|
+
contract = get_provider_contract("claude")
|
|
158
|
+
print(contract.binary) # "claude"
|
|
159
|
+
print(contract.auth.api_key_env_var) # "CLAUDE_API_KEY"
|
|
160
|
+
print(contract.paths.config_dir) # "~/.claude"
|
|
161
|
+
print(contract.headless.approval.flag) # "--dangerously-skip-permissions"
|
|
162
|
+
|
|
163
|
+
# Build env var overlay for subprocess
|
|
164
|
+
env = build_env_overlay(contract, api_key="sk-...", base_url="https://custom.example.com")
|
|
165
|
+
# {"CLAUDE_API_KEY": "sk-...", "ANTHROPIC_BASE_URL": "https://custom.example.com"}
|
|
166
|
+
|
|
167
|
+
# Resolve config paths for container mounts
|
|
168
|
+
host_dir, container_dir = resolve_config_paths(contract, containerized=True)
|
|
169
|
+
# ("/home/user/.claude", "/root/.claude")
|
|
170
|
+
|
|
171
|
+
# Resolve prompt delivery (stdin vs flag vs activation)
|
|
172
|
+
payload = render_prompt(contract.headless.prompt, "Fix the bug")
|
|
173
|
+
# payload.args = () (stdin delivery for Claude)
|
|
174
|
+
# payload.stdin_text = "Fix the bug"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`ProviderContract` is structured as nested sub-contracts
|
|
178
|
+
(`AuthContract`, `PathContract`, `HeadlessContract`) so consumers
|
|
179
|
+
can drill into whichever aspect they need. This is reference metadata,
|
|
180
|
+
not a command-construction control plane — consumers keep their own
|
|
181
|
+
command assembly and adopt contract fields selectively.
|
|
182
|
+
|
|
151
183
|
## Key types
|
|
152
184
|
|
|
153
185
|
| Type | Purpose |
|
|
@@ -156,6 +188,7 @@ network transients, and other provider-specific error patterns.
|
|
|
156
188
|
| `CliRunResult` | Result: returncode, stdout/stderr, duration, error code |
|
|
157
189
|
| `ErrorCode` | `none` · `spawn_failed` · `timed_out` · `non_zero_exit` |
|
|
158
190
|
| `ProviderSpec` | Provider catalog entry with models, controls, defaults |
|
|
191
|
+
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless launch) |
|
|
159
192
|
| `FailureClassification` | Classified error with retryable flag and category |
|
|
160
193
|
|
|
161
194
|
`run_interactive_session()` manages long-running CLI processes with
|
|
@@ -122,6 +122,38 @@ else:
|
|
|
122
122
|
Works for all four providers. Recognizes auth failures, rate limits,
|
|
123
123
|
network transients, and other provider-specific error patterns.
|
|
124
124
|
|
|
125
|
+
### Look up provider contract metadata
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from coding_cli_runtime import get_provider_contract, build_env_overlay, resolve_config_paths, render_prompt
|
|
129
|
+
|
|
130
|
+
# Get structured metadata for any supported provider
|
|
131
|
+
contract = get_provider_contract("claude")
|
|
132
|
+
print(contract.binary) # "claude"
|
|
133
|
+
print(contract.auth.api_key_env_var) # "CLAUDE_API_KEY"
|
|
134
|
+
print(contract.paths.config_dir) # "~/.claude"
|
|
135
|
+
print(contract.headless.approval.flag) # "--dangerously-skip-permissions"
|
|
136
|
+
|
|
137
|
+
# Build env var overlay for subprocess
|
|
138
|
+
env = build_env_overlay(contract, api_key="sk-...", base_url="https://custom.example.com")
|
|
139
|
+
# {"CLAUDE_API_KEY": "sk-...", "ANTHROPIC_BASE_URL": "https://custom.example.com"}
|
|
140
|
+
|
|
141
|
+
# Resolve config paths for container mounts
|
|
142
|
+
host_dir, container_dir = resolve_config_paths(contract, containerized=True)
|
|
143
|
+
# ("/home/user/.claude", "/root/.claude")
|
|
144
|
+
|
|
145
|
+
# Resolve prompt delivery (stdin vs flag vs activation)
|
|
146
|
+
payload = render_prompt(contract.headless.prompt, "Fix the bug")
|
|
147
|
+
# payload.args = () (stdin delivery for Claude)
|
|
148
|
+
# payload.stdin_text = "Fix the bug"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`ProviderContract` is structured as nested sub-contracts
|
|
152
|
+
(`AuthContract`, `PathContract`, `HeadlessContract`) so consumers
|
|
153
|
+
can drill into whichever aspect they need. This is reference metadata,
|
|
154
|
+
not a command-construction control plane — consumers keep their own
|
|
155
|
+
command assembly and adopt contract fields selectively.
|
|
156
|
+
|
|
125
157
|
## Key types
|
|
126
158
|
|
|
127
159
|
| Type | Purpose |
|
|
@@ -130,6 +162,7 @@ network transients, and other provider-specific error patterns.
|
|
|
130
162
|
| `CliRunResult` | Result: returncode, stdout/stderr, duration, error code |
|
|
131
163
|
| `ErrorCode` | `none` · `spawn_failed` · `timed_out` · `non_zero_exit` |
|
|
132
164
|
| `ProviderSpec` | Provider catalog entry with models, controls, defaults |
|
|
165
|
+
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless launch) |
|
|
133
166
|
| `FailureClassification` | Classified error with retryable flag and category |
|
|
134
167
|
|
|
135
168
|
`run_interactive_session()` manages long-running CLI processes with
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coding-cli-runtime"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "Reusable CLI runtime primitives for provider-backed automation workflows"
|
|
9
9
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
10
|
license = "MIT"
|
|
@@ -94,7 +94,7 @@ disallow_untyped_defs = false
|
|
|
94
94
|
warn_return_any = false
|
|
95
95
|
|
|
96
96
|
[tool.bumpversion]
|
|
97
|
-
current_version = "0.
|
|
97
|
+
current_version = "0.2.0"
|
|
98
98
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
99
99
|
serialize = ["{major}.{minor}.{patch}"]
|
|
100
100
|
commit = true
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__version__ = "0.
|
|
5
|
+
__version__ = "0.2.0"
|
|
6
6
|
|
|
7
7
|
from .auth import AuthResolution, resolve_auth
|
|
8
8
|
from .codex_cli import CodexExecSpec, build_codex_exec_spec
|
|
@@ -15,6 +15,20 @@ from .contracts import (
|
|
|
15
15
|
ErrorCode,
|
|
16
16
|
)
|
|
17
17
|
from .failure_classification import FailureClassification, classify_provider_failure
|
|
18
|
+
from .provider_contracts import (
|
|
19
|
+
ApprovalContract,
|
|
20
|
+
AuthContract,
|
|
21
|
+
HeadlessContract,
|
|
22
|
+
PathContract,
|
|
23
|
+
PromptPayload,
|
|
24
|
+
PromptTransport,
|
|
25
|
+
ProviderContract,
|
|
26
|
+
SandboxContract,
|
|
27
|
+
build_env_overlay,
|
|
28
|
+
get_provider_contract,
|
|
29
|
+
render_prompt,
|
|
30
|
+
resolve_config_paths,
|
|
31
|
+
)
|
|
18
32
|
from .provider_controls import build_model_id, resolve_provider_model_controls
|
|
19
33
|
from .provider_specs import (
|
|
20
34
|
ChoiceSpec,
|
|
@@ -56,6 +70,8 @@ from .session_logs import (
|
|
|
56
70
|
from .subprocess_runner import run_cli_command, run_cli_command_sync
|
|
57
71
|
|
|
58
72
|
__all__ = [
|
|
73
|
+
"ApprovalContract",
|
|
74
|
+
"AuthContract",
|
|
59
75
|
"AuthMode",
|
|
60
76
|
"AuthResolution",
|
|
61
77
|
"CliRunRequest",
|
|
@@ -67,14 +83,21 @@ __all__ = [
|
|
|
67
83
|
"ControlSpec",
|
|
68
84
|
"ErrorCode",
|
|
69
85
|
"FailureClassification",
|
|
86
|
+
"HeadlessContract",
|
|
70
87
|
"ModelSpec",
|
|
88
|
+
"PathContract",
|
|
89
|
+
"PromptPayload",
|
|
90
|
+
"PromptTransport",
|
|
91
|
+
"ProviderContract",
|
|
71
92
|
"ProviderSpec",
|
|
93
|
+
"SandboxContract",
|
|
72
94
|
"SchemaValidationError",
|
|
73
95
|
"InteractiveCliRunResult",
|
|
74
96
|
"SessionProgressEvent",
|
|
75
97
|
"SessionRetryDecision",
|
|
76
98
|
"SessionExecutionTimeoutError",
|
|
77
99
|
"TranscriptMirrorStrategy",
|
|
100
|
+
"build_env_overlay",
|
|
78
101
|
"get_claude_default_model",
|
|
79
102
|
"get_claude_effort_levels",
|
|
80
103
|
"get_claude_model_candidates",
|
|
@@ -85,14 +108,17 @@ __all__ = [
|
|
|
85
108
|
"get_copilot_model_catalog",
|
|
86
109
|
"get_gemini_default_model",
|
|
87
110
|
"get_gemini_model_options",
|
|
111
|
+
"get_provider_contract",
|
|
88
112
|
"get_provider_spec",
|
|
89
113
|
"list_provider_specs",
|
|
90
114
|
"build_model_id",
|
|
91
115
|
"build_codex_exec_spec",
|
|
92
116
|
"classify_provider_failure",
|
|
93
117
|
"load_schema",
|
|
118
|
+
"render_prompt",
|
|
94
119
|
"resolve_auth",
|
|
95
120
|
"resolve_claude_reasoning_policy",
|
|
121
|
+
"resolve_config_paths",
|
|
96
122
|
"resolve_provider_model_controls",
|
|
97
123
|
"redact_text",
|
|
98
124
|
"claude_project_key",
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
|
|
8
8
|
from .contracts import AuthMode
|
|
9
|
+
from .provider_contracts import _CONTRACTS
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@dataclass(frozen=True)
|
|
@@ -18,15 +19,30 @@ class AuthResolution:
|
|
|
18
19
|
hint: str
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
def _build_provider_env_hints() -> dict[str, tuple[tuple[str, ...], str]]:
|
|
23
|
+
"""Derive auth env hints from the authoritative provider contracts.
|
|
24
|
+
|
|
25
|
+
Only ``api_key_env_var`` (primary auth) populates ``required_env``.
|
|
26
|
+
``byok_api_key_env_var`` is an opt-in override and should not appear
|
|
27
|
+
as "required" or "missing" — callers discover BYOK via the contract.
|
|
28
|
+
"""
|
|
29
|
+
hints: dict[str, tuple[tuple[str, ...], str]] = {}
|
|
30
|
+
for provider_id, contract in _CONTRACTS.items():
|
|
31
|
+
auth = contract.auth
|
|
32
|
+
env_vars: list[str] = []
|
|
33
|
+
if auth.api_key_env_var:
|
|
34
|
+
env_vars.append(auth.api_key_env_var)
|
|
35
|
+
if env_vars:
|
|
36
|
+
hint = f"Use CLI login or set {env_vars[0]}."
|
|
37
|
+
elif auth.byok_api_key_env_var:
|
|
38
|
+
hint = f"Use CLI login. BYOK available via {auth.byok_api_key_env_var}."
|
|
39
|
+
else:
|
|
40
|
+
hint = "Use CLI login (no env-based auth path available)."
|
|
41
|
+
hints[provider_id] = (tuple(env_vars), hint)
|
|
42
|
+
return hints
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
_PROVIDER_ENV_HINTS = _build_provider_env_hints()
|
|
30
46
|
|
|
31
47
|
|
|
32
48
|
def resolve_auth(provider: str, env: dict[str, str] | None = None) -> AuthResolution:
|