Synced from monorepo

Synced from monorepo

Changes:
- Workspace server: surface preview-proxy metrics through the hub metric pump
- Shell: reclaim a session’s retained state in one entry
- Shell: reclaim a session’s resident state in one entry
- Pager: withhold key event types from Alacritty builds that double keys
- Tools: cancel a session’s subagents when it closes
- Pager: keep the whole plan in scrollback and separate reasoning from output in minimal mode
- Pager: probe terminal version over DA2 and include it with feedback
- SuperGrok Plus: identity, CLI, and analytics tier surfaces
- Shell: inherit the session process scope into subagents
- Pager: build @-file-search matcher lazily on first use
- Tools: fix description and output contradictions in tool definitions
- Workspace: degrade @-file-search instead of aborting on thread exhaustion
- Tools: reap a session’s LSP servers when it closes
- Tools: fix contradictions and defects in tool descriptions, schemas, and harness pools
- MCP: reap stdio MCP children on session close
- Shell: reuse spawn-time skill discovery for session telemetry
- Tools: stop leaking shell-wrapper positional params into sourced scripts (fixes activate_conda under persistent/static shell)
- Shell: self-heal corrupt session-search SQLite cache
- Workspace: cap workspace-server tokio workers on many-core hosts
- Shell: reap a session’s child processes when it closes
- Crash handler: capture SIGABRT so panic-aborts leave crash reports
- CLI chat proxy: team-scoped Grok Code managed-config admin routes
- MCP: add CLI enable/disable for MCP servers
- Shell: cap tokio worker threads for startup thread demand
- Workspace: harden git_commit and add git_sync_base operation
- Circuit breaker: add feature-gated gRPC retry policy

Source-Revision: 2a818575225183d8ca915f5632a09b8067b5156a
This commit is contained in:
grokkybara[bot] 2026-07-28 22:50:19 +00:00
commit 5da6962e4a
192 changed files with 10337 additions and 3421 deletions

View file

@ -6,7 +6,7 @@ edition.workspace = true
description = "SDK for the xAI Computer Hub: connection pool, transparent reconnect, tool harness, and tool-server runtime."
[features]
metrics = ["dep:prometheus"]
metrics = ["dep:prometheus", "dep:prometheus-parse"]
[dependencies]
tokio = { workspace = true, features = ["rt", "sync", "time", "macros"] }
@ -25,6 +25,7 @@ tracing-subscriber = { workspace = true }
url = { workspace = true }
http = { workspace = true }
prometheus = { workspace = true, optional = true }
prometheus-parse = { version = "0.2.5", optional = true }
reqwest = { workspace = true }
chrono = { workspace = true }
parking_lot = { workspace = true }

View file

@ -125,6 +125,138 @@ fn convert_families(families: &[MetricFamily]) -> Vec<Metric> {
out
}
/// Text-format exposition → OTLP, same shapes as [`convert_families`].
fn convert_text_exposition(text: &str, prefix: &str) -> Vec<Metric> {
let Ok(scrape) =
prometheus_parse::Scrape::parse(text.lines().map(|l| std::io::Result::Ok(l.to_owned())))
else {
return Vec::new();
};
let now = now_unix_nanos();
let cumulative = AggregationTemporality::Cumulative as i32;
let histogram_names: std::collections::HashSet<&str> = scrape
.samples
.iter()
.filter(|s| matches!(s.value, prometheus_parse::Value::Histogram(_)))
.map(|s| s.metric.as_str())
.collect();
let histogram_sums: std::collections::HashMap<(String, String), f64> = scrape
.samples
.iter()
.filter_map(|s| {
let base = s.metric.strip_suffix("_sum")?;
if !histogram_names.contains(base) {
return None;
}
let prometheus_parse::Value::Untyped(v) = s.value else {
return None;
};
Some(((base.to_owned(), s.labels.to_string()), v))
})
.collect();
let parsed_labels_to_kv = |labels: &prometheus_parse::Labels| -> Vec<KeyValue> {
let mut kv: Vec<KeyValue> = labels
.iter()
.map(|(k, v)| string_kv(k, v.clone()))
.collect();
kv.sort_by(|a, b| a.key.cmp(&b.key));
kv
};
let mut out = Vec::new();
for sample in &scrape.samples {
if !sample.metric.starts_with(prefix) {
continue;
}
let data = match &sample.value {
prometheus_parse::Value::Counter(v) => metric::Data::Sum(Sum {
data_points: vec![NumberDataPoint {
attributes: parsed_labels_to_kv(&sample.labels),
time_unix_nano: now,
value: Some(number_data_point::Value::AsDouble(*v)),
..Default::default()
}],
aggregation_temporality: cumulative,
is_monotonic: true,
}),
prometheus_parse::Value::Gauge(v) => metric::Data::Gauge(Gauge {
data_points: vec![NumberDataPoint {
attributes: parsed_labels_to_kv(&sample.labels),
time_unix_nano: now,
value: Some(number_data_point::Value::AsDouble(*v)),
..Default::default()
}],
}),
prometheus_parse::Value::Histogram(counts) => {
let mut counts = counts.clone();
counts.sort_by(|a, b| a.less_than.total_cmp(&b.less_than));
let mut bucket_counts = Vec::with_capacity(counts.len());
let mut explicit_bounds = Vec::with_capacity(counts.len().saturating_sub(1));
let mut prev = 0f64;
let mut total = 0u64;
for bucket in &counts {
bucket_counts.push((bucket.count - prev).max(0.0) as u64);
if bucket.less_than.is_finite() {
explicit_bounds.push(bucket.less_than);
} else {
total = bucket.count.max(0.0) as u64;
}
prev = bucket.count;
}
let sum = histogram_sums
.get(&(sample.metric.clone(), sample.labels.to_string()))
.copied();
metric::Data::Histogram(Histogram {
data_points: vec![HistogramDataPoint {
attributes: parsed_labels_to_kv(&sample.labels),
time_unix_nano: now,
count: total,
sum,
bucket_counts,
explicit_bounds,
..Default::default()
}],
aggregation_temporality: cumulative,
})
}
// Untyped = histogram `_sum`/`_count` twins, joined above.
prometheus_parse::Value::Summary(_) | prometheus_parse::Value::Untyped(_) => continue,
};
out.push(Metric {
name: sample.metric.clone(),
data: Some(data),
..Default::default()
});
}
out
}
/// Donates metrics from outside the default Prometheus registry.
pub struct DonatedMetricsSink {
exporter: Arc<MetricExporter>,
}
impl DonatedMetricsSink {
/// Returns the number of OTLP metrics queued (malformed input → 0).
pub fn export_text_exposition(&self, text: &str, prefix: &str) -> usize {
let metrics = convert_text_exposition(text, prefix);
let exported = metrics.len();
if exported > 0 {
self.exporter.export(metrics);
}
exported
}
}
/// `Some` while the donation pump is active; re-fetch per use (cheap).
pub fn active_metrics_sink() -> Option<DonatedMetricsSink> {
ACTIVE_METRIC_EXPORTER
.load_full()
.map(|exporter| DonatedMetricsSink { exporter })
}
/// Encodes batches of OTLP metrics onto the pump channel. Chunks at
/// [`MAX_METRICS_PER_DONATION`], drops payloads over
/// [`MAX_DONATION_BYTES`], and never blocks.
@ -299,6 +431,92 @@ mod tests {
.collect()
}
const PROXY_TEXT: &str = "\
# HELP preview_proxy_requests_total Proxied preview requests.\n\
# TYPE preview_proxy_requests_total counter\n\
preview_proxy_requests_total{visibility=\"public\",outcome=\"ok\"} 41\n\
preview_proxy_requests_total{visibility=\"private\",outcome=\"upstream_error\"} 2\n\
# HELP preview_proxy_active_ws_connections Live proxied WebSocket connections.\n\
# TYPE preview_proxy_active_ws_connections gauge\n\
preview_proxy_active_ws_connections 3\n\
# HELP preview_proxy_request_duration_seconds Preview request latency.\n\
# TYPE preview_proxy_request_duration_seconds histogram\n\
preview_proxy_request_duration_seconds_bucket{le=\"0.5\"} 4\n\
preview_proxy_request_duration_seconds_bucket{le=\"1\"} 6\n\
preview_proxy_request_duration_seconds_bucket{le=\"+Inf\"} 7\n\
preview_proxy_request_duration_seconds_sum 5.25\n\
preview_proxy_request_duration_seconds_count 7\n\
# TYPE other_family_total counter\n\
other_family_total 9\n";
#[test]
fn text_exposition_converts_and_filters_by_prefix() {
let metrics = convert_text_exposition(PROXY_TEXT, "preview_proxy_");
let by_name: std::collections::HashMap<&str, &Metric> =
metrics.iter().map(|m| (m.name.as_str(), m)).collect();
assert!(!by_name.contains_key("other_family_total"));
assert!(!by_name.contains_key("preview_proxy_request_duration_seconds_sum"));
assert!(!by_name.contains_key("preview_proxy_request_duration_seconds_count"));
let counters: Vec<&Metric> = metrics
.iter()
.filter(|m| m.name == "preview_proxy_requests_total")
.collect();
assert_eq!(2, counters.len());
let ok_point = counters
.iter()
.find_map(|m| match m.data.as_ref() {
Some(metric::Data::Sum(sum)) => {
assert!(sum.is_monotonic);
sum.data_points.iter().find(|p| {
label_map(&p.attributes).get("outcome").map(String::as_str) == Some("ok")
})
}
_ => None,
})
.expect("ok counter point");
assert_eq!(
Some(number_data_point::Value::AsDouble(41.0)),
ok_point.value
);
assert_eq!(
Some("public"),
label_map(&ok_point.attributes)
.get("visibility")
.map(String::as_str)
);
let Some(metric::Data::Gauge(gauge)) =
by_name["preview_proxy_active_ws_connections"].data.as_ref()
else {
panic!("gauge expected");
};
assert_eq!(
Some(number_data_point::Value::AsDouble(3.0)),
gauge.data_points[0].value
);
let Some(metric::Data::Histogram(hist)) = by_name["preview_proxy_request_duration_seconds"]
.data
.as_ref()
else {
panic!("histogram expected");
};
let point = &hist.data_points[0];
assert_eq!(vec![0.5, 1.0], point.explicit_bounds);
assert_eq!(vec![4, 2, 1], point.bucket_counts);
assert_eq!(7, point.count);
assert_eq!(Some(5.25), point.sum);
}
#[test]
fn text_exposition_tolerates_garbage_and_empty_input() {
assert!(convert_text_exposition("", "preview_proxy_").is_empty());
assert!(convert_text_exposition("not a metric line at all", "preview_proxy_").is_empty());
assert!(convert_text_exposition(PROXY_TEXT, "no_such_prefix_").is_empty());
}
#[test]
fn converts_counter_gauge_histogram_with_labels() {
let registry = Registry::new();