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:
1 parent
fe1f885bb3
commit
ea0ce9d15f
231 files changed
+4730
-26358
No files matched your search
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::remote::DEFAULT_CONTEXT_WINDOW;
|
||||
use crate::agent::models_fetch::DEFAULT_CONTEXT_WINDOW;
|
||||
use kigi_chat_state::conversation_util::replace_or_insert_system_head;
|
||||
impl SessionActor {
|
||||
pub(super) async fn handle_set_session_model(
|
||||
@@ -72,7 +72,6 @@ impl SessionActor {
|
||||
existing.auth_type,
|
||||
),
|
||||
alpha_test_key: existing.alpha_test_key,
|
||||
client_version: sampling_config.client_version.clone(),
|
||||
});
|
||||
self.model_auth_facts.replace(None);
|
||||
self.signals_handle()
|
||||
|
||||
@@ -691,7 +691,6 @@ impl SessionActor {
|
||||
crate::agent::config::finalize_image_describe_sampler_config(
|
||||
resolved_describe,
|
||||
&active_session_config,
|
||||
self.client_identifier.clone(),
|
||||
Some(self.max_retries),
|
||||
);
|
||||
let client = kigi_sampler::SamplingClient::new(sampler_config).map_err(|e| {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::remote::DEFAULT_CONTEXT_WINDOW;
|
||||
use crate::agent::models_fetch::DEFAULT_CONTEXT_WINDOW;
|
||||
|
||||
impl SessionActor {
|
||||
/// Handle a /btw side question — single-turn model call using the
|
||||
|
||||
@@ -134,7 +134,7 @@ pub(super) fn build_todo_gate_reminder(pending: &[&str], unbacked_in_progress: &
|
||||
/// (which is disabled). Extracted from `spawn_session_actor` so the
|
||||
/// precedence rules are unit-testable. Named `resolve_*` to match the
|
||||
/// sibling precedence helpers in `crate::util::config`
|
||||
/// (`resolve_zdr_access_enabled`, `resolve_restore_code`, …).
|
||||
/// (`resolve_restore_code`, …).
|
||||
pub(crate) fn resolve_reminder_policy(
|
||||
remote: Option<&crate::util::config::RemoteSettings>,
|
||||
todo_gate: bool,
|
||||
|
||||
@@ -205,8 +205,7 @@ pub(super) async fn run_session(
|
||||
.emit_buffered(notification). await; }
|
||||
if let Some(tx) = respond_to { let _ =
|
||||
tx.send(()); } } } } } maybe_completion = completion_rx.recv() => { let
|
||||
Some((prompt_id, result)) = maybe_completion else { if let Some(cancel) = &
|
||||
session.sync_loop_cancel { cancel.cancel(); } cleanup_session_scratch(&
|
||||
Some((prompt_id, result)) = maybe_completion else { cleanup_session_scratch(&
|
||||
session); return; }; if let Some(notification) = replay_buffer.flush() {
|
||||
session.emit_buffered(notification). await; } let (turn_succeeded,
|
||||
infra_pause_message) = SessionActor::post_turn_goal_degradation_plan(&
|
||||
@@ -265,8 +264,7 @@ pub(super) async fn run_session(
|
||||
{ let
|
||||
model_id = session.current_model_id(). await; if let Some(signals) = session
|
||||
.signals_handle().snapshot(). await {
|
||||
} } if let
|
||||
Some(cancel) = & session.sync_loop_cancel { cancel.cancel(); } session
|
||||
} } session
|
||||
.feedback_manager.shutdown(). await; if ! session
|
||||
.startup_hints.is_subagent { session.persist_background_task_manifest().
|
||||
await; } cleanup_session_scratch(& session); return; }; match cmd {
|
||||
@@ -327,8 +325,7 @@ pub(super) async fn run_session(
|
||||
::agent::config::try_resolve_model_credentials(model_name.as_str(), existing
|
||||
.api_key.as_deref()) { session.chat_state_handle
|
||||
.update_credentials(kigi_chat_state::Credentials { api_key : r.api_key,
|
||||
auth_type : r.auth_type, alpha_test_key : existing.alpha_test_key,
|
||||
client_version : existing.client_version, }); } session.model_auth_facts
|
||||
auth_type : r.auth_type, alpha_test_key : existing.alpha_test_key, }); } session.model_auth_facts
|
||||
.replace(None); } } SessionCommand::GetCurrentModel { responds_to } => { let
|
||||
model = session.chat_state_handle.get_sampling_config(). await .map(| c | c
|
||||
.model).unwrap_or_default(); let _ = responds_to.send(model); }
|
||||
@@ -697,7 +694,7 @@ pub(super) async fn run_session(
|
||||
await; session.send_hook_execution("session_start", None, None, & results).
|
||||
await; } } SessionCommand::GetFeedbackContext { turn_number, responds_to } =>
|
||||
{ let s = session.clone(); tokio::task::spawn_local(async move { use
|
||||
prod_mc_cli_chat_proxy_types::feedback_types::FeedbackToolOutcome; let
|
||||
crate::session::feedback_types::FeedbackToolOutcome; let
|
||||
turn_idx = turn_number.and_then(| n | usize::try_from(n).ok()); let
|
||||
(last_user_message, last_assistant_message) = match turn_idx { Some(n) => {
|
||||
let conv = s.chat_state_handle.get_conversation(). await;
|
||||
@@ -809,8 +806,7 @@ pub(super) async fn run_session(
|
||||
"MEMORY_SUBAGENT_SKIP: skipping on_session_end for subagent session"); }
|
||||
session.maybe_run_dream(). await; let telem = session.memory
|
||||
.telemetry_snapshot(); session.emit_memory_session_summary(& telem,
|
||||
total_chunks_at_end, session_end_result); if let Some(cancel) = & session
|
||||
.sync_loop_cancel { cancel.cancel(); } session.feedback_manager
|
||||
total_chunks_at_end, session_end_result); session.feedback_manager
|
||||
.shutdown(). await; if ! session.startup_hints
|
||||
.is_subagent { session.persist_background_task_manifest(). await; }
|
||||
cleanup_session_scratch(& session); return; } } }
|
||||
|
||||
@@ -49,7 +49,7 @@ impl SessionTokenAuthGate {
|
||||
is_session_based: auth_method_id
|
||||
.is_some_and(crate::agent::auth_method::is_session_based_method),
|
||||
model_byok,
|
||||
endpoint_is_first_party: crate::util::is_first_party_xai_url(base_url),
|
||||
endpoint_is_first_party: crate::util::is_first_party_url(base_url),
|
||||
}
|
||||
}
|
||||
fn active(self) -> bool {
|
||||
@@ -314,22 +314,11 @@ impl SessionActor {
|
||||
auth_scheme,
|
||||
extra_headers,
|
||||
context_window: cfg.context_window.get(),
|
||||
client_version: creds.client_version,
|
||||
reasoning_effort: cfg.reasoning_effort,
|
||||
force_http1: false,
|
||||
max_retries: Some(self.max_retries),
|
||||
stream_tool_calls: cfg.stream_tool_calls.unwrap_or(false),
|
||||
idle_timeout_secs: None,
|
||||
client_identifier: self.client_identifier.clone(),
|
||||
deployment_id: crate::managed_config::resolve_deployment_id(
|
||||
crate::managed_config::resolve_deployment_key().as_deref(),
|
||||
),
|
||||
user_id: self
|
||||
.auth_manager
|
||||
.as_ref()
|
||||
.and_then(|am| am.current_or_expired())
|
||||
.filter(|a| a.is_session_auth())
|
||||
.map(|a| a.user_id),
|
||||
origin_client: self.origin_client.clone(),
|
||||
attribution_callback: self.attribution_callback.clone(),
|
||||
bearer_resolver: if use_bearer_resolver {
|
||||
@@ -482,7 +471,6 @@ impl SessionActor {
|
||||
&endpoints,
|
||||
session_key.as_deref(),
|
||||
creds.alpha_test_key.clone(),
|
||||
creds.client_version.clone(),
|
||||
)
|
||||
}
|
||||
/// Resolve a dedicated sampler for the Auto-mode classifier model `slug`,
|
||||
@@ -499,7 +487,6 @@ impl SessionActor {
|
||||
crate::agent::config::stamp_session_local_sampler_fields(
|
||||
&mut cfg,
|
||||
&active_session_config,
|
||||
self.client_identifier.clone(),
|
||||
Some(self.max_retries),
|
||||
);
|
||||
let model = cfg.model.clone();
|
||||
|
||||
@@ -323,10 +323,10 @@ impl SessionActor {
|
||||
/// Check if the session has been idle and proactively refresh model metadata.
|
||||
///
|
||||
/// Called at the start of each turn. If idle > `IDLE_REFRESH_THRESHOLD_SECS`,
|
||||
/// fetches `/models-v2` from cli-chat-proxy and updates the cached
|
||||
/// fetches `/models` from cli-chat-proxy and updates the cached
|
||||
/// context_window / max_completion_tokens if remote settings changed them.
|
||||
///
|
||||
/// Skipped for BYOK users (no remote settings, no `/models-v2`).
|
||||
/// Skipped for BYOK users (no remote settings, no `/models`).
|
||||
pub(super) async fn maybe_refresh_model_metadata_on_resume(&self) {
|
||||
if !self.is_session_based_auth() {
|
||||
return;
|
||||
@@ -353,7 +353,7 @@ impl SessionActor {
|
||||
tracing::info!(
|
||||
idle_secs,
|
||||
threshold_secs = Self::IDLE_REFRESH_THRESHOLD_SECS,
|
||||
"Session resumed after idle — refreshing model metadata from cli-chat-proxy"
|
||||
"Session resumed after idle — refreshing model metadata"
|
||||
);
|
||||
let creds = self.chat_state_handle.get_credentials().await;
|
||||
let Some(ref am) = self.auth_manager else {
|
||||
@@ -370,27 +370,21 @@ impl SessionActor {
|
||||
);
|
||||
let middleware_client =
|
||||
crate::http::with_auth_retry(crate::http::shared_client(), provider);
|
||||
let url = format!("{}/models-v2", base_url);
|
||||
let url = format!("{}/models", base_url);
|
||||
let parse_models_response =
|
||||
|json: serde_json::Value| -> Option<(std::num::NonZeroU64, Option<u32>)> {
|
||||
let data = json.get("data")?.as_array()?;
|
||||
for entry in data {
|
||||
let parsed = crate::remote::client::parse_remote_model_value(entry, base_url)?;
|
||||
let parsed =
|
||||
crate::agent::models_fetch::parse_remote_model_value(entry, base_url)?;
|
||||
if parsed.model == *current_model {
|
||||
return Some((parsed.context_window, parsed.max_completion_tokens));
|
||||
}
|
||||
}
|
||||
None
|
||||
};
|
||||
#[allow(unused_mut)]
|
||||
let mut request = middleware_client
|
||||
let request = middleware_client
|
||||
.get(&url)
|
||||
.header("X-XAI-Token-Auth", "xai-grok-cli")
|
||||
.header("x-grok-client-version", kigi_version::VERSION)
|
||||
.header(
|
||||
crate::http::CLIENT_MODE_HEADER,
|
||||
crate::http::process_client_mode(),
|
||||
)
|
||||
.timeout(std::time::Duration::from_secs(5));
|
||||
let response = match request.send().await {
|
||||
Ok(r) => r,
|
||||
|
||||
@@ -828,7 +828,7 @@ impl SessionActor {
|
||||
);
|
||||
let model_id = sampling_config.map(|c| c.model);
|
||||
let resolved_model_id = model_metadata.resolved_model_id;
|
||||
let client_version = credentials.client_version;
|
||||
let client_version = Some(kigi_version::VERSION.to_string());
|
||||
|
||||
use crate::session::feedback_manager::{SessionFeedbackData, SubmitOutcome};
|
||||
let outcome = self
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! the MCP auto-restart wiring (`SessionRestartActions`).
|
||||
#![allow(clippy::items_after_test_module)]
|
||||
use super::*;
|
||||
use crate::remote::DEFAULT_CONTEXT_WINDOW;
|
||||
use crate::agent::models_fetch::DEFAULT_CONTEXT_WINDOW;
|
||||
/// Partition CLI `--allow` rules under the pin: blanket catch-all allows
|
||||
/// (`Allow(Any)` `*` / `**`, plus bare/match-all Bash/MCP/WebFetch grants — see
|
||||
/// `resolution::is_catchall_allow`) substitute for the blocked `--yolo`, so drop them when
|
||||
@@ -123,10 +123,7 @@ pub(crate) async fn spawn_session_actor(
|
||||
codebase_indexes: std::sync::Arc<parking_lot::Mutex<CodebaseIndexManager>>,
|
||||
code_nav_enabled: bool,
|
||||
fs_watch_caps: fs_watch::FsWatchCapabilities,
|
||||
feedback_proxy_url: Option<String>,
|
||||
feedback_user_token: Option<String>,
|
||||
feedback_alpha_test_key: Option<String>,
|
||||
deployment_key: Option<String>,
|
||||
feedback_base_url: Option<String>,
|
||||
client_terminal_capable: bool,
|
||||
client_fs_capable: bool,
|
||||
gateway_enabled: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||
@@ -141,7 +138,6 @@ pub(crate) async fn spawn_session_actor(
|
||||
persisted_goal_mode: Option<crate::session::goal_tracker::GoalOrchestration>,
|
||||
persisted_announcement_state: Option<crate::session::announcement_state::AnnouncementState>,
|
||||
memory_config: Option<crate::config::MemoryConfig>,
|
||||
loc_tracking_enabled: bool,
|
||||
feedback_flags: crate::session::feedback_manager::FeedbackFlags,
|
||||
managed_mcp_handle: crate::session::managed_mcp::ManagedMcpStateHandle,
|
||||
managed_mcp_expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
@@ -879,36 +875,30 @@ pub(crate) async fn spawn_session_actor(
|
||||
}
|
||||
persist_chat_history_jsonl_sync(&session_info, &conversation);
|
||||
chat_state_handle.replace_conversation(conversation);
|
||||
let feedback_client = feedback_proxy_url.map(|base_url| {
|
||||
let mut client =
|
||||
crate::agent::feedback_client::FeedbackClient::new(base_url, feedback_user_token)
|
||||
.with_alpha_test_key(feedback_alpha_test_key)
|
||||
.with_deployment_key(deployment_key);
|
||||
if let Some(am) = auth_manager.as_ref() {
|
||||
client = client.with_auth_manager(am.clone());
|
||||
}
|
||||
client
|
||||
});
|
||||
let feedback_client = match (feedback_base_url, auth_manager.as_ref()) {
|
||||
(Some(base_url), Some(am)) => Some(
|
||||
crate::agent::feedback_client::FeedbackClient::new(base_url, am.clone())
|
||||
.with_session_id(session_info.id.0.to_string()),
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
let has_feedback_client = feedback_client.is_some();
|
||||
tracing::info!(
|
||||
session_id = % session_info.id.0, has_feedback_client = has_feedback_client,
|
||||
"Creating feedback manager"
|
||||
);
|
||||
let feedback_client_type = match client_type {
|
||||
ClientType::GrokTUI => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Tui,
|
||||
ClientType::GrokWeb => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Web,
|
||||
ClientType::Nebula => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Nebula,
|
||||
ClientType::Extension => {
|
||||
prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Extension
|
||||
}
|
||||
ClientType::Generic => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Agent,
|
||||
ClientType::Desktop => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Desktop,
|
||||
ClientType::GrokPager => prod_mc_cli_chat_proxy_types::feedback_types::ClientType::Tui,
|
||||
ClientType::GrokTUI => crate::session::feedback_types::ClientType::Tui,
|
||||
ClientType::GrokWeb => crate::session::feedback_types::ClientType::Web,
|
||||
ClientType::Nebula => crate::session::feedback_types::ClientType::Nebula,
|
||||
ClientType::Extension => crate::session::feedback_types::ClientType::Extension,
|
||||
ClientType::Generic => crate::session::feedback_types::ClientType::Agent,
|
||||
ClientType::Desktop => crate::session::feedback_types::ClientType::Desktop,
|
||||
ClientType::GrokPager => crate::session::feedback_types::ClientType::Tui,
|
||||
};
|
||||
let feedback_config = FeedbackManagerConfig {
|
||||
feedback_enabled: feedback_flags.enabled,
|
||||
client_type: feedback_client_type,
|
||||
loc_tracking_enabled,
|
||||
..Default::default()
|
||||
};
|
||||
let feedback_manager = Arc::new(FeedbackManager::new(
|
||||
@@ -930,11 +920,6 @@ pub(crate) async fn spawn_session_actor(
|
||||
}
|
||||
signals_handle.set_primary_model(&primary_model_id);
|
||||
signals_handle.set_tracing_config(inference_idle_timeout_secs);
|
||||
let sync_loop_cancel = if has_feedback_client {
|
||||
Some(tokio_util::sync::CancellationToken::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let force_compact = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
let resolved_workspace_root = kigi_workspace::session::git::find_git_root_from_path(
|
||||
std::path::Path::new(&session_info.cwd),
|
||||
@@ -1141,7 +1126,6 @@ pub(crate) async fn spawn_session_actor(
|
||||
client_identifier: session_client_identifier.clone(),
|
||||
origin_client: origin_client.clone(),
|
||||
feedback_manager: feedback_manager.clone(),
|
||||
sync_loop_cancel: sync_loop_cancel.clone(),
|
||||
agent: std::cell::RefCell::new(agent),
|
||||
last_reported_branch: Arc::new(Mutex::new(None)),
|
||||
git_head_enabled: fs_watch_caps.git_head,
|
||||
@@ -1375,18 +1359,6 @@ pub(crate) async fn spawn_session_actor(
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Some(cancel) = sync_loop_cancel {
|
||||
tracing::info!(session_id = % session_info.id.0, "Spawning feedback sync loop");
|
||||
let fm = feedback_manager.clone();
|
||||
tokio::spawn(async move {
|
||||
fm.run_sync_loop(cancel).await;
|
||||
});
|
||||
} else {
|
||||
tracing::debug!(
|
||||
session_id = % session_info.id.0,
|
||||
"No feedback client available, skipping sync loop"
|
||||
);
|
||||
}
|
||||
{
|
||||
use agent_client_protocol::Client as _;
|
||||
use kigi_tools::implementations::grok_build::ask_user_question::{
|
||||
@@ -1600,10 +1572,7 @@ pub(crate) async fn spawn_session_on_thread(
|
||||
codebase_indexes: std::sync::Arc<parking_lot::Mutex<CodebaseIndexManager>>,
|
||||
code_nav_enabled: bool,
|
||||
fs_watch_caps: fs_watch::FsWatchCapabilities,
|
||||
feedback_proxy_url: Option<String>,
|
||||
feedback_user_token: Option<String>,
|
||||
feedback_alpha_test_key: Option<String>,
|
||||
deployment_key: Option<String>,
|
||||
feedback_base_url: Option<String>,
|
||||
client_terminal_capable: bool,
|
||||
client_fs_capable: bool,
|
||||
gateway_enabled: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||
@@ -1618,7 +1587,6 @@ pub(crate) async fn spawn_session_on_thread(
|
||||
persisted_goal_mode: Option<crate::session::goal_tracker::GoalOrchestration>,
|
||||
persisted_announcement_state: Option<crate::session::announcement_state::AnnouncementState>,
|
||||
memory_config: Option<crate::config::MemoryConfig>,
|
||||
loc_tracking_enabled: bool,
|
||||
feedback_flags: crate::session::feedback_manager::FeedbackFlags,
|
||||
managed_mcp_handle: crate::session::managed_mcp::ManagedMcpStateHandle,
|
||||
managed_mcp_expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
@@ -1751,10 +1719,7 @@ pub(crate) async fn spawn_session_on_thread(
|
||||
codebase_indexes,
|
||||
code_nav_enabled,
|
||||
fs_watch_caps,
|
||||
feedback_proxy_url,
|
||||
feedback_user_token,
|
||||
feedback_alpha_test_key,
|
||||
deployment_key,
|
||||
feedback_base_url,
|
||||
client_terminal_capable,
|
||||
client_fs_capable,
|
||||
gateway_enabled,
|
||||
@@ -1769,7 +1734,6 @@ pub(crate) async fn spawn_session_on_thread(
|
||||
persisted_goal_mode,
|
||||
persisted_announcement_state,
|
||||
memory_config,
|
||||
loc_tracking_enabled,
|
||||
feedback_flags,
|
||||
managed_mcp_handle,
|
||||
managed_mcp_expires_at,
|
||||
|
||||
Reference in new issue
Block a user