refactor(memory): migrate slice/topic/date lookup to Result flow and unify MemoryLookupException reporting

This commit is contained in:
2026-04-12 20:13:11 +08:00
parent e37a282141
commit 93304878ad
16 changed files with 166 additions and 99 deletions

View File

@@ -4,6 +4,7 @@ import work.slhaf.partner.core.memory.pojo.MemorySlice;
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability;
import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.support.Result;
import java.util.Collection;
import java.util.List;
@@ -13,7 +14,7 @@ public interface MemoryCapability {
MemoryUnit getMemoryUnit(String unitId);
MemorySlice getMemorySlice(String unitId, String sliceId);
Result<MemorySlice> getMemorySlice(String unitId, String sliceId);
MemoryUnit updateMemoryUnit(List<Message> chatMessages, String summary);

View File

@@ -12,6 +12,8 @@ import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.state.State;
import work.slhaf.partner.framework.agent.state.StateSerializable;
import work.slhaf.partner.framework.agent.state.StateValue;
import work.slhaf.partner.framework.agent.support.Result;
import work.slhaf.partner.module.memory.runtime.exception.MemoryLookupException;
import java.nio.file.Path;
import java.util.*;
@@ -71,17 +73,25 @@ public class MemoryCore implements StateSerializable {
}
@CapabilityMethod
public MemorySlice getMemorySlice(String unitId, String sliceId) {
public Result<MemorySlice> getMemorySlice(String unitId, String sliceId) {
MemoryUnit memoryUnit = memoryUnits.get(unitId);
if (memoryUnit == null || memoryUnit.getSlices() == null) {
return null;
return Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
));
}
for (MemorySlice slice : memoryUnit.getSlices()) {
if (sliceId.equals(slice.getId())) {
return slice;
return Result.success(slice);
}
}
return null;
return Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
));
}
@CapabilityMethod

View File

@@ -14,6 +14,7 @@ import work.slhaf.partner.core.memory.pojo.MemorySlice;
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
import work.slhaf.partner.framework.agent.support.Result;
import java.util.*;
import java.util.function.Function;
@@ -66,14 +67,14 @@ class BuiltinCapabilityActionProvider implements BuiltinActionProvider {
Function<Map<String, Object>, String> invoker = params -> {
String unitId = BuiltinActionRegistry.BuiltinActionDefinition.requireString(params, "unit_id");
String sliceId = BuiltinActionRegistry.BuiltinActionDefinition.requireString(params, "slice_id");
MemorySlice slice = memoryCapability.getMemorySlice(unitId, sliceId);
if (slice == null) {
Result<MemorySlice> sliceResult = memoryCapability.getMemorySlice(unitId, sliceId);
if (sliceResult.exceptionOrNull() != null) {
return JSONObject.of(
"ok", false,
"message", "Memory slice not found"
"message", sliceResult.exceptionOrNull().getLocalizedMessage()
).toJSONString();
}
MemorySlice slice = sliceResult.getOrThrow();
MemoryUnit unit = memoryCapability.getMemoryUnit(unitId);
cognitionCapability.contextWorkspace().register(new ContextBlock(
@@ -85,7 +86,7 @@ class BuiltinCapabilityActionProvider implements BuiltinActionProvider {
));
return JSONObject.of(
"ok", false,
"ok", true,
"message", "Memory slice found and recalled into context"
).toJSONString();
};

View File

@@ -10,6 +10,7 @@ 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.memory.pojo.SliceRef;
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -17,8 +18,8 @@ import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.state.State;
import work.slhaf.partner.framework.agent.state.StateSerializable;
import work.slhaf.partner.framework.agent.state.StateValue;
import work.slhaf.partner.module.memory.runtime.exception.UnExistedDateIndexException;
import work.slhaf.partner.module.memory.runtime.exception.UnExistedTopicException;
import work.slhaf.partner.framework.agent.support.Result;
import work.slhaf.partner.module.memory.runtime.exception.MemoryLookupException;
import work.slhaf.partner.module.memory.selector.ActivatedMemorySlice;
import java.nio.file.Path;
@@ -105,16 +106,26 @@ public class MemoryRuntime extends AbstractAgentModule.Standalone implements Sta
private List<SliceRef> findByTopicPath(String topicPath) {
String normalizedPath = normalizeTopicPath(topicPath);
List<SliceRef> refs = topicSlices.get(normalizedPath);
if (refs == null || refs.isEmpty()) {
throw new UnExistedTopicException("不存在的主题: " + normalizedPath);
if (refs == null) {
ExceptionReporterHandler.INSTANCE.report(new MemoryLookupException(
"Unexisted topic path: " + normalizedPath,
normalizedPath,
"TOPIC"
));
return List.of();
}
return new ArrayList<>(refs);
}
private List<SliceRef> findByDate(LocalDate date) {
List<SliceRef> refs = dateIndex.get(date);
if (refs == null || refs.isEmpty()) {
throw new UnExistedDateIndexException("不存在的日期索引: " + date);
if (refs == null) {
ExceptionReporterHandler.INSTANCE.report(new MemoryLookupException(
"Unexisted date index: " + date,
date.toString(),
"DATE_INDEX"
));
return List.of();
}
return new ArrayList<>(refs);
}
@@ -160,10 +171,11 @@ public class MemoryRuntime extends AbstractAgentModule.Standalone implements Sta
private ActivatedMemorySlice buildActivatedMemorySlice(SliceRef ref) {
MemoryUnit memoryUnit = memoryCapability.getMemoryUnit(ref.getUnitId());
MemorySlice memorySlice = memoryCapability.getMemorySlice(ref.getUnitId(), ref.getSliceId());
if (memoryUnit == null || memorySlice == null) {
Result<MemorySlice> memorySliceResult = memoryCapability.getMemorySlice(ref.getUnitId(), ref.getSliceId());
if (memorySliceResult.exceptionOrNull() != null) {
return null;
}
MemorySlice memorySlice = memorySliceResult.getOrThrow();
List<Message> messages = sliceMessages(memoryUnit, memorySlice);
LocalDate date = Instant.ofEpochMilli(memorySlice.getTimestamp())
.atZone(ZoneId.systemDefault())
@@ -254,7 +266,7 @@ public class MemoryRuntime extends AbstractAgentModule.Standalone implements Sta
try {
dateIndex.put(LocalDate.parse(date), decodeSliceRefs(dateObject.getJSONArray("refs")));
} catch (Exception e) {
log.warn("[MemoryRuntime] 跳过非法日期索引: {}", date, e);
log.warn("skip invalid date index: {}", date, e);
}
}
}

View File

@@ -0,0 +1,30 @@
package work.slhaf.partner.module.memory.runtime.exception;
import work.slhaf.partner.framework.agent.exception.AgentRuntimeException;
import work.slhaf.partner.framework.agent.exception.ExceptionReport;
public class MemoryLookupException extends AgentRuntimeException {
private final String lookupKey;
private final String lookupTarget;
public MemoryLookupException(String message, String lookupKey, String lookupTarget) {
super(message);
this.lookupKey = lookupKey;
this.lookupTarget = lookupTarget;
}
public MemoryLookupException(String message, String lookupKey, String lookupTarget, Throwable cause) {
super(message, cause);
this.lookupKey = lookupKey;
this.lookupTarget = lookupTarget;
}
@Override
public ExceptionReport toReport() {
ExceptionReport report = super.toReport();
report.getExtra().put("lookupKey", lookupKey);
report.getExtra().put("lookupTarget", lookupTarget);
return report;
}
}

View File

@@ -1,7 +0,0 @@
package work.slhaf.partner.module.memory.runtime.exception;
public class UnExistedDateIndexException extends RuntimeException {
public UnExistedDateIndexException(String message) {
super(message);
}
}

View File

@@ -1,7 +0,0 @@
package work.slhaf.partner.module.memory.runtime.exception;
public class UnExistedTopicException extends RuntimeException {
public UnExistedTopicException(String message) {
super(message);
}
}

View File

@@ -16,8 +16,7 @@ import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAg
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.module.memory.runtime.MemoryRuntime;
import work.slhaf.partner.module.memory.runtime.exception.UnExistedDateIndexException;
import work.slhaf.partner.module.memory.runtime.exception.UnExistedTopicException;
import work.slhaf.partner.module.memory.runtime.exception.MemoryLookupException;
import work.slhaf.partner.module.memory.selector.evaluator.SliceSelectEvaluator;
import work.slhaf.partner.module.memory.selector.evaluator.entity.EvaluatorInput;
import work.slhaf.partner.module.memory.selector.extractor.MemorySelectExtractor;
@@ -114,7 +113,7 @@ public class MemorySelector extends AbstractAgentModule.Running<PartnerRunningFl
);
ExtractorResult extractorResult = memorySelectExtractor.execute(input);
if (extractorResult.isRecall() || !extractorResult.getMatches().isEmpty()) {
if (!extractorResult.getMatches().isEmpty()) {
List<ActivatedMemorySlice> activatedSlices = selectAndEvaluateMemory(snapshotInputs, extractorResult);
updateMemoryContext(activatedSlices);
}
@@ -207,7 +206,6 @@ public class MemorySelector extends AbstractAgentModule.Running<PartnerRunningFl
}
private List<ActivatedMemorySlice> selectAndEvaluateMemory(Map<LocalDateTime, String> snapshotInputs, ExtractorResult extractorResult) {
log.debug("[MemorySelector] 触发记忆回溯...");
LinkedHashMap<String, ActivatedMemorySlice> candidates = new LinkedHashMap<>();
setMemoryCandidates(candidates, extractorResult.getMatches());
EvaluatorInput evaluatorInput = EvaluatorInput.builder()
@@ -231,7 +229,7 @@ public class MemorySelector extends AbstractAgentModule.Running<PartnerRunningFl
for (ActivatedMemorySlice recalledSlice : recalledSlices) {
candidates.putIfAbsent(recalledSlice.getUnitId() + ":" + recalledSlice.getSliceId(), recalledSlice);
}
} catch (UnExistedDateIndexException | UnExistedTopicException e) {
} catch (MemoryLookupException e) {
log.error("[MemorySelector] 不存在的记忆索引", e);
log.error("[MemorySelector] 错误索引: {}", match.getText());
}

View File

@@ -8,6 +8,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.core.cognition.ContextBlock;
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
@@ -43,15 +44,10 @@ public class MemorySelectExtractor extends AbstractAgentModule.Sub<ExtractorInpu
messages,
ExtractorResult.class
);
extractorResult = result.fold(
value -> {
log.debug("[MemorySelectExtractor] 主题提取结果: {}", value);
return value;
},
extractorResult = result.onFailure(ExceptionReporterHandler.INSTANCE::report).fold(
value -> value,
exception -> {
log.error("[MemorySelectExtractor] 主题提取出错: ", exception);
ExtractorResult fallback = new ExtractorResult();
fallback.setRecall(false);
fallback.setMatches(List.of());
return fallback;
}

View File

@@ -6,6 +6,5 @@ import java.util.List;
@Data
public class ExtractorResult {
private boolean recall;
private List<ExtractorMatchData> matches;
}

View File

@@ -1,6 +1,5 @@
package work.slhaf.partner.module.memory.updater;
import com.alibaba.fastjson2.JSONObject;
import kotlin.Unit;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -25,7 +24,6 @@ import work.slhaf.partner.module.memory.runtime.MemoryRuntime;
import work.slhaf.partner.module.memory.updater.summarizer.MultiSummarizer;
import work.slhaf.partner.module.memory.updater.summarizer.SingleSummarizer;
import work.slhaf.partner.module.memory.updater.summarizer.entity.SummarizeInput;
import work.slhaf.partner.module.memory.updater.summarizer.entity.SummarizeResult;
import work.slhaf.partner.runtime.PartnerRunningFlowContext;
import java.util.List;
@@ -126,9 +124,7 @@ public class MemoryUpdater extends AbstractAgentModule.Running<PartnerRunningFlo
}
RollingRecord record = updateMemory(chatIncrement);
if (record != null) {
dialogRollingService.rollMessages(chatIncrement, fullChatSnapshot.size(), CONTEXT_RETAIN_DIVISOR, record.unitId, record.sliceId, record.summary);
}
dialogRollingService.rollMessages(chatIncrement, fullChatSnapshot.size(), CONTEXT_RETAIN_DIVISOR, record.unitId, record.sliceId, record.summary);
if (refreshMemoryId) {
memoryCapability.refreshMemorySession();
@@ -167,23 +163,23 @@ public class MemoryUpdater extends AbstractAgentModule.Running<PartnerRunningFlo
return null;
}
SummarizeInput summarizeInput = new SummarizeInput(chatSnapshot, memoryRuntime.getTopicTree());
log.debug("[MemoryUpdater] 记忆更新-总结流程-输入: {}", JSONObject.toJSONString(summarizeInput));
SummarizeResult summarizeResult = summarize(summarizeInput);
log.debug("[MemoryUpdater] 记忆更新-总结流程-输出: {}", JSONObject.toJSONString(summarizeResult));
MemoryUnit memoryUnit = memoryCapability.updateMemoryUnit(chatSnapshot, summarizeResult.getSummary());
memoryRuntime.recordMemory(
memoryUnit,
summarizeResult.getTopicPath(),
summarizeResult.getRelatedTopicPath()
);
log.debug("[MemoryUpdater] 记忆更新流程结束...");
MemorySlice newSlice = memoryUnit.getSlices().getLast();
return new RollingRecord(memoryUnit.getId(), newSlice.getId(), newSlice.getSummary());
}
private SummarizeResult summarize(SummarizeInput summarizeInput) {
singleSummarizer.execute(summarizeInput.getChatMessages());
return multiSummarizer.execute(summarizeInput);
return multiSummarizer.execute(summarizeInput).fold(
summarizeResult -> {
MemoryUnit memoryUnit = memoryCapability.updateMemoryUnit(chatSnapshot, summarizeResult.getSummary());
memoryRuntime.recordMemory(
memoryUnit,
summarizeResult.getTopicPath(),
summarizeResult.getRelatedTopicPath()
);
MemorySlice newSlice = memoryUnit.getSlices().getLast();
return new RollingRecord(memoryUnit.getId(), newSlice.getId(), newSlice.getSummary());
},
exp -> {
MemoryUnit memoryUnit = memoryCapability.updateMemoryUnit(chatSnapshot, "no summary, due to exception");
MemorySlice newSlice = memoryUnit.getSlices().getLast();
return new RollingRecord(memoryUnit.getId(), newSlice.getId(), newSlice.getSummary());
});
}
@Override

View File

@@ -1,13 +1,14 @@
package work.slhaf.partner.module.memory.updater.summarizer;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
import work.slhaf.partner.framework.agent.model.ActivateModel;
import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.support.Result;
import work.slhaf.partner.module.memory.runtime.MemoryRuntime;
import work.slhaf.partner.module.memory.updater.summarizer.entity.SummarizeInput;
import work.slhaf.partner.module.memory.updater.summarizer.entity.SummarizeResult;
@@ -17,25 +18,22 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class MultiSummarizer extends AbstractAgentModule.Sub<SummarizeInput, SummarizeResult> implements ActivateModel {
public class MultiSummarizer extends AbstractAgentModule.Sub<SummarizeInput, Result<SummarizeResult>> implements ActivateModel {
@InjectModule
private MemoryRuntime memoryRuntime;
@Override
public SummarizeResult execute(SummarizeInput input) {
log.debug("[MemorySummarizer] 整体摘要开始...");
SummarizeResult result = formattedChat(
public @NotNull Result<SummarizeResult> execute(SummarizeInput input) {
return formattedChat(
List.of(new Message(Message.Character.USER, JSONUtil.toJsonPrettyStr(input))),
SummarizeResult.class
).getOrThrow();
log.debug("[MemorySummarizer] 整体摘要结果: {}", JSONObject.toJSONString(result));
return fix(result);
).onSuccess(this::fix);
}
private SummarizeResult fix(SummarizeResult result) {
private void fix(SummarizeResult result) {
if (result == null || result.getTopicPath() == null || result.getTopicPath().isEmpty()) {
return result;
return;
}
String topicPath = memoryRuntime.fixTopicPath(result.getTopicPath());
List<String> relatedTopicPath = new ArrayList<>();
@@ -44,9 +42,9 @@ public class MultiSummarizer extends AbstractAgentModule.Sub<SummarizeInput, Sum
}
result.setTopicPath(topicPath);
result.setRelatedTopicPath(relatedTopicPath);
return result;
}
@NotNull
@Override
public String modelKey() {
return "multi_summarizer";

View File

@@ -1,10 +1,10 @@
package work.slhaf.partner.module.memory.updater.summarizer;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.core.action.ActionCapability;
import work.slhaf.partner.core.action.ActionCore;
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -41,7 +41,10 @@ public class SingleSummarizer extends AbstractAgentModule.Sub<List<Message>, Voi
int index = i;
executor.execute(() -> {
try {
String summarized = singleExecute(JSONObject.of("content", content).toString());
String summarized = chat(List.of(new Message(Message.Character.USER, content))).onFailure(ExceptionReporterHandler.INSTANCE::report).fold(
res -> res,
exp -> content
);
chatMessages.set(index, new Message(Message.Character.ASSISTANT, summarized));
} finally {
latch.countDown();
@@ -59,12 +62,7 @@ public class SingleSummarizer extends AbstractAgentModule.Sub<List<Message>, Voi
}
private String singleExecute(String primaryContent) {
try {
return chat(List.of(new Message(Message.Character.USER, primaryContent))).getOrThrow();
} catch (Exception e) {
log.error("[SingleSummarizer] 单消息总结出错: ", e);
return primaryContent;
}
return chat(List.of(new Message(Message.Character.USER, primaryContent))).getOrThrow();
}
@Override

View File

@@ -77,7 +77,7 @@ class MemoryCoreTest {
assertEquals("second-summary", appendedSlice.getSummary());
assertTrue(appendedSlice.getTimestamp() > 0);
MemorySlice loadedSlice = memoryCore.getMemorySlice(sessionId, appendedSlice.getId());
MemorySlice loadedSlice = memoryCore.getMemorySlice(sessionId, appendedSlice.getId()).getOrThrow();
assertNotNull(loadedSlice);
assertEquals(1, loadedSlice.getStartIndex());
assertEquals(3, loadedSlice.getEndIndex());

View File

@@ -12,6 +12,8 @@ import work.slhaf.partner.core.memory.pojo.MemorySlice;
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
import work.slhaf.partner.core.memory.pojo.SliceRef;
import work.slhaf.partner.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.support.Result;
import work.slhaf.partner.module.memory.runtime.exception.MemoryLookupException;
import work.slhaf.partner.module.memory.selector.ActivatedMemorySlice;
import java.lang.reflect.Field;
@@ -26,8 +28,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
class MemoryRuntimeTest {
@@ -204,6 +205,27 @@ class MemoryRuntimeTest {
assertEquals("second", dateResult.getFirst().getSummary());
}
@Test
void shouldThrowMemoryLookupExceptionWhenTopicOrDateIndexDoesNotExist() throws Exception {
StubMemoryCapability memoryCapability = new StubMemoryCapability("session-test");
MemoryRuntime runtime = new MemoryRuntime();
setField(runtime, "memoryCapability", memoryCapability);
setField(runtime, "cognitionCapability", stubCognitionCapability(List.of(message("seed"))));
MemoryLookupException topicException = assertThrows(
MemoryLookupException.class,
() -> runtime.queryActivatedMemoryByTopicPath("topic/missing")
);
assertEquals("不存在的主题: topic/missing", topicException.getMessage());
MemoryLookupException dateException = assertThrows(
MemoryLookupException.class,
() -> runtime.queryActivatedMemoryByDate(LocalDate.parse("1970-01-01"))
);
assertEquals("不存在的日期索引: 1970-01-01", dateException.getMessage());
assertInstanceOf(MemoryLookupException.class, dateException);
}
private static final class StubMemoryCapability implements MemoryCapability {
private final String sessionId;
private final Map<String, MemoryUnit> units = new HashMap<>();
@@ -222,15 +244,24 @@ class MemoryRuntimeTest {
}
@Override
public MemorySlice getMemorySlice(String unitId, String sliceId) {
public Result<MemorySlice> getMemorySlice(String unitId, String sliceId) {
MemoryUnit unit = units.get(unitId);
if (unit == null || unit.getSlices() == null) {
return null;
return Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
));
}
return unit.getSlices().stream()
.filter(slice -> sliceId.equals(slice.getId()))
.findFirst()
.orElse(null);
.map(Result::success)
.orElseGet(() -> Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
)));
}
@Override

View File

@@ -8,7 +8,9 @@ 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.framework.agent.model.pojo.Message;
import work.slhaf.partner.framework.agent.support.Result;
import work.slhaf.partner.module.memory.runtime.MemoryRuntime;
import work.slhaf.partner.module.memory.runtime.exception.MemoryLookupException;
import work.slhaf.partner.module.memory.updater.summarizer.MultiSummarizer;
import work.slhaf.partner.module.memory.updater.summarizer.SingleSummarizer;
import work.slhaf.partner.module.memory.updater.summarizer.entity.SummarizeResult;
@@ -84,9 +86,9 @@ class MemoryUpdaterTest {
setField(updater, "singleSummarizer", singleSummarizer);
when(memoryRuntime.getTopicTree()).thenReturn("topic-tree");
when(multiSummarizer.execute(Mockito.any())).thenReturn(
when(multiSummarizer.execute(Mockito.any())).thenReturn(Result.success(
summarizeResult("new-summary", "topic/main", List.of("topic/related"))
);
));
MemoryUnit existingUnit = new MemoryUnit("session-1");
existingUnit.getConversationMessages().addAll(List.of(
@@ -134,9 +136,9 @@ class MemoryUpdaterTest {
setField(updater, "singleSummarizer", singleSummarizer);
when(memoryRuntime.getTopicTree()).thenReturn("topic-tree");
when(multiSummarizer.execute(Mockito.any())).thenReturn(
when(multiSummarizer.execute(Mockito.any())).thenReturn(Result.success(
summarizeResult("fresh-summary", "topic/root", List.of())
);
));
Object rollingRecord = invokeUpdateMemory(updater, List.of(
message(Message.Character.USER, "first"),
@@ -258,15 +260,24 @@ class MemoryUpdaterTest {
}
@Override
public MemorySlice getMemorySlice(String unitId, String sliceId) {
public Result<MemorySlice> getMemorySlice(String unitId, String sliceId) {
MemoryUnit unit = units.get(unitId);
if (unit == null || unit.getSlices() == null) {
return null;
return Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
));
}
return unit.getSlices().stream()
.filter(slice -> sliceId.equals(slice.getId()))
.findFirst()
.orElse(null);
.map(Result::success)
.orElseGet(() -> Result.failure(new MemoryLookupException(
"Memory slice not found: " + unitId + ":" + sliceId,
unitId + ":" + sliceId,
"MEMORY_SLICE"
)));
}
@Override