mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
refactor(action): redefine ExtractorResult structure to support openai sdk better, and make failed meta-action executing should be recorded as history normally
This commit is contained in:
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="project">
|
<dictionary name="project">
|
||||||
<words>
|
<words>
|
||||||
|
<w>openai</w>
|
||||||
<w>zuper</w>
|
<w>zuper</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
@@ -112,6 +112,12 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
if (value instanceof Number number) {
|
if (value instanceof Number number) {
|
||||||
return number.intValue();
|
return number.intValue();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
if (value instanceof String string) {
|
||||||
|
return Integer.parseInt(string);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
throw new IllegalArgumentException("参数 " + key + " 必须为整数");
|
throw new IllegalArgumentException("参数 " + key + " 必须为整数");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +129,12 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
if (value instanceof Number n) {
|
if (value instanceof Number n) {
|
||||||
return n.intValue();
|
return n.intValue();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
if (value instanceof String string) {
|
||||||
|
return Integer.parseInt(string);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
throw new IllegalArgumentException("参数 " + key + " 必须为整数");
|
throw new IllegalArgumentException("参数 " + key + " 必须为整数");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,13 +304,13 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
private void executeMetaActionWithRetry(MetaAction metaAction, ExecutableAction actionData) {
|
private void executeMetaActionWithRetry(MetaAction metaAction, ExecutableAction actionData) {
|
||||||
AtomicReference<String> failureReason = new AtomicReference<>("参数提取失败");
|
AtomicReference<String> failureReason = new AtomicReference<>("参数提取失败");
|
||||||
val actionKey = metaAction.getKey();
|
val actionKey = metaAction.getKey();
|
||||||
|
int executingStage = actionData.getExecutingStage();
|
||||||
|
boolean succeeded = false;
|
||||||
for (int attempt = 1; attempt <= MAX_EXTRACTOR_ATTEMPTS; attempt++) {
|
for (int attempt = 1; attempt <= MAX_EXTRACTOR_ATTEMPTS; attempt++) {
|
||||||
val result = metaAction.getResult();
|
val result = metaAction.getResult();
|
||||||
result.reset();
|
result.reset();
|
||||||
metaAction.getParams().clear();
|
metaAction.getParams().clear();
|
||||||
|
|
||||||
val executingStage = actionData.getExecutingStage();
|
|
||||||
|
|
||||||
Result<ExtractorInput> extractorInputResult = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription());
|
Result<ExtractorInput> extractorInputResult = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription());
|
||||||
AgentRuntimeException exception = extractorInputResult.exceptionOrNull();
|
AgentRuntimeException exception = extractorInputResult.exceptionOrNull();
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
@@ -331,7 +331,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
failureReason.set(buildAttemptFailureReason("参数提取失败", null));
|
failureReason.set(buildAttemptFailureReason("参数提取失败", null));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
metaAction.getParams().putAll(extractorResult.getParams());
|
metaAction.getParams().putAll(toMetaActionParams(extractorResult.getParams()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runnerClient.submit(metaAction);
|
runnerClient.submit(metaAction);
|
||||||
@@ -341,18 +341,47 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.getStatus() == MetaAction.Result.Status.SUCCESS) {
|
if (result.getStatus() == MetaAction.Result.Status.SUCCESS) {
|
||||||
val historyAction = new HistoryAction(actionKey, resolveHistoryDescription(actionKey), result.getData());
|
succeeded = true;
|
||||||
actionData.getHistory()
|
break;
|
||||||
.computeIfAbsent(executingStage, integer -> new ArrayList<>())
|
|
||||||
.add(historyAction);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
failureReason.set(buildAttemptFailureReason("行动执行失败", result.getData()));
|
failureReason.set(buildAttemptFailureReason("行动执行失败", result.getData()));
|
||||||
}
|
}
|
||||||
|
if (!succeeded) {
|
||||||
metaAction.getResult().setStatus(MetaAction.Result.Status.FAILED);
|
metaAction.getResult().setStatus(MetaAction.Result.Status.FAILED);
|
||||||
metaAction.getResult().setData(failureReason.get());
|
metaAction.getResult().setData(failureReason.get());
|
||||||
}
|
}
|
||||||
|
appendHistoryAction(actionData, executingStage, metaAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> toMetaActionParams(List<ExtractorResult.ParamEntry> params) {
|
||||||
|
if (params == null || params.isEmpty()) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
Map<String, Object> converted = new LinkedHashMap<>();
|
||||||
|
for (ExtractorResult.ParamEntry entry : params) {
|
||||||
|
if (entry == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = entry.getName();
|
||||||
|
if (name == null || name.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
converted.put(name, entry.getValue());
|
||||||
|
}
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendHistoryAction(ExecutableAction actionData, int executingStage, MetaAction metaAction) {
|
||||||
|
HistoryAction historyAction = new HistoryAction(
|
||||||
|
metaAction.getKey(),
|
||||||
|
resolveHistoryDescription(metaAction.getKey()),
|
||||||
|
metaAction.getResult().getData()
|
||||||
|
);
|
||||||
|
actionData.getHistory()
|
||||||
|
.computeIfAbsent(executingStage, integer -> new ArrayList<>())
|
||||||
|
.add(historyAction);
|
||||||
|
}
|
||||||
|
|
||||||
private RecognizerTaskRecord startRecognizerIfNeeded(ExecutableAction executableAction, Phaser phaser) {
|
private RecognizerTaskRecord startRecognizerIfNeeded(ExecutableAction executableAction, Phaser phaser) {
|
||||||
if (!shouldRunCorrectionRecognizer(executableAction)) {
|
if (!shouldRunCorrectionRecognizer(executableAction)) {
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ class ExecutingActionBlockManager {
|
|||||||
|
|
||||||
private @NotNull BlockContent buildActionStageAbstractBlock(ExecutableActionSnapshot snapshot, String blockName, String event) {
|
private @NotNull BlockContent buildActionStageAbstractBlock(ExecutableActionSnapshot snapshot, String blockName, String event) {
|
||||||
int settledStage = snapshot.getExecutingStage();
|
int settledStage = snapshot.getExecutingStage();
|
||||||
List<HistoryAction> history = snapshot.getHistory().get(settledStage);
|
List<HistoryAction> history = resolveStageHistory(snapshot, settledStage);
|
||||||
|
|
||||||
return new ActionBlockContent(blockName, SOURCE) {
|
return new ActionBlockContent(blockName, SOURCE) {
|
||||||
@Override
|
@Override
|
||||||
@@ -252,7 +252,7 @@ class ExecutingActionBlockManager {
|
|||||||
|
|
||||||
private @NotNull BlockContent buildActionStageCompactBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) {
|
private @NotNull BlockContent buildActionStageCompactBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) {
|
||||||
int settledStage = snapshot.getExecutingStage();
|
int settledStage = snapshot.getExecutingStage();
|
||||||
List<HistoryAction> history = snapshot.getHistory().get(settledStage);
|
List<HistoryAction> history = resolveStageHistory(snapshot, settledStage);
|
||||||
|
|
||||||
return new ActionBlockContent(blockName, SOURCE) {
|
return new ActionBlockContent(blockName, SOURCE) {
|
||||||
@Override
|
@Override
|
||||||
@@ -267,7 +267,7 @@ class ExecutingActionBlockManager {
|
|||||||
|
|
||||||
private @NotNull BlockContent buildActionStageFullBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) {
|
private @NotNull BlockContent buildActionStageFullBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) {
|
||||||
int settledStage = snapshot.getExecutingStage();
|
int settledStage = snapshot.getExecutingStage();
|
||||||
List<HistoryAction> history = snapshot.getHistory().get(settledStage);
|
List<HistoryAction> history = resolveStageHistory(snapshot, settledStage);
|
||||||
|
|
||||||
return new ActionBlockContent(blockName, SOURCE) {
|
return new ActionBlockContent(blockName, SOURCE) {
|
||||||
@Override
|
@Override
|
||||||
@@ -312,6 +312,11 @@ class ExecutingActionBlockManager {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<HistoryAction> resolveStageHistory(ExecutableActionSnapshot snapshot, int settledStage) {
|
||||||
|
List<HistoryAction> history = snapshot.getHistory().get(settledStage);
|
||||||
|
return history == null ? List.of() : history;
|
||||||
|
}
|
||||||
|
|
||||||
private @NotNull BlockContent buildActionCorrectionAbstractBlock(ExecutableActionSnapshot snapshot, List<MetaIntervention> interventions, String blockName, String event) {
|
private @NotNull BlockContent buildActionCorrectionAbstractBlock(ExecutableActionSnapshot snapshot, List<MetaIntervention> interventions, String blockName, String event) {
|
||||||
return new ActionBlockContent(blockName, SOURCE) {
|
return new ActionBlockContent(blockName, SOURCE) {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ public class ParamsExtractor extends AbstractAgentModule.Sub<ExtractorInput, Res
|
|||||||
return new TaskBlock() {
|
return new TaskBlock() {
|
||||||
@Override
|
@Override
|
||||||
protected void fillXml(@NotNull Document document, @NotNull Element root) {
|
protected void fillXml(@NotNull Document document, @NotNull Element root) {
|
||||||
appendChildElement(document, root, "target_action", blok -> {
|
appendChildElement(document, root, "target_action", block -> {
|
||||||
appendTextElement(document, blok, "uuid", input.getTargetActionId());
|
appendTextElement(document, block, "uuid", input.getTargetActionId());
|
||||||
appendTextElement(document, blok, "description", input.getTargetActionDesc());
|
appendTextElement(document, block, "description", input.getTargetActionDesc());
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
appendChildElement(document, root, "meta_action_info", element -> {
|
appendChildElement(document, root, "meta_action_info", element -> {
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
package work.slhaf.partner.module.action.executor.entity;
|
package work.slhaf.partner.module.action.executor.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class ExtractorResult {
|
public class ExtractorResult {
|
||||||
private boolean ok;
|
private boolean ok;
|
||||||
private Map<String, Object> params;
|
private List<ParamEntry> params;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class ParamEntry {
|
||||||
|
private String name;
|
||||||
|
private String value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package work.slhaf.partner.module.action.executor;
|
package work.slhaf.partner.module.action.executor;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import work.slhaf.partner.core.action.ActionCapability;
|
import work.slhaf.partner.core.action.ActionCapability;
|
||||||
import work.slhaf.partner.core.action.ActionCore;
|
import work.slhaf.partner.core.action.ActionCore;
|
||||||
@@ -14,6 +16,7 @@ import work.slhaf.partner.module.action.executor.entity.ExtractorResult;
|
|||||||
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -29,6 +32,11 @@ class ActionExecutorTest {
|
|||||||
|
|
||||||
private final List<ExecutorService> executors = new ArrayList<>();
|
private final List<ExecutorService> executors = new ArrayList<>();
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void beforeAll(@TempDir Path tempDir) {
|
||||||
|
System.setProperty("user.home", tempDir.toAbsolutePath().toString());
|
||||||
|
}
|
||||||
|
|
||||||
private static void inject(Object target, String fieldName, Object value) throws Exception {
|
private static void inject(Object target, String fieldName, Object value) throws Exception {
|
||||||
Field field = ActionExecutor.class.getDeclaredField(fieldName);
|
Field field = ActionExecutor.class.getDeclaredField(fieldName);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
@@ -137,7 +145,7 @@ class ActionExecutorTest {
|
|||||||
|
|
||||||
ExtractorResult extractorResult = new ExtractorResult();
|
ExtractorResult extractorResult = new ExtractorResult();
|
||||||
extractorResult.setOk(true);
|
extractorResult.setOk(true);
|
||||||
extractorResult.setParams(Map.of("fresh", "value"));
|
extractorResult.setParams(List.of(new ExtractorResult.ParamEntry("fresh", "value")));
|
||||||
when(paramsExtractor.execute(any())).thenReturn(Result.success(extractorResult));
|
when(paramsExtractor.execute(any())).thenReturn(Result.success(extractorResult));
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
MetaAction metaAction = invocation.getArgument(0);
|
MetaAction metaAction = invocation.getArgument(0);
|
||||||
@@ -242,6 +250,9 @@ class ActionExecutorTest {
|
|||||||
assertEquals(MetaAction.Result.Status.FAILED, metaAction.getResult().getStatus());
|
assertEquals(MetaAction.Result.Status.FAILED, metaAction.getResult().getStatus());
|
||||||
assertTrue(metaAction.getResult().getData().contains("missing"));
|
assertTrue(metaAction.getResult().getData().contains("missing"));
|
||||||
assertEquals(metaAction.getResult().getData(), action.getResult());
|
assertEquals(metaAction.getResult().getData(), action.getResult());
|
||||||
|
assertEquals(1, action.getHistory().size());
|
||||||
|
assertTrue(action.getHistory().containsKey(1));
|
||||||
|
assertEquals(metaAction.getResult().getData(), action.getHistory().get(1).getFirst().result());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -282,7 +293,7 @@ class ActionExecutorTest {
|
|||||||
|
|
||||||
ExtractorResult extractorResult = new ExtractorResult();
|
ExtractorResult extractorResult = new ExtractorResult();
|
||||||
extractorResult.setOk(true);
|
extractorResult.setOk(true);
|
||||||
extractorResult.setParams(Map.of("fresh", "value"));
|
extractorResult.setParams(List.of(new ExtractorResult.ParamEntry("fresh", "value")));
|
||||||
when(paramsExtractor.execute(any())).thenReturn(Result.success(extractorResult));
|
when(paramsExtractor.execute(any())).thenReturn(Result.success(extractorResult));
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
MetaAction metaAction = invocation.getArgument(0);
|
MetaAction metaAction = invocation.getArgument(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user