Partner 主体与框架适配完成! 完整逻辑已达到适配框架之前的完成度。发现并修复了不少问题,以及更新了README

框架:
- 由于`Gateway`的启动属于`Agent`启动流程的子线程,而主线程可能由于逻辑执行结束时机早于`Gateway`创建完成时机而报错,故引入`CountDownLatch`进行阻塞
- 在`AgentRunningModule`与`AgentRunningSubModule`中添加日志hook,记录模块执行的起始与截止时机
- 修复了`AgentUtil`中收集继承链时遗忘起始类的错误
- 在`CapabilityCheckFactory`中针对`CoordinateManager`无参构造方法的实现检验
- 在`CapabilityRegisterFactory`中添加了收集模块之外的CapabilityHolder的逻辑,与`@InjectCapability`的校验与注入逻辑保持一致
- 修复了‘生成模块启用配置时,多余局部变量导致无法执行流正确读取启用情况’的错误
- 在GlobalExceptionHandler中添加了对于未知异常的处理逻辑,确保不会导致程序异常终止
- 发现`ModuleProxyFactory`中使用`record`类型会导致`ByteBuddy`无法正确创建代理类,已修复,替换成普通类

本体:
- `ActiveData`由于`CognationCore`的引用,也需要实现序列化,已修复
- 修复了`MemorySelectExtractor`中由于匹配到的主题列表为空导致的空指针异常
- 将后置模块的trigger判定抽取到新的父类中,统一判断
- 修复了`WebSocketServer`如果存在过ws连接,关闭后短时间再次启动内仍提示端口占用的情况,设置允许端口重用
- 在`WebSocketGateway`新增了断开ws客户端连接的逻辑
This commit is contained in:
2025-09-30 15:46:05 +08:00
parent a7d54349e4
commit 941943f696
32 changed files with 271 additions and 105 deletions

1
.gitignore vendored
View File

@@ -53,3 +53,4 @@ build/
/CLAUDE.md /CLAUDE.md
/config/ /config/
/data/ /data/
/generated-classes/

11
.idea/misc.xml generated
View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<list size="13"> <list size="14">
<item index="0" class="java.lang.String" itemvalue="lombok.Data" /> <item index="0" class="java.lang.String" itemvalue="lombok.Data" />
<item index="1" class="java.lang.String" itemvalue="net.bytebuddy.implementation.bind.annotation.RuntimeType" /> <item index="1" class="java.lang.String" itemvalue="net.bytebuddy.implementation.bind.annotation.RuntimeType" />
<item index="2" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Capability" /> <item index="2" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Capability" />
@@ -11,10 +11,11 @@
<item index="6" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Coordinated" /> <item index="6" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.capability.annotation.Coordinated" />
<item index="7" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute" /> <item index="7" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute" />
<item index="8" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentModule" /> <item index="8" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.AgentModule" />
<item index="9" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.Init" /> <item index="9" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute" />
<item index="10" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" /> <item index="10" class="java.lang.String" itemvalue="work.slhaf.partner.api.agent.factory.module.annotation.Init" />
<item index="11" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" /> <item index="11" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" />
<item index="12" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" /> <item index="12" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CoordinateManager" />
<item index="13" class="java.lang.String" itemvalue="work.slhaf.partner.api.register.capability.annotation.Capability" />
</list> </list>
</component> </component>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.api.agent; package work.slhaf.partner.api.agent;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.AgentRegisterFactory; import work.slhaf.partner.api.agent.factory.AgentRegisterFactory;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager; import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.exception.AgentExceptionCallback; import work.slhaf.partner.api.agent.runtime.exception.AgentExceptionCallback;
@@ -9,6 +10,7 @@ import work.slhaf.partner.api.agent.runtime.interaction.AgentGateway;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@@ -16,6 +18,7 @@ import java.util.concurrent.Executors;
* <h2>Agent 启动入口</h2> * <h2>Agent 启动入口</h2>
* 详细启动流程请参阅{@link AgentRegisterFactory} * 详细启动流程请参阅{@link AgentRegisterFactory}
*/ */
@Slf4j
public final class Agent { public final class Agent {
public static AgentConfigManagerStep newAgent(Class<?> clazz) { public static AgentConfigManagerStep newAgent(Class<?> clazz) {
@@ -59,6 +62,8 @@ public final class Agent {
private Class<? extends AgentGateway> gatewayClass; private Class<? extends AgentGateway> gatewayClass;
private Class<? extends AgentExceptionCallback> agentExceptionCallbackClass; private Class<? extends AgentExceptionCallback> agentExceptionCallbackClass;
private final CountDownLatch latch = new CountDownLatch(1);
private AgentApp(Class<?> clazz) { private AgentApp(Class<?> clazz) {
this.applicationClass = clazz; this.applicationClass = clazz;
} }
@@ -115,9 +120,15 @@ public final class Agent {
private void afterLaunch() { private void afterLaunch() {
try { try {
this.gateway = gatewayClass.getDeclaredConstructor().newInstance(); this.gateway = gatewayClass.getDeclaredConstructor().newInstance();
executorService.execute(() -> gateway.launch()); executorService.execute(() -> {
gateway.launch();
latch.countDown();
log.info("Gateway 启动完毕: {}", gatewayClass.getSimpleName());
});
latch.await();
launchRunners(afterLaunchRunners); launchRunners(afterLaunchRunners);
}catch (Exception e){ log.info("后置任务启动完毕");
} catch (Exception e) {
throw new AgentLaunchFailedException("Agent 后置任务启动失败", e); throw new AgentLaunchFailedException("Agent 后置任务启动失败", e);
} }
} }
@@ -125,8 +136,11 @@ public final class Agent {
private void beforeLaunch() { private void beforeLaunch() {
try { try {
AgentConfigManager.setINSTANCE(agentConfigManagerClass.getDeclaredConstructor().newInstance()); AgentConfigManager.setINSTANCE(agentConfigManagerClass.getDeclaredConstructor().newInstance());
log.info("配置管理器设置完毕: {}",agentConfigManagerClass.getSimpleName());
GlobalExceptionHandler.setExceptionCallback(agentExceptionCallbackClass.getDeclaredConstructor().newInstance()); GlobalExceptionHandler.setExceptionCallback(agentExceptionCallbackClass.getDeclaredConstructor().newInstance());
log.info("异常处理回调设置完毕: {}",agentExceptionCallbackClass.getSimpleName());
launchRunners(beforeLaunchRunners); launchRunners(beforeLaunchRunners);
log.info("前置任务启动完毕");
} catch (Exception e) { } catch (Exception e) {
throw new AgentLaunchFailedException("Agent 前置任务启动失败", e); throw new AgentLaunchFailedException("Agent 前置任务启动失败", e);
} }

View File

@@ -1,12 +1,10 @@
package work.slhaf.partner.api.agent.factory.capability; package work.slhaf.partner.api.agent.factory.capability;
import cn.hutool.core.util.ClassUtil;
import org.reflections.Reflections; import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory; import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.capability.annotation.*; import work.slhaf.partner.api.agent.factory.capability.annotation.*;
import work.slhaf.partner.api.agent.factory.capability.exception.DuplicateCapabilityException; import work.slhaf.partner.api.agent.factory.capability.exception.*;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityException;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCapabilityMethodException;
import work.slhaf.partner.api.agent.factory.capability.exception.UnMatchedCoordinatedMethodException;
import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext; import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext; import work.slhaf.partner.api.agent.factory.context.CapabilityFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
@@ -67,14 +65,29 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
@Override @Override
protected void run() { protected void run() {
//TODO 对于CoordinateManager的所注类进行唯一性检验以及检测是否留有公开的无参构造方法
loadCoresAndCapabilities(); loadCoresAndCapabilities();
checkCountAndCapabilities(); checkCountAndCapabilities();
checkCapabilityMethods(); checkCapabilityMethods();
checkCoordinatedMethods(); checkCoordinatedMethods();
checkCoordinatedManager();
checkInjectCapability(); checkInjectCapability();
} }
private void checkCoordinatedManager() {
reflections.getTypesAnnotatedWith(CoordinateManager.class)
.stream()
.filter(ClassUtil::isNormalClass)
.forEach(managerClass -> {
try {
if (!managerClass.getDeclaredConstructor().canAccess(null)) {
throw new CapabilityCheckFailedException("CoordinateManager 所注类的无参构造方法未公开!");
}
} catch (NoSuchMethodException e) {
throw new CapabilityCheckFailedException("CoordinateManager 所注类缺少无参构造方法!");
}
});
}
private void loadCoresAndCapabilities() { private void loadCoresAndCapabilities() {
cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class)); cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class));
capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class)); capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class));
@@ -86,8 +99,8 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
private void checkInjectCapability() { private void checkInjectCapability() {
reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> { reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> {
Class<?> declaringClass = field.getDeclaringClass(); Class<?> declaringClass = field.getDeclaringClass();
if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)){ if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)) {
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: "+declaringClass); throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: " + declaringClass);
} }
}); });
} }

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.api.agent.factory.capability; package work.slhaf.partner.api.agent.factory.capability;
import cn.hutool.core.util.ClassUtil;
import org.reflections.Reflections; import org.reflections.Reflections;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory; import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.capability.annotation.*; import work.slhaf.partner.api.agent.factory.capability.annotation.*;
@@ -18,6 +19,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature; import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
@@ -79,10 +81,30 @@ public class CapabilityRegisterFactory extends AgentBaseFactory {
@Override @Override
protected void run() { protected void run() {
setCapabilityHolderInstances();
setCoreInstances(); setCoreInstances();
generateRouterTable(); generateRouterTable();
} }
private void setCapabilityHolderInstances() {
Set<Class<?>> collect = reflections.getTypesAnnotatedWith(CapabilityHolder.class).stream()
.filter(ClassUtil::isNormalClass)
.filter(clazz -> !capabilityHolderInstances.containsKey(clazz))
.collect(Collectors.toSet());
for (Class<?> clazz : collect) {
try {
Constructor<?> constructor = clazz.getDeclaredConstructor();
if (constructor.canAccess(null)) {
throw new CapabilityFactoryExecuteFailedException("缺少无参构造方法的类: " + clazz);
}
Object o = constructor.newInstance();
capabilityHolderInstances.put(clazz, o);
}catch (Exception e){
throw new CapabilityFactoryExecuteFailedException("创建代理对象失败: " + clazz, e);
}
}
}
/** /**
* 生成函数路由表 * 生成函数路由表
*/ */

View File

@@ -57,7 +57,7 @@ public class ConfigLoaderFactory extends AgentBaseFactory {
* 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词 * 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词
*/ */
private void check() { private void check() {
log.info("[ConfigLoaderFactory]: 执行config与prompt检测..."); log.info("执行config与prompt检测...");
if (!modelConfigMap.containsKey("default")) { if (!modelConfigMap.containsKey("default")) {
throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`"); throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`");
} }
@@ -72,7 +72,6 @@ public class ConfigLoaderFactory extends AgentBaseFactory {
log.warn("存在未被提示词包含的模型配置,该配置将无法生效!"); log.warn("存在未被提示词包含的模型配置,该配置将无法生效!");
} }
//检查提示词数量与`ActivateModel`的实现数量是否一致 //检查提示词数量与`ActivateModel`的实现数量是否一致
log.info("检测完毕.");
log.info("[ConfigLoaderFactory]: 检测完毕.");
} }
} }

View File

@@ -67,6 +67,8 @@ public class ModuleCheckFactory extends AgentBaseFactory {
moduleConstructorsCheck(annotatedModules.subModuleTypes()); moduleConstructorsCheck(annotatedModules.subModuleTypes());
//检查实现了ActivateModel的模块数量、名称与prompt是否一致 //检查实现了ActivateModel的模块数量、名称与prompt是否一致
activateModelImplCheck(); activateModelImplCheck();
//检查hook注解所在位置是否正确
hookLocationCheck();
} }
private ExtendedModules getExtendedModules() { private ExtendedModules getExtendedModules() {
@@ -128,17 +130,6 @@ public class ModuleCheckFactory extends AgentBaseFactory {
preHookLocationCheck(); preHookLocationCheck();
//检查@Init注解 //检查@Init注解
initHookLocationCheck(); initHookLocationCheck();
//检查@AgentModule注解是否只位于普通类上
agentModuleLocationCheck();
}
private void agentModuleLocationCheck() {
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
for (Class<?> type : types) {
if (!ClassUtil.isNormalClass(type)) {
throw new ModuleCheckException("AgentModule 注解仅能位于普通类上! 异常类信息: " + type.getSimpleName());
}
}
} }
private void initHookLocationCheck() { private void initHookLocationCheck() {

View File

@@ -11,6 +11,8 @@ import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module;
import work.slhaf.partner.api.agent.util.AgentUtil; import work.slhaf.partner.api.agent.util.AgentUtil;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -30,7 +32,7 @@ import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
* *
* <ol> * <ol>
* <li> * <li>
* <p>{@link ModuleInitHookExecuteFactory#collectInitHookMethods(Class)}</p> * <p>{@link ModuleInitHookExecuteFactory#collectInitHookMethods(Class, Class)}</p>
* 分别遍历前置模块拿到的模块列表({@link ModuleInitHookExecuteFactory#moduleList}, {@link ModuleInitHookExecuteFactory#subModuleList}),通过 {@link AgentUtil#collectExtendedClasses(Class, Class)} 收集到当前模块类的继承链上的所有类后,收集其所有带有 {@link Init} 注解的方法 * 分别遍历前置模块拿到的模块列表({@link ModuleInitHookExecuteFactory#moduleList}, {@link ModuleInitHookExecuteFactory#subModuleList}),通过 {@link AgentUtil#collectExtendedClasses(Class, Class)} 收集到当前模块类的继承链上的所有类后,收集其所有带有 {@link Init} 注解的方法
* </li> * </li>
* <li> * <li>
@@ -57,12 +59,12 @@ public class ModuleInitHookExecuteFactory extends AgentBaseFactory {
protected void run() { protected void run() {
//遍历模块列表,并向上查找@Init注解 //遍历模块列表,并向上查找@Init注解
for (MetaSubModule metaSubModule : subModuleList) { for (MetaSubModule metaSubModule : subModuleList) {
List<MetaMethod> initHookMethods = collectInitHookMethods(metaSubModule.getClazz()); List<MetaMethod> initHookMethods = collectInitHookMethods(metaSubModule.getClazz(),AgentRunningModule.class);
proceedInitMethods(metaSubModule, initHookMethods); proceedInitMethods(metaSubModule, initHookMethods);
} }
for (MetaModule metaModule : moduleList) { for (MetaModule metaModule : moduleList) {
List<MetaMethod> initHookMethods = collectInitHookMethods(metaModule.getClazz()); List<MetaMethod> initHookMethods = collectInitHookMethods(metaModule.getClazz(), AgentRunningSubModule.class);
proceedInitMethods(metaModule, initHookMethods); proceedInitMethods(metaModule, initHookMethods);
} }
} }
@@ -77,8 +79,8 @@ public class ModuleInitHookExecuteFactory extends AgentBaseFactory {
} }
} }
private List<MetaMethod> collectInitHookMethods(Class<?> clazz) { private List<MetaMethod> collectInitHookMethods(Class<?> clazz, Class<? extends Module> target) {
Set<Class<?>> classes = collectExtendedClasses(clazz, AgentRunningModule.class); Set<Class<?>> classes = collectExtendedClasses(clazz, target);
return classes.stream() return classes.stream()
.map(Class::getDeclaredMethods) .map(Class::getDeclaredMethods)
.flatMap(Arrays::stream) .flatMap(Arrays::stream)

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.api.agent.factory.module; package work.slhaf.partner.api.agent.factory.module;
import lombok.Getter;
import net.bytebuddy.ByteBuddy; import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*; import net.bytebuddy.implementation.bind.annotation.*;
@@ -14,11 +15,13 @@ import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleInstanceGenerateFailedException; import work.slhaf.partner.api.agent.factory.module.exception.ModuleInstanceGenerateFailedException;
import work.slhaf.partner.api.agent.factory.module.exception.ModuleProxyGenerateFailedException; import work.slhaf.partner.api.agent.factory.module.exception.ModuleProxyGenerateFailedException;
import work.slhaf.partner.api.agent.factory.module.exception.ProxiedModuleRunningException;
import work.slhaf.partner.api.agent.factory.module.pojo.BaseMetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.BaseMetaModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod; import work.slhaf.partner.api.agent.factory.module.pojo.MetaMethod;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule; import work.slhaf.partner.api.agent.factory.module.pojo.MetaSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.Module;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -74,7 +77,8 @@ public class ModuleProxyFactory extends AgentBaseFactory {
private void injectSubModule() { private void injectSubModule() {
for (MetaModule module : moduleList) { for (MetaModule module : moduleList) {
Arrays.stream(module.getClazz().getFields()) //因为实际上ByteBuddy生成的是module.getClazz()的子类所以应当使用getDeclaredFields()获取字段
Arrays.stream(module.getClazz().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(InjectModule.class)) .filter(field -> field.isAnnotationPresent(InjectModule.class))
.forEach(field -> { .forEach(field -> {
try { try {
@@ -92,15 +96,14 @@ public class ModuleProxyFactory extends AgentBaseFactory {
} }
private void createProxiedInstances() { private void createProxiedInstances() {
generateModuleProxy(moduleList); generateModuleProxy(moduleList, AgentRunningModule.class);
generateModuleProxy(subModuleList); generateModuleProxy(subModuleList, AgentRunningSubModule.class);
updateInstanceMap(moduleInstances, moduleList); updateInstanceMap(moduleInstances, moduleList);
updateInstanceMap(subModuleInstances, subModuleList); updateInstanceMap(subModuleInstances, subModuleList);
updateCapabilityHolderInstances(); updateCapabilityHolderInstances();
} }
private void updateCapabilityHolderInstances() { private void updateCapabilityHolderInstances() {
//TODO 扫描并添加所有与@CapabilityHolder相关的实例
capabilityHolderInstances.putAll(moduleInstances); capabilityHolderInstances.putAll(moduleInstances);
capabilityHolderInstances.putAll(subModuleInstances); capabilityHolderInstances.putAll(subModuleInstances);
} }
@@ -112,29 +115,38 @@ public class ModuleProxyFactory extends AgentBaseFactory {
} }
private void generateModuleProxy(List<? extends BaseMetaModule> list) { private void generateModuleProxy(List<? extends BaseMetaModule> list, Class<? extends Module> overrideSource) {
for (BaseMetaModule module : list) { for (BaseMetaModule module : list) {
Class<?> clazz = module.getClazz(); Class<?> clazz = module.getClazz();
try { try {
MethodsListRecord record = collectHookMethods(clazz); MethodsListRecord record = collectHookMethods(clazz);
//生成实例 //生成实例
generateProxiedInstances(record, module); generateProxiedInstances(record, module, overrideSource);
} catch (Exception e) { } catch (Exception e) {
throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e); throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e);
} }
} }
} }
private void generateProxiedInstances(MethodsListRecord record, BaseMetaModule module) { private void generateProxiedInstances(MethodsListRecord record, BaseMetaModule module, Class<? extends Module> overrideSource) {
try { try {
Class<? extends Module> clazz = module.getClazz(); Class<? extends Module> clazz = module.getClazz();
Class<? extends Module> proxyClass = new ByteBuddy() Class<? extends Module> proxyClass = new ByteBuddy()
.subclass(clazz) .subclass(clazz)
.method(ElementMatchers.isOverriddenFrom(AgentRunningModule.class)) .method(ElementMatchers.isOverriddenFrom(overrideSource))
.intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre))) .intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre)))
.make() .make()
.load(ModuleProxyFactory.class.getClassLoader()) .load(ModuleProxyFactory.class.getClassLoader())
.getLoaded(); .getLoaded();
// new ByteBuddy()
// .subclass(clazz)
// .method(ElementMatchers.isOverriddenFrom(overrideSource))
// .intercept(MethodDelegation.to(new ModuleProxyInterceptor(record.post, record.pre)))
//
// .make()
// .saveIn(new File("./generated-classes"));
module.setInstance(proxyClass.getConstructor().newInstance()); module.setInstance(proxyClass.getConstructor().newInstance());
} catch (Exception e) { } catch (Exception e) {
throw new ModuleProxyGenerateFailedException("模块Hook代理生成失败! 代理失败的模块名: " + module.getClazz().getSimpleName(), e); throw new ModuleProxyGenerateFailedException("模块Hook代理生成失败! 代理失败的模块名: " + module.getClazz().getSimpleName(), e);
@@ -188,7 +200,7 @@ public class ModuleProxyFactory extends AgentBaseFactory {
private void collectHookMethods(List<MetaMethod> post, List<MetaMethod> pre, Class<?> clazz) { private void collectHookMethods(List<MetaMethod> post, List<MetaMethod> pre, Class<?> clazz) {
Method[] methods = clazz.getMethods(); Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) { for (Method method : methods) {
if (method.isAnnotationPresent(BeforeExecute.class)) { if (method.isAnnotationPresent(BeforeExecute.class)) {
MetaMethod metaMethod = new MetaMethod(); MetaMethod metaMethod = new MetaMethod();
@@ -204,18 +216,38 @@ public class ModuleProxyFactory extends AgentBaseFactory {
} }
} }
public record ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) { @Getter
@SuppressWarnings("ClassCanBeRecord")
public static class ModuleProxyInterceptor {
private final List<MetaMethod> postHookMethods;
private final List<MetaMethod> preHookMethods;
public ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) {
this.postHookMethods = postHookMethods;
this.preHookMethods = preHookMethods;
}
@RuntimeType @RuntimeType
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception { public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
for (MetaMethod metaMethod : preHookMethods) { executeHookMethods(preHookMethods, proxy);
metaMethod.getMethod().invoke(proxy);
}
Object res = zuper.call(); Object res = zuper.call();
for (MetaMethod metaMethod : postHookMethods) { executeHookMethods(postHookMethods, proxy);
metaMethod.getMethod().invoke(proxy);
}
return res; return res;
} }
private void executeHookMethods(List<MetaMethod> hookMethods, Object proxy) {
for (MetaMethod metaMethod : hookMethods) {
Method m = metaMethod.getMethod();
try {
m.setAccessible(true);
m.invoke(proxy);
} catch (Exception e) {
throw new ProxiedModuleRunningException("hook方法执行异常: " + m.getDeclaringClass() + "#" + m.getName(), e);
}
}
}
} }
record MethodsListRecord(List<MetaMethod> post, List<MetaMethod> pre) { record MethodsListRecord(List<MetaMethod> post, List<MetaMethod> pre) {

View File

@@ -3,10 +3,7 @@ package work.slhaf.partner.api.agent.factory.module.annotation;
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder; import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder;
import java.lang.annotation.ElementType; import java.lang.annotation.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 用于注解执行模块 * 用于注解执行模块
@@ -14,6 +11,7 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@CapabilityHolder @CapabilityHolder
@Inherited
public @interface AgentModule { public @interface AgentModule {
/** /**

View File

@@ -0,0 +1,13 @@
package work.slhaf.partner.api.agent.factory.module.exception;
import work.slhaf.partner.api.agent.runtime.exception.AgentRuntimeException;
public class ProxiedModuleRunningException extends AgentRuntimeException {
public ProxiedModuleRunningException(String message) {
super(message);
}
public ProxiedModuleRunningException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -3,7 +3,6 @@ package work.slhaf.partner.api.agent.runtime.config;
import lombok.Data; import lombok.Data;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigNotExistException;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigUpdateFailedException; import work.slhaf.partner.api.agent.factory.config.exception.ConfigUpdateFailedException;
import work.slhaf.partner.api.agent.factory.config.exception.PromptNotExistException; import work.slhaf.partner.api.agent.factory.config.exception.PromptNotExistException;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig; import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
@@ -11,9 +10,7 @@ import work.slhaf.partner.api.agent.factory.module.pojo.MetaModule;
import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
@Slf4j @Slf4j
@Data @Data

View File

@@ -77,7 +77,7 @@ public class FileAgentConfigManager extends AgentConfigManager {
protected HashMap<String, Boolean> loadModuleEnabledStatusMap() { protected HashMap<String, Boolean> loadModuleEnabledStatusMap() {
File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE); File file = new File(MODULE_ENABLED_STATUS_CONFIG_FILE);
try { try {
HashMap<String, Boolean> moduleEnabledStatus = new HashMap<>(); moduleEnabledStatus = new HashMap<>();
if (!file.exists()) { if (!file.exists()) {
file.createNewFile(); file.createNewFile();
for (MetaModule module : moduleList) { for (MetaModule module : moduleList) {

View File

@@ -1,5 +1,8 @@
package work.slhaf.partner.api.agent.runtime.exception; package work.slhaf.partner.api.agent.runtime.exception;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
public static GlobalExceptionHandler INSTANCE = new GlobalExceptionHandler(); public static GlobalExceptionHandler INSTANCE = new GlobalExceptionHandler();
@@ -16,7 +19,7 @@ public class GlobalExceptionHandler {
exceptionCallback.onFailedException((AgentLaunchFailedException) e); exceptionCallback.onFailedException((AgentLaunchFailedException) e);
break; break;
default: default:
throw new RuntimeException("经处理的异常!", e); log.error("知异常: ", e);
} }
} }

View File

@@ -2,7 +2,6 @@ package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig; import work.slhaf.partner.api.agent.factory.config.pojo.ModelConfig;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager; import work.slhaf.partner.api.agent.runtime.config.AgentConfigManager;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model; import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.Model;

View File

@@ -1,5 +1,10 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts; package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext; import work.slhaf.partner.api.agent.runtime.interaction.flow.entity.RunningFlowContext;
import java.io.IOException; import java.io.IOException;
@@ -7,6 +12,27 @@ import java.io.IOException;
/** /**
* 流程执行模块基类 * 流程执行模块基类
*/ */
@Slf4j
public abstract class AgentRunningModule<C extends RunningFlowContext> extends Module { public abstract class AgentRunningModule<C extends RunningFlowContext> extends Module {
public abstract void execute(C context) throws IOException, ClassNotFoundException; public abstract void execute(C context) throws IOException, ClassNotFoundException;
@BeforeExecute
private void beforeLog() {
log.debug("[{}] 模块执行开始...", getModuleName());
}
@AfterExecute
private void afterLog() {
log.debug("[{}] 模块执行结束...", getModuleName());
}
private String getModuleName(){
if (this.getClass().isAnnotationPresent(AgentModule.class)) {
return this.getClass().getAnnotation(AgentModule.class).name();
} else if (this.getClass().isAnnotationPresent(CoreModule.class)) {
return CoreModule.class.getAnnotation(AgentModule.class).name();
}else {
return "Unknown Module";
}
}
} }

View File

@@ -1,8 +1,35 @@
package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts; package work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.BeforeExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule;
@Slf4j
public abstract class AgentRunningSubModule<I, O> extends Module { public abstract class AgentRunningSubModule<I, O> extends Module {
public abstract O execute(I data); public abstract O execute(I data);
@BeforeExecute
private void beforeLog() {
log.debug("[{}] 模块执行开始...", getModuleName());
}
@AfterExecute
private void afterLog() {
log.debug("[{}] 模块执行结束...", getModuleName());
}
private String getModuleName(){
if (this.getClass().isAnnotationPresent(AgentModule.class)) {
return this.getClass().getAnnotation(AgentModule.class).name();
} else if (this.getClass().isAnnotationPresent(CoreModule.class)) {
return CoreModule.class.getAnnotation(AgentModule.class).name();
}else {
return "Unknown Module";
}
}
} }

View File

@@ -49,6 +49,7 @@ public final class AgentUtil {
public static Set<Class<?>> collectExtendedClasses(Class<?> clazz, Class<?> targetClass) { public static Set<Class<?>> collectExtendedClasses(Class<?> clazz, Class<?> targetClass) {
Set<Class<?>> classes = new HashSet<>(); Set<Class<?>> classes = new HashSet<>();
collectExtendedClasses(classes, clazz, targetClass); collectExtendedClasses(classes, clazz, targetClass);
classes.add(clazz);
return classes; return classes;
} }

View File

@@ -56,6 +56,7 @@ public class CognationCore extends PersistableObject {
} else { } else {
FileUtils.createParentDirectories(filePath.toFile().getParentFile()); FileUtils.createParentDirectories(filePath.toFile().getParentFile());
connectCores(this); connectCores(this);
this.activeData = new ActiveData();
this.serialize(); this.serialize();
} }
setupHook(this); setupHook(this);

View File

@@ -1,14 +1,21 @@
package work.slhaf.partner.core.cognation.pojo; package work.slhaf.partner.core.cognation.pojo;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.api.common.entity.PersistableObject;
import work.slhaf.partner.core.submodule.memory.pojo.EvaluatedSlice; import work.slhaf.partner.core.submodule.memory.pojo.EvaluatedSlice;
import java.io.Serial;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data @Data
public class ActiveData { public class ActiveData extends PersistableObject {
private HashMap<String, List<EvaluatedSlice>> activatedSlices; private HashMap<String, List<EvaluatedSlice>> activatedSlices = new HashMap<>();
@Serial
private static final long serialVersionUID = 1L;
public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) { public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) {
activatedSlices.put(userId, memorySlices); activatedSlices.put(userId, memorySlices);

View File

@@ -1,7 +0,0 @@
package work.slhaf.partner.module.common.module;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
public abstract class CoreRunningModule extends AgentRunningModule<PartnerRunningFlowContext> {
}

View File

@@ -3,5 +3,19 @@ package work.slhaf.partner.module.common.module;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
import java.io.IOException;
public abstract class PostRunningModule extends AgentRunningModule<PartnerRunningFlowContext> { public abstract class PostRunningModule extends AgentRunningModule<PartnerRunningFlowContext> {
@Override
public final void execute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException {
boolean trigger = context.getModuleContext().getExtraContext().getBoolean("post_process_trigger");
if (!trigger){
return;
}
doExecute(context);
}
protected void doExecute(PartnerRunningFlowContext context){}
} }

View File

@@ -1,7 +1,6 @@
package work.slhaf.partner.module.common.module; package work.slhaf.partner.module.common.module;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.module.common.entity.AppendPromptData; import work.slhaf.partner.module.common.entity.AppendPromptData;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
@@ -32,11 +31,9 @@ public abstract class PreRunningModule extends AgentRunningModule<PartnerRunning
@Override @Override
public final void execute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException { public final void execute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException {
log.debug("[{}] 模块执行开始...", this.getClass().getAnnotation(AgentModule.class).name());
doExecute(context); // 子类实现差异化逻辑 doExecute(context); // 子类实现差异化逻辑
setAppendedPrompt(context); // 通用逻辑 setAppendedPrompt(context); // 通用逻辑
setActiveModule(context); // 通用逻辑 setActiveModule(context); // 通用逻辑
log.debug("[{}] 模块执行结束...", this.getClass().getAnnotation(AgentModule.class).name());
} }
protected abstract void doExecute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException; protected abstract void doExecute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException;

View File

@@ -8,6 +8,7 @@ import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapabili
import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule; import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule;
import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.ActivateModel; import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.ActivateModel;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.api.chat.constant.ChatConstant; import work.slhaf.partner.api.chat.constant.ChatConstant;
import work.slhaf.partner.api.chat.pojo.ChatResponse; import work.slhaf.partner.api.chat.pojo.ChatResponse;
import work.slhaf.partner.api.chat.pojo.Message; import work.slhaf.partner.api.chat.pojo.Message;
@@ -15,7 +16,6 @@ import work.slhaf.partner.api.chat.pojo.MetaMessage;
import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.cognation.CognationCapability;
import work.slhaf.partner.module.common.entity.AppendPromptData; import work.slhaf.partner.module.common.entity.AppendPromptData;
import work.slhaf.partner.module.common.model.ModelConstant; import work.slhaf.partner.module.common.model.ModelConstant;
import work.slhaf.partner.module.common.module.CoreRunningModule;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
import work.slhaf.partner.runtime.session.SessionManager; import work.slhaf.partner.runtime.session.SessionManager;
@@ -30,7 +30,7 @@ import static work.slhaf.partner.common.util.ExtractUtil.extractJson;
@Data @Data
@Slf4j @Slf4j
@CoreModule @CoreModule
public class CoreModel extends CoreRunningModule implements ActivateModel { public class CoreModel extends AgentRunningModule<PartnerRunningFlowContext> implements ActivateModel {
@InjectCapability @InjectCapability
private CognationCapability cognationCapability; private CognationCapability cognationCapability;

View File

@@ -5,7 +5,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.module.annotation.AfterExecute;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule;
import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.cognation.CognationCapability;
@@ -59,6 +58,7 @@ public class MemorySelector extends PreRunningModule {
List<EvaluatedSlice> evaluatedSlices = selectAndEvaluateMemory(runningFlowContext, extractorResult); List<EvaluatedSlice> evaluatedSlices = selectAndEvaluateMemory(runningFlowContext, extractorResult);
cognationCapability.updateActivatedSlices(userId, evaluatedSlices); cognationCapability.updateActivatedSlices(userId, evaluatedSlices);
} }
setModuleContextRecall(runningFlowContext);
} }
private List<EvaluatedSlice> selectAndEvaluateMemory(PartnerRunningFlowContext runningFlowContext, ExtractorResult extractorResult) throws IOException, ClassNotFoundException { private List<EvaluatedSlice> selectAndEvaluateMemory(PartnerRunningFlowContext runningFlowContext, ExtractorResult extractorResult) throws IOException, ClassNotFoundException {
@@ -79,7 +79,6 @@ public class MemorySelector extends PreRunningModule {
return memorySlices; return memorySlices;
} }
@AfterExecute(order = 1)
private void setModuleContextRecall(PartnerRunningFlowContext runningFlowContext) { private void setModuleContextRecall(PartnerRunningFlowContext runningFlowContext) {
String userId = runningFlowContext.getUserId(); String userId = runningFlowContext.getUserId();
boolean recall = cognationCapability.hasActivatedSlices(userId); boolean recall = cognationCapability.hasActivatedSlices(userId);

View File

@@ -94,6 +94,9 @@ public class MemorySelectExtractor extends AgentRunningSubModule<PartnerRunningF
} }
m.setText(fixTopicPath(m.getText())); m.setText(fixTopicPath(m.getText()));
}); });
if (extractorResult.getMatches().isEmpty()) {
return extractorResult;
}
extractorResult.getMatches().removeIf(m -> m.getText().split("->")[0].isEmpty()); extractorResult.getMatches().removeIf(m -> m.getText().split("->")[0].isEmpty());
return extractorResult; return extractorResult;
} }

View File

@@ -96,7 +96,7 @@ public class MemoryUpdater extends PostRunningModule {
} }
@Override @Override
public void execute(PartnerRunningFlowContext context) { public void doExecute(PartnerRunningFlowContext context) {
if (context.isFinished()) { if (context.isFinished()) {
log.warn("[MemoryUpdater] 流程强制结束, 不触发记忆被动更新机制"); log.warn("[MemoryUpdater] 流程强制结束, 不触发记忆被动更新机制");
return; return;

View File

@@ -7,17 +7,16 @@ import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapabili
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule; import work.slhaf.partner.api.agent.factory.module.annotation.InjectModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor; import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor;
import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.cognation.CognationCapability;
import work.slhaf.partner.core.submodule.perceive.PerceiveCapability; import work.slhaf.partner.core.submodule.perceive.PerceiveCapability;
import work.slhaf.partner.core.submodule.perceive.pojo.User; import work.slhaf.partner.core.submodule.perceive.pojo.User;
import work.slhaf.partner.module.common.module.PostRunningModule;
import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.RelationExtractor; import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.RelationExtractor;
import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.pojo.RelationExtractResult; import work.slhaf.partner.module.modules.perceive.updater.relation_extractor.pojo.RelationExtractResult;
import work.slhaf.partner.module.modules.perceive.updater.static_extractor.StaticMemoryExtractor; import work.slhaf.partner.module.modules.perceive.updater.static_extractor.StaticMemoryExtractor;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -31,7 +30,7 @@ import java.util.concurrent.locks.ReentrantLock;
@Slf4j @Slf4j
@Data @Data
@AgentModule(name = "perceive_updater", order = 8) @AgentModule(name = "perceive_updater", order = 8)
public class PerceiveUpdater extends AgentRunningModule<PartnerRunningFlowContext> { public class PerceiveUpdater extends PostRunningModule {
private static volatile PerceiveUpdater perceiveUpdater; private static volatile PerceiveUpdater perceiveUpdater;
@@ -53,12 +52,9 @@ public class PerceiveUpdater extends AgentRunningModule<PartnerRunningFlowContex
this.executor = InteractionThreadPoolExecutor.getInstance(); this.executor = InteractionThreadPoolExecutor.getInstance();
} }
public void execute(PartnerRunningFlowContext context) throws IOException, ClassNotFoundException { @Override
public void doExecute(PartnerRunningFlowContext context) {
executor.execute(() -> { executor.execute(() -> {
boolean trigger = context.getModuleContext().getExtraContext().getBoolean("perceive_updater");
if (!trigger){
return;
}
ReentrantLock userLock = new ReentrantLock(); ReentrantLock userLock = new ReentrantLock();
User user = new User(); User user = new User();
user.setUuid(context.getUserId()); user.setUuid(context.getUserId());

View File

@@ -5,8 +5,8 @@ import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule; import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningModule;
import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.cognation.CognationCapability;
import work.slhaf.partner.module.common.module.PostRunningModule;
import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext; import work.slhaf.partner.runtime.interaction.data.context.PartnerRunningFlowContext;
import java.io.IOException; import java.io.IOException;
@@ -15,7 +15,7 @@ import java.io.IOException;
@Slf4j @Slf4j
@Data @Data
@AgentModule(name = "postprocess_executor", order = 6) @AgentModule(name = "postprocess_executor", order = 6)
public class PostprocessExecutor extends PostRunningModule { public class PostprocessExecutor extends AgentRunningModule<PartnerRunningFlowContext> {
private static final int POST_PROCESS_TRIGGER_ROLL_LIMIT = 36; private static final int POST_PROCESS_TRIGGER_ROLL_LIMIT = 36;

View File

@@ -1,9 +1,10 @@
package work.slhaf.partner.module.modules.process; package work.slhaf.partner.module.modules.process;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityHolder;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.Init; import work.slhaf.partner.api.agent.factory.module.annotation.Init;
import work.slhaf.partner.core.cognation.CognationCapability; import work.slhaf.partner.core.cognation.CognationCapability;
import work.slhaf.partner.core.submodule.perceive.PerceiveCapability; import work.slhaf.partner.core.submodule.perceive.PerceiveCapability;
@@ -17,9 +18,10 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.HashMap; import java.util.HashMap;
@EqualsAndHashCode(callSuper = true)
@Data @Data
@Slf4j @Slf4j
@CapabilityHolder @AgentModule(name = "preprocess_executor", order = 1)
public class PreprocessExecutor extends PreRunningModule { public class PreprocessExecutor extends PreRunningModule {
private static volatile PreprocessExecutor preprocessExecutor; private static volatile PreprocessExecutor preprocessExecutor;

View File

@@ -38,6 +38,7 @@ public class WebSocketGateway extends WebSocketServer implements AgentGateway<Pa
private WebSocketGateway(int port) { private WebSocketGateway(int port) {
super(new InetSocketAddress(port)); super(new InetSocketAddress(port));
this.setReuseAddr(true);
this.executor = InteractionThreadPoolExecutor.getInstance(); this.executor = InteractionThreadPoolExecutor.getInstance();
} }
@@ -101,15 +102,29 @@ public class WebSocketGateway extends WebSocketServer implements AgentGateway<Pa
} }
private void setShutDownHook() { private void setShutDownHook() {
try {
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try { try {
//关闭WebSocketServer // 先断开所有客户端连接
this.stop(); for (WebSocket webSocket : getConnections()) {
try {
webSocket.close(1001, "Server shutting down");
} catch (Exception e) {
log.warn("关闭客户端连接时出错: ", e);
}
}
//关闭WebSocketServer给10秒超时时间确保连接正确关闭
this.stop(10000);
log.info("WebSocketServer 已关闭"); log.info("WebSocketServer 已关闭");
} catch (IllegalStateException e) {
log.warn("无法添加关闭钩子JVM可能已在关闭过程中: ", e);
} catch (Exception e) { } catch (Exception e) {
log.error("WebSocketServer关闭失败: ", e); log.error("WebSocketServer关闭失败: ", e);
} }
})); }));
} catch (IllegalStateException e) {
log.warn("无法添加关闭钩子JVM可能已在关闭过程中: ", e);
}
} }
@Override @Override

View File

@@ -47,35 +47,35 @@ Partner 的目标不是复现某种单一能力,而是尝试在结构中形成
## 模块(已实现/正在实现) ## 模块(已实现/正在实现)
- 预处理模块: `PreprocessExecutor` - 预处理模块: `PreprocessExecutor`
- 后处理模块: `PostprocessExecutor` - 后处理模块: `PostprocessExecutor`
- 主对话模块: `CoreModel`
- 记忆模块 - 记忆模块
- 记忆选择模块: `MemorySelector` - 记忆选择模块: `MemorySelector`
- 主题提取模块: `MemorySelectExtractor` - 主题提取模块: `MemorySelectExtractor`
- 切片评估模块: `SliceSelectEvaluator` - 切片评估模块: `SliceSelectEvaluator`
- 记忆更新模块: `MemoryUpdater` - 记忆更新模块: `MemoryUpdater`
- 记忆总结模块: `MemorySummarizer` - 记忆总结模块[多聊天对象]: `MultiSummarizer`
- 静态记忆提取模块: `StaticMemoryExtractor` - 记忆总结模块[单聊天对象]: `SingleSummarizer`
- 记忆总结模块[汇总]`TotalSummarizer`
- 感知模块 - 感知模块
- 感知选择模块: `PerceiveSelector` - 感知选择模块: `PerceiveSelector`
- 感知更新模块: `PerceiveUpdater` - 感知更新模块: `PerceiveUpdater`
- 关系提取模块: `RelationExtractor` - 关系提取模块: `RelationExtractor`
- 静态记忆提取模块: `StaticExtractor` - 静态记忆提取模块: `StaticMemoryExtractor`
- 任务调度模块 - 任务调度模块(待实现)
- 任务评估模块: `TaskEvaluator` - 任务评估模块: `TaskEvaluator`
- 任务执行模块: `TaskExecutor` - 任务执行模块: `TaskExecutor`
- 任务规划模块: `TaskScheduler` - 任务规划模块: `TaskScheduler`
- 主对话模块: `CoreModel`
## 当前问题 ## 当前问题
- 系统的正常运作效果取决于各模块中大模型对于`prompt`的遵循能力,目前来看`qwen3`的遵循效果明显较好,但在轮次较多时,也容易出现不遵循的情况。 - 系统的正常运作效果取决于各模块中大模型对于`prompt`的遵循能力,目前来看`qwen3`的遵循效果明显较好,但在轮次较多时,也容易出现不遵循的情况。
## 规划 ## 规划
- [ ] 完成框架与本体的适配工作
- [ ] 实现任务与主动调度模块,目前打算用 `时间轮算法` 实现定时操作 - [ ] 实现任务与主动调度模块,目前打算用 `时间轮算法` 实现定时操作
- [ ] 完善具备‘记忆切片、实体图谱、向量召回’的三维记忆融合架构,包含 Episodic + Semantic + Fuzzy 三类记忆 - [ ] 完善具备‘记忆切片、实体图谱、向量召回’的三维记忆融合架构,包含 Episodic + Semantic + Fuzzy 三类记忆
- [ ] 服务端与客户端的通信加上消息队列,防止消息因连接断开而丢失。 - [ ] 服务端与客户端的通信加上消息队列,防止消息因连接断开而丢失。
- [ ] 实现流式输出,同时在各模块执行时可向客户端返回回调信息,优化使用体验。(现在用的是`websocket`与客户端通信, 应该实现这点会简单些) - [ ] 实现流式输出,同时在各模块执行时可向客户端返回回调信息,优化使用体验。(现在用的是`websocket`与客户端通信, 应该实现这点会简单些)
- [ ] 踩坑。 - [ ] 踩坑。
- [ ] 实现角色演进机制 - [ ] 实现演进机制
## License ## License
This project is not licensed for public use. All rights reserved. This project is not licensed for public use. All rights reserved.