fix(runner): repair MetaAction related logic in McpMetaRegistry and tests

This commit is contained in:
2026-03-14 21:44:27 +08:00
parent cba9ff4f0b
commit 4c47cac3a5
5 changed files with 122 additions and 81 deletions

View File

@@ -99,7 +99,7 @@ public class McpMetaRegistry implements AutoCloseable {
} }
MetaActionInfo info = existedMetaActions.get(actionKey); MetaActionInfo info = existedMetaActions.get(actionKey);
if (info != null) { if (info != null) {
resetMetaActionInfo(info); existedMetaActions.put(actionKey, resetMetaActionInfo(info));
} }
} }
@@ -172,18 +172,18 @@ public class McpMetaRegistry implements AutoCloseable {
return root.toFile().listFiles(); return root.toFile().listFiles();
} }
private void resetMetaActionInfo(@NotNull MetaActionInfo info) { private MetaActionInfo resetMetaActionInfo(@NotNull MetaActionInfo info) {
info.setIo(false); return new MetaActionInfo(
if (info.getTags() != null) { false,
info.getTags().clear(); info.getLauncher(),
} copyParams(info.getParams()),
if (info.getPreActions() != null) { info.getDescription(),
info.getPreActions().clear(); new LinkedHashSet<>(),
} new LinkedHashSet<>(),
if (info.getPostActions() != null) { new LinkedHashSet<>(),
info.getPostActions().clear(); false,
} copyResponseSchema(info.getResponseSchema())
info.setStrictDependencies(false); );
} }
@Override @Override
@@ -192,22 +192,32 @@ public class McpMetaRegistry implements AutoCloseable {
} }
private MetaActionInfo buildToolMetaActionInfo(McpSchema.Tool tool) { private MetaActionInfo buildToolMetaActionInfo(McpSchema.Tool tool) {
MetaActionInfo info = new MetaActionInfo();
info.setDescription(tool.description());
Map<String, Object> outputSchema = tool.outputSchema(); Map<String, Object> outputSchema = tool.outputSchema();
info.setResponseSchema(outputSchema == null ? JSONObject.of() : JSONObject.from(outputSchema)); boolean io = false;
info.setParams(tool.inputSchema().properties()); Set<String> preActions = new LinkedHashSet<>();
Set<String> postActions = new LinkedHashSet<>();
boolean strictDependencies = false;
Set<String> tags = new LinkedHashSet<>();
Map<String, Object> meta = tool.meta(); Map<String, Object> meta = tool.meta();
if (meta != null) { if (meta != null) {
JSONObject metaJson = JSONObject.from(meta); JSONObject metaJson = JSONObject.from(meta);
info.setIo(Boolean.TRUE.equals(metaJson.getBoolean("io"))); io = Boolean.TRUE.equals(metaJson.getBoolean("io"));
info.setPreActions(metaJson.getList("pre", String.class)); preActions = toOrderedSet(metaJson.getList("pre", String.class));
info.setPostActions(metaJson.getList("post", String.class)); postActions = toOrderedSet(metaJson.getList("post", String.class));
info.setStrictDependencies(Boolean.TRUE.equals(metaJson.getBoolean("strict"))); strictDependencies = Boolean.TRUE.equals(metaJson.getBoolean("strict"));
info.setTags(metaJson.getList("tag", String.class)); tags = toOrderedSet(metaJson.getList("tag", String.class));
} }
return info; return new MetaActionInfo(
io,
null,
copyParams(tool.inputSchema().properties()),
tool.description(),
tags,
preActions,
postActions,
strictDependencies,
outputSchema == null ? JSONObject.of() : JSONObject.from(outputSchema)
);
} }
private MetaActionInfo mergeWithOriginal(String actionKey, MetaActionInfo override) { private MetaActionInfo mergeWithOriginal(String actionKey, MetaActionInfo override) {
@@ -219,15 +229,33 @@ public class McpMetaRegistry implements AutoCloseable {
if (source == null) { if (source == null) {
return null; return null;
} }
MetaActionInfo copy = new MetaActionInfo(); return new MetaActionInfo(
copy.setIo(source.isIo()); source.getIo(),
copy.setParams(source.getParams() == null ? null : new HashMap<>(source.getParams())); source.getLauncher(),
copy.setDescription(source.getDescription()); copyParams(source.getParams()),
copy.setTags(source.getTags() == null ? new ArrayList<>() : new ArrayList<>(source.getTags())); source.getDescription(),
copy.setPreActions(source.getPreActions() == null ? new ArrayList<>() : new ArrayList<>(source.getPreActions())); toOrderedSet(source.getTags()),
copy.setPostActions(source.getPostActions() == null ? new ArrayList<>() : new ArrayList<>(source.getPostActions())); toOrderedSet(source.getPreActions()),
copy.setStrictDependencies(source.isStrictDependencies()); toOrderedSet(source.getPostActions()),
copy.setResponseSchema(source.getResponseSchema() == null ? JSONObject.of() : JSONObject.from(source.getResponseSchema())); source.getStrictDependencies(),
return copy; copyResponseSchema(source.getResponseSchema())
);
}
private <T> LinkedHashSet<T> toOrderedSet(Collection<T> source) {
return source == null ? new LinkedHashSet<>() : new LinkedHashSet<>(source);
}
private Map<String, String> copyParams(Map<String, ?> params) {
if (params == null) {
return null;
}
Map<String, String> copied = new LinkedHashMap<>();
params.forEach((key, value) -> copied.put(key, value == null ? null : String.valueOf(value)));
return copied;
}
private JSONObject copyResponseSchema(JSONObject responseSchema) {
return responseSchema == null ? JSONObject.of() : JSONObject.from(responseSchema);
} }
} }

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.core.action.runner; package work.slhaf.partner.core.action.runner;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -142,15 +143,17 @@ public class LocalRunnerClientTest {
} }
static MetaActionInfo buildMetaActionInfo(String description) { static MetaActionInfo buildMetaActionInfo(String description) {
MetaActionInfo info = new MetaActionInfo(); return new MetaActionInfo(
info.setIo(true); true,
info.setParams(new HashMap<>()); null,
info.setDescription(description); new HashMap<>(),
info.setTags(new ArrayList<>(List.of("tag"))); description,
info.setPreActions(new ArrayList<>(List.of("pre"))); new LinkedHashSet<>(List.of("tag")),
info.setPostActions(new ArrayList<>(List.of("post"))); new LinkedHashSet<>(List.of("pre")),
info.setStrictDependencies(true); new LinkedHashSet<>(List.of("post")),
return info; true,
new JSONObject()
);
} }
static String buildCommonMcpConfig(String... serverEntries) { static String buildCommonMcpConfig(String... serverEntries) {
@@ -181,6 +184,7 @@ public class LocalRunnerClientTest {
MetaAction metaAction = new MetaAction( MetaAction metaAction = new MetaAction(
name, name,
false, false,
null,
type, type,
location location
); );
@@ -402,8 +406,8 @@ public class LocalRunnerClientTest {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertEquals("v1", info.getDescription()); Assertions.assertEquals("v1", info.getDescription());
Assertions.assertTrue(info.isIo()); Assertions.assertTrue(info.getIo());
Assertions.assertTrue(info.isStrictDependencies()); Assertions.assertTrue(info.getStrictDependencies());
Assertions.assertFalse(info.getTags().isEmpty()); Assertions.assertFalse(info.getTags().isEmpty());
writeDescMcpJson(descDir, actionKey, "v2"); writeDescMcpJson(descDir, actionKey, "v2");
@@ -419,16 +423,16 @@ public class LocalRunnerClientTest {
waitForCondition(() -> { waitForCondition(() -> {
MetaActionInfo current = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo current = getMetaActionInfo(existedMetaActions, actionKey);
return current != null return current != null
&& !current.isIo() && !current.getIo()
&& !current.isStrictDependencies() && !current.getStrictDependencies()
&& current.getTags().isEmpty() && current.getTags().isEmpty()
&& current.getPreActions().isEmpty() && current.getPreActions().isEmpty()
&& current.getPostActions().isEmpty(); && current.getPostActions().isEmpty();
}, 2000); }, 2000);
info = getMetaActionInfo(existedMetaActions, actionKey); info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertFalse(info.isIo()); Assertions.assertFalse(info.getIo());
Assertions.assertFalse(info.isStrictDependencies()); Assertions.assertFalse(info.getStrictDependencies());
Assertions.assertTrue(info.getTags().isEmpty()); Assertions.assertTrue(info.getTags().isEmpty());
Assertions.assertTrue(info.getPreActions().isEmpty()); Assertions.assertTrue(info.getPreActions().isEmpty());
Assertions.assertTrue(info.getPostActions().isEmpty()); Assertions.assertTrue(info.getPostActions().isEmpty());
@@ -453,16 +457,16 @@ public class LocalRunnerClientTest {
waitForCondition(() -> { waitForCondition(() -> {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
return info != null return info != null
&& !info.isIo() && !info.getIo()
&& !info.isStrictDependencies() && !info.getStrictDependencies()
&& info.getTags().isEmpty() && info.getTags().isEmpty()
&& info.getPreActions().isEmpty() && info.getPreActions().isEmpty()
&& info.getPostActions().isEmpty(); && info.getPostActions().isEmpty();
}, 2000); }, 2000);
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertFalse(info.isIo()); Assertions.assertFalse(info.getIo());
Assertions.assertFalse(info.isStrictDependencies()); Assertions.assertFalse(info.getStrictDependencies());
Assertions.assertTrue(info.getTags().isEmpty()); Assertions.assertTrue(info.getTags().isEmpty());
Assertions.assertTrue(info.getPreActions().isEmpty()); Assertions.assertTrue(info.getPreActions().isEmpty());
Assertions.assertTrue(info.getPostActions().isEmpty()); Assertions.assertTrue(info.getPostActions().isEmpty());
@@ -475,8 +479,8 @@ public class LocalRunnerClientTest {
info = getMetaActionInfo(existedMetaActions, actionKey); info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertEquals("fixed", info.getDescription()); Assertions.assertEquals("fixed", info.getDescription());
Assertions.assertTrue(info.isIo()); Assertions.assertTrue(info.getIo());
Assertions.assertTrue(info.isStrictDependencies()); Assertions.assertTrue(info.getStrictDependencies());
} finally { } finally {
executor.shutdownNow(); executor.shutdownNow();
} }
@@ -501,7 +505,7 @@ public class LocalRunnerClientTest {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertEquals("base", info.getDescription()); Assertions.assertEquals("base", info.getDescription());
Assertions.assertTrue(info.isIo()); Assertions.assertTrue(info.getIo());
Assertions.assertEquals(1, existedMetaActions.size()); Assertions.assertEquals(1, existedMetaActions.size());
} finally { } finally {
executor.shutdownNow(); executor.shutdownNow();
@@ -545,16 +549,16 @@ public class LocalRunnerClientTest {
waitForCondition(() -> { waitForCondition(() -> {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
return info != null return info != null
&& !info.isIo() && !info.getIo()
&& !info.isStrictDependencies() && !info.getStrictDependencies()
&& info.getTags().isEmpty() && info.getTags().isEmpty()
&& info.getPreActions().isEmpty() && info.getPreActions().isEmpty()
&& info.getPostActions().isEmpty(); && info.getPostActions().isEmpty();
}, 2000); }, 2000);
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
Assertions.assertNotNull(info); Assertions.assertNotNull(info);
Assertions.assertFalse(info.isIo()); Assertions.assertFalse(info.getIo());
Assertions.assertFalse(info.isStrictDependencies()); Assertions.assertFalse(info.getStrictDependencies());
Assertions.assertTrue(info.getTags().isEmpty()); Assertions.assertTrue(info.getTags().isEmpty());
Assertions.assertTrue(info.getPreActions().isEmpty()); Assertions.assertTrue(info.getPreActions().isEmpty());
Assertions.assertTrue(info.getPostActions().isEmpty()); Assertions.assertTrue(info.getPostActions().isEmpty());
@@ -585,8 +589,8 @@ public class LocalRunnerClientTest {
waitForCondition(() -> { waitForCondition(() -> {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
return info != null return info != null
&& !info.isIo() && !info.getIo()
&& !info.isStrictDependencies() && !info.getStrictDependencies()
&& info.getTags().isEmpty() && info.getTags().isEmpty()
&& info.getPreActions().isEmpty() && info.getPreActions().isEmpty()
&& info.getPostActions().isEmpty(); && info.getPostActions().isEmpty();
@@ -628,8 +632,8 @@ public class LocalRunnerClientTest {
waitForCondition(() -> { waitForCondition(() -> {
MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey); MetaActionInfo info = getMetaActionInfo(existedMetaActions, actionKey);
return info != null return info != null
&& !info.isIo() && !info.getIo()
&& !info.isStrictDependencies() && !info.getStrictDependencies()
&& info.getTags().isEmpty() && info.getTags().isEmpty()
&& info.getPreActions().isEmpty() && info.getPreActions().isEmpty()
&& info.getPostActions().isEmpty(); && info.getPostActions().isEmpty();

View File

@@ -1,6 +1,4 @@
package work.slhaf.partner.core.action.runner; package work.slhaf.partner.core.action.runner;
import com.alibaba.fastjson2.JSONObject;
import work.slhaf.partner.core.action.entity.ActionFileMetaData; import work.slhaf.partner.core.action.entity.ActionFileMetaData;
import work.slhaf.partner.core.action.entity.MetaAction; import work.slhaf.partner.core.action.entity.MetaAction;
import work.slhaf.partner.core.action.entity.MetaActionInfo; import work.slhaf.partner.core.action.entity.MetaActionInfo;
@@ -36,10 +34,5 @@ public class RunnerClientTest {
public void persistSerialize(MetaActionInfo metaActionInfo, ActionFileMetaData fileMetaData) { public void persistSerialize(MetaActionInfo metaActionInfo, ActionFileMetaData fileMetaData) {
} }
@Override
public JSONObject listSysDependencies() {
return null;
}
} }
} }

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.module.modules.action.builtin; package work.slhaf.partner.module.modules.action.builtin;
import com.alibaba.fastjson2.JSONObject;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import work.slhaf.partner.core.action.ActionCapability; import work.slhaf.partner.core.action.ActionCapability;
@@ -12,6 +13,7 @@ import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@@ -34,10 +36,17 @@ class BuiltinActionRegistryTest {
} }
private static MetaActionInfo buildMetaActionInfo(String description) { private static MetaActionInfo buildMetaActionInfo(String description) {
MetaActionInfo info = new MetaActionInfo(); return new MetaActionInfo(
info.setDescription(description); false,
info.setParams(new HashMap<>()); null,
return info; new HashMap<>(),
description,
Set.of(),
Set.of(),
Set.of(),
false,
new JSONObject()
);
} }
@Test @Test

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.module.modules.action.dispatcher.executor; package work.slhaf.partner.module.modules.action.dispatcher.executor;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import lombok.val; import lombok.val;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
@@ -77,12 +78,17 @@ class ActionExecutorTest {
lenient().when(memoryCapability.getActivatedSlices()).thenReturn(Collections.emptyList()); lenient().when(memoryCapability.getActivatedSlices()).thenReturn(Collections.emptyList());
lenient().when(actionCapability.putPhaserRecord(any(Phaser.class), any(ExecutableAction.class))) lenient().when(actionCapability.putPhaserRecord(any(Phaser.class), any(ExecutableAction.class)))
.thenAnswer(inv -> new PhaserRecord(inv.getArgument(0), inv.getArgument(1))); .thenAnswer(inv -> new PhaserRecord(inv.getArgument(0), inv.getArgument(1)));
lenient().when(actionCapability.loadMetaActionInfo(anyString())).thenAnswer(inv -> { lenient().when(actionCapability.loadMetaActionInfo(anyString())).thenAnswer(inv -> new MetaActionInfo(
MetaActionInfo info = new MetaActionInfo(); false,
info.setDescription("desc"); null,
info.setParams(Collections.emptyMap()); Collections.emptyMap(),
return info; "desc",
}); Set.of(),
Set.of(),
Set.of(),
false,
new JSONObject()
));
CorrectorResult correctorResult = new CorrectorResult(); CorrectorResult correctorResult = new CorrectorResult();
correctorResult.setMetaInterventionList(Collections.emptyList()); correctorResult.setMetaInterventionList(Collections.emptyList());
lenient().when(actionCorrector.execute(any())).thenReturn(correctorResult); lenient().when(actionCorrector.execute(any())).thenReturn(correctorResult);
@@ -385,6 +391,7 @@ class ActionExecutorTest {
return new MetaAction( return new MetaAction(
name, name,
io, io,
null,
MetaAction.Type.ORIGIN, MetaAction.Type.ORIGIN,
"location" "location"
); );