feat: complete page ai hermes control checklist

This commit is contained in:
lix-2026
2026-05-14 18:24:30 +08:00
parent f257b2a014
commit 0fc9fa7551
7 changed files with 687 additions and 64 deletions
@@ -9,6 +9,7 @@ use futures_util::TryStreamExt;
use serde::Deserialize;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::fs;
use std::process::Command;
use std::time::Duration;
@@ -387,8 +388,50 @@ pub async fn list_tools(
{
"name": "mnote.page.get",
"scope": "page.read",
"kind": "read",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "planned_by_task_e"
"status": "available",
"description": "读取当前页面正文、标题、设置与结构快照"
},
{
"name": "mnote.page.save",
"scope": "page.write",
"kind": "write",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "available",
"description": "保存当前页面正文"
},
{
"name": "mnote.page.update_title",
"scope": "page.write",
"kind": "write",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "available",
"description": "更新当前页面标题"
},
{
"name": "mnote.page.update_options",
"scope": "page.write",
"kind": "write",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "available",
"description": "更新当前页面设置"
},
{
"name": "mnote.artifact.create_summary",
"scope": "artifact.write",
"kind": "write",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "available",
"description": "为当前页面创建或更新 AI Summary"
},
{
"name": "mnote.artifact.create_ai_note",
"scope": "artifact.write",
"kind": "write",
"schemaVersion": "mnote.hermes_tool.v1",
"status": "available",
"description": "基于当前页面创建新的 AI Note"
}
]
})),
@@ -411,20 +454,61 @@ fn ensure_authenticated(context: &RequestContext) -> Result<(), WebError> {
}
fn configured_upstream() -> Option<String> {
std::env::var("MNOTE_WEB_HERMES_UPSTREAM_URL")
.ok()
.or_else(|| std::env::var("MNOTE_HERMES_UPSTREAM_URL").ok())
.map(|value| value.trim().trim_end_matches('/').to_string())
.filter(|value| !value.is_empty())
[
"MNOTE_WEB_HERMES_UPSTREAM_URL",
"MNOTE_HERMES_UPSTREAM_URL",
"MNOTE_HERMES_API_BASE_URL",
]
.into_iter()
.find_map(env_or_dotenv)
.map(|value| value.trim().trim_end_matches('/').to_string())
.filter(|value| !value.is_empty())
}
fn configured_api_key() -> Option<String> {
std::env::var("MNOTE_WEB_HERMES_API_KEY")
.ok()
.or_else(|| std::env::var("HERMES_API_SERVER_KEY").ok())
.or_else(|| std::env::var("API_SERVER_KEY").ok())
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
[
"MNOTE_WEB_HERMES_API_KEY",
"MNOTE_HERMES_API_KEY",
"HERMES_API_SERVER_KEY",
"API_SERVER_KEY",
]
.into_iter()
.find_map(env_or_dotenv)
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
}
fn env_or_dotenv(key: &str) -> Option<String> {
if let Ok(value) = std::env::var(key) {
let trimmed = value.trim().trim_matches('"').to_string();
if !trimmed.is_empty() {
return Some(trimmed);
}
}
if cfg!(test) {
return None;
}
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../..")
.join(".env.all");
let content = fs::read_to_string(root).ok()?;
for line in content.lines() {
let line = line.trim_end_matches('\r');
if line.starts_with('#') || line.trim().is_empty() {
continue;
}
let Some((candidate_key, value)) = line.split_once('=') else {
continue;
};
if candidate_key.trim() != key {
continue;
}
let trimmed = value.trim().trim_matches('"').to_string();
if !trimmed.is_empty() {
return Some(trimmed);
}
}
None
}
fn build_run_upstream_body(context: &RequestContext, payload: Value) -> Result<Value, WebError> {