@@ -587,112 +587,6 @@ public List<ZtatAsessment> analyzeAtatRequests(AgentExecution execution, List<At
587587 }
588588
589589
590- @ Verb (
591- name = "create_agent_context" , returnType = AgentContextDTO .class , description = "Creates an agent Context." +
592- " must be done before creating an agent." ,
593- requiresTokenManagement = true ,
594- returnName = "created_context" ,
595- exampleJson = "{ \" context\" : \" Notify when a new user is added\" }"
596- )
597- public AgentContextDTO createAgentContext (AgentExecution execution , AgentExecutionContextDTO context )
598- throws ZtatException , Exception {
599- log .info ("Creating agent context" );
600- var contextArgs = context .getExecutionArgs ();
601- if (contextArgs == null || contextArgs .isEmpty ()) {
602- throw new RuntimeException ("Context is required to create an agent context" );
603- }
604- var name = context .getExecutionArgument ("agentName" );
605-
606- String agentName = name .isPresent () ? name .get ().toString () : "name" ;
607- if (!agentName .isEmpty ()) {
608- agentName = agentName .replaceAll ("_" , "-" );
609- }
610-
611- var originalContext = context .getExecutionArgument ("context" );
612-
613- var requestDtoContext = normalize ( originalContext .orElseThrow ().toString () );
614- requestDtoContext += ". Please request endpoints to perform your work." ;
615- AgentContextRequestDTO dto = AgentContextRequestDTO .builder ().context (requestDtoContext ).
616- description (requestDtoContext ).name (agentName ).build ();
617- var createdContext = agentClientService .createAgentContext (execution , dto );
618- // Here you would typically create a context in your system, e.g., store it in a database or cache.
619-
620- context .setAgentContext (AgentContextDTO .builder ()
621- .contextId (createdContext .getContextId ())
622- .name (createdContext .getName ())
623- .context (createdContext .getContext ())
624- .description (createdContext .getDescription ())
625- .build ());
626-
627- // load the endpoints
628- var messages = new ArrayList <Message >();
629-
630- messages .add (Message .builder ().role ("system" ).content ("The user will provide the context of what an agent to " +
631- "be created will do. Respond with a json response { \" endpoints_like\" : [ array ] } where array is the " +
632- "features " +
633- "or tools to be called. Do not put endpoints in there, just text and explanation of the endpoint. " +
634- "We'll perform a text " +
635- "search to find" +
636- " endpoints" ).build ());
637- messages .add (Message .builder ().role ("user" ).content (originalContext .get ().asText ()).build ());
638-
639- LLMRequest chatRequest = LLMRequest .builder ().model ("gpt-4o-mini" ).messages (messages ).build ();
640- var resp = llmService .askQuestion (execution , chatRequest );
641-
642- Response response = JsonUtil .MAPPER .readValue (resp , Response .class );
643- log .info ("Response is {}" , resp );
644- ArrayNode endpointsLikeList = JsonUtil .MAPPER .createArrayNode ();
645- for (Response .OutputItem choice : response .getOutputItems ()) {
646- var content = choice .getContent ().stream ().filter (c -> "output_text" .equals (c .getType ()) || "text" .equals (c .getType ())).map (c -> c .getText ()).findFirst ().orElse ("" );
647- if (content .startsWith ("```json" )) {
648- content = content .substring (7 , content .length () - 3 );
649- } else if (content .startsWith ("```" )) {
650- content = content .substring (3 , content .length () - 3 );
651- }
652- log .info ("content is {}" , content );
653- if (null != content && !content .isEmpty ()) {
654-
655- var node = JsonUtil .MAPPER .enable (JsonParser .Feature .ALLOW_COMMENTS ).readTree (content );
656-
657- if (node .get ("endpoints_like" ) == null || !node .get ("endpoints_like" ).isArray ()) {
658- log .info ("No endpoints_like found in response" );
659- continue ;
660- }
661- var arrayNode = (ArrayNode ) node .get ("endpoints_like" );
662- for (JsonNode localNode : arrayNode ) {
663- if (localNode .isNull () || localNode .asText ().isEmpty ()) {
664- continue ;
665- }
666- if (localNode .has ("method" ) && localNode .has ("endpoint" )) {
667-
668- if (localNode .get ("endpoint" ).asText ().isEmpty () || localNode .get ("method" ).asText ().isEmpty ()) {
669- log .info ("Skipping empty endpoint or method" );
670- continue ;
671- }
672-
673- endpointsLikeList .add (localNode .asText ());
674- }
675-
676- }
677-
678- }
679- }
680-
681- if (endpointsLikeList .size () > 0 ) {
682-
683- ObjectNode endpointsLike = JsonUtil .MAPPER .createObjectNode ();
684- endpointsLike .put ("context" , originalContext .orElseThrow ().toString ());
685- endpointsLike .put ("endpoints_like" , endpointsLikeList );
686- context .setExecutionArgs (endpointsLike );
687- var endpoints = getEndpointsLike (execution , context );
688- log .info ("Endpoints like {}" , endpoints );
689-
690- context .addToMemory ("endpoints" , endpoints );
691- }
692-
693- return createdContext ;
694- }
695-
696590 private String normalize (String s ) {
697591 if (s == null ) return null ;
698592 if (s .startsWith ("\" " ) && s .endsWith ("\" " )) {
@@ -865,74 +759,214 @@ public ObjectNode getCurrentAgentStatus(AgentExecution execution, AgentExecution
865759 return result ;
866760 }
867761
868- @ Verb (name = "create_agent" , returnType = AgentExecutionContextDTO .class , description = "Creates an agent who has the " +
869- "context. a previously defined contextId is required. previously defined endpoints can be used to build a " +
870- "trust policy. must call create_agent_context before this verb. agent type is chat or chat-autonomous. chat is chat only, chat-autonomous is chat and autonomous. determine based on workload." ,
871- exampleJson = "{ \" agentName\" : \" agentName\" , \" agentType\" : \" agentType\" }" ,
872- requiresTokenManagement = true )
873- public ObjectNode createAgent (AgentExecution execution , AgentExecutionContextDTO context )
874- throws ZtatException , JsonProcessingException {
875- log .info ("Creating agent with context: {}" , context );
876-
877- var contextId =context .getSafeLabel ("created_context" , "contextId" );
878- var agentName = context .getSafeLabel ("agentName" );
879- var agentType = context .getSafeLabel ("agentType" );
880- Optional <ObjectNode > optEndpoints = context .getExecutionArgumentScoped ("endpoints" , ObjectNode .class );
881- var policyId = "" ;
882- log .info ("Context ID is {}, agentName is {}" , contextId , agentName );
883- if (null != optEndpoints && optEndpoints .isPresent ()) {
884- var policyBuilder = ATPLPolicy .builder ()
885- .version ("v0" )
886- .description ("Policy for agent " + agentName )
887- .policyId (UUID .randomUUID ().toString ());
888-
889- var endpoints = optEndpoints .get ().get ("endpoints" );
890- log .info ("Endpoints are {}" , endpoints );
891- List <Capability > capabilities = new ArrayList <>();
892- for (JsonNode endpoint : endpoints ) {
893- var endpointStr = endpoint .get ("endpoint" ).asText ();
894-
895- Capability capability = Capability .builder ()
896- .description (endpoint .get ("name" ).asText ())
897- .endpoints (List .of (extractNormalizedPath (endpointStr )))
898- .build ();
899- capabilities .add (capability );
762+ /**
763+ * Creates an agent with its context, trust policy, and endpoint discovery in a single call.
764+ * This is the primary method for agent creation, handling context creation,
765+ * LLM-driven endpoint discovery, trust policy generation, and agent registration.
766+ *
767+ * @param execution The agent execution context containing authentication and execution details
768+ * @param context The execution context DTO containing agentName, context, and agentType parameters
769+ * @return ObjectNode containing the created agent's ID and context information
770+ * @throws ZtatException If there is an error during API communication
771+ * @throws Exception If there is an error during LLM communication or endpoint discovery
772+ */
773+ @ Verb (
774+ name = "create_agent_with_context" ,
775+ returnType = ObjectNode .class ,
776+ description = "Creates an agent with context, trust policy, and endpoint discovery in a single call. " +
777+ "This handles context creation, endpoint discovery via LLM, trust policy generation, and agent creation. " +
778+ "Agent type can be 'chat' (chat only) or 'chat-autonomous' (chat and autonomous). " +
779+ "Determine agent type based on whether the workload requires autonomous operation." ,
780+ exampleJson = "{ \" agentName\" : \" my-agent\" , \" context\" : \" Notify when a new user is added\" , \" agentType\" : \" chat\" }" ,
781+ requiresTokenManagement = true ,
782+ returnName = "created_agent"
783+ )
784+ public ObjectNode createAgentWithContext (AgentExecution execution , AgentExecutionContextDTO context )
785+ throws ZtatException , Exception {
786+ log .info ("Creating agent with context in a single call" );
787+
788+ // Step 1: Extract and validate parameters
789+ var contextArgs = context .getExecutionArgs ();
790+ if (contextArgs == null || contextArgs .isEmpty ()) {
791+ throw new RuntimeException ("Arguments are required to create an agent. Expected: agentName, context, agentType" );
792+ }
793+
794+ var nameArg = context .getExecutionArgument ("agentName" );
795+ String agentName = nameArg .isPresent () ? nameArg .get ().asText () : "agent-" + UUID .randomUUID ().toString ().substring (0 , 8 );
796+ if (!agentName .isEmpty ()) {
797+ agentName = agentName .replaceAll ("_" , "-" );
798+ }
799+
800+ var originalContext = context .getExecutionArgument ("context" );
801+ if (originalContext .isEmpty ()) {
802+ throw new RuntimeException ("Context is required to create an agent. Please provide a description of what the agent should do." );
803+ }
804+
805+ var agentTypeArg = context .getExecutionArgument ("agentType" );
806+ String agentType = agentTypeArg .isPresent () ? agentTypeArg .get ().asText () : "chat" ;
807+
808+ log .info ("Creating agent '{}' with type '{}' and context: {}" , agentName , agentType , originalContext .get ().asText ());
809+
810+ // Step 2: Create the agent context via API
811+ var requestDtoContext = normalize (originalContext .get ().asText ());
812+ requestDtoContext += ". Please request endpoints to perform your work." ;
813+ AgentContextRequestDTO dto = AgentContextRequestDTO .builder ()
814+ .context (requestDtoContext )
815+ .description (requestDtoContext )
816+ .name (agentName )
817+ .build ();
818+ var createdContext = agentClientService .createAgentContext (execution , dto );
819+
820+ if (createdContext == null || createdContext .getContextId () == null ) {
821+ throw new RuntimeException ("Failed to create agent context" );
822+ }
900823
824+ context .setAgentContext (AgentContextDTO .builder ()
825+ .contextId (createdContext .getContextId ())
826+ .name (createdContext .getName ())
827+ .context (createdContext .getContext ())
828+ .description (createdContext .getDescription ())
829+ .build ());
901830
831+ log .info ("Created agent context with ID: {}" , createdContext .getContextId ());
832+
833+ // Step 3: Use LLM to discover endpoints based on context
834+ var messages = new ArrayList <Message >();
835+ messages .add (Message .builder ().role ("system" ).content ("The user will provide the context of what an agent to " +
836+ "be created will do. Respond with a json response { \" endpoints_like\" : [ array ] } where array is the " +
837+ "features " +
838+ "or tools to be called. Do not put endpoints in there, just text and explanation of the endpoint. " +
839+ "We'll perform a text " +
840+ "search to find" +
841+ " endpoints" ).build ());
842+ messages .add (Message .builder ().role ("user" ).content (originalContext .get ().asText ()).build ());
843+
844+ LLMRequest chatRequest = LLMRequest .builder ().model ("gpt-4o-mini" ).messages (messages ).build ();
845+ var resp = llmService .askQuestion (execution , chatRequest );
846+
847+ Response response = JsonUtil .MAPPER .readValue (resp , Response .class );
848+ log .info ("LLM response for endpoint discovery: {}" , resp );
849+
850+ ArrayNode endpointsLikeList = JsonUtil .MAPPER .createArrayNode ();
851+ for (Response .OutputItem choice : response .getOutputItems ()) {
852+ var content = choice .getContent ().stream ()
853+ .filter (c -> "output_text" .equals (c .getType ()) || "text" .equals (c .getType ()))
854+ .map (c -> c .getText ())
855+ .findFirst ()
856+ .orElse ("" );
857+ if (content .startsWith ("```json" )) {
858+ content = content .substring (7 , content .length () - 3 );
859+ } else if (content .startsWith ("```" )) {
860+ content = content .substring (3 , content .length () - 3 );
902861 }
903- CapabilitySet capabilitySet = CapabilitySet .builder ()
904- .primitives (capabilities )
905- .build ();
906- policyBuilder .capabilities (capabilitySet );
907862
908- ATPLPolicy policy = policyBuilder .build ();
863+ if (null != content && !content .isEmpty ()) {
864+ var node = JsonUtil .MAPPER .enable (JsonParser .Feature .ALLOW_COMMENTS ).readTree (content );
909865
910- policyId = savePolicy (execution , true , policy );
866+ if (node .get ("endpoints_like" ) == null || !node .get ("endpoints_like" ).isArray ()) {
867+ log .info ("No endpoints_like found in response" );
868+ continue ;
869+ }
870+ var arrayNode = (ArrayNode ) node .get ("endpoints_like" );
871+ for (JsonNode localNode : arrayNode ) {
872+ if (localNode .isNull () || localNode .asText ().isEmpty ()) {
873+ continue ;
874+ }
875+ if (localNode .has ("method" ) && localNode .has ("endpoint" )) {
876+ if (localNode .get ("endpoint" ).asText ().isEmpty () || localNode .get ("method" ).asText ().isEmpty ()) {
877+ log .info ("Skipping empty endpoint or method" );
878+ continue ;
879+ }
880+ endpointsLikeList .add (localNode .asText ());
881+ } else {
882+ // Handle simple text entries (common LLM response format)
883+ endpointsLikeList .add (localNode .asText ());
884+ }
885+ }
886+ }
887+ }
911888
912- } else {
913- log .info ("No endpoints provided, using default" );
889+ // Step 4: Discover actual endpoints based on LLM suggestions
890+ ObjectNode discoveredEndpoints = null ;
891+ if (endpointsLikeList .size () > 0 ) {
892+ ObjectNode endpointsLike = JsonUtil .MAPPER .createObjectNode ();
893+ endpointsLike .put ("context" , originalContext .get ().asText ());
894+ endpointsLike .put ("endpoints_like" , endpointsLikeList );
895+ context .setExecutionArgs (endpointsLike );
896+ discoveredEndpoints = getEndpointsLike (execution , context );
897+ log .info ("Discovered endpoints: {}" , discoveredEndpoints );
898+ context .addToMemory ("endpoints" , discoveredEndpoints );
914899 }
915900
901+ // Step 5: Build trust policy from discovered endpoints
902+ String policyId = "" ;
903+ if (discoveredEndpoints != null && discoveredEndpoints .has ("endpoints" )) {
904+ var endpoints = discoveredEndpoints .get ("endpoints" );
905+ if (endpoints .isArray () && endpoints .size () > 0 ) {
906+ var policyBuilder = ATPLPolicy .builder ()
907+ .version ("v0" )
908+ .description ("Policy for agent " + agentName )
909+ .policyId (UUID .randomUUID ().toString ());
910+
911+ List <Capability > capabilities = new ArrayList <>();
912+ for (JsonNode endpoint : endpoints ) {
913+ if (endpoint .has ("endpoint" ) && endpoint .has ("name" )) {
914+ var endpointStr = endpoint .get ("endpoint" ).asText ();
915+ Capability capability = Capability .builder ()
916+ .description (endpoint .get ("name" ).asText ())
917+ .endpoints (List .of (extractNormalizedPath (endpointStr )))
918+ .build ();
919+ capabilities .add (capability );
920+ }
921+ }
922+
923+ if (!capabilities .isEmpty ()) {
924+ CapabilitySet capabilitySet = CapabilitySet .builder ()
925+ .primitives (capabilities )
926+ .build ();
927+ policyBuilder .capabilities (capabilitySet );
916928
929+ ATPLPolicy policy = policyBuilder .build ();
930+ policyId = savePolicy (execution , true , policy );
931+ log .info ("Created trust policy with ID: {}" , policyId );
932+ }
933+ }
934+ }
917935
918- var agentBuilder = AgentRegistrationDTO .builder ()
919- .agentContextId (contextId )
936+ // Step 6: Create the agent with context and policy
937+ var agentBuilder = AgentRegistrationDTO .builder ()
938+ .agentContextId (createdContext .getContextId ().toString ())
920939 .clientId (UUID .randomUUID ().toString ())
921940 .agentType (agentType )
922941 .agentName (agentName );
923- if (!policyId .isEmpty ()){
942+
943+ if (!policyId .isEmpty ()) {
924944 log .info ("Using policyId {}" , policyId );
925945 agentBuilder .agentPolicyId (policyId );
926946 } else {
927- log .info ("No policyId provided , using default" );
947+ log .info ("No policy created , using default policy " );
928948 }
929949
930950 AgentRegistrationDTO agentRegistration = agentBuilder .build ();
931- var response = agentClientService .createAgent (execution , agentRegistration );
932- ObjectNode contextNode = JsonUtil .MAPPER .createObjectNode ();
933- contextNode .put ("agentId" , agentRegistration .getAgentName ());
951+ var agentResponse = agentClientService .createAgent (execution , agentRegistration );
952+ log .info ("Agent creation response: {}" , agentResponse );
953+
954+ // Step 7: Build and return the result
955+ ObjectNode resultNode = JsonUtil .MAPPER .createObjectNode ();
956+ resultNode .put ("agentId" , agentName );
957+ resultNode .put ("agentName" , agentName );
958+ resultNode .put ("agentType" , agentType );
959+ resultNode .put ("contextId" , createdContext .getContextId ().toString ());
960+ resultNode .put ("policyId" , policyId .isEmpty () ? "default" : policyId );
961+
962+ if (discoveredEndpoints != null && discoveredEndpoints .has ("endpoints" )) {
963+ resultNode .put ("endpointCount" , discoveredEndpoints .get ("endpoints" ).size ());
964+ } else {
965+ resultNode .put ("endpointCount" , 0 );
966+ }
934967
935- return contextNode ;
968+ log .info ("Successfully created agent '{}' with context and trust policy" , agentName );
969+ return resultNode ;
936970 }
937971
938972 @ Verb (name = "get_agent_status" , returnType = AgentExecutionContextDTO .class , description = "Queries the agent " +
0 commit comments