feat(mnote-web): add local file read support to mnote.doc.fetch + WS push design doc

## mnote.doc.fetch: local file path support
- Detect local file paths (starting with `/` or `./`) and bypass Convex aggregate
- Read .md file directly via fs::read_to_string
- Return source: "local_fs" in response
- Support maxChars truncation for local files
- Online Convex path unchanged

## Design: WS push migration (3-14)
- New: design/03-rust-web/process/3-14-rust-web-tree-realtime-ws-push-v1.md
- Documents commit 9d8e361e WebSocket push migration rationale,
  architecture, and verification

## Updated design doc references
- 3-3: Mark SSE as fallback transport (WS push is primary)
- 08 checklist: Note WS push in Tree Realtime section
- AGENTS.md: Update tree/realtime references to reflect WS push

## Housekeeping
- desktop-hot.js: remove 3 stale log messages about disabled services
- page_ai_workflow.rs: fix 5 warnings (unused import, dead_code)
This commit is contained in:
lix-2026
2026-05-17 15:57:40 +08:00
parent 9d8e361e43
commit 3f43020603
7 changed files with 291 additions and 67 deletions
@@ -1,7 +1,7 @@
use crate::app::AppState;
use crate::context::RequestContext;
use crate::error::WebError;
use crate::hermes_tools::{block, doc, ToolCallInput};
use crate::hermes_tools::{doc, ToolCallInput};
use axum::extract::{Extension, State};
use axum::http::{HeaderMap, StatusCode};
use axum::Json;
@@ -185,6 +185,7 @@ fn extract_markdown_operations_from_model_text(text: &str) -> Result<Vec<Value>,
))
}
#[allow(dead_code)]
fn extract_operations_from_model_text(text: &str) -> Result<Vec<Value>, WebError> {
let parsed = parse_model_json(text)?;
if let Some(content) = parsed
@@ -289,7 +290,7 @@ async fn call_block_edit_model(
.get("pageText")
.and_then(Value::as_str)
.unwrap_or_default();
let allowed = ai_context
let _allowed_block_ids = ai_context
.get("allowedTargetBlockIds")
.cloned()
.unwrap_or_else(|| json!([]));
@@ -405,6 +406,7 @@ fn looks_like_block_edit(message: &str) -> bool {
.any(|needle| message.contains(needle))
}
#[allow(dead_code)]
fn direct_block_edit_operations(message: &str) -> Option<Vec<Value>> {
let mut operations = Vec::new();
for clause in message
@@ -441,6 +443,7 @@ fn direct_block_edit_operations(message: &str) -> Option<Vec<Value>> {
}
}
#[allow(dead_code)]
fn quoted_segments(value: &str) -> Vec<String> {
let mut segments = Vec::new();
let mut start: Option<char> = None;