4242import io .sentrius .sso .core .dto .agents .AgentContextRequestDTO ;
4343import io .sentrius .sso .core .dto .agents .AgentExecutionContextDTO ;
4444import io .sentrius .sso .core .dto .agents .AgentExecution ;
45+ import io .sentrius .sso .core .dto .capabilities .EndpointDescriptor ;
4546import io .sentrius .sso .core .dto .ztat .AtatRequest ;
4647import io .sentrius .sso .core .dto .ztat .TokenDTO ;
4748import io .sentrius .sso .core .dto .ztat .ZtatRequestDTO ;
@@ -80,6 +81,10 @@ public class AgentVerbs extends VerbBase {
8081
8182 final ObjectMapper mapper = new ObjectMapper (new YAMLFactory ()); // Jackson ObjectMapper for YAML parsing
8283 private final AgentExecutionService agentExecutionService ;
84+
85+ // Field names to search when extracting query strings from nested JSON structures
86+ private static final String [] QUERY_FIELD_NAMES = {"arg1" , "field" , "context" , "query" , "text" , "value" };
87+
8388
8489 /**
8590 * Constructs an `AgentVerbs` instance with the required services and registry.
@@ -804,8 +809,9 @@ public ObjectNode createAgent(AgentExecution execution, AgentExecutionContextDTO
804809 return contextNode ;
805810 }
806811
807- @ Verb (name = "get_agent_status" , returnType = AgentExecutionContextDTO .class , description = "Queries the agent status. Can" +
808- " be Running, pending, NotFound, or Failed" ,
812+ @ Verb (name = "get_agent_status" , returnType = AgentExecutionContextDTO .class , description = "Queries the agent " +
813+ "status for other agents. Not to be used internally. Can" +
814+ " be Running, pending, NotFound, or Failed." ,
809815 exampleJson = "{ \" agentName\" : \" agentName\" }" ,
810816 requiresTokenManagement = true )
811817 public ObjectNode getAgentStatus (AgentExecution execution , AgentExecutionContextDTO agentIdentifier )
@@ -825,6 +831,8 @@ public ObjectNode getAgentStatus(AgentExecution execution, AgentExecutionContext
825831 return contextNode ;
826832 }
827833
834+
835+
828836 @ Verb (name = "get_endpoints_like" , returnType = AgentExecutionContextDTO .class , description = "Queries for endpoints in " +
829837 "the system that match the input text." ,
830838 returnName = "endpoints" ,
@@ -841,33 +849,94 @@ public ObjectNode getEndpointsLike(AgentExecution execution,
841849 var parsedQuery = queryInput .get ("endpoints_like" );
842850
843851 if (null == parsedQuery ) {
844- throw new IllegalArgumentException ("Missing 'endpoints_like' argument" );
852+ throw new IllegalArgumentException ("Missing 'endpoints_like' argument. Expected format: " +
853+ "{ \" endpoints_like\" : [\" query text 1\" , \" query text 2\" ] }" );
845854 }
855+
846856 ObjectNode contextNode = JsonUtil .MAPPER .createObjectNode ();
847857 ArrayNode endpoints = JsonUtil .MAPPER .createArrayNode ();
848- for (JsonNode node : parsedQuery ) {
849- if (!node .isTextual ()) {
850- if (node .has ("arg1" )){
851- node = node .get ("arg1" );
852- if (!node .isTextual ()) {
853- throw new IllegalArgumentException ("All items in 'endpoints_like' must be strings" );
854- }
858+
859+ // Handle different input formats from the LLM
860+ List <String > queryStrings = new ArrayList <>();
861+
862+ if (parsedQuery .isArray ()) {
863+ // Expected format: ["text1", "text2"]
864+ for (JsonNode node : parsedQuery ) {
865+ String queryText = extractQueryString (node );
866+ if (queryText != null && !queryText .isEmpty ()) {
867+ queryStrings .add (queryText );
855868 }
856869 }
857- var endpointList = endpointSearcher .getEndpointsLike (execution , node .asText ());
858- JsonNode finalNode = node ;
859- endpointList .forEach (endpoint -> {
870+ } else if (parsedQuery .isObject ()) {
871+ // Handle nested object format: {"arg1": {"field": "text"}} or {"arg1": "text"}
872+ String queryText = extractQueryString (parsedQuery );
873+ if (queryText != null && !queryText .isEmpty ()) {
874+ queryStrings .add (queryText );
875+ }
876+ } else if (parsedQuery .isTextual ()) {
877+ // Simple string format
878+ queryStrings .add (parsedQuery .asText ());
879+ }
880+
881+ if (queryStrings .isEmpty ()) {
882+ throw new IllegalArgumentException ("Could not extract any valid query strings from 'endpoints_like'. " +
883+ "Expected format: { \" endpoints_like\" : [\" query text 1\" , \" query text 2\" ] }. " +
884+ "Received: " + parsedQuery .toString ());
885+ }
886+
887+ // Query endpoints for each search string
888+ for (String queryText : queryStrings ) {
889+ log .info ("Searching endpoints for: {}" , queryText );
890+ var endpointList = endpointSearcher .getEndpointsLike (execution , queryText );
891+ for (EndpointDescriptor endpoint : endpointList ) {
860892 ObjectNode endpointNode = JsonUtil .MAPPER .createObjectNode ();
861- endpointNode .put ("name" , finalNode .asText ());
893+ endpointNode .put ("name" , endpoint .getName ());
894+ endpointNode .put ("description" , endpoint .getDescription ());
862895 endpointNode .put ("method" , endpoint .getHttpMethod ());
863896 endpointNode .put ("endpoint" , endpoint .getPath ());
897+ endpointNode .put ("searchQuery" , queryText );
864898 endpoints .add (endpointNode );
865- });
899+ }
866900 }
901+
867902 contextNode .put ("endpoints" , endpoints );
868903
869904 return contextNode ;
870905 }
906+
907+ /**
908+ * Recursively extracts a query string from a JsonNode, handling various nested structures.
909+ * Tries common patterns like {"arg1": "text"}, {"field": "text"}, {"context": "text"}, etc.
910+ */
911+ private String extractQueryString (JsonNode node ) {
912+ if (node == null ) {
913+ return null ;
914+ }
915+
916+ if (node .isTextual ()) {
917+ return node .asText ();
918+ }
919+
920+ if (node .isObject ()) {
921+ // Try common field names that might contain the query
922+ for (String fieldName : QUERY_FIELD_NAMES ) {
923+ if (node .has (fieldName )) {
924+ log .debug ("Extracting query string from field: {}" , fieldName );
925+ return extractQueryString (node .get (fieldName ));
926+ }
927+ }
928+
929+ // If no known fields, try the first field as fallback
930+ var fields = node .fields ();
931+ if (fields .hasNext ()) {
932+ var entry = fields .next ();
933+ log .warn ("No recognized query field found in object, using first field: {}" , entry .getKey ());
934+ return extractQueryString (entry .getValue ());
935+ }
936+ }
937+
938+ return null ;
939+ }
871940
872941 @ Verb (name = "call_endpoint" , returnType = AgentExecutionContextDTO .class , description = "Executes an endpoint at the " +
873942 "service. Input " , exampleJson = "{ \" endpoint\" : \" <url>\" , \" method\" : \" httpMethod\" , \" params\" : { " +
0 commit comments