refactor(perceive): expose last interaction tracking and refresh memory sessions

This commit is contained in:
2026-03-10 22:57:59 +08:00
parent 3d1c258944
commit 3f6283d12a
9 changed files with 113 additions and 37 deletions

View File

@@ -29,8 +29,8 @@ public interface MemoryCapability {
Collection<MemoryUnit> listMemoryUnits();
void refreshMemoryId();
void refreshMemorySession();
String getCurrentMemoryId();
String getMemorySessionId();
}

View File

@@ -13,6 +13,7 @@ import work.slhaf.partner.core.memory.pojo.MemoryUnit;
import java.io.IOException;
import java.io.Serial;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -32,7 +33,10 @@ public class MemoryCore extends PartnerCore<MemoryCore> {
private final Lock memoryLock = new ReentrantLock();
private ConcurrentHashMap<String, MemoryUnit> memoryUnits = new ConcurrentHashMap<>();
private List<ActivatedMemorySlice> activatedSlices = new CopyOnWriteArrayList<>();
private String currentMemoryId;
// 默认值一般只存在于智能体初次启动时
private String memorySessionId = UUID.randomUUID().toString();
private Instant memorySessionStartTime = Instant.now();
public MemoryCore() throws IOException, ClassNotFoundException {
}
@@ -98,13 +102,14 @@ public class MemoryCore extends PartnerCore<MemoryCore> {
}
@CapabilityMethod
public void refreshMemoryId() {
currentMemoryId = UUID.randomUUID().toString();
public void refreshMemorySession() {
memorySessionId = UUID.randomUUID().toString();
memorySessionStartTime = Instant.now();
}
@CapabilityMethod
public String getCurrentMemoryId() {
return currentMemoryId;
public String getMemorySessionId() {
return memorySessionId;
}
private void normalizeMemoryUnit(MemoryUnit memoryUnit) {

View File

@@ -12,4 +12,8 @@ public interface PerceiveCapability {
User addUser(String userInfo, String platform, String userNickName);
void updateUser(User user);
String refreshInteract();
long showLastInteract();
}

View File

@@ -11,6 +11,9 @@ import work.slhaf.partner.core.perceive.pojo.User;
import java.io.IOException;
import java.io.Serial;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -27,6 +30,8 @@ public class PerceiveCore extends PartnerCore<PerceiveCore> {
private static final long serialVersionUID = 1L;
private static final ReentrantLock usersLock = new ReentrantLock();
private Instant lastInteractTime;
/**
* 用户列表
*/
@@ -92,6 +97,18 @@ public class PerceiveCore extends PartnerCore<PerceiveCore> {
usersLock.unlock();
}
@CapabilityMethod
public String refreshInteract() {
String last = lastInteractTime.atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
lastInteractTime = Instant.now();
return last;
}
@CapabilityMethod
public long showLastInteract() {
return lastInteractTime.toEpochMilli();
}
@Override
protected String getCoreKey() {
return "perceive-core";

View File

@@ -56,9 +56,9 @@ public class MemoryRuntime extends AbstractAgentModule.Standalone {
}
private void checkAndSetMemoryId() {
String currentMemoryId = memoryCapability.getCurrentMemoryId();
String currentMemoryId = memoryCapability.getMemorySessionId();
if (currentMemoryId == null || cognationCapability.getChatMessages().isEmpty()) {
memoryCapability.refreshMemoryId();
memoryCapability.refreshMemorySession();
}
}

View File

@@ -15,6 +15,7 @@ import work.slhaf.partner.core.cognation.CognationCapability;
import work.slhaf.partner.core.memory.MemoryCapability;
import work.slhaf.partner.core.memory.pojo.MemorySlice;
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
import work.slhaf.partner.core.perceive.PerceiveCapability;
import work.slhaf.partner.module.common.module.PostRunningAgentModule;
import work.slhaf.partner.module.modules.action.scheduler.ActionScheduler;
import work.slhaf.partner.module.modules.memory.runtime.MemoryRuntime;
@@ -41,6 +42,8 @@ public class MemoryUpdater extends PostRunningAgentModule {
private CognationCapability cognationCapability;
@InjectCapability
private MemoryCapability memoryCapability;
@InjectCapability
private PerceiveCapability perceiveCapability;
@InjectModule
private MemoryRuntime memoryRuntime;
@@ -53,7 +56,6 @@ public class MemoryUpdater extends PostRunningAgentModule {
private final AtomicBoolean updating = new AtomicBoolean(false);
private InteractionThreadPoolExecutor executor;
private volatile long lastUpdatedTime;
@Init
public void init() {
@@ -103,7 +105,7 @@ public class MemoryUpdater extends PostRunningAgentModule {
private void tryAutoUpdate() {
long currentTime = System.currentTimeMillis();
int chatCount = cognationCapability.snapshotChatMessages().size();
if (lastUpdatedTime != 0 && currentTime - lastUpdatedTime > UPDATE_TRIGGER_INTERVAL && chatCount > 1) {
if (currentTime - perceiveCapability.showLastInteract() > UPDATE_TRIGGER_INTERVAL && chatCount > 1) {
triggerMemoryUpdate(true);
log.info("[MemoryUpdater] 记忆更新: 自动触发");
}
@@ -122,7 +124,7 @@ public class MemoryUpdater extends PostRunningAgentModule {
updateMemory(chatSnapshot);
cognationCapability.rollChatMessagesWithSnapshot(chatSnapshot.size(), CONTEXT_RETAIN_DIVISOR);
if (refreshMemoryId) {
memoryCapability.refreshMemoryId();
memoryCapability.refreshMemorySession();
}
} catch (Exception e) {
log.error("[MemoryUpdater] 记忆更新线程出错: ", e);
@@ -147,7 +149,6 @@ public class MemoryUpdater extends PostRunningAgentModule {
summarizeResult.getRelatedTopicPath(),
summarizeResult.getSummary()
);
lastUpdatedTime = System.currentTimeMillis();
log.debug("[MemoryUpdater] 记忆更新流程结束...");
}
@@ -166,7 +167,7 @@ public class MemoryUpdater extends PostRunningAgentModule {
memorySlice.setTimestamp(now);
MemoryUnit memoryUnit = new MemoryUnit();
String memoryId = memoryCapability.getCurrentMemoryId();
String memoryId = memoryCapability.getMemorySessionId();
memoryUnit.setId(memoryId == null || memoryId.isBlank() ? UUID.randomUUID().toString() : memoryId);
memoryUnit.setTimestamp(now);
memoryUnit.setConversationMessages(new ArrayList<>(chatMessages));

View File

@@ -0,0 +1,71 @@
package work.slhaf.partner.module.modules.perceive;
import lombok.AllArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.ContextBlock;
import work.slhaf.partner.core.perceive.PerceiveCapability;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@Setter
public class PerceiveMonitor extends AbstractAgentModule.Running<PartnerRunningFlowContext> {
@InjectCapability
private PerceiveCapability perceiveCapability;
@Override
public void execute(PartnerRunningFlowContext context) {
context.getContextBlocks().add(new PerceiveBlock(perceiveCapability.refreshInteract()));
}
@Override
public int order() {
return 1;
}
@AllArgsConstructor
private static class PerceiveBlock extends ContextBlock {
private String lastInteractTime;
@Override
public int getPriority() {
return 0;
}
@Override
@NotNull
public Type getType() {
return Type.CONTEXT;
}
@Override
@NotNull
public String getBlockName() {
return "perceive_info";
}
@Override
@NotNull
public String getSource() {
return "perceive_monitor";
}
@Override
protected void fillXml(@NotNull Document document, @NotNull Element root) {
Element lastInteractTime = document.createElement("last_interact_time");
lastInteractTime.setTextContent(this.lastInteractTime);
root.appendChild(lastInteractTime);
Element currentTime = document.createElement("current_time");
currentTime.setTextContent(ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
root.appendChild(currentTime);
}
}
}

View File

@@ -1,22 +0,0 @@
package work.slhaf.partner.module.modules.perceive.selector;
import lombok.Setter;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.core.perceive.PerceiveCapability;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
@Setter
public class PerceiveSelector extends AbstractAgentModule.Running<PartnerRunningFlowContext> {
@InjectCapability
private PerceiveCapability perceiveCapability;
@Override
public void execute(PartnerRunningFlowContext context) {
}
@Override
public int order() {
return 2;
}
}

View File

@@ -20,6 +20,6 @@ public class ReflectionTest {
}
return null;
});
memory.getCurrentMemoryId();
memory.getMemorySessionId();
}
}