mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
推进 ActionDispatcher 模块、完善行动程序规范与加载逻辑
- 明确行动程序的存储形式与加载规则,分为执行程序和描述文件,前者负责逻辑,后者提供必要的描述性信息; - 将 ActionInfo 重命名为 ActionData,更新相关接口和实现,增强代码一致性和可读性; - 添加异常处理类以支持行动程序、描述信息的初始化和加载失败的场景; - 实现行动程序目录的监控功能,支持行动程序的动态加载与管理; - 明确了 ActionDispatcher 两个子模块的输入输出规范
This commit is contained in:
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AgentMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AskMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EditMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.common;
|
||||||
|
|
||||||
|
public final class Constant {
|
||||||
|
|
||||||
|
public static final class Path {
|
||||||
|
public static final String DATA = "./data";
|
||||||
|
public static final String MEMORY_DATA = DATA + "/memory";
|
||||||
|
public static final String ACTION_PROGRAM = DATA + "/action";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,10 +13,11 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
import static work.slhaf.partner.common.Constant.Path.MEMORY_DATA;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class PartnerCore<T extends PartnerCore<T>> extends PersistableObject {
|
public abstract class PartnerCore<T extends PartnerCore<T>> extends PersistableObject {
|
||||||
|
|
||||||
private static final String STORAGE_DIR = "./data/memory/";
|
|
||||||
private final String id = ((PartnerAgentConfigManager) AgentConfigManager.INSTANCE).getConfig().getAgentId();
|
private final String id = ((PartnerAgentConfigManager) AgentConfigManager.INSTANCE).getConfig().getAgentId();
|
||||||
|
|
||||||
public PartnerCore() throws IOException, ClassNotFoundException {
|
public PartnerCore() throws IOException, ClassNotFoundException {
|
||||||
@@ -53,7 +54,7 @@ public abstract class PartnerCore<T extends PartnerCore<T>> extends PersistableO
|
|||||||
public void serialize() throws IOException {
|
public void serialize() throws IOException {
|
||||||
//先写入到临时文件,如果正常写入则覆盖原文件
|
//先写入到临时文件,如果正常写入则覆盖原文件
|
||||||
Path filePath = getFilePath(id + "-temp");
|
Path filePath = getFilePath(id + "-temp");
|
||||||
Files.createDirectories(Path.of(STORAGE_DIR));
|
Files.createDirectories(Path.of(MEMORY_DATA));
|
||||||
try {
|
try {
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath.toFile()));
|
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath.toFile()));
|
||||||
oos.writeObject(this);
|
oos.writeObject(this);
|
||||||
@@ -78,12 +79,12 @@ public abstract class PartnerCore<T extends PartnerCore<T>> extends PersistableO
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Path getFilePath(String s) {
|
private Path getFilePath(String s) {
|
||||||
return Paths.get(STORAGE_DIR, s + "-" + getCoreKey() + ".memory");
|
return Paths.get(MEMORY_DATA, s + "-" + getCoreKey() + ".memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createStorageDirectory() {
|
private void createStorageDirectory() {
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(Paths.get(STORAGE_DIR));
|
Files.createDirectories(Paths.get(MEMORY_DATA));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("[{}]创建存储目录失败: {}", getCoreKey(), e.getMessage());
|
log.error("[{}]创建存储目录失败: {}", getCoreKey(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
package work.slhaf.partner.core.action;
|
package work.slhaf.partner.core.action;
|
||||||
|
|
||||||
import work.slhaf.partner.api.agent.factory.capability.annotation.Capability;
|
import work.slhaf.partner.api.agent.factory.capability.annotation.Capability;
|
||||||
import work.slhaf.partner.core.action.entity.ActionInfo;
|
import work.slhaf.partner.core.action.entity.ActionData;
|
||||||
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Capability(value = "action")
|
@Capability(value = "action")
|
||||||
public interface ActionCapability {
|
public interface ActionCapability {
|
||||||
void putPreparedAction(String uuid, ActionInfo actionInfo);
|
void putPreparedAction(String uuid, ActionData actionData);
|
||||||
|
|
||||||
List<ActionInfo> popPreparedAction(String userId);
|
List<ActionData> popPreparedAction(String userId);
|
||||||
|
|
||||||
List<ActionInfo> popPendingAction(String userId);
|
List<ActionData> popPendingAction(String userId);
|
||||||
|
|
||||||
List<ActionInfo> listPreparedAction(String userId);
|
List<ActionData> listPreparedAction(String userId);
|
||||||
|
|
||||||
List<ActionInfo> listPendingAction(String userId);
|
List<ActionData> listPendingAction(String userId);
|
||||||
|
|
||||||
void putPendingActions(String userId, ActionInfo actionInfo);
|
void putPendingActions(String userId, ActionData actionData);
|
||||||
|
|
||||||
List<String> selectTendencyCache(String input);
|
List<String> selectTendencyCache(String input);
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,35 @@
|
|||||||
package work.slhaf.partner.core.action;
|
package work.slhaf.partner.core.action;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityCore;
|
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityCore;
|
||||||
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityMethod;
|
import work.slhaf.partner.api.agent.factory.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.common.vector.VectorClient;
|
import work.slhaf.partner.common.vector.VectorClient;
|
||||||
import work.slhaf.partner.core.PartnerCore;
|
import work.slhaf.partner.core.PartnerCore;
|
||||||
import work.slhaf.partner.core.action.entity.ActionInfo;
|
import work.slhaf.partner.core.action.entity.ActionData;
|
||||||
|
import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
||||||
import work.slhaf.partner.core.action.entity.cache.ActionCacheData;
|
import work.slhaf.partner.core.action.entity.cache.ActionCacheData;
|
||||||
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
||||||
import work.slhaf.partner.core.action.entity.cache.CacheAdjustMetaData;
|
import work.slhaf.partner.core.action.entity.cache.CacheAdjustMetaData;
|
||||||
|
import work.slhaf.partner.core.action.exception.ActionInitFailedException;
|
||||||
|
import work.slhaf.partner.core.action.exception.ActionLoadFailedException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
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 java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static work.slhaf.partner.common.Constant.Path.ACTION_PROGRAM;
|
||||||
|
|
||||||
@SuppressWarnings("FieldMayBeFinal")
|
@SuppressWarnings("FieldMayBeFinal")
|
||||||
@CapabilityCore(value = "action")
|
@CapabilityCore(value = "action")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -28,64 +38,68 @@ public class ActionCore extends PartnerCore<ActionCore> {
|
|||||||
/**
|
/**
|
||||||
* 对应本次交互即将执行或将要放置在行动池的预备任务,因此将以本次交互的uuid为键,其起到的作用相当于暂时的模块上下文
|
* 对应本次交互即将执行或将要放置在行动池的预备任务,因此将以本次交互的uuid为键,其起到的作用相当于暂时的模块上下文
|
||||||
*/
|
*/
|
||||||
private HashMap<String, List<ActionInfo>> preparedActions = new HashMap<>();
|
private HashMap<String, List<ActionData>> preparedActions = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 待确认任务,以userId区分不同用户,因为需要跨请求确认
|
* 待确认任务,以userId区分不同用户,因为需要跨请求确认
|
||||||
*/
|
*/
|
||||||
private HashMap<String, List<ActionInfo>> pendingActions = new HashMap<>();
|
private HashMap<String, List<ActionData>> pendingActions = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语义缓存与行为倾向映射
|
* 语义缓存与行为倾向映射
|
||||||
*/
|
*/
|
||||||
private List<ActionCacheData> actionCache = new ArrayList<>();
|
private List<ActionCacheData> actionCache = new ArrayList<>();
|
||||||
|
|
||||||
private Lock cacheLock = new ReentrantLock();
|
private final Lock cacheLock = new ReentrantLock();
|
||||||
|
|
||||||
private Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
private final ExecutorService platformExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
|
private final ExecutorService virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
|
|
||||||
|
private final LinkedHashMap<String, MetaActionInfo> existedMetaActions = new LinkedHashMap<>();
|
||||||
|
|
||||||
public ActionCore() throws IOException, ClassNotFoundException {
|
public ActionCore() throws IOException, ClassNotFoundException {
|
||||||
|
new ActionWatchService().launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public synchronized void putPendingActions(String userId, ActionInfo actionInfo) {
|
public synchronized void putPendingActions(String userId, ActionData actionData) {
|
||||||
pendingActions.computeIfAbsent(userId, k -> {
|
pendingActions.computeIfAbsent(userId, k -> {
|
||||||
List<ActionInfo> temp = new ArrayList<>();
|
List<ActionData> temp = new ArrayList<>();
|
||||||
temp.add(actionInfo);
|
temp.add(actionData);
|
||||||
return temp;
|
return temp;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public synchronized List<ActionInfo> popPendingAction(String userId) {
|
public synchronized List<ActionData> popPendingAction(String userId) {
|
||||||
List<ActionInfo> infos = pendingActions.get(userId);
|
List<ActionData> infos = pendingActions.get(userId);
|
||||||
pendingActions.remove(userId);
|
pendingActions.remove(userId);
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public synchronized void putPreparedAction(String uuid, ActionInfo actionInfo) {
|
public synchronized void putPreparedAction(String uuid, ActionData actionData) {
|
||||||
preparedActions.computeIfAbsent(uuid, k -> {
|
preparedActions.computeIfAbsent(uuid, k -> {
|
||||||
List<ActionInfo> temp = new ArrayList<>();
|
List<ActionData> temp = new ArrayList<>();
|
||||||
temp.add(actionInfo);
|
temp.add(actionData);
|
||||||
return temp;
|
return temp;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public synchronized List<ActionInfo> popPreparedAction(String userId) {
|
public synchronized List<ActionData> popPreparedAction(String userId) {
|
||||||
List<ActionInfo> infos = preparedActions.get(userId);
|
List<ActionData> infos = preparedActions.get(userId);
|
||||||
preparedActions.remove(userId);
|
preparedActions.remove(userId);
|
||||||
return infos;
|
return infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public List<ActionInfo> listPreparedAction(String userId) {
|
public List<ActionData> listPreparedAction(String userId) {
|
||||||
return preparedActions.get(userId);
|
return preparedActions.get(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public List<ActionInfo> listPendingAction(String userId) {
|
public List<ActionData> listPendingAction(String userId) {
|
||||||
return pendingActions.get(userId);
|
return pendingActions.get(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,9 +150,9 @@ public class ActionCore extends PartnerCore<ActionCore> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.execute(() -> adjustMatchAndPassed(matchAndPassed, inputVector, input, vectorClient));
|
platformExecutor.execute(() -> adjustMatchAndPassed(matchAndPassed, inputVector, input, vectorClient));
|
||||||
executor.execute(() -> adjustMatchNotPassed(matchNotPassed, vectorClient));
|
platformExecutor.execute(() -> adjustMatchNotPassed(matchNotPassed, vectorClient));
|
||||||
executor.execute(() -> adjustNotMatchPassed(notMatchPassed, inputVector, input, vectorClient));
|
platformExecutor.execute(() -> adjustNotMatchPassed(notMatchPassed, inputVector, input, vectorClient));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,7 +162,8 @@ public class ActionCore extends PartnerCore<ActionCore> {
|
|||||||
* @param inputVector 本次输入内容的语义向量
|
* @param inputVector 本次输入内容的语义向量
|
||||||
* @param vectorClient 向量客户端
|
* @param vectorClient 向量客户端
|
||||||
*/
|
*/
|
||||||
private void adjustMatchAndPassed(List<CacheAdjustMetaData> matchAndPassed, float[] inputVector, String input, VectorClient vectorClient) {
|
private void adjustMatchAndPassed(List<CacheAdjustMetaData> matchAndPassed, float[] inputVector, String
|
||||||
|
input, VectorClient vectorClient) {
|
||||||
matchAndPassed.forEach(adjustData -> {
|
matchAndPassed.forEach(adjustData -> {
|
||||||
//获取原始缓存条目
|
//获取原始缓存条目
|
||||||
String tendency = adjustData.getTendency();
|
String tendency = adjustData.getTendency();
|
||||||
@@ -204,7 +219,8 @@ public class ActionCore extends PartnerCore<ActionCore> {
|
|||||||
* @param input 本次输入内容
|
* @param input 本次输入内容
|
||||||
* @param vectorClient 向量客户端
|
* @param vectorClient 向量客户端
|
||||||
*/
|
*/
|
||||||
private void adjustNotMatchPassed(List<CacheAdjustMetaData> notMatchPassed, float[] inputVector, String input, VectorClient vectorClient) {
|
private void adjustNotMatchPassed(List<CacheAdjustMetaData> notMatchPassed, float[] inputVector, String
|
||||||
|
input, VectorClient vectorClient) {
|
||||||
notMatchPassed.forEach(adjustData -> {
|
notMatchPassed.forEach(adjustData -> {
|
||||||
//获取原始缓存条目
|
//获取原始缓存条目
|
||||||
String tendency = adjustData.getTendency();
|
String tendency = adjustData.getTendency();
|
||||||
@@ -232,4 +248,169 @@ public class ActionCore extends PartnerCore<ActionCore> {
|
|||||||
protected String getCoreKey() {
|
protected String getCoreKey() {
|
||||||
return "action-core";
|
return "action-core";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private class ActionWatchService {
|
||||||
|
|
||||||
|
private HashMap<Path, WatchKey> registeredPaths = new HashMap<>();
|
||||||
|
|
||||||
|
public void launch() {
|
||||||
|
Path path = Path.of(ACTION_PROGRAM);
|
||||||
|
scanActions(path.toFile());
|
||||||
|
launchActionDirectoryWatcher(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchActionDirectoryWatcher(Path path) {
|
||||||
|
WatchService watchService;
|
||||||
|
try {
|
||||||
|
watchService = FileSystems.getDefault().newWatchService();
|
||||||
|
setupShutdownHook(watchService);
|
||||||
|
registerParentToWatch(path, watchService);
|
||||||
|
registerSubToWatch(path, watchService);
|
||||||
|
virtualExecutor.execute(registerWatchTask(path, watchService));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ActionInitFailedException("行动程序目录监听器启动失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupShutdownHook(WatchService watchService) {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
try {
|
||||||
|
watchService.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable registerWatchTask(Path path, WatchService watchService) {
|
||||||
|
return () -> {
|
||||||
|
log.info("[{}] 行动程序目录监听器已启动", getCoreKey());
|
||||||
|
while (true) {
|
||||||
|
WatchKey key;
|
||||||
|
try {
|
||||||
|
key = watchService.take();
|
||||||
|
List<WatchEvent<?>> events = key.pollEvents();
|
||||||
|
for (WatchEvent<?> e : events) {
|
||||||
|
WatchEvent<Path> event = (WatchEvent<Path>) e;
|
||||||
|
WatchEvent.Kind<Path> kind = event.kind();
|
||||||
|
Path context = event.context();
|
||||||
|
log.info("[{}] 行动程序目录变更事件: {} - {}", getCoreKey(), kind.name(), context.toString());
|
||||||
|
Path thisDir = (Path) key.watchable();
|
||||||
|
//根据事件发生的目录进行分流,分为父目录事件和子程序事件
|
||||||
|
if (thisDir.equals(path)) {
|
||||||
|
handleParentDirEvent(kind, thisDir, context, watchService);
|
||||||
|
} else {
|
||||||
|
handleSubDirEvent(kind, thisDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.info("监听线程被中断,准备退出...");
|
||||||
|
Thread.currentThread().interrupt(); // 恢复中断标志
|
||||||
|
break;
|
||||||
|
} catch (ClosedWatchServiceException e) {
|
||||||
|
log.info("WatchService 已关闭,监听线程退出。");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSubDirEvent(WatchEvent.Kind<Path> kind, Path thisDir) {
|
||||||
|
// path为触发本次行动的文件的路径(当前位于某个action目录下)
|
||||||
|
// 先判定发生的目录前缀是否匹配(action、desc),否则忽略
|
||||||
|
if (kind == StandardWatchEventKinds.ENTRY_CREATE || kind == StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||||
|
// CREATE、MODIFY 事件将触发一次检测,看当前thisDir中action和desc是否都具备,如果通过则尝试加载(put)。
|
||||||
|
boolean complete = checkComplete(thisDir);
|
||||||
|
if (!complete) return;
|
||||||
|
try {
|
||||||
|
MetaActionInfo newActionInfo = new MetaActionInfo(thisDir.toFile());
|
||||||
|
existedMetaActions.put(thisDir.toString(), newActionInfo);
|
||||||
|
} catch (ActionLoadFailedException e) {
|
||||||
|
log.warn("[{}] 行动信息重新加载失败,触发行为: {}", getCoreKey(), kind.name());
|
||||||
|
}
|
||||||
|
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
|
||||||
|
// DELETE 事件将会把该 MetaActionInfo 从记录中移除
|
||||||
|
existedMetaActions.remove(thisDir.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkComplete(Path thisDir) {
|
||||||
|
File[] files = thisDir.toFile().listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
log.error("[{}]当前目录无法访问: [{}]", getCoreKey(), thisDir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean existedAction = false;
|
||||||
|
boolean existedDesc = false;
|
||||||
|
for (File file : files) {
|
||||||
|
String fileName = file.getName();
|
||||||
|
String nameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||||
|
if (nameWithoutExt.equals("action")) existedAction = true;
|
||||||
|
else if (nameWithoutExt.equals("desc")) existedDesc = true;
|
||||||
|
}
|
||||||
|
return existedAction && existedDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleParentDirEvent(WatchEvent.Kind<Path> kind, Path thisDir, Path context, WatchService watchService) {
|
||||||
|
Path path = Path.of(thisDir.toString(), context.toString());
|
||||||
|
// MODIFY 事件不进行处理
|
||||||
|
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
|
||||||
|
try {
|
||||||
|
path.register(watchService,
|
||||||
|
StandardWatchEventKinds.ENTRY_CREATE,
|
||||||
|
StandardWatchEventKinds.ENTRY_DELETE,
|
||||||
|
StandardWatchEventKinds.ENTRY_MODIFY);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("[{}] 新增行动程序目录监听失败: {}", getCoreKey(), path, e);
|
||||||
|
}
|
||||||
|
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
|
||||||
|
WatchKey remove = registeredPaths.remove(path);
|
||||||
|
remove.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerSubToWatch(Path path, WatchService watchService) throws IOException {
|
||||||
|
Files.walkFileTree(path, new SimpleFileVisitor<>() {
|
||||||
|
@Override
|
||||||
|
public @NotNull FileVisitResult preVisitDirectory(@NotNull Path dir, @NotNull BasicFileAttributes attrs) throws IOException {
|
||||||
|
if (dir.getFileName().startsWith(".")) return FileVisitResult.CONTINUE;
|
||||||
|
WatchKey key = dir.register(watchService,
|
||||||
|
StandardWatchEventKinds.ENTRY_CREATE,
|
||||||
|
StandardWatchEventKinds.ENTRY_DELETE,
|
||||||
|
StandardWatchEventKinds.ENTRY_MODIFY);
|
||||||
|
registeredPaths.put(dir, key);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerParentToWatch(Path path, WatchService watchService) throws IOException {
|
||||||
|
WatchKey key = path.register(watchService,
|
||||||
|
StandardWatchEventKinds.ENTRY_CREATE,
|
||||||
|
StandardWatchEventKinds.ENTRY_DELETE,
|
||||||
|
StandardWatchEventKinds.ENTRY_MODIFY);
|
||||||
|
registeredPaths.put(path, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanActions(File file) {
|
||||||
|
if (!file.exists() || file.isFile()) {
|
||||||
|
throw new ActionInitFailedException("未找到行动程序目录: " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
throw new ActionInitFailedException("目录无法访问: " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
for (File f : files) {
|
||||||
|
try {
|
||||||
|
MetaActionInfo actionInfo = new MetaActionInfo(f);
|
||||||
|
existedMetaActions.put(f.getName(), actionInfo);
|
||||||
|
log.info("[{}] 行动程序[{}]已加载", getCoreKey(), actionInfo.getKey());
|
||||||
|
} catch (ActionLoadFailedException e) {
|
||||||
|
log.warn("[{}] 行动程序未加载: {}", getCoreKey(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行动模块传递的行动数据,包含行动uuid、倾向、状态、行动链、结果、发起原因、行动描述等信息。
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
public abstract class ActionInfo {
|
public abstract class ActionData {
|
||||||
protected String uuid;
|
protected String uuid;
|
||||||
protected String tendency;
|
protected String tendency;
|
||||||
protected ActionStatus status;
|
protected ActionStatus status;
|
||||||
@@ -13,4 +16,8 @@ public abstract class ActionInfo {
|
|||||||
protected String Result;
|
protected String Result;
|
||||||
protected String reason;
|
protected String reason;
|
||||||
protected String description;
|
protected String description;
|
||||||
|
|
||||||
|
public enum ActionStatus {
|
||||||
|
SUCCESS, FAILED, EXECUTING, WAITING, PREPARE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package work.slhaf.partner.core.action.entity;
|
|
||||||
|
|
||||||
public enum ActionStatus {
|
|
||||||
SUCCESS, FAILED, EXECUTING, WAITING, PREPARE
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package work.slhaf.partner.core.action.entity;
|
|
||||||
|
|
||||||
public enum ActionType {
|
|
||||||
IMMEDIATE, PLANNING
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,10 @@ package work.slhaf.partner.core.action.entity;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 即时行动数据类,继承自{@link ActionData}
|
||||||
|
*/
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
public class ImmediateActionInfo extends ActionInfo {
|
public class ImmediateActionData extends ActionData {
|
||||||
}
|
}
|
||||||
@@ -2,25 +2,97 @@ package work.slhaf.partner.core.action.entity;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import work.slhaf.partner.common.Constant;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import static work.slhaf.partner.common.Constant.Path.ACTION_PROGRAM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行动链中的单一元素,实现{@link Runnable}接口,封装了调用外部行动程序的必要信息,可被执行
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class MetaAction implements Comparable<MetaAction> {
|
public class MetaAction implements Comparable<MetaAction>, Callable<Void> {
|
||||||
//行动key
|
|
||||||
|
/**
|
||||||
|
* 行动key,用于标识与定位行动程序
|
||||||
|
*/
|
||||||
private String key;
|
private String key;
|
||||||
//行动参数
|
/**
|
||||||
|
* 行动程序可接受的参数,由调用处设置
|
||||||
|
*/
|
||||||
private String[] params;
|
private String[] params;
|
||||||
//行动回应
|
/**
|
||||||
private String response;
|
* 行动结果,包括执行状态和相应内容(执行结果或者错误信息)
|
||||||
//执行顺序,升序排列
|
*/
|
||||||
|
private Result result;
|
||||||
|
/**
|
||||||
|
* 执行顺序,升序排列
|
||||||
|
*/
|
||||||
private int order;
|
private int order;
|
||||||
|
/**
|
||||||
|
* 是否IO密集,用于决定使用何种线程池
|
||||||
|
*/
|
||||||
private boolean io;
|
private boolean io;
|
||||||
|
/**
|
||||||
|
* 行动程序类型,可分为PLUGIN(jar文件)、SCRIPT(Python程序)、MCP(MCP服务)
|
||||||
|
*/
|
||||||
|
private MetaActionType type;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@NotNull MetaAction metaAction) {
|
public int compareTo(@NotNull MetaAction metaAction) {
|
||||||
return this.order - metaAction.order;
|
return this.order - metaAction.order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void execute() {
|
@Override
|
||||||
|
public Void call() {
|
||||||
|
File action = loadFromFile();
|
||||||
|
if (!action.exists()) {
|
||||||
|
result = new Result();
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setData("Action file not found: " + action.getAbsolutePath());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
switch (type) {
|
||||||
|
case PLUGIN -> executePlugin(action);
|
||||||
|
case MCP -> executeMcp(action);
|
||||||
|
case SCRIPT -> executeScript(action);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
result = new Result();
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setData(e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File loadFromFile() {
|
||||||
|
return switch (type) {
|
||||||
|
case PLUGIN -> Path.of(Constant.Path.ACTION_PROGRAM, key, "action.jar").toFile();
|
||||||
|
case SCRIPT -> Path.of(ACTION_PROGRAM, key, "action.py").toFile();
|
||||||
|
case MCP -> Path.of(ACTION_PROGRAM, key, "action.json").toFile();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executePlugin(File actionFile) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void executeMcp(File actionFile) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeScript(File actionFile) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Result {
|
||||||
|
private boolean success;
|
||||||
|
private String data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package work.slhaf.partner.core.action.entity;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import work.slhaf.partner.core.action.exception.ActionLoadFailedException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MetaActionInfo {
|
||||||
|
private String key;
|
||||||
|
private boolean io;
|
||||||
|
private MetaActionType type;
|
||||||
|
|
||||||
|
private Map<String, String> params;
|
||||||
|
private String description;
|
||||||
|
private List<String> tags;
|
||||||
|
|
||||||
|
private List<String> preActions;
|
||||||
|
private List<String> postActions;
|
||||||
|
/**
|
||||||
|
* 是否严格依赖前置行动的成功执行,若为true且前置行动失败则不执行该行动,后置任务多为触发式。默认即执行。
|
||||||
|
*/
|
||||||
|
private boolean strictDependencies;
|
||||||
|
|
||||||
|
private JSONObject responseSchema;
|
||||||
|
|
||||||
|
public MetaActionInfo(File actionDir) {
|
||||||
|
if (actionDir.isFile()) {
|
||||||
|
throw new ActionLoadFailedException("Action directory expected, but file found: " + actionDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
File[] files = actionDir.listFiles();
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
throw new ActionLoadFailedException("Action directory is empty: " + actionDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
//加载desc.json
|
||||||
|
File desc = Path.of(actionDir.getPath(), "desc.json").toFile();
|
||||||
|
if (!desc.exists() || desc.isDirectory()) {
|
||||||
|
throw new ActionLoadFailedException("Action desc.json not found: " + desc.getAbsolutePath());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String s = FileUtils.readFileToString(desc, StandardCharsets.UTF_8);
|
||||||
|
MetaActionInfo temp = JSONObject.parseObject(s, MetaActionInfo.class);
|
||||||
|
BeanUtil.copyProperties(temp, this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ActionLoadFailedException("Failed to load action desc.json: " + desc.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
//进行必要的字段校验和初始化
|
||||||
|
if (type == null) throw new ActionLoadFailedException("Action type missing in desc.json");
|
||||||
|
if (params == null) params = new HashMap<>();
|
||||||
|
if (preActions == null) preActions = new ArrayList<>();
|
||||||
|
if (postActions == null) postActions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package work.slhaf.partner.core.action.entity;
|
||||||
|
|
||||||
|
public enum MetaActionType {
|
||||||
|
PLUGIN, MCP, SCRIPT
|
||||||
|
}
|
||||||
@@ -3,9 +3,12 @@ package work.slhaf.partner.core.action.entity;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划行动数据类,继承自{@link ActionData},扩展了属性{@link ScheduledActionData#type}和{@link ScheduledActionData#scheduleContent},用于标识计划类型(单次还是周期性任务)和计划内容
|
||||||
|
*/
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
public class ScheduledActionInfo extends ActionInfo {
|
public class ScheduledActionData extends ActionData {
|
||||||
private ScheduledType type;
|
private ScheduledType type;
|
||||||
private String scheduleContent; //如果为周期,则对应cron表达式,如果为一次性,则对应为LocalDateTime字符串
|
private String scheduleContent; //如果为周期,则对应cron表达式,如果为一次性,则对应为LocalDateTime字符串
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package work.slhaf.partner.core.action.exception;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.agent.runtime.exception.AgentLaunchFailedException;
|
||||||
|
|
||||||
|
public class ActionInitFailedException extends AgentLaunchFailedException {
|
||||||
|
public ActionInitFailedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionInitFailedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package work.slhaf.partner.core.action.exception;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.agent.runtime.exception.AgentRuntimeException;
|
||||||
|
|
||||||
|
public class ActionLoadFailedException extends AgentRuntimeException {
|
||||||
|
public ActionLoadFailedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionLoadFailedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -198,9 +198,9 @@ public class MemoryCore extends PartnerCore<MemoryCore> {
|
|||||||
//尝试更新缓存
|
//尝试更新缓存
|
||||||
updateCache(topicPath, memoryResult);
|
updateCache(topicPath, memoryResult);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[CoordinatedManager] selectMemory error: ", e);
|
log.error("[{}] selectMemory error: ", getCoreKey(), e);
|
||||||
log.error("[CoordinatedManager] 路径: {}", topicPathStr);
|
log.error("[{}] 路径: {}", getCoreKey(), topicPathStr);
|
||||||
log.error("[CoordinatedManager] 主题树: {}", getTopicTree());
|
log.error("[{}] 主题树: {}", getCoreKey(), getTopicTree());
|
||||||
memoryResult = new MemoryResult();
|
memoryResult = new MemoryResult();
|
||||||
memoryResult.setRelatedMemorySliceResult(new ArrayList<>());
|
memoryResult.setRelatedMemorySliceResult(new ArrayList<>());
|
||||||
memoryResult.setMemorySliceResult(new CopyOnWriteArrayList<>());
|
memoryResult.setMemorySliceResult(new CopyOnWriteArrayList<>());
|
||||||
@@ -211,7 +211,7 @@ public class MemoryCore extends PartnerCore<MemoryCore> {
|
|||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) {
|
public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) {
|
||||||
cache.activatedSlices.put(userId, memorySlices);
|
cache.activatedSlices.put(userId, memorySlices);
|
||||||
log.debug("[CoordinatedManager] 已更新激活切片, userId: {}", userId);
|
log.debug("[{}] 已更新激活切片, userId: {}", getCoreKey(), userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ 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.common.thread.InteractionThreadPoolExecutor;
|
import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor;
|
||||||
import work.slhaf.partner.core.action.ActionCapability;
|
import work.slhaf.partner.core.action.ActionCapability;
|
||||||
import work.slhaf.partner.core.action.entity.ActionInfo;
|
import work.slhaf.partner.core.action.entity.ActionData;
|
||||||
import work.slhaf.partner.core.action.entity.ImmediateActionInfo;
|
import work.slhaf.partner.core.action.entity.ImmediateActionData;
|
||||||
import work.slhaf.partner.core.action.entity.ScheduledActionInfo;
|
import work.slhaf.partner.core.action.entity.ScheduledActionData;
|
||||||
import work.slhaf.partner.module.common.module.PostRunningModule;
|
import work.slhaf.partner.module.common.module.PostRunningModule;
|
||||||
import work.slhaf.partner.module.modules.action.dispatcher.executor.ActionExecutor;
|
import work.slhaf.partner.module.modules.action.dispatcher.executor.ActionExecutor;
|
||||||
import work.slhaf.partner.module.modules.action.dispatcher.scheduler.ActionScheduler;
|
import work.slhaf.partner.module.modules.action.dispatcher.scheduler.ActionScheduler;
|
||||||
@@ -42,14 +42,14 @@ public class ActionDispatcher extends PostRunningModule {
|
|||||||
//对于将触发的PLANNING action,理想做法是将执行工具做成执行链的形式,模型的自对话流程、是否通知用户都做成与普通工具同等的通用可选能力,避免绑定固定流程
|
//对于将触发的PLANNING action,理想做法是将执行工具做成执行链的形式,模型的自对话流程、是否通知用户都做成与普通工具同等的通用可选能力,避免绑定固定流程
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
String userId = context.getUserId();
|
String userId = context.getUserId();
|
||||||
List<ActionInfo> preparedActions = actionCapability.popPreparedAction(userId);
|
List<ActionData> preparedActions = actionCapability.popPreparedAction(userId);
|
||||||
//分类成PLANNING和IMMEDIATE两类
|
//分类成PLANNING和IMMEDIATE两类
|
||||||
List<ScheduledActionInfo> scheduledActions = new ArrayList<>();
|
List<ScheduledActionData> scheduledActions = new ArrayList<>();
|
||||||
List<ImmediateActionInfo> immediateActions = new ArrayList<>();
|
List<ImmediateActionData> immediateActions = new ArrayList<>();
|
||||||
for (ActionInfo preparedAction : preparedActions) {
|
for (ActionData preparedAction : preparedActions) {
|
||||||
if (preparedAction instanceof ScheduledActionInfo actionInfo) {
|
if (preparedAction instanceof ScheduledActionData actionInfo) {
|
||||||
scheduledActions.add(actionInfo);
|
scheduledActions.add(actionInfo);
|
||||||
} else if (preparedAction instanceof ImmediateActionInfo actionInfo) {
|
} else if (preparedAction instanceof ImmediateActionData actionInfo) {
|
||||||
immediateActions.add(actionInfo);
|
immediateActions.add(actionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapabili
|
|||||||
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
|
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
|
||||||
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
|
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
|
||||||
import work.slhaf.partner.core.action.ActionCapability;
|
import work.slhaf.partner.core.action.ActionCapability;
|
||||||
import work.slhaf.partner.core.action.entity.ImmediateActionInfo;
|
import work.slhaf.partner.core.action.entity.ImmediateActionData;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AgentSubModule
|
@AgentSubModule
|
||||||
public class ActionExecutor extends AgentRunningSubModule<List<ImmediateActionInfo>, Void> {
|
public class ActionExecutor extends AgentRunningSubModule<List<ImmediateActionData>, Void> {
|
||||||
|
|
||||||
@InjectCapability
|
@InjectCapability
|
||||||
private ActionCapability actionCapability;
|
private ActionCapability actionCapability;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void execute(List<ImmediateActionInfo> immediateActions) {
|
public Void execute(List<ImmediateActionData> immediateActions) {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package work.slhaf.partner.module.modules.action.dispatcher.scheduler;
|
|||||||
|
|
||||||
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
|
import work.slhaf.partner.api.agent.factory.module.annotation.AgentSubModule;
|
||||||
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
|
import work.slhaf.partner.api.agent.runtime.interaction.flow.abstracts.AgentRunningSubModule;
|
||||||
import work.slhaf.partner.core.action.entity.ScheduledActionInfo;
|
import work.slhaf.partner.core.action.entity.ScheduledActionData;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AgentSubModule
|
@AgentSubModule
|
||||||
public class ActionScheduler extends AgentRunningSubModule<List<ScheduledActionInfo>, Void> {
|
public class ActionScheduler extends AgentRunningSubModule<List<ScheduledActionData>, Void> {
|
||||||
@Override
|
@Override
|
||||||
public Void execute(List<ScheduledActionInfo> data) {
|
public Void execute(List<ScheduledActionData> data) {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ import work.slhaf.partner.api.chat.pojo.Message;
|
|||||||
import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor;
|
import work.slhaf.partner.common.thread.InteractionThreadPoolExecutor;
|
||||||
import work.slhaf.partner.common.vector.VectorClient;
|
import work.slhaf.partner.common.vector.VectorClient;
|
||||||
import work.slhaf.partner.core.action.ActionCapability;
|
import work.slhaf.partner.core.action.ActionCapability;
|
||||||
import work.slhaf.partner.core.action.entity.ActionInfo;
|
import work.slhaf.partner.core.action.entity.ActionData;
|
||||||
import work.slhaf.partner.core.action.entity.ActionStatus;
|
import work.slhaf.partner.core.action.entity.ImmediateActionData;
|
||||||
import work.slhaf.partner.core.action.entity.ImmediateActionInfo;
|
import work.slhaf.partner.core.action.entity.ScheduledActionData;
|
||||||
import work.slhaf.partner.core.action.entity.ScheduledActionInfo;
|
|
||||||
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
import work.slhaf.partner.core.action.entity.cache.CacheAdjustData;
|
||||||
import work.slhaf.partner.core.action.entity.cache.CacheAdjustMetaData;
|
import work.slhaf.partner.core.action.entity.cache.CacheAdjustMetaData;
|
||||||
import work.slhaf.partner.core.cognation.CognationCapability;
|
import work.slhaf.partner.core.cognation.CognationCapability;
|
||||||
@@ -140,10 +139,10 @@ public class ActionPlanner extends PreRunningModule {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String contextUuid = context.getUuid();
|
String contextUuid = context.getUuid();
|
||||||
List<ActionInfo> pendingActions = actionCapability.popPendingAction(context.getUserId());
|
List<ActionData> pendingActions = actionCapability.popPendingAction(context.getUserId());
|
||||||
for (ActionInfo actionInfo : pendingActions) {
|
for (ActionData actionData : pendingActions) {
|
||||||
if (uuids.contains(actionInfo.getUuid())) {
|
if (uuids.contains(actionData.getUuid())) {
|
||||||
actionCapability.putPreparedAction(contextUuid, actionInfo);
|
actionCapability.putPreparedAction(contextUuid, actionData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,11 +150,11 @@ public class ActionPlanner extends PreRunningModule {
|
|||||||
|
|
||||||
private void setupActionInfo(List<EvaluatorResult> evaluatorResults, PartnerRunningFlowContext context) {
|
private void setupActionInfo(List<EvaluatorResult> evaluatorResults, PartnerRunningFlowContext context) {
|
||||||
for (EvaluatorResult evaluatorResult : evaluatorResults) {
|
for (EvaluatorResult evaluatorResult : evaluatorResults) {
|
||||||
ActionInfo actionInfo = assemblyHelper.buildMetaActionInfo(evaluatorResult);
|
ActionData actionData = assemblyHelper.buildMetaActionInfo(evaluatorResult);
|
||||||
if (evaluatorResult.isNeedConfirm()) {
|
if (evaluatorResult.isNeedConfirm()) {
|
||||||
actionCapability.putPendingActions(context.getUserId(), actionInfo);
|
actionCapability.putPendingActions(context.getUserId(), actionData);
|
||||||
} else {
|
} else {
|
||||||
actionCapability.putPreparedAction(context.getUuid(), actionInfo);
|
actionCapability.putPreparedAction(context.getUuid(), actionData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,31 +169,31 @@ public class ActionPlanner extends PreRunningModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupPendingActions(HashMap<String, String> map, String userId) {
|
private void setupPendingActions(HashMap<String, String> map, String userId) {
|
||||||
List<ActionInfo> actionInfos = actionCapability.listPendingAction(userId);
|
List<ActionData> actionData = actionCapability.listPendingAction(userId);
|
||||||
if (actionInfos == null || actionInfos.isEmpty()) {
|
if (actionData == null || actionData.isEmpty()) {
|
||||||
map.put("[待确认行动] <待确认行动信息>", "无待确认行动");
|
map.put("[待确认行动] <待确认行动信息>", "无待确认行动");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < actionInfos.size(); i++) {
|
for (int i = 0; i < actionData.size(); i++) {
|
||||||
map.put("[待确认行动 " + (i + 1) + " ]", generateActionStr(actionInfos.get(i)));
|
map.put("[待确认行动 " + (i + 1) + " ]", generateActionStr(actionData.get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPreparedActions(HashMap<String, String> map, String uuid) {
|
private void setupPreparedActions(HashMap<String, String> map, String uuid) {
|
||||||
List<ActionInfo> actionInfos = actionCapability.listPreparedAction(uuid);
|
List<ActionData> actionData = actionCapability.listPreparedAction(uuid);
|
||||||
if (actionInfos == null || actionInfos.isEmpty()) {
|
if (actionData == null || actionData.isEmpty()) {
|
||||||
map.put("[预备行动] <预备行动信息>", "无预备行动");
|
map.put("[预备行动] <预备行动信息>", "无预备行动");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < actionInfos.size(); i++) {
|
for (int i = 0; i < actionData.size(); i++) {
|
||||||
map.put("[预备行动 " + (i + 1) + " ]", generateActionStr(actionInfos.get(i)));
|
map.put("[预备行动 " + (i + 1) + " ]", generateActionStr(actionData.get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateActionStr(ActionInfo actionInfo) {
|
private String generateActionStr(ActionData actionData) {
|
||||||
return "<行动倾向>" + " : " + actionInfo.getTendency() +
|
return "<行动倾向>" + " : " + actionData.getTendency() +
|
||||||
"<行动原因>" + " : " + actionInfo.getReason() +
|
"<行动原因>" + " : " + actionData.getReason() +
|
||||||
"<工具描述>" + " : " + actionInfo.getDescription();
|
"<工具描述>" + " : " + actionData.getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -229,20 +228,20 @@ public class ActionPlanner extends PreRunningModule {
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActionInfo buildMetaActionInfo(EvaluatorResult evaluatorResult) {
|
private ActionData buildMetaActionInfo(EvaluatorResult evaluatorResult) {
|
||||||
return switch (evaluatorResult.getType()) {
|
return switch (evaluatorResult.getType()) {
|
||||||
case PLANNING -> {
|
case PLANNING -> {
|
||||||
ScheduledActionInfo actionInfo = new ScheduledActionInfo();
|
ScheduledActionData actionInfo = new ScheduledActionData();
|
||||||
actionInfo.setActionChain(evaluatorResult.getActionChain());
|
actionInfo.setActionChain(evaluatorResult.getActionChain());
|
||||||
actionInfo.setScheduleContent(evaluatorResult.getScheduleContent());
|
actionInfo.setScheduleContent(evaluatorResult.getScheduleContent());
|
||||||
actionInfo.setStatus(ActionStatus.PREPARE);
|
actionInfo.setStatus(ActionData.ActionStatus.PREPARE);
|
||||||
actionInfo.setUuid(UUID.randomUUID().toString());
|
actionInfo.setUuid(UUID.randomUUID().toString());
|
||||||
yield actionInfo;
|
yield actionInfo;
|
||||||
}
|
}
|
||||||
case IMMEDIATE -> {
|
case IMMEDIATE -> {
|
||||||
ImmediateActionInfo actionInfo = new ImmediateActionInfo();
|
ImmediateActionData actionInfo = new ImmediateActionData();
|
||||||
actionInfo.setActionChain(evaluatorResult.getActionChain());
|
actionInfo.setActionChain(evaluatorResult.getActionChain());
|
||||||
actionInfo.setStatus(ActionStatus.PREPARE);
|
actionInfo.setStatus(ActionData.ActionStatus.PREPARE);
|
||||||
actionInfo.setUuid(UUID.randomUUID().toString());
|
actionInfo.setUuid(UUID.randomUUID().toString());
|
||||||
yield actionInfo;
|
yield actionInfo;
|
||||||
}
|
}
|
||||||
@@ -252,8 +251,8 @@ public class ActionPlanner extends PreRunningModule {
|
|||||||
private ConfirmerInput buildConfirmerInput(PartnerRunningFlowContext context) {
|
private ConfirmerInput buildConfirmerInput(PartnerRunningFlowContext context) {
|
||||||
ConfirmerInput confirmerInput = new ConfirmerInput();
|
ConfirmerInput confirmerInput = new ConfirmerInput();
|
||||||
confirmerInput.setInput(context.getInput());
|
confirmerInput.setInput(context.getInput());
|
||||||
List<ActionInfo> pendingActions = actionCapability.listPendingAction(context.getUserId());
|
List<ActionData> pendingActions = actionCapability.listPendingAction(context.getUserId());
|
||||||
confirmerInput.setActionInfos(pendingActions);
|
confirmerInput.setActionData(pendingActions);
|
||||||
return confirmerInput;
|
return confirmerInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package work.slhaf.partner.module.modules.action.planner.confirmer.entity;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import work.slhaf.partner.api.chat.pojo.Message;
|
import work.slhaf.partner.api.chat.pojo.Message;
|
||||||
import work.slhaf.partner.core.action.entity.ActionInfo;
|
import work.slhaf.partner.core.action.entity.ActionData;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class ConfirmerInput {
|
public class ConfirmerInput {
|
||||||
private String input;
|
private String input;
|
||||||
private List<ActionInfo> actionInfos;
|
private List<ActionData> actionData;
|
||||||
private List<Message> recentMessages;
|
private List<Message> recentMessages;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package work.slhaf.partner.module.modules.action.planner.evaluator.entity;
|
package work.slhaf.partner.module.modules.action.planner.evaluator.entity;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import work.slhaf.partner.core.action.entity.ActionType;
|
|
||||||
import work.slhaf.partner.core.action.entity.MetaAction;
|
import work.slhaf.partner.core.action.entity.MetaAction;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -14,4 +13,8 @@ public class EvaluatorResult {
|
|||||||
private String scheduleContent;
|
private String scheduleContent;
|
||||||
private List<MetaAction> actionChain;
|
private List<MetaAction> actionChain;
|
||||||
private String tendency;
|
private String tendency;
|
||||||
|
|
||||||
|
public enum ActionType {
|
||||||
|
IMMEDIATE, PLANNING
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user