refactor(action): optimize builtin actions descriptions and param explanations

This commit is contained in:
2026-04-21 21:31:23 +08:00
parent aa05d3817b
commit 3a5d0f1cb4
6 changed files with 107 additions and 68 deletions

View File

@@ -6,4 +6,9 @@ interface BuiltinActionProvider {
List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions(); List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions();
String createActionKey(String actionName); String createActionKey(String actionName);
default String param(String requirement, String type, String detail) {
return requirement + "|" + type + "|" + detail;
}
} }

View File

@@ -49,11 +49,10 @@ class BuiltinCapabilityActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"unit_id", "The id of the memory unit that contains the target memory slice.", "unit_id", param("required", "string", "Memory unit id that contains the target memory slice."),
"slice_id", "The id of the memory slice to recall into context." "slice_id", param("required", "string", "Memory slice id to load into short-lived context.")
), ),
"Recall the target memory slice into context using its unit_id and slice_id. " + "Purpose: bring a known memory slice back into the agent's working context so later reasoning can use the original conversation messages. Use when: the exact memory unit and slice have already been identified. Input: memory slice id and memory unit id. Does not: search, rank, summarize, or infer memories. Returns: whether the slice was recalled and a short result message.",
"This action loads the slice's original conversation messages as a short-lived recalled memory context block.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),
@@ -125,10 +124,10 @@ class BuiltinCapabilityActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"input", "Input required to initiate an internal Agent Turn.", "input", param("required", "string", "Prompt content for the internal Agent Turn."),
"target", "The people expected to reply to this internal Agent Turn." "target", param("required", "string", "Target user expected to receive/respond to the turn.")
), ),
"Create an internal Agent Turn to resolve a task.", "Purpose: initiate a self-dialogue or proactive dialogue by sending input to a target participant. Use when: the agent needs to start a new turn for reflection, clarification, coordination, or active communication. Input: input content and the user expected to respond. Returns: confirmation that the turn was initiated. Does not: wait for or include the target's answer.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),

View File

@@ -7,14 +7,14 @@ import work.slhaf.partner.core.action.runner.execution.CommandExecutionService;
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry; import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec; import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
import java.time.Instant;
import java.time.Duration;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function; import java.util.function.Function;
@@ -38,6 +38,22 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>();
private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE; private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE;
private Map<String, String> commandParams() {
Map<String, String> params = new LinkedHashMap<>();
params.put("arg", param("required", "string", "Command executable name or path."));
params.put("arg1", param("optional", "string", "First command argument after the executable."));
params.put("arg2", param("optional", "string", "Second command argument after the executable."));
params.put("argN", param("optional", "string", "Additional command arguments after arg2. Use consecutive numeric keys such as arg3, arg4, arg5, ... when more arguments are needed."));
return params;
}
private Map<String, String> commandSessionParams() {
Map<String, String> params = new LinkedHashMap<>();
params.put("desc", param("required", "string", "Short human-readable description of why this background command session exists."));
params.putAll(commandParams());
return params;
}
@Override @Override
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() { public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
return List.of( return List.of(
@@ -61,8 +77,8 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
MetaActionInfo info = new MetaActionInfo( MetaActionInfo info = new MetaActionInfo(
false, false,
null, null,
Map.of("arg / argN", "Command arguments. Use arg for first argument, arg1/arg2... for remaining arguments."), commandParams(),
"Execute any allowed system commands and get result instantly, the number of arguments is not limited.", "Purpose: execute a short, non-interactive system command synchronously and return its completed output. Inputs: argv entries through arg/argN. Returns: JSON with result containing stdout/stderr/exit summary text. Use when: the task can finish quickly in one process call. Notes: do not use for long-running services, interactive programs, streaming output, or processes that need later inspection.",
tags, tags,
Set.of(), Set.of(),
Set.of(createActionKey("inspect")), Set.of(createActionKey("inspect")),
@@ -92,11 +108,8 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
MetaActionInfo info = new MetaActionInfo( MetaActionInfo info = new MetaActionInfo(
false, false,
null, null,
Map.of( commandSessionParams(),
"desc", "Command session description.", "Purpose: start a long-running or streaming command as a background session. Inputs: session description and argument entries. Returns: JSON with executionId; pass it as id to inspect, read, or cancel. Use when: the command may run for a while, produce incremental output, or need later control. Notes: usually follow with builtin::command::inspect or builtin::command::read.",
"arg / argN", "Command arguments. Use arg for first argument, arg1/arg2... for remaining arguments."
),
"Start a background command session and return execution id.",
tags, tags,
Set.of(), Set.of(),
Set.of(createActionKey("inspect")), Set.of(createActionKey("inspect")),
@@ -145,8 +158,8 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
MetaActionInfo info = new MetaActionInfo( MetaActionInfo info = new MetaActionInfo(
false, false,
null, null,
Map.of("id", "Command session id."), Map.of("id", param("required", "string", "Command executionId returned by builtin::command::start.")),
"Inspect a background command session.", "Purpose: inspect status and short output summaries for an existing background command session. Inputs: id from command::start. Returns: JSON with executionId, desc, exitCode, stdoutSize, stderrSize, stdoutSummary, stderrSummary, startAt, and endAt. Use when: deciding whether a background command is still running, failed, or needs a full output read. Notes: use builtin::command::read for complete or paginated output.",
tags, tags,
Set.of(createActionKey("overview")), Set.of(createActionKey("overview")),
Set.of(), Set.of(),
@@ -195,12 +208,12 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"id", "Command execution session id.", "id", param("required", "string", "Command executionId returned by builtin::command::start."),
"stream", "Target stream, stdout or stderr. Default stdout.", "stream", param("optional", "string", "Target stream to read. Allowed values: stdout, stderr. Default: stdout."),
"offset", "Read start offset. Default 0.", "offset", param("optional", "int", "Start byte offset in the persisted stream log. Default: 0. Use nextOffset from a previous read to continue."),
"limit", "Read max length. Default 4096." "limit", param("optional", "int", "Maximum bytes to read from the persisted stream log. Default: 4096. Must be greater than 0.")
), ),
"Read output from a background command session.", "Purpose: read stdout or stderr content from a background command session with offset pagination. Returns: JSON with content, contentTruncated, nextOffset, and eof. Use when: inspect summaries are insufficient or a command failed and stderr/stdout details are needed. Notes: repeat with nextOffset until eof or enough evidence is collected.",
tags, tags,
Set.of(createActionKey("overview")), Set.of(createActionKey("overview")),
Set.of(), Set.of(),
@@ -263,8 +276,8 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
MetaActionInfo info = new MetaActionInfo( MetaActionInfo info = new MetaActionInfo(
false, false,
null, null,
Map.of("id", "Command session id."), Map.of("id", param("required", "string", "Command executionId returned by builtin::command::start.")),
"Cancel a background command session.", "Purpose: terminate an existing background command session. Inputs: id from command::start. Returns: JSON with ok and executionId. Use when: the user explicitly asks to stop a command, or correction determines the running command is wrong, stuck, unsafe, or no longer needed. Notes: this has process side effects and should not be used as a status check.",
tags, tags,
Set.of(), Set.of(),
Set.of(createActionKey("overview")), Set.of(createActionKey("overview")),
@@ -316,16 +329,16 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of(), Map.of(),
"List all background command sessions.", "Purpose: list known background command sessions. Inputs: none. Returns: JSON with result array of session overviews containing executionId, desc, and exitCode. Use when: an id is missing or correction needs to discover active command sessions before inspect/read/cancel. Notes: this does not start, stop, or read a command.",
tags, tags,
Set.of(createActionKey("start")), Set.of(createActionKey("start")),
Set.of(createActionKey("inspect"), createActionKey("read"), createActionKey("cancel")), Set.of(createActionKey("inspect"), createActionKey("read"), createActionKey("cancel")),
false, false,
JSONObject.of( JSONObject.of(
"commands", "Array of command session overview items.", "result", "Array of command session overview items.",
"command.executionId", "Command execution session id for each overview item.", "result[].executionId", "Command execution session id for each overview item.",
"command.desc", "Command session description for each overview item.", "result[].desc", "Command session description for each overview item.",
"command.exitCode", "Process exit code for each overview item. Null when still running." "result[].exitCode", "Process exit code for each overview item. Null when still running."
) )
); );
Function<Map<String, Object>, String> invoker = params -> { Function<Map<String, Object>, String> invoker = params -> {
@@ -492,30 +505,36 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
} }
private List<String> requireCommandArguments(Map<String, Object> params) { private List<String> requireCommandArguments(Map<String, Object> params) {
List<Map.Entry<String, Object>> entries = params.entrySet().stream() List<Map.Entry<String, Object>> unexpectedArgs = params.entrySet().stream()
.filter(entry -> entry.getKey().startsWith(COMMAND_ARG_PREFIX)) .filter(entry -> entry.getKey().startsWith(COMMAND_ARG_PREFIX))
.sorted(Comparator.comparingInt(entry -> commandArgIndex(entry.getKey()))) .filter(entry -> !COMMAND_ARG_PREFIX.equals(entry.getKey()) && !isNumberedCommandArg(entry.getKey()))
.toList(); .toList();
if (entries.isEmpty()) { if (!unexpectedArgs.isEmpty()) {
throw new IllegalArgumentException("缺少命令参数"); throw new IllegalArgumentException("非法命令参数: " + unexpectedArgs.getFirst().getKey());
} }
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
for (Map.Entry<String, Object> entry : entries) { commands.add(BuiltinActionRegistry.BuiltinActionDefinition.requireString(params, COMMAND_ARG_PREFIX));
commands.add(BuiltinActionRegistry.BuiltinActionDefinition.requireString(params, entry.getKey())); params.entrySet().stream()
} .filter(entry -> isNumberedCommandArg(entry.getKey()))
.sorted(Comparator.comparingInt(entry -> commandArgIndex(entry.getKey())))
.forEach(entry -> commands.add(BuiltinActionRegistry.BuiltinActionDefinition.requireString(params, entry.getKey())));
return commands; return commands;
} }
private int commandArgIndex(String key) { private boolean isNumberedCommandArg(String key) {
if (!key.startsWith(COMMAND_ARG_PREFIX) || COMMAND_ARG_PREFIX.equals(key)) {
return false;
}
String suffix = key.substring(COMMAND_ARG_PREFIX.length()).trim(); String suffix = key.substring(COMMAND_ARG_PREFIX.length()).trim();
if (suffix.isEmpty()) { if (suffix.isEmpty()) {
return 0; return false;
} }
try { return suffix.chars().allMatch(Character::isDigit);
return Integer.parseInt(suffix);
} catch (NumberFormatException ignored) {
return Integer.MAX_VALUE;
} }
private int commandArgIndex(String key) {
return Integer.parseInt(key.substring(COMMAND_ARG_PREFIX.length()).trim());
} }
private String bufferSnapshot(StringBuilder buffer) { private String bufferSnapshot(StringBuilder buffer) {

View File

@@ -43,13 +43,13 @@ class BuiltinDynamicActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"desc", "Human-readable description for the temporary action. Required because the generated action name is only a short id.", "desc", param("required", "string", "Human-readable description for the generated temporary action. This becomes the new action's planning description."),
"code", "Dynamic action source code content.", "code", param("required", "string", "Dynamic action source code content."),
"codeType", "Code extension, for example py/sh/js.", "codeType", param("required", "string", "Source file extension without or with leading dot, for example py, sh, js, or .py."),
"launcher", "Interpreter or launcher used for ORIGIN execution.", "launcher", param("required", "string", "Interpreter or launcher command used to run the generated code, for example python3, bash, or node."),
"meta", "MetaActionInfo extra fields as JSON string. Available fields example: {\"io\":true,\"params\":{\"input\":\"user input\"},\"tags\":[\"dynamic\"],\"preActions\":[\"builtin::command::execute\"],\"postActions\":[\"builtin::dynamic::persist\"],\"strictDependencies\":false,\"responseSchema\":{\"result\":\"dynamic result\"}}" "meta", param("required", "json-string", "MetaActionInfo fields for the generated action. Supported fields: io, params, tags, preActions, postActions, strictDependencies, responseSchema.")
), ),
"Generate a temporary ORIGIN action from source code and return a temporary actionKey.", "Purpose: generate and register a temporary script as an ORIGIN MetaAction from supplied source code. Inputs: desc, code, codeType, launcher, and meta info. Returns: JSON with ok and temporary actionKey. Use when: existing MetaActions cannot perform the task and a temporary code-backed action is needed. Notes: this registers executable code with cleanup TTL; the generated action is temporary until builtin::dynamic::persist is called.",
basicTags, basicTags,
Set.of(), Set.of(),
Set.of(createActionKey("persist")), Set.of(createActionKey("persist")),
@@ -110,8 +110,8 @@ class BuiltinDynamicActionProvider implements BuiltinActionProvider {
MetaActionInfo info = new MetaActionInfo( MetaActionInfo info = new MetaActionInfo(
false, false,
null, null,
Map.of("actionKey", "Temporary ORIGIN actionKey returned by generate."), Map.of("actionKey", param("required", "string", "Temporary ORIGIN actionKey returned by builtin::dynamic::generate.")),
"Persist a temporary ORIGIN action and cancel its cleanup task.", "Purpose: persist a previously generated temporary ORIGIN MetaAction and cancel its cleanup task. Inputs: actionKey from dynamic::generate. Returns: JSON with ok and actionKey. Use when: a generated temporary action should become reusable beyond its cleanup TTL. Notes: this has persistence side effects and should only be used when the generated action is validated or explicitly requested.",
basicTags, basicTags,
Set.of(createActionKey("generate")), Set.of(createActionKey("generate")),
Set.of(), Set.of(),

View File

@@ -56,9 +56,9 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"actionId", "Uuid of the interrupted executable action to resume." "actionId", param("required", "string", "Uuid of an executable action currently in INTERRUPTED status.")
), ),
"Resume action that is interrupted.", "Purpose: resume an executable action that is currently interrupted. Inputs: actionId. Returns: plain text success or failure reason. Use when: an intervention or user decision is complete and the original action should continue. Notes: this does not modify the action chain; use create_intervention before resuming when chain changes are required.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),
@@ -101,14 +101,14 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
true, true,
null, null,
Map.of( Map.of(
"actionId", "Uuid of the executing action that should enter intervention flow.", "actionId", param("required", "string", "Uuid of the executing action that should be interrupted for external intervention."),
"actionInfo", "Readable summary of the current action, used to explain the intervention context to the target.", "actionInfo", param("required", "string", "Readable summary of the current action and why intervention is needed."),
"demand", "What feedback, decision or operation is required from the target user.", "demand", param("required", "string", "Specific feedback, decision, permission, or operation required from the target."),
"target", "Target user or channel identifier that should receive the intervention request.", "target", param("required", "string", "Target user or channel identifier that should receive the intervention request."),
"input", "Prompt content used to initiate the intervention turn toward the target.", "input", param("required", "string", "Prompt content used to initiate the intervention turn toward the target."),
"timeout", "Maximum wait time for the interruption result, in the unit expected by ExecutableAction.interrupt(timeout)." "timeout", param("required", "int", "Maximum wait time passed to ExecutableAction.interrupt(timeout).")
), ),
"Try to acquire the target user to intervene this Action.", "Purpose: interrupt an executing action and ask a target participant/channel for intervention. Inputs: actionId, actionInfo, demand, target, input, timeout. Returns: plain text intervention status. Use when: execution cannot safely continue without user decision, missing information, permission, or manual operation. Notes: this creates communication side effects and temporarily interrupts the action.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),
@@ -190,7 +190,7 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of(), Map.of(),
"List existing actions that can be intervened", "Purpose: list executable actions that can be inspected for possible intervention. Inputs: none. Returns: JSON array with tendency, description, status, and uuid for each action. Use when: an action id is needed before acquire_intervention, create_intervention, or resume_interrupted_action. Notes: this only discovers actions; it does not modify them.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),
@@ -237,7 +237,7 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of(), Map.of(),
"List available MetaActions.", "Purpose: list currently available MetaActions that can be used in action chains or interventions. Inputs: none. Returns: JSON array with action key/location, description, tags, and params. Use when: correction needs to discover valid action_key values for APPEND, INSERT, DELETE, or REBUILD. Notes: this is a discovery action and does not execute those MetaActions.",
tags, tags,
Set.of(), Set.of(),
Set.of(), Set.of(),
@@ -282,12 +282,12 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
false, false,
null, null,
Map.of( Map.of(
"id", "The uuid of the Action to be intervened on.", "id", param("required", "string", "Uuid of the executable action to modify."),
"type", "Intervention type. Allowed values: APPEND, INSERT, DELETE, CANCEL.", "type", param("required", "string", "Intervention type. Allowed values: APPEND, INSERT, DELETE, CANCEL, REBUILD."),
"order", "Action chain order/stage to apply the intervention on.", "order", param("required", "int", "Action chain order/stage where the intervention applies."),
"actions", "Comma-separated actionKey list to be inserted, appended, rebuilt or deleted. Example: \"builtin::command::execute, builtin::capability::show_memory_slices\"" "actions", param("conditional", "string", "Comma-separated actionKey list to insert, append, rebuild, or delete. Required except for CANCEL. Example: builtin::command::execute,builtin::command::read.")
), ),
"Used to create an Action Intervention and act on the specified Executable Action.", "Purpose: apply a structural intervention to an executable action chain. Inputs: id, type, order, and conditional actions. Returns: JSON with ok and optional result. Use when: correction must append, insert, delete, cancel, or rebuild future action-chain steps. Notes: actions must be valid action_key values; CANCEL may omit actions; this has direct action-chain side effects and resumes the target action after applying changes.",
basicTags, basicTags,
Set.of( Set.of(
createActionKey("list_available_meta_actions"), createActionKey("list_available_meta_actions"),

View File

@@ -4,6 +4,7 @@ import kotlin.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import work.slhaf.partner.core.action.ActionCapability;
import work.slhaf.partner.core.cognition.CognitionCapability; import work.slhaf.partner.core.cognition.CognitionCapability;
import work.slhaf.partner.core.cognition.ContextBlock; import work.slhaf.partner.core.cognition.ContextBlock;
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability; import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
@@ -30,6 +31,7 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
- 一条任务消息,其中包含: - 一条任务消息,其中包含:
- executable_action_info当前正在执行的行动信息包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who - executable_action_info当前正在执行的行动信息包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who
- current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、description 与 status。 - current_action_chain_overview当前行动链概览按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、description 与 status。
- available_meta_action当前系统真实可用的 MetaAction 候选,包含 meta_action_key 与 meta_action_description。
你的任务: 你的任务:
- 基于当前上下文、原始行动意图与当前行动链进展,判断后续行动是否仍然符合目的; - 基于当前上下文、原始行动意图与当前行动链进展,判断后续行动是否仍然符合目的;
@@ -43,6 +45,7 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
- original_tendency 是这条行动链最初要解决的问题;后续行动的调整必须仍然围绕它。 - original_tendency 是这条行动链最初要解决的问题;后续行动的调整必须仍然围绕它。
- evaluation_passed_reason 与 description 表示该行动最初为何能够成立;若当前链路已经与这些前提不一致,可据此进行纠偏。 - evaluation_passed_reason 与 description 表示该行动最初为何能够成立;若当前链路已经与这些前提不一致,可据此进行纠偏。
- current_action_chain_overview 是判断后续链路是否缺步骤、顺序失衡、重复冗余或整体方向错误的主要依据。 - current_action_chain_overview 是判断后续链路是否缺步骤、顺序失衡、重复冗余或整体方向错误的主要依据。
- available_meta_action 是你进行 APPEND、INSERT 或 REBUILD 时可选择的动作全集;不要使用其中不存在的 action_key。
- communication 域用于判断最新交流语境是否已经变化,导致当前链路需要调整。 - communication 域用于判断最新交流语境是否已经变化,导致当前链路需要调整。
- memory 域只在与当前行动明显相关时作为辅助参考使用。 - memory 域只在与当前行动明显相关时作为辅助参考使用。
@@ -88,6 +91,8 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
@InjectCapability @InjectCapability
private CognitionCapability cognitionCapability; private CognitionCapability cognitionCapability;
@InjectCapability
private ActionCapability actionCapability;
@Override @Override
protected @NotNull Result<CorrectorResult> doExecute(CorrectorInput input) { protected @NotNull Result<CorrectorResult> doExecute(CorrectorInput input) {
@@ -121,6 +126,17 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
}); });
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
appendRepeatedElements(
document,
root,
"available_meta_action",
actionCapability.listAvailableMetaActions().entrySet(),
(block, value) -> {
appendTextElement(document, block, "meta_action_key", value.getKey());
appendTextElement(document, block, "meta_action_description", value.getValue().getDescription());
return Unit.INSTANCE;
}
);
} }
}.encodeToMessage(); }.encodeToMessage();
} }