1. Pengantar
Google Workspace Studio memungkinkan Anda mengotomatiskan proses bisnis di seluruh aplikasi Google Workspace seperti Gmail, Google Chat, Google Drive, dan Google Spreadsheet. Jika alur kerja Anda perlu dimulai dari aplikasi web eksternal atau menjalankan logika kustom di lingkungan cloud Anda sendiri, Anda dapat memperluas Google Workspace Studio dengan Add-on Google Workspace HTTP di Node.js di Cloud Run:
- Langkah awal kustom (
workflowTrigger): Memulai alur Google Workspace Studio saat peristiwa eksternal terjadi—seperti pelanggan yang mengirimkan tiket di portal web internal—dengan memanggiltriggers.fireREST API Google Workspace Studio. - Langkah tindakan kustom (
workflowAction): Menerima variabel dari langkah-langkah sebelumnya dalam alur, menjalankan logika kustom atau inferensi AI di layanan Node.js Anda, dan menampilkan variabel output kembali ke Google Workspace Studio.
Dalam codelab ini, Anda akan membangun dan men-deploy ekstensi HTTP Node.js lengkap untuk Google Workspace Studio di Cloud Run, menggunakan Cloud Firestore untuk mempertahankan langganan pemicu alur aktif dan tiket yang dikirimkan di seluruh revisi penampung, serta mengklasifikasikan urgensi tiket di langkah tindakan kustom menggunakan Gemini 3.8 Flash (gemini-3.8-flash) di Gemini Enterprise Agent Platform dengan penggantian pencocokan kata kunci yang tangguh.
Yang akan Anda build
- Aplikasi web Support Quick Portal dan Add-on Google Workspace HTTP yang dibuat dengan Node.js, Express, dan Firestore di Cloud Run.
- Langkah awal kustom Tiket Dukungan Baru (
supportTicketTrigger) yang mempertahankan langganan alur aktif dalam koleksi Firestorestudio_triggers, mencatat tiket yang dikirimkan dalam koleksi Firestoresupport_tickets, dan diaktifkan setiap kali tiket dikirimkan di portal web—meneruskanticketTitledanticketDescriptionke alur Google Workspace Studio. - Langkah tindakan kustom Deteksi Keterdesakan (
urgencyDetectorStep) yang mengklasifikasikan urgensi tiket menggunakan Gemini 3.8 Flash (gemini-3.8-flash) di Gemini Enterprise Agent Platform (aiplatform.googleapis.com), dengan penggantian otomatis ke pencocokan kata kunci (urgent,blocker,critical).
Yang akan Anda pelajari
- Cara mengonfigurasi manifes deployment Add-on Google Workspace HTTP (
deployment.json) dengan elemenworkflowTriggerdanworkflowAction. - Cara mempertahankan langganan pemicu Google Workspace Studio (
triggerId,notifyUri, danuserOAuthToken) dalam koleksi Firestorestudio_triggersdan memicu alur menggunakan REST APItriggers.fire. - Cara membuat langkah kustom
workflowActiondi Node.js menggunakan output terstruktur Gemini 3.8 Flash (gemini-3.8-flash) di Gemini Enterprise Agent Platform dengan penggantian kata kunci.
Prasyarat
- Akun Google Workspace dengan akses ke Google Workspace Studio.
- Project Google Cloud dengan penagihan diaktifkan, dibuat dalam organisasi Google Workspace yang sama dengan akun pengguna Anda sehingga Anda dapat menginstal deployment add-on yang tidak dipublikasikan untuk pengujian.
2. Menyiapkan project Google Cloud dan Firestore
Pada langkah ini, Anda akan mengonfigurasi layar izin OAuth project, mengaktifkan Google Cloud dan Google Workspace API yang diperlukan di Cloud Shell, menyediakan database (default) Firestore, dan menginisialisasi akun layanan otorisasi add-on.
- Buka Konsol Google Cloud, pilih project Google Cloud Anda, lalu klik ikon Activate Cloud Shell di panel navigasi atas.
- Konfigurasi layar izin OAuth agar Google Workspace dapat menyediakan klien OAuth untuk add-on Anda:
- Buka halaman Branding Google Auth Platform.
- Jika diminta, klik Mulai. (Jika layar izin Anda sudah dikonfigurasi, lanjutkan ke langkah 3.)
- Di bagian App Information, masukkan
Support Extensionuntuk App name, pilih User support email Anda, lalu klik Next. - Di bagian Audience, pilih Internal, lalu klik Next.
- Di bagian Contact Information, masukkan alamat email Anda, lalu klik Next.
- Di bagian Selesai, setujui Google API Services: Kebijakan Data Pengguna, klik Continue, lalu klik Create.
- Di Cloud Shell, tetapkan project aktif Anda (ganti
YOUR_PROJECT_IDdengan project ID Google Cloud Anda) dan aktifkan API yang diperlukan: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 - Sediakan database Firestore
(default)dius-central1(jika belum ada) dan inisialisasi akun layanan Add-on Google Workspace Anda: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. Bangun aplikasi Node.js dengan Firestore dan Gemini 3.8 Flash
Pada langkah ini, Anda akan membangun aplikasi Node.js di ~/studio-support-addon. Untuk menjaga kode tetap modular dan mudah dibaca, Anda mengatur project ke dalam lima file terfokus:
firestore.js: Menginisialisasi klien Cloud Firestore (koleksistudio_triggersdansupport_tickets) serta memperbarui token OAuth yang di-cache.starter.js: Menerapkan webhook langkah awal kustom Tiket Dukungan Baru (/onConfigTriggerdan/onManageTrigger).action.js: Menerapkan webhook langkah tindakan kustom Deteksi Urgensi (/onConfigUrgencydan/onExecuteUrgency) menggunakan Gemini 3.8 Flash (gemini-3.8-flash) dengan penggantian pencocokan kata kunci.portal.js: Menayangkan UI web Support Quick Portal (GET /) dan memicu pemicu Google Workspace Studio yang aktif (POST /api/submit-ticket).index.js: Menghubungkan semua rute Express dan memulai server HTTP.
Lakukan inisialisasi project dan package.json
- Buat direktori project dan buka direktori tersebut:
mkdir -p ~/studio-support-addon && cd ~/studio-support-addon - Buat
package.jsondenganexpress,@google-cloud/firestore, dan@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 — Status Firestore bersama dan refresh token OAuth
Buat firestore.js untuk mengelola dua koleksi Firestore dan menjaga agar token OAuth pengguna yang di-cache tetap baru:
studio_triggers: Menyimpan langganan alur Google Workspace Studio yang aktif (triggerId,notifyUri, danuserOAuthToken) sehingga langganan tersebut tetap ada saat container Cloud Run dimulai ulang dan peristiwa penskalaan hingga nol.support_tickets: Menyimpan catatan setiap tiket dukungan yang dikirimkan melalui portal.refreshTokenInFirestore(req): Setiap kali Google Workspace Studio memanggil endpoint webhook Anda, endpoint tersebut akan menyertakanauthorizationEventObject.userOAuthTokenyang berumur pendek. Helper ini memperbarui dokumen pemicu aktif dengan token terbaru sehingga panggilantriggers.firedi latar belakang tetap diizinkan.
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 — Langkah Awal Kustom (workflowTrigger)
Buat starter.js untuk menerapkan dua endpoint webhook yang diperlukan oleh langkah awal kustom Google Workspace Studio:
onConfigTrigger(POST /onConfigTrigger): Dipanggil saat pengguna memilih Tiket Dukungan Baru sebagai titik awal alur mereka di Google Workspace Studio. Menampilkan tindakan navigasipushCardyang mendeskripsikan starter.onManageTrigger(POST /onManageTrigger): Dipanggil saat pengguna mengaktifkan alur Aktif (req.body.workflow.triggerCreation) atau menonaktifkannya / menghapusnya (req.body.workflow.triggerDeletion). Menyimpan atau menghapus dokumen langganan di koleksi Firestorestudio_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 — Langkah Tindakan Kustom (workflowAction) dengan Gemini 3.8 Flash
Buat action.js untuk menerapkan dua endpoint webhook yang diperlukan oleh langkah tindakan kustom Google Workspace Studio:
onConfigUrgency(POST /onConfigUrgency): Menampilkan kartu konfigurasi dengan widgettextInputyang menetapkanhostAppDataSource.workflowDataSource.includeVariables: true, sehingga pengguna dapat memilih variabelticketDescriptionyang dihasilkan oleh langkah awal.onExecuteUrgency(POST /onExecuteUrgency): Membaca inputticketDescriptiondarireq.body.workflow.actionInvocation.inputs, mengklasifikasikan dampak bisnis dan urgensinya menggunakan Gemini 3.8 Flash (gemini-3.8-flash) di Gemini Enterprise Agent Platform dengan output terstruktur (enumresponseSchema["High", "Normal"]), melakukan penggantian kedetectKeywordUrgency()(urgent,blocker,critical) jika panggilan model gagal, dan menampilkan variabel outputurgencyLevelmenggunakanhostAppAction.workflowAction.returnOutputVariablesAction.
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 — Mendukung UI Quick Portal dan pengirim triggers.fire
Buat portal.js untuk menayangkan portal web dan mengirimkan pengajuan tiket ke Google Workspace Studio:
renderPortal(GET /): Mengirim kueri ke koleksi Firestorestudio_triggersuntuk menampilkan jumlah pemicu Google Workspace Studio aktif yang terdaftar, dan menyajikan formulir pengiriman tiket HTML.submitTicket(POST /api/submit-ticket): Melakukan iterasi melalui semua dokumen pemicu aktif distudio_triggers, memanggil endpointtriggers.fireGoogle Workspace Studio (https://workspacestudio.googleapis.com/v1/triggers/{triggerId}:fire) dengan variabel outputticketTitledanticketDescriptionsertarequestIdunik, lalu menyimpan tiket ke koleksisupport_ticketsFirestore.
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 — Titik entri server Express
Buat index.js untuk menghubungkan rute portal dan endpoint webhook Google Workspace Studio menjadi server HTTP Express yang memproses PORT (default 8080 di Cloud Run):
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. Men-deploy ke Cloud Run dan menginstal add-on
Pada langkah ini, Anda akan men-deploy layanan Node.js ke Cloud Run, memberikan izin IAM untuk pemanggil Add-on Google Workspace dan akses runtime Firestore dan Agent Platform, membuat manifes deployment.json, serta menginstal deployment add-on.
- Deploy layanan
support-extensionke Cloud Run dengan variabel lingkungan project dan koleksi Firestore Anda: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 - Beri
roles/run.invokerpada layanan Cloud Run ke akun layanan Add-on Google Workspace agar Google Workspace Studio dapat memanggil endpoint webhook Anda: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 - Berikan
roles/datastore.user(untuk membaca dan menulis koleksi Firestorestudio_triggersdansupport_tickets) sertaroles/aiplatform.user(untuk memanggil Gemini di Gemini Enterprise Agent Platform) ke akun layanan runtime Cloud Run: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 - Ambil URL Cloud Run yang di-deploy dan buat manifes
deployment.jsonyang menentukan elemensupportTicketTrigger(workflowTrigger) danurgencyDetectorStep(workflowAction):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 - Buat (atau ganti) dan instal deployment Add-on Google Workspace untuk akun Anda, lalu cetak URL Portal Cepat Dukungan Anda:
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. Menguji langkah kustom Anda di Google Workspace Studio
- Buka Google Workspace Studio (muat ulang tab browser jika sudah terbuka) lalu klik Alur Baru.
- Klik Pilih starter > Support Extension > Tiket Dukungan Baru.
- Klik Tambahkan langkah (
+) > Ekstensi Dukungan > Deteksi Urgensi. Di kolom Deskripsi Sumber, klik + Variabel, lalu pilih Deskripsi Tiket. - Klik Tambahkan langkah (
+), lalu tambahkan langkah Chat > Beri tahu saya di Chat yang menyertakan variabel Judul Tiket, Tingkat Mendesak, dan Deskripsi Tiket dalam pesan. - Aktifkan alur On di pojok kanan atas. Google Workspace Studio akan segera memanggil endpoint
/onManageTriggerAnda di Cloud Run, yang menulis langganan pemicu aktif ke koleksistudio_triggersdi Firestore. - Buka URL Support Quick Portal (
https://support-extension-...run.app) di tab baru, pastikan portal menampilkan1pemicu aktif di Firestore, dan kirim dua tiket untuk menguji klasifikasi Gemini 3.8 Flash (gemini-3.8-flash):- Tiket berdampak tinggi (Judul Tiket:
London office lockout, Deskripsi Masalah:All 500 employees in the London office are locked out of their workstations 20 minutes before the board presentation.): Meskipun tanpa kata kunci yang dikodekan secara permanen sepertiurgentataublocker,gemini-3.8-flashmengklasifikasikan tiket ini sebagai mendesakHigh. - Tiket rutin (Judul Tiket:
Conference room adapters, Deskripsi Masalah:Could we order two extra HDMI adapters for the third-floor conference room next month?):gemini-3.8-flashmengklasifikasikan tiket ini sebagai urgensiNormal.
- Tiket berdampak tinggi (Judul Tiket:
- Verifikasi di Google Chat dan di tab Aktivitas Google Workspace Studio bahwa alur Anda berjalan untuk kedua tiket dengan
Urgency Level: HighdanUrgency Level: Normal.
6. Pembersihan
Agar tidak menimbulkan biaya berkelanjutan pada akun Google Cloud Anda, hapus resource yang di-deploy di Cloud Shell:
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. Selamat!
Anda telah membuat, men-deploy, dan menguji ekstensi HTTP Node.js untuk Google Workspace Studio menggunakan Firestore, Cloud Run, dan Gemini 3.8 Flash di Gemini Enterprise Agent Platform.
Yang telah kita bahas
- Mengonfigurasi manifes Add-on HTTP Google Workspace Studio (
deployment.json) dengan elemenworkflowTriggerdanworkflowAction. - Mempertahankan langganan Google Workspace Studio
workflowTriggerdi koleksistudio_triggersFirestore dan mengirimkan log pengiriman portal disupport_ticketssehingga pemicu tetap ada saat penskalaan dan deployment ulang Cloud Run. - Membangun langkah
workflowActionyang mengklasifikasikan tiket dukungan dengan output terstruktur Gemini 3.8 Flash (gemini-3.8-flash) di Gemini Enterprise Agent Platform, dengan penggantian pencocokan kata kunci yang tangguh.