@@ -140,23 +140,24 @@ def print_deployment_success(
140140{% - endif % }
141141
142142
143- def grant_agent_identity_roles (agent : Any , project : str ) -> None :
144- """Grant required IAM roles to the agent identity principal.
143+ def setup_agent_identity (client : Any , project : str , display_name : str ) -> Any :
144+ """Create agent with identity and grant required IAM roles."""
145+ click .echo (f"\n 🔧 Creating agent identity for: { display_name } " )
146+ agent = client .agent_engines .create (
147+ config = {"identity_type" : IdentityType .AGENT_IDENTITY }
148+ )
145149
146- Uses get-modify-set pattern with etag for optimistic concurrency control.
147- The policy object returned by get_iam_policy includes an etag that is
148- automatically validated by set_iam_policy to prevent race conditions.
149- """
150150 roles = [
151151 "roles/aiplatform.expressUser" ,
152152 "roles/serviceusage.serviceUsageConsumer" ,
153153 "roles/browser" ,
154+ "roles/cloudapiregistry.viewer" ,
155+ "roles/logging.logWriter" ,
156+ "roles/monitoring.metricWriter" ,
154157 ]
155158 principal = f"principal://{ agent .api_resource .spec .effective_identity } "
156- click .echo (f"\n 🔐 Granting IAM roles to agent identity : { principal } " )
159+ click .echo (f"🔐 Granting IAM roles to: { principal } " )
157160 proj_client = resourcemanager_v3 .ProjectsClient ()
158- # Policy includes etag for optimistic locking - set_iam_policy will fail
159- # if policy was modified between get and set operations
160161 policy = proj_client .get_iam_policy (
161162 request = iam_policy_pb2 .GetIamPolicyRequest (resource = f"projects/{ project } " )
162163 )
@@ -167,7 +168,8 @@ def grant_agent_identity_roles(agent: Any, project: str) -> None:
167168 resource = f"projects/{ project } " , policy = policy
168169 )
169170 )
170- click .echo (" ✅ Granted IAM roles" )
171+ click .echo (" ✅ Agent identity ready" )
172+ return agent
171173
172174
173175@click .command ()
@@ -317,18 +319,22 @@ def deploy_agent_engine_app(
317319
318320 # Log deployment parameters
319321 click .echo ("\n 📋 Deployment Parameters:" )
320- click .echo (f" Project: { project } " )
321- click .echo (f" Location: { location } " )
322- click .echo (f" Display Name: { display_name } " )
323- click .echo (f" Min Instances: { min_instances } " )
324- click .echo (f" Max Instances: { max_instances } " )
325- click .echo (f" CPU: { cpu } " )
326- click .echo (f" Memory: { memory } " )
327- click .echo (f" Container Concurrency: { container_concurrency } " )
322+ params = [
323+ ("Project" , project ),
324+ ("Location" , location ),
325+ ("Display Name" , display_name ),
326+ ("Min Instances" , min_instances ),
327+ ("Max Instances" , max_instances ),
328+ ("CPU" , cpu ),
329+ ("Memory" , memory ),
330+ ("Container Concurrency" , container_concurrency ),
331+ ]
328332 if service_account :
329- click . echo ( f" Service Account: { service_account } " )
333+ params . append (( " Service Account" , service_account ) )
330334 if agent_identity :
331- click .echo (" Agent Identity: Enabled (Preview)" )
335+ params .append (("Agent Identity" , "Enabled (Preview)" ))
336+ for name , value in params :
337+ click .echo (f" { name } : { value } " )
332338 if env_vars :
333339 click .echo ("\n 🌍 Environment Variables:" )
334340 for key , value in sorted (env_vars .items ()):
@@ -388,11 +394,6 @@ def deploy_agent_engine_app(
388394 resource_limits = {"cpu" : cpu , "memory" : memory },
389395 identity_type = IdentityType .AGENT_IDENTITY if agent_identity else None ,
390396 )
391-
392- agent_config = {
393- "agent" : agent_instance ,
394- "config" : config ,
395- }
396397{% - else % }
397398 # Generate class methods spec from register_operations
398399 class_methods_list = generate_class_methods_from_agent (agent_instance )
@@ -427,22 +428,15 @@ def deploy_agent_engine_app(
427428 if agent .api_resource .display_name == display_name
428429 ]
429430
430- # Handle agent identity: create empty agent if needed, then grant roles
431- if agent_identity :
432- if not matching_agents :
433- click .echo (f"\n 🔧 Creating agent identity for: { display_name } " )
434- empty_agent = client .agent_engines .create (
435- config = {"identity_type" : IdentityType .AGENT_IDENTITY }
436- )
437- matching_agents = [empty_agent ]
438- grant_agent_identity_roles (matching_agents [0 ], project )
431+ # Setup agent identity on first deployment
432+ if agent_identity and not matching_agents :
433+ matching_agents = [setup_agent_identity (client , project , display_name )]
439434
440435 # Deploy the agent (create or update)
436+ action = "Updating" if matching_agents else "Creating"
437+ click .echo (f"\n 🚀 { action } agent: { display_name } (this can take 3-5 minutes)..." )
438+
441439 if matching_agents :
442- click .echo (f"\n 📝 Updating agent: { display_name } " )
443- click .echo (
444- "🚀 Deploying to Vertex AI Agent Engine (this can take 3-5 minutes)..."
445- )
446440{% - if cookiecutter .is_adk_live % }
447441 remote_agent = client .agent_engines .update (
448442 name = matching_agents [0 ].api_resource .name ,
@@ -455,10 +449,6 @@ def deploy_agent_engine_app(
455449 )
456450{% - endif % }
457451 else :
458- click .echo (f"\n 🚀 Creating new agent: { display_name } " )
459- click .echo (
460- "🚀 Deploying to Vertex AI Agent Engine (this can take 3-5 minutes)..."
461- )
462452{% - if cookiecutter .is_adk_live % }
463453 remote_agent = client .agent_engines .create (
464454 agent = agent_instance ,
0 commit comments