§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:
ZacharyZhang-NY committed 2026-07-18 02:48:46 -04:00
1 parent 86e3724310
commit 6f31415ed6
1056 files changed
+8410 -18307

No files matched your search

@@ -22,7 +22,7 @@ impl RoleCapability {
/// `can_execute` for terminal/bash).
fn is_satisfied(
self,
summary: &kigi_tools::implementations::grok_build::task::types::SubagentTypeSummary,
summary: &kigi_tools::implementations::kigi::task::types::SubagentTypeSummary,
) -> bool {
match self {
Self::Skeptic => summary.can_read && summary.can_search,
@@ -42,7 +42,7 @@ pub(crate) struct PanelResolveCache {
/// result for the role's `general-purpose` toolset on that harness).
describe: std::collections::HashMap<
String,
kigi_tools::implementations::grok_build::task::types::SubagentDescribeOutcome,
kigi_tools::implementations::kigi::task::types::SubagentDescribeOutcome,
>,
}
@@ -57,7 +57,7 @@ fn role_tool_names_from(
cache: &PanelResolveCache,
inherit: &crate::session::goal_role_tools::RoleToolNames,
) -> crate::session::goal_role_tools::RoleToolNames {
use kigi_tools::implementations::grok_build::task::types::SubagentDescribeOutcome;
use kigi_tools::implementations::kigi::task::types::SubagentDescribeOutcome;
// `override_.agent_type` is the committed harness; the cache is keyed on it.
match override_.agent_type.as_deref() {
Some(harness) => match cache.describe.get(harness) {
@@ -115,9 +115,9 @@ impl SessionActor {
&self,
current_tokens: i64,
purpose: DrainPurpose,
extra: Vec<kigi_tools::implementations::grok_build::update_goal::UpdateGoalEnvelope>,
extra: Vec<kigi_tools::implementations::kigi::update_goal::UpdateGoalEnvelope>,
) {
use kigi_tools::implementations::grok_build::update_goal::{RejectReason, UpdateGoalAck};
use kigi_tools::implementations::kigi::update_goal::{RejectReason, UpdateGoalAck};
// The `update_goal` tool and its `GoalUpdateHandle` are always
// registered (see `spawn_session_actor`), so a model can call
// `update_goal` in a session that never entered goal mode — e.g. any
@@ -650,10 +650,10 @@ impl SessionActor {
attempt: u32,
outcome: crate::session::goal_classifier::GoalClassifierOutcome,
notify: &crate::session::goal_orchestrator::GoalNotifySender,
) -> kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck {
) -> kigi_tools::implementations::kigi::update_goal::UpdateGoalAck {
use crate::session::goal_classifier::GoalClassifierOutcome;
use crate::session::goal_tracker::GoalClassifierVerdict;
use kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck;
use kigi_tools::implementations::kigi::update_goal::UpdateGoalAck;
let current_tokens = self.chat_state_handle.get_total_tokens().await as i64;
let (tokens_used, finished_marginal) = self.goal_tokens(current_tokens);
@@ -1299,7 +1299,7 @@ impl SessionActor {
choice: &crate::agent::config::GoalRoleModelChoice,
capability: RoleCapability,
event_tx: &tokio::sync::mpsc::UnboundedSender<
kigi_tools::implementations::grok_build::task::types::SubagentEvent,
kigi_tools::implementations::kigi::task::types::SubagentEvent,
>,
) -> (
crate::session::goal_planner::RoleSpawnOverride,
@@ -1372,17 +1372,15 @@ impl SessionActor {
pair: &crate::util::config::GoalRoleModel,
capability: RoleCapability,
event_tx: &tokio::sync::mpsc::UnboundedSender<
kigi_tools::implementations::grok_build::task::types::SubagentEvent,
kigi_tools::implementations::kigi::task::types::SubagentEvent,
>,
available_models: &indexmap::IndexMap<String, crate::agent::config::ModelEntry>,
cache: &mut PanelResolveCache,
) -> crate::session::goal_planner::RoleSpawnOverride {
use crate::session::events::{Event, GoalRoleModelFailOpenReason as Reason};
use crate::session::goal_planner::RoleSpawnOverride;
use kigi_tools::implementations::grok_build::task::backend::{
ChannelBackend, SubagentBackend,
};
use kigi_tools::implementations::grok_build::task::types::SubagentDescribeOutcome;
use kigi_tools::implementations::kigi::task::backend::{ChannelBackend, SubagentBackend};
use kigi_tools::implementations::kigi::task::types::SubagentDescribeOutcome;
let fail_open = |reason: Reason| {
self.emit_event(Event::GoalRoleModelFailOpen {
@@ -1408,7 +1406,7 @@ impl SessionActor {
}
// 2b. Reject a STRICT harness whose flavor isn't representable (e.g.
// `codex`): it resolves, but `resolve_subagent_toolset` would
// silently run grok-build flavor. Non-strict names (grok-build
// silently run kigi flavor. Non-strict names (kigi
// family) run the default flavor and pass; unresolvable names fall
// through to the describe `Unknown` arm below.
if kigi_agent::config::is_strict_harness_agent_type(&pair.agent_type)
@@ -1511,9 +1509,9 @@ impl SessionActor {
/// toolset; [`RoleToolNames::from_parent`] applies the literal fallback for
/// any kind the bridge lacks, and resolves `{WRITE_TOOL}` from the parent
/// `Edit` tool when the bridge has no `Write` (so the inherit / retry render
/// agrees with `from_summary` — `search_replace` on the default grok-build
/// agrees with `from_summary` — `search_replace` on the default kigi
/// host, not the literal `write`). The `{TOOLSET_TOOLS}` block is empty on
/// this path (no per-role toolset enumeration); on the default grok-build
/// this path (no per-role toolset enumeration); on the default kigi
/// host the bridge resolves the parent's real tool ids (`read_file`, …).
pub(crate) async fn resolve_inherit_role_tool_names(
&self,
@@ -2340,7 +2338,7 @@ impl SessionActor {
#[cfg(test)]
mod role_capability_tests {
use super::RoleCapability;
use kigi_tools::implementations::grok_build::task::types::SubagentTypeSummary;
use kigi_tools::implementations::kigi::task::types::SubagentTypeSummary;
fn summary(can_read: bool, can_search: bool, can_execute: bool) -> SubagentTypeSummary {
SubagentTypeSummary {
@@ -2371,7 +2369,7 @@ mod role_tool_names_tests {
use super::{PanelResolveCache, role_tool_names_from};
use crate::session::goal_planner::RoleSpawnOverride;
use crate::session::goal_role_tools::RoleToolNames;
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentDescribeOutcome, SubagentTypeSummary,
};
use kigi_tools::types::tool::ToolKind;
@@ -15,10 +15,10 @@ impl DrainSource {
pub(super) fn into_parts(
self,
) -> (
kigi_tools::implementations::grok_build::update_goal::UpdateGoalInput,
kigi_tools::implementations::kigi::update_goal::UpdateGoalInput,
Option<
tokio::sync::oneshot::Sender<
kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck,
kigi_tools::implementations::kigi::update_goal::UpdateGoalAck,
>,
>,
) {
@@ -33,11 +33,9 @@ impl DrainSource {
/// source). No-op for `Pending` source — its ack was already resolved.
pub(super) fn try_send_ack(
ack_tx: Option<
tokio::sync::oneshot::Sender<
kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck,
>,
tokio::sync::oneshot::Sender<kigi_tools::implementations::kigi::update_goal::UpdateGoalAck>,
>,
ack: kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck,
ack: kigi_tools::implementations::kigi::update_goal::UpdateGoalAck,
) {
if let Some(tx) = ack_tx {
send_ack(tx, ack);
@@ -154,9 +152,9 @@ impl<F: FnOnce(&mut crate::session::goal_tracker::GoalTracker)> Drop for Tracker
/// the receiver was dropped (benign — tool future aborted).
pub(super) fn send_ack(
ack_tx: tokio::sync::oneshot::Sender<
kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck,
kigi_tools::implementations::kigi::update_goal::UpdateGoalAck,
>,
ack: kigi_tools::implementations::grok_build::update_goal::UpdateGoalAck,
ack: kigi_tools::implementations::kigi::update_goal::UpdateGoalAck,
) {
if ack_tx.send(ack).is_err() {
tracing::debug!("update_goal ack receiver dropped before harness could respond");
@@ -702,14 +700,14 @@ mod fold_tokens_by_model_tests {
#[test]
fn mixed_models_sum_marginals_sorted_desc() {
let records = vec![
rec(Some("g1"), 0, 100, Some("grok-3")),
rec(Some("g1"), 100, 500, Some("grok-4")), // marginal 400
rec(Some("g1"), 0, 50, Some("grok-3")), // grok-3 total 150
rec(Some("g1"), 0, 100, Some("kigi-3")),
rec(Some("g1"), 100, 500, Some("kigi-4")), // marginal 400
rec(Some("g1"), 0, 50, Some("kigi-3")), // kigi-3 total 150
];
let out = fold_tokens_by_model(&records, "g1", "cur");
assert_eq!(
out,
vec![("grok-4".to_owned(), 400), ("grok-3".to_owned(), 150)]
vec![("kigi-4".to_owned(), 400), ("kigi-3".to_owned(), 150)]
);
}
@@ -736,38 +734,38 @@ mod fold_tokens_by_model_tests {
#[test]
fn single_distinct_model_collapses_to_one_entry() {
let records = vec![
rec(Some("g1"), 0, 100, Some("grok-4")),
rec(Some("g1"), 0, 200, None), // folds under current = grok-4
rec(Some("g1"), 0, 100, Some("kigi-4")),
rec(Some("g1"), 0, 200, None), // folds under current = kigi-4
];
let out = fold_tokens_by_model(&records, "g1", "grok-4");
assert_eq!(out, vec![("grok-4".to_owned(), 300)]);
let out = fold_tokens_by_model(&records, "g1", "kigi-4");
assert_eq!(out, vec![("kigi-4".to_owned(), 300)]);
}
#[test]
fn other_goal_records_excluded() {
let records = vec![
rec(Some("g1"), 0, 100, Some("grok-4")),
rec(Some("g2"), 0, 999, Some("grok-4")),
rec(None, 0, 999, Some("grok-4")),
rec(Some("g1"), 0, 100, Some("kigi-4")),
rec(Some("g2"), 0, 999, Some("kigi-4")),
rec(None, 0, 999, Some("kigi-4")),
];
let out = fold_tokens_by_model(&records, "g1", "cur");
assert_eq!(out, vec![("grok-4".to_owned(), 100)]);
assert_eq!(out, vec![("kigi-4".to_owned(), 100)]);
}
#[test]
fn last_below_anchor_does_not_underflow() {
let records = vec![rec(Some("g1"), 500, 100, Some("grok-4"))];
let records = vec![rec(Some("g1"), 500, 100, Some("kigi-4"))];
// marginal saturates to 0 -> skipped as a zero-token entry.
assert!(fold_tokens_by_model(&records, "g1", "cur").is_empty());
}
#[test]
fn captured_model_survives_mid_goal_current_model_switch() {
// A record captured `grok-4` at spawn keeps it even though the
// current model at aggregation time is `grok-3`.
let records = vec![rec(Some("g1"), 0, 100, Some("grok-4"))];
let out = fold_tokens_by_model(&records, "g1", "grok-3");
assert_eq!(out, vec![("grok-4".to_owned(), 100)]);
// A record captured `kigi-4` at spawn keeps it even though the
// current model at aggregation time is `kigi-3`.
let records = vec![rec(Some("g1"), 0, 100, Some("kigi-4"))];
let out = fold_tokens_by_model(&records, "g1", "kigi-3");
assert_eq!(out, vec![("kigi-4".to_owned(), 100)]);
}
#[test]
@@ -788,11 +786,11 @@ mod fold_tokens_by_model_tests {
// An empty id folds into the SAME bucket as records that
// explicitly captured the current model id.
let records = vec![
rec(Some("g1"), 0, 100, Some("grok-4")),
rec(Some("g1"), 0, 100, Some("kigi-4")),
rec(Some("g1"), 0, 200, Some("")),
];
let out = fold_tokens_by_model(&records, "g1", "grok-4");
assert_eq!(out, vec![("grok-4".to_owned(), 300)]);
let out = fold_tokens_by_model(&records, "g1", "kigi-4");
assert_eq!(out, vec![("kigi-4".to_owned(), 300)]);
}
}
@@ -822,7 +820,7 @@ pub(crate) fn planner_failure_pause_message() -> String {
}
pub(crate) fn goal_slash_and_harness_available(goal_enabled: bool, tool_names: &[String]) -> bool {
use kigi_tools::implementations::grok_build::UPDATE_GOAL_TOOL_NAME;
use kigi_tools::implementations::kigi::UPDATE_GOAL_TOOL_NAME;
goal_enabled && tool_names.iter().any(|n| n == UPDATE_GOAL_TOOL_NAME)
}
@@ -1468,9 +1466,7 @@ impl SessionActor {
self.agent
.borrow()
.tool_bridge()
.update_resource(
kigi_tools::implementations::grok_build::task::types::GoalLoopActive(active),
)
.update_resource(kigi_tools::implementations::kigi::task::types::GoalLoopActive(active))
.await;
}
}
@@ -22,7 +22,7 @@ pub(crate) type PendingInterjection =
/// converted into standalone prompt turns (arrived while idle, or after the
/// running turn's final drain). The prefix keeps the turn's user echo
/// persist-only: every pane already rendered the text from the
/// `x.ai/session/interjection` broadcast, so a live echo would duplicate it.
/// `kigi/session/interjection` broadcast, so a live echo would duplicate it.
pub(crate) const INTERJECT_FALLBACK_PROMPT_PREFIX: &str = "interject-fallback-";
impl SessionActor {
@@ -164,7 +164,7 @@ impl SessionActor {
self.notifications
.gateway
.forward_fire_and_forget(acp::ExtNotification::new(
"x.ai/session/interjection",
"kigi/session/interjection",
params.into(),
));
}
@@ -323,7 +323,7 @@ impl SessionActor {
/// the sampler call goes through `prepare_chat_completion().conversation_collect()`
/// — a side-channel direct-HTTP call that does NOT publish events
/// on the per-session shared sampler channel. The client never
/// sees "Grok is thinking", streaming token chunks, or any other
/// sees "Kigi is thinking", streaming token chunks, or any other
/// session update from a classifier fire. Stalled verdicts only
/// queue a `<system-reminder>` into chat state via
/// `push_system_reminder`; no `InputItem` is pushed into
@@ -549,18 +549,18 @@ impl SessionActor {
model: Some(model_id.clone()),
temperature: Some(0.0),
max_output_tokens: Some(LAZINESS_MAX_OUTPUT_TOKENS),
// Don't pass `reasoning_effort` — `grok-4.5` (and
// other tool-flavoured Grok variants) reject the field at
// Don't pass `reasoning_effort` — `kigi-4.5` (and
// other tool-flavoured Kigi variants) reject the field at
// the proxy with `400 Bad Request: Model does not support
// parameter reasoningEffort`. Omitting it lets each model
// apply its own default. The classifier task is one short
// JSON object — even on reasoning-capable models the
// default suffices; no need to force it off.
reasoning_effort: None,
x_grok_conv_id: Some(session_id_str.clone()),
x_grok_req_id: Some(format!("{LAZINESS_REQ_ID_PREFIX}{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(session_id_str),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(session_id_str.clone()),
x_kigi_req_id: Some(format!("{LAZINESS_REQ_ID_PREFIX}{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(session_id_str),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..ConversationRequest::default()
};
@@ -110,7 +110,7 @@ impl LazinessAbortReason {
/// Prompt-structure mitigations against motivated reasoning:
/// "Do not roleplay", JSON-only, no chain-of-thought,
/// no role context, transcript framed as third-party data.
/// Prefix on `x_grok_req_id` for laziness-classifier sampler calls.
/// Prefix on `x_kigi_req_id` for laziness-classifier sampler calls.
/// Centralised here so the production producer
/// (`maybe_fire_laziness_check`) AND the offline replay harness
/// (`crate::trace_classifier::build_classifier_request`) share a
@@ -150,7 +150,7 @@ impl SessionActor {
);
}
}
/// Emit per-server `x.ai/mcp/tools_changed` notifications.
/// Emit per-server `kigi/mcp/tools_changed` notifications.
///
/// Each emission carries the owning
/// `sessionId` so the pager can route via `find_session_match`
@@ -182,7 +182,7 @@ impl SessionActor {
}
}
}
/// Handle explicit auth trigger from the client (x.ai/mcp/auth_trigger).
/// Handle explicit auth trigger from the client (kigi/mcp/auth_trigger).
///
/// Runs force_reauth (browser flow), then re-initializes the server
/// and registers its tools.
@@ -580,7 +580,7 @@ impl SessionActor {
/// On success: the new `Arc<McpClient>` is in
/// `mcp_state.owned_clients[server]` with `ClientState::Ready`,
/// the dispatcher's `notify_tx` is wired to its
/// `GrokClientHandler`, and the liveness watcher is armed —
/// `KigiClientHandler`, and the liveness watcher is armed —
/// matching the post-handshake state produced by
/// [`Self::ensure_mcp_tools_initialized`] for a fresh server.
///
@@ -603,7 +603,7 @@ impl SessionActor {
/// `Reason::Initialized` from the dispatcher's mapping, one
/// `Reason::RestartSucceeded` from the restart task).
///
/// The `GrokClientHandler` constructed inside `try_handshake`
/// The `KigiClientHandler` constructed inside `try_handshake`
/// holds the SHARED `Arc<Mutex<Option<Sender>>>` slot
/// (`SharedEventTx`), so wiring the sender AFTER the handshake
/// still routes subsequent `tools/list_changed` /
@@ -814,7 +814,7 @@ impl SessionActor {
self.notifications
.gateway
.forward_fire_and_forget(acp::ExtNotification::new(
"x.ai/mcp_initialized",
"kigi/mcp_initialized",
params.into(),
));
}
@@ -884,7 +884,7 @@ impl SessionActor {
self.notifications
.gateway
.forward_fire_and_forget(acp::ExtNotification::new(
"x.ai/mcp_initialized",
"kigi/mcp_initialized",
params.into(),
));
}
@@ -1432,7 +1432,7 @@ impl SessionActor {
"elapsedMs" : elapsed.as_millis() as u64, }
)) {
gateway.forward_fire_and_forget(acp::ExtNotification::new(
"x.ai/mcp_initialized",
"kigi/mcp_initialized",
params.into(),
));
}
@@ -314,10 +314,10 @@ impl SessionActor {
ConversationItem::user(user_message),
],
model: Some(model),
x_grok_conv_id: Some(session_id.clone()),
x_grok_req_id: Some(format!("xai-dream-{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(session_id),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(session_id.clone()),
x_kigi_req_id: Some(format!("xai-dream-{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(session_id),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..Default::default()
};
let response = sampling_client
@@ -413,10 +413,10 @@ impl SessionActor {
let request = ConversationRequest {
items,
model: Some(model),
x_grok_conv_id: Some(session_id.clone()),
x_grok_req_id: Some(format!("xai-flush-{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(session_id.clone()),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(session_id.clone()),
x_kigi_req_id: Some(format!("xai-flush-{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(session_id.clone()),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..Default::default()
};
@@ -608,7 +608,7 @@ impl SessionActor {
}
/// Rewrite a raw memory note into well-structured markdown via a one-shot
/// LLM call using the `grok-build` model.
/// LLM call using the `kigi` model.
///
/// Follows the same streaming pattern as [`handle_ai_suggest`]: prepares
/// a sampling client, builds a system+user prompt, streams the response,
@@ -207,7 +207,7 @@ impl SessionActor {
}
bridge
.update_resource(
kigi_tools::implementations::grok_build::update_goal::GoalUpdateHandle(
kigi_tools::implementations::kigi::update_goal::GoalUpdateHandle(
self.goal_update_tx.clone(),
),
)
@@ -94,7 +94,7 @@ impl SessionActor {
.borrow()
.tool_bridge()
.update_resource(
kigi_tools::implementations::grok_build::task::types::CurrentPromptIdResource(
kigi_tools::implementations::kigi::task::types::CurrentPromptIdResource(
prompt_id.clone(),
),
)
@@ -249,7 +249,7 @@ impl SessionActor {
let Some(buffer) = &self.tool_context.monitor_event_buffer else {
return;
};
for event in kigi_tools::implementations::grok_build::task::types::drain_owned(
for event in kigi_tools::implementations::kigi::task::types::drain_owned(
buffer,
Some(self.session_info.id.0.as_ref()),
) {
@@ -308,7 +308,7 @@ impl SessionActor {
notifications: Vec<PendingNotification>,
task_output_tool_name: &str,
) -> bool {
use kigi_tools::implementations::grok_build::task::types::MonitorEventNotification;
use kigi_tools::implementations::kigi::task::types::MonitorEventNotification;
// Collapse monitor entries: collect their text into events, remember
// where the first one sat so the batch lands in arrival position.
@@ -277,7 +277,7 @@ pub(super) fn build_truncated_prompt_message(
}
/// Replace the file-referencing offload `notice` embedded in `message` with the
/// no-file [`OFFLOAD_FAILED_NOTICE`]. Position-independent (the notice sits at the
/// end for grok ordering), so a failed offload never
/// end for kigi ordering), so a failed offload never
/// leaves the model chasing a "read this file" pointer to a file that does not
/// exist. Returns `message` unchanged if the notice is absent (defensive).
pub(super) fn strip_offload_notice(message: &str, notice: &str) -> String {
@@ -319,7 +319,7 @@ impl SessionActor {
entry_count = payload.entries.len(),
entries = ?payload.entries.iter().map(|e| e.id.as_str()).collect::<Vec<_>>(),
session = self.session_info.id.0.as_ref(),
"broadcasting x.ai/queue/changed to subscribers",
"broadcasting kigi/queue/changed to subscribers",
);
if let Ok(params) = serde_json::value::to_raw_value(&payload) {
self.notifications
@@ -426,7 +426,7 @@ impl SessionActor {
/// stale `expected_version`, or is owned by another client, or
/// - the row is not a plain prompt (it would reach the model as prompt text).
///
/// Always re-broadcasts `x.ai/queue/changed` so every client reconciles
/// Always re-broadcasts `kigi/queue/changed` so every client reconciles
/// (the row vanishes on success, is unchanged on a no-op).
/// `new_text` (when `Some`) replaces the stored queue text in the
/// interjection — the client edited the row before interjecting. It rides
@@ -609,7 +609,7 @@ impl SessionActor {
/// user has explicitly typed replacement text).
/// 2. Update `queue_meta.text`, bump `queue_meta.version`, and record
/// `last_editor` (the original `owner` attribution is preserved).
/// 3. Re-broadcast `x.ai/queue/changed` so every subscriber renders the
/// 3. Re-broadcast `kigi/queue/changed` so every subscriber renders the
/// new text and version.
///
/// **No-op cases** (each is a benign discard with no rebroadcast — nothing
@@ -110,10 +110,10 @@ impl SessionActor {
tools: tool_specs,
model: Some(model.clone()),
temperature: None,
x_grok_conv_id: Some(btw_session_id.clone()),
x_grok_req_id: Some(format!("xai-btw-{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(parent_session_id.clone()),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(btw_session_id.clone()),
x_kigi_req_id: Some(format!("xai-btw-{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(parent_session_id.clone()),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..Default::default()
};
@@ -238,8 +238,8 @@ impl SessionActor {
// ~25–40 words, and `clean_recap_text` caps it at a generous
// RECAP_MAX_CHARS safety net, so an explicit token cap isn't needed.
let started_at = chrono::Utc::now().to_rfc3339();
let x_grok_conv_id = format!("recap-{}", uuid::Uuid::new_v4());
let x_grok_req_id = format!("xai-recap-{}", uuid::Uuid::new_v4());
let x_kigi_conv_id = format!("recap-{}", uuid::Uuid::new_v4());
let x_kigi_req_id = format!("xai-recap-{}", uuid::Uuid::new_v4());
// Clone the exact request items for the on-disk artifact (recap never
// mutates conversation state, so this file is the only durable record).
let chat_history_for_artifact = items.clone();
@@ -248,10 +248,10 @@ impl SessionActor {
tools: vec![],
model: Some(model.clone()),
temperature: None,
x_grok_conv_id: Some(x_grok_conv_id.clone()),
x_grok_req_id: Some(x_grok_req_id.clone()),
x_grok_session_id: Some(self.session_info.id.to_string()),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(x_kigi_conv_id.clone()),
x_kigi_req_id: Some(x_kigi_req_id.clone()),
x_kigi_session_id: Some(self.session_info.id.to_string()),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..Default::default()
};
@@ -265,8 +265,8 @@ impl SessionActor {
auto,
strip_reasoning,
tag,
&x_grok_req_id,
&x_grok_conv_id,
&x_kigi_req_id,
&x_kigi_conv_id,
started_at,
None,
None,
@@ -291,8 +291,8 @@ impl SessionActor {
auto,
strip_reasoning,
tag,
&x_grok_req_id,
&x_grok_conv_id,
&x_kigi_req_id,
&x_kigi_conv_id,
started_at,
None,
Some(raw_response.as_str()).filter(|s| !s.is_empty()),
@@ -307,7 +307,7 @@ impl SessionActor {
}
// New prompt while generating: keep artifact, skip display, leave watermark.
// Applies to manual `/recap` too: spinner-less clients (e.g. Grok
// Applies to manual `/recap` too: spinner-less clients (e.g. Kigi
// Desktop) would otherwise append the late recap mid-turn.
if self.recap_was_cancelled(recap_epoch) {
tracing::info!(
@@ -322,8 +322,8 @@ impl SessionActor {
auto,
strip_reasoning,
tag,
&x_grok_req_id,
&x_grok_conv_id,
&x_kigi_req_id,
&x_kigi_conv_id,
started_at,
Some(summary.as_str()),
Some(raw_response.as_str()),
@@ -346,8 +346,8 @@ impl SessionActor {
auto,
strip_reasoning,
tag,
&x_grok_req_id,
&x_grok_conv_id,
&x_kigi_req_id,
&x_kigi_conv_id,
started_at,
Some(summary.as_str()),
Some(raw_response.as_str()),
@@ -365,8 +365,8 @@ impl SessionActor {
auto,
strip_reasoning,
tag,
&x_grok_req_id,
&x_grok_conv_id,
&x_kigi_req_id,
&x_kigi_conv_id,
started_at,
Some(summary.as_str()),
Some(raw_response.as_str()),
@@ -433,8 +433,8 @@ impl SessionActor {
auto: bool,
strip_reasoning: bool,
reminder_tag: &str,
x_grok_req_id: &str,
x_grok_conv_id: &str,
x_kigi_req_id: &str,
x_kigi_conv_id: &str,
started_at: String,
summary: Option<&str>,
raw_response: Option<&str>,
@@ -449,8 +449,8 @@ impl SessionActor {
created_at: started_at,
trigger: if auto { "auto" } else { "manual" }.to_owned(),
model: model.to_owned(),
x_grok_req_id: x_grok_req_id.to_owned(),
x_grok_conv_id: x_grok_conv_id.to_owned(),
x_kigi_req_id: x_kigi_req_id.to_owned(),
x_kigi_conv_id: x_kigi_conv_id.to_owned(),
strip_reasoning,
reminder_tag: reminder_tag.to_owned(),
chat_history,
@@ -578,7 +578,7 @@ impl SessionActor {
/// Temperature, max_output_tokens, and
/// reasoning_effort are left unset — mirrors [`Self::handle_recap`]: the
/// proxy may inject provider defaults, a small token cap silently empties
/// a reasoning model's response, and some models (e.g. `grok-build`)
/// a reasoning model's response, and some models (e.g. `kigi`)
/// reject an explicit `reasoningEffort` with a 400. Output is filtered
/// through [`prompt_suggest::sanitize_suggestion`]; any failure returns
/// through [`prompt_suggest::sanitize_suggestion`]; any failure returns
@@ -643,10 +643,10 @@ impl SessionActor {
tools: vec![],
model: Some(model),
temperature: None,
x_grok_conv_id: Some(format!("promptsuggest-{}", uuid::Uuid::new_v4())),
x_grok_req_id: Some(format!("xai-promptsuggest-{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(self.session_info.id.to_string()),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(format!("promptsuggest-{}", uuid::Uuid::new_v4())),
x_kigi_req_id: Some(format!("xai-promptsuggest-{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(self.session_info.id.to_string()),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..Default::default()
};
@@ -175,7 +175,7 @@ pub(crate) fn date_rollover_reminder(
}
/// Body of the one-shot interrupt `<system-reminder>` injected on the next real
/// user turn after a mid-stream abort that left the model with no other signal.
/// Wrapped in grok's `<system-reminder>` shape by [`SessionActor::push_system_reminder`].
/// Wrapped in kigi's `<system-reminder>` shape by [`SessionActor::push_system_reminder`].
/// See [`SessionActor::maybe_inject_interrupt_reminder`].
pub(crate) const INTERRUPT_REMINDER: &str = "[Request interrupted by user]";
/// TodoGate when enabled and the prompt carries `<task_completion_discipline>`
@@ -317,7 +317,7 @@ impl SessionActor {
let Some(tx) = &self.tool_context.subagent_event_tx else {
return;
};
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentCompletionsRequest, SubagentEvent,
};
let suppress_ids = self
@@ -525,7 +525,7 @@ impl SessionActor {
.send(PersistenceMsg::MergeRewindPointsFrom { target_index });
}
/// Out-of-band history repair (`x.ai/session/repair`) for a resident
/// Out-of-band history repair (`kigi/session/repair`) for a resident
/// session: run `kigi_chat_state::compaction_utils::repair_history` inside
/// the chat-state actor, then flush persistence so `chat_history.jsonl`
/// is rewritten on disk before the caller sees success.
@@ -386,7 +386,7 @@ pub(super) async fn run_session(
acp::ContentBlock::Text(t) = b { Some(t.text.clone()) } else { None } })
.collect::< Vec < _ >> ().join("\n"); let task_id = source.task_id()
.to_owned(); const MAX_BUFFER_EVENTS : usize = 50; buffer
.push_capped(kigi_tools::implementations::grok_build::task::types::MonitorEventNotification
.push_capped(kigi_tools::implementations::kigi::task::types::MonitorEventNotification
{ task_id : task_id.clone(), event_text, owner_session_id : Some(session
.session_info.id.0.to_string(),), }, MAX_BUFFER_EVENTS,);
tracing::debug!(task_id = % task_id,
@@ -33,7 +33,7 @@ struct SessionTokenAuthGate {
is_session_based: bool,
model_byok: crate::agent::auth_method::ModelByok,
/// Whether the request targets a first-party host. Lets an `Unknown`
/// BYOK status still refresh against cli-chat-proxy / `*.x.ai` without
/// BYOK status still refresh against the first-party cli-chat-proxy hosts without
/// risking a session-token leak to a third-party BYOK endpoint.
endpoint_is_first_party: bool,
}
@@ -419,10 +419,10 @@ impl SessionActor {
kigi_workspace::permission::classifier_output_json_schema(),
),
reasoning_effort: classifier_reasoning_effort,
x_grok_conv_id: Some(session_id.clone()),
x_grok_req_id: Some(format!("xai-perm-auto-{}", uuid::Uuid::new_v4())),
x_grok_session_id: Some(session_id),
x_grok_agent_id: Some(crate::util::agent_id::agent_id()),
x_kigi_conv_id: Some(session_id.clone()),
x_kigi_req_id: Some(format!("xai-perm-auto-{}", uuid::Uuid::new_v4())),
x_kigi_session_id: Some(session_id),
x_kigi_agent_id: Some(crate::util::agent_id::agent_id()),
..ConversationRequest::default()
};
let fut = sampling_client.conversation_collect(request);
@@ -289,7 +289,7 @@ impl SessionActor {
);
}
/// The activation reminder template for the active template (no
/// first-entry/reentry distinction), or grok's reentry/full variant.
/// first-entry/reentry distinction), or kigi's reentry/full variant.
/// Shared by turn-start injection (`inject_plan_mode_reminders` case 1)
/// and the mid-turn toggle (`activate_plan_mode_mid_turn`).
fn plan_activation_template(&self, is_reentry: bool) -> &'static str {
@@ -146,8 +146,8 @@ pub(crate) async fn spawn_session_actor(
inference_idle_timeout_secs: u64,
max_retries: Option<u32>,
web_search_config: kigi_tools::implementations::WebSearchConfig,
web_fetch_config: kigi_tools::implementations::grok_build::web_fetch::WebFetchConfig,
app_builder_deployer_config: kigi_tools::implementations::grok_build::deploy_app::AppBuilderDeployerConfig,
web_fetch_config: kigi_tools::implementations::kigi::web_fetch::WebFetchConfig,
app_builder_deployer_config: kigi_tools::implementations::kigi::deploy_app::AppBuilderDeployerConfig,
write_file_enabled: bool,
goal_enabled: bool,
subagents_enabled: bool,
@@ -180,7 +180,7 @@ pub(crate) async fn spawn_session_actor(
std::sync::Arc<dyn kigi_tools::computer::types::TerminalBackend>,
>,
parent_scheduler_handle: Option<
kigi_tools::implementations::grok_build::scheduler::types::SchedulerHandle,
kigi_tools::implementations::kigi::scheduler::types::SchedulerHandle,
>,
max_turns: Option<usize>,
forked_tool_override: Option<Vec<ToolSpec>>,
@@ -224,7 +224,7 @@ pub(crate) async fn spawn_session_actor(
"CLI --allow catch-all ignored: always-approve disabled by managed policy"
);
if startup_hints.non_interactive {
eprintln!("grok: --allow catch-all ignored: {reason}");
eprintln!("kigi: --allow catch-all ignored: {reason}");
}
}
if !cli_permission_rules.is_empty() {
@@ -531,7 +531,7 @@ pub(crate) async fn spawn_session_actor(
};
let reminder_policy = resolve_reminder_policy(remote_settings.as_ref(), todo_gate);
let (user_question_tx, user_question_rx) = tokio::sync::mpsc::unbounded_channel::<
kigi_tools::implementations::grok_build::ask_user_question::types::UserQuestionRequest,
kigi_tools::implementations::kigi::ask_user_question::types::UserQuestionRequest,
>();
let attribution_callback_for_spec = auth_manager.as_ref().map(|am| {
crate::auth::attribution::ShellAttribution::new_tool_callback(
@@ -672,7 +672,7 @@ pub(crate) async fn spawn_session_actor(
state.set_acp_servers(acp_mcp_servers, invoker);
tracing::info!(
session_id = % session_info.id.0, acp_mcp_servers = acp_server_count,
"Registered in-process SDK MCP servers (x.ai/mcp/sdk_call)"
"Registered in-process SDK MCP servers (kigi/mcp/sdk_call)"
);
}
Arc::new(TokioMutex::new(state))
@@ -763,7 +763,7 @@ pub(crate) async fn spawn_session_actor(
let scheduler_handle_for_handle = {
let toolset = agent.tool_bridge().toolset();
let res = toolset.resources.lock().await;
res.get::<kigi_tools::implementations::grok_build::scheduler::types::SchedulerHandle>()
res.get::<kigi_tools::implementations::kigi::scheduler::types::SchedulerHandle>()
.cloned()
};
if let Err(e) = workspace_ops.bind_local_session(
@@ -831,13 +831,13 @@ pub(crate) async fn spawn_session_actor(
"Creating feedback manager"
);
let feedback_client_type = match client_type {
ClientType::GrokTUI => crate::session::feedback_types::ClientType::Tui,
ClientType::GrokWeb => crate::session::feedback_types::ClientType::Web,
ClientType::KigiTUI => crate::session::feedback_types::ClientType::Tui,
ClientType::KigiWeb => 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,
ClientType::KigiPager => crate::session::feedback_types::ClientType::Tui,
};
let feedback_config = FeedbackManagerConfig {
feedback_enabled: feedback_flags.enabled,
@@ -930,7 +930,7 @@ pub(crate) async fn spawn_session_actor(
.map(|e| e.to_string())
.collect();
let (goal_update_tx, goal_update_rx) = tokio::sync::mpsc::unbounded_channel::<
kigi_tools::implementations::grok_build::update_goal::UpdateGoalEnvelope,
kigi_tools::implementations::kigi::update_goal::UpdateGoalEnvelope,
>();
let mut effective_config = crate::config::load_effective_config()
.ok()
@@ -1224,7 +1224,7 @@ pub(crate) async fn spawn_session_actor(
.borrow()
.tool_bridge()
.update_resource(
kigi_tools::implementations::grok_build::update_goal::GoalUpdateHandle(
kigi_tools::implementations::kigi::update_goal::GoalUpdateHandle(
session.goal_update_tx.clone(),
),
)
@@ -1288,7 +1288,7 @@ pub(crate) async fn spawn_session_actor(
}
{
use agent_client_protocol::Client as _;
use kigi_tools::implementations::grok_build::ask_user_question::{
use kigi_tools::implementations::kigi::ask_user_question::{
AskUserQuestionExtRequest, AskUserQuestionExtResponse, UserQuestionError,
UserQuestionResponse,
};
@@ -1300,7 +1300,7 @@ pub(crate) async fn spawn_session_actor(
let mut user_question_rx = user_question_rx;
tokio::task::spawn_local(async move {
while let Some(mut request) = user_question_rx.recv().await {
use kigi_tools::implementations::grok_build::ask_user_question::AskUserQuestionMode;
use kigi_tools::implementations::kigi::ask_user_question::AskUserQuestionMode;
let mode = match *current_prompt_mode.lock() {
PromptMode::Plan => AskUserQuestionMode::Plan,
_ => AskUserQuestionMode::Default,
@@ -1316,7 +1316,7 @@ pub(crate) async fn spawn_session_actor(
"ask_user_question reverse-request must carry a non-empty sessionId (design §5.4)"
);
let ext_request = agent_client_protocol::ExtRequest::new(
"x.ai/ask_user_question",
"kigi/ask_user_question",
serde_json::value::to_raw_value(&ext_req)
.expect("AskUserQuestionExtRequest serialization should not fail")
.into(),
@@ -1521,8 +1521,8 @@ pub(crate) async fn spawn_session_on_thread(
inference_idle_timeout_secs: u64,
max_retries: Option<u32>,
web_search_config: kigi_tools::implementations::WebSearchConfig,
web_fetch_config: kigi_tools::implementations::grok_build::web_fetch::WebFetchConfig,
app_builder_deployer_config: kigi_tools::implementations::grok_build::deploy_app::AppBuilderDeployerConfig,
web_fetch_config: kigi_tools::implementations::kigi::web_fetch::WebFetchConfig,
app_builder_deployer_config: kigi_tools::implementations::kigi::deploy_app::AppBuilderDeployerConfig,
write_file_enabled: bool,
goal_enabled: bool,
subagents_enabled: bool,
@@ -1556,7 +1556,7 @@ pub(crate) async fn spawn_session_on_thread(
std::sync::Arc<dyn kigi_tools::computer::types::TerminalBackend>,
>,
parent_scheduler_handle: Option<
kigi_tools::implementations::grok_build::scheduler::types::SchedulerHandle,
kigi_tools::implementations::kigi::scheduler::types::SchedulerHandle,
>,
max_turns: Option<usize>,
forked_tool_override: Option<Vec<ToolSpec>>,
@@ -179,7 +179,7 @@ impl SessionActor {
fn cancel_subagents_for_prompt_id(&self, parent_prompt_id: &str) {
if let Some(event_tx) = self.tool_context.subagent_event_tx.clone() {
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentCancelRequest, SubagentCancelTarget, SubagentEvent,
};
let _ = event_tx.send(SubagentEvent::Cancel(SubagentCancelRequest {
@@ -346,7 +346,7 @@ impl SessionActor {
// * normal interactive cancel: remove ONLY the running turn,
// PRESERVING every queued prompt so the `Cancel` handler's
// follow-up `maybe_start_running_task` promotes the new front (the
// user's next queued prompt) and rebroadcasts `x.ai/queue/changed`.
// user's next queued prompt) and rebroadcasts `kigi/queue/changed`.
// The cancelling client does not pull any prompt back into its
// input — the server queue is the single source of truth for what
// runs next. Previously every cancel did `std::mem::take`,
@@ -418,7 +418,7 @@ impl SessionActor {
.borrow()
.tool_bridge()
.update_resource(
kigi_tools::implementations::grok_build::task::types::CurrentPromptIdResource(
kigi_tools::implementations::kigi::task::types::CurrentPromptIdResource(
String::new(),
),
)
@@ -135,7 +135,7 @@ pub(super) fn should_intercept_exit_plan_approval(
pub(super) enum PlanEditGate {
/// Execute normally (plan mode inactive, not an edit, or allowed target).
Allow,
/// Grok-toolset edit outside the plan file (plan-file-only rule).
/// Kigi-toolset edit outside the plan file (plan-file-only rule).
RejectNonPlanFile,
}
/// Gate edit-class tool calls while plan mode is active.
@@ -149,7 +149,7 @@ pub(super) enum PlanEditGate {
/// file is editable in plan mode (plan docs are written with these
/// same tools); everything else is rejected. Pre-existing behavior.
/// - **Compat-toolset `Delete`** is **not** on the markdown carve-out: it maps to
/// `AccessKind::Edit` and is plan-file-only (same as grok edits). Deleting
/// `AccessKind::Edit` and is plan-file-only (same as kigi edits). Deleting
/// an arbitrary `.md` in plan mode must not pass.
/// - **Every other edit tool** (`AccessKind::Edit`) is restricted to the plan
/// file itself, via the same predicate that auto-approves plan-file edits
@@ -192,7 +192,7 @@ pub(super) enum PlanApprovalOutcome {
}
impl PlanApprovalOutcome {
fn from_response(
resp: &kigi_tools::implementations::grok_build::exit_plan_mode::ExitPlanModeExtResponse,
resp: &kigi_tools::implementations::kigi::exit_plan_mode::ExitPlanModeExtResponse,
) -> Self {
match resp.outcome.as_str() {
"approved" => Self::Approved,
@@ -255,7 +255,7 @@ fn resume_action_for(outcome: PlanApprovalOutcome, feedback: Option<String>) ->
}
}
impl SessionActor {
/// Merge the canonical `x.ai/tool` identity envelope into a tool-call
/// Merge the canonical `kigi/tool` identity envelope into a tool-call
/// event's `_meta`, resolving the tool from the live toolset by wire name.
pub(super) fn stamp_tool_meta(
&self,
@@ -1203,7 +1203,7 @@ impl SessionActor {
};
Ok(Ok(prepared))
}
/// Issue the `x.ai/exit_plan_mode` reverse-request and await the user's
/// Issue the `kigi/exit_plan_mode` reverse-request and await the user's
/// decision. Shared by the mid-turn intercept and the resume
/// re-park. Marks `awaiting_plan_approval` while the request is
/// outstanding and clears it on every exit path via [`AwaitingApprovalGuard`].
@@ -1212,11 +1212,11 @@ impl SessionActor {
tool_call_id: &acp::ToolCallId,
plan_content: Option<String>,
) -> Result<
kigi_tools::implementations::grok_build::exit_plan_mode::ExitPlanModeExtResponse,
kigi_tools::implementations::kigi::exit_plan_mode::ExitPlanModeExtResponse,
acp::Error,
> {
use agent_client_protocol::Client as _;
use kigi_tools::implementations::grok_build::exit_plan_mode::{
use kigi_tools::implementations::kigi::exit_plan_mode::{
ExitPlanModeExtRequest, ExitPlanModeExtResponse,
};
let ext_req = ExitPlanModeExtRequest {
@@ -1229,7 +1229,7 @@ impl SessionActor {
"exit_plan_mode reverse-request must carry a non-empty sessionId (design §5.4)"
);
let ext_request = acp::ExtRequest::new(
"x.ai/exit_plan_mode",
"kigi/exit_plan_mode",
serde_json::value::to_raw_value(&ext_req)
.expect("ExitPlanModeExtRequest serialization should not fail")
.into(),
@@ -2540,7 +2540,7 @@ mod plan_mode_edit_gate_tests {
plan_mode_edit_gate(tracker, input, &AccessKind::from(input))
}
fn search_replace(path: &str) -> ToolInput {
use kigi_tools::implementations::grok_build::search_replace::SearchReplaceInput;
use kigi_tools::implementations::kigi::search_replace::SearchReplaceInput;
ToolInput::SearchReplace(SearchReplaceInput {
file_path: path.into(),
old_string: "a".into(),
@@ -2555,10 +2555,10 @@ mod plan_mode_edit_gate_tests {
content: "x".into(),
})
}
/// Grok edit tools are plan-file-only while plan mode is active — the
/// Kigi edit tools are plan-file-only while plan mode is active — the
/// enforcement that makes plan mode read-only even under always-approve.
#[test]
fn grok_edits_outside_plan_file_rejected() {
fn kigi_edits_outside_plan_file_rejected() {
let t = active_tracker();
assert_eq!(
gate(&t, &search_replace("/tmp/src/main.rs")),
@@ -2567,7 +2567,7 @@ mod plan_mode_edit_gate_tests {
assert_eq!(
gate(&t, &write("/tmp/README.md")),
PlanEditGate::RejectNonPlanFile,
"grok tools get no markdown exception — plan file only"
"kigi tools get no markdown exception — plan file only"
);
}
/// The carve-out and the permission bypass share `should_auto_approve_edit`,
@@ -2644,7 +2644,7 @@ mod plan_approval_helper_tests {
PlanApprovalOutcome, ResumeAction, ext_method_no_client, resume_action_for,
revise_plan_message,
};
use kigi_tools::implementations::grok_build::exit_plan_mode::ExitPlanModeExtResponse;
use kigi_tools::implementations::kigi::exit_plan_mode::ExitPlanModeExtResponse;
fn resp(outcome: &str) -> ExitPlanModeExtResponse {
ExitPlanModeExtResponse {
outcome: outcome.into(),
@@ -41,11 +41,11 @@ fn str_arg<'a>(args: &'a serde_json::Value, keys: &[&str]) -> Option<&'a str> {
/// serializing concurrent same-file edits inside `execute_tool_calls`.
///
/// Different toolsets advertise the path under different JSON keys:
/// - `file_path` — grok_build (`search_replace`), opencode (`EditTool`,
/// `WriteTool`, `ReadTool`), codex (`read_file`), grok_build_hashline
/// - `file_path` — kigi (`search_replace`), opencode (`EditTool`,
/// `WriteTool`, `ReadTool`), codex (`read_file`), kigi_hashline
/// (`hashline_edit`)
/// - `path` — alternate edit/read tools
/// - `target_file` — grok_build (`read_file`, via `#[serde(rename)]`)
/// - `target_file` — kigi (`read_file`, via `#[serde(rename)]`)
///
/// Returning the same string for two calls in a batch causes them to share a
/// `tokio::sync::Mutex` and therefore run sequentially in model-emitted order.
@@ -202,7 +202,7 @@ impl SessionActor {
is_background: false,
});
// Bash mode has no model-issued wire name; resolve the toolset's
// execute tool by kind so the x.ai/tool identity still stamps.
// execute tool by kind so the kigi/tool identity still stamps.
let bash_marker = serde_json::json!({"bash_mode": true}).as_object().cloned();
let exec_wire = {
let agent = self.agent.borrow();
@@ -366,7 +366,7 @@ pub(crate) const MAX_ARGS_IN_ERROR: usize = 2_000;
///
/// 1. The normal error description (so the model knows *what* failed).
/// 2. The **original arguments string** the model produced (capped at
/// [`MAX_ARGS_IN_ERROR`] bytes). Without this, grok-shell would sanitize
/// [`MAX_ARGS_IN_ERROR`] bytes). Without this, kigi-shell would sanitize
/// the arguments to `"{}"` before forwarding them to the provider (to
/// avoid 400 errors), so the model would only see an empty object and have
/// to regenerate all its work from scratch.
@@ -60,9 +60,7 @@ impl UsageDrainOutcome {
/// Same policy as freeze's terminal outcome: FG live → fail-closed;
/// sticky and background → report only.
pub(super) fn from_outstanding_reply(
reply: Option<
&kigi_tools::implementations::grok_build::task::types::SubagentOutstandingReply,
>,
reply: Option<&kigi_tools::implementations::kigi::task::types::SubagentOutstandingReply>,
) -> Self {
match reply {
None => Self {
@@ -1050,7 +1048,7 @@ impl SessionActor {
let Some(tx) = &self.tool_context.subagent_event_tx else {
return false;
};
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentEvent, SubagentMarkUsageNotAppliedRequest,
};
let (respond_to, ack) = tokio::sync::oneshot::channel();
@@ -1074,12 +1072,12 @@ impl SessionActor {
/// `push_user_message`, NOT `inject_synthetic_user_message`: the latter
/// persists a `UserMessageChunk` to `updates.jsonl`, which resume
/// replays — the raw XML would render as a user prompt. Clients see
/// monitor events only via the structured `x.ai/monitor_event` channel.
/// monitor events only via the structured `kigi/monitor_event` channel.
pub(crate) async fn inject_pending_monitor_events(&self) {
let Some(buffer) = &self.tool_context.monitor_event_buffer else {
return;
};
let mine = kigi_tools::implementations::grok_build::task::types::drain_owned(
let mine = kigi_tools::implementations::kigi::task::types::drain_owned(
buffer,
Some(self.session_info.id.0.as_ref()),
);
@@ -1632,12 +1630,12 @@ impl SessionActor {
)),
);
let mut request = request;
request.x_grok_session_id = Some(self.session_info.id.to_string());
request.x_grok_turn_idx =
request.x_kigi_session_id = Some(self.session_info.id.to_string());
request.x_kigi_turn_idx =
Some(self.chat_state_handle.get_prompt_index().await.to_string());
request.x_grok_agent_id = Some(crate::util::agent_id::agent_id());
if request.x_grok_deployment_id.is_none() {
request.x_grok_deployment_id = crate::managed_config::resolve_deployment_id(
request.x_kigi_agent_id = Some(crate::util::agent_id::agent_id());
if request.x_kigi_deployment_id.is_none() {
request.x_kigi_deployment_id = crate::managed_config::resolve_deployment_id(
crate::managed_config::resolve_deployment_key().as_deref(),
);
}
@@ -2115,7 +2113,7 @@ mod user_echo_broadcast_tests {
);
}
/// Interject-fallback turns are persist-only: every pane already rendered
/// the text from the `x.ai/session/interjection` broadcast, so a live
/// the text from the `kigi/session/interjection` broadcast, so a live
/// echo would duplicate the block.
#[test]
fn interject_fallback_turn_is_persist_only() {
@@ -78,7 +78,7 @@ impl SessionActor {
self.emit_transient_notification(notification);
}
/// Emit `x.ai/git_head_changed` after an edit/shell command that may have
/// Emit `kigi/git_head_changed` after an edit/shell command that may have
/// moved HEAD (e.g. `git checkout`), so clients update their status bar
/// immediately rather than waiting for the debounced fs-watch refresh.
pub(super) async fn maybe_notify_git_branch(&self) {
@@ -112,7 +112,7 @@ impl SessionActor {
main_repo,
};
if let Ok(raw) = serde_json::value::to_raw_value(&params) {
let notification = acp::ExtNotification::new("x.ai/git_head_changed", raw.into());
let notification = acp::ExtNotification::new("kigi/git_head_changed", raw.into());
self.notifications
.gateway
.forward_fire_and_forget(notification);
@@ -123,12 +123,11 @@ impl SessionActor {
pub(super) async fn outstanding_reply_for_prompt(
&self,
prompt_id: &str,
) -> Option<kigi_tools::implementations::grok_build::task::types::SubagentOutstandingReply>
{
) -> Option<kigi_tools::implementations::kigi::task::types::SubagentOutstandingReply> {
let Some(tx) = &self.tool_context.subagent_event_tx else {
return Some(Default::default());
};
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentEvent, SubagentOutstandingRequest,
};
let (respond_to, rx) = tokio::sync::oneshot::channel();
@@ -147,9 +146,7 @@ impl SessionActor {
/// Report-level incomplete (error-path attach, tests). Same OR as
/// [`super::turn::UsageDrainOutcome::report_incomplete`].
pub(super) fn usage_incomplete_from_reply(
reply: Option<
&kigi_tools::implementations::grok_build::task::types::SubagentOutstandingReply,
>,
reply: Option<&kigi_tools::implementations::kigi::task::types::SubagentOutstandingReply>,
) -> bool {
super::turn::UsageDrainOutcome::from_outstanding_reply(reply).report_incomplete()
}
@@ -158,7 +155,7 @@ impl SessionActor {
let Some(tx) = &self.tool_context.subagent_event_tx else {
return;
};
use kigi_tools::implementations::grok_build::task::types::{
use kigi_tools::implementations::kigi::task::types::{
SubagentClearUsageNotAppliedRequest, SubagentEvent,
};
let _ = tx.send(SubagentEvent::ClearUsageNotApplied(
@@ -186,7 +183,7 @@ impl SessionActor {
.borrow()
.tool_bridge()
.update_resource(
kigi_tools::implementations::grok_build::task::types::CurrentPromptIdResource(
kigi_tools::implementations::kigi::task::types::CurrentPromptIdResource(
String::new(),
),
)
@@ -257,7 +254,7 @@ impl SessionActor {
// Durable twin of the fire-and-forget `prompt_complete` (emitted from
// `MvpAgent::prompt`): publish the turn's terminal on the persisted +
// replayed `_x.ai/session/update` rail so a viewer that re-attaches
// replayed `_kigi/session/update` rail so a viewer that re-attaches
// mid-turn finalizes from replay instead of stranding on "Waiting…".
// The caller flushed the replay buffer first, so this lands strictly
// after the turn's last `session/update` delta. Emit ONLY for a
@@ -199,8 +199,8 @@ pub(crate) enum DrainPurpose {
/// Origin of a drain entry. `Pending` entries had their acks resolved
/// at defer time; `Channel` entries still carry a live oneshot.
pub(crate) enum DrainSource {
Pending(kigi_tools::implementations::grok_build::update_goal::UpdateGoalInput),
Channel(kigi_tools::implementations::grok_build::update_goal::UpdateGoalEnvelope),
Pending(kigi_tools::implementations::kigi::update_goal::UpdateGoalInput),
Channel(kigi_tools::implementations::kigi::update_goal::UpdateGoalEnvelope),
}
/// Reason a NotAchieved verdict was synthesized without invoking the
@@ -230,7 +230,7 @@ impl SessionActor {
self.notifications
.gateway
.forward_fire_and_forget(acp::ExtNotification::new(
"x.ai/session_notification",
"kigi/session_notification",
params.into(),
));
}
@@ -734,7 +734,7 @@ impl SessionActor {
.ok();
if let Some(params) = params {
let ext_notification =
acp::ExtNotification::new("x.ai/session_notification", params.into());
acp::ExtNotification::new("kigi/session_notification", params.into());
self.notifications
.gateway
.forward_fire_and_forget(ext_notification);