1. Einführung
Mit Google Workspace Studio können Sie Geschäftsprozesse in Google Workspace-Anwendungen wie Gmail, Google Chat, Google Drive und Google Sheets automatisieren. Wenn Ihre Arbeitsabläufe in einer externen Webanwendung gestartet werden müssen oder benutzerdefinierte Logik in Ihrer eigenen Cloud-Umgebung ausgeführt werden soll, können Sie Google Workspace Studio mit einem HTTP-Google Workspace-Add-on in Node.js auf Cloud Run erweitern:
- Benutzerdefinierter Startschritt (
workflowTrigger): Startet einen Google Workspace Studio-Ablauf, wenn ein externes Ereignis eintritt, z. B. wenn ein Kunde ein Ticket in einem internen Webportal einreicht. Dazu wird die Google Workspace Studio REST APItriggers.fireaufgerufen. - Benutzerdefinierter Aktionsschritt (
workflowAction): Empfängt Variablen aus früheren Schritten im Flow, führt benutzerdefinierte Logik oder KI-Inferenz in Ihrem Node.js-Dienst aus und gibt Ausgabevariablen an Google Workspace Studio zurück.
In diesem Codelab erstellen und stellen Sie eine vollständige Node.js-HTTP-Erweiterung für Google Workspace Studio in Cloud Run bereit, verwenden Cloud Firestore, um aktive Flow-Trigger-Abos und eingereichte Tickets über Containerrevisionen hinweg beizubehalten, und klassifizieren die Dringlichkeit von Tickets in Ihrem benutzerdefinierten Aktionsschritt mit Gemini 3.8 Flash (gemini-3.8-flash) auf der Gemini Enterprise Agent Platform mit einem robusten Fallback für den Keyword-Abgleich.
Aufgaben
- Eine Support Quick Portal-Webanwendung und ein HTTP-Google Workspace-Add-on, die mit Node.js, Express und Firestore in Cloud Run erstellt wurden.
- Ein benutzerdefinierter Startschritt New Support Ticket (
supportTicketTrigger), mit dem aktive Flow-Abos in einerstudio_triggersFirestore-Sammlung gespeichert, eingereichte Tickets in einersupport_ticketsFirestore-Sammlung protokolliert und ausgelöst werden, wenn ein Ticket im Webportal eingereicht wird. Dabei werdenticketTitleundticketDescriptionin einen Google Workspace Studio-Flow übergeben. - Ein benutzerdefinierter Aktionsschritt vom Typ Detect Urgency (
urgencyDetectorStep), der die Dringlichkeit von Tickets mit Gemini 3.8 Flash (gemini-3.8-flash) auf der Gemini Enterprise Agent Platform (aiplatform.googleapis.com) klassifiziert. Es erfolgt ein automatisches Fallback auf die Keyword-Optionen (urgent,blocker,critical).
Lerninhalte
- So konfigurieren Sie ein HTTP-Google Workspace-Add‑on-Bereitstellungsmanifest (
deployment.json) mit den ElementenworkflowTriggerundworkflowAction. - Anleitung zum persistenten Speichern von Google Workspace Studio-Triggerabos (
triggerId,notifyUriunduserOAuthToken) in einerstudio_triggersFirestore-Sammlung und zum Auslösen von Flows mit dertriggers.fireREST API. - So erstellen Sie einen benutzerdefinierten
workflowAction-Schritt in Node.js mit strukturierter Ausgabe von Gemini 3.8 Flash (gemini-3.8-flash) auf der Gemini Enterprise Agent Platform mit einem Keyword-Fallback.
Vorbereitung
- Ein Google Workspace-Konto mit Zugriff auf Google Workspace Studio.
- Ein Google Cloud-Projekt mit aktivierter Abrechnung, das in derselben Google Workspace-Organisation wie Ihr Nutzerkonto erstellt wurde, damit Sie nicht veröffentlichte Add‑on-Bereitstellungen zum Testen installieren können.
2. Google Cloud-Projekt und Firestore einrichten
In diesem Schritt konfigurieren Sie den OAuth-Zustimmungsbildschirm Ihres Projekts, aktivieren die erforderlichen Google Cloud- und Google Workspace-APIs in Cloud Shell, stellen Ihre (default)-Firestore-Datenbank bereit und initialisieren das Dienstkonto für die Add-on-Autorisierung.
- Öffnen Sie die Google Cloud Console, wählen Sie Ihr Google Cloud-Projekt aus und klicken Sie in der oberen Navigationsleiste auf das Symbol Cloud Shell aktivieren.
- Konfigurieren Sie den OAuth-Zustimmungsbildschirm, damit Google Workspace einen OAuth-Client für Ihr Add-on bereitstellen kann:
- Öffnen Sie die Branding-Seite der Google Auth Platform.
- Klicken Sie bei Aufforderung auf Jetzt starten. Wenn Ihr Zustimmungsbildschirm bereits konfiguriert ist, fahren Sie mit Schritt 3 fort.
- Geben Sie unter App-Informationen
Support Extensionfür den App-Namen ein, wählen Sie Ihre E‑Mail-Adresse für Nutzersupport aus und klicken Sie auf Weiter. - Wählen Sie unter Zielgruppe die Option Intern aus und klicken Sie auf Weiter.
- Geben Sie unter Kontaktdaten Ihre E‑Mail-Adresse ein und klicken Sie auf Weiter.
- Klicken Sie auf Abschließen, akzeptieren Sie die Richtlinie zu Nutzerdaten für Google API-Dienste, klicken Sie auf Weiter und dann auf Erstellen.
- Legen Sie in Cloud Shell Ihr aktives Projekt fest (ersetzen Sie
YOUR_PROJECT_IDdurch Ihre Google Cloud-Projekt-ID) und aktivieren Sie die erforderlichen APIs:gcloud config set project YOUR_PROJECT_ID gcloud services enable \ aiplatform.googleapis.com \ firestore.googleapis.com \ run.googleapis.com \ cloudbuild.googleapis.com \ artifactregistry.googleapis.com \ appsmarket-component.googleapis.com \ gsuiteaddons.googleapis.com \ workspacestudio.googleapis.com - Stellen Sie Ihre
(default)-Firestore-Datenbank inus-central1bereit (falls sie noch nicht vorhanden ist) und initialisieren Sie Ihr Google Workspace-Add-ons-Dienstkonto:gcloud firestore databases describe --database="(default)" >/dev/null 2>&1 || \ gcloud firestore databases create \ --database="(default)" \ --location=us-central1 \ --type=firestore-native \ --quiet gcloud workspace-add-ons get-authorization
3. Node.js-App mit Firestore und Gemini 3.8 Flash erstellen
In diesem Schritt erstellen Sie die Node.js-Anwendung in ~/studio-support-addon. Damit der Code modular und lesbar bleibt, organisieren Sie das Projekt in fünf Dateien:
firestore.js: Initialisiert den Cloud Firestore-Client (studio_triggers- undsupport_tickets-Sammlungen) und aktualisiert zwischengespeicherte OAuth-Tokens.starter.js: Implementiert die Webhooks für den benutzerdefinierten Starter-Schritt Neues Support-Ticket (/onConfigTriggerund/onManageTrigger).action.js: Implementiert die Webhooks für den benutzerdefinierten Aktionsschritt Detect Urgency (/onConfigUrgencyund/onExecuteUrgency) mit Gemini 3.8 Flash (gemini-3.8-flash) und einem Fallback für den Keyword-Abgleich.portal.js: Stellt die Web-UI des Support Quick Portal (GET /) bereit und löst aktive Google Workspace Studio-Trigger (POST /api/submit-ticket) aus.index.js: Verbindet alle Express-Routen und startet den HTTP-Server.
Projekt und package.json initialisieren
- Erstellen Sie ein Projektverzeichnis und rufen Sie es auf:
mkdir -p ~/studio-support-addon && cd ~/studio-support-addon - Erstellen Sie
package.jsonmitexpress,@google-cloud/firestoreund@google/genai:cat << 'EOF' > package.json { "name": "studio-support-addon", "version": "1.0.0", "type": "module", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "@google-cloud/firestore": "^7.11.0", "@google/genai": "^1.0.0", "express": "^4.21.2" } } EOF
firestore.js – Gemeinsamer Firestore-Status und Aktualisierung von OAuth-Tokens
Erstellen Sie firestore.js, um Ihre beiden Firestore-Sammlungen zu verwalten und zwischengespeicherte OAuth-Tokens für Nutzer aktuell zu halten:
studio_triggers: Hier werden aktive Google Workspace Studio-Abo-Flows (triggerId,notifyUriunduserOAuthToken) gespeichert, damit sie Cloud Run-Containerneustarts und Skalierung-auf-null-Ereignisse überstehen.support_tickets: Speichert einen Datensatz für jedes Support-Ticket, das über das Portal eingereicht wurde.refreshTokenInFirestore(req): Wenn Google Workspace Studio einen Ihrer Webhook-Endpunkte aufruft, wird ein kurzlebigerauthorizationEventObject.userOAuthTokeneingefügt. Mit diesem Helfer werden aktive Triggerdokumente mit dem neuesten Token aktualisiert, damittriggers.fire-Hintergrundaufrufe autorisiert bleiben.
cat << 'EOF' > firestore.js
import { Firestore } from '@google-cloud/firestore';
export const db = new Firestore({
projectId: process.env.GOOGLE_CLOUD_PROJECT || undefined,
databaseId: '(default)',
ignoreUndefinedProperties: true,
});
export const triggersCollection = db.collection(
process.env.FIRESTORE_TRIGGERS_COLLECTION || 'studio_triggers'
);
export const ticketsCollection = db.collection(
process.env.FIRESTORE_TICKETS_COLLECTION || 'support_tickets'
);
// Keep cached userOAuthToken fresh across active trigger documents
export async function refreshTokenInFirestore(req) {
const freshToken = req.body?.authorizationEventObject?.userOAuthToken;
if (!freshToken) return;
try {
const snapshot = await triggersCollection.get();
if (snapshot.empty) return;
const batch = db.batch();
snapshot.docs.forEach((doc) => {
batch.set(
doc.ref,
{ userOAuthToken: freshToken, updatedAt: new Date().toISOString() },
{ merge: true }
);
});
await batch.commit();
} catch (err) {
console.error('Error refreshing OAuth token in Firestore:', err.message);
}
}
EOF
starter.js – Benutzerdefinierter Auslöserschritt (workflowTrigger)
Erstellen Sie starter.js, um die beiden Webhook-Endpunkte zu implementieren, die für einen benutzerdefinierten Starter-Schritt in Google Workspace Studio erforderlich sind:
onConfigTrigger(POST /onConfigTrigger): Wird aufgerufen, wenn ein Nutzer Neues Support-Ticket als Starter für den Flow in Google Workspace Studio auswählt. Gibt einepushCard-Navigationsaktion zurück, die den Starter beschreibt.onManageTrigger(POST /onManageTrigger): Wird aufgerufen, wenn ein Nutzer einen Ablauf aktiviert (req.body.workflow.triggerCreation) oder deaktiviert / löscht (req.body.workflow.triggerDeletion). Speichert oder löscht das Abo-Dokument in der Firestore-Sammlungstudio_triggers.
cat << 'EOF' > starter.js
import { triggersCollection, refreshTokenInFirestore } from './firestore.js';
// Custom Starter Configuration Card
export async function onConfigTrigger(req, res) {
await refreshTokenInFirestore(req);
res.status(200).json({
action: {
navigations: [
{
pushCard: {
sections: [
{
header: 'Support Ticket Listener',
widgets: [
{
textParagraph: {
text: 'This starter listens for new tickets submitted through the Support Quick Portal and stores subscriptions in Firestore.',
},
},
],
},
],
},
},
],
},
});
}
// Custom Starter Subscription Lifecycle (Firestore studio_triggers collection)
export async function onManageTrigger(req, res) {
try {
const triggerCreation = req.body?.workflow?.triggerCreation;
const triggerDeletion = req.body?.workflow?.triggerDeletion;
const userOAuthToken =
req.body?.authorizationEventObject?.userOAuthToken || null;
if (triggerCreation?.triggerId) {
const triggerId = String(triggerCreation.triggerId);
const docId = encodeURIComponent(triggerId);
await triggersCollection.doc(docId).set(
{
triggerId,
notifyUri: triggerCreation.notifyUri || null,
...(userOAuthToken ? { userOAuthToken } : {}),
updatedAt: new Date().toISOString(),
},
{ merge: true }
);
}
if (triggerDeletion?.triggerId) {
const triggerId = String(triggerDeletion.triggerId);
const docId = encodeURIComponent(triggerId);
await triggersCollection.doc(docId).delete();
}
if (!triggerCreation && !triggerDeletion && userOAuthToken) {
await refreshTokenInFirestore(req);
}
} catch (err) {
console.error('Error in /onManageTrigger:', err.message);
}
res.status(200).json({});
}
EOF
action.js – Benutzerdefinierter Aktionsschritt (workflowAction) mit Gemini 3.8 Flash
Erstellen Sie action.js, um die beiden Webhook-Endpunkte zu implementieren, die für einen benutzerdefinierten Aktionsschritt in Google Workspace Studio erforderlich sind:
onConfigUrgency(POST /onConfigUrgency): Gibt eine Konfigurationskarte mit einemtextInput-Widget zurück, dashostAppDataSource.workflowDataSource.includeVariables: truefestlegt. So können Nutzer dieticketDescription-Variable auswählen, die vom Startschritt ausgegeben wird.onExecuteUrgency(POST /onExecuteUrgency): Liest dieticketDescription-Eingabe vonreq.body.workflow.actionInvocation.inputs, klassifiziert ihre geschäftlichen Auswirkungen und Dringlichkeit mit Gemini 3.8 Flash (gemini-3.8-flash) auf der Gemini Enterprise Agent Platform mit strukturierter Ausgabe (responseSchema-Enum["High", "Normal"]), greift aufdetectKeywordUrgency()(urgent,blocker,critical) zurück, wenn der Modellaufruf fehlschlägt, und gibt dieurgencyLevel-Ausgabevariable mithostAppAction.workflowAction.returnOutputVariablesActionzurück.
cat << 'EOF' > action.js
import { GoogleGenAI, Type } from '@google/genai';
import { refreshTokenInFirestore } from './firestore.js';
// Initialize Google GenAI SDK for the Gemini Enterprise Agent Platform
const ai = new GoogleGenAI({
vertexai: true,
project: process.env.GOOGLE_CLOUD_PROJECT,
location: 'global',
});
// Fallback keyword classifier if the Gemini API call is unavailable
export function detectKeywordUrgency(description) {
const lower = (description || '').toLowerCase();
return lower.includes('urgent') ||
lower.includes('blocker') ||
lower.includes('critical')
? 'High'
: 'Normal';
}
// Custom Action Step Configuration Card
export async function onConfigUrgency(req, res) {
await refreshTokenInFirestore(req);
res.status(200).json({
action: {
navigations: [
{
pushCard: {
sections: [
{
header: 'Urgency Detector Step',
widgets: [
{
textInput: {
name: 'ticketDescription',
label: 'Source Description',
hintText:
'Select the description variable outputted by the starter',
hostAppDataSource: {
workflowDataSource: {
includeVariables: true,
},
},
},
},
],
},
],
},
},
],
},
});
}
// Custom Action Step Execution: Gemini 3.8 Flash with keyword fallback
export async function onExecuteUrgency(req, res) {
await refreshTokenInFirestore(req);
const inputs = req.body?.workflow?.actionInvocation?.inputs || {};
const description = inputs.ticketDescription?.stringValues?.[0] || '';
let urgencyLevel = detectKeywordUrgency(description);
try {
const response = await ai.models.generateContent({
model: 'gemini-3.8-flash',
contents: `Evaluate the business impact and time sensitivity of this support ticket description and classify its urgency:\n\n${description}`,
config: {
responseMimeType: 'text/x.enum',
responseSchema: {
type: Type.STRING,
enum: ['High', 'Normal'],
},
},
});
const candidate = (response.text || '').trim();
if (candidate === 'High' || candidate === 'Normal') {
urgencyLevel = candidate;
}
} catch (err) {
console.error('Gemini fallback to keyword matching:', err.message);
}
res.status(200).json({
hostAppAction: {
workflowAction: {
returnOutputVariablesAction: {
variables: {
urgencyLevel: {
stringValues: [urgencyLevel],
},
},
},
},
},
});
}
EOF
portal.js – Unterstützung für die Quick Portal-Benutzeroberfläche und den triggers.fire-Dispatcher
Erstellen Sie portal.js, um das Webportal bereitzustellen und Ticketanfragen an Google Workspace Studio zu senden:
renderPortal(GET /): Fragt die Firestore-Sammlungstudio_triggersab, um die Anzahl der registrierten aktiven Google Workspace Studio-Trigger anzuzeigen, und stellt das HTML-Formular für die Ticketübermittlung bereit.submitTicket(POST /api/submit-ticket): Durchläuft alle aktiven Triggerdokumente instudio_triggers, ruft den Google Workspace Studio-Endpunkttriggers.fire(https://workspacestudio.googleapis.com/v1/triggers/{triggerId}:fire) mit den AusgabevariablenticketTitleundticketDescriptionsowie einer eindeutigenrequestIdauf und speichert das Ticket in der Firestore-Sammlungsupport_tickets.
cat << 'EOF' > portal.js
import { triggersCollection, ticketsCollection } from './firestore.js';
// Support Quick Portal UI
export async function renderPortal(req, res) {
let activeCount = 0;
try {
const snapshot = await triggersCollection.get();
activeCount = snapshot.size;
} catch (err) {
console.error('Error reading studio_triggers collection:', err.message);
}
res.status(200).send(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Support Quick Portal</title>
<style>
body { font-family: Arial, sans-serif; padding: 24px; max-width: 540px; margin: auto; color: #202124; }
.badge { background: #e8f0fe; color: #1967d2; padding: 8px 12px; border-radius: 6px; font-size: 14px; margin-bottom: 16px; }
label { font-weight: bold; display: block; margin-top: 16px; }
input, textarea { width: 100%; margin-top: 6px; padding: 10px; box-sizing: border-box; border: 1px solid #dadce0; border-radius: 4px; }
button { background-color: #1a73e8; color: white; border: none; padding: 10px 18px; margin-top: 16px; font-weight: bold; cursor: pointer; border-radius: 4px; }
button:hover { background-color: #1557b0; }
#status { margin-top: 16px; font-weight: bold; }
</style>
</head>
<body>
<h2>Support Quick Portal</h2>
<div class="badge">
Active Google Workspace Studio triggers in Firestore (<code>studio_triggers</code>):
<strong id="trigger-count">${activeCount}</strong>
</div>
<p>Submit a support ticket below to fire your Google Workspace Studio flow.</p>
<label for="title">Ticket Title</label>
<input type="text" id="title" placeholder="e.g. Database failure">
<label for="description">Issue Description</label>
<textarea id="description" rows="4" placeholder="Describe the issue..."></textarea>
<button onclick="submitTicket()">Submit Ticket</button>
<div id="status"></div>
<script>
async function submitTicket() {
const title = document.getElementById('title').value.trim();
const description = document.getElementById('description').value.trim();
const statusEl = document.getElementById('status');
if (!title || !description) {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Please fill out both fields.';
return;
}
statusEl.style.color = '#188038';
statusEl.textContent = 'Submitting ticket...';
try {
const res = await fetch('/api/submit-ticket', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, description }),
});
const data = await res.json();
if (data.ok) {
statusEl.textContent =
'Ticket saved to Firestore! Fired ' + data.triggersFired + ' Google Workspace Studio trigger(s).';
} else {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Error: ' + (data.error || 'Unknown error');
}
} catch (err) {
statusEl.style.color = '#d93025';
statusEl.textContent = 'Request failed: ' + err.message;
}
}
</script>
</body>
</html>`);
}
// Portal Form Submission -> Fire Active Google Workspace Studio Triggers
export async function submitTicket(req, res) {
const title = req.body?.title || 'Untitled Ticket';
const description = req.body?.description || '';
const results = [];
try {
const snapshot = await triggersCollection.get();
for (const doc of snapshot.docs) {
const trigger = doc.data();
if (!trigger.triggerId || !trigger.userOAuthToken) continue;
const response = await fetch(
`https://workspacestudio.googleapis.com/v1/triggers/${encodeURIComponent(trigger.triggerId)}:fire`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${trigger.userOAuthToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'triggers/' + trigger.triggerId,
outputs: {
ticketTitle: { stringValues: [title] },
ticketDescription: { stringValues: [description] },
},
requestId:
'req_' + Date.now() + '_' + Math.floor(Math.random() * 1000),
}),
}
);
results.push({ triggerId: trigger.triggerId, status: response.status });
}
await ticketsCollection.add({
title,
description,
triggersFired: results.length,
createdAt: new Date().toISOString(),
});
res.status(200).json({ ok: true, triggersFired: results.length, results });
} catch (err) {
console.error('Error in /api/submit-ticket:', err.message);
res.status(500).json({ ok: false, error: err.message });
}
}
EOF
index.js – Express-Server-Einstiegspunkt
Erstellen Sie index.js, um Ihre Portalrouten und Google Workspace Studio-Webhook-Endpunkte in einem Express-HTTP-Server zu verbinden, der an PORT (Standard 8080 in Cloud Run) lauscht:
cat << 'EOF' > index.js
import express from 'express';
import { onConfigTrigger, onManageTrigger } from './starter.js';
import { onConfigUrgency, onExecuteUrgency } from './action.js';
import { renderPortal, submitTicket } from './portal.js';
const app = express();
app.use(express.json());
// Support Quick Portal routes
app.get('/', renderPortal);
app.post('/api/submit-ticket', submitTicket);
// Google Workspace Studio Custom Starter Step webhooks
app.post('/onConfigTrigger', onConfigTrigger);
app.post('/onManageTrigger', onManageTrigger);
// Google Workspace Studio Custom Action Step webhooks
app.post('/onConfigUrgency', onConfigUrgency);
app.post('/onExecuteUrgency', onExecuteUrgency);
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Support Extension listening on port ${PORT}`);
});
EOF
4. In Cloud Run bereitstellen und Add-on installieren
In diesem Schritt stellen Sie den Node.js-Dienst in Cloud Run bereit, erteilen IAM-Berechtigungen für den Aufrufer von Google Workspace-Add-ons sowie für den Firestore- und Agent Platform-Laufzeitzugriff, generieren das deployment.json-Manifest und installieren die Add-on-Bereitstellung.
- Stellen Sie den
support-extension-Dienst mit Ihren Umgebungsvariablen für Projekt und Firestore-Sammlung in Cloud Run bereit:gcloud run deploy support-extension \ --source . \ --region us-central1 \ --allow-unauthenticated \ --set-env-vars="GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project),FIRESTORE_TRIGGERS_COLLECTION=studio_triggers,FIRESTORE_TICKETS_COLLECTION=support_tickets" \ --quiet - Erteilen Sie dem Google Workspace-Dienstkonto für Add-ons die Rolle
roles/run.invokerfür den Cloud Run-Dienst, damit Google Workspace Studio Ihre Webhook-Endpunkte aufrufen kann:ADDON_SA=$(gcloud workspace-add-ons get-authorization --format="value(serviceAccountEmail)") gcloud run services add-iam-policy-binding support-extension \ --region=us-central1 \ --member="serviceAccount:${ADDON_SA}" \ --role="roles/run.invoker" \ --quiet - Weisen Sie dem Cloud Run-Laufzeitdienstkonto
roles/datastore.user(zum Lesen und Schreiben der Firestore-Sammlungenstudio_triggersundsupport_tickets) undroles/aiplatform.user(zum Aufrufen von Gemini auf der Gemini Enterprise Agent Platform) zu:PROJECT_ID=$(gcloud config get-value project) PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)") RUNTIME_SA=$(gcloud run services describe support-extension --region=us-central1 --format="value(spec.template.spec.serviceAccountName)") RUNTIME_SA=${RUNTIME_SA:-"${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"} gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${RUNTIME_SA}" \ --role="roles/datastore.user" \ --condition=None \ --quiet gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${RUNTIME_SA}" \ --role="roles/aiplatform.user" \ --condition=None \ --quiet - Rufen Sie die bereitgestellte Cloud Run-URL ab und generieren Sie das
deployment.json-Manifest, in dem die ElementesupportTicketTrigger(workflowTrigger) undurgencyDetectorStep(workflowAction) definiert sind:SERVICE_URL=$(gcloud run services describe support-extension --region=us-central1 --format="value(status.url)") cat << EOF > deployment.json { "oauthScopes": [ "https://www.googleapis.com/auth/workspace.studio.trigger", "https://www.googleapis.com/auth/userinfo.email" ], "addOns": { "common": { "name": "Support Extension", "logoUrl": "https://www.gstatic.com/images/branding/productlogos/buganizer/v1/192px.svg" }, "studio": { "flows": { "workflowElements": [ { "id": "supportTicketTrigger", "state": "ACTIVE", "name": "New Support Ticket", "description": "Fires when someone submits a ticket in the Support Quick Portal.", "workflowTrigger": { "inputs": [], "outputs": [ { "id": "ticketTitle", "description": "Ticket Title", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } }, { "id": "ticketDescription", "description": "Ticket Description", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "onConfigFunction": "${SERVICE_URL}/onConfigTrigger", "onManageFunction": "${SERVICE_URL}/onManageTrigger" } }, { "id": "urgencyDetectorStep", "state": "ACTIVE", "name": "Detect Urgency", "description": "Evaluates the ticket description to detect High or Normal urgency.", "workflowAction": { "inputs": [ { "id": "ticketDescription", "description": "Description to scan", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "outputs": [ { "id": "urgencyLevel", "description": "Detected Urgency (High / Normal)", "cardinality": "SINGLE", "dataType": { "basicType": "STRING" } } ], "onConfigFunction": "${SERVICE_URL}/onConfigUrgency", "onExecuteFunction": "${SERVICE_URL}/onExecuteUrgency" } } ] } }, "httpOptions": { "authorizationHeader": "SYSTEM_ID_TOKEN" } } } EOF - Erstellen (oder ersetzen) und installieren Sie die Google Workspace-Add-on-Bereitstellung für Ihr Konto und drucken Sie die URL des Support Quick Portal:
gcloud workspace-add-ons deployments create support-extension --deployment-file=deployment.json || \ gcloud workspace-add-ons deployments replace support-extension --deployment-file=deployment.json gcloud workspace-add-ons deployments install support-extension echo "Support Quick Portal URL: ${SERVICE_URL}"
5. Benutzerdefinierte Schritte in Google Workspace Studio testen
- Öffnen Sie Google Workspace Studio (aktualisieren Sie den Browsertab, falls er bereits geöffnet war) und klicken Sie auf Neuer Flow.
- Klicken Sie auf Starter auswählen > Support-Erweiterung > Neues Support-Ticket.
- Klicken Sie auf Schritt hinzufügen (
+) > Support-Erweiterung > Dringlichkeit erkennen. Klicken Sie im Feld Quellbeschreibung auf + Variablen und wählen Sie Ticketbeschreibung aus. - Klicken Sie auf Schritt hinzufügen (
+) und fügen Sie den Schritt Chat > Mich in Google Chat benachrichtigen hinzu. Die Nachricht sollte die Variablen Ticket Title (Ticket-Titel), Urgency Level (Dringlichkeitsstufe) und Ticket Description (Ticketbeschreibung) enthalten. - Stellen Sie den Flow rechts oben auf Ein. Google Workspace Studio ruft sofort Ihren
/onManageTrigger-Endpunkt in Cloud Run auf, der das aktive Trigger-Abo in diestudio_triggers-Sammlung in Firestore schreibt. - Öffnen Sie die Support Quick Portal-URL (
https://support-extension-...run.app) in einem neuen Tab, bestätigen Sie, dass im Portal der aktive Trigger1in Firestore angezeigt wird, und senden Sie zwei Tickets, um die Klassifizierung von Gemini 3.8 Flash (gemini-3.8-flash) zu testen:- Ticket mit hoher Priorität (Titel des Tickets:
London office lockout, Beschreibung des Problems:All 500 employees in the London office are locked out of their workstations 20 minutes before the board presentation.): Auch ohne fest codierte Keywords wieurgentoderblockerstuftgemini-3.8-flashdieses Ticket alsHighein. - Routine-Ticket (Ticket Title:
Conference room adapters, Issue Description:Could we order two extra HDMI adapters for the third-floor conference room next month?):gemini-3.8-flashklassifiziert dieses Ticket alsNormal.
- Ticket mit hoher Priorität (Titel des Tickets:
- Prüfen Sie in Google Chat und auf dem Tab Aktivität in Google Workspace Studio, ob Ihr Flow für beide Tickets mit
Urgency Level: HighundUrgency Level: Normalausgeführt wurde.
6. Bereinigen
So vermeiden Sie, dass Ihrem Google Cloud-Konto laufende Gebühren in Rechnung gestellt werden:
gcloud workspace-add-ons deployments uninstall support-extension
gcloud workspace-add-ons deployments delete support-extension --quiet
gcloud run services delete support-extension --region=us-central1 --quiet
gcloud firestore databases delete --database="(default)" --quiet
7. Glückwunsch!
Sie haben eine Node.js-HTTP-Erweiterung für Google Workspace Studio mit Firestore, Cloud Run und Gemini 3.8 Flash auf der Gemini Enterprise Agent Platform erstellt, bereitgestellt und getestet.
Behandelte Themen
- Konfiguration eines Google Workspace Studio-HTTP-Add-on-Manifests (
deployment.json) mitworkflowTrigger- undworkflowAction-Elementen. - Google Workspace Studio-Abos
workflowTriggerin derstudio_triggers-Sammlung Firestore beibehalten und Portaleinsendungen insupport_ticketsprotokollieren, damit Trigger Cloud Run-Skalierungen und ‑Neubereitstellungen überstehen. - Erstellen eines
workflowAction-Schritts, der Support-Tickets mit Gemini 3.8 Flash (gemini-3.8-flash) mit strukturierter Ausgabe auf der Gemini Enterprise Agent Platform klassifiziert, mit einem robusten Fallback für den Keyword-Abgleich.