mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
feat(LocalRunnerClient): support overflow event in DynamicActionMcpServer
This commit is contained in:
@@ -38,15 +38,13 @@ import java.io.InputStreamReader;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static work.slhaf.partner.common.util.PathUtil.buildPathStr;
|
import static work.slhaf.partner.common.util.PathUtil.buildPathStr;
|
||||||
@@ -548,10 +546,7 @@ public class LocalRunnerClient extends RunnerClient {
|
|||||||
@NotNull
|
@NotNull
|
||||||
protected LocalWatchServiceBuild.InitLoader buildLoad() {
|
protected LocalWatchServiceBuild.InitLoader buildLoad() {
|
||||||
// 从该路径列出已存在的目录,每个目录对应不同的行动程序及描述文件,从描述文件加载程序信息
|
// 从该路径列出已存在的目录,每个目录对应不同的行动程序及描述文件,从描述文件加载程序信息
|
||||||
return this::load;
|
return () -> {
|
||||||
}
|
|
||||||
|
|
||||||
private void load() {
|
|
||||||
Path root = ctx.root;
|
Path root = ctx.root;
|
||||||
File file = root.toFile();
|
File file = root.toFile();
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
@@ -565,9 +560,9 @@ public class LocalRunnerClient extends RunnerClient {
|
|||||||
if (!normalPath(dir.toPath())) {
|
if (!normalPath(dir.toPath())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction(dir.getName(), dir.toPath());
|
addAction(dir.getName(), dir.toPath());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private McpStatelessServerFeatures.AsyncToolSpecification buildAsyncToolSpecification(MetaActionInfo info, File program, String actionKey, String name) {
|
private McpStatelessServerFeatures.AsyncToolSpecification buildAsyncToolSpecification(MetaActionInfo info, File program, String actionKey, String name) {
|
||||||
@@ -703,7 +698,56 @@ public class LocalRunnerClient extends RunnerClient {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
protected LocalWatchServiceBuild.EventHandler buildOverflow() {
|
protected LocalWatchServiceBuild.EventHandler buildOverflow() {
|
||||||
return null;
|
return (thisDir, context) -> {
|
||||||
|
// 直接从 existedMetaActions 中拿取现有的 key,上游也从这里发现可用工具
|
||||||
|
Set<String> existed = existedMetaActions.keySet().stream().map(actionKey -> actionKey.split("::")[1]).collect(Collectors.toSet());
|
||||||
|
Set<String> currentDirs = new HashSet<>();
|
||||||
|
// 按照预期 root 目录下有效 path 只包括各个 action 目录
|
||||||
|
// 排除非目录 path
|
||||||
|
try (Stream<Path> stream = Files.list(ctx.root).filter(Files::isDirectory)) {
|
||||||
|
stream.forEach(path -> {
|
||||||
|
String name = path.getFileName().toString();
|
||||||
|
currentDirs.add(name);
|
||||||
|
|
||||||
|
boolean contains = existed.contains(name);
|
||||||
|
boolean normal = normalPath(path);
|
||||||
|
|
||||||
|
// 如果该目录对应 action 已被记录,且符合 action 目录要求,则无处理
|
||||||
|
// 如果已被记录,但不符合,则移除行动
|
||||||
|
// 此时必定被监听
|
||||||
|
if (contains && !normal) {
|
||||||
|
removeAction(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 action 没有记录,但符合要求,由于此时必定尚未被监听,则注册监听且添加新 action
|
||||||
|
// 如果未被记录,且不符合要求,则只注册监听
|
||||||
|
if (!contains) {
|
||||||
|
boolean alreadyWatching = ctx.watchKeys.values().stream()
|
||||||
|
.anyMatch(p -> p.equals(path));
|
||||||
|
if (!alreadyWatching) {
|
||||||
|
try {
|
||||||
|
WatchKey watchKey = path.register(ctx.watchService, ctx.kinds.toArray(WatchEvent.Kind[]::new));
|
||||||
|
ctx.watchKeys.put(watchKey, path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("监听目录注册失败: {}", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normal) {
|
||||||
|
addAction(name, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("目录无法读取: {}", ctx.root);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String existedName : existed) {
|
||||||
|
if (!currentDirs.contains(existedName)) {
|
||||||
|
removeAction(existedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user