Skip to content

About

Terraform module: terraform-google-dialogflow-cx-intent

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

☁️ Google Cloud Dialogflow CX Intent Terraform Module

Provisions a Dialogflow CX intent (google_dialogflow_cx_intent) — training phrases, parameter annotations, priority, and default-intent flags — targeting hashicorp/google ~> 7.0 on Terraform >= 1.12.0.

Terraform Provider Module Version Module Type Resource Count Posture


🧩 Overview

  • 🎯 Manages one Dialogflow CX intent (google_dialogflow_cx_intent) — the natural-language matching unit that maps end-user utterances to a named intent within an agent.
  • 🗣️ training_phrases (with nested parts) and parameters are both provider nesting_mode = "list" blocks rendered inline via dynamic — no separate child resources.
  • 🏷️ The only Dialogflow CX resource confirmed in this batch to carry labels / effective_labels / terraform_labels — every sibling module confirmed absent.
  • 🧯 deletion_policy defaults to "PREVENT" — a house extension over the provider's own "DELETE" default.
  • ⚠️ is_default_negative_intent / is_default_welcome_intent are exclusivity-sensitive across module instances — Terraform cannot catch two intents on the same agent both claiming the flag.

💡 Why it matters: Intents are the primary decision surface for how a Dialogflow CX agent interprets member requests — priority, fallback wiring, and parameter annotation directly shape which conversational path a member's utterance takes. Route changes to production intent priority/fallback behavior through the team owning the member-support conversational design before applying.


❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


🗺️ Where this fits

graph LR
 INTENT["🎯 terraform-google-dialogflow-cx-intent<br/>(this module)"] -->|parent = agent id| AGENT["🤖 terraform-google-dialogflow-cx-agent"]
 ENTITY["🏷️ terraform-google-dialogflow-cx-entity-type<br/>(developer entity types)"] -.->|entity_type id| INTENT
 INTENT -.->|intent id, by name| PAGE["📄 terraform-google-dialogflow-cx-page / -flow<br/>(intent routing)"]

 style INTENT fill:#4285F4,color:#fff
 style AGENT fill:#174EA6,color:#fff
 style ENTITY fill:#e8eaed,color:#3c4043
 style PAGE fill:#e8eaed,color:#3c4043
Loading

🧬 What this builds

graph TD
 P["parent, display_name"] --> R["google_dialogflow_cx_intent.this"]
 T["training_phrases map"] -.dynamic.-> R
 PM["parameters map"] -.dynamic.-> R
 L["labels"] --> R
 R --> O1["id"]
 R --> O2["name"]
 R --> O3["terraform_labels"]
 R --> O4["effective_labels"]

 style R fill:#4285F4,color:#fff
Loading
  • One resource: google_dialogflow_cx_intent.this. No child collection — training_phrases and parameters are nested blocks on the same resource.

✅ Provider / Versions

Component Constraint
Terraform >= 1.12.0
hashicorp/google ~> 7.0
Provider block None — the caller configures google

Schema notes that bite:

  • parent is schema-Optional (omittable on import) but this module makes it a required variable — every intent belongs to exactly one agent.
  • is_default_negative_intent/is_default_welcome_intent are confirmed plain optional booleans (not computed) — genuinely caller-settable, but the schema itself warns that more than one intent per agent with the same flag true causes the resources to compete for a single GCP resource.
  • is_fallback is effectively superseded by is_default_negative_intent per confirmed schema text — see Architecture Notes.
  • labels allows international/unicase letters and digits, -, and _, with a reserved sys- prefix (only sys-head/sys-contextual permitted) — enforced via validation, though the 128-byte-per-value cap is only proxied by a 63-character check (Terraform's length counts characters, not UTF-8 bytes).
  • training_phrases[*].parts requires at least 1 item (confirmed schema min_items: 1).
  • No self_link attribute — confirmed absent.

🔑 Required IAM Roles

  • roles/dialogflow.admin (or a narrower Dialogflow configuration role) on the target project.

☁️ GCP Prerequisites

  • dialogflow.googleapis.com enabled.
  • The consuming agent must already exist; any language_code supplied here must already be enabled on that agent.
  • Developer entity types referenced by parameters[*].entity_type must already exist in the same agent.

📁 Module Structure

terraform-google-dialogflow-cx-intent/
├── providers.tf
├── variables.tf
├── main.tf
├── outputs.tf
├── README.md
├── SCOPE.md
└── examples/basic/

⚙️ Quick Start

module "cx_intent" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "account.balance.inquiry"

  training_phrases = {
    balance_check = {
      parts = [{ text = "What is my account balance?" }]
    }
  }
}

🔌 Cross-Module Contract

Consumes

Input Type Source module
parent string, required terraform-google-dialogflow-cx-agent (.id)
parameters[*].entity_type string, required per entry Caller literal (system entity type) or terraform-google-dialogflow-cx-entity-type (.id)

Emits

Output Description Consumed by
id Terraform-internal id None in this batch
name Resource name (identical format to id) None in this batch
terraform_labels Labels this module manages plus provider defaults None in this batch
effective_labels Full label set GCP reports None in this batch

📚 Example Library

1 · Minimal — smallest valid call
module "cx_intent_minimal" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "minimal.intent"
}

💡 No training phrases, no parameters — a valid but practically unmatched intent shell.

2 · Single training phrase
module "cx_intent_single_phrase" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "account.balance.inquiry"

  training_phrases = {
    balance_check = {
      parts = [{ text = "What is my account balance?" }]
    }
  }
}
3 · Multiple training phrases
module "cx_intent_multi_phrase" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "loan.payment.due_date"

  training_phrases = {
    phrase_1 = { parts = [{ text = "When is my next loan payment due?" }] }
    phrase_2 = { parts = [{ text = "What date is my payment due?" }] }
    phrase_3 = { parts = [{ text = "Tell me my next due date." }], repeat_count = 2 }
  }
}

ℹ️ repeat_count reflects how many times an example was added to the intent — the map key is an arbitrary caller-chosen string since training_phrases[*].id is computed-only.

4 · Training phrase annotated with a system entity type
module "cx_intent_system_entity" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "statement.request.by_date"

  parameters = {
    statement_date = {
      entity_type = "projects/-/locations/-/agents/-/entityTypes/sys.date"
    }
  }

  training_phrases = {
    phrase_1 = {
      parts = [
        { text = "Send me my statement for " },
        { text = "last March", parameter_id = "statement_date" },
      ]
    }
  }
}

💡 System entity types use the wildcard projects/-/locations/-/agents/-/entityTypes/sys.<Name> form — no project/location/agent substitution needed.

5 · Training phrase annotated with a developer entity type (is_list + redact)
module "cx_intent_developer_entity" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "member.pin.verification"

  parameters = {
    account_pin = {
      entity_type = module.cx_entity_type_pin.id
      is_list     = false
      redact      = true
    }
  }

  training_phrases = {
    phrase_1 = {
      parts = [
        { text = "My PIN is " },
        { text = "1234", parameter_id = "account_pin" },
      ]
    }
  }
}

🔒 redact = true replaces the parameter content with the parameter name during logging — recommended for anything resembling a PIN, account number, or other sensitive fragment.

6 · Priority tuning — high-priority intent
module "cx_intent_high_priority" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "fraud.report.urgent"
  priority     = 900000

  training_phrases = {
    phrase_1 = { parts = [{ text = "I think someone stole my card." }] }
  }
}
7 · Negative priority — intent excluded from runtime matching
module "cx_intent_disabled" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "legacy.retired_flow"
  priority     = -1

  training_phrases = {
    phrase_1 = { parts = [{ text = "some retired phrasing" }] }
  }
}

⚠️ Confirmed schema text: a negative priority means "the intent is ignored in runtime detect intent requests" — the intent still exists and can be trained/tested, but never matches live traffic. Useful for staging a retirement without a destructive delete.

8 · Non-default language code
module "cx_intent_spanish" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent        = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name  = "account.balance.inquiry.es"
  language_code = "es"

  training_phrases = {
    phrase_1 = { parts = [{ text = "¿Cuál es el saldo de mi cuenta?" }] }
  }
}

ℹ️ es must already be enabled as a supported language on the consuming agent — an API-level rejection at apply time, not caught by terraform validate.

9 · Labels applied
module "cx_intent_labeled" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "account.balance.inquiry"

  labels = {
    environment = "prod"
    team        = "member-support"
    sys-head    = ""
  }

  training_phrases = {
    phrase_1 = { parts = [{ text = "What is my account balance?" }] }
  }
}

🏷️ sys-head is one of the two Dialogflow-reserved label keys (the other is sys-contextual) and is deliberately allowed an empty value — confirmed schema text: "The above labels do not require value."

10 · Reserved label prefix — documented failure mode
# FAILS terraform plan — cross-field validation rejects an unrecognized "sys-" key.
module "cx_intent_bad_label" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "invalid-label-demo"

  labels = {
    sys-custom = "not-allowed"
  }
}

⚠️ Demonstrates the plan-time guard — only sys-head and sys-contextual are permitted with the sys- prefix (confirmed schema text); this never reaches the API.

11 · Default Welcome Intent
module "cx_intent_welcome" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent                    = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name              = "Default Welcome Intent"
  is_default_welcome_intent = true

  training_phrases = {
    phrase_1 = { parts = [{ text = "hi" }] }
    phrase_2 = { parts = [{ text = "hello" }] }
  }
}

⚠️ Ensure at most ONE terraform-google-dialogflow-cx-intent instance per agent sets is_default_welcome_intent = true — Terraform cannot detect a second instance elsewhere in the composition claiming the same flag.

12 · Default Negative Intent (fallback management)
module "cx_intent_negative" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent                     = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name               = "Default Negative Intent"
  is_default_negative_intent = true

  training_phrases = {
    phrase_1 = { parts = [{ text = "asdkjfh nonsense input" }] }
  }
}

💡 Confirmed schema text: the supported way to manage the agent's fallback intent is is_default_negative_intent = true, not is_fallback directly.

13 · Custom deletion policy — allow delete in dev
module "cx_intent_dev" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent          = "projects/casey-dev-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name    = "dev.scratch.intent"
  deletion_policy = "DELETE"

  training_phrases = {
    phrase_1 = { parts = [{ text = "test phrase" }] }
  }
}
14 · Explicit timeouts
module "cx_intent_timeouts" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000"
  display_name = "custom-timeouts-demo"

  timeouts = {
    create = "10m"
    update = "10m"
    delete = "10m"
  }

  training_phrases = {
    phrase_1 = { parts = [{ text = "example phrase" }] }
  }
}
15 · 🏗️ End-to-end composition
module "cx_agent" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-agent.git?ref=v1.0.0"

  display_name          = "Member Support Agent"
  location              = "us-central1"
  default_language_code = "en"
  time_zone             = "America/Chicago"
}

module "cx_intent_balance_inquiry" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent       = module.cx_agent.id
  display_name = "account.balance.inquiry"
  priority     = 750000

  labels = {
    team = "member-support"
  }

  parameters = {
    account_type = {
      entity_type = "projects/-/locations/-/agents/-/entityTypes/sys.any"
    }
  }

  training_phrases = {
    phrase_1 = {
      parts = [
        { text = "What is my " },
        { text = "checking", parameter_id = "account_type" },
        { text = " account balance?" },
      ]
    }
    phrase_2 = { parts = [{ text = "How much money do I have?" }] }
  }
}

module "cx_intent_welcome" {
  source = "git::https://github.com/microsoftexpert/terraform-google-dialogflow-cx-intent.git?ref=v1.0.0"

  parent                    = module.cx_agent.id
  display_name              = "Default Welcome Intent"
  is_default_welcome_intent = true

  training_phrases = {
    phrase_1 = { parts = [{ text = "hi" }] }
    phrase_2 = { parts = [{ text = "hello" }] }
  }
}

📥 Inputs

Variable Type Default Notes
parent string — required Sourced from terraform-google-dialogflow-cx-agent's id
display_name string — required Unique within the agent
description string null Max 140 characters
language_code string null Must already be enabled on the agent
priority number null Negative excludes from runtime matching
is_default_negative_intent bool null Exclusivity-sensitive across module instances
is_default_welcome_intent bool null Exclusivity-sensitive across module instances
is_fallback bool null Superseded by is_default_negative_intent per schema text
deletion_policy string "PREVENT" House extension; "DELETE" | "ABANDON" | "PREVENT"
parameters map(object(...)) {} Keyed by the parameter's own id
training_phrases map(object(...)) {} Keyed by an arbitrary caller-chosen string
labels map(string) {} sys- prefix reserved except sys-head/sys-contextual
timeouts object({ create, update, delete }) null
Full object schemas
variable "parameters" {
  type = map(object({
    entity_type = string
    is_list     = optional(bool)
    redact      = optional(bool)
  }))
  default = {}
}

variable "training_phrases" {
  type = map(object({
    repeat_count = optional(number)
    parts = list(object({
      text         = string
      parameter_id = optional(string)
    }))
  }))
  default = {}
}

🧾 Outputs

Output Description
id Terraform-internal id (primary output)
name Resource name (identical format to id)
terraform_labels Labels this module manages plus provider-level default labels
effective_labels Full label set GCP reports, including labels applied outside Terraform

No self_link — confirmed absent.


🧠 Architecture Notes

  • parameters and training_phrases are nested blocks on the single this resource, not separate child resources — the for_each-over-a-keyed-map convention is followed for readable diffs, not to avoid resource re-indexing (there is none to avoid here).
  • parameters reuses its own required id field as the map key since that value is the exact string training_phrases[*].parts[*].parameter_id must match to annotate a training phrase.
  • is_default_negative_intent/is_default_welcome_intent are confirmed genuine caller-settable booleans (not computed), but only one google_dialogflow_cx_intent per agent should set each to true — a cross-module-instance constraint Terraform's type system and validation {} blocks cannot express (they only see one instance's inputs at a time).
  • is_fallback is documented by the provider as effectively superseded by is_default_negative_intent — both are exposed here since the schema marks both plain optional booleans, but new compositions should prefer is_default_negative_intent.
  • labels character-set validation permits Unicode letters (\p{L}) per confirmed schema text ("International characters are allowed, including letters from unicase alphabets") — this is deliberately looser than a pure-ASCII lowercase regex some other GCP resources' labels use.

🧱 Design Principles

Concern Secure default Opt-out
Deletion protection deletion_policy = "PREVENT" Caller sets "DELETE" or "ABANDON"
Sensitive parameter logging redact left to caller per parameter (no house-wide default — provider default is false) Caller sets redact = true per parameter
Reserved label keys sys- prefix rejected unless it is exactly sys-head/sys-contextual N/A — provider-reserved values, not a caller opt-out

🚀 Runbook

terraform init -backend=false
terraform validate
terraform fmt -check

Pin ?ref=v1.0.0 — never a branch. Plan-only; a human applies from CI.


🧪 Testing

validate/fmt -check confirm structural correctness only, given the caller has valid ADC/WIF credentials configured for any downstream plan. They cannot catch: language_code not enabled on the agent, a developer entity_type that doesn't exist, or a second intent on the same agent also claiming is_default_welcome_intent/is_default_negative_intent — all of these fail only at apply time against a real project.


💬 Example Output

$ terraform output
id = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000/intents/a1b2c3d4-0000-1111-2222-333344445555"
name = "projects/casey-prod-networking/locations/us-central1/agents/00000000-0000-0000-0000-000000000000/intents/a1b2c3d4-0000-1111-2222-333344445555"
terraform_labels = {
 "team" = "member-support"
}
effective_labels = {
 "team" = "member-support"
}

🔍 Troubleshooting

Symptom Cause Fix
apply fails with a language error language_code not enabled on the consuming agent Enable the language on the agent first, or omit to use the agent's default
apply fails resolving entity_type Developer entity type doesn't exist yet, or wrong agent Create the entity type first, in the same agent
Two intents both claim the welcome/negative flag Multiple terraform-google-dialogflow-cx-intent instances set the same is_default_* flag true Set the flag on exactly one instance per agent
plan rejects a labels key Key uses the reserved sys- prefix but isn't sys-head/sys-contextual Rename the key, or use the two permitted reserved keys
plan rejects training_phrases entry A parts list is empty Supply at least one parts entry per training phrase

🔗 Related Docs

About

Terraform module: terraform-google-dialogflow-cx-intent

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages