mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 11:58:34 +08:00
feat(wiki): knowledge-layer filter on wiki search
This commit is contained in:
parent
ad1f5b4a15
commit
cc8c9cf951
@ -275,6 +275,7 @@ public class WikiTool {
|
|||||||
@ToolParam(description = "Search query") String query,
|
@ToolParam(description = "Search query") String query,
|
||||||
@ToolParam(description = "Mode: keyword|semantic|hybrid (default: hybrid)", required = false) String mode,
|
@ToolParam(description = "Mode: keyword|semantic|hybrid (default: hybrid)", required = false) String mode,
|
||||||
@ToolParam(description = "Max results (default 5, max 20)", required = false) Integer topK,
|
@ToolParam(description = "Max results (default 5, max 20)", required = false) Integer topK,
|
||||||
|
@ToolParam(description = "Knowledge layer filter: fact | experience | all (default all). 'fact' = factual pages (and unlayered pages); 'experience' = synthesis/analysis pages.", required = false) String layer,
|
||||||
@ToolParam(description = "Target knowledge base name (from wiki_list_kbs). Omit to use the agent's primary KB; switch to `kbId` when two KBs share the name.", required = false) String kbName,
|
@ToolParam(description = "Target knowledge base name (from wiki_list_kbs). Omit to use the agent's primary KB; switch to `kbId` when two KBs share the name.", required = false) String kbName,
|
||||||
@ToolParam(description = "Numeric KB id from wiki_list_kbs. Use when `kbName` returns an ambiguous-name error.", required = false) Long kbId) {
|
@ToolParam(description = "Numeric KB id from wiki_list_kbs. Use when `kbName` returns an ambiguous-name error.", required = false) Long kbId) {
|
||||||
|
|
||||||
@ -289,15 +290,17 @@ public class WikiTool {
|
|||||||
int k = (topK != null && topK > 0) ? Math.min(topK, 20) : 5;
|
int k = (topK != null && topK > 0) ? Math.min(topK, 20) : 5;
|
||||||
List<PageSearchResult> results = hybridRetriever.search(kbId, query, mode, k);
|
List<PageSearchResult> results = hybridRetriever.search(kbId, query, mode, k);
|
||||||
|
|
||||||
// Drop hits whose page type this agent may not read, so search cannot
|
// Drop hits this agent may not read (by page type) or that fall outside
|
||||||
// surface pages a direct read would refuse.
|
// the requested knowledge layer. Both need the page, so fetch it once.
|
||||||
WikiPageTypePermissionService.Access access = pageTypeAccess(agentId, kbId);
|
WikiPageTypePermissionService.Access access = pageTypeAccess(agentId, kbId);
|
||||||
if (access != null) {
|
boolean layerFilter = layer != null && !layer.isBlank() && !"all".equalsIgnoreCase(layer.trim());
|
||||||
|
if (access != null || layerFilter) {
|
||||||
final Long resolvedKbId = kbId;
|
final Long resolvedKbId = kbId;
|
||||||
|
final String layerWanted = layer;
|
||||||
results = results.stream()
|
results = results.stream()
|
||||||
.filter(r -> {
|
.filter(r -> {
|
||||||
WikiPageEntity p = pageService.getBySlug(resolvedKbId, r.slug());
|
WikiPageEntity p = pageService.getBySlug(resolvedKbId, r.slug());
|
||||||
return canRead(access, p);
|
return canRead(access, p) && matchesLayer(p == null ? null : p.getKnowledgeLayer(), layerWanted);
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@ -1069,6 +1072,20 @@ public class WikiTool {
|
|||||||
return access == null || access.canRead(pageType);
|
return access == null || access.canRead(pageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a page's knowledge layer matches a retrieval filter. A null/blank
|
||||||
|
* or {@code all} filter matches everything; an unlayered page counts as
|
||||||
|
* {@code fact} (the RFC default), so {@code layer=fact} includes legacy
|
||||||
|
* pages while {@code layer=experience} returns only experience pages.
|
||||||
|
*/
|
||||||
|
static boolean matchesLayer(String pageLayer, String filter) {
|
||||||
|
if (filter == null || filter.isBlank() || "all".equalsIgnoreCase(filter.trim())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String effective = (pageLayer == null || pageLayer.isBlank()) ? "fact" : pageLayer.trim().toLowerCase();
|
||||||
|
return effective.equals(filter.trim().toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gate a write/mutate operation by pageType permission. Returns an error
|
* Gate a write/mutate operation by pageType permission. Returns an error
|
||||||
* JSON string to short-circuit the tool when the write is not permitted, or
|
* JSON string to short-circuit the tool when the write is not permitted, or
|
||||||
|
|||||||
@ -0,0 +1,41 @@
|
|||||||
|
package vip.mate.wiki.tool;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the retrieval knowledge-layer filter ({@link WikiTool#matchesLayer}).
|
||||||
|
*/
|
||||||
|
class WikiToolLayerFilterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noFilterOrAll_matchesEverything() {
|
||||||
|
assertTrue(WikiTool.matchesLayer("experience", null));
|
||||||
|
assertTrue(WikiTool.matchesLayer("experience", ""));
|
||||||
|
assertTrue(WikiTool.matchesLayer("experience", "all"));
|
||||||
|
assertTrue(WikiTool.matchesLayer(null, "all"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void factFilter_includesUnlayeredPages() {
|
||||||
|
assertTrue(WikiTool.matchesLayer(null, "fact")); // legacy / unlayered counts as fact
|
||||||
|
assertTrue(WikiTool.matchesLayer("", "fact"));
|
||||||
|
assertTrue(WikiTool.matchesLayer("fact", "fact"));
|
||||||
|
assertFalse(WikiTool.matchesLayer("experience", "fact"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void experienceFilter_excludesFactAndUnlayered() {
|
||||||
|
assertTrue(WikiTool.matchesLayer("experience", "experience"));
|
||||||
|
assertFalse(WikiTool.matchesLayer("fact", "experience"));
|
||||||
|
assertFalse(WikiTool.matchesLayer(null, "experience"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void caseInsensitive() {
|
||||||
|
assertTrue(WikiTool.matchesLayer("Experience", "EXPERIENCE"));
|
||||||
|
assertTrue(WikiTool.matchesLayer("FACT", "fact"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user