§9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok' crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party license archives, README provenance, and the required 'Based on Grok Build Open Source' attribution, now sourced from version_attribution.txt). Wire-visible renames (both sides in this repo, changed in lockstep): - Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode). - Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* / _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps a read-side alias for the legacy '_x.ai/session/update' method so existing updates.jsonl histories load; writes emit only the new name (both directions test-pinned). - Agent types grok-build* → kigi* with a documented legacy-prefix alias at resolution time so persisted sessions keep resolving. - ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build implementation dirs renamed to kigi*. - x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes grokday/groknight → kigiday/kiginight (old persisted values fall back to the default theme), web_fetch allowlist xAI hosts → kimi.com + moonshot platforms, changelog CDN → this repo, grok-build changelog archives deleted. - BYOK default endpoint removed: [endpoints] api_base_url is now truly optional with NO default — consumers fail fast with the flag name when unset (no silent x.ai egress). Mock harnesses inject it explicitly. - System-prompt identity fixed: 'released by xAI' → 'an unofficial community CLI for Kimi' (template + regenerated encrypted form). Also repaired pre-existing grok-era test debt found by the sweep: the stale trace_classify default-model pin, the grok-pager UA label test, pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY test could previously reach the real api.moonshot.cn), and the outdated oauth fixture scope key. Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings); FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed; deny advisories ok.
This commit is contained in:
@@ -616,7 +616,7 @@ fn transform_session_id_in_update(
|
||||
/// 2. Truncates at the last complete turn boundary. A complete turn runs
|
||||
/// `User → Assistant → (matching ToolResults)`, possibly across multiple
|
||||
/// Assistant/ToolResult cycles, with `Reasoning` siblings interleaved
|
||||
/// throughout (real grok-build turns emit `[reasoning, assistant, tool
|
||||
/// throughout (real kigi turns emit `[reasoning, assistant, tool
|
||||
/// results, reasoning, assistant, ...]`). The scan treats everything
|
||||
/// except `Assistant` as transparent and only advances the boundary when an
|
||||
/// Assistant closes every tool call it made, so it survives reasoning
|
||||
|
||||
@@ -121,7 +121,7 @@ async fn test_jsonl_round_trip() {
|
||||
.unwrap();
|
||||
let plan_state = create_test_plan_state();
|
||||
adapter.write_plan_state(&info, &plan_state).await.unwrap();
|
||||
let new_model = acp::ModelId::new("grok-4.3");
|
||||
let new_model = acp::ModelId::new("kigi-4.3");
|
||||
adapter.update_current_model(&info, &new_model).await.unwrap();
|
||||
let loaded = adapter.load_session(&info).await.unwrap();
|
||||
assert_eq!(loaded.summary.info.id, info.id);
|
||||
@@ -456,12 +456,12 @@ async fn test_subagent_notifications_round_trip() {
|
||||
.len()
|
||||
);
|
||||
let spawned_json: serde_json::Value = serde_json::from_str(lines[0]).unwrap();
|
||||
assert_eq!(spawned_json["method"], "_x.ai/session/update");
|
||||
assert_eq!(spawned_json["method"], "_kigi/session/update");
|
||||
let spawned_update = &spawned_json["params"]["update"];
|
||||
assert_eq!(spawned_update["sessionUpdate"], "subagent_spawned");
|
||||
assert_eq!(spawned_update["subagent_id"], "child-001");
|
||||
let finished_json: serde_json::Value = serde_json::from_str(lines[1]).unwrap();
|
||||
assert_eq!(finished_json["method"], "_x.ai/session/update");
|
||||
assert_eq!(finished_json["method"], "_kigi/session/update");
|
||||
let finished_update = &finished_json["params"]["update"];
|
||||
assert_eq!(finished_update["sessionUpdate"], "subagent_finished");
|
||||
assert_eq!(finished_update["tool_calls"], 5);
|
||||
@@ -742,13 +742,13 @@ async fn test_copy_session_data_with_model_override() {
|
||||
};
|
||||
let options = CopySessionOptions {
|
||||
parent_session_id: Some("source-model-test".to_string()),
|
||||
new_model_id: Some("grok-3".to_string()),
|
||||
new_model_id: Some("kigi-3".to_string()),
|
||||
target_prompt_index: None,
|
||||
..Default::default()
|
||||
};
|
||||
adapter.copy_session_data(&source_info, &target_info, options).await.unwrap();
|
||||
let loaded = adapter.load_session(&target_info).await.unwrap();
|
||||
assert_eq!(loaded.summary.current_model_id.0.as_ref(), "grok-3");
|
||||
assert_eq!(loaded.summary.current_model_id.0.as_ref(), "kigi-3");
|
||||
assert_eq!(loaded.summary.parent_session_id, Some("source-model-test".to_string()));
|
||||
}
|
||||
#[tokio::test]
|
||||
@@ -1108,8 +1108,8 @@ async fn test_append_feedback_creates_file_and_persists() {
|
||||
rating_value: Some(1),
|
||||
feedback_text: None,
|
||||
feedback_categories: vec![],
|
||||
model_id: Some("grok-3-fast".into()),
|
||||
resolved_model_id: Some("grok-4.5".into()),
|
||||
model_id: Some("kigi-3-fast".into()),
|
||||
resolved_model_id: Some("kigi-4.5".into()),
|
||||
model_fingerprint: None,
|
||||
context_type: None,
|
||||
request_id: None,
|
||||
@@ -1163,7 +1163,7 @@ async fn test_copy_session_data_copies_tool_state() {
|
||||
.await
|
||||
.unwrap();
|
||||
let tool_state_json = serde_json::json!(
|
||||
{ "state" : { "grok_build.TodoState" : { "todos" : [] } } }
|
||||
{ "state" : { "kigi.TodoState" : { "todos" : [] } } }
|
||||
);
|
||||
let source_dir = adapter.session_dir(&source_info);
|
||||
std::fs::write(
|
||||
@@ -2250,7 +2250,7 @@ fn load_lines(lines: &[&str]) -> Vec<ConversationItem> {
|
||||
}
|
||||
/// Real-shape legacy fixture from a web-search session.
|
||||
/// The assistant carries `reasoning: { text, encrypted, id }` inline —
|
||||
/// the legacy grok-build / Opus / chat-completions shape.
|
||||
/// the legacy kigi / Opus / chat-completions shape.
|
||||
/// BackendToolCall sits as its own sibling line (it was already a
|
||||
/// sibling variant in the legacy shape).
|
||||
#[test]
|
||||
@@ -2260,7 +2260,7 @@ fn read_chat_history_upgrades_legacy_singular_reasoning_to_sibling() {
|
||||
r#"{"type":"system","content":"You are helpful."}"#,
|
||||
r#"{"type":"user","content":[{"type":"text","text":"cats and dogs"}]}"#,
|
||||
r#"{"type":"backend_tool_call","kind":{"tool_type":"web_search","id":"ws_legacy_1","status":"completed","action":{"type":"search","query":"cats and dogs","sources":[]}}}"#,
|
||||
r#"{"type":"assistant","content":"results...","reasoning":{"text":"the results are about cats","encrypted":"enc-blob","id":"rs_legacy"},"model_id":"grok-build"}"#,
|
||||
r#"{"type":"assistant","content":"results...","reasoning":{"text":"the results are about cats","encrypted":"enc-blob","id":"rs_legacy"},"model_id":"kigi"}"#,
|
||||
],
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -2336,11 +2336,11 @@ fn read_chat_history_handles_hybrid_legacy_and_post_pr_lines() {
|
||||
r#"{"type":"system","content":"sys"}"#,
|
||||
r#"{"type":"user","content":[{"type":"text","text":"q1"}]}"#,
|
||||
r#"{"type":"backend_tool_call","kind":{"tool_type":"web_search","id":"ws_legacy_1","status":"completed","action":{"type":"search","query":"q1","sources":[]}}}"#,
|
||||
r#"{"type":"assistant","content":"a1","reasoning":{"text":"legacy thinking","encrypted":"enc","id":"rs_legacy"},"model_id":"grok-build"}"#,
|
||||
r#"{"type":"assistant","content":"a1","reasoning":{"text":"legacy thinking","encrypted":"enc","id":"rs_legacy"},"model_id":"kigi"}"#,
|
||||
r#"{"type":"user","content":[{"type":"text","text":"q2"}]}"#,
|
||||
r#"{"type":"reasoning","id":"rs_postpr","summary":[{"type":"summary_text","text":"new thinking"}]}"#,
|
||||
r#"{"type":"backend_tool_call","kind":{"tool_type":"web_search","id":"ws_postpr","status":"completed","action":{"type":"search","query":"q2","sources":[]}}}"#,
|
||||
r#"{"type":"assistant","content":"a2","model_id":"grok-build"}"#,
|
||||
r#"{"type":"assistant","content":"a2","model_id":"kigi"}"#,
|
||||
],
|
||||
);
|
||||
let kinds: Vec<&'static str> = items
|
||||
@@ -2381,7 +2381,7 @@ fn read_chat_history_handles_hybrid_legacy_and_post_pr_lines() {
|
||||
};
|
||||
assert_eq!(legacy_assistant.content.as_ref(), "a1");
|
||||
assert_eq!(
|
||||
legacy_assistant.model_id.as_deref(), Some("grok-build"),
|
||||
legacy_assistant.model_id.as_deref(), Some("kigi"),
|
||||
"model_id preserved across the upgrade"
|
||||
);
|
||||
let ConversationItem::Reasoning(reconstructed) = &items[3] else {
|
||||
@@ -2402,7 +2402,7 @@ fn read_chat_history_is_idempotent_on_post_pr_sessions() {
|
||||
r#"{"type":"system","content":"sys"}"#,
|
||||
r#"{"type":"user","content":[{"type":"text","text":"q"}]}"#,
|
||||
r#"{"type":"reasoning","id":"rs_x","summary":[{"type":"summary_text","text":"thought"}]}"#,
|
||||
r#"{"type":"assistant","content":"a","model_id":"grok-build"}"#,
|
||||
r#"{"type":"assistant","content":"a","model_id":"kigi"}"#,
|
||||
],
|
||||
);
|
||||
let kinds: Vec<&'static str> = items
|
||||
@@ -2516,7 +2516,7 @@ fn read_chat_history_skips_merged_line_from_interrupted_append() {
|
||||
let good_1 = r#"{"type":"user","content":[{"type":"text","text":"kept"}]}"#;
|
||||
let partial = r#"{"type":"assistant","content":"cut mid-wri"#;
|
||||
let merged_onto = r#"{"type":"user","content":[{"type":"text","text":"lost"}]}"#;
|
||||
let good_2 = r#"{"type":"assistant","content":"after","model_id":"grok-build"}"#;
|
||||
let good_2 = r#"{"type":"assistant","content":"after","model_id":"kigi"}"#;
|
||||
let raw = format!("{good_1}\n{partial}{merged_onto}\n{good_2}\n");
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
let (_, _, items) = load_raw_chat(&temp_dir, raw.as_bytes());
|
||||
|
||||
@@ -92,8 +92,22 @@ impl Iterator for UpdatesIterator {
|
||||
/// Method name for standard ACP session/update notifications.
|
||||
const ACP_SESSION_UPDATE_METHOD: &str = "session/update";
|
||||
|
||||
/// Method name for xAI extension session/update notifications.
|
||||
pub(crate) const XAI_SESSION_UPDATE_METHOD: &str = "_x.ai/session/update";
|
||||
/// Method name for extension session/update notifications.
|
||||
pub(crate) const XAI_SESSION_UPDATE_METHOD: &str = "_kigi/session/update";
|
||||
|
||||
/// Pre-rebrand spelling of [`XAI_SESSION_UPDATE_METHOD`], as written into
|
||||
/// `updates.jsonl` by builds that predate the `kigi/` extension-method
|
||||
/// rename. READ-SIDE ALIAS ONLY: parsing accepts both spellings so existing
|
||||
/// session files keep loading; the write side always emits
|
||||
/// [`XAI_SESSION_UPDATE_METHOD`].
|
||||
pub(crate) const LEGACY_XAI_SESSION_UPDATE_METHOD: &str = "_x.ai/session/update";
|
||||
|
||||
/// Whether `method` names the extension session-update rail, accepting the
|
||||
/// current spelling and the legacy pre-rebrand spelling (persisted session
|
||||
/// files written by older builds).
|
||||
pub(crate) fn is_ext_session_update_method(method: &str) -> bool {
|
||||
method == XAI_SESSION_UPDATE_METHOD || method == LEGACY_XAI_SESSION_UPDATE_METHOD
|
||||
}
|
||||
|
||||
/// A unified session update that can be either an ACP notification or an xAI extension notification.
|
||||
/// This allows storing all session updates in chronological order.
|
||||
@@ -153,7 +167,7 @@ pub(crate) struct SessionUpdateEnvelope {
|
||||
#[serde(default)]
|
||||
pub timestamp: u64,
|
||||
/// The method name identifying the update type.
|
||||
/// Either "session/update" for ACP or "_x.ai/session/update" for xAI extensions.
|
||||
/// Either "session/update" for ACP or "_kigi/session/update" for xAI extensions.
|
||||
pub method: String,
|
||||
/// The actual notification payload.
|
||||
pub params: serde_json::Value,
|
||||
@@ -183,7 +197,7 @@ impl SessionUpdateEnvelope {
|
||||
|
||||
/// Convert this envelope back into a SessionUpdate.
|
||||
pub(crate) fn into_update(self) -> Result<SessionUpdate, serde_json::Error> {
|
||||
if self.method == XAI_SESSION_UPDATE_METHOD {
|
||||
if is_ext_session_update_method(&self.method) {
|
||||
let notification: SessionNotification = serde_json::from_value(self.params)?;
|
||||
Ok(SessionUpdate::Xai(Box::new(notification)))
|
||||
} else {
|
||||
@@ -224,7 +238,7 @@ impl SessionUpdateEnvelope {
|
||||
// Try to parse as envelope first (has "method" + "params")
|
||||
if let Ok(envelope) = serde_json::from_str::<BorrowedEnvelope<'_>>(line) {
|
||||
let raw_params = envelope.params.get();
|
||||
return if envelope.method == Some(XAI_SESSION_UPDATE_METHOD) {
|
||||
return if envelope.method.is_some_and(is_ext_session_update_method) {
|
||||
let notification: SessionNotification = serde_json::from_str(raw_params)?;
|
||||
Ok(SessionUpdate::Xai(Box::new(notification)))
|
||||
} else {
|
||||
@@ -774,7 +788,7 @@ pub(crate) fn filter_rewind_lines<'a>(lines: Vec<&'a str>) -> Vec<&'a str> {
|
||||
for line in &lines {
|
||||
let (raw_params, is_xai) = if let Ok(env) = serde_json::from_str::<RawLinePeek<'_>>(line) {
|
||||
let raw = env.params.map(|p| p.get()).unwrap_or(line);
|
||||
let xai = env.method == Some(XAI_SESSION_UPDATE_METHOD);
|
||||
let xai = env.method.is_some_and(is_ext_session_update_method);
|
||||
(raw, xai)
|
||||
} else {
|
||||
(*line, false)
|
||||
@@ -923,7 +937,7 @@ pub fn load_updates_for_replay(
|
||||
load_updates_for_replay_from_dir(&session_dir)
|
||||
}
|
||||
|
||||
/// Like [`load_updates_for_replay`], but resolves the session under a specific grok home.
|
||||
/// Like [`load_updates_for_replay`], but resolves the session under a specific kigi home.
|
||||
pub fn load_updates_for_replay_at(
|
||||
session_id: &str,
|
||||
kigi_home: &std::path::Path,
|
||||
@@ -1666,7 +1680,7 @@ pub(crate) fn parse_prompt_extract_event(line: &str) -> PromptExtractEvent {
|
||||
// Step 1: try to extract the envelope (method + raw params).
|
||||
let (raw_params, is_xai) = if let Ok(env) = serde_json::from_str::<RawLinePeek<'_>>(line) {
|
||||
let raw = env.params.map(|p| p.get()).unwrap_or(line);
|
||||
let xai = env.method == Some(XAI_SESSION_UPDATE_METHOD);
|
||||
let xai = env.method.is_some_and(is_ext_session_update_method);
|
||||
(raw, xai)
|
||||
} else {
|
||||
// Not a valid envelope → try legacy format: the line IS the params.
|
||||
@@ -1739,7 +1753,7 @@ mod tests {
|
||||
/// Wrap a xAI notification as the envelope stored in updates.jsonl.
|
||||
fn xai_envelope(session_update_json: &str) -> String {
|
||||
format!(
|
||||
r#"{{"timestamp":1,"method":"_x.ai/session/update","params":{{"sessionId":"s","update":{session_update_json}}}}}"#
|
||||
r#"{{"timestamp":1,"method":"_kigi/session/update","params":{{"sessionId":"s","update":{session_update_json}}}}}"#
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2479,7 +2493,7 @@ mod tests {
|
||||
r#"{"eventId":"ev1"}"#,
|
||||
);
|
||||
// xAI-style line persisted by an older binary: no _meta at all.
|
||||
let old_xai = r#"{"timestamp":2,"method":"_x.ai/session/update","params":{"sessionId":"s","update":{"sessionUpdate":"hook_annotation","message":"trailing"}}}"#;
|
||||
let old_xai = r#"{"timestamp":2,"method":"_kigi/session/update","params":{"sessionId":"s","update":{"sessionUpdate":"hook_annotation","message":"trailing"}}}"#;
|
||||
let raw = format!("{a1}\n{old_xai}\n");
|
||||
|
||||
let prepared = prepare_replay_lines(&raw, Some("ev1"));
|
||||
@@ -2490,7 +2504,7 @@ mod tests {
|
||||
assert_eq!(prepared.lines.len(), 2, "full history is replayed");
|
||||
|
||||
// Same history with the trailing line stamped resolves incrementally.
|
||||
let new_xai = r#"{"timestamp":2,"method":"_x.ai/session/update","params":{"sessionId":"s","update":{"sessionUpdate":"hook_annotation","message":"trailing"},"_meta":{"eventId":"ev2"}}}"#;
|
||||
let new_xai = r#"{"timestamp":2,"method":"_kigi/session/update","params":{"sessionId":"s","update":{"sessionUpdate":"hook_annotation","message":"trailing"},"_meta":{"eventId":"ev2"}}}"#;
|
||||
let raw = format!("{a1}\n{new_xai}\n");
|
||||
let prepared = prepare_replay_lines(&raw, Some("ev1"));
|
||||
assert!(!prepared.mark_replay);
|
||||
@@ -2961,12 +2975,12 @@ mod tests {
|
||||
fn prepare_replay_reports_spawn_without_finish() {
|
||||
let spawn = |id: &str, child: &str| {
|
||||
format!(
|
||||
r#"{{"method":"_x.ai/session/update","params":{{"sessionId":"s","update":{{"sessionUpdate":"subagent_spawned","subagent_id":"{id}","parent_session_id":"s","child_session_id":"{child}","subagent_type":"general-purpose","description":"task"}},"_meta":{{"eventId":"s-1"}}}}}}"#
|
||||
r#"{{"method":"_kigi/session/update","params":{{"sessionId":"s","update":{{"sessionUpdate":"subagent_spawned","subagent_id":"{id}","parent_session_id":"s","child_session_id":"{child}","subagent_type":"general-purpose","description":"task"}},"_meta":{{"eventId":"s-1"}}}}}}"#
|
||||
)
|
||||
};
|
||||
let finish = |id: &str| {
|
||||
format!(
|
||||
r#"{{"method":"_x.ai/session/update","params":{{"sessionId":"s","update":{{"sessionUpdate":"subagent_finished","subagent_id":"{id}","child_session_id":"c{id}","status":"completed","tool_calls":0,"turns":0,"duration_ms":0}},"_meta":{{"eventId":"s-2"}}}}}}"#
|
||||
r#"{{"method":"_kigi/session/update","params":{{"sessionId":"s","update":{{"sessionUpdate":"subagent_finished","subagent_id":"{id}","child_session_id":"c{id}","status":"completed","tool_calls":0,"turns":0,"duration_ms":0}},"_meta":{{"eventId":"s-2"}}}}}}"#
|
||||
)
|
||||
};
|
||||
// `a` spawns and finishes (paired); `b` only spawns (orphan).
|
||||
@@ -3139,4 +3153,38 @@ mod tests {
|
||||
SessionUpdate::Acp(_) => panic!("expected Xai variant"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Session files written before the `kigi/` extension-method rename carry
|
||||
/// the legacy `_…/session/update` method name. The read-side alias must
|
||||
/// keep those lines loading as extension updates; the write side always
|
||||
/// emits the current [`XAI_SESSION_UPDATE_METHOD`].
|
||||
#[test]
|
||||
fn from_str_accepts_legacy_pre_rebrand_method_name() {
|
||||
let line = format!(
|
||||
r#"{{"timestamp":1,"method":"{LEGACY_XAI_SESSION_UPDATE_METHOD}","params":{{"sessionId":"s","update":{{"sessionUpdate":"memory_flush_started"}}}}}}"#
|
||||
);
|
||||
let update = SessionUpdateEnvelope::from_str(&line).unwrap();
|
||||
match &update {
|
||||
SessionUpdate::Xai(notif) => {
|
||||
assert_eq!(
|
||||
notif.update,
|
||||
crate::extensions::notification::SessionUpdate::MemoryFlushStarted
|
||||
);
|
||||
}
|
||||
SessionUpdate::Acp(_) => panic!("expected Xai variant for legacy method name"),
|
||||
}
|
||||
|
||||
// Both spellings classify as the extension rail; an unrelated method
|
||||
// does not.
|
||||
assert!(is_ext_session_update_method(XAI_SESSION_UPDATE_METHOD));
|
||||
assert!(is_ext_session_update_method(
|
||||
LEGACY_XAI_SESSION_UPDATE_METHOD
|
||||
));
|
||||
assert!(!is_ext_session_update_method("session/update"));
|
||||
|
||||
// Write side: envelopes produced today carry the current name only.
|
||||
let reserialized = serde_json::to_string(&update).unwrap();
|
||||
assert!(reserialized.contains(XAI_SESSION_UPDATE_METHOD));
|
||||
assert!(!reserialized.contains(LEGACY_XAI_SESSION_UPDATE_METHOD));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! The index is bootstrapped (all sessions indexed) on first search.
|
||||
//! After that, individual sessions are re-indexed on save/title update
|
||||
//! via `notify_session_updated()`. Because the SQLite DB is shared with
|
||||
//! other concurrently running grok processes (which may wipe or downgrade
|
||||
//! other concurrently running kigi processes (which may wipe or downgrade
|
||||
//! it — older binaries drop-and-restamp the schema on open), every
|
||||
//! subsequent search re-verifies the on-disk completed-bootstrap marker
|
||||
//! and re-runs the full bootstrap when it is missing.
|
||||
@@ -27,7 +27,7 @@ use super::search_fts::{SessionDoc, SessionSearchIndex, SessionSearchRow};
|
||||
use super::search_remote_sync;
|
||||
use super::{
|
||||
ContentPeek, PromptExtractEvent, RawLinePeek, RawParamsPeek, StorageAdapter,
|
||||
XAI_SESSION_UPDATE_METHOD, collect_prompts_from_events,
|
||||
collect_prompts_from_events, is_ext_session_update_method,
|
||||
};
|
||||
use crate::session::info::Info;
|
||||
use crate::session::persistence::Summary;
|
||||
@@ -133,7 +133,7 @@ struct SearchManagerState {
|
||||
///
|
||||
/// Requires an active tokio runtime on first access (spawns tasks).
|
||||
///
|
||||
/// TODO: When multiple grok processes run concurrently, they each have
|
||||
/// TODO: When multiple kigi processes run concurrently, they each have
|
||||
/// their own `SearchIndexManager` writing to the same SQLite database.
|
||||
/// WAL mode prevents corruption, but redundant work is done. Consider
|
||||
/// adding reindex claim coordination (like the memory system's
|
||||
@@ -921,7 +921,7 @@ fn collect_all_indexable_content_single_pass(updates_path: &Path) -> io::Result<
|
||||
let (raw_params, is_xai) = if let Ok(env) = serde_json::from_str::<RawLinePeek<'_>>(trimmed)
|
||||
{
|
||||
let raw = env.params.map(|p| p.get()).unwrap_or(trimmed);
|
||||
let xai = env.method == Some(XAI_SESSION_UPDATE_METHOD);
|
||||
let xai = env.method.is_some_and(is_ext_session_update_method);
|
||||
(raw, xai)
|
||||
} else {
|
||||
(trimmed, false)
|
||||
@@ -938,7 +938,7 @@ fn collect_all_indexable_content_single_pass(updates_path: &Path) -> io::Result<
|
||||
// Content events (user messages, assistant responses, tool calls,
|
||||
// thoughts) come from the standard ACP protocol ("session/update").
|
||||
// Control events (rewind markers) come from xAI extensions
|
||||
// ("_x.ai/session/update"). Dispatch on source first, then tag.
|
||||
// ("_kigi/session/update"). Dispatch on source first, then tag.
|
||||
if !is_xai {
|
||||
// ── ACP content events ──────────────────────────────────
|
||||
match tag {
|
||||
@@ -1176,7 +1176,7 @@ fn collect_delta_content(updates_path: &Path, offset: u64) -> io::Result<DeltaRe
|
||||
let (raw_params, is_xai) = if let Ok(env) = serde_json::from_str::<RawLinePeek<'_>>(trimmed)
|
||||
{
|
||||
let raw = env.params.map(|p| p.get()).unwrap_or(trimmed);
|
||||
let xai = env.method == Some(XAI_SESSION_UPDATE_METHOD);
|
||||
let xai = env.method.is_some_and(is_ext_session_update_method);
|
||||
(raw, xai)
|
||||
} else {
|
||||
(trimmed, false)
|
||||
@@ -1389,7 +1389,7 @@ mod tests {
|
||||
|
||||
fn xai_update(session_update_json: &str) -> String {
|
||||
format!(
|
||||
r#"{{"timestamp":1,"method":"_x.ai/session/update","params":{{"sessionId":"s","update":{session_update_json}}}}}"#
|
||||
r#"{{"timestamp":1,"method":"_kigi/session/update","params":{{"sessionId":"s","update":{session_update_json}}}}}"#
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ impl SessionSearchIndex {
|
||||
.unwrap_or(None);
|
||||
|
||||
// One-way ratchet: drop only on UPGRADE (stored < current). Multiple
|
||||
// grok generations share this DB (stable vs alpha); an equality check
|
||||
// kigi generations share this DB (stable vs alpha); an equality check
|
||||
// made each binary wipe the other's index in a ping-pong that left
|
||||
// search empty mid-rebootstrap. A newer index is safe to read: bumps
|
||||
// regenerate content only (table schema is column-identical), and the
|
||||
@@ -709,7 +709,7 @@ mod tests {
|
||||
index
|
||||
.upsert_doc(&test_doc("s1", "Rust debugging", "borrow checker"))
|
||||
.unwrap();
|
||||
// Simulate an index owned by a newer grok generation that has
|
||||
// Simulate an index owned by a newer kigi generation that has
|
||||
// completed a bootstrap.
|
||||
index
|
||||
.set_meta("session_search_schema_version", "5")
|
||||
|
||||
Reference in New Issue
Block a user