feat: purge legacy agent hosts and land vault Chrome extension path

Retire ACP/Hermes/OpenCode surfaces and rename hermes_tools to
mnote_agent_tools so Page AI stays on Pi Lab only. Add Chrome vault
extension + extension token route, pre-release purge design, and soft-retire
legacy smokes for the small-group production cut.
This commit is contained in:
Agent Board
2026-07-25 14:25:37 +08:00
parent bc6f8488ee
commit 262e66b02e
137 changed files with 9018 additions and 46049 deletions
@@ -1,7 +1,7 @@
use crate::app::AppState;
use crate::context::RequestContext;
use crate::error::WebError;
use crate::hermes_tools::ToolCallInput;
use crate::mnote_agent_tools::ToolCallInput;
use axum::extract::{Extension, State};
use axum::http::{HeaderMap, StatusCode};
use axum::Json;
@@ -132,7 +132,7 @@ pub async fn block_edit_workflow(
};
let apply_started = Instant::now();
let tool_response =
crate::routes::hermes_tools::execute_mnote_tool_call(&state, &context, edit_input).await?;
crate::routes::mnote_tools::execute_mnote_tool_call(&state, &context, edit_input).await?;
let apply_result = tool_response.get("result").cloned().unwrap_or(Value::Null);
let apply_ms = apply_started.elapsed().as_millis();
info!(
@@ -518,21 +518,35 @@ fn quoted_segments(value: &str) -> Vec<String> {
segments
}
fn hermes_home() -> PathBuf {
std::env::var("HERMES_HOME")
fn agent_profile_home() -> PathBuf {
std::env::var("MNOTE_AGENT_HOME")
.ok()
.filter(|value| !value.trim().is_empty())
.map(PathBuf::from)
.or_else(|| {
std::env::var("HOME")
std::env::var("HERMES_HOME")
.ok()
.map(|home| PathBuf::from(home).join(".hermes"))
.filter(|value| !value.trim().is_empty())
.map(PathBuf::from)
})
.unwrap_or_else(|| PathBuf::from(".hermes"))
.or_else(|| {
std::env::var("HOME").ok().and_then(|home| {
let preferred = PathBuf::from(&home).join(".mnote-agent");
if preferred.exists() {
return Some(preferred);
}
let legacy = PathBuf::from(&home).join(".hermes");
if legacy.exists() {
return Some(legacy);
}
Some(preferred)
})
})
.unwrap_or_else(|| PathBuf::from(".mnote-agent"))
}
fn profile_config_path(profile: &str) -> PathBuf {
let home = hermes_home();
let home = agent_profile_home();
let profile = profile.trim();
if profile.is_empty() || profile == "default" {
return home.join("config.yaml");
@@ -598,7 +612,7 @@ mod tests {
use tower::util::ServiceExt;
fn env_lock() -> &'static Mutex<()> {
crate::test_support::hermes_env_lock()
crate::test_support::agent_env_lock()
}
fn app() -> axum::Router {
@@ -612,7 +626,6 @@ mod tests {
enable_debug_shell_routes: false,
enable_editor_actor: true,
enable_page_ai_pi_lab: false,
hermes_base_path: "/api/hermes".into(),
compat_next_base_path: "/api/compat/next".into(),
convex_url: None,
convex_admin_key: None,
@@ -763,12 +776,12 @@ mod tests {
async fn block_edit_workflow_respects_disabled_markdown_edit_tool() {
let _guard = env_lock().lock().expect("env lock");
let base_url = spawn_mock_model_server().await;
let hermes_home = std::env::temp_dir().join(format!(
let agent_home = std::env::temp_dir().join(format!(
"mnote-page-ai-workflow-disabled-tool-{}",
std::process::id()
));
let _ = fs::remove_dir_all(&hermes_home);
let profile_dir = hermes_home.join("profiles").join("mnoteai");
let _ = fs::remove_dir_all(&agent_home);
let profile_dir = agent_home.join("profiles").join("mnoteai");
fs::create_dir_all(&profile_dir).expect("profile dir");
fs::write(
profile_dir.join("config.yaml"),
@@ -777,7 +790,7 @@ mod tests {
),
)
.expect("profile config");
std::env::set_var("HERMES_HOME", &hermes_home);
std::env::set_var("MNOTE_AGENT_HOME", &agent_home);
let response = app()
.oneshot(
@@ -821,20 +834,20 @@ mod tests {
let payload: Value = serde_json::from_slice(&body).expect("json");
assert_eq!(payload["code"], "mnote_tool_disabled");
std::env::remove_var("HERMES_HOME");
let _ = fs::remove_dir_all(&hermes_home);
std::env::remove_var("MNOTE_AGENT_HOME");
let _ = fs::remove_dir_all(&agent_home);
}
#[tokio::test]
async fn block_edit_workflow_forwards_allowed_target_blocks_to_markdown_edit() {
let _guard = env_lock().lock().expect("env lock");
let base_url = spawn_out_of_scope_mock_model_server().await;
let hermes_home = std::env::temp_dir().join(format!(
let agent_home = std::env::temp_dir().join(format!(
"mnote-page-ai-workflow-selection-scope-{}",
std::process::id()
));
let _ = fs::remove_dir_all(&hermes_home);
let profile_dir = hermes_home.join("profiles").join("mnoteai");
let _ = fs::remove_dir_all(&agent_home);
let profile_dir = agent_home.join("profiles").join("mnoteai");
fs::create_dir_all(&profile_dir).expect("profile dir");
fs::write(
profile_dir.join("config.yaml"),
@@ -843,7 +856,7 @@ mod tests {
),
)
.expect("profile config");
std::env::set_var("HERMES_HOME", &hermes_home);
std::env::set_var("MNOTE_AGENT_HOME", &agent_home);
let response = app()
.oneshot(
@@ -888,20 +901,20 @@ mod tests {
let payload: Value = serde_json::from_slice(&body).expect("json");
assert_eq!(payload["code"], "mnote_markdown_edit_target_out_of_scope");
std::env::remove_var("HERMES_HOME");
let _ = fs::remove_dir_all(&hermes_home);
std::env::remove_var("MNOTE_AGENT_HOME");
let _ = fs::remove_dir_all(&agent_home);
}
#[tokio::test]
async fn block_edit_workflow_surfaces_model_summary_for_read_and_edit_request() {
let _guard = env_lock().lock().expect("env lock");
let base_url = spawn_read_and_edit_mock_model_server().await;
let hermes_home = std::env::temp_dir().join(format!(
let agent_home = std::env::temp_dir().join(format!(
"mnote-page-ai-workflow-read-summary-{}",
std::process::id()
));
let _ = fs::remove_dir_all(&hermes_home);
let profile_dir = hermes_home.join("profiles").join("mnoteai");
let _ = fs::remove_dir_all(&agent_home);
let profile_dir = agent_home.join("profiles").join("mnoteai");
fs::create_dir_all(&profile_dir).expect("profile dir");
fs::write(
profile_dir.join("config.yaml"),
@@ -910,7 +923,7 @@ mod tests {
),
)
.expect("profile config");
std::env::set_var("HERMES_HOME", &hermes_home);
std::env::set_var("MNOTE_AGENT_HOME", &agent_home);
let response = app()
.oneshot(
@@ -962,7 +975,7 @@ mod tests {
.unwrap_or_default()
.contains("测试123"));
std::env::remove_var("HERMES_HOME");
let _ = fs::remove_dir_all(&hermes_home);
std::env::remove_var("MNOTE_AGENT_HOME");
let _ = fs::remove_dir_all(&agent_home);
}
}