Lección 23 — Tutoriels pas à pas

12-3. Ajouter des agents un par un : un service par agent, une entrée par agent dans Gemini Enterprise

34 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Le but : passer de 6 agents à 7, puis 10, puis 20, sans jamais toucher aux agents déjà en place :

  • chaque agent a son service Cloud Run (ou son agent Agent Runtime), sa carte A2A et son identité ;
  • chaque agent est ajouté séparément dans l'app dev_gemini-entreprise-app, avec son propre accès ;
  • ajouter, modifier ou retirer un agent ne change rien aux autres.

Le chemin, en 4 étapes :

#ÉtapeOù
1Créer l'agent : son dossier, ses outils, sa fiche dans le cataloguePartie 1 (commun)
2Le tester sur votre poste1.4
3Le déployer et le tester en ligneTerraform, shell ou console
4L'ajouter à l'app, donner l'accès, tester dans le chatDans chaque méthode

Deux questions qu'on pose ensuite, traitées ici :

  • Partie B : vos agents peuvent-ils utiliser les sources, connecteurs et MCP déjà branchés sur Gemini Enterprise ?
  • Partie C : un outil qui a besoin du compte de l'utilisateur (OAuth, comme un connecteur) : comment le faire marcher depuis Gemini Enterprise ?

Avant de commencer (une fois) :

  • outils, dossier, Python, fichier de configuration, connexion, droits, API : 12-1-1, parties 2 à 5 ;

  • au moins un déploiement déjà fait, avec la méthode que vous allez réutiliser :

    Les éléments communs (filtres Model Armor, dépôt d'images, compte de construction des images) existent alors déjà.

Valable pour 12-1 (agents dans aiml-gemini-ent-exp-0zga) comme pour 12-2 (agents dans le projet de l'app) : seul le fichier de configuration chargé change.

Testé en vrai (9 et 10 octobre 2026, projets de test) :

  • Cloud Run : un 7e agent ajouté avec Terraform ; plan limité au nouvel agent ; modification et retrait d'un seul agent ; test A2A.
  • Agent Runtime : ajout d'un agent (7 to add), modification d'un seul (mise à jour sur place).
  • Test local : un agent, avant tout déploiement.
  • OAuth : l'agent Identité utilisateur a reçu le vrai jeton Google de l'utilisateur et l'a fait vérifier par Google, par les deux chemins. Côté A2A : serveur local, mêmes en-têtes que Gemini Enterprise. Côté Agent Runtime : l'appel que fait Gemini Enterprise. Le format de la création d'autorisation est accepté par l'API Google.

Non testable sans votre app : l'ajout dans l'app, le consentement OAuth dans le chat, la recherche dans les sources de l'app.


Sommaire

  1. Le principe : le catalogue décide
  2. Créer l'agent (commun aux 3 méthodes)
  3. Méthode B : Terraform (recommandée)
  4. Méthode A : shell, un agent
  5. Méthode C : console, un agent
  6. Ce que Terraform garantit (et ce qui demande de l'attention)
  7. Partie B : utiliser les sources et connecteurs de Gemini Enterprise
  8. Partie C : outils avec le compte de l'utilisateur (OAuth)
  9. Ce qui peut arriver

0. Le principe : le catalogue décide

 agents/trio/catalogue.json                 Projet des agents                       App Gemini Enterprise
 ┌──────────────────────────┐      ┌─────────────────────────────────────┐      ┌───────────────────────────┐
 │ meteo      -> meteo_agent │ ───▶ │ meteo-a2a       (Cloud Run, image   │ ───▶ │ « Météo & équipement »    │
 │ redaction  -> …           │      │   meteo:<empreinte>, compte         │      │ « Rédaction … »           │
 │ traduction -> …           │      │   meteo-a2a-sa)                     │      │ « Traduction … »          │
 │ taille     -> taille_agent│      │ taille-a2a      (son image, son     │      │ « Conseil taille »        │
 │ retour     -> retour_agent│      │   compte, sa carte A2A)             │      │ « Retours produits »      │
 │ identite   -> …           │      │ identite-a2a    (…)                 │      │ « Identité utilisateur »  │
 │ velo       -> velo_agent  │ NEW  │ velo-a2a        ← seul créé         │ NEW  │ « Atelier vélo » ← seule  │
 └──────────────────────────┘      └─────────────────────────────────────┘      └───────────────────────────┘
MotEn clair
CatalogueLe fichier agents/trio/catalogue.json : la liste de tous les agents, chacun avec sa fiche (dossier, nom affiché, description, compétences, exemples)
CléLe nom court d'un agent dans le catalogue : velo. Elle donne tous ses noms dans Google Cloud
Dossier de l'agentagents/trio/velo_agent/ : son code (agent.py)
Code communagents/trio/commun.py : le modèle Gemini, le filtre Model Armor, le jeton OAuth. Partagé par tous

Les noms que donne la clé velo :

MéthodeCloud RunSon compteAgent RuntimeSon compteDans l'app
Terraformvelo-a2avelo-a2a-savelo-agentvelo-agent-sa« Atelier vélo » / « Atelier vélo (A2A) »
Shellvelo-a2a-shellvelo-a2a-shell-savelo-shellvelo-shell-sa« Atelier vélo (shell) » / « (A2A shell) »
Consolevelo-a2a-consolevelo-a2a-console-savelo-consolevelo-console-sale nom que vous tapez

Pourquoi rien ne touche aux autres : l'image (Cloud Run) et l'archive (Agent Runtime) d'un agent ne contiennent que son dossier et le code commun, avec une étiquette qui est l'empreinte de ce contenu. Modifier velo_agent ne change que velo. Modifier commun.py change tout le monde : c'est voulu, ils l'utilisent tous.

Les 6 agents fournis : météo, rédaction, traduction, conseil taille (taille), retours produits (retour), identité utilisateur (identite : vérifie la chaîne OAuth, voir C7). L'exemple ajoute un 7e agent, velo.


1. Créer l'agent (commun aux 3 méthodes)

1.1 Ouvrir un terminal prêt

cd ~/Desktop/09-agents-multi-projets-gemini-enterprise && source .venv/bin/activate
source scripts/config.sh config/12-1-agents-dans-projet-exp.env          # ou config/12-2-agents-dans-projet-app.env

Attendu : l'invite commence par (.venv), et le résumé de la configuration finit par OK.

1.2 Le squelette

python scripts/nouvel_agent.py velo "Atelier vélo" "Diagnostique une panne de vélo simple et dit si l'atelier est nécessaire."

Résultat obtenu :

créé : agents/trio/velo_agent/agent.py et l'entrée « velo » du catalogue
à faire : écrire les outils dans velo_agent/agent.py, mettre de vrais exemples dans le catalogue, tester.
ArgumentRèglePourquoi
Clé (velo)minuscules et chiffres, commence par une lettre, 2 à 15 caractèresElle forme les noms Google (un compte de service : 30 caractères max)
Nom affiché ("Atelier vélo")unique dans le catalogueC'est par ce nom que l'app reconnaît l'agent : deux agents du même nom s'écraseraient
Descriptionune phrase claireGemini Enterprise la montre aux utilisateurs

Le script refuse une clé ou un nom déjà pris, par exemple : Le nom « Atelier vélo » est déjà pris par un autre agent : choisir un nom affiché unique.

Ce qu'il a créé :

  • le dossier agents/trio/velo_agent/, avec __init__.py et agent.py (un outil d'exemple, exemple_outil) ;
  • une entrée "velo" à la fin de agents/trio/catalogue.json.

1.3 Écrire les vrais outils

Ouvrez agents/trio/velo_agent/agent.py dans un éditeur. Remplacez exemple_outil par vos fonctions. Modèle à copier : agents/trio/taille_agent/agent.py (deux outils, des tables, des contrôles d'entrée).

Un outil, c'est une fonction Python, par exemple :

def diagnostic(symptome: str) -> dict:
    """Donne la cause probable d'une panne de vélo et dit si l'atelier est nécessaire.

    Args:
        symptome: Ce que le client constate, ex. « la chaîne saute », « le frein couine ».
    """
    pannes = {"chaîne": ("dérailleur mal réglé", False), "frein": ("plaquettes usées", True)}
    for mot, (cause, atelier) in pannes.items():
        if mot in symptome.lower():
            return {"status": "success", "cause": cause, "atelier_necessaire": atelier}
    return {"status": "error", "error_message": "Symptôme inconnu : demander plus de détails."}
RèglePourquoi
Une docstring claire (le texte entre """)Le modèle la lit pour savoir quand appeler l'outil
Des arguments typés (symptome: str) décrits sous Args:Le modèle sait quoi passer
Renvoie un dict avec "status": "success" ou "status": "error" + "error_message"Le modèle sait si ça a marché

Puis, dans le même fichier :

  • tools=[exemple_outil] → tools=[diagnostic] ;
  • l'instruction : dites quand appeler l'outil (« Appelle toujours diagnostic… ») ;
  • les trois dernières lignes ne changent pas : root_agent = Agent(…), app = commun.app_securisee(root_agent), agent_runtime_app = AdkApp(app=app).

Dans agents/trio/catalogue.json, entrée "velo" : remplacez "Que sais-tu faire ?" par de vraies questions d'exemple (ex. "Ma chaîne saute quand je pédale fort, je dois aller à l'atelier ?"). Elles apparaissent dans la carte de l'agent, et les scripts de test posent la première.

Vérifier que le catalogue est valide (une virgule oubliée suffit à le casser) :

python3 -m json.tool agents/trio/catalogue.json > /dev/null && echo "catalogue OK"

1.4 Le tester sur votre poste

cd agents/trio
PROMPT_TEMPLATE= RESPONSE_TEMPLATE= LOCAL_DEV=1 adk web

Sans watchdog (Mac Acme installé avec requirements-poste.txt, voir 12-1-1, partie 2), adk web ne démarre pas : utilisez PROMPT_TEMPLATE= RESPONSE_TEMPLATE= LOCAL_DEV=1 adk run velo_agent (on discute dans le terminal, exit pour quitter).

Ouvrez http://localhost:8000 → en haut à gauche, choisir velo_agent → poser une question d'exemple. Attendu : une réponse, et dans le panneau de gauche l'appel de votre outil (diagnostic). Ctrl+C dans le terminal pour arrêter, puis cd ../...

MorceauPourquoi
LOCAL_DEV=1Autorise l'agent à tourner sans filtre Model Armor, en local seulement (déployé, il refuse)
PROMPT_TEMPLATE= RESPONSE_TEMPLATE=Vide les chemins de filtres chargés par la configuration. Sinon, si ces filtres n'existent pas encore, toutes les réponses sont « filtrée par Model Armor » (vérifié)

Tests automatiques des agents fournis (sans appel au modèle) :

python scripts/test_trio.py

Résultat obtenu : tests trio OK (9 scénarios, 6 agents). Ce script vérifie aussi que chaque entrée du catalogue a son dossier et une clé de 15 caractères au plus : votre velo y passe.

Ensuite, une des trois méthodes.


2. Méthode B : Terraform (recommandée)

Rien à écrire dans Terraform : il lit le catalogue. Les mêmes commandes servent pour le 7e agent comme pour le 20e.

La ligne AGENTS du fichier de configuration :

Votre fichierÀ faire
AGENTS="" (tous les agents du catalogue)Rien : velo est déjà dedans
AGENTS="meteo taille" (une liste)Ajouter velo à la liste : AGENTS="meteo taille velo", puis recharger (source scripts/config.sh …)

⚠ Ne mettez pas AGENTS="velo" seul : la liste dit ce qui doit exister, Terraform supprimerait les autres. Le mécanisme (for_each) est expliqué en 12-1-2, partie 2.

2.1 Cloud Run (A2A), dossier 01-bis

Configuration chargée (pas de Docker : l'image est construite dans Google Cloud par Cloud Build) :

cd $DOSSIER/01-bis-cloud-run-a2a/terraform
terraform plan

Résultat obtenu (le point à vérifier avant tout apply) :

  # google_agent_registry_service.agent["velo"] will be created
  # google_cloud_run_v2_service.agent["velo"] will be created
  # google_cloud_run_v2_service_iam_member.ge_invokes["velo"] will be created
  # google_project_iam_member.agent["velo roles/aiplatform.user"] will be created
  # google_project_iam_member.agent["velo roles/logging.logWriter"] will be created
  # google_project_iam_member.armor["velo"] will be created
  # google_service_account.agent["velo"] will be created
  # terraform_data.image["velo"] will be created
Plan: 8 to add, 0 to change, 0 to destroy.

Comment le lire :

  • uniquement des lignes ["velo"], et 0 to change, 0 to destroy : les 6 autres agents ne sont pas touchés ;
  • ge_invokes["velo"] : le droit de l'app d'appeler ce service. Il n'apparaît que si l'app est renseignée dans la configuration ; sans app : 7 to add ;
  • avec PUBLIER=oui : une ligne de plus, terraform_data.publish["velo"] (l'ajout dans l'app) : 9 to add.

Si le plan montre autre chose (des destroy, ou des create pour des agents qui existent déjà), répondez no : voir 5. Ce que Terraform garantit.

terraform apply       # relit le plan, tapez yes ; 3 à 5 minutes (Cloud Build construit la seule image velo, ~1 min 20 s)
terraform output -json urls

Résultat obtenu : Apply complete! Resources: 8 added, 0 changed, 0 destroyed., puis dans urls la ligne "velo": "https://velo-a2a-….a.run.app" à côté des 6 autres, inchangées.

Attendre 3 à 5 minutes (les droits du nouveau compte s'appliquent), puis tester ce seul agent :

cd .. && URL=$(terraform -chdir=terraform output -json urls | python3 -c 'import json,sys; print(json.load(sys.stdin)["velo"])') ./test.sh velo

(La partie URL=$(…) lit l'adresse de velo dans les sorties de Terraform.) Résultat obtenu (agent tout juste créé, outil d'exemple encore en place) :

== velo  carte : velo_agent (A2A 0.3)
   Q1 > Que sais-tu faire ?
   R1 < Bonjour ! En tant que spécialiste vélo, je peux vous aider à diagnostiquer des pannes simples sur votre
        bicyclette (freins, chaîne, pneus, etc.). Je vous indiquerai également s'il est nécessaire de vous rendre dans un atelier…
   Q2 > Peux-tu résumer ta réponse en une phrase ?
   R2 < Je peux diagnostiquer les pannes simples de votre vélo et vous dire si une visite en atelier de réparation est nécessaire.

OK : les agents répondent en A2A v0.3, avec mémoire de conversation

Testé trop tôt, le script le dit : ÉCHEC : réponse bloquée par Model Armor. Juste après le premier apply, attendre 2 à 5 minutes…. Attendez et relancez. ./test.sh sans argument teste tous les agents.

2.2 Agent Runtime, dossier 02-bis

cd $DOSSIER/02-bis-agent-runtime/terraform
terraform plan

Résultat obtenu (même mécanisme, ici pour l'agent taille) :

  # module.agent["taille"].google_project_iam_member.agent["roles/aiplatform.user"] will be created
  # module.agent["taille"].google_project_iam_member.agent["roles/cloudtrace.agent"] will be created
  # module.agent["taille"].google_project_iam_member.agent["roles/logging.logWriter"] will be created
  # module.agent["taille"].google_project_iam_member.agent["roles/monitoring.metricWriter"] will be created
  # module.agent["taille"].google_project_iam_member.armor will be created
  # module.agent["taille"].google_service_account.agent will be created
  # module.agent["taille"].google_vertex_ai_reasoning_engine.agent will be created
Plan: 7 to add, 0 to change, 0 to destroy.

Pour velo : les mêmes 7 lignes avec module.agent["velo"] (+1 terraform_data.publish["velo"] si PUBLIER=oui). Le droit de l'app sur Agent Runtime vaut pour tout le projet : rien de plus par agent.

terraform apply       # yes ; 5 à 10 minutes
cd .. && ./test.sh velo

Résultat attendu : == velo (projects/…/reasoningEngines/…), les outils appelés (-> outil : …), puis la réponse.

2.3 L'ajouter dans l'app, séparément

  • PUBLIER=oui déjà dans le fichier : l'apply ci-dessus a déjà ajouté « Atelier vélo » (Agent Runtime) et « Atelier vélo (A2A) » (Cloud Run) dans l'app. Ligne registered Atelier vélo dans la sortie.
  • Sinon :
    1. passez PUBLIER=oui et rechargez la configuration ;
    2. lancez terraform plan dans chaque dossier. Vous voyez terraform_data.publish["velo"], plus celles des agents pas encore publiés ;
    3. lancez terraform apply.

Donner l'accès, agent par agent :

  1. 🔎 « Gemini Enterprise » → dev_gemini-entreprise-app → Agents → « Atelier vélo ».
  2. Autorisations utilisateur → Ajouter → le groupe → Agent User → Enregistrer.

Vous pouvez ouvrir un agent à un groupe pilote et un autre à tout le monde.

Tester dans le chat : l'app → Intégration → lien de l'app web, avec un compte du groupe → Agents → « Atelier vélo » → une question d'exemple.

Publier un seul agent sans publier les autres : méthode A, étape 3.6.

2.4 Modifier un agent, retirer un agent

Vous faitesterraform plan montre (testé)
Modifier velo_agent/agent.pyCloud Run : terraform_data.image["velo"] must be replaced + google_cloud_run_v2_service.agent["velo"] will be updated in-place → Plan: 1 to add, 1 to change, 1 to destroy. La ligne « destroy » est l'ancienne étiquette d'image, rien dans Google Cloud. Même URL, nouvelle révision. Agent Runtime : module.agent["velo"]…reasoning_engine.agent will be updated in-place → 0 to add, 1 to change, 0 to destroy. Même ID.
Retirer veloVoir ci-dessous → Plan: 0 to add, 0 to change, 8 to destroy, uniquement ["velo"] (because key ["velo"] is not in for_each map). Avec PUBLIER=oui : il est aussi retiré de l'app.
Modifier commun.py ou requirements.txtTous les agents : nouvelle image (ou archive), mise à jour sur place. Même URL, même ID Agent Runtime.

Retirer velo :

  • si AGENTS est une liste, enlevez-en velo ;
  • si AGENTS="", retirez-le du catalogue :
    python3 -c 'import json; p="agents/trio/catalogue.json"; c=json.load(open(p)); c.pop("velo"); open(p,"w").write(json.dumps(c, ensure_ascii=False, indent=2) + "\n")'
    rm -r agents/trio/velo_agent

Puis rechargez la configuration, terraform plan (vérifier : seulement ["velo"] en destroy), et terraform apply dans chaque dossier.


3. Méthode A : shell, un agent

Les commandes de 12-1-1, pour un seul agent. Dans le terminal de 1.1 (configuration chargée) :

K=velo
NOM=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])")
echo "$K / $NOM"

Attendu : velo / Atelier vélo. K est la clé de l'agent : toutes les commandes suivantes l'utilisent.

3.1 Son image

Pas de Docker : l'image est construite dans Google Cloud par Cloud Build, depuis le dossier du projet (cd $DOSSIER). Le compte de construction agents-build-sa existe déjà si vous avez déployé un agent Cloud Run en shell (12-1-1, partie 7) ; sinon, créez-le d'abord comme indiqué là, puis attendez 1 à 2 minutes.

cd $DOSSIER
gcloud artifacts repositories describe agents-shell --location=$REGION >/dev/null 2>&1 || \
  gcloud artifacts repositories create agents-shell --repository-format=docker --location=$REGION
IMAGE=$REGION-docker.pkg.dev/$PROJET_AGENTS/agents-shell/$K:v1
gcloud builds submit --region=$REGION --service-account=projects/$PROJET_AGENTS/serviceAccounts/agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com \
  --config=01-bis-cloud-run-a2a/cloudbuild.yaml --substitutions=_AGENT_DIR=${K}_agent,_IMAGE=$IMAGE .

La 1re commande crée le dépôt d'images seulement s'il n'existe pas (|| = « sinon »). Résultat attendu (~1 min 20 s) : Creating temporary archive of … file(s)…, Uploading tarball of [.] to [gs://…_cloudbuild/…], Created [https://cloudbuild.googleapis.com/…/builds/…], puis une ligne qui finit par europe-west1-docker.pkg.dev/…/agents-shell/velo:v1 SUCCESS. _AGENT_DIR=velo_agent : l'image ne contient que cet agent et le code commun. Le journal de la construction : 🔎 « Cloud Build » → Historique (région europe-west1).

3.2 Son compte de service

SA=$K-a2a-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com
gcloud iam service-accounts create $K-a2a-shell-sa --display-name="Agent $K (Cloud Run A2A, méthode shell)"
for R in aiplatform.user logging.logWriter modelarmor.user; do
  gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R --member=serviceAccount:$SA >/dev/null \
    && echo "  $K-a2a-shell-sa : roles/$R"
done

Résultat attendu : Created service account [velo-a2a-shell-sa]., puis ses 3 rôles (appeler Gemini, écrire ses journaux, utiliser Model Armor).

3.3 Son service Cloud Run

URL=https://$K-a2a-shell-$NUM_AGENTS.$REGION.run.app
python3 scripts/carte_a2a.py $K $URL --env-yaml > env-$K.yaml
gcloud run deploy $K-a2a-shell --image=$IMAGE --region=$REGION --service-account=$SA --no-allow-unauthenticated \
  --env-vars-file=env-$K.yaml --memory=1Gi --cpu=1 --min-instances=0 --max-instances=1 --quiet

Résultat attendu : Service URL: https://velo-a2a-shell-433175138344.europe-west1.run.app, identique à $URL. Le sens de chaque option : 12-1-1, 7.2 c).

3.4 Le tester (3 à 5 minutes après)

URL=$URL ./01-bis-cloud-run-a2a/test.sh $K

Résultat attendu : comme en 2.1, OK : les agents répondent en A2A v0.3….

3.5 Le droit de l'app sur ce service (si l'app existe)

gcloud run services add-iam-policy-binding $K-a2a-shell --region=$REGION \
  --member=serviceAccount:$GE_SA --role=roles/run.invoker

Résultat attendu : la politique affichée, avec service-100000000003@gcp-sa-discoveryengine… sous roles/run.invoker. ($GE_SA vide = pas d'app dans la configuration : sautez 3.5 et 3.6.)

3.6 L'ajouter dans l'app

python3 scripts/carte_a2a.py $K $URL > carte-$K.json
./scripts/add_agent_to_ge.sh a2a carte-$K.json "$NOM (A2A shell)"
./scripts/add_agent_to_ge.sh list

Résultat attendu :

  1. droit accordé : … : le droit de 3.5, déjà en place, sans effet ;
  2. ajouté : projects/…/agents/<ID> ;
  3. la liste, avec « Atelier vélo (A2A shell) ».

Donner l'accès et tester : comme en 2.3.

3.7 Agent Runtime à la place (ou en plus) de Cloud Run

SA_RT=$K-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com
gcloud iam service-accounts create $K-shell-sa --display-name="Agent $K (Agent Runtime, méthode shell)"
for R in aiplatform.user logging.logWriter modelarmor.user; do
  gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R --member=serviceAccount:$SA_RT >/dev/null \
    && echo "  $K-shell-sa : roles/$R"
done
DESC=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['description'])")
python scripts/deployer_agent_runtime.py --projet $PROJET_AGENTS --region $REGION --agent ${K}_agent --nom $K-shell \
  --description "$DESC" --compte-service $SA_RT \
  --env PROMPT_TEMPLATE=$PROMPT_TEMPLATE --env RESPONSE_TEMPLATE=$RESPONSE_TEMPLATE

Résultat attendu : déployé : projects/100000000002/locations/europe-west1/reasoningEngines/<ID>. Puis, 3 à 5 minutes après :

AGENT_NAME=projects/$NUM_AGENTS/locations/$REGION/reasoningEngines/<ID> python scripts/query.py - "Ma chaîne saute, je dois aller à l'atelier ?"
./scripts/add_agent_to_ge.sh adk projects/$NUM_AGENTS/locations/$REGION/reasoningEngines/<ID> "$NOM (shell)" "$DESC"

(Remplacez <ID> par le nombre affiché après déployé :.) Attendu :

  1. la réponse de l'agent, avec -> outil : … ;
  2. ajouté : …. Dans le scénario 12-1, avant ajouté, le script donne aussi à l'app le droit sur le projet (si ce n'est pas déjà fait).

3.8 Retirer cet agent

./scripts/add_agent_to_ge.sh delete "$NOM (A2A shell)"         # de l'app (et "$NOM (shell)" pour Agent Runtime)
python scripts/nettoyer.py --agent $K                          # inventaire de ce qui appartient à velo
python scripts/nettoyer.py --agent $K --supprimer              # suppression, après confirmation (tapez l'ID du projet)
rm -f env-$K.yaml carte-$K.json

nettoyer.py --agent velo ne touche qu'aux éléments de velo :

  • son service Cloud Run ;
  • son agent Agent Runtime ;
  • ses entrées du registre ;
  • ses comptes de service et leurs rôles.

Les autres agents et les éléments communs ne sont pas concernés. Son image reste dans le dépôt agents-shell : gcloud artifacts docker images delete $REGION-docker.pkg.dev/$PROJET_AGENTS/agents-shell/$K --delete-tags --quiet.


4. Méthode C : console, un agent

Les écrans détaillés, champ par champ, sont dans 12-1-3 ; ici, pour velo :

  1. L'image et la carte (Cloud Shell, configuration chargée) : 12-1-3, 5.2 avec K=velo. Copiez la carte affichée.

  2. Son compte de service : 12-1-3, 5.3, nom velo-a2a-console-sa, 3 rôles : Utilisateur Vertex AI, Rédacteur de journaux, Utilisateur Model Armor.

  3. Son service : 12-1-3, 5.4 avec :

    ChampValeur
    Imageagents-console/velo:v1
    Nomvelo-a2a-console
    AGENTvelo_agent
    AGENT_CARDla carte de l'étape 1
    Compte de servicevelo-a2a-console-sa

    Les autres champs sont identiques. Créer, puis tester (Cloud Shell, 3 à 5 minutes après) : URL=https://velo-a2a-console-$NUM_AGENTS.$REGION.run.app ./01-bis-cloud-run-a2a/test.sh velo.

  4. Le droit de l'app :

    1. Service velo-a2a-console → Sécurité → Ajouter un compte principal.
    2. service-100000000003@gcp-sa-discoveryengine.iam.gserviceaccount.com → rôle Demandeur Cloud Run → Enregistrer.
  5. Le registre : 12-1-3, 7, nom velo-a2a-console.

  6. L'app :

    1. Projet acme-gemini-prod → 🔎 « Gemini Enterprise » → dev_gemini-entreprise-app → Agents → + Ajouter un agent → Agent personnalisé via A2A.
    2. Coller la carte → Prévisualiser les détails de l'agent → Suivant.
    3. Authentification : Ignorer et terminer, sauf si l'agent utilise le compte de l'utilisateur (partie C).
    4. Autorisations utilisateur → le groupe → Agent User → Enregistrer.
  7. Tester dans le chat : l'app web → Agents → votre agent.

Agent Runtime à la place : 12-1-3, partie 6 avec K=velo. Puis dans l'app : Agent personnalisé via Agent Runtime → nom, description, chemin de ressource (copié dans la console Agent Runtime) → Créer.

Les agents existants ne sont jamais ouverts : rien ne peut les modifier.


5. Ce que Terraform garantit (et ce qui demande de l'attention)

SituationCe qui se passeVérifié
Ajouter un agentSeules ses ressources sont créées (0 to change, 0 to destroy)Oui, plan et apply
Modifier le code d'un agent Cloud RunSeuls son image et son service changent ; même URLOui, plan
Modifier le code d'un agent Agent RuntimeSeul cet agent est mis à jour, sur place : même ID, l'entrée dans l'app reste valable (Plan: 0 to add, 1 to change, 0 to destroy)Oui, plan
Retirer un agentSeules ses ressources sont suppriméesOui, plan et apply
Deux agents avec le même nom affichénouvel_agent.py refuse ; Terraform refuse de publier (Deux agents du catalogue ont le même nom_affiche)Oui, script
Relancer apply sans rien changerNo changes. Your infrastructure matches the configuration.Oui
Lancer Terraform depuis un autre dossier ou un autre poste (avec le même état)Rien n'est republié : le chemin du dossier n'entre pas dans ce que Terraform comparePar construction (publication non testable sans l'app)
Oublier source scripts/config.sh …Terraform demande var.agents_project_id … Enter a value: (Ctrl+C), ou mauvais espace de travail : le plan montre tout en create. Ne pas appliquer. Si on applique quand même, Google refuse les doublons (already exists)Comportement Google
Une clé de AGENTS mal tapéeRefusé au chargement de la configuration : ATTENTION : agent « … » absent de agents/trio/catalogue.jsonOui

Ce qui demande de l'attention :

  • Renommer une clé (velo → atelier) = retirer un agent et en créer un autre : nouvelle URL, nouvelle entrée dans l'app (accès à redonner). Changez plutôt le nom affiché.
  • Changer le nom affiché, la description ou les exemples d'un agent publié : son entrée dans l'app est recréée. Redonnez l'accès Agent User à cet agent (les autres ne bougent pas).
  • L'état Terraform est sur votre poste (terraform.tfstate.d/scenario-12-1/, un par dossier). Toujours depuis le même dossier, et sauvegardez-le. Si plusieurs personnes déploient : mettre l'état dans un bucket Cloud Storage (bloc backend "gcs"), sinon chacun croit les agents de l'autre inexistants.
  • La règle d'or : lire la ligne Plan: avant chaque apply. Ajout d'un agent : N to add, 0 to change, 0 to destroy.

6. Partie B : utiliser les sources et connecteurs de Gemini Enterprise

Question : mes agents (Cloud Run, Agent Runtime, A2A) peuvent-ils utiliser les MCP, outils et connecteurs déjà connectés à Gemini Enterprise ?

Réponse courte : les données, oui (avec les droits de l'utilisateur). Les actions et les serveurs MCP, non pas « à travers » Gemini Enterprise : votre agent s'y connecte lui-même.

Ce qui est branché sur l'appVotre agent peut-il s'en servir ?Comment
Sources de données (connecteurs Drive, SharePoint, Confluence, Jira, Cloud Storage, BigQuery, sites…)OuiL'outil commun.recherche_gemini_enterprise interroge la recherche de l'app avec le jeton de l'utilisateur : il ne voit que ce que l'utilisateur a le droit de voir. Demande la partie C.
Les mêmes, avec l'identité de l'agentOui, déconseilléOutil ADK VertexAiSearchTool ou DiscoveryEngineSearchTool : l'agent voit tout ce que son compte de service voit, sans tenir compte des droits de l'utilisateur. Acceptable seulement pour des sources publiques en interne.
Actions des connecteurs (envoyer un e-mail, créer un ticket Jira…)Non (Google ne documente aucun moyen)Votre agent appelle lui-même l'API (Gmail, Jira…) avec le jeton OAuth de l'utilisateur (partie C).
Serveur MCP ajouté à l'appNon à travers l'appBranchez le même serveur MCP sur votre agent : McpToolset d'ADK, avec son URL et son authentification.
Airtable (et les connecteurs du même type : Jira, Salesforce, ServiceNow…)Données : peut-être (recherche fédérée). Actions : non à travers l'app6.2 : votre agent se branche lui-même sur le serveur MCP officiel d'Airtable, avec le compte Airtable de l'utilisateur
Les autres agents de l'appNon à travers l'appVotre agent les appelle directement en A2A (voir 06).

6.1 Brancher la recherche de l'app sur un agent

  1. Dans agents/trio/<clé>_agent/agent.py, ajoutez l'outil commun :
    tools=[mes_outils, commun.recherche_gemini_enterprise],
    Et dans l'instruction : « Pour une question sur nos documents internes, appelle recherche_gemini_enterprise. »
  2. Faites la partie C avec la portée https://www.googleapis.com/auth/cloud-platform.
  3. Les utilisateurs doivent avoir accès à l'app (licence) : c'est leur recherche, avec leurs droits.

L'outil appelle https://eu-discoveryengine.googleapis.com/v1/projects/100000000003/locations/eu/collections/default_collection/engines/dev_gemini-entreprise-app/servingConfigs/default_search:search. Il renvoie au maximum 5 documents (titre, lien, extrait), que le modèle cite. Sans autorisation configurée, il répond Recherche indisponible : autorisation OAuth (AUTH_ID) ou app (GE_ENGINE) non configurée. : l'agent fonctionne, sans cette capacité.

Les connecteurs fédérés (données lues en direct chez l'éditeur, sans copie dans l'app) peuvent ne pas répondre à cette recherche comme dans le chat de l'app. Testez avec une question dont vous connaissez le document.

Alternative : le serveur MCP géré de Discovery Engine (https://discoveryengine.googleapis.com/mcp, outil search), à brancher avec McpToolset et le même jeton utilisateur dans l'en-tête. Même résultat, avec une dépendance de plus ; l'appel direct ci-dessus suffit.

6.2 Exemple : Airtable

Le connecteur Airtable de Gemini Enterprise (recherche fédérée et actions : créer une table, un champ, un commentaire…) sert l'assistant de l'app et le Workflow Builder de l'app. Vos agents A2A ou Agent Runtime ne l'appellent pas : Google ne documente aucun moyen. Votre agent fait donc comme le connecteur : il parle lui-même à Airtable, avec le compte Airtable de l'utilisateur, que Gemini Enterprise lui transmet.

ÉtapeQuoi
1. Application OAuth chez Airtableairtable.com → Builder hub → OAuth integrations → Register new OAuth integration. URI de redirection : les deux de C1. Portées : le minimum (ex. data.records:read, data.records:write, schema.bases:read). Générez un client secret.
2. Autorisation dans l'appComme C2, console ou API, avec : URI d'autorisation https://airtable.com/oauth2/v1/authorize?… (ID client, portées, response_type=code), URI du jeton https://airtable.com/oauth2/v1/token. autorisation_oauth.sh est fait pour Google : pour Airtable, utilisez la console.
3. L'agentLe serveur MCP officiel d'Airtable, avec le jeton de l'utilisateur (code ci-dessous)
4. DéployerAGENTS_OAUTH="airtable=acces-airtable" (C4)
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset

import commun


def entetes_airtable(ctx) -> dict:
    """À chaque appel : le jeton Airtable de CET utilisateur (transmis par Gemini Enterprise)."""
    jeton = commun.jeton_utilisateur(ctx)
    return {"Authorization": f"Bearer {jeton}"} if jeton else {}


airtable = McpToolset(connection_params=StreamableHTTPConnectionParams(url="https://mcp.airtable.com/mcp"),
                      header_provider=entetes_airtable)
# root_agent = Agent(…, tools=[airtable])

L'agent voit alors les bases que l'utilisateur a autorisées, avec ses droits Airtable.

À vérifier chez vous (non testé : pas de compte Airtable ici) :

  • Airtable impose PKCE dans son OAuth. Google ne dit pas si les autorisations de Gemini Enterprise le gèrent. Si le consentement échoue, vous avez deux solutions :
    • un serveur MCP intermédiaire qui gère lui-même l'OAuth d'Airtable ;
    • un jeton d'accès personnel Airtable dans Secret Manager, comme la clé d'API du modèle. Avec ce jeton, tous les utilisateurs agissent avec le même compte Airtable : réservez-le à des bases partagées.
  • Commencez par l'agent Identité utilisateur (C7) branché sur l'autorisation Airtable. Il doit répondre « jeton reçu, mais Google ne le reconnaît pas (… d'un autre fournisseur OAuth) » : c'est normal (un jeton Airtable), et cela prouve que le jeton arrive.

7. Partie C : outils avec le compte de l'utilisateur (OAuth)

Question : mon agent a un outil qui doit agir au nom de l'utilisateur (lire son Drive, chercher avec ses droits, créer un ticket dans un outil externe). Comment le faire marcher dans Gemini Enterprise ?

Le mécanisme (le même que pour les connecteurs de l'app) :

 1. L'utilisateur parle à l'agent dans l'app
 2. Première fois : l'app affiche « Autoriser » → écran de consentement (Google, ou Jira, Salesforce…) → accepter
 3. À chaque message, l'app envoie le jeton OAuth DE L'UTILISATEUR à l'agent :
      Agent Runtime : dans l'état de session « temp:AUTH_ID »  (AdkApp s'en charge)
      A2A / Cloud Run : dans l'en-tête Authorization            (01-bis/main.py le range sous « temp:AUTH_ID »)
 4. L'outil lit le jeton :  commun.jeton_utilisateur(tool_context)  → appelle l'API avec
 5. « temp: » : le jeton n'est jamais enregistré dans la session, ni dans les journaux

AUTH_ID est l'ID de l'autorisation créée dans l'app (étape C2). Le même code marche aux deux endroits.

A2A sur Cloud Run : l'app s'authentifie auprès de Cloud Run avec l'en-tête X-Serverless-Authorization, que Cloud Run consomme, et laisse Authorization (le jeton de l'utilisateur) au conteneur. main.py ne prend le jeton que si X-Serverless-Authorization est présent : sans lui, Authorization est le jeton d'appel Cloud Run, pas celui d'un utilisateur. Testé en local avec ces deux en-têtes : le jeton arrive dans l'outil ; sans X-Serverless-Authorization, l'outil reçoit AUCUN. URL .run.app par défaut requise (Google n'envoie pas cet en-tête aux domaines personnalisés).

C1. Le client OAuth (une fois par fournisseur)

Pour une API Google (Drive, Gmail, Agenda, la recherche de l'app…), dans le projet de l'app acme-gemini-prod :

  1. 🔎 « Écran de consentement OAuth » (ou Google Auth Platform) → type Interne (seuls les comptes Acme) → nom de l'application, e-mail d'assistance → Enregistrer.
  2. 🔎 « Identifiants » → + Créer des identifiants → ID client OAuth → type Application Web → nom gemini-enterprise-agents → URI de redirection autorisés, les deux :
    https://vertexaisearch.cloud.google.com/oauth-redirect
    https://vertexaisearch.cloud.google.com/static/oauth/oauth.html
    
    → Créer → Télécharger le JSON (client_secret_….json). Ne le mettez jamais dans le dépôt.
  3. Activez l'API visée (ex. gcloud services enable drive.googleapis.com --project=$PROJET_APP).

Pour un autre fournisseur (Jira, Salesforce, ServiceNow…) : créez l'application OAuth chez lui, avec les deux URI de redirection ci-dessus. Notez l'ID client, le secret, l'URL d'autorisation, l'URL de jeton.

Portées (scopes) : le minimum utile. Exemples : recherche dans l'app ou agent sur Agent Runtime → https://www.googleapis.com/auth/cloud-platform (Google l'exige pour Agent Runtime) ; lire le Drive → https://www.googleapis.com/auth/drive.readonly.

C2. L'autorisation dans l'app

Shell :

cd $DOSSIER && source scripts/config.sh config/12-1-agents-dans-projet-exp.env
./scripts/autorisation_oauth.sh create acces-drive ~/Downloads/client_secret_XXXX.json "https://www.googleapis.com/auth/cloud-platform"
./scripts/autorisation_oauth.sh list

Résultat attendu : autorisation créée : projects/100000000003/locations/eu/authorizations/acces-drive, puis ce nom dans la liste. Le script ajoute à l'URL d'autorisation ce que Google exige (access_type=offline, prompt=consent, response_type=code) : sans access_type=offline, Google répond The authorization URI must contain 'access_type=offline' for Google authorization servers. (vérifié).

Pas de Terraform pour cette étape : Google ne propose pas de ressource Terraform pour les autorisations. C'est aussi mieux ainsi : le secret du client ne se retrouve pas dans l'état Terraform.

Console : l'autorisation se crée au moment d'ajouter l'agent (étape C4, méthode C).

C3. Le code de l'outil

def mon_outil(question: str, tool_context) -> dict:
    """…"""
    jeton = commun.jeton_utilisateur(tool_context)
    if not jeton:
        return {"status": "error", "error_message": "Autorisation manquante : cliquez sur « Autoriser » dans Gemini Enterprise."}
    # appeler l'API avec l'en-tête  Authorization: Bearer <jeton>

tool_context est fourni par ADK (ne pas le décrire dans la docstring : le modèle ne le voit pas). Exemple complet : commun.recherche_gemini_enterprise dans agents/trio/commun.py.

C4. Déployer avec l'autorisation, l'ajouter dans l'app

Terraform (01-bis et 02-bis) : dans le fichier de configuration,

AGENTS_OAUTH="velo=acces-drive"            # plusieurs : "velo=acces-drive retour=acces-jira"

puis source scripts/config.sh … et terraform plan. Résultat attendu : le service (ou l'agent Agent Runtime) ["velo"] updated in-place (variables AUTH_ID et GE_ENGINE ajoutées) et, si PUBLIER=oui, terraform_data.publish["velo"] must be replaced (l'entrée dans l'app est refaite avec l'autorisation : redonnez l'accès Agent User). Les autres agents : rien. apply.

Ce que Terraform envoie à l'app :

  • A2A : "authorizationConfig": {"agentAuthorization": "projects/100000000003/locations/eu/authorizations/acces-drive"} ;
  • Agent Runtime : "authorizationConfig": {"toolAuthorizations": ["projects/…/authorizations/acces-drive"]}.

C'est le format de la documentation Google.

Shell :

K=velo
AUTH_ID=acces-drive python3 scripts/carte_a2a.py $K $URL --env-yaml > env-$K.yaml     # + AUTH_ID et GE_ENGINE
gcloud run deploy $K-a2a-shell --image=$IMAGE --region=$REGION --env-vars-file=env-$K.yaml --quiet
./scripts/add_agent_to_ge.sh delete "Atelier vélo (A2A shell)"
AUTH_ID=acces-drive ./scripts/add_agent_to_ge.sh a2a carte-$K.json "Atelier vélo (A2A shell)"

Agent Runtime : --env AUTH_ID=acces-drive --env GE_ENGINE=$TF_VAR_ge_engine dans deployer_agent_runtime.py, puis AUTH_ID=acces-drive ./scripts/add_agent_to_ge.sh adk ….

Console :

  • Cloud Run → velo-a2a-console → Modifier et déployer une nouvelle révision → variables AUTH_ID = acces-drive, GE_ENGINE = projects/100000000003/locations/eu/collections/default_collection/engines/dev_gemini-entreprise-app → Déployer.

  • App → Agents → + Ajouter un agent :

    • Via A2A : coller la carte → Prévisualiser → Suivant → Authentification : ID client, Code secret du client, URI d'autorisation, URI du jeton, Portées (les valeurs du JSON de C1) → Terminer.
    • Via Agent Runtime : page Autorisations → Ajouter une autorisation → Nom (acces-drive : l'ID qui en découle est définitif ; c'est la valeur de AUTH_ID) → les mêmes champs → OK → Suivant.

    Vérifiez l'ID réellement créé (./scripts/autorisation_oauth.sh list) : il doit être identique à AUTH_ID.

C5. Ce que voit l'utilisateur

  1. Il ouvre « Atelier vélo » dans l'app et pose une question qui demande l'outil.
  2. Première fois : un bouton Autoriser → la fenêtre de consentement (Google, avec les portées demandées) → Autoriser.
  3. L'agent répond, avec ses données. Les fois suivantes, plus de consentement (jeton rafraîchi par l'app).

C6. Sécurité

  • Le jeton est celui de l'utilisateur : l'agent ne peut rien faire que l'utilisateur ne puisse faire.
  • Il n'est jamais écrit dans la session (temp:), ni dans les journaux (ne le loggez pas dans vos outils).
  • Écran de consentement Interne : seuls les comptes de l'organisation.
  • Portées minimales. cloud-platform est large : réservez-le aux agents qui en ont besoin.
  • Le secret du client OAuth : seulement dans l'app (C2), jamais dans le dépôt ni dans Terraform.

C7. L'agent Identité utilisateur : vérifier l'OAuth de bout en bout

Avant de brancher de vrais outils, vérifiez la chaîne avec l'agent fourni identite. Son outil qui_suis_je lit le jeton transmis par Gemini Enterprise, demande à Google à qui il appartient (oauth2.googleapis.com/tokeninfo) et répond : authentifié ou non, le compte, le domaine (acme.example), les portées, la durée restante. Il n'affiche jamais le jeton lui-même.

  1. Autorisation (C1, C2) avec les portées openid email https://www.googleapis.com/auth/cloud-platform. cloud-platform est exigée par Google pour Agent Runtime ; pour Cloud Run seul, openid email suffit.
    ./scripts/autorisation_oauth.sh create acces-identite ~/Downloads/client_secret_XXXX.json "openid email https://www.googleapis.com/auth/cloud-platform"
  2. Configuration : AGENTS_OAUTH="identite=acces-identite", puis source scripts/config.sh …, terraform plan (seul ["identite"] change) et terraform apply, dans 01-bis et/ou 02-bis, avec PUBLIER=oui.
  3. Dans l'app : Agent User sur « Identité utilisateur », puis dans le chat : « Suis-je authentifié ? Avec quel compte ? » → Autoriser → consentement.

Résultats obtenus (projets de test, compte de test ; chez vous : prenom.nom@acme.example, domaine acme.example) :

  • Agent Runtime. L'agent a été déployé, puis appelé comme Gemini Enterprise l'appelle (streaming_agent_run_with_events, jeton dans authorizations). Ce que l'outil a renvoyé :
    <- outil : {"status": "success", "authentifie": true, "verifie_par_google": true, "compte": "…@gmail.com",
                "domaine": "gmail.com", "portees": ["email", "…/auth/cloud-platform", "…/auth/userinfo.email", "openid", …],
                "expire_dans_secondes": 1391, "autorisation": "acces-identite"}
    agent : Oui, vous êtes authentifié avec le compte …@gmail.com (domaine : gmail.com).
            Vos portées de droits sont : email, cloud-platform, userinfo.email, openid…
            La durée restante de votre session est d'environ 23 minutes.
    
  • Même appel sans jeton (l'utilisateur n'a pas encore cliqué sur « Autoriser ») :
    <- outil : {"status": "success", "authentifie": false, "raison": "aucun jeton reçu : l'utilisateur n'a pas encore
                cliqué sur « Autoriser », ou l'agent n'est pas appelé depuis Gemini Enterprise"}
    agent : Non, vous n'êtes pas authentifié. […] connectez-vous via Gemini Enterprise et autorisez l'application.
    
  • A2A (serveur Cloud Run en local, en-têtes de Gemini Enterprise) : la même réponse « Oui, vous êtes authentifié… ». Avec un jeton invalide : « Le jeton reçu n'est pas reconnu par Google (il est expiré ou provient d'un autre fournisseur OAuth) ». Le jeton n'apparaît jamais dans les journaux du serveur (vérifié).
L'agent répondCe que ça veut dire
« agent déployé sans autorisation OAuth (AUTH_ID absent) »AGENTS_OAUTH ne contient pas identite=…, ou pas redéployé
« aucun jeton reçu »Agent ajouté dans l'app sans l'autorisation, ou l'utilisateur n'a pas cliqué « Autoriser »
« jeton reçu, mais Google ne le reconnaît pas »Jeton expiré, ou d'un autre fournisseur (normal pour Airtable, Jira…)
« authentifié, compte …@acme.example »Chaîne complète : vos outils peuvent utiliser ce jeton

8. Ce qui peut arriver

Ce que vous voyezCauseQue faire
Clé invalide / existe déjà / nom … déjà pris (nouvel_agent.py)Règles de 1.1Autre clé, ou autre nom affiché
Le plan montre des destroy ou recrée des agents existantsMauvaise configuration chargée, autre dossier, état perduNe pas appliquer. echo $TF_WORKSPACE (doit être scenario-12-1 ou scenario-12-2) ; recharger la configuration
PERMISSION_DENIED à la construction de l'image (gcloud builds submit ou terraform apply)API Cloud Build ou compte de construction tout neufs : droits pas encore actifsAttendre 1 à 2 minutes, relancer (Terraform réessaie déjà seul jusqu'à 4 fois)
… does not have storage.objects.get access to the Google Cloud Storage objectCompte de construction agents-build-sa absent, ou --service-account oublié12-1-1, partie 7
Construction FAILUREErreur dans l'image (souvent le code ou requirements.txt de l'agent)Lien du journal affiché par gcloud ; 🔎 « Cloud Build » → Historique (région europe-west1) ; corriger puis relancer : seules les images manquantes sont refaites
is tainted, so must be replaced au plan suivantUne construction d'image a échouéNormal : relancer apply
ÉCHEC : réponse bloquée par Model Armor juste après l'ajoutDroit du nouveau compte pas encore actifAttendre 2 à 5 minutes
Agent absent du chatPas d'accès Agent User sur cet agent2.3
Recherche indisponible : autorisation OAuth (AUTH_ID) …AGENTS_OAUTH vide pour cet agent, ou pas redéployéC4
Recherche refusée (403)Portée insuffisante, API non activée, ou l'utilisateur n'a pas accès à l'appC1 (portée, API), licence de l'utilisateur
ÉCHEC : TenantProject with location eu … does not exist (autorisation_oauth.sh)Pas d'app Gemini Enterprise dans ce projet / cette localisationVérifier PROJET_APP, NUM_APP, GE_LOCATION
Pas de bouton « Autoriser » dans le chatAgent ajouté sans autorisationC4 : supprimer et rajouter l'agent avec l'autorisation

Sources Google : Agents ADK (Agent Runtime) dans Gemini Enterprise, autorisations, Agents A2A dans Gemini Enterprise, OAuth et Cloud Run.

Siguiente