Synced from monorepo
Synced from monorepo Changes: - grok-shell: send an expired external-provider credential to the sign-in flow, not a 401 loop - pager: clickable ▲ jumps to the top of the response being read - grok-shell: keep a large task log from making the completion message too long - Plan viewer scrollbar: widen grab zone to the border column; fix striped thumb in Terminal.app - pager: poll the tmux probe teardown grace instead of sleeping it - security: vendor-compat MCP kill switch is now actually enforced when reported as on - grok-shell: restore session eviction when a leader client disconnects - Bump rust-toolchain to 1.93.0 - workspace: lexical-normalize permission path patterns before glob matching - pager: reject garbage Enter in the /resume picker - pager: show Mermaid affordances in plan mode preview - pager: drop manage-account link from /session-info - workspace: auto-approve read-only git queries; defer write floor to auto classifier - Add free-form pattern editor to the "Always allow" command prompt - grok-shell: fix /btw caching - pager: Tab walks answers in the ask_user_question card - External-provider auth refresh: single 7s attempt instead of 3×5s - pager: don't resurrect finished background tasks as Running when completion arrives first - pager: report tmux truecolor clamping in Doctor - Fix plan viewer scrollbar click+drag hijacked by comment gutter - pager/shell: stop double Recap after the same last turn - sampler: preserve x-should-retry through stream collection - pager: clear plan-mode indicator immediately when the user approves a plan - pager: tmux does not re-read its config on reattach Source-Revision: 64c4de99cc822b25ce9c54ab5a4f372093d0885d
This commit is contained in:
parent
a422116582
commit
780d1388ff
323 changed files with 12258 additions and 7226 deletions
|
|
@ -1,5 +1,5 @@
|
|||
//! Subagent lifecycle soak: churn spawn/run/completion/eviction and assert
|
||||
//! threads, fds, and heap/RSS reach steady state. A stub `ChildRunner` drives
|
||||
//! threads, open files, and heap/RSS reach steady state. A stub `ChildRunner` drives
|
||||
//! the real coordinator/transport.
|
||||
//!
|
||||
//! SUBAGENT_SOAK_CYCLES=20000 cargo test -p xai-grok-tools \
|
||||
|
|
@ -45,7 +45,7 @@ impl Metric {
|
|||
match self {
|
||||
Metric::Rss => "rss",
|
||||
Metric::Threads => "threads",
|
||||
Metric::Fds => "fds",
|
||||
Metric::Fds => "open_files",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ impl Metric {
|
|||
match self {
|
||||
Metric::Rss => "rss_bytes",
|
||||
Metric::Threads => "threads",
|
||||
Metric::Fds => "fds",
|
||||
Metric::Fds => "open_files",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ impl Metric {
|
|||
match self {
|
||||
Metric::Rss => bounds.max_rss_growth_mib as f64,
|
||||
Metric::Threads => bounds.max_thread_growth as f64,
|
||||
Metric::Fds => bounds.max_fd_growth as f64,
|
||||
Metric::Fds => bounds.max_open_files_growth as f64,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ impl Metric {
|
|||
}
|
||||
}
|
||||
|
||||
/// RSS is sampled on every unix; thread and fd counts are Linux-only.
|
||||
/// RSS is sampled on every unix; thread and open-file counts are Linux-only.
|
||||
fn expected_on_this_platform(self) -> bool {
|
||||
match self {
|
||||
Metric::Rss => true,
|
||||
|
|
@ -100,22 +100,30 @@ impl MetricValue for ResourceSnapshot {
|
|||
fn value_of(&self, metric: Metric) -> Option<usize> {
|
||||
// Destructure so a new resource field is a compile error here, not a
|
||||
// silently dropped metric.
|
||||
let ResourceSnapshot { rss, threads, fds } = *self;
|
||||
let ResourceSnapshot {
|
||||
rss,
|
||||
threads,
|
||||
open_files,
|
||||
} = *self;
|
||||
match metric {
|
||||
Metric::Rss => rss,
|
||||
Metric::Threads => threads,
|
||||
Metric::Fds => fds,
|
||||
Metric::Fds => open_files,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MetricValue for ResourceGrowth {
|
||||
fn value_of(&self, metric: Metric) -> Option<usize> {
|
||||
let ResourceGrowth { rss, threads, fds } = *self;
|
||||
let ResourceGrowth {
|
||||
rss,
|
||||
threads,
|
||||
open_files,
|
||||
} = *self;
|
||||
match metric {
|
||||
Metric::Rss => rss,
|
||||
Metric::Threads => threads,
|
||||
Metric::Fds => fds,
|
||||
Metric::Fds => open_files,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,7 +180,7 @@ struct Bounds {
|
|||
measure: u64,
|
||||
concurrency: u64,
|
||||
max_thread_growth: u64,
|
||||
max_fd_growth: u64,
|
||||
max_open_files_growth: u64,
|
||||
max_rss_growth_mib: u64,
|
||||
max_blocks_per_cycle: f64,
|
||||
max_bytes_per_cycle: f64,
|
||||
|
|
@ -187,9 +195,9 @@ impl Bounds {
|
|||
warmup: env_parse("SUBAGENT_SOAK_WARMUP", MAX_COMPLETED_ENTRIES as u64),
|
||||
measure: env_parse("SUBAGENT_SOAK_CYCLES", 512u64),
|
||||
concurrency: env_parse("SUBAGENT_SOAK_CONCURRENCY", 16u64),
|
||||
// RSS is looser than threads and fds to absorb allocator noise.
|
||||
// RSS is looser than threads and open files to absorb allocator noise.
|
||||
max_thread_growth: env_parse("SUBAGENT_SOAK_MAX_THREAD_GROWTH", 8u64),
|
||||
max_fd_growth: env_parse("SUBAGENT_SOAK_MAX_FD_GROWTH", 16u64),
|
||||
max_open_files_growth: env_parse("SUBAGENT_SOAK_MAX_OPEN_FILES_GROWTH", 16u64),
|
||||
max_rss_growth_mib: env_parse("SUBAGENT_SOAK_MAX_RSS_GROWTH_MIB", 256u64),
|
||||
max_blocks_per_cycle: env_parse("SUBAGENT_SOAK_MAX_BLOCKS_PER_CYCLE", 2.0f64),
|
||||
max_bytes_per_cycle: env_parse("SUBAGENT_SOAK_MAX_BYTES_PER_CYCLE", 4096.0f64),
|
||||
|
|
@ -595,7 +603,7 @@ fn assert_bounds(bounds: &Bounds, m: &Measurement) {
|
|||
/// Keep this the only test in the binary that creates a `dhat::Profiler`.
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
#[ignore = "subagent soak; run with --ignored (SUBAGENT_SOAK_CYCLES bounds the measured window)"]
|
||||
async fn subagent_lifecycle_soak_bounds_threads_fds_and_heap() {
|
||||
async fn subagent_lifecycle_soak_bounds_threads_open_files_and_heap() {
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
let _profiler = dhat::Profiler::builder().testing().build();
|
||||
|
||||
|
|
@ -646,7 +654,7 @@ mod tests {
|
|||
let snapshot = ResourceSnapshot {
|
||||
rss: Some(11),
|
||||
threads: Some(22),
|
||||
fds: Some(33),
|
||||
open_files: Some(33),
|
||||
};
|
||||
assert_eq!(snapshot.value_of(Metric::Rss), Some(11));
|
||||
assert_eq!(snapshot.value_of(Metric::Threads), Some(22));
|
||||
|
|
@ -655,7 +663,7 @@ mod tests {
|
|||
let growth = ResourceGrowth {
|
||||
rss: Some(1),
|
||||
threads: None,
|
||||
fds: Some(3),
|
||||
open_files: Some(3),
|
||||
};
|
||||
assert_eq!(growth.value_of(Metric::Rss), Some(1));
|
||||
assert_eq!(growth.value_of(Metric::Threads), None);
|
||||
|
|
@ -669,10 +677,10 @@ mod tests {
|
|||
let snapshot = ResourceSnapshot {
|
||||
rss: Some(1),
|
||||
threads: None,
|
||||
fds: Some(3),
|
||||
open_files: Some(3),
|
||||
};
|
||||
let json = serde_json::to_string(&Wrap(snapshot)).expect("snapshot serializes");
|
||||
assert_eq!(json, r#"{"rss_bytes":1,"threads":null,"fds":3}"#);
|
||||
assert_eq!(json, r#"{"rss_bytes":1,"threads":null,"open_files":3}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -696,7 +704,7 @@ mod tests {
|
|||
measure: 0,
|
||||
concurrency: 0,
|
||||
max_thread_growth: 3,
|
||||
max_fd_growth: 5,
|
||||
max_open_files_growth: 5,
|
||||
max_rss_growth_mib: 7,
|
||||
max_blocks_per_cycle: 1.0,
|
||||
max_bytes_per_cycle: 2.0,
|
||||
|
|
@ -729,7 +737,7 @@ mod tests {
|
|||
measure: 4,
|
||||
concurrency: 4,
|
||||
max_thread_growth: 100,
|
||||
max_fd_growth: 100,
|
||||
max_open_files_growth: 100,
|
||||
max_rss_growth_mib: 100,
|
||||
max_blocks_per_cycle: 10.0,
|
||||
max_bytes_per_cycle: 10_000.0,
|
||||
|
|
@ -741,7 +749,7 @@ mod tests {
|
|||
ResourceGrowth {
|
||||
rss: Some(0),
|
||||
threads: Some(0),
|
||||
fds: Some(0),
|
||||
open_files: Some(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -771,7 +779,7 @@ mod tests {
|
|||
let growth = ResourceGrowth {
|
||||
rss: None,
|
||||
threads: Some(0),
|
||||
fds: Some(0),
|
||||
open_files: Some(0),
|
||||
};
|
||||
let failures = check_bounds(&generous_bounds(), &drained(growth, None));
|
||||
assert!(
|
||||
|
|
@ -814,7 +822,7 @@ mod tests {
|
|||
let growth = ResourceGrowth {
|
||||
rss: Some(200 * 1024 * 1024),
|
||||
threads: Some(0),
|
||||
fds: Some(0),
|
||||
open_files: Some(0),
|
||||
};
|
||||
let failures = check_bounds(&generous_bounds(), &drained(growth, None));
|
||||
assert!(
|
||||
|
|
@ -828,7 +836,7 @@ mod tests {
|
|||
let growth = ResourceGrowth {
|
||||
rss: Some(100 * 1024 * 1024),
|
||||
threads: Some(100),
|
||||
fds: Some(100),
|
||||
open_files: Some(100),
|
||||
};
|
||||
assert!(check_bounds(&generous_bounds(), &drained(growth, None)).is_empty());
|
||||
}
|
||||
|
|
@ -885,11 +893,11 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn check_bounds_flags_thread_and_fd_over_budget() {
|
||||
fn check_bounds_flags_thread_and_open_files_over_budget() {
|
||||
let growth = ResourceGrowth {
|
||||
rss: Some(0),
|
||||
threads: Some(200),
|
||||
fds: Some(200),
|
||||
open_files: Some(200),
|
||||
};
|
||||
let failures = check_bounds(&generous_bounds(), &drained(growth, None));
|
||||
assert!(
|
||||
|
|
@ -897,7 +905,7 @@ mod tests {
|
|||
"{failures:?}"
|
||||
);
|
||||
assert!(
|
||||
failures.iter().any(|f| f.starts_with("fds:")),
|
||||
failures.iter().any(|f| f.starts_with("open_files:")),
|
||||
"{failures:?}"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue