mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
fix(communication): fix errors while import external xml node into input xml
This commit is contained in:
@@ -127,7 +127,7 @@ public class CognitionCore implements StateSerializable {
|
|||||||
new BlockContent("recent_chat_messages", "communication_producer") {
|
new BlockContent("recent_chat_messages", "communication_producer") {
|
||||||
@Override
|
@Override
|
||||||
protected void fillXml(@NotNull Document document, @NotNull Element root) {
|
protected void fillXml(@NotNull Document document, @NotNull Element root) {
|
||||||
document.appendChild(document.importNode(messageNotesElement(), true));
|
root.appendChild(document.importNode(messageNotesElement(), true));
|
||||||
Element chatMessagesElement = document.createElement("chat_messages");
|
Element chatMessagesElement = document.createElement("chat_messages");
|
||||||
root.appendChild(chatMessagesElement);
|
root.appendChild(chatMessagesElement);
|
||||||
appendRepeatedElements(document, chatMessagesElement, "chat_message", resolveRecentChatMessages(), (messageElement, message) -> {
|
appendRepeatedElements(document, chatMessagesElement, "chat_message", resolveRecentChatMessages(), (messageElement, message) -> {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
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 org.w3c.dom.Node;
|
||||||
import work.slhaf.partner.core.cognition.*;
|
import work.slhaf.partner.core.cognition.*;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
|
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
|
||||||
@@ -171,7 +172,7 @@ public class CommunicationProducer extends AbstractAgentModule.Running<PartnerRu
|
|||||||
Element root = document.createElement("input");
|
Element root = document.createElement("input");
|
||||||
document.appendChild(root);
|
document.appendChild(root);
|
||||||
|
|
||||||
document.appendChild(document.importNode(runningFlowContext.encodeInputsBlock().encodeToXml(), true));
|
root.appendChild(importExternalNode(document, runningFlowContext.encodeInputsBlock().encodeToXml()));
|
||||||
appendTextElement(document, root, "source", runningFlowContext.getSource());
|
appendTextElement(document, root, "source", runningFlowContext.getSource());
|
||||||
for (Map.Entry<String, String> entry : runningFlowContext.getAdditionalUserInfo().entrySet()) {
|
for (Map.Entry<String, String> entry : runningFlowContext.getAdditionalUserInfo().entrySet()) {
|
||||||
appendTextElement(document, root, sanitizeTagName(entry.getKey()), entry.getValue());
|
appendTextElement(document, root, sanitizeTagName(entry.getKey()), entry.getValue());
|
||||||
@@ -242,11 +243,25 @@ public class CommunicationProducer extends AbstractAgentModule.Running<PartnerRu
|
|||||||
inputRoot.appendChild(groupElement);
|
inputRoot.appendChild(groupElement);
|
||||||
for (CommunicationBlockContent block : entry.getValue()) {
|
for (CommunicationBlockContent block : entry.getValue()) {
|
||||||
Element blockElement = block.encodeToXml();
|
Element blockElement = block.encodeToXml();
|
||||||
groupElement.appendChild(document.importNode(blockElement, true));
|
groupElement.appendChild(importExternalNode(document, blockElement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node importExternalNode(Document targetDocument, Node externalNode) {
|
||||||
|
Node nodeToImport = externalNode;
|
||||||
|
if (externalNode != null && externalNode.getNodeType() == Node.DOCUMENT_NODE) {
|
||||||
|
nodeToImport = ((Document) externalNode).getDocumentElement();
|
||||||
|
}
|
||||||
|
if (nodeToImport == null) {
|
||||||
|
throw new IllegalArgumentException("待导入节点不能为空");
|
||||||
|
}
|
||||||
|
if (nodeToImport.getOwnerDocument() == targetDocument) {
|
||||||
|
return nodeToImport.cloneNode(true);
|
||||||
|
}
|
||||||
|
return targetDocument.importNode(nodeToImport, true);
|
||||||
|
}
|
||||||
|
|
||||||
private String sanitizeTagName(String rawTagName) {
|
private String sanitizeTagName(String rawTagName) {
|
||||||
if (rawTagName == null || rawTagName.isBlank()) {
|
if (rawTagName == null || rawTagName.isBlank()) {
|
||||||
return "meta";
|
return "meta";
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class MessageSummarizer extends AbstractAgentModule.Sub<List<Message>, Re
|
|||||||
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) {
|
||||||
document.appendChild(document.importNode(cognitionCapability.messageNotesElement(), true));
|
root.appendChild(document.importNode(cognitionCapability.messageNotesElement(), true));
|
||||||
appendListElement(document, root, "chat_messages", "message", messages, (element, message) -> {
|
appendListElement(document, root, "chat_messages", "message", messages, (element, message) -> {
|
||||||
element.setAttribute("role", message.roleValue());
|
element.setAttribute("role", message.roleValue());
|
||||||
element.setTextContent(message.getContent());
|
element.setTextContent(message.getContent());
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package experimental;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.w3c.dom.DOMException;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
class ExternalNodeImportTest {
|
||||||
|
|
||||||
|
private static Node importExternalNode(Document targetDocument, Node externalNode) {
|
||||||
|
Node nodeToImport = externalNode;
|
||||||
|
if (externalNode != null && externalNode.getNodeType() == Node.DOCUMENT_NODE) {
|
||||||
|
nodeToImport = ((Document) externalNode).getDocumentElement();
|
||||||
|
}
|
||||||
|
if (nodeToImport == null) {
|
||||||
|
throw new IllegalArgumentException("nodeToImport must not be null");
|
||||||
|
}
|
||||||
|
if (nodeToImport.getOwnerDocument() == targetDocument) {
|
||||||
|
return nodeToImport.cloneNode(true);
|
||||||
|
}
|
||||||
|
return targetDocument.importNode(nodeToImport, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Document newDocument() throws Exception {
|
||||||
|
return DocumentBuilderFactory.newInstance()
|
||||||
|
.newDocumentBuilder()
|
||||||
|
.newDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void appendForeignElementDirectlyShouldThrow() throws Exception {
|
||||||
|
Document targetDocument = newDocument();
|
||||||
|
Element inputRoot = targetDocument.createElement("input");
|
||||||
|
targetDocument.appendChild(inputRoot);
|
||||||
|
|
||||||
|
Document externalDocument = newDocument();
|
||||||
|
Element externalInputs = externalDocument.createElement("inputs");
|
||||||
|
externalDocument.appendChild(externalInputs);
|
||||||
|
|
||||||
|
assertThrows(DOMException.class, () -> inputRoot.appendChild(externalInputs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importForeignElementShouldWork() throws Exception {
|
||||||
|
Document targetDocument = newDocument();
|
||||||
|
Element inputRoot = targetDocument.createElement("input");
|
||||||
|
targetDocument.appendChild(inputRoot);
|
||||||
|
|
||||||
|
Document externalDocument = newDocument();
|
||||||
|
Element externalInputs = externalDocument.createElement("inputs");
|
||||||
|
externalDocument.appendChild(externalInputs);
|
||||||
|
|
||||||
|
Node imported = importExternalNode(targetDocument, externalInputs);
|
||||||
|
inputRoot.appendChild(imported);
|
||||||
|
|
||||||
|
assertEquals("inputs", inputRoot.getFirstChild().getNodeName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importExternalDocumentShouldUseDocumentElement() throws Exception {
|
||||||
|
Document targetDocument = newDocument();
|
||||||
|
Element inputRoot = targetDocument.createElement("input");
|
||||||
|
targetDocument.appendChild(inputRoot);
|
||||||
|
|
||||||
|
Document externalDocument = newDocument();
|
||||||
|
Element externalInputs = externalDocument.createElement("inputs");
|
||||||
|
externalDocument.appendChild(externalInputs);
|
||||||
|
|
||||||
|
Node imported = importExternalNode(targetDocument, externalDocument);
|
||||||
|
inputRoot.appendChild(imported);
|
||||||
|
|
||||||
|
assertEquals("inputs", inputRoot.getFirstChild().getNodeName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import java.util.List;
|
|||||||
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 static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
class CommunicationProducerTest {
|
class CommunicationProducerTest {
|
||||||
|
|
||||||
@@ -32,6 +32,20 @@ class CommunicationProducerTest {
|
|||||||
method.invoke(producer, context, response);
|
method.invoke(producer, context, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String invokeBuildInputXml(
|
||||||
|
CommunicationProducer producer,
|
||||||
|
PartnerRunningFlowContext context,
|
||||||
|
List<?> communicationBlocks
|
||||||
|
) throws Exception {
|
||||||
|
Method method = CommunicationProducer.class.getDeclaredMethod(
|
||||||
|
"buildInputXml",
|
||||||
|
PartnerRunningFlowContext.class,
|
||||||
|
List.class
|
||||||
|
);
|
||||||
|
method.setAccessible(true);
|
||||||
|
return (String) method.invoke(producer, context, communicationBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
private static void setField(Object target, String fieldName, Object value) throws Exception {
|
private static void setField(Object target, String fieldName, Object value) throws Exception {
|
||||||
Field field = target.getClass().getDeclaredField(fieldName);
|
Field field = target.getClass().getDeclaredField(fieldName);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
@@ -72,6 +86,24 @@ class CommunicationProducerTest {
|
|||||||
assertEquals("[[AGENT]: self]:\n\nnormal reply", chatMessages.get(1).getContent());
|
assertEquals("[[AGENT]: self]:\n\nnormal reply", chatMessages.get(1).getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldBuildInputXmlWithoutExtraWrapper() throws Exception {
|
||||||
|
StubCognitionCapability cognitionCapability = new StubCognitionCapability();
|
||||||
|
CommunicationProducer producer = new CommunicationProducer();
|
||||||
|
setField(producer, "cognitionCapability", cognitionCapability);
|
||||||
|
|
||||||
|
String xml = invokeBuildInputXml(
|
||||||
|
producer,
|
||||||
|
PartnerRunningFlowContext.fromUser("user-1", "hello"),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
|
||||||
|
assertTrue(xml.contains("<input>"));
|
||||||
|
assertTrue(xml.contains("<inputs>"));
|
||||||
|
assertTrue(xml.contains("<input interval-to-first=\"0\">hello</input>"));
|
||||||
|
assertFalse(xml.contains("<wrapper>"));
|
||||||
|
}
|
||||||
|
|
||||||
private static final class StubCognitionCapability implements CognitionCapability {
|
private static final class StubCognitionCapability implements CognitionCapability {
|
||||||
private final ContextWorkspace contextWorkspace = new ContextWorkspace();
|
private final ContextWorkspace contextWorkspace = new ContextWorkspace();
|
||||||
private final List<Message> chatMessages = new ArrayList<>();
|
private final List<Message> chatMessages = new ArrayList<>();
|
||||||
|
|||||||
Reference in New Issue
Block a user