Custom Provider Lifecycle
This guide walks through the full lifecycle of a Custom Provider in the using the Custom Accounts GraphQL APIs in Agent Control Tower:
- Creating the provider account
- Creating an agent (with its automatic draft version and alias)
- Configure the DRAFT version
- Creating a version and alias of an agent
- Query and list operations
- Deleting a provider
All field names below are the exact GraphQL mutation and query names exposed by this service, verified against the generated schema at target/schema.graphql.
Terminology
| What you might call it | What it actually is in the API |
|---|---|
| "Provider" (the thing you create) | AiAgentProviderAccount (providerType: CUSTOM, providerSubType: CUSTOM_PROVIDER or a named framework) |
| AiAgentProvider (singular, no "Account") | Not something you create. It's a static, read-only rollup row per AiAgentProviderType, used only for dashboard counts (aiAgentProviders / aiAgentSubProviders). Ignore it for lifecycle purposes. |
| "Instruction" | Not a separate entity. It's a [String] field directly on AiAgentTask (instructions). |
| "Packaged version" | Not a separate mutation. It's a side effect of aiAgentAliasCreate when you omit agentVersionId — refer to Step 4. |
Entity relationship
AiAgentProviderAccount (the "Custom Provider")
└─ AiAgent (1 : many)
└─ AiAgentVersion (1 : many — exactly one is the mutable DRAFT; all others are
immutable numbered packages: v1, v2, …)
└─ AiAgentAlias (1 : many — every agent always has exactly one alias
pointing at its DRAFT version)
AiAgentTask, AiAgentTool, AiAgentLlm, AiAgentGuardrail
are top-level entities scoped to providerAccountId, linked to a VERSION
(specifically an agent's DRAFT version) via association fields — NOT owned by it.
AiAgentTool → associates only to AiAgentTask (via aiAgentTaskIds)
"Instructions" → lives only on AiAgentTask (via instructions: [String!])
End-to-end example call sequence
aiAgentProviderAccountCreate→providerAccountIdaiAgentCreate→agentId(DRAFT version and default alias auto-created)aiAgentTaskCreate→taskId(instructions inline,agentIds: [agentId])aiAgentToolCreate→toolId(aiAgentTaskIds: [taskId])aiAgentLlmCreate→llmId(agentIds: [agentId])aiAgentGuardrailCreate→guardrailId(agentIds: [agentId])- Iterate on the draft as needed (
aiAgentTaskUpdate,aiAgentToolUpdate, and so on).
- Iterate on the draft as needed (
aiAgentAliasCreate(noagentVersionId) → packages the draft into v1 plus a new alias- Keep editing the draft, and take another packages later with a second
aiAgentAliasCreate.
- Keep editing the draft, and take another packages later with a second
Step 1: Create the Custom Provider
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentProviderAccountCreate | providerType: CUSTOM (required), providerAccountName (required), providerSubType (optional, defaults to CUSTOM_PROVIDER), providerAccountDescription, metadataJson, externalAccountId |
Returns an AiAgentProviderAccount. Save its id, you need it as providerAccountId for every entity you create in the steps below (agent, task, tool, LLM, guardrail).
providerType is immutable after create.
Step 2: Create the agent
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentCreate | providerAccountId (required, from Step 1), agentName (required), agentDescription, tags, trustLevel (default UNENDORSED), metadata |
On creation, the service automatically creates a DRAFT version and a default draft alias (informally the "TestAlias") there is no separate call needed. Tags and trust level passed here apply to the draft alias.
At this point you have:
AiAgent.idAiAgent.agentVersions[0]→ the DRAFT version (mutable — keep editing it in Step 3)- That version's default alias (
TestAlias)
Step 3: Configure the DRAFT version
Everything in this step attaches to the agent's DRAFT version by passing agentIds: [ID!]. The service resolves each agent ID to its current DRAFT version internally. Keep editing the draft freely.
The DRAFT version is untouched and stays open for further edits. You can create a non-editable packaged version by referring to Step 4.
Setting up tasks and its instructions
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentTaskCreate | providerAccountId (required), name (required), description, taskMetaData, instructions: [String!], agentToolIds: [ID!] (attach existing tools), agentIds: [ID!] (attach to agents' DRAFT versions), tags |
| Update | aiAgentTaskUpdate | id (required), name, description, taskStatus, taskMetaData, instructions: [String!] (wholesale replace), agentToolIds (incremental add), agentIds (incremental add), tags |
| Remove agent association | aiAgentTaskDisassociation | id (required), agentIds (omit or leave empty to remove all) |
| Delete | aiAgentTaskDelete | id. Deleting a task fails if any association still exists. |
There is no dedicated instruction-association mutation. instructions is a plain string list you set or replace directly on the task.
Setting up tools
A tool is associated to a task purely through the aiAgentTaskIds field on create or update. There is no separate "associate" mutation, only a dedicated aiAgentToolDisassociation to remove it. The schema explicitly deprecated a generic aiRegistryEntityType / aiRegistryEntityIds mechanism.
Tools can be associated only with a task, there is no need of a different entity type.
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentToolCreate | providerAccountId (required), toolType (required), name (required), description, toolJson, resources: [AiAgentToolResourceInput!], aiAgentTaskIds: [ID!] (associate to task(s)), tags |
| Update | aiAgentToolUpdate | id (required), name, description, toolJson, status, resources, tags, aiAgentTaskIds (incremental add) |
| Remove task association | aiAgentToolDisassociation | id (required), aiAgentTaskIds: [ID]! (pass an empty array to remove from all tasks) |
| Delete | aiAgentToolDelete | id. Tool deletion fails if any association exists. |
Setting up LLMs
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentLlmCreate | providerAccountId (required), name (required), description, agentIds (associate to DRAFT versions) |
| Update | aiAgentLlmUpdate | id (required), name, description, agentIds (incremental add) |
| Remove association | aiAgentLlmDisassociation | id (required), agentIds: [ID!]! |
| Delete | aiAgentLlmDelete | id. You can only delete a DRAFT-version LLM |
Setting up Guardrails
| Step | Mutation | Key inputs |
|---|---|---|
| Create | aiAgentGuardrailCreate | providerAccountId (required), name (required), description, configurationJson, agentIds (associate to DRAFT versions), tags |
| Update | aiAgentGuardrailUpdate | id (required), name, description, configurationJson, status, agentIds (incremental add), tags |
| Remove association | aiAgentGuardrailDisassociation | id (required), agentVersionIds: [ID!]! (pass an empty array to remove all) |
| Delete | aiAgentGuardrailDelete | id — fails if any association exists |
Step 4: Creating a version and alias of an agent
There is no dedicated "packaging" mutation. Call aiAgentAliasCreate with agentId and name, and omit agentVersionId:
aiAgentAliasCreate(input: {
agentId: "agent-guid",
name: "Production Alias"
}) {
id
name
agentVersion { id version }
}
When you omit agentVersionId, the service:
- Loads the agent's current DRAFT version.
- Allocates the next numeric version (v1, v2, …) and clones the version's core fields into a new immutable
AiAgentVersion(agentStatus = ACTIVE). - Copies the draft's LLM, guardrail, task and tool associations, tags, and instructions into the new version.
- Creates the new alias pointing at this freshly packaged version.
The DRAFT version is untouched and stays open for further edits. You can keep configuring tasks, tools, LLMs, and guardrails on it and create another package later.
If you instead pass an existing non-DRAFT agentVersionId, aiAgentAliasCreate creates an additional alias against that already published version and a new package is not created. Passing a DRAFT version ID is an error.
Managing versions and aliases
| Step | Mutation | Key inputs |
|---|---|---|
| Update alias | aiAgentAliasUpdate | id, name, description, trustLevel, agentStatus, tags |
| Delete alias | aiAliasDelete | id — deleting the DRAFT/default alias deletes the whole agent; deleting a packaged alias deletes just that alias (and its version too, if left with no aliases) |
| Bulk delete aliases | aiAliasesDelete | aiAgentsWithAliases: [AgentWithAliasesInput!]! |
Step 5: Query and list operations
| Query | Params | Returns |
|---|---|---|
| aiAgentProviderAccounts | pageIndex, pageSize, aiAgentProviderType, accountName, providerSubType | Paginated list of provider accounts |
| aiAgentProviderAccount | id | Single account, including agents[] |
| aiAgents | pageIndex, pageSize, providerAccountIds, agentIds | Paginated list of agents |
| aiAgentByVersionId | aiAgentVersionId | Agent looked up via one of its versions |
| aiAgentListings | offset, limit, providerAccountIds, searchInput, agentListingFilter | Denormalized grid view (one row per alias/version) plus status counts |
| aiAgentListingFilterValues | filter input | Filter-dropdown values (providers, models, tags, trust levels) |
| aiAgentTask | id | Single task |
| aiAgentTasks | providerAccountId (required), pageIndex, pageSize | Paginated list of tasks |
| aiAgentTool | id | Single tool |
| aiAgentTools | providerAccountId (required), pageIndex, pageSize | Paginated list of tools |
| aiAgentLlm | id | Single LLM |
| aiAgentLlms | startIndex, endIndex, providerAccountId | Paginated list of LLMs |
| aiAgentGuardrail | id | Single guardrail |
| aiAgentGuardrails | startIndex, endIndex, providerAccountId | Paginated list of guardrails |
| aiAgentAliases | providerTypes, providerAccountIds, providerSubTypes | Alias list for filter dropdowns |
| aiAgentTags | none | Distinct tag keys in use |
Versions and aliases don't have a standalone paginated query. Navigate them through AiAgent.agentVersions[].agentAliases[], or jump straight to a version or alias with aiAgentByVersionId.
Step 6: Delete the provider
| Step | Mutation | Notes |
|---|---|---|
| Delete agent | aiAgentDelete | Results in deletion of the agent plus all its versions, aliases, and associations. Shared entities (tasks, tools, LLMs, guardrails) are only deleted if not used by another agent. |
| Bulk delete agents | aiAgentBulkDelete | ids: [ID!]! |
| Delete provider account | aiAgentProviderAccountDelete | id |
Delete agents (and their orphaned tasks, tools, LLMs, and guardrails) before deleting the provider account.