Configure Google Cloud Dialogflow CX Tools

The gcp:diagflow/cxTool:CxTool resource, part of the Pulumi Google Cloud provider, defines tools that extend Dialogflow CX agent capabilities by connecting to external APIs, data stores, custom functions, or Google Cloud services. This guide focuses on four capabilities: client-side function definitions, Discovery Engine data store integration, external API calls via OpenAPI, and BigQuery operations through Integration Connectors.

Tools belong to Dialogflow CX agents and may reference Discovery Engine data stores, Integration Connector connections, BigQuery resources, or external OAuth endpoints. The examples are intentionally small. Combine them with your own agent configuration, authentication setup, and data infrastructure.

Define client-side functions with input and output schemas

Conversational agents often need to invoke custom logic that runs on the client side, such as echoing messages or performing calculations. Function tools define the contract between the agent and your application code.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const agent = new gcp.diagflow.CxAgent("agent", {
    displayName: "dialogflowcx-agent-fucntion",
    location: "global",
    defaultLanguageCode: "en",
    timeZone: "America/New_York",
    description: "Example description.",
});
const functionTool = new gcp.diagflow.CxTool("function_tool", {
    parent: agent.id,
    displayName: "Example Function Tool",
    description: "Example Description",
    functionSpec: {
        inputSchema: `      {
        \\"type\\": \\"object\\",
        \\"properties\\": {
          \\"message_to_echo\\": {
            \\"type\\": \\"string\\",
            \\"description\\": \\"The message that should be echoed back.\\"
          }
        },
        \\"required\\": [
          \\"message_to_echo\\"
        ]
      }
`,
        outputSchema: `      {
        \\"type\\": \\"object\\",
        \\"properties\\": {
          \\"echoed_message\\": {
            \\"type\\": \\"string\\",
            \\"description\\": \\"The message that is echoed back.\\"
          }
        }
      }
`,
    },
});
import pulumi
import pulumi_gcp as gcp

agent = gcp.diagflow.CxAgent("agent",
    display_name="dialogflowcx-agent-fucntion",
    location="global",
    default_language_code="en",
    time_zone="America/New_York",
    description="Example description.")
function_tool = gcp.diagflow.CxTool("function_tool",
    parent=agent.id,
    display_name="Example Function Tool",
    description="Example Description",
    function_spec={
        "input_schema": """      {
        \"type\": \"object\",
        \"properties\": {
          \"message_to_echo\": {
            \"type\": \"string\",
            \"description\": \"The message that should be echoed back.\"
          }
        },
        \"required\": [
          \"message_to_echo\"
        ]
      }
""",
        "output_schema": """      {
        \"type\": \"object\",
        \"properties\": {
          \"echoed_message\": {
            \"type\": \"string\",
            \"description\": \"The message that is echoed back.\"
          }
        }
      }
""",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/diagflow"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		agent, err := diagflow.NewCxAgent(ctx, "agent", &diagflow.CxAgentArgs{
			DisplayName:         pulumi.String("dialogflowcx-agent-fucntion"),
			Location:            pulumi.String("global"),
			DefaultLanguageCode: pulumi.String("en"),
			TimeZone:            pulumi.String("America/New_York"),
			Description:         pulumi.String("Example description."),
		})
		if err != nil {
			return err
		}
		_, err = diagflow.NewCxTool(ctx, "function_tool", &diagflow.CxToolArgs{
			Parent:      agent.ID(),
			DisplayName: pulumi.String("Example Function Tool"),
			Description: pulumi.String("Example Description"),
			FunctionSpec: &diagflow.CxToolFunctionSpecArgs{
				InputSchema: pulumi.String(`      {
        \"type\": \"object\",
        \"properties\": {
          \"message_to_echo\": {
            \"type\": \"string\",
            \"description\": \"The message that should be echoed back.\"
          }
        },
        \"required\": [
          \"message_to_echo\"
        ]
      }
`),
				OutputSchema: pulumi.String(`      {
        \"type\": \"object\",
        \"properties\": {
          \"echoed_message\": {
            \"type\": \"string\",
            \"description\": \"The message that is echoed back.\"
          }
        }
      }
`),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var agent = new Gcp.Diagflow.CxAgent("agent", new()
    {
        DisplayName = "dialogflowcx-agent-fucntion",
        Location = "global",
        DefaultLanguageCode = "en",
        TimeZone = "America/New_York",
        Description = "Example description.",
    });

    var functionTool = new Gcp.Diagflow.CxTool("function_tool", new()
    {
        Parent = agent.Id,
        DisplayName = "Example Function Tool",
        Description = "Example Description",
        FunctionSpec = new Gcp.Diagflow.Inputs.CxToolFunctionSpecArgs
        {
            InputSchema = @"      {
        \""type\"": \""object\"",
        \""properties\"": {
          \""message_to_echo\"": {
            \""type\"": \""string\"",
            \""description\"": \""The message that should be echoed back.\""
          }
        },
        \""required\"": [
          \""message_to_echo\""
        ]
      }
",
            OutputSchema = @"      {
        \""type\"": \""object\"",
        \""properties\"": {
          \""echoed_message\"": {
            \""type\"": \""string\"",
            \""description\"": \""The message that is echoed back.\""
          }
        }
      }
",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.diagflow.CxAgent;
import com.pulumi.gcp.diagflow.CxAgentArgs;
import com.pulumi.gcp.diagflow.CxTool;
import com.pulumi.gcp.diagflow.CxToolArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolFunctionSpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var agent = new CxAgent("agent", CxAgentArgs.builder()
            .displayName("dialogflowcx-agent-fucntion")
            .location("global")
            .defaultLanguageCode("en")
            .timeZone("America/New_York")
            .description("Example description.")
            .build());

        var functionTool = new CxTool("functionTool", CxToolArgs.builder()
            .parent(agent.id())
            .displayName("Example Function Tool")
            .description("Example Description")
            .functionSpec(CxToolFunctionSpecArgs.builder()
                .inputSchema("""
      {
        \"type\": \"object\",
        \"properties\": {
          \"message_to_echo\": {
            \"type\": \"string\",
            \"description\": \"The message that should be echoed back.\"
          }
        },
        \"required\": [
          \"message_to_echo\"
        ]
      }
                """)
                .outputSchema("""
      {
        \"type\": \"object\",
        \"properties\": {
          \"echoed_message\": {
            \"type\": \"string\",
            \"description\": \"The message that is echoed back.\"
          }
        }
      }
                """)
                .build())
            .build());

    }
}
resources:
  agent:
    type: gcp:diagflow:CxAgent
    properties:
      displayName: dialogflowcx-agent-fucntion
      location: global
      defaultLanguageCode: en
      timeZone: America/New_York
      description: Example description.
  functionTool:
    type: gcp:diagflow:CxTool
    name: function_tool
    properties:
      parent: ${agent.id}
      displayName: Example Function Tool
      description: Example Description
      functionSpec:
        inputSchema: |2
                {
                  \"type\": \"object\",
                  \"properties\": {
                    \"message_to_echo\": {
                      \"type\": \"string\",
                      \"description\": \"The message that should be echoed back.\"
                    }
                  },
                  \"required\": [
                    \"message_to_echo\"
                  ]
                }
        outputSchema: |2
                {
                  \"type\": \"object\",
                  \"properties\": {
                    \"echoed_message\": {
                      \"type\": \"string\",
                      \"description\": \"The message that is echoed back.\"
                    }
                  }
                }

The functionSpec property defines what parameters your function accepts and what it returns. The inputSchema describes required and optional parameters using JSON Schema format. The outputSchema defines the structure of the function’s response. Your client application receives these parameters at runtime and returns data matching the output schema.

Agents that need to answer questions from enterprise knowledge bases can connect to Discovery Engine data stores, enabling semantic search over documents and structured data.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const myDatastore = new gcp.discoveryengine.DataStore("my_datastore", {
    location: "global",
    dataStoreId: "datastore-tool",
    displayName: "datastore for Tool test",
    industryVertical: "GENERIC",
    contentConfig: "NO_CONTENT",
    solutionTypes: ["SOLUTION_TYPE_CHAT"],
});
const agent = new gcp.diagflow.CxAgent("agent", {
    displayName: "dialogflowcx-agent-data-store",
    location: "global",
    defaultLanguageCode: "en",
    timeZone: "America/New_York",
    description: "Example description.",
    deleteChatEngineOnDestroy: true,
}, {
    dependsOn: [myDatastore],
});
const project = gcp.organizations.getProject({});
const dataStoreTool = new gcp.diagflow.CxTool("data_store_tool", {
    parent: agent.id,
    displayName: "Example Data Store Tool",
    description: "Example Description",
    dataStoreSpec: {
        dataStoreConnections: [{
            dataStoreType: "UNSTRUCTURED",
            dataStore: pulumi.all([project, myDatastore.dataStoreId]).apply(([project, dataStoreId]) => `projects/${project.number}/locations/global/collections/default_collection/dataStores/${dataStoreId}`),
            documentProcessingMode: "DOCUMENTS",
        }],
        fallbackPrompt: {},
    },
}, {
    dependsOn: [
        myDatastore,
        agent,
    ],
});
import pulumi
import pulumi_gcp as gcp

my_datastore = gcp.discoveryengine.DataStore("my_datastore",
    location="global",
    data_store_id="datastore-tool",
    display_name="datastore for Tool test",
    industry_vertical="GENERIC",
    content_config="NO_CONTENT",
    solution_types=["SOLUTION_TYPE_CHAT"])
agent = gcp.diagflow.CxAgent("agent",
    display_name="dialogflowcx-agent-data-store",
    location="global",
    default_language_code="en",
    time_zone="America/New_York",
    description="Example description.",
    delete_chat_engine_on_destroy=True,
    opts = pulumi.ResourceOptions(depends_on=[my_datastore]))
project = gcp.organizations.get_project()
data_store_tool = gcp.diagflow.CxTool("data_store_tool",
    parent=agent.id,
    display_name="Example Data Store Tool",
    description="Example Description",
    data_store_spec={
        "data_store_connections": [{
            "data_store_type": "UNSTRUCTURED",
            "data_store": my_datastore.data_store_id.apply(lambda data_store_id: f"projects/{project.number}/locations/global/collections/default_collection/dataStores/{data_store_id}"),
            "document_processing_mode": "DOCUMENTS",
        }],
        "fallback_prompt": {},
    },
    opts = pulumi.ResourceOptions(depends_on=[
            my_datastore,
            agent,
        ]))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/diagflow"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/discoveryengine"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		myDatastore, err := discoveryengine.NewDataStore(ctx, "my_datastore", &discoveryengine.DataStoreArgs{
			Location:         pulumi.String("global"),
			DataStoreId:      pulumi.String("datastore-tool"),
			DisplayName:      pulumi.String("datastore for Tool test"),
			IndustryVertical: pulumi.String("GENERIC"),
			ContentConfig:    pulumi.String("NO_CONTENT"),
			SolutionTypes: pulumi.StringArray{
				pulumi.String("SOLUTION_TYPE_CHAT"),
			},
		})
		if err != nil {
			return err
		}
		agent, err := diagflow.NewCxAgent(ctx, "agent", &diagflow.CxAgentArgs{
			DisplayName:               pulumi.String("dialogflowcx-agent-data-store"),
			Location:                  pulumi.String("global"),
			DefaultLanguageCode:       pulumi.String("en"),
			TimeZone:                  pulumi.String("America/New_York"),
			Description:               pulumi.String("Example description."),
			DeleteChatEngineOnDestroy: pulumi.Bool(true),
		}, pulumi.DependsOn([]pulumi.Resource{
			myDatastore,
		}))
		if err != nil {
			return err
		}
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = diagflow.NewCxTool(ctx, "data_store_tool", &diagflow.CxToolArgs{
			Parent:      agent.ID(),
			DisplayName: pulumi.String("Example Data Store Tool"),
			Description: pulumi.String("Example Description"),
			DataStoreSpec: &diagflow.CxToolDataStoreSpecArgs{
				DataStoreConnections: diagflow.CxToolDataStoreSpecDataStoreConnectionArray{
					&diagflow.CxToolDataStoreSpecDataStoreConnectionArgs{
						DataStoreType: pulumi.String("UNSTRUCTURED"),
						DataStore: myDatastore.DataStoreId.ApplyT(func(dataStoreId string) (string, error) {
							return fmt.Sprintf("projects/%v/locations/global/collections/default_collection/dataStores/%v", project.Number, dataStoreId), nil
						}).(pulumi.StringOutput),
						DocumentProcessingMode: pulumi.String("DOCUMENTS"),
					},
				},
				FallbackPrompt: &diagflow.CxToolDataStoreSpecFallbackPromptArgs{},
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			myDatastore,
			agent,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var myDatastore = new Gcp.DiscoveryEngine.DataStore("my_datastore", new()
    {
        Location = "global",
        DataStoreId = "datastore-tool",
        DisplayName = "datastore for Tool test",
        IndustryVertical = "GENERIC",
        ContentConfig = "NO_CONTENT",
        SolutionTypes = new[]
        {
            "SOLUTION_TYPE_CHAT",
        },
    });

    var agent = new Gcp.Diagflow.CxAgent("agent", new()
    {
        DisplayName = "dialogflowcx-agent-data-store",
        Location = "global",
        DefaultLanguageCode = "en",
        TimeZone = "America/New_York",
        Description = "Example description.",
        DeleteChatEngineOnDestroy = true,
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            myDatastore,
        },
    });

    var project = Gcp.Organizations.GetProject.Invoke();

    var dataStoreTool = new Gcp.Diagflow.CxTool("data_store_tool", new()
    {
        Parent = agent.Id,
        DisplayName = "Example Data Store Tool",
        Description = "Example Description",
        DataStoreSpec = new Gcp.Diagflow.Inputs.CxToolDataStoreSpecArgs
        {
            DataStoreConnections = new[]
            {
                new Gcp.Diagflow.Inputs.CxToolDataStoreSpecDataStoreConnectionArgs
                {
                    DataStoreType = "UNSTRUCTURED",
                    DataStore = Output.Tuple(project, myDatastore.DataStoreId).Apply(values =>
                    {
                        var project = values.Item1;
                        var dataStoreId = values.Item2;
                        return $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}/locations/global/collections/default_collection/dataStores/{dataStoreId}";
                    }),
                    DocumentProcessingMode = "DOCUMENTS",
                },
            },
            FallbackPrompt = null,
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            myDatastore,
            agent,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.discoveryengine.DataStore;
import com.pulumi.gcp.discoveryengine.DataStoreArgs;
import com.pulumi.gcp.diagflow.CxAgent;
import com.pulumi.gcp.diagflow.CxAgentArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.diagflow.CxTool;
import com.pulumi.gcp.diagflow.CxToolArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolDataStoreSpecArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolDataStoreSpecFallbackPromptArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var myDatastore = new DataStore("myDatastore", DataStoreArgs.builder()
            .location("global")
            .dataStoreId("datastore-tool")
            .displayName("datastore for Tool test")
            .industryVertical("GENERIC")
            .contentConfig("NO_CONTENT")
            .solutionTypes("SOLUTION_TYPE_CHAT")
            .build());

        var agent = new CxAgent("agent", CxAgentArgs.builder()
            .displayName("dialogflowcx-agent-data-store")
            .location("global")
            .defaultLanguageCode("en")
            .timeZone("America/New_York")
            .description("Example description.")
            .deleteChatEngineOnDestroy(true)
            .build(), CustomResourceOptions.builder()
                .dependsOn(myDatastore)
                .build());

        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var dataStoreTool = new CxTool("dataStoreTool", CxToolArgs.builder()
            .parent(agent.id())
            .displayName("Example Data Store Tool")
            .description("Example Description")
            .dataStoreSpec(CxToolDataStoreSpecArgs.builder()
                .dataStoreConnections(CxToolDataStoreSpecDataStoreConnectionArgs.builder()
                    .dataStoreType("UNSTRUCTURED")
                    .dataStore(myDatastore.dataStoreId().applyValue(_dataStoreId -> String.format("projects/%s/locations/global/collections/default_collection/dataStores/%s", project.number(),_dataStoreId)))
                    .documentProcessingMode("DOCUMENTS")
                    .build())
                .fallbackPrompt(CxToolDataStoreSpecFallbackPromptArgs.builder()
                    .build())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    myDatastore,
                    agent)
                .build());

    }
}
resources:
  agent:
    type: gcp:diagflow:CxAgent
    properties:
      displayName: dialogflowcx-agent-data-store
      location: global
      defaultLanguageCode: en
      timeZone: America/New_York
      description: Example description.
      deleteChatEngineOnDestroy: true
    options:
      dependsOn:
        - ${myDatastore}
  dataStoreTool:
    type: gcp:diagflow:CxTool
    name: data_store_tool
    properties:
      parent: ${agent.id}
      displayName: Example Data Store Tool
      description: Example Description
      dataStoreSpec:
        dataStoreConnections:
          - dataStoreType: UNSTRUCTURED
            dataStore: projects/${project.number}/locations/global/collections/default_collection/dataStores/${myDatastore.dataStoreId}
            documentProcessingMode: DOCUMENTS
        fallbackPrompt: {}
    options:
      dependsOn:
        - ${myDatastore}
        - ${agent}
  myDatastore:
    type: gcp:discoveryengine:DataStore
    name: my_datastore
    properties:
      location: global
      dataStoreId: datastore-tool
      displayName: datastore for Tool test
      industryVertical: GENERIC
      contentConfig: NO_CONTENT
      solutionTypes:
        - SOLUTION_TYPE_CHAT
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The dataStoreSpec property connects your tool to one or more Discovery Engine data stores. Each dataStoreConnection specifies the dataStoreType (structured or unstructured), the dataStore path, and how documents are processed. The fallbackPrompt property controls what happens when search returns no results. This configuration requires an existing Discovery Engine data store and an agent with deleteChatEngineOnDestroy enabled.

Integrate external APIs using OpenAPI specifications

Production agents often need to call external REST APIs for real-time data or actions. OpenAPI tools define the API contract, authentication, and TLS configuration in a single specification.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";

const agent = new gcp.diagflow.CxAgent("agent", {
    displayName: "dialogflowcx-agent-open-api",
    location: "global",
    defaultLanguageCode: "en",
    timeZone: "America/New_York",
    description: "Example description.",
});
const openApiTool = new gcp.diagflow.CxTool("open_api_tool", {
    parent: agent.id,
    displayName: "Example Open API Tool",
    description: "Example Description",
    openApiSpec: {
        authentication: {
            oauthConfig: {
                oauthGrantType: "CLIENT_CREDENTIAL",
                clientId: "example client ID",
                clientSecret: "example client secret",
                scopes: ["example scope"],
                secretVersionForClientSecret: "projects/-/secrets/-/versions/-",
                tokenEndpoint: "https://example.com/oauth/token",
            },
        },
        tlsConfig: {
            caCerts: [{
                displayName: "example ca cert name",
                cert: std.base64encode({
                    input: "example cert",
                }).then(invoke => invoke.result),
            }],
        },
        serviceDirectoryConfig: {
            service: "projects/-/locations/-/namespaces/-/services/-",
        },
        textSchema: `    {
      \\"openapi\\": \\"3.0.0\\",
      \\"info\\": {
        \\"title\\": \\"Time API\\",
        \\"version\\": \\"1.0.0\\",
        \\"description\\": \\"A simple API to get the current time.\\"
      },
      \\"servers\\": [
        {
          \\"url\\": \\"https://example-api-endpoint.com\\"
        }
      ],
      \\"paths\\": {
        \\"/time\\": {
          \\"get\\": {
            \\"operationId\\": \\"getCurrentTime\\",
            \\"summary\\": \\"Gets the current server time.\\",
            \\"responses\\": {
              \\"200\\": {
                \\"description\\": \\"Successful response with the current time.\\",
                \\"content\\": {
                  \\"application/json\\": {
                    \\"schema\\": {
                      \\"type\\": \\"object\\",
                      \\"properties\\": {
                        \\"currentTime\\": {
                          \\"type\\": \\"string\\",
                          \\"format\\": \\"date-time\\",
                          \\"description\\": \\"The current time in ISO 8601 format.\\"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
`,
    },
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

agent = gcp.diagflow.CxAgent("agent",
    display_name="dialogflowcx-agent-open-api",
    location="global",
    default_language_code="en",
    time_zone="America/New_York",
    description="Example description.")
open_api_tool = gcp.diagflow.CxTool("open_api_tool",
    parent=agent.id,
    display_name="Example Open API Tool",
    description="Example Description",
    open_api_spec={
        "authentication": {
            "oauth_config": {
                "oauth_grant_type": "CLIENT_CREDENTIAL",
                "client_id": "example client ID",
                "client_secret": "example client secret",
                "scopes": ["example scope"],
                "secret_version_for_client_secret": "projects/-/secrets/-/versions/-",
                "token_endpoint": "https://example.com/oauth/token",
            },
        },
        "tls_config": {
            "ca_certs": [{
                "display_name": "example ca cert name",
                "cert": std.base64encode(input="example cert").result,
            }],
        },
        "service_directory_config": {
            "service": "projects/-/locations/-/namespaces/-/services/-",
        },
        "text_schema": """    {
      \"openapi\": \"3.0.0\",
      \"info\": {
        \"title\": \"Time API\",
        \"version\": \"1.0.0\",
        \"description\": \"A simple API to get the current time.\"
      },
      \"servers\": [
        {
          \"url\": \"https://example-api-endpoint.com\"
        }
      ],
      \"paths\": {
        \"/time\": {
          \"get\": {
            \"operationId\": \"getCurrentTime\",
            \"summary\": \"Gets the current server time.\",
            \"responses\": {
              \"200\": {
                \"description\": \"Successful response with the current time.\",
                \"content\": {
                  \"application/json\": {
                    \"schema\": {
                      \"type\": \"object\",
                      \"properties\": {
                        \"currentTime\": {
                          \"type\": \"string\",
                          \"format\": \"date-time\",
                          \"description\": \"The current time in ISO 8601 format.\"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
""",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/diagflow"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		agent, err := diagflow.NewCxAgent(ctx, "agent", &diagflow.CxAgentArgs{
			DisplayName:         pulumi.String("dialogflowcx-agent-open-api"),
			Location:            pulumi.String("global"),
			DefaultLanguageCode: pulumi.String("en"),
			TimeZone:            pulumi.String("America/New_York"),
			Description:         pulumi.String("Example description."),
		})
		if err != nil {
			return err
		}
		invokeBase64encode, err := std.Base64encode(ctx, &std.Base64encodeArgs{
			Input: "example cert",
		}, nil)
		if err != nil {
			return err
		}
		_, err = diagflow.NewCxTool(ctx, "open_api_tool", &diagflow.CxToolArgs{
			Parent:      agent.ID(),
			DisplayName: pulumi.String("Example Open API Tool"),
			Description: pulumi.String("Example Description"),
			OpenApiSpec: &diagflow.CxToolOpenApiSpecArgs{
				Authentication: &diagflow.CxToolOpenApiSpecAuthenticationArgs{
					OauthConfig: &diagflow.CxToolOpenApiSpecAuthenticationOauthConfigArgs{
						OauthGrantType: pulumi.String("CLIENT_CREDENTIAL"),
						ClientId:       pulumi.String("example client ID"),
						ClientSecret:   pulumi.String("example client secret"),
						Scopes: pulumi.StringArray{
							pulumi.String("example scope"),
						},
						SecretVersionForClientSecret: pulumi.String("projects/-/secrets/-/versions/-"),
						TokenEndpoint:                pulumi.String("https://example.com/oauth/token"),
					},
				},
				TlsConfig: &diagflow.CxToolOpenApiSpecTlsConfigArgs{
					CaCerts: diagflow.CxToolOpenApiSpecTlsConfigCaCertArray{
						&diagflow.CxToolOpenApiSpecTlsConfigCaCertArgs{
							DisplayName: pulumi.String("example ca cert name"),
							Cert:        pulumi.String(invokeBase64encode.Result),
						},
					},
				},
				ServiceDirectoryConfig: &diagflow.CxToolOpenApiSpecServiceDirectoryConfigArgs{
					Service: pulumi.String("projects/-/locations/-/namespaces/-/services/-"),
				},
				TextSchema: pulumi.String(`    {
      \"openapi\": \"3.0.0\",
      \"info\": {
        \"title\": \"Time API\",
        \"version\": \"1.0.0\",
        \"description\": \"A simple API to get the current time.\"
      },
      \"servers\": [
        {
          \"url\": \"https://example-api-endpoint.com\"
        }
      ],
      \"paths\": {
        \"/time\": {
          \"get\": {
            \"operationId\": \"getCurrentTime\",
            \"summary\": \"Gets the current server time.\",
            \"responses\": {
              \"200\": {
                \"description\": \"Successful response with the current time.\",
                \"content\": {
                  \"application/json\": {
                    \"schema\": {
                      \"type\": \"object\",
                      \"properties\": {
                        \"currentTime\": {
                          \"type\": \"string\",
                          \"format\": \"date-time\",
                          \"description\": \"The current time in ISO 8601 format.\"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
`),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var agent = new Gcp.Diagflow.CxAgent("agent", new()
    {
        DisplayName = "dialogflowcx-agent-open-api",
        Location = "global",
        DefaultLanguageCode = "en",
        TimeZone = "America/New_York",
        Description = "Example description.",
    });

    var openApiTool = new Gcp.Diagflow.CxTool("open_api_tool", new()
    {
        Parent = agent.Id,
        DisplayName = "Example Open API Tool",
        Description = "Example Description",
        OpenApiSpec = new Gcp.Diagflow.Inputs.CxToolOpenApiSpecArgs
        {
            Authentication = new Gcp.Diagflow.Inputs.CxToolOpenApiSpecAuthenticationArgs
            {
                OauthConfig = new Gcp.Diagflow.Inputs.CxToolOpenApiSpecAuthenticationOauthConfigArgs
                {
                    OauthGrantType = "CLIENT_CREDENTIAL",
                    ClientId = "example client ID",
                    ClientSecret = "example client secret",
                    Scopes = new[]
                    {
                        "example scope",
                    },
                    SecretVersionForClientSecret = "projects/-/secrets/-/versions/-",
                    TokenEndpoint = "https://example.com/oauth/token",
                },
            },
            TlsConfig = new Gcp.Diagflow.Inputs.CxToolOpenApiSpecTlsConfigArgs
            {
                CaCerts = new[]
                {
                    new Gcp.Diagflow.Inputs.CxToolOpenApiSpecTlsConfigCaCertArgs
                    {
                        DisplayName = "example ca cert name",
                        Cert = Std.Base64encode.Invoke(new()
                        {
                            Input = "example cert",
                        }).Apply(invoke => invoke.Result),
                    },
                },
            },
            ServiceDirectoryConfig = new Gcp.Diagflow.Inputs.CxToolOpenApiSpecServiceDirectoryConfigArgs
            {
                Service = "projects/-/locations/-/namespaces/-/services/-",
            },
            TextSchema = @"    {
      \""openapi\"": \""3.0.0\"",
      \""info\"": {
        \""title\"": \""Time API\"",
        \""version\"": \""1.0.0\"",
        \""description\"": \""A simple API to get the current time.\""
      },
      \""servers\"": [
        {
          \""url\"": \""https://example-api-endpoint.com\""
        }
      ],
      \""paths\"": {
        \""/time\"": {
          \""get\"": {
            \""operationId\"": \""getCurrentTime\"",
            \""summary\"": \""Gets the current server time.\"",
            \""responses\"": {
              \""200\"": {
                \""description\"": \""Successful response with the current time.\"",
                \""content\"": {
                  \""application/json\"": {
                    \""schema\"": {
                      \""type\"": \""object\"",
                      \""properties\"": {
                        \""currentTime\"": {
                          \""type\"": \""string\"",
                          \""format\"": \""date-time\"",
                          \""description\"": \""The current time in ISO 8601 format.\""
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.diagflow.CxAgent;
import com.pulumi.gcp.diagflow.CxAgentArgs;
import com.pulumi.gcp.diagflow.CxTool;
import com.pulumi.gcp.diagflow.CxToolArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolOpenApiSpecArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolOpenApiSpecAuthenticationArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolOpenApiSpecAuthenticationOauthConfigArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolOpenApiSpecTlsConfigArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolOpenApiSpecServiceDirectoryConfigArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.Base64encodeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var agent = new CxAgent("agent", CxAgentArgs.builder()
            .displayName("dialogflowcx-agent-open-api")
            .location("global")
            .defaultLanguageCode("en")
            .timeZone("America/New_York")
            .description("Example description.")
            .build());

        var openApiTool = new CxTool("openApiTool", CxToolArgs.builder()
            .parent(agent.id())
            .displayName("Example Open API Tool")
            .description("Example Description")
            .openApiSpec(CxToolOpenApiSpecArgs.builder()
                .authentication(CxToolOpenApiSpecAuthenticationArgs.builder()
                    .oauthConfig(CxToolOpenApiSpecAuthenticationOauthConfigArgs.builder()
                        .oauthGrantType("CLIENT_CREDENTIAL")
                        .clientId("example client ID")
                        .clientSecret("example client secret")
                        .scopes("example scope")
                        .secretVersionForClientSecret("projects/-/secrets/-/versions/-")
                        .tokenEndpoint("https://example.com/oauth/token")
                        .build())
                    .build())
                .tlsConfig(CxToolOpenApiSpecTlsConfigArgs.builder()
                    .caCerts(CxToolOpenApiSpecTlsConfigCaCertArgs.builder()
                        .displayName("example ca cert name")
                        .cert(StdFunctions.base64encode(Base64encodeArgs.builder()
                            .input("example cert")
                            .build()).result())
                        .build())
                    .build())
                .serviceDirectoryConfig(CxToolOpenApiSpecServiceDirectoryConfigArgs.builder()
                    .service("projects/-/locations/-/namespaces/-/services/-")
                    .build())
                .textSchema("""
    {
      \"openapi\": \"3.0.0\",
      \"info\": {
        \"title\": \"Time API\",
        \"version\": \"1.0.0\",
        \"description\": \"A simple API to get the current time.\"
      },
      \"servers\": [
        {
          \"url\": \"https://example-api-endpoint.com\"
        }
      ],
      \"paths\": {
        \"/time\": {
          \"get\": {
            \"operationId\": \"getCurrentTime\",
            \"summary\": \"Gets the current server time.\",
            \"responses\": {
              \"200\": {
                \"description\": \"Successful response with the current time.\",
                \"content\": {
                  \"application/json\": {
                    \"schema\": {
                      \"type\": \"object\",
                      \"properties\": {
                        \"currentTime\": {
                          \"type\": \"string\",
                          \"format\": \"date-time\",
                          \"description\": \"The current time in ISO 8601 format.\"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
                """)
                .build())
            .build());

    }
}
resources:
  agent:
    type: gcp:diagflow:CxAgent
    properties:
      displayName: dialogflowcx-agent-open-api
      location: global
      defaultLanguageCode: en
      timeZone: America/New_York
      description: Example description.
  openApiTool:
    type: gcp:diagflow:CxTool
    name: open_api_tool
    properties:
      parent: ${agent.id}
      displayName: Example Open API Tool
      description: Example Description
      openApiSpec:
        authentication:
          oauthConfig:
            oauthGrantType: CLIENT_CREDENTIAL
            clientId: example client ID
            clientSecret: example client secret
            scopes:
              - example scope
            secretVersionForClientSecret: projects/-/secrets/-/versions/-
            tokenEndpoint: https://example.com/oauth/token
        tlsConfig:
          caCerts:
            - displayName: example ca cert name
              cert:
                fn::invoke:
                  function: std:base64encode
                  arguments:
                    input: example cert
                  return: result
        serviceDirectoryConfig:
          service: projects/-/locations/-/namespaces/-/services/-
        textSchema: |2
              {
                \"openapi\": \"3.0.0\",
                \"info\": {
                  \"title\": \"Time API\",
                  \"version\": \"1.0.0\",
                  \"description\": \"A simple API to get the current time.\"
                },
                \"servers\": [
                  {
                    \"url\": \"https://example-api-endpoint.com\"
                  }
                ],
                \"paths\": {
                  \"/time\": {
                    \"get\": {
                      \"operationId\": \"getCurrentTime\",
                      \"summary\": \"Gets the current server time.\",
                      \"responses\": {
                        \"200\": {
                          \"description\": \"Successful response with the current time.\",
                          \"content\": {
                            \"application/json\": {
                              \"schema\": {
                                \"type\": \"object\",
                                \"properties\": {
                                  \"currentTime\": {
                                    \"type\": \"string\",
                                    \"format\": \"date-time\",
                                    \"description\": \"The current time in ISO 8601 format.\"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }

The openApiSpec property wraps your API definition in textSchema (standard OpenAPI 3.0 format), authentication configuration, and optional TLS settings. The oauthConfig block handles OAuth 2.0 client credentials flow, storing the client secret in Secret Manager. The tlsConfig property adds custom CA certificates for private APIs. The serviceDirectoryConfig property routes requests through Service Directory for internal services. This configuration assumes you have valid OAuth credentials, Secret Manager access, and Service Directory setup.

Execute BigQuery operations through Integration Connectors

Agents that need to query or modify data in Google Cloud services can use Integration Connectors, which provide pre-built integrations with managed authentication and connection pooling.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const agent = new gcp.diagflow.CxAgent("agent", {
    displayName: "dialogflowcx-agent-connector",
    location: "us-central1",
    defaultLanguageCode: "en",
    timeZone: "America/New_York",
    description: "Example description.",
    deleteChatEngineOnDestroy: true,
});
const bqDataset = new gcp.bigquery.Dataset("bq_dataset", {
    datasetId: "terraformdatasetdfcxtool",
    friendlyName: "test",
    description: "This is a test description",
    location: "us-central1",
    deleteContentsOnDestroy: true,
});
const testProject = gcp.organizations.getProject({});
const integrationConnector = new gcp.integrationconnectors.Connection("integration_connector", {
    name: "terraform-df-cx-tool-connection",
    location: "us-central1",
    connectorVersion: pulumi.interpolate`projects/${agent.project}/locations/global/providers/gcp/connectors/bigquery/versions/1`,
    description: "tf created description",
    configVariables: [
        {
            key: "dataset_id",
            stringValue: bqDataset.datasetId,
        },
        {
            key: "project_id",
            stringValue: agent.project,
        },
        {
            key: "support_native_data_type",
            booleanValue: false,
        },
        {
            key: "proxy_enabled",
            booleanValue: false,
        },
    ],
    serviceAccount: testProject.then(testProject => `${testProject.number}-compute@developer.gserviceaccount.com`),
    authConfig: {
        authType: "AUTH_TYPE_UNSPECIFIED",
    },
});
const bqTable = new gcp.bigquery.Table("bq_table", {
    deletionProtection: false,
    datasetId: bqDataset.datasetId,
    tableId: "terraformdatasetdfcxtooltable",
});
const connectorSaDatasetPerms = new gcp.bigquery.DatasetIamMember("connector_sa_dataset_perms", {
    project: testProject.then(testProject => testProject.projectId),
    datasetId: bqDataset.datasetId,
    role: "roles/bigquery.dataEditor",
    member: testProject.then(testProject => `serviceAccount:${testProject.number}-compute@developer.gserviceaccount.com`),
});
const connectorTool = new gcp.diagflow.CxTool("connector_tool", {
    parent: agent.id,
    displayName: "Example Connector Tool",
    description: "Example Description",
    connectorSpec: {
        name: pulumi.interpolate`projects/${agent.project}/locations/us-central1/connections/${integrationConnector.name}`,
        actions: [
            {
                connectionActionId: "ExecuteCustomQuery",
                inputFields: ["test1"],
                outputFields: ["test1"],
            },
            {
                entityOperation: {
                    entityId: bqTable.tableId,
                    operation: "LIST",
                },
            },
        ],
    },
});
import pulumi
import pulumi_gcp as gcp

agent = gcp.diagflow.CxAgent("agent",
    display_name="dialogflowcx-agent-connector",
    location="us-central1",
    default_language_code="en",
    time_zone="America/New_York",
    description="Example description.",
    delete_chat_engine_on_destroy=True)
bq_dataset = gcp.bigquery.Dataset("bq_dataset",
    dataset_id="terraformdatasetdfcxtool",
    friendly_name="test",
    description="This is a test description",
    location="us-central1",
    delete_contents_on_destroy=True)
test_project = gcp.organizations.get_project()
integration_connector = gcp.integrationconnectors.Connection("integration_connector",
    name="terraform-df-cx-tool-connection",
    location="us-central1",
    connector_version=agent.project.apply(lambda project: f"projects/{project}/locations/global/providers/gcp/connectors/bigquery/versions/1"),
    description="tf created description",
    config_variables=[
        {
            "key": "dataset_id",
            "string_value": bq_dataset.dataset_id,
        },
        {
            "key": "project_id",
            "string_value": agent.project,
        },
        {
            "key": "support_native_data_type",
            "boolean_value": False,
        },
        {
            "key": "proxy_enabled",
            "boolean_value": False,
        },
    ],
    service_account=f"{test_project.number}-compute@developer.gserviceaccount.com",
    auth_config={
        "auth_type": "AUTH_TYPE_UNSPECIFIED",
    })
bq_table = gcp.bigquery.Table("bq_table",
    deletion_protection=False,
    dataset_id=bq_dataset.dataset_id,
    table_id="terraformdatasetdfcxtooltable")
connector_sa_dataset_perms = gcp.bigquery.DatasetIamMember("connector_sa_dataset_perms",
    project=test_project.project_id,
    dataset_id=bq_dataset.dataset_id,
    role="roles/bigquery.dataEditor",
    member=f"serviceAccount:{test_project.number}-compute@developer.gserviceaccount.com")
connector_tool = gcp.diagflow.CxTool("connector_tool",
    parent=agent.id,
    display_name="Example Connector Tool",
    description="Example Description",
    connector_spec={
        "name": pulumi.Output.all(
            project=agent.project,
            name=integration_connector.name
).apply(lambda resolved_outputs: f"projects/{resolved_outputs['project']}/locations/us-central1/connections/{resolved_outputs['name']}")
,
        "actions": [
            {
                "connection_action_id": "ExecuteCustomQuery",
                "input_fields": ["test1"],
                "output_fields": ["test1"],
            },
            {
                "entity_operation": {
                    "entity_id": bq_table.table_id,
                    "operation": "LIST",
                },
            },
        ],
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/diagflow"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/integrationconnectors"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		agent, err := diagflow.NewCxAgent(ctx, "agent", &diagflow.CxAgentArgs{
			DisplayName:               pulumi.String("dialogflowcx-agent-connector"),
			Location:                  pulumi.String("us-central1"),
			DefaultLanguageCode:       pulumi.String("en"),
			TimeZone:                  pulumi.String("America/New_York"),
			Description:               pulumi.String("Example description."),
			DeleteChatEngineOnDestroy: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		bqDataset, err := bigquery.NewDataset(ctx, "bq_dataset", &bigquery.DatasetArgs{
			DatasetId:               pulumi.String("terraformdatasetdfcxtool"),
			FriendlyName:            pulumi.String("test"),
			Description:             pulumi.String("This is a test description"),
			Location:                pulumi.String("us-central1"),
			DeleteContentsOnDestroy: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		testProject, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		integrationConnector, err := integrationconnectors.NewConnection(ctx, "integration_connector", &integrationconnectors.ConnectionArgs{
			Name:     pulumi.String("terraform-df-cx-tool-connection"),
			Location: pulumi.String("us-central1"),
			ConnectorVersion: agent.Project.ApplyT(func(project string) (string, error) {
				return fmt.Sprintf("projects/%v/locations/global/providers/gcp/connectors/bigquery/versions/1", project), nil
			}).(pulumi.StringOutput),
			Description: pulumi.String("tf created description"),
			ConfigVariables: integrationconnectors.ConnectionConfigVariableArray{
				&integrationconnectors.ConnectionConfigVariableArgs{
					Key:         pulumi.String("dataset_id"),
					StringValue: bqDataset.DatasetId,
				},
				&integrationconnectors.ConnectionConfigVariableArgs{
					Key:         pulumi.String("project_id"),
					StringValue: agent.Project,
				},
				&integrationconnectors.ConnectionConfigVariableArgs{
					Key:          pulumi.String("support_native_data_type"),
					BooleanValue: pulumi.Bool(false),
				},
				&integrationconnectors.ConnectionConfigVariableArgs{
					Key:          pulumi.String("proxy_enabled"),
					BooleanValue: pulumi.Bool(false),
				},
			},
			ServiceAccount: pulumi.Sprintf("%v-compute@developer.gserviceaccount.com", testProject.Number),
			AuthConfig: &integrationconnectors.ConnectionAuthConfigArgs{
				AuthType: pulumi.String("AUTH_TYPE_UNSPECIFIED"),
			},
		})
		if err != nil {
			return err
		}
		bqTable, err := bigquery.NewTable(ctx, "bq_table", &bigquery.TableArgs{
			DeletionProtection: pulumi.Bool(false),
			DatasetId:          bqDataset.DatasetId,
			TableId:            pulumi.String("terraformdatasetdfcxtooltable"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetIamMember(ctx, "connector_sa_dataset_perms", &bigquery.DatasetIamMemberArgs{
			Project:   pulumi.String(testProject.ProjectId),
			DatasetId: bqDataset.DatasetId,
			Role:      pulumi.String("roles/bigquery.dataEditor"),
			Member:    pulumi.Sprintf("serviceAccount:%v-compute@developer.gserviceaccount.com", testProject.Number),
		})
		if err != nil {
			return err
		}
		_, err = diagflow.NewCxTool(ctx, "connector_tool", &diagflow.CxToolArgs{
			Parent:      agent.ID(),
			DisplayName: pulumi.String("Example Connector Tool"),
			Description: pulumi.String("Example Description"),
			ConnectorSpec: &diagflow.CxToolConnectorSpecArgs{
				Name: pulumi.All(agent.Project, integrationConnector.Name).ApplyT(func(_args []interface{}) (string, error) {
					project := _args[0].(string)
					name := _args[1].(string)
					return fmt.Sprintf("projects/%v/locations/us-central1/connections/%v", project, name), nil
				}).(pulumi.StringOutput),
				Actions: diagflow.CxToolConnectorSpecActionArray{
					&diagflow.CxToolConnectorSpecActionArgs{
						ConnectionActionId: pulumi.String("ExecuteCustomQuery"),
						InputFields: pulumi.StringArray{
							pulumi.String("test1"),
						},
						OutputFields: pulumi.StringArray{
							pulumi.String("test1"),
						},
					},
					&diagflow.CxToolConnectorSpecActionArgs{
						EntityOperation: &diagflow.CxToolConnectorSpecActionEntityOperationArgs{
							EntityId:  bqTable.TableId,
							Operation: pulumi.String("LIST"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var agent = new Gcp.Diagflow.CxAgent("agent", new()
    {
        DisplayName = "dialogflowcx-agent-connector",
        Location = "us-central1",
        DefaultLanguageCode = "en",
        TimeZone = "America/New_York",
        Description = "Example description.",
        DeleteChatEngineOnDestroy = true,
    });

    var bqDataset = new Gcp.BigQuery.Dataset("bq_dataset", new()
    {
        DatasetId = "terraformdatasetdfcxtool",
        FriendlyName = "test",
        Description = "This is a test description",
        Location = "us-central1",
        DeleteContentsOnDestroy = true,
    });

    var testProject = Gcp.Organizations.GetProject.Invoke();

    var integrationConnector = new Gcp.IntegrationConnectors.Connection("integration_connector", new()
    {
        Name = "terraform-df-cx-tool-connection",
        Location = "us-central1",
        ConnectorVersion = agent.Project.Apply(project => $"projects/{project}/locations/global/providers/gcp/connectors/bigquery/versions/1"),
        Description = "tf created description",
        ConfigVariables = new[]
        {
            new Gcp.IntegrationConnectors.Inputs.ConnectionConfigVariableArgs
            {
                Key = "dataset_id",
                StringValue = bqDataset.DatasetId,
            },
            new Gcp.IntegrationConnectors.Inputs.ConnectionConfigVariableArgs
            {
                Key = "project_id",
                StringValue = agent.Project,
            },
            new Gcp.IntegrationConnectors.Inputs.ConnectionConfigVariableArgs
            {
                Key = "support_native_data_type",
                BooleanValue = false,
            },
            new Gcp.IntegrationConnectors.Inputs.ConnectionConfigVariableArgs
            {
                Key = "proxy_enabled",
                BooleanValue = false,
            },
        },
        ServiceAccount = $"{testProject.Apply(getProjectResult => getProjectResult.Number)}-compute@developer.gserviceaccount.com",
        AuthConfig = new Gcp.IntegrationConnectors.Inputs.ConnectionAuthConfigArgs
        {
            AuthType = "AUTH_TYPE_UNSPECIFIED",
        },
    });

    var bqTable = new Gcp.BigQuery.Table("bq_table", new()
    {
        DeletionProtection = false,
        DatasetId = bqDataset.DatasetId,
        TableId = "terraformdatasetdfcxtooltable",
    });

    var connectorSaDatasetPerms = new Gcp.BigQuery.DatasetIamMember("connector_sa_dataset_perms", new()
    {
        Project = testProject.Apply(getProjectResult => getProjectResult.ProjectId),
        DatasetId = bqDataset.DatasetId,
        Role = "roles/bigquery.dataEditor",
        Member = $"serviceAccount:{testProject.Apply(getProjectResult => getProjectResult.Number)}-compute@developer.gserviceaccount.com",
    });

    var connectorTool = new Gcp.Diagflow.CxTool("connector_tool", new()
    {
        Parent = agent.Id,
        DisplayName = "Example Connector Tool",
        Description = "Example Description",
        ConnectorSpec = new Gcp.Diagflow.Inputs.CxToolConnectorSpecArgs
        {
            Name = Output.Tuple(agent.Project, integrationConnector.Name).Apply(values =>
            {
                var project = values.Item1;
                var name = values.Item2;
                return $"projects/{project}/locations/us-central1/connections/{name}";
            }),
            Actions = new[]
            {
                new Gcp.Diagflow.Inputs.CxToolConnectorSpecActionArgs
                {
                    ConnectionActionId = "ExecuteCustomQuery",
                    InputFields = new[]
                    {
                        "test1",
                    },
                    OutputFields = new[]
                    {
                        "test1",
                    },
                },
                new Gcp.Diagflow.Inputs.CxToolConnectorSpecActionArgs
                {
                    EntityOperation = new Gcp.Diagflow.Inputs.CxToolConnectorSpecActionEntityOperationArgs
                    {
                        EntityId = bqTable.TableId,
                        Operation = "LIST",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.diagflow.CxAgent;
import com.pulumi.gcp.diagflow.CxAgentArgs;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.integrationconnectors.Connection;
import com.pulumi.gcp.integrationconnectors.ConnectionArgs;
import com.pulumi.gcp.integrationconnectors.inputs.ConnectionConfigVariableArgs;
import com.pulumi.gcp.integrationconnectors.inputs.ConnectionAuthConfigArgs;
import com.pulumi.gcp.bigquery.Table;
import com.pulumi.gcp.bigquery.TableArgs;
import com.pulumi.gcp.bigquery.DatasetIamMember;
import com.pulumi.gcp.bigquery.DatasetIamMemberArgs;
import com.pulumi.gcp.diagflow.CxTool;
import com.pulumi.gcp.diagflow.CxToolArgs;
import com.pulumi.gcp.diagflow.inputs.CxToolConnectorSpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var agent = new CxAgent("agent", CxAgentArgs.builder()
            .displayName("dialogflowcx-agent-connector")
            .location("us-central1")
            .defaultLanguageCode("en")
            .timeZone("America/New_York")
            .description("Example description.")
            .deleteChatEngineOnDestroy(true)
            .build());

        var bqDataset = new Dataset("bqDataset", DatasetArgs.builder()
            .datasetId("terraformdatasetdfcxtool")
            .friendlyName("test")
            .description("This is a test description")
            .location("us-central1")
            .deleteContentsOnDestroy(true)
            .build());

        final var testProject = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var integrationConnector = new Connection("integrationConnector", ConnectionArgs.builder()
            .name("terraform-df-cx-tool-connection")
            .location("us-central1")
            .connectorVersion(agent.project().applyValue(_project -> String.format("projects/%s/locations/global/providers/gcp/connectors/bigquery/versions/1", _project)))
            .description("tf created description")
            .configVariables(            
                ConnectionConfigVariableArgs.builder()
                    .key("dataset_id")
                    .stringValue(bqDataset.datasetId())
                    .build(),
                ConnectionConfigVariableArgs.builder()
                    .key("project_id")
                    .stringValue(agent.project())
                    .build(),
                ConnectionConfigVariableArgs.builder()
                    .key("support_native_data_type")
                    .booleanValue(false)
                    .build(),
                ConnectionConfigVariableArgs.builder()
                    .key("proxy_enabled")
                    .booleanValue(false)
                    .build())
            .serviceAccount(String.format("%s-compute@developer.gserviceaccount.com", testProject.number()))
            .authConfig(ConnectionAuthConfigArgs.builder()
                .authType("AUTH_TYPE_UNSPECIFIED")
                .build())
            .build());

        var bqTable = new Table("bqTable", TableArgs.builder()
            .deletionProtection(false)
            .datasetId(bqDataset.datasetId())
            .tableId("terraformdatasetdfcxtooltable")
            .build());

        var connectorSaDatasetPerms = new DatasetIamMember("connectorSaDatasetPerms", DatasetIamMemberArgs.builder()
            .project(testProject.projectId())
            .datasetId(bqDataset.datasetId())
            .role("roles/bigquery.dataEditor")
            .member(String.format("serviceAccount:%s-compute@developer.gserviceaccount.com", testProject.number()))
            .build());

        var connectorTool = new CxTool("connectorTool", CxToolArgs.builder()
            .parent(agent.id())
            .displayName("Example Connector Tool")
            .description("Example Description")
            .connectorSpec(CxToolConnectorSpecArgs.builder()
                .name(Output.tuple(agent.project(), integrationConnector.name()).applyValue(values -> {
                    var project = values.t1;
                    var name = values.t2;
                    return String.format("projects/%s/locations/us-central1/connections/%s", project,name);
                }))
                .actions(                
                    CxToolConnectorSpecActionArgs.builder()
                        .connectionActionId("ExecuteCustomQuery")
                        .inputFields("test1")
                        .outputFields("test1")
                        .build(),
                    CxToolConnectorSpecActionArgs.builder()
                        .entityOperation(CxToolConnectorSpecActionEntityOperationArgs.builder()
                            .entityId(bqTable.tableId())
                            .operation("LIST")
                            .build())
                        .build())
                .build())
            .build());

    }
}
resources:
  agent:
    type: gcp:diagflow:CxAgent
    properties:
      displayName: dialogflowcx-agent-connector
      location: us-central1
      defaultLanguageCode: en
      timeZone: America/New_York
      description: Example description.
      deleteChatEngineOnDestroy: true
  integrationConnector:
    type: gcp:integrationconnectors:Connection
    name: integration_connector
    properties:
      name: terraform-df-cx-tool-connection
      location: us-central1
      connectorVersion: projects/${agent.project}/locations/global/providers/gcp/connectors/bigquery/versions/1
      description: tf created description
      configVariables:
        - key: dataset_id
          stringValue: ${bqDataset.datasetId}
        - key: project_id
          stringValue: ${agent.project}
        - key: support_native_data_type
          booleanValue: false
        - key: proxy_enabled
          booleanValue: false
      serviceAccount: ${testProject.number}-compute@developer.gserviceaccount.com
      authConfig:
        authType: AUTH_TYPE_UNSPECIFIED
  bqDataset:
    type: gcp:bigquery:Dataset
    name: bq_dataset
    properties:
      datasetId: terraformdatasetdfcxtool
      friendlyName: test
      description: This is a test description
      location: us-central1
      deleteContentsOnDestroy: true
  bqTable:
    type: gcp:bigquery:Table
    name: bq_table
    properties:
      deletionProtection: false
      datasetId: ${bqDataset.datasetId}
      tableId: terraformdatasetdfcxtooltable
  connectorSaDatasetPerms:
    type: gcp:bigquery:DatasetIamMember
    name: connector_sa_dataset_perms
    properties:
      project: ${testProject.projectId}
      datasetId: ${bqDataset.datasetId}
      role: roles/bigquery.dataEditor
      member: serviceAccount:${testProject.number}-compute@developer.gserviceaccount.com
  connectorTool:
    type: gcp:diagflow:CxTool
    name: connector_tool
    properties:
      parent: ${agent.id}
      displayName: Example Connector Tool
      description: Example Description
      connectorSpec:
        name: projects/${agent.project}/locations/us-central1/connections/${integrationConnector.name}
        actions:
          - connectionActionId: ExecuteCustomQuery
            inputFields:
              - test1
            outputFields:
              - test1
          - entityOperation:
              entityId: ${bqTable.tableId}
              operation: LIST
variables:
  testProject:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The connectorSpec property references an Integration Connector connection by name and defines available actions. Each action either specifies a connectionActionId (like ExecuteCustomQuery) with input and output fields, or an entityOperation that targets a specific BigQuery table. The connector handles authentication using the service account specified in the connection configuration. This setup requires an existing Integration Connector connection, BigQuery dataset and table, and appropriate IAM permissions for the service account.

Beyond these examples

These snippets focus on specific tool-level features: client-side functions and external API integration, data store search and BigQuery operations, and OAuth authentication and TLS configuration. They’re intentionally minimal rather than full conversational applications.

The examples may reference pre-existing infrastructure such as Dialogflow CX agents, Discovery Engine data stores, Integration Connector connections, BigQuery datasets and tables, and OAuth credentials and Secret Manager secrets. They focus on configuring the tool rather than provisioning everything around it.

To keep things focused, common tool patterns are omitted, including:

  • Tool versioning and lifecycle management
  • Error handling and retry configuration
  • Rate limiting and quota management
  • Tool chaining and composition patterns

These omissions are intentional: the goal is to illustrate how each tool type is wired, not provide drop-in agent modules. See the Dialogflow CX Tool resource reference for all available configuration options.

Let's configure Google Cloud Dialogflow CX Tools

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Tool Types & Specifications
Can I use multiple tool specification types together?
No. The specification field is a union, meaning you must choose exactly one of openApiSpec, dataStoreSpec, functionSpec, or connectorSpec. Setting multiple specifications will cause an error.
What are the four tool specification types?

Dialogflow CX Tools support four types:

  1. Open API (openApiSpec) - REST API integration with OpenAPI specification
  2. Data Store (dataStoreSpec) - Search tool connected to Discovery Engine data stores
  3. Function (functionSpec) - Client-side executed functions with custom schemas
  4. Connector (connectorSpec) - Integration with services via Integration Connectors (Beta)
Is the connector specification stable for production use?
The connectorSpec field is marked as Beta, indicating it may have limited support or change in future versions. Consider this when planning production deployments.
Configuration & Setup
Can I move a tool to a different agent after creation?
No. The parent property is immutable and cannot be changed after the tool is created. You must specify the correct agent format (projects/<Project ID>/locations/<Location ID>/agents/<Agent ID>) at creation time.
Does the tool display name need to be unique?
Yes. The displayName must be unique within the agent. You cannot have two tools with the same display name under the same agent.
What import formats are supported?
You can import tools using either {{parent}}/tools/{{name}} or {{parent}}/{{name}} format.
Authentication & Security
How do I configure OAuth authentication for an Open API tool?
Configure authentication.oauthConfig within openApiSpec, specifying oauthGrantType (e.g., CLIENT_CREDENTIAL), clientId, clientSecret, scopes, tokenEndpoint, and optionally secretVersionForClientSecret for secret management.
Can I configure TLS certificates for Open API tools?
Yes. Use the tlsConfig.caCerts block within openApiSpec to specify custom CA certificates with a display name and base64-encoded certificate content.
Tool-Specific Configuration
How do I define schemas for a function tool?
Use functionSpec with inputSchema and outputSchema properties. Both accept JSON schemas defining the structure, including property types, descriptions, and required fields.
How do I connect a tool to a data store?
Configure dataStoreSpec.dataStoreConnections with the data store path (format: projects/<number>/locations/<location>/collections/<collection>/dataStores/<id>), dataStoreType (e.g., UNSTRUCTURED), and documentProcessingMode.

Using a different cloud?

Explore integration guides for other cloud providers: