feat(rag): align LightRAG native citations and MCP bridge
This commit is contained in:
@@ -3,8 +3,8 @@ use crate::app::AppState;
|
||||
use crate::context::RequestContext;
|
||||
use crate::error::WebError;
|
||||
use crate::hermes_tools::{
|
||||
artifact, block, context_tools, doc, evidence, knowledge_rag, manifest, onlyoffice_live, page,
|
||||
resource, skill, ToolCallInput,
|
||||
artifact, block, context_tools, doc, knowledge_rag, manifest, onlyoffice_live, page, resource,
|
||||
skill, ToolCallInput,
|
||||
};
|
||||
use axum::extract::{Extension, Query, State};
|
||||
use axum::http::{HeaderMap, HeaderName, HeaderValue, StatusCode};
|
||||
@@ -360,13 +360,15 @@ pub(crate) async fn execute_mnote_tool_call(
|
||||
}
|
||||
"mnote.doc.fetch" => doc::doc_fetch(&state, &context, &input).await,
|
||||
"mnote.doc.find" => doc::doc_find(&state, &context, &input).await,
|
||||
"docs_search" => evidence::legacy_docs_search(&state, &context, &input).await,
|
||||
"docs_read" => evidence::legacy_docs_read(&state, &context, &input).await,
|
||||
"mnote.evidence.search" | "mnote.evidence.read" | "mnote.evidence.open" => {
|
||||
"docs_search"
|
||||
| "docs_read"
|
||||
| "mnote.evidence.search"
|
||||
| "mnote.evidence.read"
|
||||
| "mnote.evidence.open" => {
|
||||
Err(WebError::new(
|
||||
StatusCode::GONE,
|
||||
"mnote_evidence_tools_retired",
|
||||
"旧 evidence / LiteParse tools 已退役;请使用 mnote.knowledge_rag.query/open_reference",
|
||||
"旧 docs/evidence/LiteParse tools 已退役;请使用 mnote.knowledge_rag.query/open_reference",
|
||||
)
|
||||
.with_context(&context))
|
||||
}
|
||||
@@ -5466,38 +5468,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hermes_tools_legacy_docs_search_forwards_to_evidence_search() {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("mnote-docs-search-evidence-{}", std::process::id()));
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
fs::create_dir_all(root.join(".mnote")).expect("metadata");
|
||||
fs::write(
|
||||
root.join(".mnote").join("workspace.json"),
|
||||
r#"{"workspaceId":"local-ws-docs-search","ownerId":"user_1","createdAt":"2026-06-03T00:00:00Z","capabilities":["local_files"]}"#,
|
||||
)
|
||||
.expect("manifest");
|
||||
fs::write(
|
||||
root.join("README.md"),
|
||||
"# Evidence Home\n\ncompat-evidence-token 正文\n",
|
||||
)
|
||||
.expect("markdown");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
crate::routes::local_search_index::write_local_index_settings(
|
||||
&root,
|
||||
&[String::from(".")],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("settings");
|
||||
crate::routes::local_search_index::refresh_local_search_index(
|
||||
&root,
|
||||
&root_uri,
|
||||
"local-ws-docs-search",
|
||||
)
|
||||
.expect("refresh");
|
||||
|
||||
async fn hermes_tools_legacy_docs_search_is_retired() {
|
||||
let response = app()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
@@ -5511,7 +5482,7 @@ mod tests {
|
||||
"toolName": "docs_search",
|
||||
"workspaceId": "local-ws-docs-search",
|
||||
"sourceKind": "local_folder",
|
||||
"rootUri": root_uri,
|
||||
"rootUri": "file:///tmp/mnote-retired-docs-search",
|
||||
"sessionId": "sess_docs_search",
|
||||
"runId": "run_docs_search",
|
||||
"toolCallId": "call_docs_search",
|
||||
@@ -5529,72 +5500,15 @@ mod tests {
|
||||
.await
|
||||
.expect("response");
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
assert_eq!(response.status(), StatusCode::GONE);
|
||||
let body = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
let payload: Value = serde_json::from_slice(&body).expect("json");
|
||||
assert_eq!(payload["result"]["compatTool"], "docs_search");
|
||||
assert_eq!(payload["result"]["source"], "mnote.evidence.search");
|
||||
let result = payload["result"]["results"]
|
||||
.as_array()
|
||||
.and_then(|items| items.first())
|
||||
.expect("evidence result");
|
||||
assert_eq!(
|
||||
result["source"]["schema"].as_str(),
|
||||
Some("mnote.evidence_locator.v1")
|
||||
payload["code"].as_str(),
|
||||
Some("mnote_evidence_tools_retired")
|
||||
);
|
||||
assert_eq!(
|
||||
result["source"]["ownerDocumentPath"].as_str(),
|
||||
Some("README.md")
|
||||
);
|
||||
assert!(result["citationMarkdown"]
|
||||
.as_str()
|
||||
.is_some_and(|value| value.contains("](/documents/")));
|
||||
assert!(result["citationUrl"]
|
||||
.as_str()
|
||||
.is_some_and(|value| value.contains("resourceTab=")));
|
||||
let evidence_id = result["evidenceId"].as_str().expect("evidence id");
|
||||
assert_eq!(
|
||||
payload["result"]["evidenceIds"][0].as_str(),
|
||||
Some(evidence_id)
|
||||
);
|
||||
assert_eq!(
|
||||
payload["result"]["runReceipt"]["schema"].as_str(),
|
||||
Some("mnote.agent_run_receipt.evidence.v1")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["result"]["runReceipt"]["evidenceIds"][0].as_str(),
|
||||
Some(evidence_id)
|
||||
);
|
||||
assert_eq!(payload["evidenceIds"][0].as_str(), Some(evidence_id));
|
||||
assert_eq!(
|
||||
payload["runReceipt"]["toolCallId"].as_str(),
|
||||
Some("call_docs_search")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["audit"]["evidenceIds"][0].as_str(),
|
||||
Some(evidence_id)
|
||||
);
|
||||
let completed_audit =
|
||||
super::audit_events(Some("trace_docs_search"), Some("call_docs_search"))
|
||||
.into_iter()
|
||||
.find(|event| event["phase"] == "completed")
|
||||
.expect("completed audit");
|
||||
assert_eq!(
|
||||
completed_audit["audit"]["runReceipt"]["evidenceIds"][0].as_str(),
|
||||
Some(evidence_id)
|
||||
);
|
||||
assert!(payload["result"]["evidence"]
|
||||
.as_array()
|
||||
.expect("evidence")
|
||||
.iter()
|
||||
.any(|item| item["quote"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.contains("compat-evidence-token")));
|
||||
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -5697,19 +5611,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hermes_tools_legacy_docs_read_returns_document_with_locator() {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("mnote-docs-read-evidence-{}", std::process::id()));
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
fs::create_dir_all(root.join(".mnote")).expect("metadata");
|
||||
fs::write(
|
||||
root.join(".mnote").join("workspace.json"),
|
||||
r#"{"workspaceId":"local-ws-docs-read","ownerId":"user_1","createdAt":"2026-06-03T00:00:00Z","capabilities":["local_files"]}"#,
|
||||
)
|
||||
.expect("manifest");
|
||||
fs::write(root.join("README.md"), "# Docs Read\n\nlegacy docs read\n").expect("markdown");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
|
||||
async fn hermes_tools_legacy_docs_read_is_retired() {
|
||||
let response = app()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
@@ -5724,7 +5626,7 @@ mod tests {
|
||||
"workspaceId": "local-ws-docs-read",
|
||||
"documentId": "local-md:README.md",
|
||||
"sourceKind": "local_folder",
|
||||
"rootUri": root_uri,
|
||||
"rootUri": "file:///tmp/mnote-retired-docs-read",
|
||||
"sessionId": "sess_docs_read",
|
||||
"runId": "run_docs_read",
|
||||
"toolCallId": "call_docs_read",
|
||||
@@ -5741,25 +5643,15 @@ mod tests {
|
||||
.await
|
||||
.expect("response");
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
assert_eq!(response.status(), StatusCode::GONE);
|
||||
let body = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
let payload: Value = serde_json::from_slice(&body).expect("json");
|
||||
assert_eq!(payload["result"]["compatTool"], "docs_read");
|
||||
assert_eq!(
|
||||
payload["result"]["source"]["locator"]["schema"].as_str(),
|
||||
Some("mnote.evidence_locator.v1")
|
||||
payload["code"].as_str(),
|
||||
Some("mnote_evidence_tools_retired")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["result"]["source"]["locator"]["ownerDocumentPath"].as_str(),
|
||||
Some("README.md")
|
||||
);
|
||||
assert!(payload["result"]["document"]
|
||||
.to_string()
|
||||
.contains("legacy docs read"));
|
||||
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user