M1/F2+F4: platform registry, Moonshot API-key channel, dynamic model sync

F2 — fixed three-platform registry in kigi-models: kimi-code
(subscription, OAuth bearer, base kigi_env::coding_api_base_url()),
moonshot-cn (https://api.moonshot.cn/v1), moonshot-ai
(https://api.moonshot.ai/v1) with kimi-k model-prefix filtering.
Moonshot API keys via KIGI_MOONSHOT_CN_API_KEY / KIGI_MOONSHOT_AI_API_KEY
(+ KIGI_MOONSHOT_API_KEY shared fallback) or ~/.kigi/config.toml;
values redacted from logs/display.

F4 — model catalog now syncs from GET {base}/models (Bearer auth,
wire shape per official kimi-cli: id/context_length/supports_reasoning/
supports_image_in/supports_video_in/display_name) with the official
capability-derivation rules (thinking / always_thinking-in-name /
kimi-k2 implicit set). Managed keys {platform_id}/{model_id}; default
model = first list entry; default thinking iff capabilities contain
thinking/always_thinking. Sync failure → last cache; no cache →
built-in fallback table seeded from ids sourced in official kimi-cli
(kimi-for-coding, kimi-k2-turbo-preview, kimi-k2-thinking-turbo).
401 during sync forces one token refresh and retries.

Model resolution priority preserved: CLI > env > config > server >
fallback. Grok model artifacts (grok-4*/grok-build catalog, tier
gating remnants) removed from non-test code.

All first-party endpoints re-verified live: device_authorization mints
real codes; /models on all three platforms answers with real API auth
errors when unauthenticated.

Gates: check/clippy --all-targets 0/0, fmt clean, deny ok,
kigi-shell lib 5136 green, kigi-tui lib 6819 green, kigi-models 8.
This commit is contained in:
2026-07-17 09:23:44 -04:00
parent 021b82443d
commit fe1f885bb3
25 changed files with 2148 additions and 430 deletions
+8 -4
View File
@@ -173,11 +173,12 @@ pub(crate) async fn run_auto_update_checker(
async fn prefetch_models(agent_config: &AgentConfig) -> Option<IndexMap<String, ModelEntry>> {
let auth = agent_config.create_auth_manager().current();
let endpoints = agent_config.endpoints.clone();
let fetch_auth = ModelFetchAuth::resolve(&endpoints, auth.is_some());
let fetch_auth = ModelFetchAuth::resolve(&endpoints);
let platform_keys = crate::agent::models::PlatformApiKeys::resolve(&agent_config.platforms);
if auth.is_some() || endpoints.has_custom_endpoint() || fetch_auth != ModelFetchAuth::Session {
if auth.is_some() || endpoints.has_custom_endpoint() || platform_keys.any() {
tokio::task::spawn_blocking(move || {
prefetch_models_blocking(&endpoints, auth.as_ref(), fetch_auth)
prefetch_models_blocking(&endpoints, auth.as_ref(), fetch_auth, &platform_keys)
})
.await
.ok()
@@ -617,7 +618,9 @@ pub async fn run_leader(
let auth_for_prefetch: Option<KimiAuth> = auth.clone();
let endpoints_for_prefetch = agent_config.endpoints.clone();
let fetch_auth_for_prefetch = ModelFetchAuth::resolve(&endpoints_for_prefetch, auth.is_some());
let fetch_auth_for_prefetch = ModelFetchAuth::resolve(&endpoints_for_prefetch);
let platform_keys_for_prefetch =
crate::agent::models::PlatformApiKeys::resolve(&agent_config.platforms);
// The shared pair helper owns the remote_fetch gate for both halves, so a
// disabled knob cannot block leader readiness on settings retries.
let (prefetched_models, remote_settings) = tokio::task::spawn_blocking(move || {
@@ -625,6 +628,7 @@ pub async fn run_leader(
&endpoints_for_prefetch,
auth_for_prefetch.as_ref(),
fetch_auth_for_prefetch,
&platform_keys_for_prefetch,
)
})
.await