Accueil / Articles

Transférer les charges de travail d’Apps Script vers un environnement sandbox Linux géré par Gemini Managed Agent.

Google Apps Script qui pilote un environnement sandbox Linux pour un agent géré par Gemini : transférer des fichiers vers Drive à l’aide de ggsrun, contourner la limite de 50 MB, exécuter Playwright, FFmpeg et esbuild.

Éditeur : REACTAPP.TOP13 min de lecture2934 mots

Sources: Taking Advantage of Gemini Managed Agents with Google Apps Script

Pourquoi associer Apps Script à un environnement sandbox Linux

Google Apps Script est un outil pratique pour automatiser Google Workspace, mais il s’agit d’un environnement sans serveur léger et restreint, sans accès au niveau du système d’exploitation. Cela exclut de nombreuses tâches plus complexes. Le contrôle réseau et protocolaire au niveau basique est limité. Il n’y a pas de navigateur sans interface pour afficher des pages dynamiques, aucune façon d’exécuter des binaires natifs pour la transcodage de médias ou le traitement de signaux, pas de compilateurs modernes ni de chaînes d’outils de compilation, et des quotas stricts en matière de temps d’exécution et de taille du chargement.

Gemini Managed Agents offrent une solution à ce problème. Faisant partie de l’API Gemini v1beta Interactions and Environments, ils permettent aux développeurs de mettre en place des environnements sandbox Linux distants capables d’exécuter du code par eux-mêmes, de lancer des commandes shell et de gérer des paquets. Leur association avec la CLI de Google Workspace a déjà suscité l’intérêt de la communauté.

L’architecture décrite ici relie les deux éléments. Apps Script orchestre un conteneur Linux persistant disposant de 4 cœurs CPU et de 16 Go de RAM, ainsi que de Python 3.12, Node.js 22 et des gestionnaires de paquets habituels (apt, npm, pip). Le conteneur envoie directement les fichiers générés vers Google Drive à l’aide de l’outil en ligne de commande ggsrun. Comme les fichiers ne passent jamais par la réponse API, cette conception évite les limites de charge utile et les surcoûts liés aux tokens, permettant ainsi une automatisation cloud à fort débit.

Le problème lié au retour de fichiers binaires en format Base64

Supposons que le sandbox génère un fichier de grande taille, comme des captures d’écran en haute résolution, des formes d’onde audio ou un fichier JavaScript compressé, et qu’il doive être stocké dans Drive. La solution évidente consiste à retourner les octets bruts sous forme de chaîne Base64 dans la réponse de l’API Gemini, puis à les déchiffrer dans Apps Script. Cependant, cette approche se heurte à plusieurs obstacles.

  • UrlFetchApp dans Apps Script impose une limite de 50 MB pour les chargements de réponse.
  • L’environnement d’exécution du code de l’API Interactions limite le buffer stdout, ce qui peut entraîner la coupure d’une chaîne Base64 de plusieurs mégaoctets en cours de transmission.
  • Les agents gérés disposent d’une quota de 200 000 tokens par minute. Le format Base64 augmente la taille binaire d’environ un tiers, et lors de sessions multiples, les chaînes Base64 précédentes s’accumulent dans l’historique des conversations jusqu’à épuisement du quota, ce qui provoque immédiatement des erreurs 429 Quota Exceeded.
  • Décoder de longues chaînes Base64 et créer des fichiers Drive dans Apps Script consomme du temps d’exécution ainsi que de la mémoire du script.
  • Le diagramme suivant compare cette méthode à la diffusion directe.

    La meilleure approche consiste à exécuter l’outil ggsrun basé sur Go directement à l’intérieur du sandbox, en injectant un jeton d’accès OAuth au moment de l’exécution via ScriptApp.getOAuthToken(). Le sandbox transmet ensuite les fichiers binaires vers Drive via l’infrastructure interne de Google Cloud à des vitesses supérieures à 2 MB/s, contournant ainsi les limites de mémoire, de taille de réponse et les quotas de jetons d’Apps Script en une seule étape.

    La diffusion fonctionne dans les deux sens

    Le transfert direct de cloud en cloud est également utile pour les téléchargements. Lorsque de gros ensembles de données externes, tels que des images haute résolution, de l’audio, de la vidéo, des fichiers CSV ou JSON de plusieurs gigaoctets ou des modèles d’apprentissage automatique, doivent être transférés dans le sandbox, l’incorporation de ces données sous forme de texte Base64 ou sérialisé épuise presque immédiatement la quota de tokens d’entrée, ce qui entraîne une erreur 429. Avec ggsrun, le sandbox télécharge directement le fichier depuis Drive, et la commande nécessite uniquement une instruction courte du type « téléchargez l’ensemble de données cible depuis Drive et analysez-le ». L’utilisation des tokens d’entrée diminue pratiquement à zéro, ce qui évite l’épuisement des limites de vitesse.

    Le partage d’un environnement sandbox persistant permet de réduire encore les coûts. Une seule étape de provisionnement génère un environmentId que les projets Apps Script, les postes de travail locaux Node.js, les scripts Python ainsi que les pipelines CI/CD peuvent tous utiliser. Les ensembles de données principaux, les corpus, les bibliothèques ou les modèles pré-entraînés stockés sous /workspace/ sont alors accessibles à chaque client, ce qui évite de recharger les données ou de répéter la configuration à chaque utilisation. Cela diminue la latence, la bande passante réseau et la charge cumulée des API, et les tâches peuvent réutiliser des fichiers de travail partagés ainsi que des paquets pré-installés.

    Le diagramme suivant présente l’architecture complète, où Apps Script et les postes de travail locaux Node.js orchestrent le même environnement sandbox persistant grâce à un environmentId partagé, en utilisant un streaming bidirectionnel et des ensembles de données partagés pour une génération rapide de contenu.

    Celle-ci se divise en quatre parties :

    • Plusieurs clients gèrent un seul conteneur. Apps Script basé sur le cloud utilise un déclencheur synchrone et un jeton OAuth dynamique, tandis que les postes de travail locaux Node.js emploient un streaming en temps réel SSE ainsi qu’une authentification gcloud.
    • Le sandbox conserve les ensembles de données partagés et les outils de construction tels que Playwright, FFmpeg et esbuild, ce qui permet de générer du contenu sans avoir à recharger les données.
    • ggsrun download transfère des ensembles de données volumineux depuis Drive vers le sandbox, ce qui évite l’incorporation immédiate des données et permet de respecter la limite de 200 000 TPM.
    • ggsrun upload envoie les binaires finalisés vers Drive à une vitesse de 2 MB/s ou plus, ce qui dépasse la limite de 50 MB de charge utile ainsi que le problème de troncature de stdout.

    Le code source complet (les classes d’Apps Script, les clients de flux Node.js, les suites de tests et les journaux d’exécution bruts) se trouve dans le répertoire GitHub public du projet.

    Mise en place

    Tout d’abord, générez une clé API dans Google AI Studio. Elle authentifie les demandes adressées aux API Gemini v1beta Interactions and Environments. Ensuite, créez un projet Apps Script de deux manières : un projet indépendant depuis script.google.com via Nouveau projet, ou un projet lié à un conteneur en ouvrant une feuille de calcul, un document ou un formulaire, puis en sélectionnant Extensions, puis Apps Script.

    Copiez deux fichiers depuis le répertoire dans l’éditeur :

    • ManagedAgentSandboxClient.js est la classe client principale. Elle gère le cycle de vie du sandbox et les variables d’environnement dynamiques, conserve les données de session dans PropertiesService et applique des stratégies de retentissement appropriées en cas de réponse 429.
    • tests.js est le ensemble de tests principal. Il couvre l’allocation du sandbox, les vérifications des outils, le traitement des médias, le web scraping ainsi que les benchmarks de performance.

    Ensuite, ouvrez les Paramètres du projet, puis les Propriétés du script, et ajoutez une propriété nommée GEMINI_API_KEY qui contiendra la clé. Enfin, assurez-vous que le manifeste (appsscript.json) comporte les scopes OAuth appropriés. Le scope https://www.googleapis.com/auth/script.external_request est nécessaire pour les appels à UrlFetchApp, tandis que https://www.googleapis.com/auth/drive permet de créer des dossiers de destination et de télécharger des fichiers. Le code qui utilise des dossiers existants sans DriveApp.createFolder() peut se contenter du scope https://www.googleapis.com/auth/drive.file. Les journaux d’exécution de chaque test se trouvent dans gas-src/execution-logs.md du répertoire.

    Mise à disposition du sandbox partagé

    L’exécution de provisionSharedSandbox() démarre un nouveau conteneur Linux à distance, installe les outils CLI et les dépendances, configure les chemins du disque de destination et enregistre l’environmentId généré dans PropertiesService.

    L’infographie montre quatre étapes. Drive crée d’abord un dossier de destination nommé ManagedAgent_Artifacts_YYYYMMDD. Ensuite, le conteneur disposant de 4 cœurs CPU et de 16 Go de mémoire démarre ggsrun, ffmpeg, sox, jq, typescript, esbuild ainsi que Playwright avec Chromium, via une invite d’initialisation. Par la suite, le sandbox vérifie les binaires installés et affiche READY. Enfin, l’environmentId unique est stocké sous SHARED_SANDBOX_SESSION, afin que des tests ultérieurs et d’autres clients puissent le réutiliser. Appeler testListSandboxes() ensuite permet de consulter l’API des Environnements pour confirmer que le sandbox est actif et de récupérer ses métadonnées.

    Test 1 : en-têtes personnalisés que Apps Script écrase

    Le premier test montre quelque chose que UrlFetchApp ne peut pas faire. Apps Script remplace automatiquement une en-tête User-Agent personnalisé par la chaîne d’identité du proxy de Google, tandis que le sandbox conserve tous les en-têtes que vous avez définis, car il envoie les requêtes via des sockets POSIX bruts et curl natif.

    Le diagramme illustre une demande contenant User-Agent: sample user agent envoyée à httpbin.org/anything. Du côté d’Apps Script, la politique de proxy de la plateforme modifie l’en-tête. Du côté du sandbox, curl conserve exactement la même chaîne de caractères. Un script Python intégré compare ensuite les en-têtes JSON reflétés et affiche une matrice de vérification. Plus concrètement, Apps Script envoie une requête GET avec l’en-tête personnalisé, le sandbox envoie la même requête curl, et la comparaison confirme qu’Apps Script a remplacé Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; ...) tandis que le sandbox a conservé sample user agent tel quel.

    Test 2 : authentification auprès de Drive depuis l’intérieur du sandbox

    Ce test vérifie l’authentification de Drive ainsi que l’accès direct via ggsrun en injectant un jeton OAuth frais provenant de ScriptApp.getOAuthToken() dans l’exécution de cette étape.

    À l’étape un, Apps Script extrait le jeton et l’injecte en tant que variable d’environnement GGSRUN_AT, ce qui élimine le risque d’expiration du jeton en une heure. À l’étape deux, le sandbox génère un fichier de vérification, 00_ggsrun_verification.txt, dans le répertoire /workspace/test2/, puis le télécharge à l’aide de ggsrun upload en mode d’écrasement non bloquant (--nc --cm OverwriteIfNewer -j). À l’étape trois, ggsrun searchfiles interroge le dossier de destination et renvoie des métadonnées structurées confirmant la présence des neuf fichiers. L’ensemble du cycle de création, de téléchargement et de vérification a duré 12,1 secondes, et aucun jeton sensible n’a persisté entre les sessions.

    Test 3 : extraction sans interface avec Playwright

    Ensuite, une session automatisée sans interface de Chromium dans le sandbox extrait du contenu dynamique généré par JavaScript et prend des captures d’écran à plusieurs tailles d’affichage.

    Un script Node.js Playwright ouvre un site de citations affichées via JavaScript (quotes.toscrape.com/js/), prend des captures d’écran de toute la page à la taille d’un ordinateur de bureau (1280x800) et dans une emulation d’iPhone (375x812), puis clique sur le contrôle de pagination, capture une image de la deuxième page en mode bureau et extrait les citations dans 02_Page2_Quotes.json. Les tailles étaient d’environ 92,5 KB pour la capture d’ordinateur de bureau, 51,6 KB pour le format mobile et 171,9 KB pour la deuxième page, plus 4,1 KB pour le fichier JSON, soit environ 320 KB au total pour les quatre fichiers générés. Une seule commande ggsrun upload a envoyé les trois fichiers PNG ainsi que le jeu de données JSON vers Drive sans aucune conversion en Base64, et toute l’opération a duré 20,4 secondes. Il s’agit d’une rendu côté client que Apps Script ne peut pas parser nativement.

    Test 4 : synthèse audio avec FFmpeg et SoX

    Le quatrième test exécute un traitement numérique de signaux natif dans le sandbox, en créant un accord polytonal à l’aide de FFmpeg et SoX.

    Trois générateurs d’ondes sinusoïdales à 440 Hz (A4), 554,37 Hz (C#5) et 659,25 Hz (E5) sont mélangés via le filtre amix de ffmpeg pour former un MP3 d’accord majeur d’une durée de trois secondes et d’une taille de 73,4 KB. ffprobe extrait ensuite les métadonnées du flux dans le fichier 03_Audio_Analysis.json, dont la taille est de 1,8 KB. L’instruction ggsrun upload envoie directement 03_Chord_Major.mp3 ainsi que le fichier JSON sur Drive. La synthèse, l’extraction des métadonnées et le téléchargement ont duré 9,1 secondes.

    Test 5 : Analyse de TypeScript et empaquetage avec esbuild

    Ce test démontre le fonctionnement des outils modernes de compilation pour JavaScript et TypeScript à l’intérieur du sandbox.

    Deux ensembles d’outils travaillent sur un module TypeScript, matrix.ts, qui définit des classes et des interfaces génériques et se trouve dans /workspace/test5/. Dans la première branche, un script Node.js utilise l’API officielle du compilateur TypeScript pour analyser l’arbre de syntaxe abstraite et exporter les schémas d’interfaces et de méthodes dans 04_TypeScript_AST.json, soit seulement 152 octets. Dans la seconde, esbuild empaquette et minifie le module en un fichier IIFE autonome, 04_Matrix_Bundle.iife.js, d’une taille de 1,2 KB, avec un temps de compilation de seulement 13 millisecondes. ggsrun upload envoie ensuite les deux résultats sur Drive, et l’exécution complète dure 10,0 secondes.

    Test 6 : téléchargement direct via Base64 à l’aide d’Apps Script

    Le benchmark transfère un fichier binaire de 10 000 octets depuis le sandbox vers Drive par deux méthodes différentes.

    Dans l’approche A, le sandbox crée un fichier binaire de 10 KB à partir de /dev/urandom et le transmet à Drive via ggsrun au cours d’une seule interaction (freshInteraction: true). Dans l’approche B, le sandbox encode ces mêmes octets en Base64 et les renvoie dans le texte de réponse de l’API ; Apps Script décode ensuite cette chaîne et enregistre le fichier à Drive. L’approche A a mis 16,20 secondes pour traiter le fichier à une vitesse de 0,60 KB/s, sans consommer de ressources CPU d’Apps Script. L’approche B a nécessité 32,13 secondes à une vitesse de 0,30 KB/s, en plus de 1,23 seconde de consommation CPU d’Apps Script, ce qui fait que l’approche A était 1,98 fois plus rapide. Elle évite également l’inflation d’environ 33 % due à la codification Base64 ainsi que l’épuisement des tokens que subissent les sessions multi-étapes. Le rapport enregistré ressemble à ceci.

    ================================================================================
    PERFORMANCE BENCHMARK REPORT: 10,000 BYTES FILE TRANSFER TO GOOGLE DRIVE
    ================================================================================
    | Metric                       | Approach A: Direct ggsrun Upload | Approach B: Base64 via Gemini API -> GAS |
    | :--------------------------- | :------------------------------- | :--------------------------------------- |
    | Transfer Method              | Direct Sandbox-to-Drive (Go CLI) | Base64 Stream -> GAS -> Drive            |
    | Drive File Name              | benchmark_10kb_ggsrun.bin        | benchmark_10kb_gas.bin                   |
    | Verified File Size           | 10,000 bytes (9.77 KB)           | 10,000 bytes (9.77 KB)                   |
    | API Turns Required           | 1 Turn (Direct Offload)          | 1 Turn (Base64 Retrieval)                |
    | Local GAS Processing Time    | 0.00 s (Zero CPU overhead)       | 1.23 s (Base64 Decode & Blob Creation)   |
    | Total End-to-End Duration    | 16.20 s                          | 32.13 s                                  |
    | Effective Throughput         | 0.60 KB/s                        | 0.30 KB/s                                |
    | Performance Multiplier       | 1.98x FASTER                     | Baseline (Higher Latency & Token Usage)  |
    ================================================================================
    

    Le streaming via ggsrun était 1,98 fois plus rapide, éliminait tous les coûts en CPU et en mémoire liés à la décodage dans Apps Script, et ne consommait aucune part de la quota des tokens de conversation. Pour des charges de travail de plusieurs mégaoctets, cette voie directe permet d’éviter les erreurs 429 Quota Exceeded.

    Utilisation de la même sandbox depuis un poste de travail local

    Afin de démontrer qu’il est possible de contrôler la même sandbox Linux persistante depuis Apps Script ainsi que depuis un ordinateur portable, un client Node.js utilisant le streaming Server-Sent Events a été développé à l’aide du SDK @google/genai. Apps Script s’exécute de manière synchrone et bloquante, en collectant les événements de l’agent à la fin de la requête HTTP ; par conséquent, l’exécuteur local offre aux développeurs plusieurs fonctionnalités que Apps Script ne peut pas fournir.

    • Visibilité en temps réel du processus. Les étapes de raisonnement (thought), les commandes de shell (code_execution_call), les sorties stdout et stderr du sandbox (code_execution_result) ainsi que le texte généré par le modèle (model_output) sont affichés dans la terminal au fur et à mesure qu’ils se produisent, avec des couleurs ANSI.
    • Un flux de travail hybride pour le développement. Les prompts et les chaînes d’outils peuvent être prototypés, débogués et ajustés localement avec un retour en temps réel, avant d’être intégrés dans des déclencheurs Apps Script automatisés qui s’exécutent sans surveillance.
    • Partage facile du sandbox. En saisissant l’identifiant généré lors de la configuration d’Apps Script dans ENVIRONMENT_ID d’un fichier .env local, on relie le client au conteneur existant, y compris tous ses paquets installés, ses binaires compilés et ses fichiers de travail, sans nécessiter de réinstallation.
  • Gestion automatique d’OAuth. Le lanceur obtient de nouveaux tokens d’accès Google à l’aide de gcloud auth print-access-token et les insère dans GGSRUN_AT, ce qui permet des téléchargements directs vers Drive, tout comme dans Apps Script, sans avoir à copier manuellement les identifiants.
  • Exécuter les tests locaux nécessite quatre étapes.

    1. Cloner le répertoire et exécuter npm install à l’intérieur de local-node.js-src.
    2. Dupliquer .env.example en .env et y saisir trois valeurs : votre clé API en tant que GEMINI_API_KEY, l’identifiant de l’environnement de test en tant que ENVIRONMENT_ID, et le dossier Drive vers lequel écrire en tant que TARGET_FOLDER_ID.
    3. Exécuter npm test, ou un test spécifique avec npm run test:1 jusqu’à test:6, et observer le fonctionnement de l’agent en temps réel.
    4. Lorsque vous avez terminé, exécutez npm run test:teardown pour supprimer le sandbox distant et libérer les ressources cloud.

    Les transcriptions brutes complètes, accompagnées des résultats diffusés en direct, sont sauvegardées dans local-node.js-src/execution-logs.md du répertoire, et elles présentent les mêmes résultats fonctionnels que ceux obtenus lors des exécutions d’Apps Script.

    Modèles API pour les Agents gérés

    Les modèles ci-dessous résument les méthodes courantes pour interagir avec l’API Gemini v1beta Interactions and Environments. Chacun d’eux envoie une requête POST vers le même point de terminaison de base.

    POST https://generativelanguage.googleapis.com/v1beta/interactions?key=${API_KEY}
    Content-Type: application/json
    

    Le scénario 1 partage un seul environnement sandbox persistant entre de nombreux clients. Créez l’environnement distant une seule fois, en définissant environment.type sur "remote", conservez l’environment_id qui est retourné, et envoyez-le sous forme de chaîne de caractères simple dans les demandes ultérieures depuis Apps Script, Node.js, Python ou un job CI/CD.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Run task in shared container...",
      "environment": "environments/env-12345"
    }
    

    Le scénario 2 constitue un environnement isolé pour chaque exécution. Lorsqu’une tâche nécessite un environnement Linux entièrement neuf, définissez environment.type sur "remote" à chaque appel.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Execute client-specific isolated task...",
      "environment": {
        "type": "remote"
      }
    }
    

    Le scénario 3 conserve le contexte de la conversation au fil des échanges. Incluez previous_interaction_id chaque fois que l’agent doit se souvenir de raisonnements, de variables ou de résultats de commandes antérieurs.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Based on the previous output, proceed to step 2...",
      "environment": "environments/env-12345",
      "previous_interaction_id": "interaction-prev-67890"
    }
    

    Le scénario 4 réutilise un environnement isolé avec un contexte vierge, grâce à l’option freshInteraction. Il suffit de fournir l’environment_id existant et d’omettre previous_interaction_id. Tous les fichiers et outils installés dans le conteneur restent en place, tandis que l’historique des conversations est réinitialisé à zéro tokens, ce qui évite d’épuiser la limite de vitesse du TPM.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Execute a completely new task in the existing sandbox...",
      "environment": "environments/env-12345"
    }
    

    Comparaison en un coup d’œil

    La matrice de résumé place les différentes approches côte à côte.

    Quelles en sont les conséquences

    En combinant Apps Script avec Gemini Managed Agents, on dépasse les limites habituelles d’un environnement sans serveur. Un espace de travail distant persistant, ainsi que des flux en continu entre le stockage cloud et cet espace de travail dans les deux sens, permettent de gérer des charges de travail que Apps Script seul ne peut pas traiter, tout en contournant les limites de taille des données API et les quotas de tokens de conversation.

    • Les limites d’Apps Script sont surmontées. Les tâches nécessitant un environnement Linux natif, telles que le scraping avec un navigateur sans interface via Playwright, la synthèse audio avec FFmpeg ou la compilation de TypeScript à l’aide de esbuild, peuvent désormais être lancées depuis Apps Script.
    • Le raisonnement de l’IA s’associe à l’exécution sous Linux. Au lieu d’exécuter des commandes externes fixes, le raisonnement de Gemini est couplé à un vrai shell, ce qui permet de composer des commandes en temps réel, d’exécuter du code au moment de l’exécution et pour que l’agent puisse se corriger lors de workflows complexes.
    • La transmission en flux dans les deux sens permet d’économiser des tokens et du chargement de données. Le téléchargement d’artefacts ainsi que le récupération de grands ensembles de données depuis Drive dans le sandbox évitent d’insérer des données dans des prompts ou de recourir à une conversion Base64, ce qui maintient le nombre de tokens d’entrée et de sortie faible, tout en évitant la limite de 50 MB et le quota de 200 000 TPM.
    • Les sandboxes partagés réduisent les coûts. Le stockage de jeux de données et d’outils courants dans un système de fichiers de conteneur partagé élimine les téléchargements et les configurations répétés pour chaque tâche, ce qui diminue la latence et la bande passante.
    • Les benchmarks confirment cela. Le streaming direct de cloud à cloud via la CLI était 1,98 fois plus rapide que la récupération en format Base64 via l’API, sans coût de décodage en CPU et sans utilisation de mémoire locale dans Apps Script.