Add [remote_control] config section (patch 0003)
Exports the work/ commit adding the [remote_control] config section that the /rc bridge reads: url, api_key, auto_start and replay_buffer, with GROK_RC_URL / GROK_RC_API_KEY overriding the file.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: iceBear67 <icebear67@sfclub.cc>
|
||||
Date: Sat, 15 Aug 2026 06:39:14 +0000
|
||||
Subject: [PATCH] Add [remote_control] config section for the /rc glance bridge
|
||||
|
||||
|
||||
diff --git a/crates/codegen/xai-grok-shell/src/agent/config.rs b/crates/codegen/xai-grok-shell/src/agent/config.rs
|
||||
index 3dd50b3217936911d6858e4c9c169d7609e1a0fd..f39d1bd460a4635dd4767afe92622ab9b04952a1 100644
|
||||
--- a/crates/codegen/xai-grok-shell/src/agent/config.rs
|
||||
+++ b/crates/codegen/xai-grok-shell/src/agent/config.rs
|
||||
@@ -1014,6 +1014,79 @@ pub struct CliConfig {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub session_picker_grouped: Option<bool>,
|
||||
}
|
||||
+/// `[remote_control]` section: the `/rc` bridge to a grok-glance server.
|
||||
+///
|
||||
+/// `/rc` mirrors the session you are already in to glance over ACP -- it does not
|
||||
+/// restart it, switch it to headless, or hand it over. Both ends stay live and
|
||||
+/// either can drive the session.
|
||||
+///
|
||||
+/// Every field has an env override, which is how the API key is normally supplied:
|
||||
+/// a bearer token in a plaintext config file is a poor default.
|
||||
+#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
+#[serde(default)]
|
||||
+pub struct RemoteControlConfig {
|
||||
+ /// Glance WebSocket endpoint, e.g. `wss://glance.example.com/api/acp/agent`.
|
||||
+ /// Env `GROK_RC_URL`.
|
||||
+ #[serde(skip_serializing_if = "Option::is_none")]
|
||||
+ pub url: Option<String>,
|
||||
+ /// Bearer token presented on the WebSocket upgrade. Env `GROK_RC_API_KEY`.
|
||||
+ #[serde(skip_serializing_if = "Option::is_none")]
|
||||
+ pub api_key: Option<String>,
|
||||
+ /// Connect at session start instead of waiting for `/rc`. Env `GROK_RC_AUTO_START`.
|
||||
+ #[serde(skip_serializing_if = "Option::is_none")]
|
||||
+ pub auto_start: Option<bool>,
|
||||
+ /// Session updates retained for replay when glance (re)connects.
|
||||
+ /// See [`RemoteControlConfig::DEFAULT_REPLAY_BUFFER`].
|
||||
+ #[serde(skip_serializing_if = "Option::is_none")]
|
||||
+ pub replay_buffer: Option<usize>,
|
||||
+}
|
||||
+impl RemoteControlConfig {
|
||||
+ /// Bounded so a long session cannot grow the bridge without limit; large
|
||||
+ /// enough that a browser attaching mid-session still sees useful history.
|
||||
+ pub const DEFAULT_REPLAY_BUFFER: usize = 2048;
|
||||
+ /// Env wins over config, and an empty value counts as unset -- an exported
|
||||
+ /// but blank `GROK_RC_URL` should not mask a working config entry.
|
||||
+ fn env_override(key: &str) -> Option<String> {
|
||||
+ std::env::var(key)
|
||||
+ .ok()
|
||||
+ .map(|v| v.trim().to_owned())
|
||||
+ .filter(|v| !v.is_empty())
|
||||
+ }
|
||||
+ pub fn resolved_url(&self) -> Option<String> {
|
||||
+ Self::env_override("GROK_RC_URL").or_else(|| {
|
||||
+ self.url
|
||||
+ .as_deref()
|
||||
+ .map(str::trim)
|
||||
+ .filter(|v| !v.is_empty())
|
||||
+ .map(str::to_owned)
|
||||
+ })
|
||||
+ }
|
||||
+ pub fn resolved_api_key(&self) -> Option<String> {
|
||||
+ Self::env_override("GROK_RC_API_KEY").or_else(|| {
|
||||
+ self.api_key
|
||||
+ .as_deref()
|
||||
+ .map(str::trim)
|
||||
+ .filter(|v| !v.is_empty())
|
||||
+ .map(str::to_owned)
|
||||
+ })
|
||||
+ }
|
||||
+ pub fn auto_start_enabled(&self) -> bool {
|
||||
+ Self::env_override("GROK_RC_AUTO_START")
|
||||
+ .map(|v| matches!(v.to_ascii_lowercase().as_str(), "1" | "true" | "yes" | "on"))
|
||||
+ .or(self.auto_start)
|
||||
+ .unwrap_or(false)
|
||||
+ }
|
||||
+ pub fn replay_buffer_len(&self) -> usize {
|
||||
+ self.replay_buffer
|
||||
+ .filter(|n| *n > 0)
|
||||
+ .unwrap_or(Self::DEFAULT_REPLAY_BUFFER)
|
||||
+ }
|
||||
+ /// Both a URL and a key are required; `/rc` reports which one is missing
|
||||
+ /// rather than dialing an endpoint that will reject it.
|
||||
+ pub fn is_configured(&self) -> bool {
|
||||
+ self.resolved_url().is_some() && self.resolved_api_key().is_some()
|
||||
+ }
|
||||
+}
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct DiagnosticsConfig {
|
||||
@@ -1348,6 +1421,9 @@ pub struct Config {
|
||||
pub paths: PathsConfig,
|
||||
#[serde(default, skip_serializing)]
|
||||
pub cli: CliConfig,
|
||||
+ /// `[remote_control]` section: the `/rc` bridge to grok-glance.
|
||||
+ #[serde(default, skip_serializing)]
|
||||
+ pub remote_control: RemoteControlConfig,
|
||||
#[serde(default, skip_serializing)]
|
||||
pub models: ModelsConfig,
|
||||
#[serde(default, skip_serializing)]
|
||||
@@ -1759,6 +1835,7 @@ impl Default for Config {
|
||||
feedback: FeedbackConfig::default(),
|
||||
paths: PathsConfig::default(),
|
||||
cli: CliConfig::default(),
|
||||
+ remote_control: RemoteControlConfig::default(),
|
||||
models: ModelsConfig::default(),
|
||||
harness: HarnessConfig::default(),
|
||||
relay: RelayConfig::default(),
|
||||
Reference in New Issue
Block a user