diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/hotcache/WikiHotCacheProvider.java b/mateclaw-server/src/main/java/vip/mate/wiki/hotcache/WikiHotCacheProvider.java new file mode 100644 index 00000000..10d291f4 --- /dev/null +++ b/mateclaw-server/src/main/java/vip/mate/wiki/hotcache/WikiHotCacheProvider.java @@ -0,0 +1,85 @@ +package vip.mate.wiki.hotcache; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import vip.mate.memory.spi.MemoryProvider; +import vip.mate.system.featureflag.FeatureFlagService; +import vip.mate.wiki.model.WikiKnowledgeBaseEntity; +import vip.mate.wiki.service.WikiKnowledgeBaseService; + +import java.util.List; + +/** + * Memory-SPI provider that injects each KB's hot cache snapshot into the + * agent's system prompt at build time. + * + *
Resolves the agent's accessible KBs via the same path the chat + * pipeline already uses ({@link WikiKnowledgeBaseService#listByAgentId}). + * If the agent reaches more than {@link #MAX_KBS_PER_AGENT} KBs, only the + * top KBs by recent-update order contribute (the list is already sorted + * by {@code update_time DESC}); this is a prompt-budget guard, not a + * permissions decision. + * + *
Per-turn paths are intentionally untouched — wiki relevance is
+ * already handled by {@code WikiContextService.buildRelevantContext} on
+ * each user message; this provider's job is the steady "what's been
+ * happening here" header that the model sees once at session start.
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class WikiHotCacheProvider implements MemoryProvider {
+
+ private static final String FLAG = "wiki.hot_cache.enabled";
+ private static final int MAX_KBS_PER_AGENT = 2;
+
+ private final WikiHotCacheService cacheService;
+ private final WikiKnowledgeBaseService kbService;
+ private final FeatureFlagService featureFlagService;
+
+ @Override
+ public String id() {
+ return "wiki_hot_cache";
+ }
+
+ @Override
+ public int order() {
+ // After builtin (0), structured (10), session-search (20).
+ // Hot cache is freshest, but slots after the more general blocks
+ // so the model frames "recent activity" as a sub-context, not a
+ // top-level identity hint.
+ return 30;
+ }
+
+ @Override
+ public String systemPromptBlock(Long agentId) {
+ if (agentId == null) return "";
+ try {
+ if (!featureFlagService.isEnabled(FLAG)) return "";
+
+ List