进行 框架-主题 的适配测试,发现了一些问题并进行了修复

框架:
- 去除了 ActivateModel 中 modelKey() 方法的默认实现,对于特殊的 AgentModule 继承者(CoreModule)而言,直接获取注解信息不可行,如果保持,则需要另加判断逻辑。这是没有必要的
- 发现 Agent 启动流程中,由于 Gateway 的启动可能依赖配置文件的加载,故将 AgentConfigManager 与 AgentGateway 的指定替换为类型指定,在合适的时机通过反射进行实例化
- 在 AgentUtil 中新增了链式判断指定类的注解链上是否存在指定注解的方法,目前用于 CapabilityHolder 的持有实例判定
- 发现 CapabilityFactoryContext 中 cores、capabilities 未赋值导致空指针异常,已修复
- 将 AgentConfigManager 中的检验逻辑进行抽离,放到了 ConfigLoaderFactory 中,避免职责混淆
- 发现 CoreModule 的注解使用错误,`@Retention(RetentionPolicy.RUNTIME)`元注解可以使得注解在代码运行时能够被反射扫描
- 在 ModuleCheckFactory 中添加了对于 Module 与 SubModule 的注解、继承使用是否匹配的检验
- 发现对于一个类来说,无法直接通过一层反射获取到‘注解的注解’,故在 ModuleRegisterFactory 中针对 CoreModule 的注册做了特殊处理

主体:
- 发现一些类缺少必要注解,已修复
- 发现存在有些必要的类未公开化无参构造函数,已修复,并在框架部分增加校验逻辑

其他:
- 由于项目的启动流程与完整的配置文件密不可分,所以开始尝试编写启动说明,目前只写了开头
This commit is contained in:
2025-09-21 23:29:45 +08:00
parent 3c2ac32708
commit a7d54349e4
20 changed files with 237 additions and 73 deletions

6
.gitignore vendored
View File

@@ -36,8 +36,8 @@ build/
### Mac OS ###
.DS_Store
/data/
/config/
/backup/data/
/backup/config/
/Partner-Core/src/main/java/src/test/java/memory/test.json
/Partner-Core/src/main/java/src/test/java/memory/result/input1.json
/Partner-Core/src/main/java/src/test/java/memory/result/input2.json
@@ -51,3 +51,5 @@ build/
/backup/
/Partner-Main/src/test/java/text/test.json
/CLAUDE.md
/config/
/data/

View File

@@ -18,15 +18,19 @@ import java.util.concurrent.Executors;
*/
public final class Agent {
public static AgentGatewayStep newAgent(Class<?> clazz) {
public static AgentConfigManagerStep newAgent(Class<?> clazz) {
if (clazz == null) {
throw new AgentLaunchFailedException("Agent class 和 interaction flow context 不能为 null");
}
return new AgentApp(clazz);
}
public interface AgentConfigManagerStep {
AgentGatewayStep setAgentConfigManager(Class<? extends AgentConfigManager> agentConfigManager);
}
public interface AgentGatewayStep {
AgentStep setGateway(AgentGateway gateway);
AgentStep setGateway(Class<? extends AgentGateway> gateway);
}
public interface AgentStep {
@@ -34,9 +38,7 @@ public final class Agent {
AgentStep addAfterLaunchRunners(Runnable... runners);
AgentStep setAgentConfigManager(AgentConfigManager agentConfigManager);
AgentStep setAgentExceptionCallback(AgentExceptionCallback agentExceptionCallback);
AgentStep setAgentExceptionCallback(Class<? extends AgentExceptionCallback> agentExceptionCallback);
AgentStep addScanPackage(String packageName);
@@ -46,21 +48,24 @@ public final class Agent {
}
public static class AgentApp implements AgentStep, AgentGatewayStep {
public static class AgentApp implements AgentStep, AgentGatewayStep, AgentConfigManagerStep {
private final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
private final List<Runnable> beforeLaunchRunners = new ArrayList<>();
private final List<Runnable> afterLaunchRunners = new ArrayList<>();
private AgentGateway gateway;
private final Class<?> applicationClass;
private Class<? extends AgentConfigManager> agentConfigManagerClass;
private Class<? extends AgentGateway> gatewayClass;
private Class<? extends AgentExceptionCallback> agentExceptionCallbackClass;
private AgentApp(Class<?> clazz) {
this.applicationClass = clazz;
}
@Override
public AgentStep setGateway(AgentGateway gateway) {
this.gateway = gateway;
public AgentStep setGateway(Class<? extends AgentGateway> gateway) {
this.gatewayClass = gateway;
return this;
}
@@ -77,14 +82,14 @@ public final class Agent {
}
@Override
public AgentStep setAgentConfigManager(AgentConfigManager agentConfigManager) {
AgentConfigManager.setINSTANCE(agentConfigManager);
public AgentGatewayStep setAgentConfigManager(Class<? extends AgentConfigManager> agentConfigManager) {
this.agentConfigManagerClass = agentConfigManager;
return this;
}
@Override
public AgentStep setAgentExceptionCallback(AgentExceptionCallback agentExceptionCallback) {
GlobalExceptionHandler.setExceptionCallback(agentExceptionCallback);
public AgentStep setAgentExceptionCallback(Class<? extends AgentExceptionCallback> agentExceptionCallback) {
agentExceptionCallbackClass = agentExceptionCallback;
return this;
}
@@ -102,10 +107,29 @@ public final class Agent {
@Override
public void launch() {
launchRunners(beforeLaunchRunners);
beforeLaunch();
AgentRegisterFactory.launch(applicationClass.getPackageName());
afterLaunch();
}
private void afterLaunch() {
try {
this.gateway = gatewayClass.getDeclaredConstructor().newInstance();
executorService.execute(() -> gateway.launch());
launchRunners(afterLaunchRunners);
}catch (Exception e){
throw new AgentLaunchFailedException("Agent 后置任务启动失败", e);
}
}
private void beforeLaunch() {
try {
AgentConfigManager.setINSTANCE(agentConfigManagerClass.getDeclaredConstructor().newInstance());
GlobalExceptionHandler.setExceptionCallback(agentExceptionCallbackClass.getDeclaredConstructor().newInstance());
launchRunners(beforeLaunchRunners);
} catch (Exception e) {
throw new AgentLaunchFailedException("Agent 前置任务启动失败", e);
}
}
private void launchRunners(List<Runnable> runners) {

View File

@@ -17,6 +17,7 @@ import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.agent.util.AgentUtil.isAssignableFromAnnotation;
import static work.slhaf.partner.api.agent.util.AgentUtil.methodSignature;
/**
@@ -66,6 +67,7 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
@Override
protected void run() {
//TODO 对于CoordinateManager的所注类进行唯一性检验以及检测是否留有公开的无参构造方法
loadCoresAndCapabilities();
checkCountAndCapabilities();
checkCapabilityMethods();
@@ -83,8 +85,9 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
*/
private void checkInjectCapability() {
reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> {
if (!field.getDeclaringClass().isAssignableFrom(CapabilityHolder.class)) {
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类");
Class<?> declaringClass = field.getDeclaringClass();
if (!isAssignableFromAnnotation(declaringClass, CapabilityHolder.class)){
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于 CapabilityHolder 注解所在类,检查该类是否使用了@CapabilityHolder注解或者受其标注的注解或父类: "+declaringClass);
}
});
}

View File

@@ -1,6 +1,9 @@
package work.slhaf.partner.api.agent.factory.config;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.AgentBaseFactory;
import work.slhaf.partner.api.agent.factory.config.exception.ConfigNotExistException;
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.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ConfigFactoryContext;
@@ -10,7 +13,9 @@ import work.slhaf.partner.api.agent.runtime.config.FileAgentConfigManager;
import work.slhaf.partner.api.chat.pojo.Message;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <h2>Agent启动流程 0</h2>
@@ -20,6 +25,7 @@ import java.util.List;
*
* <p>下一步流程请参阅{@link ModuleCheckFactory}</p>
*/
@Slf4j
public class ConfigLoaderFactory extends AgentBaseFactory {
private AgentConfigManager agentConfigManager;
@@ -42,9 +48,31 @@ public class ConfigLoaderFactory extends AgentBaseFactory {
@Override
protected void run() {
agentConfigManager.load();
agentConfigManager.check();
modelConfigMap.putAll(agentConfigManager.getModelConfigMap());
modelPromptMap.putAll(agentConfigManager.getModelPromptMap());
check();
}
/**
* 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词
*/
private void check() {
log.info("[ConfigLoaderFactory]: 执行config与prompt检测...");
if (!modelConfigMap.containsKey("default")) {
throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`");
}
if (!modelPromptMap.containsKey("basic")) {
throw new PromptNotExistException("缺少基础Prompt! 需要确保存在key为basic的Prompt文件它将与其他Prompt共同作用于模块节点。");
}
Set<String> configKeySet = new HashSet<>(modelConfigMap.keySet());
configKeySet.remove("default");
Set<String> promptKeySet = new HashSet<>(modelPromptMap.keySet());
promptKeySet.remove("basic");
if (!promptKeySet.containsAll(configKeySet)) {
log.warn("存在未被提示词包含的模型配置,该配置将无法生效!");
}
//检查提示词数量与`ActivateModel`的实现数量是否一致
log.info("[ConfigLoaderFactory]: 检测完毕.");
}
}

View File

@@ -3,6 +3,7 @@ package work.slhaf.partner.api.agent.factory.context;
import lombok.Data;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
@@ -12,6 +13,6 @@ public class CapabilityFactoryContext {
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
private Set<Class<?>> cores = new HashSet<>();
private Set<Class<?>> capabilities = new HashSet<>();
}

View File

@@ -56,18 +56,43 @@ public class ModuleCheckFactory extends AgentBaseFactory {
@Override
protected void run() {
Set<Class<?>> moduleTypes = reflections.getTypesAnnotatedWith(AgentModule.class);
Set<Class<?>> subModuleTypes = reflections.getTypesAnnotatedWith(AgentSubModule.class);
AnnotatedModules annotatedModules = getAnnotatedModules();
ExtendedModules extendedModules = getExtendedModules();
checkIfClassCorresponds(annotatedModules, extendedModules);
//检查注解AgentModule或AgentSubModule所在类是否继承了对应的抽象类
annotationAbstractCheck(moduleTypes, AgentRunningModule.class);
annotationAbstractCheck(subModuleTypes, AgentRunningSubModule.class);
annotationAbstractCheck(annotatedModules.moduleTypes(), AgentRunningModule.class);
annotationAbstractCheck(annotatedModules.subModuleTypes(), AgentRunningSubModule.class);
//检查AgentModule是否具备无参构造方法
moduleConstructorsCheck(moduleTypes);
moduleConstructorsCheck(subModuleTypes);
moduleConstructorsCheck(annotatedModules.moduleTypes());
moduleConstructorsCheck(annotatedModules.subModuleTypes());
//检查实现了ActivateModel的模块数量、名称与prompt是否一致
activateModelImplCheck();
}
private ExtendedModules getExtendedModules() {
Set<Class<?>> moduleTypes = reflections.getSubTypesOf(AgentRunningModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
Set<Class<?>> subModuleTypes = reflections.getSubTypesOf(AgentRunningSubModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
return new ExtendedModules(moduleTypes, subModuleTypes);
}
private AnnotatedModules getAnnotatedModules() {
Set<Class<?>> moduleTypes = reflections.getTypesAnnotatedWith(AgentModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
Set<Class<?>> subModuleTypes = reflections.getTypesAnnotatedWith(AgentSubModule.class)
.stream()
.filter(ClassUtil::isNormalClass)
.collect(Collectors.toSet());
return new AnnotatedModules(moduleTypes, subModuleTypes);
}
private void moduleConstructorsCheck(Set<Class<?>> types) {
for (Class<?> type : types) {
try {
@@ -164,4 +189,48 @@ public class ModuleCheckFactory extends AgentBaseFactory {
throw new ModuleCheckException("存在未继承AgentInteractionModule.class的AgentModule实现: " + type.getSimpleName());
}
}
private void checkIfClassCorresponds(AnnotatedModules annotatedModules, ExtendedModules extendedModules) {
// 检查是否有被@AgentModule注解但没有继承AgentRunningModule的类
checkSets(annotatedModules.moduleTypes(), extendedModules.moduleTypes(),
"存在被@AgentModule注解但未继承AgentRunningModule的类");
// 检查是否有继承AgentRunningModule但没有被@AgentModule注解的类
checkSets(extendedModules.moduleTypes(), annotatedModules.moduleTypes(),
"存在继承AgentRunningModule但未被@AgentModule注解的类");
// 检查是否有被@AgentSubModule注解但没有继承AgentRunningSubModule的类
checkSets(annotatedModules.subModuleTypes(), extendedModules.subModuleTypes(),
"存在被@AgentSubModule注解但未继承AgentRunningSubModule的类");
// 检查是否有继承AgentRunningSubModule但没有被@AgentSubModule注解的类
checkSets(extendedModules.subModuleTypes(), annotatedModules.subModuleTypes(),
"存在继承AgentRunningSubModule但未被@AgentSubModule注解的类");
}
/**
* 检查源集合中是否有不在目标集合中的元素
* @param source 源集合
* @param target 目标集合
* @param errorMessage 错误信息前缀
*/
private void checkSets(Set<Class<?>> source, Set<Class<?>> target, String errorMessage) {
// 只有在需要时才创建HashSet以节省内存
if (!target.containsAll(source)) {
// 使用流式处理找出差异部分,避免创建完整的中间集合
String classNames = source.stream()
.filter(clazz -> !target.contains(clazz))
.map(Class::getSimpleName)
.limit(10) // 限制显示数量,避免信息泄露
.collect(Collectors.joining(", ", "[", "]"));
throw new ModuleCheckException(errorMessage + ": " + classNames);
}
}
private record AnnotatedModules(Set<Class<?>> moduleTypes, Set<Class<?>> subModuleTypes) {
}
private record ExtendedModules(Set<Class<?>> moduleTypes, Set<Class<?>> subModuleTypes) {
}
}

View File

@@ -100,6 +100,7 @@ public class ModuleProxyFactory extends AgentBaseFactory {
}
private void updateCapabilityHolderInstances() {
//TODO 扫描并添加所有与@CapabilityHolder相关的实例
capabilityHolderInstances.putAll(moduleInstances);
capabilityHolderInstances.putAll(subModuleInstances);
}
@@ -203,7 +204,7 @@ public class ModuleProxyFactory extends AgentBaseFactory {
}
}
private record ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) {
public record ModuleProxyInterceptor(List<MetaMethod> postHookMethods, List<MetaMethod> preHookMethods) {
@RuntimeType
public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable<?> zuper, @This Object proxy) throws Exception {
for (MetaMethod metaMethod : preHookMethods) {

View File

@@ -7,6 +7,7 @@ import work.slhaf.partner.api.agent.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.agent.factory.context.ModuleFactoryContext;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentModule;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
import work.slhaf.partner.api.agent.factory.module.annotation.CoreModule;
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.runtime.interaction.flow.abstracts.AgentRunningModule;
@@ -80,14 +81,24 @@ public class ModuleRegisterFactory extends AgentBaseFactory {
continue;
}
Class<? extends AgentRunningModule> clazz = module.asSubclass(AgentRunningModule.class);
AgentModule agentModule = clazz.getAnnotation(AgentModule.class);
MetaModule metaModule = new MetaModule();
metaModule.setName(agentModule.name());
metaModule.setOrder(agentModule.order());
metaModule.setClazz(clazz);
MetaModule metaModule = getMetaModule(clazz);
moduleList.add(metaModule);
}
moduleList.sort(Comparator.comparing(MetaModule::getOrder));
}
private static MetaModule getMetaModule(Class<? extends AgentRunningModule> clazz) {
MetaModule metaModule = new MetaModule();
AgentModule agentModule;
if (clazz.isAnnotationPresent(CoreModule.class)){
agentModule = CoreModule.class.getAnnotation(AgentModule.class);
}else{
agentModule = clazz.getAnnotation(AgentModule.class);
}
metaModule.setName(agentModule.name());
metaModule.setOrder(agentModule.order());
metaModule.setClazz(clazz);
return metaModule;
}
}

View File

@@ -1,5 +1,9 @@
package work.slhaf.partner.api.agent.factory.module.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@AgentModule(name = "core",order = 5)
public @interface CoreModule {
}

View File

@@ -20,7 +20,7 @@ import java.util.Set;
public abstract class AgentConfigManager {
@Setter
public static AgentConfigManager INSTANCE;
public static AgentConfigManager INSTANCE = new FileAgentConfigManager();
private static final String DEFAULT_KEY = "default";
protected HashMap<String, ModelConfig> modelConfigMap;
@@ -62,27 +62,6 @@ public abstract class AgentConfigManager {
}
}
/**
* 对模型Config与Prompt分别进行检验,除了都必须包含default外还需要确保数量、key一致毕竟是模型配置与提示词
*/
public void check() {
log.info("[AgentConfigManager]: 执行config与prompt检测...");
if (!modelConfigMap.containsKey("default")) {
throw new ConfigNotExistException("缺少默认配置! 需确保存在一个模型配置的key为`default`");
}
if (!modelPromptMap.containsKey("basic")) {
throw new PromptNotExistException("缺少基础Prompt! 需要确保存在key为basic的Prompt文件它将与其他Prompt共同作用于模块节点。");
}
Set<String> configKeySet = new HashSet<>(modelConfigMap.keySet());
configKeySet.remove("default");
Set<String> promptKeySet = new HashSet<>(modelPromptMap.keySet());
promptKeySet.remove("basic");
if (!promptKeySet.containsAll(configKeySet)) {
log.warn("存在未被提示词包含的模型配置,该配置将无法生效!");
}
log.info("[AgentConfigManager]: 检测完毕.");
}
public List<Message> loadModelPrompt(String modelKey) {
if (!modelPromptMap.containsKey(modelKey)) {
throw new PromptNotExistException("不存在的modelPrompt: " + modelKey);

View File

@@ -88,9 +88,7 @@ public interface ActivateModel {
((Module) this).setModel(model);
}
default String modelKey(){
return this.getClass().getAnnotation(AgentModule.class).name();
}
String modelKey();
boolean withBasicPrompt();

View File

@@ -10,6 +10,28 @@ import java.util.stream.Collectors;
public final class AgentUtil {
public static boolean isAssignableFromAnnotation(Class<?> clazz,Class<? extends Annotation> targetAnnotation){
Set<Class<?>> visited = new HashSet<>();
return isAssignableFromAnnotation(clazz,targetAnnotation,visited);
}
private static boolean isAssignableFromAnnotation(Class<?> clazz,Class<? extends Annotation> targetAnnotation,Set<Class<?>> visited){
if (!visited.add(clazz)){
return false;
}
if (clazz.isAnnotationPresent(targetAnnotation)){
return true;
}
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
boolean ok = isAssignableFromAnnotation(annotation.annotationType(),targetAnnotation,visited);
if (ok){
return true;
}
}
return false;
}
public static String methodSignature(Method method) {
StringBuilder sb = new StringBuilder();
sb.append("(");

View File

@@ -8,9 +8,9 @@ import work.slhaf.partner.runtime.interaction.WebSocketGateway;
public class Main {
public static void main(String[] args) {
Agent.newAgent(Main.class)
.setGateway(WebSocketGateway.initialize())
.setAgentConfigManager(new PartnerAgentConfigManager())
.setAgentExceptionCallback(new PartnerExceptionCallback())
.setAgentConfigManager(PartnerAgentConfigManager.class)
.setGateway(WebSocketGateway.class)
.setAgentExceptionCallback(PartnerExceptionCallback.class)
.launch();
}
}

View File

@@ -44,10 +44,6 @@ public class CoordinatedManager implements Serializable {
private PerceiveCore perceiveCore;
private DispatchCore dispatchCore;
private CoordinatedManager() {
}
public static CoordinatedManager getInstance() throws IOException, ClassNotFoundException {
if (coordinatedManager == null) {
synchronized (CoordinatedManager.class) {

View File

@@ -22,6 +22,7 @@ import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@EqualsAndHashCode(callSuper = true)
@@ -185,5 +186,10 @@ public class CognationCore extends PersistableObject {
public List<EvaluatedSlice> getActivatedSlices(String userId) {
return activeData.getActivatedSlices().get(userId);
}
@CapabilityMethod
public Lock getMessageLock() {
return messageLock;
}
}

View File

@@ -54,6 +54,11 @@ public class CoreModel extends CoreRunningModule implements ActivateModel {
chatClient().setTop_p(0.7);
}
@Override
public String modelKey() {
return "core_model";
}
@Override
public boolean withBasicPrompt() {
return true;

View File

@@ -6,6 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
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.AgentRunningSubModule;
@@ -31,6 +32,7 @@ import static work.slhaf.partner.common.util.ExtractUtil.fixTopicPath;
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
@AgentSubModule
public class MemorySelectExtractor extends AgentRunningSubModule<PartnerRunningFlowContext, ExtractorResult>
implements ActivateModel {

View File

@@ -25,10 +25,6 @@ import static work.slhaf.partner.common.util.ExtractUtil.fixTopicPath;
@AgentSubModule
public class MultiSummarizer extends AgentRunningSubModule<SummarizeInput, SummarizeResult> implements ActivateModel {
private MultiSummarizer() {
modelSettings();
}
@Init
public void init() {
updateChatClientSettings();

View File

@@ -32,9 +32,8 @@ public class WebSocketGateway extends WebSocketServer implements AgentGateway<Pa
// 记录最后一次收到Pong的时间
private final ConcurrentHashMap<WebSocket, Long> lastPongTimes = new ConcurrentHashMap<>();
public static WebSocketGateway initialize() {
PartnerAgentConfigManager configManager = (PartnerAgentConfigManager) AgentConfigManager.INSTANCE;
return new WebSocketGateway(configManager.getConfig().getPort());
public WebSocketGateway() {
this(((PartnerAgentConfigManager) AgentConfigManager.INSTANCE).getConfig().getPort());
}
private WebSocketGateway(int port) {

18
doc/如何启动.md Normal file
View File

@@ -0,0 +1,18 @@
# Partner 项目启动流程
> 由于整个项目启动依赖提前写好的配置文件,所以在启动项目之前,最好阅读先该文档,准备好必要的配置,避免启动失败
## 前置操作
确保已经安装`Java21`环境
克隆项目至本地:
```bash
git clone https://github.com/slhafzjw/Partner.git
```
## 准备配置
克隆好项目之后,在项目的根目录创建目录`config/`
### 准备基础配置文件