F3: Kimi inference pipeline + full grok cloud-surface excision
Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
dialect (thinking-field mapping, model_id stripping, empty-content
tool-call message fix, stream_options.include_usage), with kimi-cli
source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)
Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
share command, credit bar: deleted (single local session lane;
paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
gate/tier/team/ZDR fields, app/subscription.rs watch loop,
dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
RPC; Kigi is zero-egress — nothing to share or retain remotely)
Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
(https://www.kimi.com/code/authorize_device?user_code=..., verified
against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
wiremock fixture URLs into the real browser (root cause of the
"garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
kimi.com, "Sign in to Grok" -> "Sign in to Kimi"
This commit is contained in:
@@ -10,8 +10,8 @@ use chrono::{DateTime, Duration as ChronoDuration, Utc};
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::agent::config::{self, ModelEntry, resolve_credentials, sampling_config_for_model};
|
||||
use crate::agent::models_fetch::{FetchModelsResult, fetch_models_blocking};
|
||||
use crate::auth::{AuthManager, KimiAuth, KimiCodeConfig};
|
||||
use crate::remote::{FetchModelsResult, fetch_models_blocking};
|
||||
use crate::sampling::SamplerConfig as SamplingConfig;
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use kigi_sampling_types::{ReasoningEffort, ReasoningEffortOption};
|
||||
@@ -290,7 +290,7 @@ impl ModelsManager {
|
||||
cache
|
||||
.load_fresh(
|
||||
&fetch_auth.cache_auth_method(),
|
||||
&crate::remote::models_fetch_origin(
|
||||
&crate::agent::models_fetch::models_fetch_origin(
|
||||
&cfg.endpoints,
|
||||
fetch_auth,
|
||||
has_session,
|
||||
@@ -1035,11 +1035,6 @@ impl ModelsManager {
|
||||
current_model,
|
||||
credentials,
|
||||
config.endpoints.alpha_test_key.clone(),
|
||||
config.client_version.clone(),
|
||||
crate::managed_config::resolve_deployment_id(
|
||||
config.endpoints.deployment_key.as_deref(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1053,7 +1048,12 @@ impl ModelsManager {
|
||||
let fetch_auth = *self.inner.fetch_auth.read();
|
||||
let has_oauth = self.inner.auth_manager.current_or_expired().is_some();
|
||||
let platform_keys = PlatformApiKeys::resolve(&platforms);
|
||||
crate::remote::models_fetch_origin(&endpoints, fetch_auth, has_oauth, &platform_keys)
|
||||
crate::agent::models_fetch::models_fetch_origin(
|
||||
&endpoints,
|
||||
fetch_auth,
|
||||
has_oauth,
|
||||
&platform_keys,
|
||||
)
|
||||
}
|
||||
|
||||
fn try_load_cache(&self) -> bool {
|
||||
@@ -1327,7 +1327,7 @@ struct ModelsCache {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
auth_method: Option<CacheAuthMethod>,
|
||||
/// Models-list URL this catalog was fetched from
|
||||
/// ([`crate::remote::models_list_url`]). Compared on load so a cache
|
||||
/// ([`crate::agent::models_fetch::models_fetch_origin`]). Compared on load so a cache
|
||||
/// written against one backend is a miss for another: entries embed
|
||||
/// absolute `base_url`s, so adopting a foreign-origin cache silently
|
||||
/// re-points inference (the windows lifecycle e2e failed exactly this
|
||||
@@ -1575,43 +1575,6 @@ pub(crate) fn prefetch_models_blocking(
|
||||
.models
|
||||
}
|
||||
|
||||
/// Blocking models + `/v1/settings` prefetch pair, shared by the early
|
||||
/// prefetch thread and the leader's startup phase so the settings gate lives
|
||||
/// once. The remote_fetch knob is resolved a single time so the two fetch
|
||||
/// decisions cannot disagree mid-startup.
|
||||
pub(crate) fn prefetch_models_and_settings_blocking(
|
||||
endpoints: &config::EndpointsConfig,
|
||||
auth: Option<&KimiAuth>,
|
||||
fetch_auth: ModelFetchAuth,
|
||||
platform_keys: &PlatformApiKeys,
|
||||
) -> (
|
||||
Option<IndexMap<String, ModelEntry>>,
|
||||
Option<crate::util::config::RemoteSettings>,
|
||||
) {
|
||||
let remote_fetch_enabled = crate::util::config::resolve_remote_fetch_enabled();
|
||||
let models = prefetch_models_blocking_gated(
|
||||
endpoints,
|
||||
auth,
|
||||
fetch_auth,
|
||||
platform_keys,
|
||||
remote_fetch_enabled,
|
||||
)
|
||||
.models;
|
||||
// Settings need a subscription session; skip for API-key-only setups.
|
||||
let settings = match auth {
|
||||
Some(auth) if remote_fetch_enabled => {
|
||||
let _timer = crate::instrumentation_timer!("startup.early_settings_fetch");
|
||||
crate::remote::fetch_settings_blocking(
|
||||
&endpoints.proxy_url(),
|
||||
auth,
|
||||
endpoints.alpha_test_key.as_deref(),
|
||||
)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
(models, settings)
|
||||
}
|
||||
|
||||
/// `remote_fetch_enabled` is a parameter so the pair helper above resolves the
|
||||
/// knob once for both halves.
|
||||
fn prefetch_models_blocking_gated(
|
||||
@@ -1624,8 +1587,12 @@ fn prefetch_models_blocking_gated(
|
||||
let cache_auth = fetch_auth.cache_auth_method();
|
||||
// Same fetch plan the network path below executes — the cache is only
|
||||
// valid for it.
|
||||
let cache_origin =
|
||||
crate::remote::models_fetch_origin(endpoints, fetch_auth, auth.is_some(), platform_keys);
|
||||
let cache_origin = crate::agent::models_fetch::models_fetch_origin(
|
||||
endpoints,
|
||||
fetch_auth,
|
||||
auth.is_some(),
|
||||
platform_keys,
|
||||
);
|
||||
let cache = ModelsCacheManager::new();
|
||||
if let Some(cached) = cache.load_fresh(&cache_auth, &cache_origin) {
|
||||
tracing::info!(
|
||||
@@ -1703,10 +1670,9 @@ fn stale_cache_or_failure(
|
||||
ModelsFetchOutcome::failed(oauth_unauthorized)
|
||||
}
|
||||
|
||||
/// Startup prefetch result: models + remote settings.
|
||||
/// Startup prefetch result: the model catalog, when a fetch plan existed.
|
||||
pub struct EarlyPrefetchResult {
|
||||
pub models: Option<IndexMap<String, ModelEntry>>,
|
||||
pub settings: Option<crate::util::config::RemoteSettings>,
|
||||
}
|
||||
|
||||
/// Handle for a startup prefetch thread.
|
||||
@@ -1743,7 +1709,7 @@ fn resolve_prefetch_env_with_auth(auth: Option<KimiAuth>) -> Option<PrefetchEnv>
|
||||
/// `has_custom_endpoint()` (which otherwise forces the prefetch to run): the
|
||||
/// explicit off switch must hold even when a stray login, a platform API key,
|
||||
/// or a `deployment_key` would re-arm the prefetch — and with it the
|
||||
/// `/v1/settings` fetch and the deployment-config sync on the prefetch thread.
|
||||
/// deployment-config sync on the prefetch thread.
|
||||
///
|
||||
/// PRD F2 acceptance: a moonshot API key alone (no subscription login) must
|
||||
/// arm the prefetch so the catalog syncs on startup.
|
||||
@@ -1754,7 +1720,7 @@ fn resolve_prefetch_env_from_parts(
|
||||
remote_fetch_enabled: bool,
|
||||
) -> Option<PrefetchEnv> {
|
||||
if !remote_fetch_enabled {
|
||||
tracing::info!("startup model/settings prefetch skipped: remote_fetch disabled");
|
||||
tracing::info!("startup model prefetch skipped: remote_fetch disabled");
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -1779,7 +1745,7 @@ fn resolve_prefetch_env(kimi_code_config: Option<KimiCodeConfig>) -> Option<Pref
|
||||
resolve_prefetch_env_with_auth(auth)
|
||||
}
|
||||
|
||||
/// Start model + settings prefetch on a background thread using pre-resolved auth.
|
||||
/// Start the model-catalog prefetch on a background thread using pre-resolved auth.
|
||||
///
|
||||
/// When the caller has already obtained valid credentials (e.g. via
|
||||
/// `try_ensure_fresh_auth`), pass them here to avoid re-reading stale cached
|
||||
@@ -1789,7 +1755,7 @@ pub fn start_early_prefetch_with_auth(auth: Option<KimiAuth>) -> Option<EarlyPre
|
||||
Some(spawn_prefetch_thread(env))
|
||||
}
|
||||
|
||||
/// Start model + settings prefetch on a background thread.
|
||||
/// Start the model-catalog prefetch on a background thread.
|
||||
///
|
||||
/// Convenience wrapper that reads cached auth from disk. Prefer
|
||||
/// `start_early_prefetch_with_auth` when you have pre-resolved credentials.
|
||||
@@ -1805,7 +1771,7 @@ fn spawn_prefetch_thread(env: PrefetchEnv) -> EarlyPrefetchHandle {
|
||||
let mut timer = crate::instrumentation_timer!("startup.early_prefetch");
|
||||
let proxy_endpoint = env.endpoints.proxy_url();
|
||||
timer.with_field("endpoint", proxy_endpoint.as_str());
|
||||
let (models, settings) = prefetch_models_and_settings_blocking(
|
||||
let models = prefetch_models_blocking(
|
||||
&env.endpoints,
|
||||
env.auth.as_ref(),
|
||||
env.model_fetch_auth,
|
||||
@@ -1824,7 +1790,7 @@ fn spawn_prefetch_thread(env: PrefetchEnv) -> EarlyPrefetchHandle {
|
||||
let _ = rt.block_on(crate::managed_config::sync());
|
||||
}
|
||||
|
||||
EarlyPrefetchResult { models, settings }
|
||||
EarlyPrefetchResult { models }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3868,7 +3834,7 @@ mod tests {
|
||||
|
||||
fn proxied_endpoints(server_uri: &str) -> config::EndpointsConfig {
|
||||
config::EndpointsConfig {
|
||||
cli_chat_proxy_base_url: Some(server_uri.to_string()),
|
||||
coding_api_base_url: Some(server_uri.to_string()),
|
||||
models_base_url: None,
|
||||
models_list_url: None,
|
||||
..config::EndpointsConfig::default()
|
||||
@@ -3900,7 +3866,7 @@ mod tests {
|
||||
..KimiAuth::test_default()
|
||||
};
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
crate::remote::fetch_models_blocking(
|
||||
crate::agent::models_fetch::fetch_models_blocking(
|
||||
&endpoints,
|
||||
Some(&auth),
|
||||
ModelFetchAuth::Platforms,
|
||||
@@ -3969,7 +3935,12 @@ mod tests {
|
||||
let endpoints = config::EndpointsConfig::default();
|
||||
let keys = PlatformApiKeys::test_keys(Some("sk-cn-secret"), None);
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
crate::remote::fetch_models_blocking(&endpoints, None, ModelFetchAuth::Platforms, &keys)
|
||||
crate::agent::models_fetch::fetch_models_blocking(
|
||||
&endpoints,
|
||||
None,
|
||||
ModelFetchAuth::Platforms,
|
||||
&keys,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -4062,7 +4033,7 @@ mod tests {
|
||||
auth_manager.set_refresher(Arc::new(SwapRefresher));
|
||||
|
||||
let mut cfg = config::Config::default();
|
||||
cfg.endpoints.cli_chat_proxy_base_url = Some(server.uri());
|
||||
cfg.endpoints.coding_api_base_url = Some(server.uri());
|
||||
let mgr = ModelsManager::new(
|
||||
None,
|
||||
IndexMap::new(),
|
||||
@@ -4120,8 +4091,12 @@ mod tests {
|
||||
assert!(bundled.contains_key("moonshot-ai/kimi-k2-turbo-preview"));
|
||||
|
||||
// 2. A STALE cache for the same fetch plan is served on sync failure.
|
||||
let origin =
|
||||
crate::remote::models_fetch_origin(&endpoints, ModelFetchAuth::Platforms, true, &keys);
|
||||
let origin = crate::agent::models_fetch::models_fetch_origin(
|
||||
&endpoints,
|
||||
ModelFetchAuth::Platforms,
|
||||
true,
|
||||
&keys,
|
||||
);
|
||||
let cache = ModelsCacheManager::new();
|
||||
let stale = ModelsCache {
|
||||
fetched_at: Utc::now() - ChronoDuration::seconds(86_400),
|
||||
@@ -4203,7 +4178,7 @@ mod tests {
|
||||
let _cache = EnvGuard::set("KIGI_MODELS_CACHE_DIR", cache_dir.path().to_str().unwrap());
|
||||
let endpoints = proxied_endpoints("http://127.0.0.1:9");
|
||||
// Cache written when a moonshot key was ALSO configured...
|
||||
let with_key_origin = crate::remote::models_fetch_origin(
|
||||
let with_key_origin = crate::agent::models_fetch::models_fetch_origin(
|
||||
&endpoints,
|
||||
ModelFetchAuth::Platforms,
|
||||
true,
|
||||
|
||||
Reference in New Issue
Block a user