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:
@@ -128,7 +128,16 @@ pub fn stream_chat_completions<'a>(
|
||||
first_chunk_seen = true;
|
||||
}
|
||||
|
||||
if let Some(u) = chunk.usage.clone() {
|
||||
// Kimi/Moonshot deviation: usage may ride inside a choice instead
|
||||
// of (or in addition to) the chunk's top-level `usage`. Same
|
||||
// fallback as kimi-cli's `extract_usage_from_chunk`
|
||||
// (packages/kosong/src/kosong/chat_provider/kimi.py:522-533):
|
||||
// top-level wins, else the first choice carrying one.
|
||||
let chunk_usage = chunk
|
||||
.usage
|
||||
.clone()
|
||||
.or_else(|| chunk.choices.iter().find_map(|c| c.usage.clone()));
|
||||
if let Some(u) = chunk_usage {
|
||||
// Wire cost is cumulative for the response, so last-write-wins.
|
||||
// Never clobber a known cost with missing/unreported.
|
||||
let chunk_cost = kigi_sampling_types::reported_cost_ticks(u.cost_in_usd_ticks);
|
||||
@@ -247,10 +256,27 @@ pub fn stream_chat_completions<'a>(
|
||||
// ── Build the final response ─────────────────────────────────
|
||||
let tool_calls: Vec<ToolCall> = tool_call_acc
|
||||
.into_values()
|
||||
.map(|(id, name, arguments)| ToolCall {
|
||||
id: std::sync::Arc::<str>::from(id),
|
||||
name,
|
||||
arguments: std::sync::Arc::<str>::from(arguments),
|
||||
.map(|(id, name, arguments)| {
|
||||
// Kimi/Moonshot deviation: tool-call deltas may omit `id`.
|
||||
// Synthesize one so the tool-result round-trip stays keyed,
|
||||
// exactly like kimi-cli (`id=tool_call.id or str(uuid.uuid4())`,
|
||||
// packages/kosong/src/kosong/chat_provider/kimi.py:505).
|
||||
let id = if id.is_empty() {
|
||||
let synthesized = uuid::Uuid::new_v4().to_string();
|
||||
tracing::debug!(
|
||||
tool_name = %name,
|
||||
synthesized_id = %synthesized,
|
||||
"tool-call delta carried no id; synthesized one"
|
||||
);
|
||||
synthesized
|
||||
} else {
|
||||
id
|
||||
};
|
||||
ToolCall {
|
||||
id: std::sync::Arc::<str>::from(id),
|
||||
name,
|
||||
arguments: std::sync::Arc::<str>::from(arguments),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -329,6 +355,7 @@ mod tests {
|
||||
index: i as u32,
|
||||
delta,
|
||||
finish_reason: None,
|
||||
usage: None,
|
||||
})
|
||||
.collect(),
|
||||
usage: None,
|
||||
@@ -664,6 +691,7 @@ mod tests {
|
||||
prompt_tokens: 100,
|
||||
completion_tokens: 50,
|
||||
total_tokens: 150,
|
||||
cached_tokens: None,
|
||||
prompt_tokens_details: None,
|
||||
completion_tokens_details: None,
|
||||
cost_in_usd_ticks: None,
|
||||
@@ -704,6 +732,7 @@ mod tests {
|
||||
prompt_tokens: 10,
|
||||
completion_tokens: 5,
|
||||
total_tokens: 15,
|
||||
cached_tokens: None,
|
||||
prompt_tokens_details: None,
|
||||
completion_tokens_details: None,
|
||||
cost_in_usd_ticks: wire,
|
||||
@@ -737,6 +766,7 @@ mod tests {
|
||||
prompt_tokens: 10,
|
||||
completion_tokens: 5,
|
||||
total_tokens: 15,
|
||||
cached_tokens: None,
|
||||
prompt_tokens_details: None,
|
||||
completion_tokens_details: None,
|
||||
cost_in_usd_ticks: Some(99),
|
||||
@@ -746,6 +776,7 @@ mod tests {
|
||||
prompt_tokens: 12,
|
||||
completion_tokens: 6,
|
||||
total_tokens: 18,
|
||||
cached_tokens: None,
|
||||
prompt_tokens_details: None,
|
||||
completion_tokens_details: None,
|
||||
cost_in_usd_ticks: Some(0),
|
||||
|
||||
@@ -90,6 +90,7 @@ mod tests {
|
||||
tool_call_id: None,
|
||||
},
|
||||
finish_reason: None,
|
||||
usage: None,
|
||||
}],
|
||||
usage: None,
|
||||
system_fingerprint: None,
|
||||
@@ -106,6 +107,7 @@ mod tests {
|
||||
index: 0,
|
||||
delta: ChatChunkDelta::default(),
|
||||
finish_reason: Some(FinishReason::Stop),
|
||||
usage: None,
|
||||
}],
|
||||
usage: None,
|
||||
system_fingerprint: None,
|
||||
|
||||
@@ -429,7 +429,6 @@ pub fn stream_messages<'a>(
|
||||
message: error_message,
|
||||
model_metadata: None,
|
||||
retry_after_secs: None,
|
||||
should_retry: None,
|
||||
};
|
||||
yield SamplingEvent::Failed {
|
||||
request_id: request_id.clone(),
|
||||
|
||||
@@ -299,7 +299,6 @@ pub fn stream_responses<'a>(
|
||||
message: error_message,
|
||||
model_metadata: None,
|
||||
retry_after_secs: None,
|
||||
should_retry: None,
|
||||
};
|
||||
yield SamplingEvent::Failed {
|
||||
request_id: request_id.clone(),
|
||||
@@ -316,7 +315,6 @@ pub fn stream_responses<'a>(
|
||||
message: error_message,
|
||||
model_metadata: None,
|
||||
retry_after_secs: None,
|
||||
should_retry: None,
|
||||
};
|
||||
yield SamplingEvent::Failed {
|
||||
request_id: request_id.clone(),
|
||||
@@ -419,7 +417,6 @@ pub fn stream_responses<'a>(
|
||||
.to_string(),
|
||||
model_metadata: None,
|
||||
retry_after_secs: None,
|
||||
should_retry: None,
|
||||
};
|
||||
yield SamplingEvent::Failed {
|
||||
request_id: request_id.clone(),
|
||||
|
||||
Reference in New Issue
Block a user