diff --git a/frontend/packages/dashboard/src/common.css b/frontend/packages/dashboard/src/common.css index ec677ed0..ea353cbe 100644 --- a/frontend/packages/dashboard/src/common.css +++ b/frontend/packages/dashboard/src/common.css @@ -85,11 +85,6 @@ code { color: var(--purple); border-color: var(--purple); text-shadow: 0 0 6px color-mix(in srgb, var(--purple) 40%, transparent); } -/* Active Claude model badge on dashboard container rows. */ -.badge-model { - color: var(--blue); border-color: var(--blue); - opacity: 0.8; -} /* Context-window usage badges on dashboard container rows. */ .badge-ctx-ok { color: var(--green); border-color: var(--green); diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 6220ac44..8b9f4c5a 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -521,7 +521,6 @@ window.marked = marked; needs_login: c.needs_login, needs_update: c.needs_update, pending_reminders: c.pending_reminders, - active_model: c.active_model, port: c.port, pending, opRunning, @@ -727,12 +726,6 @@ window.marked = marked; )); } - if (c.active_model) { - head.append(el('span', - { class: 'badge badge-model', title: `active claude model: ${c.active_model}` }, - c.active_model)); - } - if (c.pending_reminders && c.pending_reminders > 0) { head.append(el('span', { diff --git a/hive-ag3nt/src/events.rs b/hive-ag3nt/src/events.rs index b255d3f3..e4144324 100644 --- a/hive-ag3nt/src/events.rs +++ b/hive-ag3nt/src/events.rs @@ -106,7 +106,7 @@ fn harness_json_path() -> PathBuf { crate::paths::state_dir().join(HARNESS_JSON) } -fn read_harness_state() -> (bool, bool, Option) { +fn read_harness_state() -> (bool, bool) { // Try the new consolidated file first. if let Ok(raw) = std::fs::read_to_string(harness_json_path()) && let Ok(v) = serde_json::from_str::(&raw) @@ -119,34 +119,24 @@ fn read_harness_state() -> (bool, bool, Option) { .get("needs_login") .and_then(serde_json::Value::as_bool) .unwrap_or(false); - let active_model = v - .get("active_model") - .and_then(serde_json::Value::as_str) - .filter(|s| !s.is_empty()) - .map(str::to_owned); - return (rate_limited, needs_login, active_model); + return (rate_limited, needs_login); } // Fall back to legacy sentinel files written by older harness builds. let state_dir = crate::paths::state_dir(); let rate_limited = state_dir.join("hyperhive-rate-limited").exists(); let needs_login = state_dir.join("hyperhive-needs-login").exists(); - (rate_limited, needs_login, None) + (rate_limited, needs_login) } /// Write harness state atomically via a `.tmp` + `rename` pair so -/// hive-c0re never reads a partial file. Pass `active_model: Some(s)` -/// to include the resolved model (as surfaced in the dashboard badge); -/// `None` omits the field, which hive-c0re treats as "not yet known". -fn write_harness_state(rate_limited: bool, needs_login: bool, active_model: Option<&str>) { +/// hive-c0re never reads a partial file. +fn write_harness_state(rate_limited: bool, needs_login: bool) { let path = harness_json_path(); - let mut json = serde_json::json!({ + let body = serde_json::json!({ "rate_limited": rate_limited, "needs_login": needs_login, - }); - if let Some(model) = active_model { - json["active_model"] = serde_json::Value::String(model.to_string()); - } - let body = json.to_string(); + }) + .to_string(); let tmp = path.with_extension("json.tmp"); if std::fs::write(&tmp, &body).is_ok() { let _ = std::fs::rename(&tmp, &path); @@ -698,12 +688,7 @@ impl Bus { // Restore rate_limited (and needs_login) from the consolidated // harness state file so the dashboard shows the correct status // on cold load if the harness crashed while parked. - let (was_rate_limited, was_needs_login, _) = read_harness_state(); - // Write the resolved active model to hyperhive-harness.json on - // startup so hive-c0re can surface the model badge without reading - // hyperhive-model directly. Written once here; updated on every - // set_model() call (runtime override) and emit_status() call. - write_harness_state(was_rate_limited, was_needs_login, Some(&initial_model)); + let (was_rate_limited, _was_needs_login) = read_harness_state(); Self { tx: Arc::new(tx), event_seq: Arc::new(AtomicU64::new(0)), @@ -812,11 +797,6 @@ impl Bus { if let Err(e) = persist_model(&value) { tracing::warn!(error = ?e, "model: persist failed"); } - // Mirror the resolved model into hyperhive-harness.json so - // hive-c0re can surface it on the dashboard badge without reading - // the hyperhive-model override file directly. - let (rate_limited, needs_login, _) = read_harness_state(); - write_harness_state(rate_limited, needs_login, Some(&value)); self.emit(LiveEvent::ModelChanged { model: value }); } @@ -1057,7 +1037,7 @@ impl Bus { // turns, so the two callers never overlap. Documented rather than // locked because adding a Mutex here would be overkill for the // actual call pattern. - let (_, current_needs_login, _) = read_harness_state(); + let (_, current_needs_login) = read_harness_state(); let new_needs_login = if status == "needs_login_idle" { true } else if status == "online" { @@ -1065,8 +1045,7 @@ impl Bus { } else { current_needs_login }; - let current_model = self.model.lock().unwrap().clone(); - write_harness_state(new_rate_limited, new_needs_login, Some(¤t_model)); + write_harness_state(new_rate_limited, new_needs_login); self.emit(LiveEvent::StatusChanged { status }); } diff --git a/hive-c0re/src/container_view.rs b/hive-c0re/src/container_view.rs index 74c41dd1..28821cda 100644 --- a/hive-c0re/src/container_view.rs +++ b/hive-c0re/src/container_view.rs @@ -44,13 +44,6 @@ pub struct ContainerView { /// in the tree. See `docs/agent-hierarchy.md::Current state`. #[serde(default, skip_serializing_if = "Option::is_none")] pub parent: Option, - /// The Claude model the agent's harness is currently using, read from - /// `state/hyperhive-harness.json["active_model"]`. `None` when the - /// agent has never started a turn or the field is absent. Only - /// meaningful when `running` is true; the dashboard skips the badge - /// for stopped containers. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub active_model: Option, } /// Build the full container list. Wraps `lifecycle::list()` and @@ -85,14 +78,6 @@ pub async fn build_all(coord: &Coordinator) -> Vec { let needs_login = running && (!claude_has_session(&Coordinator::agent_claude_dir(&logical)) || auth_failed_sentinel(&logical)); - // Read the active model from the harness state file. Only surfaced - // when the container is running — stale model info from a stopped - // agent is misleading (the model may change on next boot). - let active_model = if running { - read_active_model(&logical) - } else { - None - }; out.push(ContainerView { port: lifecycle::agent_web_port(&logical), running, @@ -103,7 +88,6 @@ pub async fn build_all(coord: &Coordinator) -> Vec { deployed_sha, pending_reminders, parent, - active_model, }); } out @@ -206,22 +190,6 @@ pub async fn read_agent_status_live(name: &str) -> (Option, Option, (text, set_at, true) } -/// Read the active Claude model from `hyperhive-harness.json` (the -/// consolidated harness state file in the agent's state dir). Written by -/// the harness on startup and on every `set_model` / `emit_status` call, -/// so it always reflects the resolved priority (nix config > runtime -/// override > default). Returns `None` when the field is absent or the -/// harness has not yet started a turn. -fn read_active_model(name: &str) -> Option { - let path = Coordinator::agent_notes_dir(name).join("hyperhive-harness.json"); - let raw = std::fs::read_to_string(path).ok()?; - let v: serde_json::Value = serde_json::from_str(&raw).ok()?; - v.get("active_model") - .and_then(serde_json::Value::as_str) - .filter(|s| !s.is_empty()) - .map(str::to_owned) -} - /// Host-side hive + swarm display names, read from the c0re service's /// own process env. The `hive-c0re.nix` module sets these from /// `services.hyperhive.{hiveName, swarmName}`. The agent-side diff --git a/hive-c0re/src/host_stats.rs b/hive-c0re/src/host_stats.rs index 4e16da55..819c90d0 100644 --- a/hive-c0re/src/host_stats.rs +++ b/hive-c0re/src/host_stats.rs @@ -205,7 +205,6 @@ mod tests { deployed_sha: None, pending_reminders: 0, parent: None, - active_model: None, } }