This is an automated email from the ASF dual-hosted git repository.

wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new 064341a3 [hotfix] Register all resource types added via 
Agent.addResource (#668)
064341a3 is described below

commit 064341a3c7c49234117991f082911a377696e717
Author: Eugene <[email protected]>
AuthorDate: Thu May 14 15:18:24 2026 +0800

    [hotfix] Register all resource types added via Agent.addResource (#668)
---
 .../org/apache/flink/agents/plan/AgentPlan.java    | 56 ++++++++++++------
 .../apache/flink/agents/plan/AgentPlanTest.java    | 69 ++++++++++++++++++++++
 2 files changed, 106 insertions(+), 19 deletions(-)

diff --git a/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java 
b/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java
index 3fb15109..3a77f866 100644
--- a/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java
+++ b/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java
@@ -246,6 +246,18 @@ public class AgentPlan implements Serializable {
         }
     }
 
+    private static ResourceDescriptor requireResourceDescriptor(
+            String name, ResourceType type, Object value) {
+        if (!(value instanceof ResourceDescriptor)) {
+            throw new IllegalStateException(
+                    String.format(
+                            "Resource '%s' of type %s must be a 
ResourceDescriptor when added via"
+                                    + " Agent.addResource, but got %s",
+                            name, type, value == null ? "null" : 
value.getClass().getName()));
+        }
+        return (ResourceDescriptor) value;
+    }
+
     private void extractResource(ResourceType type, Method method) throws 
Exception {
         extractResource(type, method, null);
     }
@@ -462,25 +474,7 @@ public class AgentPlan implements Serializable {
 
         for (Map.Entry<ResourceType, Map<String, Object>> entry : 
agent.getResources().entrySet()) {
             ResourceType type = entry.getKey();
-            if (type == ResourceType.CHAT_MODEL || type == 
ResourceType.CHAT_MODEL_CONNECTION) {
-                for (Map.Entry<String, Object> kv : 
entry.getValue().entrySet()) {
-                    ResourceProvider provider;
-                    if (PythonResourceWrapper.class.isAssignableFrom(
-                            Class.forName(
-                                    ((ResourceDescriptor) 
kv.getValue()).getClazz(),
-                                    true,
-                                    
Thread.currentThread().getContextClassLoader()))) {
-                        provider =
-                                new PythonResourceProvider(
-                                        kv.getKey(), type, 
(ResourceDescriptor) kv.getValue());
-                    } else {
-                        provider =
-                                new JavaResourceProvider(
-                                        kv.getKey(), type, 
(ResourceDescriptor) kv.getValue());
-                    }
-                    addResourceProvider(provider);
-                }
-            } else if (type == PROMPT) {
+            if (type == PROMPT) {
                 for (Map.Entry<String, Object> kv : 
entry.getValue().entrySet()) {
                     JavaSerializableResourceProvider provider =
                             
JavaSerializableResourceProvider.createResourceProvider(
@@ -500,6 +494,30 @@ public class AgentPlan implements Serializable {
                         skillsObjects.put(kv.getKey(), (Skills) kv.getValue());
                     }
                 }
+            } else if (type == MCP_SERVER) {
+                if (!entry.getValue().isEmpty()) {
+                    throw new UnsupportedOperationException(
+                            "Adding an MCP server via Agent.addResource is not 
supported."
+                                    + " Declare the MCP server with a 
@MCPServer-annotated static"
+                                    + " method on your Agent class so its 
tools and prompts can be"
+                                    + " discovered.");
+                }
+            } else {
+                for (Map.Entry<String, Object> kv : 
entry.getValue().entrySet()) {
+                    ResourceDescriptor descriptor =
+                            requireResourceDescriptor(kv.getKey(), type, 
kv.getValue());
+                    ResourceProvider provider;
+                    if (PythonResourceWrapper.class.isAssignableFrom(
+                            Class.forName(
+                                    descriptor.getClazz(),
+                                    true,
+                                    
Thread.currentThread().getContextClassLoader()))) {
+                        provider = new PythonResourceProvider(kv.getKey(), 
type, descriptor);
+                    } else {
+                        provider = new JavaResourceProvider(kv.getKey(), type, 
descriptor);
+                    }
+                    addResourceProvider(provider);
+                }
             }
         }
 
diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java 
b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java
index 29196620..7e7d0870 100644
--- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java
+++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java
@@ -33,6 +33,7 @@ import 
org.apache.flink.agents.api.resource.SerializableResource;
 import org.apache.flink.agents.api.resource.python.PythonResourceAdapter;
 import org.apache.flink.agents.api.resource.python.PythonResourceWrapper;
 import org.apache.flink.agents.plan.actions.Action;
+import org.apache.flink.agents.plan.resourceprovider.JavaResourceProvider;
 import 
org.apache.flink.agents.plan.resourceprovider.JavaSerializableResourceProvider;
 import org.apache.flink.agents.plan.resourceprovider.PythonResourceProvider;
 import org.apache.flink.agents.plan.resourceprovider.ResourceProvider;
@@ -356,4 +357,72 @@ public class AgentPlanTest {
         
assertThat(pythonChatModelProvider.getName()).isEqualTo("pythonChatModel");
         
assertThat(pythonChatModelProvider.getType()).isEqualTo(ResourceType.CHAT_MODEL);
     }
+
+    @Test
+    public void testAddResourceRegistersEmbeddingModelProvider() throws 
Exception {
+        Agent agent = new Agent();
+        ResourceDescriptor descriptor =
+                
ResourceDescriptor.Builder.newBuilder(TestPythonResource.class.getName())
+                        .addInitialArgument("pythonClazz", 
"test.module.EmbeddingClazz")
+                        .build();
+        agent.addResource("myEmbedding", ResourceType.EMBEDDING_MODEL, 
descriptor);
+
+        AgentPlan plan = new AgentPlan(agent);
+
+        Map<String, ResourceProvider> providers =
+                plan.getResourceProviders().get(ResourceType.EMBEDDING_MODEL);
+        assertThat(providers).isNotNull();
+        assertThat(providers).containsKey("myEmbedding");
+
+        ResourceProvider provider = providers.get("myEmbedding");
+        // TestPythonResource implements PythonResourceWrapper, so a Python 
provider is expected.
+        assertThat(provider).isInstanceOf(PythonResourceProvider.class);
+        assertThat(provider.getName()).isEqualTo("myEmbedding");
+        assertThat(provider.getType()).isEqualTo(ResourceType.EMBEDDING_MODEL);
+    }
+
+    @Test
+    public void testAddResourceRegistersVectorStoreJavaProvider() throws 
Exception {
+        Agent agent = new Agent();
+        // A non-Python-wrapper class triggers JavaResourceProvider — String 
is fine for this
+        // structural check; we never call provide() here.
+        ResourceDescriptor descriptor =
+                
ResourceDescriptor.Builder.newBuilder(String.class.getName()).build();
+        agent.addResource("myVectorStore", ResourceType.VECTOR_STORE, 
descriptor);
+
+        AgentPlan plan = new AgentPlan(agent);
+
+        ResourceProvider provider =
+                
plan.getResourceProviders().get(ResourceType.VECTOR_STORE).get("myVectorStore");
+        assertThat(provider).isInstanceOf(JavaResourceProvider.class);
+        assertThat(provider.getType()).isEqualTo(ResourceType.VECTOR_STORE);
+    }
+
+    @Test
+    public void testAddResourceRejectsNonDescriptorForUnsupportedType() {
+        Agent agent = new Agent();
+        // SerializableResource for EMBEDDING_MODEL is illegal — only PROMPT / 
TOOL / SKILLS accept
+        // non-descriptors. The new code path must reject it with a clear 
message instead of CCE.
+        agent.addResource(
+                "badEmbedding",
+                ResourceType.EMBEDDING_MODEL,
+                new TestSerializableChatModel("badEmbedding"));
+
+        Assertions.assertThrows(IllegalStateException.class, () -> new 
AgentPlan(agent));
+    }
+
+    @Test
+    public void testAddResourceMCPServerRejectedWithGuidance() {
+        Agent agent = new Agent();
+        ResourceDescriptor descriptor =
+                ResourceDescriptor.Builder.newBuilder("dummy.MCPServer")
+                        .addInitialArgument("endpoint", 
"http://127.0.0.1:0/mcp";)
+                        .build();
+        agent.addResource("addedMcpServer", ResourceType.MCP_SERVER, 
descriptor);
+
+        UnsupportedOperationException ex =
+                Assertions.assertThrows(
+                        UnsupportedOperationException.class, () -> new 
AgentPlan(agent));
+        assertThat(ex.getMessage()).contains("@MCPServer");
+    }
 }

Reply via email to