From fb4999457039567460608bfe1c54e45a08296036 Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 17:16:49 +0800 Subject: [PATCH 1/6] AgentTool SPI: plugin-jar deployment for custom agent tools - Annotate AgentTool with @EventMeshSPI (new AGENT_TOOL extension type); custom tools now register via META-INF/eventmesh/ service files exactly like storage/connector plugins - ToolRegistry.registerSpi(name) resolves implementations through EventMeshExtensionFactory (singleton semantics, classpath + plugin-jar loaders) - AgentApplication: -Dagent.tools.spi= enables SPI tools alongside connector-backed tools - start-agent.sh: jars under plugin/agent/ join the agent classpath (same convention as plugin/connector/ in the connector runtime) - Tests: AgentToolSpiTest drives the real factory + a test service file (echo-test) through registerSpi; unknown-name rejection path covered - Docs: agent-tools.md SPI section + config-table entry; agent.properties key doc --- docs/feature/agent-tools.md | 20 +++++++++ eventmesh-agent/bin/start-agent.sh | 10 ++++- eventmesh-agent/build.gradle | 1 + eventmesh-agent/conf/agent.properties | 3 ++ .../eventmesh/agent/AgentApplication.java | 10 +++++ .../eventmesh/agent/tool/AgentTool.java | 11 +++++ .../eventmesh/agent/tool/ToolRegistry.java | 14 ++++++ .../agent/tool/AgentToolSpiTest.java | 43 ++++++++++++++++++ .../eventmesh/agent/tool/EchoTestTool.java | 44 +++++++++++++++++++ .../org.apache.eventmesh.agent.tool.AgentTool | 16 +++++++ .../eventmesh/spi/EventMeshExtensionType.java | 1 + 11 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java create mode 100644 eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java create mode 100644 eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool diff --git a/docs/feature/agent-tools.md b/docs/feature/agent-tools.md index e04e7ec4ac..58bb22d5cd 100644 --- a/docs/feature/agent-tools.md +++ b/docs/feature/agent-tools.md @@ -53,6 +53,25 @@ results as messages, and continues until it produces a final answer (bounded at 5 tool iterations). Without tools, behavior is unchanged token-by-token streaming. +## SPI-deployed custom tools + +Beyond connector-backed tools, custom tools follow the repo-standard plugin +mechanism (same as storage/connector plugins): + +1. Implement `agent.tool.AgentTool` (name + description + JSON schema + + `invoke`), no extra annotation needed on your class. +2. In your jar add a service file + `META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool` containing + `mytool=com.example.MyTool`. +3. Drop the jar into the agent's `plugin/agent/` directory (the launcher + puts every jar there on the classpath) and enable it with + `AGENT_TOOLS_SPI=mytool` (i.e. `-Dagent.tools.spi=mytool`; comma-list + supported). + +Resolution goes through `EventMeshExtensionFactory` — the same loader that +serves storage and connector plugins, so singleton semantics and the +`META-INF/eventmesh/` convention are identical. + ## Event-driven agents (no user in the loop) Set a subscription list and an output topic: @@ -89,6 +108,7 @@ StreamingAgent agent = new StreamingAgent(client, parent, agentId, llm, memory, | Key | Default | Meaning | | --- | --- | --- | +| `agent.tools.spi` | (empty) | Comma list of SPI names resolved via `EventMeshExtensionFactory` (jars in `plugin/agent/`) | | `agent.tools.sink.` | — | FQCN of a `SinkConnector` exposed as write tool `` | | `agent.tools.source.` | — | FQCN of a `SourceConnector` exposed as read tool `` | | `agent.tools.props..*` | — | Connector init properties for tool `` | diff --git a/eventmesh-agent/bin/start-agent.sh b/eventmesh-agent/bin/start-agent.sh index 9f54271440..f8283748b7 100644 --- a/eventmesh-agent/bin/start-agent.sh +++ b/eventmesh-agent/bin/start-agent.sh @@ -53,9 +53,17 @@ AGENT_MAX_CONVERSATIONS="${AGENT_MAX_CONVERSATIONS:-1000}" AGENT_CAPACITY="${AGENT_CAPACITY:-100}" AGENT_OPTS="${AGENT_OPTS:-}" +# SPI-deployed agent tools: every jar under plugin/agent/ joins the classpath (an AgentTool +# implementation registers itself via META-INF/eventmesh/ inside the jar; enable +# with -Dagent.tools.spi=). +PLUGIN_CP="" +if compgen -G "$AGENT_HOME/plugin/agent/*.jar" > /dev/null; then + PLUGIN_CP="$(find "$AGENT_HOME/plugin/agent" -name '*.jar' | paste -sd ':' -)" +fi + ARGS="" if [ -n "$AGENT_ID" ]; then ARGS="$ARGS -Dagent.id=${AGENT_ID}" fi -exec java -Xmx512m $AGENT_OPTS -cp "conf:apps/*:lib/*" -Dagent.runtime.url="${AGENT_RUNTIME_URL}" -Dllm.base.url="${LLM_BASE_URL}" -Dllm.api.key="${LLM_API_KEY}" -Dllm.model="${LLM_MODEL}" -Dagent.heartbeat.intervalMs="${AGENT_HEARTBEAT_MS}" -Dagent.heartbeat.failLimit="${AGENT_HEARTBEAT_FAILLIMIT}" -Dagent.conversation.maxHistory="${AGENT_MAX_HISTORY}" -Dagent.conversation.maxConversations="${AGENT_MAX_CONVERSATIONS}" -Dagent.capacity="${AGENT_CAPACITY}" $ARGS org.apache.eventmesh.agent.AgentApplication +exec java -Xmx512m $AGENT_OPTS -cp "conf:apps/*:lib/*${PLUGIN_CP:+:$PLUGIN_CP}" -Dagent.runtime.url="${AGENT_RUNTIME_URL}" -Dllm.base.url="${LLM_BASE_URL}" -Dllm.api.key="${LLM_API_KEY}" -Dllm.model="${LLM_MODEL}" -Dagent.heartbeat.intervalMs="${AGENT_HEARTBEAT_MS}" -Dagent.heartbeat.failLimit="${AGENT_HEARTBEAT_FAILLIMIT}" -Dagent.conversation.maxHistory="${AGENT_MAX_HISTORY}" -Dagent.conversation.maxConversations="${AGENT_MAX_CONVERSATIONS}" -Dagent.capacity="${AGENT_CAPACITY}" $ARGS org.apache.eventmesh.agent.AgentApplication diff --git a/eventmesh-agent/build.gradle b/eventmesh-agent/build.gradle index 08a6703fea..3d6e0da9bc 100644 --- a/eventmesh-agent/build.gradle +++ b/eventmesh-agent/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation project(':eventmesh-sdks:eventmesh-sdk-java') implementation project(':eventmesh-connector-api') + implementation project(':eventmesh-spi') implementation 'io.cloudevents:cloudevents-core' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'org.slf4j:slf4j-api' diff --git a/eventmesh-agent/conf/agent.properties b/eventmesh-agent/conf/agent.properties index 9314b061c6..aa6438847c 100644 --- a/eventmesh-agent/conf/agent.properties +++ b/eventmesh-agent/conf/agent.properties @@ -28,6 +28,9 @@ # AGENT_HEARTBEAT_FAILLIMIT -> -Dagent.heartbeat.failLimit (default 6; exits after N consecutive failures) # AGENT_MAX_CONVERSATIONS -> -Dagent.conversation.maxConversations (default 1000; LRU bound) # +# SPI-deployed custom tools (jars under plugin/agent/, META-INF/eventmesh service file): +# AGENT_TOOLS_SPI -> -Dagent.tools.spi (comma list of SPI names; default none) +# # Connector tools (function calling; see docs/feature/agent-tools.md): # AGENT_TOOL_SINK_= sink connector exposed as a write tool # AGENT_TOOL_SOURCE_= source connector exposed a read tool diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java index ebbb9b54d4..a7d4aa029d 100644 --- a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java +++ b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java @@ -68,6 +68,7 @@ public static void main(String[] args) throws Exception { final int heartbeatFailLimit = Integer.getInteger("agent.heartbeat.failLimit", 6); String triggerTopics = System.getProperty("agent.subscribe.topics", ""); String triggerOutput = System.getProperty("agent.trigger.output.topic", "agent.triggers"); + String spiTools = System.getProperty("agent.tools.spi", ""); // Step 1: register (gets the assigned agent-parent + client-reply-parent) AgentControlClient control = new AgentControlClient(runtimeUrl); @@ -163,6 +164,15 @@ private static ToolRegistry buildConnectorTools() { registerConnectorTool(registry, "source", name, System.getProperty(key)); } } + // SPI-deployed custom tools (jars in plugin/agent/ with a META-INF/eventmesh service file) + String spiTools = System.getProperty("agent.tools.spi", ""); + for (String spiName : spiTools.split(",")) { + String trimmed = spiName.trim(); + if (!trimmed.isEmpty()) { + registry.registerSpi(trimmed); + log.info("SPI agent tool registered: {}", trimmed); + } + } return registry; } diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java index a40017b48b..1eafe1ef5a 100644 --- a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java +++ b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java @@ -17,6 +17,9 @@ package org.apache.eventmesh.agent.tool; +import org.apache.eventmesh.spi.EventMeshExtensionType; +import org.apache.eventmesh.spi.EventMeshSPI; + import java.util.Map; /** @@ -24,7 +27,15 @@ * {@code StreamingAgent} tool loop. Register instances on a {@link ToolRegistry} and pass the * registry to the agent; the agent advertises every tool to the model, executes the calls the * model requests, and feeds results back until a final answer. + * + *

SPI deployment (same mechanism as storage/connector plugins): annotate nothing extra — + * implementations register themselves via a {@code META-INF/eventmesh/<this-interface-FQCN>} + * service file ({@code =}) inside their jar. Drop the jar into the agent's + * {@code plugin/agent/} directory and reference it by name with + * {@code -Dagent.tools.spi=}; {@link ToolRegistry#registerSpi(String)} resolves it through + * {@code EventMeshExtensionFactory}.

*/ +@EventMeshSPI(eventMeshExtensionType = EventMeshExtensionType.AGENT_TOOL) public interface AgentTool { /** Stable tool name the model addresses this tool by. */ diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java index a72028c066..3a974f84dd 100644 --- a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java +++ b/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java @@ -18,6 +18,7 @@ package org.apache.eventmesh.agent.tool; import org.apache.eventmesh.agent.llm.ToolSpec; +import org.apache.eventmesh.spi.EventMeshExtensionFactory; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -34,6 +35,19 @@ public ToolRegistry register(AgentTool tool) { return this; } + /** + * Register a tool discovered via the EventMesh SPI: the implementation jar carries a + * {@code META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool} service file mapping + * {@code spiName} to the implementation class. Throws when no such name is registered. + */ + public ToolRegistry registerSpi(String spiName) { + AgentTool tool = EventMeshExtensionFactory.getExtension(AgentTool.class, spiName); + if (tool == null) { + throw new IllegalArgumentException("no AgentTool SPI implementation named: " + spiName); + } + return register(tool); + } + public boolean isEmpty() { return tools.isEmpty(); } diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java b/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java new file mode 100644 index 0000000000..a31297d72d --- /dev/null +++ b/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.eventmesh.agent.tool; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +/** Covers the SPI registration path via EventMeshExtensionFactory + the test service file. */ +class AgentToolSpiTest { + + @Test + void registerSpiResolvesThroughTheFactory() throws Exception { + ToolRegistry registry = new ToolRegistry().registerSpi("echo-test"); + assertThat(registry.size()).isEqualTo(1); + assertThat(registry.invoke("echo-test", Map.of())).isEqualTo("spi-echo"); + } + + @Test + void registerSpiRejectsUnknownName() { + assertThatThrownBy(() -> new ToolRegistry().registerSpi("no-such-tool")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no AgentTool SPI implementation named"); + } +} diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java b/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java new file mode 100644 index 0000000000..62e72749b8 --- /dev/null +++ b/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.eventmesh.agent.tool; + +import java.util.Map; + +/** Test-only AgentTool resolved via the META-INF/eventmesh service file. */ +public class EchoTestTool implements AgentTool { + + @Override + public String name() { + return "echo-test"; + } + + @Override + public String description() { + return "returns a fixed string (test)"; + } + + @Override + public String parametersJsonSchema() { + return "{\"type\":\"object\"}"; + } + + @Override + public String invoke(Map args) { + return "spi-echo"; + } +} diff --git a/eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool b/eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool new file mode 100644 index 0000000000..a800d7c584 --- /dev/null +++ b/eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo-test=org.apache.eventmesh.agent.tool.EchoTestTool diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java index 8de4e1ecfd..8dd6d5cc09 100644 --- a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java +++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionType.java @@ -36,6 +36,7 @@ public enum EventMeshExtensionType { JDBC_DATABASE_DIALECT("jdbc_database_dialect"), OFFSETMGMT("offsetMgmt"), RETRY("retry"), + AGENT_TOOL("agentTool"), ; private final String extensionTypeName; From 94368023c4b68948844940248990ed902fc0255c Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 17:57:48 +0800 Subject: [PATCH 2/6] =?UTF-8?q?AgentTool=20SPI=20follow-up:=20module=20res?= =?UTF-8?q?tructure=20=E2=80=94=20connector-api=20under=20connector-plugin?= =?UTF-8?q?,=20agent=20->=20agent-runtime,=20new=20agent-plugin=20tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move eventmesh-connector-api -> eventmesh-connector-plugin/eventmesh-connector-api (SPI jar lives with its plugin family, like storage/protocol) - Rename eventmesh-agent -> eventmesh-agent-runtime (it is a process runtime, matching eventmesh-connector-runtime) - New eventmesh-agent-plugin/ tree: umbrella + eventmesh-agent-plugin-http-fetch (first in-tree AgentTool plugin: fetch a URL, return truncated body; pluginType=agentTool, pluginName=http-fetch, META-INF service file included) - dist-agent now installs pluginType==agentTool modules into dist-agent/plugin/agent// (same convention as dist-connector/plugin/connector) - References updated: settings.gradle, root build.gradle (findProject paths), all 23 connector plugin build files, architecture-guard, runtime test dep, docs --- build.gradle | 24 +++++- docs/feature/agent-tools.md | 29 +++++-- docs/feature/client-java.md | 4 +- eventmesh-agent-plugin/build.gradle | 20 +++++ .../build.gradle | 26 ++++++ .../gradle.properties | 18 ++++ .../agent/plugin/httpfetch/HttpFetchTool.java | 82 +++++++++++++++++++ .../org.apache.eventmesh.agent.tool.AgentTool | 16 ++++ .../bin/start-agent.sh | 0 .../build.gradle | 2 +- .../conf/agent.properties | 0 .../conf/log4j2.xml | 0 .../eventmesh/agent/AgentApplication.java | 0 .../eventmesh/agent/AgentControlClient.java | 0 .../eventmesh/agent/ConversationMemory.java | 0 .../eventmesh/agent/ConversationStore.java | 0 .../eventmesh/agent/StreamingAgent.java | 0 .../apache/eventmesh/agent/llm/LlmClient.java | 0 .../eventmesh/agent/llm/LlmCompletion.java | 0 .../eventmesh/agent/llm/OpenAiLlmClient.java | 0 .../apache/eventmesh/agent/llm/ToolCall.java | 0 .../apache/eventmesh/agent/llm/ToolSpec.java | 0 .../eventmesh/agent/tool/AgentTool.java | 0 .../agent/tool/ConnectorToolAdapter.java | 0 .../eventmesh/agent/tool/ToolRegistry.java | 0 .../agent/ConversationStoreTest.java | 0 .../agent/llm/OpenAiLlmClientChatTest.java | 0 .../agent/llm/OpenAiLlmClientTest.java | 0 .../agent/tool/AgentToolSpiTest.java | 0 .../agent/tool/ConnectorToolAdapterTest.java | 0 .../eventmesh/agent/tool/EchoTestTool.java | 0 .../agent/tool/ToolRegistryTest.java | 0 .../org.apache.eventmesh.agent.tool.AgentTool | 0 eventmesh-architecture-guard/build.gradle | 2 +- .../eventmesh-connector-api}/build.gradle | 0 .../connector/CloudEventSerializer.java | 0 .../connector/ConnectorOffsetStore.java | 0 .../connector/EventMeshEndpoint.java | 0 .../eventmesh/connector/HttpCaller.java | 0 .../apache/eventmesh/connector/PollEntry.java | 0 .../eventmesh/connector/SinkConnector.java | 0 .../eventmesh/connector/SourceConnector.java | 0 .../eventmesh/connector/package-info.java | 0 eventmesh-runtime/build.gradle | 2 +- settings.gradle | 9 +- 45 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 eventmesh-agent-plugin/build.gradle create mode 100644 eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle create mode 100644 eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/gradle.properties create mode 100644 eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java create mode 100644 eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool rename {eventmesh-agent => eventmesh-agent-runtime}/bin/start-agent.sh (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/build.gradle (96%) rename {eventmesh-agent => eventmesh-agent-runtime}/conf/agent.properties (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/conf/log4j2.xml (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/AgentApplication.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/AgentControlClient.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/ConversationMemory.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/ConversationStore.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/StreamingAgent.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/llm/LlmClient.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/llm/LlmCompletion.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/llm/OpenAiLlmClient.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/llm/ToolCall.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/llm/ToolSpec.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapter.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/ConversationStoreTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientChatTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapterTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/java/org/apache/eventmesh/agent/tool/ToolRegistryTest.java (100%) rename {eventmesh-agent => eventmesh-agent-runtime}/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/build.gradle (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/CloudEventSerializer.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/ConnectorOffsetStore.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/EventMeshEndpoint.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/HttpCaller.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/PollEntry.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/SinkConnector.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/SourceConnector.java (100%) rename {eventmesh-connector-api => eventmesh-connector-plugin/eventmesh-connector-api}/src/main/java/org/apache/eventmesh/connector/package-info.java (100%) diff --git a/build.gradle b/build.gradle index 696d7ca61a..c28d4f234b 100644 --- a/build.gradle +++ b/build.gradle @@ -248,7 +248,7 @@ tasks.register('dist-connector') { // exclude 'eventmesh-*' below, but ConnectorApplication itself imports the // SPI interfaces — ship it next to the runtime jar in apps/ so a bare // runtime (no plugins installed) still boots. - def connectorApi = findProject('eventmesh-connector-api') + def connectorApi = findProject('eventmesh-connector-plugin:eventmesh-connector-api') copy { from connectorApi.jar.archivePath into rootProject.file('dist-connector/apps') @@ -304,7 +304,7 @@ tasks.register('dist-agent') { doLast { // Core: the agent process jar + its third-party deps (sdk-java, common, cloudevents, // jackson, log4j binding). The agent talks to the runtime only over HTTP + lite topics. - def core = findProject('eventmesh-agent') + def core = findProject('eventmesh-agent-runtime') logger.lifecycle('Install module: module: {}', core.name) copy { from core.jar.archivePath @@ -326,6 +326,26 @@ tasks.register('dist-agent') { duplicatesStrategy = DuplicatesStrategy.EXCLUDE exclude 'META-INF' } + // Agent tool plugins (pluginType == agentTool) into dist-agent/plugin/agent// + String[] agentLibJars = java.util.Optional.ofNullable(file('dist-agent/lib').list()).orElse(new String[0]) + def agentPlugins = subprojects.findAll { + it.file('gradle.properties').exists() + && it.properties.containsKey('pluginType') + && it.properties.get('pluginType') == 'agentTool' + } + agentPlugins.forEach(subProject -> { + var pluginName = subProject.properties.get('pluginName') + logger.lifecycle('Install agent plugin: {}, module: {}', pluginName, subProject.name) + copy { + from subProject.jar.archivePath + into rootProject.file("dist-agent/plugin/agent/${pluginName}") + } + copy { + from subProject.configurations.runtimeClasspath + into rootProject.file("dist-agent/plugin/agent/${pluginName}") + exclude(agentLibJars) + } + }) copy { from 'tools/dist-license' into rootProject.file('dist-agent') diff --git a/docs/feature/agent-tools.md b/docs/feature/agent-tools.md index 58bb22d5cd..8e06af0d67 100644 --- a/docs/feature/agent-tools.md +++ b/docs/feature/agent-tools.md @@ -53,7 +53,7 @@ results as messages, and continues until it produces a final answer (bounded at 5 tool iterations). Without tools, behavior is unchanged token-by-token streaming. -## SPI-deployed custom tools +## In-tree agent plugins (`eventmesh-agent-plugin/`) Beyond connector-backed tools, custom tools follow the repo-standard plugin mechanism (same as storage/connector plugins): @@ -72,6 +72,21 @@ Resolution goes through `EventMeshExtensionFactory` — the same loader that serves storage and connector plugins, so singleton semantics and the `META-INF/eventmesh/` convention are identical. +## In-tree agent plugins + +The repo ships a plugin tree for agent tools — `eventmesh-agent-plugin/` — mirroring +`eventmesh-connector-plugin/`: each sub-module is a standalone jar with the +`META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool` service file, declared in +`gradle.properties` with `pluginType=agentTool` + `pluginName=`. The `dist-agent` task +installs every agent plugin into `dist-agent/plugin/agent//` (the directory the agent +launcher puts on the classpath), so custom in-tree tools need zero wiring: + +- `eventmesh-agent-plugin-http-fetch` — reference implementation: fetch a URL and return the + (truncated) body to the model. Enable with `AGENT_TOOLS_SPI=http-fetch`. + +Third-party jars follow the same shape: implement `AgentTool`, ship the service file, drop the +jar into `plugin/agent/`. + ## Event-driven agents (no user in the loop) Set a subscription list and an output topic: @@ -122,9 +137,9 @@ default `http://localhost:10105`). | Piece | Location | | --- | --- | -| LLM SPI + OpenAI default | `eventmesh-agent/.../agent/llm/{LlmClient,OpenAiLlmClient}.java` | -| Memory SPI + in-memory default | `eventmesh-agent/.../agent/{ConversationMemory,ConversationStore}.java` | -| Tool SPI + registry + adapter | `eventmesh-agent/.../agent/tool/{AgentTool,ToolRegistry,ConnectorToolAdapter}.java` | -| Tool loop + event trigger path | `eventmesh-agent/.../agent/StreamingAgent.java` | -| Boot wiring (tools + triggers) | `eventmesh-agent/.../agent/AgentApplication.java` | -| Tests | `eventmesh-agent/src/test/.../tool/*`, `.../llm/OpenAiLlmClientChatTest.java` | +| LLM SPI + OpenAI default | `eventmesh-agent-runtime/.../agent/llm/{LlmClient,OpenAiLlmClient}.java` | +| Memory SPI + in-memory default | `eventmesh-agent-runtime/.../agent/{ConversationMemory,ConversationStore}.java` | +| Tool SPI + registry + adapter | `eventmesh-agent-runtime/.../agent/tool/{AgentTool,ToolRegistry,ConnectorToolAdapter}.java` | +| Tool loop + event trigger path | `eventmesh-agent-runtime/.../agent/StreamingAgent.java` | +| Boot wiring (tools + triggers) | `eventmesh-agent-runtime/.../agent/AgentApplication.java` | +| Tests | `eventmesh-agent-runtime/src/test/.../tool/*`, `.../llm/OpenAiLlmClientChatTest.java` | diff --git a/docs/feature/client-java.md b/docs/feature/client-java.md index b68f5b2cb6..b63cb3a4d5 100644 --- a/docs/feature/client-java.md +++ b/docs/feature/client-java.md @@ -361,7 +361,7 @@ An agent that participates in Mode 1 follows a four-step contract: 3. on normal completion → emit a terminal frame `{chunk: "", done: true}` 4. on error → emit a terminal error frame `{chunk: "", done: true, error: "..."}` -Reference implementation: `eventmesh-agent/.../StreamingAgent.java` +Reference implementation: `eventmesh-agent-runtime/.../StreamingAgent.java` (instantiate with an LLM client, an `agentParent` topic, the agent's `agentId`, and a `ConversationStore`). @@ -656,7 +656,7 @@ history for the migration notes. (`/events/*` endpoints; `withSecurityGate(...)` wiring point) * A2A HTTP handler — `eventmesh-runtime/.../a2a/A2AGatewayHttpHandler.java` (`/a2a/*` endpoints; `withSecurityGate(...)` wiring point) -* Streaming agent — `eventmesh-agent/.../StreamingAgent.java` +* Streaming agent — `eventmesh-agent-runtime/.../StreamingAgent.java` * Storage plugins — * `eventmesh-storage-plugin/eventmesh-storage-rocketmq/` (SPI key `rocketmq`) * `eventmesh-storage-plugin/eventmesh-storage-rocketmq5/` (SPI key `rocketmq5`, diff --git a/eventmesh-agent-plugin/build.gradle b/eventmesh-agent-plugin/build.gradle new file mode 100644 index 0000000000..5db6fa86da --- /dev/null +++ b/eventmesh-agent-plugin/build.gradle @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Umbrella for agent tool plugins (AgentTool SPI, #5409). Each sub-module ships a jar with a +// META-INF/eventmesh/ service file; the dist-agent task installs them into +// dist-agent/plugin/agent//. diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle new file mode 100644 index 0000000000..8ddd3cb524 --- /dev/null +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + implementation project(':eventmesh-agent-runtime') + implementation 'com.fasterxml.jackson.core:jackson-databind' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + testImplementation 'org.assertj:assertj-core' +} diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/gradle.properties b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/gradle.properties new file mode 100644 index 0000000000..4a584bf8be --- /dev/null +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/gradle.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +pluginType=agentTool +pluginName=http-fetch diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java new file mode 100644 index 0000000000..f627d1a8e0 --- /dev/null +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.eventmesh.agent.plugin.httpfetch; + +import org.apache.eventmesh.agent.tool.AgentTool; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * Reference {@link AgentTool} implementation shipped as the first in-tree agent plugin: fetches a + * URL and returns the body (truncated) as the tool result for the model. Deployed via the + * META-INF/eventmesh service file; enable with {@code -Dagent.tools.spi=http-fetch}. + */ +@Slf4j +public class HttpFetchTool implements AgentTool { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static final int MAX_BODY_CHARS = 4000; + + private final HttpClient http = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + + @Override + public String name() { + return "http-fetch"; + } + + @Override + public String description() { + return "Fetch an HTTP/HTTPS URL and return the response body (text, truncated)"; + } + + @Override + public String parametersJsonSchema() { + return MAPPER.valueToTree(Map.of( + "type", "object", + "properties", Map.of( + "url", Map.of("type", "string", "description", "absolute http(s) URL to fetch")), + "required", java.util.List.of("url"))).toString(); + } + + @Override + public String invoke(Map args) throws Exception { + String url = String.valueOf(args.get("url")); + HttpRequest req = HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofSeconds(20)) + .GET() + .build(); + HttpResponse resp = http.send(req, HttpResponse.BodyHandlers.ofString()); + String body = resp.body() == null ? "" : resp.body(); + String truncated = body.length() > MAX_BODY_CHARS ? body.substring(0, MAX_BODY_CHARS) + "..." : body; + return MAPPER.writeValueAsString(Map.of("status", resp.statusCode(), "body", truncated)); + } +} diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool new file mode 100644 index 0000000000..6730a09135 --- /dev/null +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +http-fetch=org.apache.eventmesh.agent.plugin.httpfetch.HttpFetchTool diff --git a/eventmesh-agent/bin/start-agent.sh b/eventmesh-agent-runtime/bin/start-agent.sh similarity index 100% rename from eventmesh-agent/bin/start-agent.sh rename to eventmesh-agent-runtime/bin/start-agent.sh diff --git a/eventmesh-agent/build.gradle b/eventmesh-agent-runtime/build.gradle similarity index 96% rename from eventmesh-agent/build.gradle rename to eventmesh-agent-runtime/build.gradle index 3d6e0da9bc..430a906dce 100644 --- a/eventmesh-agent/build.gradle +++ b/eventmesh-agent-runtime/build.gradle @@ -21,7 +21,7 @@ // OpenAI 兼容的 LLM SSE client. dependencies { implementation project(':eventmesh-sdks:eventmesh-sdk-java') - implementation project(':eventmesh-connector-api') + implementation project(':eventmesh-connector-plugin:eventmesh-connector-api') implementation project(':eventmesh-spi') implementation 'io.cloudevents:cloudevents-core' implementation 'com.fasterxml.jackson.core:jackson-databind' diff --git a/eventmesh-agent/conf/agent.properties b/eventmesh-agent-runtime/conf/agent.properties similarity index 100% rename from eventmesh-agent/conf/agent.properties rename to eventmesh-agent-runtime/conf/agent.properties diff --git a/eventmesh-agent/conf/log4j2.xml b/eventmesh-agent-runtime/conf/log4j2.xml similarity index 100% rename from eventmesh-agent/conf/log4j2.xml rename to eventmesh-agent-runtime/conf/log4j2.xml diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/AgentApplication.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentApplication.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/AgentApplication.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentControlClient.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/AgentControlClient.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/AgentControlClient.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/AgentControlClient.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/ConversationMemory.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/ConversationMemory.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/ConversationMemory.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/ConversationMemory.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/ConversationStore.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/ConversationStore.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/ConversationStore.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/ConversationStore.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/StreamingAgent.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/StreamingAgent.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/StreamingAgent.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/StreamingAgent.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/LlmClient.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/LlmClient.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/LlmClient.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/LlmClient.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/LlmCompletion.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/LlmCompletion.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/LlmCompletion.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/LlmCompletion.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/OpenAiLlmClient.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/OpenAiLlmClient.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/OpenAiLlmClient.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/OpenAiLlmClient.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/ToolCall.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/ToolCall.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/ToolCall.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/ToolCall.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/ToolSpec.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/ToolSpec.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/llm/ToolSpec.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/llm/ToolSpec.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/AgentTool.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapter.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapter.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapter.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapter.java diff --git a/eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java b/eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java similarity index 100% rename from eventmesh-agent/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java rename to eventmesh-agent-runtime/src/main/java/org/apache/eventmesh/agent/tool/ToolRegistry.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/ConversationStoreTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/ConversationStoreTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/ConversationStoreTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/ConversationStoreTest.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientChatTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientChatTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientChatTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientChatTest.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/llm/OpenAiLlmClientTest.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/AgentToolSpiTest.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapterTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapterTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapterTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/ConnectorToolAdapterTest.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/EchoTestTool.java diff --git a/eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/ToolRegistryTest.java b/eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/ToolRegistryTest.java similarity index 100% rename from eventmesh-agent/src/test/java/org/apache/eventmesh/agent/tool/ToolRegistryTest.java rename to eventmesh-agent-runtime/src/test/java/org/apache/eventmesh/agent/tool/ToolRegistryTest.java diff --git a/eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool b/eventmesh-agent-runtime/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool similarity index 100% rename from eventmesh-agent/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool rename to eventmesh-agent-runtime/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.agent.tool.AgentTool diff --git a/eventmesh-architecture-guard/build.gradle b/eventmesh-architecture-guard/build.gradle index 66841aa4c2..d78e91b59a 100644 --- a/eventmesh-architecture-guard/build.gradle +++ b/eventmesh-architecture-guard/build.gradle @@ -50,7 +50,7 @@ dependencies { // test so the connector SPI boundary rule (plugins must not reach into runtime // internals) has classes in scope. Full plugin matrix enforced in CI via the // module graph; the guard samples one plugin (file) as the canary. - testImplementation project(':eventmesh-connector-api') + testImplementation project(':eventmesh-connector-plugin:eventmesh-connector-api') testImplementation project(':eventmesh-connector-runtime') testImplementation project(':eventmesh-connector-plugin:eventmesh-connector-file') // :eventmesh-storage-plugin:eventmesh-storage-kafka added for issue #5342 Q7 diff --git a/eventmesh-connector-api/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-api/build.gradle similarity index 100% rename from eventmesh-connector-api/build.gradle rename to eventmesh-connector-plugin/eventmesh-connector-api/build.gradle diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/CloudEventSerializer.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/CloudEventSerializer.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/CloudEventSerializer.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/CloudEventSerializer.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/ConnectorOffsetStore.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/ConnectorOffsetStore.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/ConnectorOffsetStore.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/ConnectorOffsetStore.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/EventMeshEndpoint.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/EventMeshEndpoint.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/EventMeshEndpoint.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/EventMeshEndpoint.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/HttpCaller.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/HttpCaller.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/HttpCaller.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/HttpCaller.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/PollEntry.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/PollEntry.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/PollEntry.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/PollEntry.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SinkConnector.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SinkConnector.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SinkConnector.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SinkConnector.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SourceConnector.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SourceConnector.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SourceConnector.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/SourceConnector.java diff --git a/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/package-info.java b/eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/package-info.java similarity index 100% rename from eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/package-info.java rename to eventmesh-connector-plugin/eventmesh-connector-api/src/main/java/org/apache/eventmesh/connector/package-info.java diff --git a/eventmesh-runtime/build.gradle b/eventmesh-runtime/build.gradle index f683c41f9e..3e01b5eecb 100644 --- a/eventmesh-runtime/build.gradle +++ b/eventmesh-runtime/build.gradle @@ -68,7 +68,7 @@ dependencies { // ClientBrokerIntegrationTest drives the runtime via the real CloudEventsClient SDK over HTTP. testImplementation project(':eventmesh-sdks:eventmesh-sdk-java') // LiteStreamCallIntegrationTest boots the agent (StreamingAgent + OpenAiLlmClient) in-process. - testImplementation project(':eventmesh-agent') + testImplementation project(':eventmesh-agent-runtime') // StreamingCallDemoE2ETest drives the demo's main() against a real booted runtime + agent. testImplementation project(':eventmesh-examples') } diff --git a/settings.gradle b/settings.gradle index 8933236a1f..bf461b4ad3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -67,11 +67,16 @@ include 'eventmesh-protocol-plugin:eventmesh-protocol-meshmessage' include 'eventmesh-protocol-plugin:eventmesh-protocol-a2a' // Connector Runtime — 独立模块 (与 EventMesh Runtime 经 HTTP 通信, 不互相依赖) -include 'eventmesh-connector-api' +// connector SPI (api) lives under the plugin tree like the other plugin families +include 'eventmesh-connector-plugin:eventmesh-connector-api' include 'eventmesh-connector-runtime' // Agent — 独立进程, 经 lite topic + CloudEvents 与 Runtime 通信, 调用真实 LLM (OpenAI 兼容) -include 'eventmesh-agent' +include 'eventmesh-agent-runtime' + +// Agent tool plugins (AgentTool SPI, #5409): drop-in jars for plugin/agent/ +include 'eventmesh-agent-plugin' +include 'eventmesh-agent-plugin:eventmesh-agent-plugin-http-fetch' // Examples — 可运行 demo (uni-architecture: 流式调用等); 依赖 SDK + common + a2a 协议 include 'eventmesh-examples' From 26eeef4495dd0e4d6d56c7c18181d0d7315f2ad6 Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 18:03:54 +0800 Subject: [PATCH 3/6] Fix restructure: point connector-runtime at the moved connector-api module path --- eventmesh-connector-runtime/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventmesh-connector-runtime/build.gradle b/eventmesh-connector-runtime/build.gradle index 46c8857c29..3c86c5331e 100644 --- a/eventmesh-connector-runtime/build.gradle +++ b/eventmesh-connector-runtime/build.gradle @@ -18,7 +18,7 @@ // Connector Runtime — 独立进程, 仅经 HTTP+CloudEvents 与 EventMesh Runtime 通信. // 不依赖 eventmesh-runtime, 只需 cloudevents + lombok. dependencies { - api project(':eventmesh-connector-api') + api project(':eventmesh-connector-plugin:eventmesh-connector-api') implementation 'io.cloudevents:cloudevents-core' implementation 'io.cloudevents:cloudevents-json-jackson' implementation 'com.fasterxml.jackson.core:jackson-databind' From 4fc1b65522fa12e3242da680c1a75b2698b1adc7 Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 18:19:29 +0800 Subject: [PATCH 4/6] Fix restructure: point all 23 connector plugins at the moved connector-api path (double-quote form) --- .../eventmesh-connector-canal/build.gradle | 2 +- .../eventmesh-connector-chatgpt/build.gradle | 2 +- .../eventmesh-connector-dingtalk/build.gradle | 2 +- .../eventmesh-connector-file/build.gradle | 2 +- .../eventmesh-connector-http/build.gradle | 2 +- .../eventmesh-connector-jdbc/build.gradle | 2 +- .../eventmesh-connector-kafka/build.gradle | 2 +- .../eventmesh-connector-knative/build.gradle | 2 +- .../eventmesh-connector-lark/build.gradle | 2 +- eventmesh-connector-plugin/eventmesh-connector-mcp/build.gradle | 2 +- .../eventmesh-connector-mongodb/build.gradle | 2 +- .../eventmesh-connector-openfunction/build.gradle | 2 +- .../eventmesh-connector-pravega/build.gradle | 2 +- .../eventmesh-connector-prometheus/build.gradle | 2 +- .../eventmesh-connector-pulsar/build.gradle | 2 +- .../eventmesh-connector-rabbitmq/build.gradle | 2 +- .../eventmesh-connector-redis/build.gradle | 2 +- .../eventmesh-connector-rocketmq/build.gradle | 2 +- eventmesh-connector-plugin/eventmesh-connector-s3/build.gradle | 2 +- .../eventmesh-connector-slack/build.gradle | 2 +- .../eventmesh-connector-spring/build.gradle | 2 +- .../eventmesh-connector-wechat/build.gradle | 2 +- .../eventmesh-connector-wecom/build.gradle | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/eventmesh-connector-plugin/eventmesh-connector-canal/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-canal/build.gradle index e1bd31a9dd..b44f3f6963 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-canal/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-canal/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.alibaba.otter:canal.client:1.1.7' diff --git a/eventmesh-connector-plugin/eventmesh-connector-chatgpt/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-chatgpt/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-chatgpt/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-chatgpt/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-dingtalk/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-dingtalk/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-dingtalk/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-dingtalk/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-file/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-file/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-file/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-file/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-http/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-http/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-http/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-http/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-jdbc/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-jdbc/build.gradle index 427dd28196..a86bc13077 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-jdbc/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-jdbc/build.gradle @@ -22,7 +22,7 @@ plugins { dependencies { antlr "org.antlr:antlr4:4.13.1" implementation 'org.antlr:antlr4-runtime:4.13.1' - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-kafka/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-kafka/build.gradle index 935362af82..4d2500a328 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-kafka/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-kafka/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'org.apache.kafka:kafka-clients:3.9.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-knative/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-knative/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-knative/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-knative/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-lark/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-lark/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-lark/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-lark/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-mcp/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-mcp/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-mcp/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-mcp/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-mongodb/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-mongodb/build.gradle index df6a3865f8..2d87d4b843 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-mongodb/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-mongodb/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'org.mongodb:mongodb-driver-sync:4.11.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-openfunction/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-openfunction/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-openfunction/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-openfunction/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-pravega/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-pravega/build.gradle index e19c0cfdf1..e993c8c8d4 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-pravega/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-pravega/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'io.pravega:pravega-client:0.11.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-prometheus/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-prometheus/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-prometheus/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-prometheus/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-pulsar/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-pulsar/build.gradle index 5b2de49841..a2d3a0fec9 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-pulsar/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-pulsar/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation "org.apache.pulsar:pulsar-client:3.3.0" diff --git a/eventmesh-connector-plugin/eventmesh-connector-rabbitmq/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-rabbitmq/build.gradle index cab1ad0cd7..443a581b20 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rabbitmq/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-rabbitmq/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation "com.rabbitmq:amqp-client:5.22.0" diff --git a/eventmesh-connector-plugin/eventmesh-connector-redis/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-redis/build.gradle index 50b23746b1..935f9ccefb 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-redis/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-redis/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation "org.redisson:redisson:3.38.1" diff --git a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle index 56001bd638..07d06df7cc 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-rocketmq/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation "org.apache.rocketmq:rocketmq-client:4.9.8" diff --git a/eventmesh-connector-plugin/eventmesh-connector-s3/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-s3/build.gradle index 2f2743d1f1..bd57cf1915 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-s3/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-s3/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'software.amazon.awssdk:s3:2.25.16' diff --git a/eventmesh-connector-plugin/eventmesh-connector-slack/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-slack/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-slack/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-slack/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' diff --git a/eventmesh-connector-plugin/eventmesh-connector-spring/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-spring/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-spring/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-spring/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-wechat/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-wechat/build.gradle index 14d7379284..ee4e9aa3ab 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-wechat/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-wechat/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' compileOnly 'org.projectlombok:lombok' diff --git a/eventmesh-connector-plugin/eventmesh-connector-wecom/build.gradle b/eventmesh-connector-plugin/eventmesh-connector-wecom/build.gradle index 9d3359fab0..9cf2cbeb2c 100644 --- a/eventmesh-connector-plugin/eventmesh-connector-wecom/build.gradle +++ b/eventmesh-connector-plugin/eventmesh-connector-wecom/build.gradle @@ -16,7 +16,7 @@ */ dependencies { - implementation project(":eventmesh-connector-api") + implementation project(":eventmesh-connector-plugin:eventmesh-connector-api") implementation 'io.cloudevents:cloudevents-core' implementation 'org.slf4j:slf4j-api' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.0' From c8ec154fd7b50e6c765a91ce22111d88d49ad73a Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 18:20:51 +0800 Subject: [PATCH 5/6] Fix restructure: update connector-api-split.md paths to the moved module --- docs/feature/connector-api-split.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/feature/connector-api-split.md b/docs/feature/connector-api-split.md index 7243108dbe..3557601acc 100644 --- a/docs/feature/connector-api-split.md +++ b/docs/feature/connector-api-split.md @@ -6,7 +6,7 @@ ## Goal Move the connector SPI interfaces out of `eventmesh-connector-runtime` into a new -`eventmesh-connector-api` module so plugins depend on a stable, minimal API jar and the runtime +`eventmesh-connector-plugin:eventmesh-connector-plugin:eventmesh-connector-api` module so plugins depend on a stable, minimal API jar and the runtime implements / orchestrates against that API. ## Interfaces to move @@ -24,7 +24,7 @@ From `eventmesh-connector-runtime/src/main/java/org/apache/eventmesh/connector/` ## Target layout ``` -eventmesh-connector-api/ +eventmesh-connector-plugin/eventmesh-connector-api/ src/main/java/org/apache/eventmesh/connector/api/ SourceConnector.java SinkConnector.java @@ -37,20 +37,20 @@ eventmesh-connector-api/ build.gradle (deps: cloudevents-core only — no plugin imports, no HTTP libs) ``` -`eventmesh-connector-runtime` depends on `:eventmesh-connector-api` and continues to provide +`eventmesh-connector-runtime` depends on `:eventmesh-connector-plugin:eventmesh-connector-api` and continues to provide implementations (`EventMeshHttpEndpoint`, `RocksDBConnectorOffsetStore`, `RemoteOffsetStore`, `InMemoryOffsetStore`, `ConnectorRuntime`, `ConnectorManager`, `ConnectorAdminServer`, `ConnectorApplication`, `ConnectorDef`). Each plugin under `eventmesh-connector-plugin/eventmesh-connector-*` should depend on -`:eventmesh-connector-api` instead of `:eventmesh-connector-runtime`. +`:eventmesh-connector-plugin:eventmesh-connector-api` instead of `:eventmesh-connector-runtime`. ## Plugin changes (mechanical) For each of the 23 plugins: 1. `build.gradle`: replace `implementation project(":eventmesh-connector-runtime")` with - `implementation project(":eventmesh-connector-api")`. + `implementation project(":eventmesh-connector-plugin:eventmesh-connector-api")`. 2. Source code: if the plugin imports `org.apache.eventmesh.connector.ConnectorRuntime` (it should not — plugins only use the SPI), add `implementation project(":eventmesh-connector-runtime")` back. Initial audit shows no plugin currently touches runtime internals. @@ -90,9 +90,9 @@ will fail the architecture guard. ## Acceptance criteria for the implementation PR(s) -- [ ] `eventmesh-connector-api` jar builds standalone (deps: cloudevents-core only). -- [ ] `eventmesh-connector-runtime` depends on `:eventmesh-connector-api`. -- [ ] All 23 plugin modules depend on `:eventmesh-connector-api`, not on `:eventmesh-connector-runtime`. +- [ ] `eventmesh-connector-plugin:eventmesh-connector-plugin:eventmesh-connector-api` jar builds standalone (deps: cloudevents-core only). +- [ ] `eventmesh-connector-runtime` depends on `:eventmesh-connector-plugin:eventmesh-connector-api`. +- [ ] All 23 plugin modules depend on `:eventmesh-connector-plugin:eventmesh-connector-api`, not on `:eventmesh-connector-runtime`. - [ ] ArchUnit rule is added and **fails** the build if any plugin reaches into runtime internals. - [ ] `:eventmesh-architecture-guard:test` passes. - [ ] Existing runtime + plugin tests stay green (this PR added the baseline tests they will From 9be70b1257ff8f92c4438d7d7618c3f0d3f265cf Mon Sep 17 00:00:00 2001 From: qqeasonchen Date: Mon, 21 Sep 2026 18:29:16 +0800 Subject: [PATCH 6/6] Fix http-fetch plugin: drop unused @Slf4j/lombok, slim deps (spi types resolve via agent-runtime) --- .../eventmesh-agent-plugin-http-fetch/build.gradle | 3 --- .../apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle index 8ddd3cb524..07bb2ea996 100644 --- a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/build.gradle @@ -19,8 +19,5 @@ dependencies { implementation project(':eventmesh-agent-runtime') implementation 'com.fasterxml.jackson.core:jackson-databind' - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.assertj:assertj-core' } diff --git a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java index f627d1a8e0..7c4ad26407 100644 --- a/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java +++ b/eventmesh-agent-plugin/eventmesh-agent-plugin-http-fetch/src/main/java/org/apache/eventmesh/agent/plugin/httpfetch/HttpFetchTool.java @@ -28,14 +28,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; - /** * Reference {@link AgentTool} implementation shipped as the first in-tree agent plugin: fetches a * URL and returns the body (truncated) as the tool result for the model. Deployed via the * META-INF/eventmesh service file; enable with {@code -Dagent.tools.spi=http-fetch}. */ -@Slf4j public class HttpFetchTool implements AgentTool { private static final ObjectMapper MAPPER = new ObjectMapper();