refactor(framework): centralize model exception reporting in ActivateModel and remove duplicated module-level handlers

This commit is contained in:
2026-04-12 22:15:08 +08:00
parent 93304878ad
commit d30e58ff83
10 changed files with 31 additions and 41 deletions

View File

@@ -8,7 +8,6 @@ import work.slhaf.partner.core.action.entity.*;
import work.slhaf.partner.core.action.runner.RunnerClient; import work.slhaf.partner.core.action.runner.RunnerClient;
import work.slhaf.partner.core.cognition.CognitionCapability; import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.framework.agent.exception.AgentRuntimeException; import work.slhaf.partner.framework.agent.exception.AgentRuntimeException;
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.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init; import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -227,7 +226,6 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
if (shouldRunCorrector) { if (shouldRunCorrector) {
val correctorInput = assemblyHelper.buildCorrectorInput(executableAction); val correctorInput = assemblyHelper.buildCorrectorInput(executableAction);
actionCorrector.execute(correctorInput) actionCorrector.execute(correctorInput)
.onFailure(ExceptionReporterHandler.INSTANCE::report)
.onSuccess(correctorResult -> { .onSuccess(correctorResult -> {
actionCapability.handleInterventions(correctorResult.getMetaInterventionList(), executableAction); actionCapability.handleInterventions(correctorResult.getMetaInterventionList(), executableAction);
blockManager.emitActionCorrectionBlock( blockManager.emitActionCorrectionBlock(
@@ -313,8 +311,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
val executingStage = actionData.getExecutingStage(); val executingStage = actionData.getExecutingStage();
Result<ExtractorInput> extractorInputResult = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription()) Result<ExtractorInput> extractorInputResult = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription());
.onFailure(ExceptionReporterHandler.INSTANCE::report);
AgentRuntimeException exception = extractorInputResult.exceptionOrNull(); AgentRuntimeException exception = extractorInputResult.exceptionOrNull();
if (exception != null) { if (exception != null) {
failureReason.set(exception.getMessage()); failureReason.set(exception.getMessage());
@@ -323,7 +320,6 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
ExtractorInput extractorInput = extractorInputResult.getOrThrow(); ExtractorInput extractorInput = extractorInputResult.getOrThrow();
Result<ExtractorResult> extractorResultWrapped = paramsExtractor.execute(extractorInput).onFailure(exp -> { Result<ExtractorResult> extractorResultWrapped = paramsExtractor.execute(extractorInput).onFailure(exp -> {
ExceptionReporterHandler.INSTANCE.report(exp);
failureReason.set(exp.getLocalizedMessage()); failureReason.set(exp.getLocalizedMessage());
}); });
if (extractorResultWrapped.exceptionOrNull() != null) { if (extractorResultWrapped.exceptionOrNull() != null) {
@@ -373,7 +369,6 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
return () -> { return () -> {
try { try {
return actionCorrectionRecognizer.execute(input) return actionCorrectionRecognizer.execute(input)
.onFailure(ExceptionReporterHandler.INSTANCE::report)
.getOrDefault(new CorrectionRecognizerResult()); .getOrDefault(new CorrectionRecognizerResult());
} finally { } finally {
phaser.arriveAndDeregister(); phaser.arriveAndDeregister();
@@ -515,7 +510,6 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
private String resolveHistoryDescription(String actionKey) { private String resolveHistoryDescription(String actionKey) {
return actionCapability.loadMetaActionInfo(actionKey) return actionCapability.loadMetaActionInfo(actionKey)
.onFailure(ExceptionReporterHandler.INSTANCE::report)
.fold( .fold(
metaActionInfo -> metaActionInfo.getDescription().isBlank() ? actionKey : metaActionInfo.getDescription(), metaActionInfo -> metaActionInfo.getDescription().isBlank() ? actionKey : metaActionInfo.getDescription(),
exception -> actionKey exception -> actionKey

View File

@@ -390,7 +390,6 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
for (String actionKey : entry.getValue()) { for (String actionKey : entry.getValue()) {
Result<MetaAction> metaActionResult = actionCapability.loadMetaAction(actionKey); Result<MetaAction> metaActionResult = actionCapability.loadMetaAction(actionKey);
AgentRuntimeException failure = metaActionResult.onSuccess(metaActions::add) AgentRuntimeException failure = metaActionResult.onSuccess(metaActions::add)
.onFailure(ExceptionReporterHandler.INSTANCE::report)
.exceptionOrNull(); .exceptionOrNull();
if (failure != null) { if (failure != null) {
return null; return null;
@@ -415,8 +414,7 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
for (String actionKey : actionKeys) { for (String actionKey : actionKeys) {
// 根据 actionKey 加载行动信息,并检查是否存在必需前置依赖 // 根据 actionKey 加载行动信息,并检查是否存在必需前置依赖
Result<MetaActionInfo> infoResult = actionCapability.loadMetaActionInfo(actionKey) Result<MetaActionInfo> infoResult = actionCapability.loadMetaActionInfo(actionKey);
.onFailure(ExceptionReporterHandler.INSTANCE::report);
if (infoResult.exceptionOrNull() != null) { if (infoResult.exceptionOrNull() != null) {
return false; return false;
} }

View File

@@ -10,7 +10,6 @@ import work.slhaf.partner.core.cognition.BlockContent;
import work.slhaf.partner.core.cognition.CognitionCapability; import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.core.cognition.ContextBlock; import work.slhaf.partner.core.cognition.ContextBlock;
import work.slhaf.partner.core.cognition.ResolvedContext; import work.slhaf.partner.core.cognition.ResolvedContext;
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.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init; import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -67,7 +66,7 @@ public class ActionEvaluator extends AbstractAgentModule.Sub<EvaluatorInput, Lis
messages, messages,
EvaluatorResult.class EvaluatorResult.class
); );
result.onFailure(ExceptionReporterHandler.INSTANCE::report).onSuccess(evaluatorResult -> { result.onSuccess(evaluatorResult -> {
evaluatorResult.setTendency(tendency); evaluatorResult.setTendency(tendency);
synchronized (evaluatorResults) { synchronized (evaluatorResults) {
evaluatorResults.add(evaluatorResult); evaluatorResults.add(evaluatorResult);

View File

@@ -3,6 +3,8 @@ package work.slhaf.partner.module.action.planner.extractor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import work.slhaf.partner.core.cognition.CognitionCapability; import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.core.cognition.ContextBlock; import work.slhaf.partner.core.cognition.ContextBlock;
import work.slhaf.partner.framework.agent.exception.AgentRuntimeException;
import work.slhaf.partner.framework.agent.exception.ModuleExecutionException;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability; 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.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.model.ActivateModel; import work.slhaf.partner.framework.agent.model.ActivateModel;
@@ -26,8 +28,15 @@ public class ActionExtractor extends AbstractAgentModule.Sub<String, Result<Extr
)).encodeToMessage(), )).encodeToMessage(),
new Message(Message.Character.USER, input) new Message(Message.Character.USER, input)
); );
return formattedChat(messages, ExtractorResult.class); try {
return Result.success(formattedChat(messages, ExtractorResult.class).getOrThrow());
} catch (AgentRuntimeException e) {
return Result.failure(new ModuleExecutionException(
"collecting action tendencies failed",
this.getClass(),
getModuleName()
));
}
} }
@NotNull @NotNull

View File

@@ -6,7 +6,6 @@ import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import work.slhaf.partner.core.cognition.*; import work.slhaf.partner.core.cognition.*;
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.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init; import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -69,7 +68,6 @@ public class CommunicationProducer extends AbstractAgentModule.Running<PartnerRu
StreamChatMessageConsumer consumer = ReplyDispatcher.INSTANCE.createConsumer(runningFlowContext.getTarget()); StreamChatMessageConsumer consumer = ReplyDispatcher.INSTANCE.createConsumer(runningFlowContext.getTarget());
this.streamChat(buildChatMessages(runningFlowContext), consumer) this.streamChat(buildChatMessages(runningFlowContext), consumer)
.onFailure(exception -> { .onFailure(exception -> {
ExceptionReporterHandler.INSTANCE.report(exception);
consumer.onDelta(INTERRUPTED_MARKER); consumer.onDelta(INTERRUPTED_MARKER);
}); });
updateChatMessages(runningFlowContext, consumer.collectResponse()); updateChatMessages(runningFlowContext, consumer.collectResponse());

View File

@@ -46,7 +46,6 @@ public class SliceSelectEvaluator extends AbstractAgentModule.Sub<EvaluatorInput
@Override @Override
public List<ActivatedMemorySlice> execute(EvaluatorInput evaluatorInput) { public List<ActivatedMemorySlice> execute(EvaluatorInput evaluatorInput) {
log.debug("切片评估模块开始...");
List<ActivatedMemorySlice> preparedSlices = evaluatorInput.getMemorySlices(); List<ActivatedMemorySlice> preparedSlices = evaluatorInput.getMemorySlices();
List<ActivatedMemorySlice> result = new ArrayList<>(); List<ActivatedMemorySlice> result = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(preparedSlices.size()); CountDownLatch latch = new CountDownLatch(preparedSlices.size());
@@ -65,7 +64,6 @@ public class SliceSelectEvaluator extends AbstractAgentModule.Sub<EvaluatorInput
resolveTaskMessage(batchInput) resolveTaskMessage(batchInput)
); );
formattedChat(messages, EvaluatorBatchResult.class) formattedChat(messages, EvaluatorBatchResult.class)
.onFailure(exception -> log.debug("切片评估失败,已跳过当前切片", exception))
.onSuccess(evaluatorBatchResult -> { .onSuccess(evaluatorBatchResult -> {
if (evaluatorBatchResult.isPassed()) { if (evaluatorBatchResult.isPassed()) {
synchronized (result) { synchronized (result) {
@@ -83,7 +81,6 @@ public class SliceSelectEvaluator extends AbstractAgentModule.Sub<EvaluatorInput
latch.await(); latch.await();
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
} }
log.debug("切片评估模块结束...");
return result; return result;
} }

View File

@@ -8,7 +8,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import work.slhaf.partner.core.cognition.CognitionCapability; import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.core.cognition.ContextBlock; 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.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; 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.factory.component.annotation.InjectModule;
@@ -34,7 +33,6 @@ public class MemorySelectExtractor extends AbstractAgentModule.Sub<ExtractorInpu
@Override @Override
public ExtractorResult execute(ExtractorInput input) { public ExtractorResult execute(ExtractorInput input) {
log.debug("[MemorySelectExtractor] 主题提取模块开始...");
ExtractorResult extractorResult; ExtractorResult extractorResult;
List<Message> messages = List.of( List<Message> messages = List.of(
resolveContextMessage(), resolveContextMessage(),
@@ -44,7 +42,7 @@ public class MemorySelectExtractor extends AbstractAgentModule.Sub<ExtractorInpu
messages, messages,
ExtractorResult.class ExtractorResult.class
); );
extractorResult = result.onFailure(ExceptionReporterHandler.INSTANCE::report).fold( extractorResult = result.fold(
value -> value, value -> value,
exception -> { exception -> {
ExtractorResult fallback = new ExtractorResult(); ExtractorResult fallback = new ExtractorResult();

View File

@@ -4,7 +4,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import work.slhaf.partner.core.action.ActionCapability; import work.slhaf.partner.core.action.ActionCapability;
import work.slhaf.partner.core.action.ActionCore; 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.capability.annotation.InjectCapability;
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init; import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
@@ -41,7 +40,7 @@ public class SingleSummarizer extends AbstractAgentModule.Sub<List<Message>, Voi
int index = i; int index = i;
executor.execute(() -> { executor.execute(() -> {
try { try {
String summarized = chat(List.of(new Message(Message.Character.USER, content))).onFailure(ExceptionReporterHandler.INSTANCE::report).fold( String summarized = chat(List.of(new Message(Message.Character.USER, content))).fold(
res -> res, res -> res,
exp -> content exp -> content
); );

View File

@@ -28,7 +28,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MemoryRuntimeTest { class MemoryRuntimeTest {
@@ -206,24 +207,14 @@ class MemoryRuntimeTest {
} }
@Test @Test
void shouldThrowMemoryLookupExceptionWhenTopicOrDateIndexDoesNotExist() throws Exception { void shouldReturnEmptyActivatedMemoryWhenTopicOrDateIndexDoesNotExist() throws Exception {
StubMemoryCapability memoryCapability = new StubMemoryCapability("session-test"); StubMemoryCapability memoryCapability = new StubMemoryCapability("session-test");
MemoryRuntime runtime = new MemoryRuntime(); MemoryRuntime runtime = new MemoryRuntime();
setField(runtime, "memoryCapability", memoryCapability); setField(runtime, "memoryCapability", memoryCapability);
setField(runtime, "cognitionCapability", stubCognitionCapability(List.of(message("seed")))); setField(runtime, "cognitionCapability", stubCognitionCapability(List.of(message("seed"))));
MemoryLookupException topicException = assertThrows( assertTrue(runtime.queryActivatedMemoryByTopicPath("topic/missing").isEmpty());
MemoryLookupException.class, assertTrue(runtime.queryActivatedMemoryByDate(LocalDate.parse("1970-01-01")).isEmpty());
() -> 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 static final class StubMemoryCapability implements MemoryCapability {

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.framework.agent.model package work.slhaf.partner.framework.agent.model
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule
import work.slhaf.partner.framework.agent.model.pojo.Message import work.slhaf.partner.framework.agent.model.pojo.Message
import work.slhaf.partner.framework.agent.support.Result import work.slhaf.partner.framework.agent.support.Result
@@ -7,18 +8,24 @@ import work.slhaf.partner.framework.agent.support.Result
interface ActivateModel { interface ActivateModel {
fun chat(messages: List<Message>): Result<String> { fun chat(messages: List<Message>): Result<String> {
return ModelRuntimeRegistry.resolveProvider(modelKey()).chat(mergeMessages(messages)) return ModelRuntimeRegistry.resolveProvider(modelKey())
.chat(mergeMessages(messages))
.onFailure { ExceptionReporterHandler.report(it) }
} }
fun streamChat( fun streamChat(
messages: List<Message>, messages: List<Message>,
handler: StreamChatMessageConsumer handler: StreamChatMessageConsumer
): Result<Unit> { ): Result<Unit> {
return ModelRuntimeRegistry.resolveProvider(modelKey()).streamChat(mergeMessages(messages), handler) return ModelRuntimeRegistry.resolveProvider(modelKey())
.streamChat(mergeMessages(messages), handler)
.onFailure { ExceptionReporterHandler.report(it) }
} }
fun <T : Any> formattedChat(messages: List<Message>, responseType: Class<T>): Result<T> { fun <T : Any> formattedChat(messages: List<Message>, responseType: Class<T>): Result<T> {
return ModelRuntimeRegistry.resolveProvider(modelKey()).formattedChat(mergeMessages(messages), responseType) return ModelRuntimeRegistry.resolveProvider(modelKey())
.formattedChat(mergeMessages(messages), responseType)
.onFailure { ExceptionReporterHandler.report(it) }
} }
fun mergeMessages(messages: List<Message>): List<Message> { fun mergeMessages(messages: List<Message>): List<Message> {